agent-shim 11.50.2 → 11.51.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/dist/cli.cjs CHANGED
@@ -23995,7 +23995,7 @@ var require_merge2 = __commonJS({
23995
23995
  exports2.mergeAll = exports2.hasOwn = void 0;
23996
23996
  exports2.hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
23997
23997
  var objToString = Function.prototype.call.bind(Object.prototype.toString);
23998
- function isPlainObject4(obj) {
23998
+ function isPlainObject5(obj) {
23999
23999
  return objToString(obj) === "[object Object]";
24000
24000
  }
24001
24001
  function merge2(target, source, options) {
@@ -24010,7 +24010,7 @@ var require_merge2 = __commonJS({
24010
24010
  target[key].push(...newValue);
24011
24011
  continue;
24012
24012
  }
24013
- } else if (isPlainObject4(target[key]) && isPlainObject4(newValue)) {
24013
+ } else if (isPlainObject5(target[key]) && isPlainObject5(newValue)) {
24014
24014
  target[key] = merge2(target[key], newValue, options);
24015
24015
  continue;
24016
24016
  }
@@ -25040,59 +25040,73 @@ var init_proxyBypass = __esm({
25040
25040
  function distinctList(member) {
25041
25041
  return external_exports.array(member).refine((items) => new Set(items).size === items.length, "must not repeat a segment");
25042
25042
  }
25043
+ function isPlainObject2(value2) {
25044
+ return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
25045
+ }
25046
+ function mergeStatuslineSettings(base, over) {
25047
+ if (!isPlainObject2(base) || !isPlainObject2(over)) {
25048
+ return over === void 0 ? base : over;
25049
+ }
25050
+ const merged = { ...base };
25051
+ for (const [key, value2] of Object.entries(over)) {
25052
+ merged[key] = key in base ? mergeStatuslineSettings(base[key], value2) : value2;
25053
+ }
25054
+ return merged;
25055
+ }
25043
25056
  function resolveStatusline(settings2) {
25044
- const resolved = {
25045
- header: settings2?.header ?? STATUSLINE_DEFAULTS.header,
25046
- bars: settings2?.bars ?? STATUSLINE_DEFAULTS.bars,
25047
- warnAt: settings2?.warnAt ?? STATUSLINE_DEFAULTS.warnAt,
25048
- criticalAt: settings2?.criticalAt ?? STATUSLINE_DEFAULTS.criticalAt,
25049
- fiveHourLabel: settings2?.fiveHourLabel ?? STATUSLINE_DEFAULTS.fiveHourLabel,
25050
- sevenDayLabel: settings2?.sevenDayLabel ?? STATUSLINE_DEFAULTS.sevenDayLabel,
25051
- barWidth: settings2?.barWidth ?? STATUSLINE_DEFAULTS.barWidth
25052
- };
25053
- if (resolved.warnAt >= resolved.criticalAt) {
25054
- throw new RangeError(`statusline warnAt (${String(resolved.warnAt)}) must be below criticalAt (${String(resolved.criticalAt)})`);
25057
+ const resolved = ResolvedStatuslineSchema.parse(mergeStatuslineSettings(STATUSLINE_DEFAULTS, settings2));
25058
+ if (resolved.bands.warnAt >= resolved.bands.criticalAt) {
25059
+ throw new RangeError(`statusline bands.warnAt (${String(resolved.bands.warnAt)}) must be below bands.criticalAt (${String(resolved.bands.criticalAt)})`);
25055
25060
  }
25056
25061
  return resolved;
25057
25062
  }
25058
- var STATUSLINE_HEADER_SEGMENTS, STATUSLINE_BAR_GROUPS, MAX_PERCENT, MAX_STATUSLINE_LABEL_CHARS, MAX_BAR_CELLS, LABEL_RE2, wholePercent, StatuslineSchema, StatuslineChangeSchema, STATUSLINE_DEFAULTS, STATUSLINE_ENV;
25063
+ var STATUSLINE_HEADER_SEGMENTS, STATUSLINE_ROWS, MAX_PERCENT, MAX_STATUSLINE_LABEL_CHARS, MAX_BAR_CELLS, LABEL_RE2, labelText, wholePercent, SHAPES, StatuslineSchema, ResolvedStatuslineSchema, STATUSLINE_DEFAULTS, STATUSLINE_ENV;
25059
25064
  var init_statusline = __esm({
25060
25065
  "src/config/statusline.ts"() {
25061
25066
  "use strict";
25062
25067
  init_zod();
25063
25068
  STATUSLINE_HEADER_SEGMENTS = ["model", "provider", "route", "account", "identity", "headroom"];
25064
- STATUSLINE_BAR_GROUPS = ["context", "quota"];
25069
+ STATUSLINE_ROWS = ["context", "quota"];
25065
25070
  MAX_PERCENT = 100;
25066
25071
  MAX_STATUSLINE_LABEL_CHARS = 12;
25067
25072
  MAX_BAR_CELLS = 40;
25068
25073
  LABEL_RE2 = /^[^\p{C}\p{Z}]+(?: [^\p{C}\p{Z}]+)*$/u;
25074
+ labelText = external_exports.string().max(MAX_STATUSLINE_LABEL_CHARS).regex(LABEL_RE2, "must be visible text without control characters");
25069
25075
  wholePercent = external_exports.number().int().min(1).max(MAX_PERCENT);
25076
+ SHAPES = {
25077
+ layout: {
25078
+ header: distinctList(external_exports.enum(STATUSLINE_HEADER_SEGMENTS)).describe("The header segments to draw, in drawing order; a segment left out is hidden, and an empty list hides the header."),
25079
+ rows: distinctList(external_exports.enum(STATUSLINE_ROWS)).describe("The rows to draw below the header, in drawing order; a row left out is hidden, and an empty list hides every row.")
25080
+ },
25081
+ bands: {
25082
+ warnAt: wholePercent.describe("The whole percentage of use at which a bar turns yellow; it must be below criticalAt."),
25083
+ criticalAt: wholePercent.describe("The whole percentage of use at which a bar turns red.")
25084
+ },
25085
+ labels: {
25086
+ fiveHour: labelText.describe("The name of the five-hour subscription window."),
25087
+ sevenDay: labelText.describe("The name of the weekly subscription window.")
25088
+ },
25089
+ bar: {
25090
+ width: external_exports.number().int().min(1).max(MAX_BAR_CELLS).describe("A bar's width in cells before the line's spare width is shared out among the bars.")
25091
+ }
25092
+ };
25070
25093
  StatuslineSchema = external_exports.strictObject({
25071
- header: distinctList(external_exports.enum(STATUSLINE_HEADER_SEGMENTS)).optional(),
25072
- bars: distinctList(external_exports.enum(STATUSLINE_BAR_GROUPS)).optional(),
25073
- warnAt: wholePercent.optional(),
25074
- criticalAt: wholePercent.optional(),
25075
- fiveHourLabel: external_exports.string().max(MAX_STATUSLINE_LABEL_CHARS).regex(LABEL_RE2, "must be visible text without control characters").optional(),
25076
- sevenDayLabel: external_exports.string().max(MAX_STATUSLINE_LABEL_CHARS).regex(LABEL_RE2, "must be visible text without control characters").optional(),
25077
- barWidth: external_exports.number().int().min(1).max(MAX_BAR_CELLS).optional()
25078
- });
25079
- StatuslineChangeSchema = external_exports.strictObject({
25080
- header: external_exports.union([StatuslineSchema.shape.header.unwrap(), external_exports.literal(false)]).optional(),
25081
- bars: external_exports.union([StatuslineSchema.shape.bars.unwrap(), external_exports.literal(false)]).optional(),
25082
- warnAt: external_exports.union([StatuslineSchema.shape.warnAt.unwrap(), external_exports.literal(false)]).optional(),
25083
- criticalAt: external_exports.union([StatuslineSchema.shape.criticalAt.unwrap(), external_exports.literal(false)]).optional(),
25084
- fiveHourLabel: external_exports.union([StatuslineSchema.shape.fiveHourLabel.unwrap(), external_exports.literal(false)]).optional(),
25085
- sevenDayLabel: external_exports.union([StatuslineSchema.shape.sevenDayLabel.unwrap(), external_exports.literal(false)]).optional(),
25086
- barWidth: external_exports.union([StatuslineSchema.shape.barWidth.unwrap(), external_exports.literal(false)]).optional()
25094
+ layout: external_exports.strictObject(SHAPES.layout).partial().optional(),
25095
+ bands: external_exports.strictObject(SHAPES.bands).partial().optional(),
25096
+ labels: external_exports.strictObject(SHAPES.labels).partial().optional(),
25097
+ bar: external_exports.strictObject(SHAPES.bar).partial().optional()
25098
+ });
25099
+ ResolvedStatuslineSchema = external_exports.strictObject({
25100
+ layout: external_exports.strictObject(SHAPES.layout),
25101
+ bands: external_exports.strictObject(SHAPES.bands),
25102
+ labels: external_exports.strictObject(SHAPES.labels),
25103
+ bar: external_exports.strictObject(SHAPES.bar)
25087
25104
  });
25088
25105
  STATUSLINE_DEFAULTS = {
25089
- header: STATUSLINE_HEADER_SEGMENTS,
25090
- bars: STATUSLINE_BAR_GROUPS,
25091
- warnAt: 70,
25092
- criticalAt: 90,
25093
- fiveHourLabel: "5h",
25094
- sevenDayLabel: "Wk",
25095
- barWidth: 10
25106
+ layout: { header: [...STATUSLINE_HEADER_SEGMENTS], rows: [...STATUSLINE_ROWS] },
25107
+ bands: { warnAt: 70, criticalAt: 90 },
25108
+ labels: { fiveHour: "5h", sevenDay: "Wk" },
25109
+ bar: { width: 10 }
25096
25110
  };
25097
25111
  STATUSLINE_ENV = "AGENT_SHIM_STATUSLINE";
25098
25112
  }
@@ -31868,6 +31882,143 @@ var init_identity = __esm({
31868
31882
  }
31869
31883
  });
31870
31884
 
31885
+ // src/statusline/keys.ts
31886
+ function valueAt(source, path66) {
31887
+ let current = source;
31888
+ for (const part of path66) {
31889
+ if (!isPlainObject2(current)) {
31890
+ return void 0;
31891
+ }
31892
+ current = current[part];
31893
+ }
31894
+ return current;
31895
+ }
31896
+ function keyOf(path66, leaf) {
31897
+ const common = { path: path66.join("."), description: leaf.description ?? "", defaultValue: valueAt(STATUSLINE_DEFAULTS, path66) };
31898
+ if (leaf instanceof external_exports.ZodNumber) {
31899
+ return { ...common, kind: "integer", choices: [] };
31900
+ }
31901
+ if (leaf instanceof external_exports.ZodString) {
31902
+ return { ...common, kind: "text", choices: [] };
31903
+ }
31904
+ if (leaf instanceof external_exports.ZodEnum) {
31905
+ return { ...common, kind: "choice", choices: Object.values(leaf.enum).map(String) };
31906
+ }
31907
+ if (leaf instanceof external_exports.ZodArray && leaf.element instanceof external_exports.ZodEnum) {
31908
+ return { ...common, kind: "list", choices: Object.values(leaf.element.enum).map(String) };
31909
+ }
31910
+ throw new TypeError(`statusline setting ${path66.join(".")} has a kind the key listing does not describe`);
31911
+ }
31912
+ function walk(shape, prefix) {
31913
+ return Object.entries(shape).flatMap(([name, schema]) => schema instanceof external_exports.ZodObject ? walk(schema.shape, [...prefix, name]) : [keyOf([...prefix, name], schema)]);
31914
+ }
31915
+ function statuslineKeys() {
31916
+ return walk(ResolvedStatuslineSchema.shape, []);
31917
+ }
31918
+ function formatStatuslineKeys(keys) {
31919
+ return keys.map((key) => {
31920
+ const takes = key.kind === "choice" || key.kind === "list" ? `${key.kind} of ${key.choices.join(", ")}` : key.kind;
31921
+ return `${key.path} (${takes}; default ${JSON.stringify(key.defaultValue)})
31922
+ ${key.description}`;
31923
+ }).join("\n");
31924
+ }
31925
+ var init_keys = __esm({
31926
+ "src/statusline/keys.ts"() {
31927
+ "use strict";
31928
+ init_zod();
31929
+ init_statusline();
31930
+ }
31931
+ });
31932
+
31933
+ // src/statusline/change.ts
31934
+ function keyNamed(path66) {
31935
+ const found = statuslineKeys().find((key) => key.path === path66);
31936
+ if (found === void 0) {
31937
+ throw new UsageError(`"${path66}" is not a statusline setting; \`agent-shim statusline keys\` lists them.`);
31938
+ }
31939
+ return found;
31940
+ }
31941
+ function parseStatuslineAssignment(text2) {
31942
+ const split = text2.indexOf("=");
31943
+ if (split < 1) {
31944
+ throw new UsageError(`"${text2}" is not <setting>=<value>.`);
31945
+ }
31946
+ const path66 = text2.slice(0, split);
31947
+ const raw = text2.slice(split + 1);
31948
+ const key = keyNamed(path66);
31949
+ switch (key.kind) {
31950
+ case "integer": {
31951
+ const number4 = Number(raw);
31952
+ if (raw.trim() === "" || !Number.isFinite(number4)) {
31953
+ throw new UsageError(`${path66}: "${raw}" is not a number.`);
31954
+ }
31955
+ return { path: path66, value: number4 };
31956
+ }
31957
+ case "text":
31958
+ case "choice":
31959
+ return { path: path66, value: raw };
31960
+ case "list":
31961
+ return { path: path66, value: raw === "" ? [] : raw.split(",") };
31962
+ default:
31963
+ return key.kind;
31964
+ }
31965
+ }
31966
+ function setAt(target, path66, value2) {
31967
+ const [head, ...rest] = path66;
31968
+ if (head === void 0) {
31969
+ return;
31970
+ }
31971
+ if (rest.length === 0) {
31972
+ target[head] = value2;
31973
+ return;
31974
+ }
31975
+ const child = target[head];
31976
+ const next = isPlainObject2(child) ? child : {};
31977
+ target[head] = next;
31978
+ setAt(next, rest, value2);
31979
+ }
31980
+ function removeAt(target, path66) {
31981
+ const [head, ...rest] = path66;
31982
+ if (head === void 0) {
31983
+ return;
31984
+ }
31985
+ const child = target[head];
31986
+ if (rest.length === 0) {
31987
+ Reflect.deleteProperty(target, head);
31988
+ return;
31989
+ }
31990
+ if (isPlainObject2(child)) {
31991
+ removeAt(child, rest);
31992
+ if (Object.keys(child).length === 0) {
31993
+ Reflect.deleteProperty(target, head);
31994
+ }
31995
+ }
31996
+ }
31997
+ function applyStatuslineChange(existing, change) {
31998
+ const draft = structuredClone(existing ?? {});
31999
+ for (const [path66, value2] of Object.entries(change.set ?? {})) {
32000
+ keyNamed(path66);
32001
+ setAt(draft, path66.split("."), value2);
32002
+ }
32003
+ for (const path66 of change.unset ?? []) {
32004
+ keyNamed(path66);
32005
+ removeAt(draft, path66.split("."));
32006
+ }
32007
+ const result = StatuslineSchema.safeParse(draft);
32008
+ if (!result.success) {
32009
+ throw new UsageError(`statusline: ${result.error.issues.map((issue2) => `${issue2.path.join(".")}: ${issue2.message}`).join("; ")}.`);
32010
+ }
32011
+ return Object.keys(result.data).length === 0 ? void 0 : result.data;
32012
+ }
32013
+ var init_change = __esm({
32014
+ "src/statusline/change.ts"() {
32015
+ "use strict";
32016
+ init_cliError();
32017
+ init_statusline();
32018
+ init_keys();
32019
+ }
32020
+ });
32021
+
31871
32022
  // src/configProfilesStore.ts
31872
32023
  function profileJsonPath(paths, name) {
31873
32024
  return import_node_path12.default.join(paths.configProfilesDir, `${name}.json`);
@@ -31967,17 +32118,6 @@ function removeProfile(paths, name) {
31967
32118
  requireProfileExists(paths, name);
31968
32119
  import_node_fs5.default.rmSync(profileJsonPath(paths, name));
31969
32120
  }
31970
- function withStatuslineChange(existing, change) {
31971
- const merged = new Map(Object.entries({ ...existing }));
31972
- for (const [key, value2] of Object.entries(change)) {
31973
- if (value2 === false) {
31974
- merged.delete(key);
31975
- } else {
31976
- merged.set(key, value2);
31977
- }
31978
- }
31979
- return merged.size === 0 ? void 0 : StatuslineSchema.parse(Object.fromEntries(merged));
31980
- }
31981
32121
  function applyProfileChange(paths, name, change) {
31982
32122
  let touched = false;
31983
32123
  if (change.category !== void 0) {
@@ -32027,7 +32167,7 @@ function applyProfileChange(paths, name, change) {
32027
32167
  launchPatch.explain = change.launchExplain;
32028
32168
  }
32029
32169
  if (change.launchStatusline !== void 0) {
32030
- launchPatch.statusline = withStatuslineChange(readProfile(paths, name)?.launch?.statusline, change.launchStatusline);
32170
+ launchPatch.statusline = applyStatuslineChange(readProfile(paths, name)?.launch?.statusline, change.launchStatusline);
32031
32171
  }
32032
32172
  if (Object.keys(launchPatch).length > 0) {
32033
32173
  setProfileLaunchFlags(paths, name, launchPatch);
@@ -32044,7 +32184,7 @@ var init_configProfilesStore = __esm({
32044
32184
  init_store();
32045
32185
  init_schema();
32046
32186
  init_cliError();
32047
- init_statusline();
32187
+ init_change();
32048
32188
  init_load();
32049
32189
  ProfileNotFoundError = class extends CliError {
32050
32190
  constructor(profileName) {
@@ -32671,9 +32811,9 @@ function referencesFact(when, key) {
32671
32811
  if (when === void 0 || !("kind" in when)) {
32672
32812
  return false;
32673
32813
  }
32674
- const walk2 = (node2) => {
32814
+ const walk3 = (node2) => {
32675
32815
  if (Array.isArray(node2)) {
32676
- return node2.some(walk2);
32816
+ return node2.some(walk3);
32677
32817
  }
32678
32818
  if (typeof node2 !== "object" || node2 === null) {
32679
32819
  return false;
@@ -32681,9 +32821,9 @@ function referencesFact(when, key) {
32681
32821
  if ("kind" in node2 && node2.kind === "reference" && "key" in node2 && node2.key === key) {
32682
32822
  return true;
32683
32823
  }
32684
- return Object.values(node2).some(walk2);
32824
+ return Object.values(node2).some(walk3);
32685
32825
  };
32686
- return walk2(when);
32826
+ return walk3(when);
32687
32827
  }
32688
32828
  function isVacuousWhen(when) {
32689
32829
  return when !== void 0 && !("kind" in when) && Object.keys(when).length === 0;
@@ -33003,7 +33143,7 @@ function flattenLayers(layers, options) {
33003
33143
  launch.proxyBypass = layer.launch.proxyBypass;
33004
33144
  }
33005
33145
  if (layer.launch.statusline !== void 0) {
33006
- launch.statusline = { ...launch.statusline, ...layer.launch.statusline };
33146
+ launch.statusline = StatuslineSchema.parse(mergeStatuslineSettings(launch.statusline, layer.launch.statusline));
33007
33147
  }
33008
33148
  }
33009
33149
  if (layer.models !== void 0) {
@@ -33184,6 +33324,7 @@ var init_flatten = __esm({
33184
33324
  "src/resolve/flatten.ts"() {
33185
33325
  "use strict";
33186
33326
  init_schema();
33327
+ init_statusline();
33187
33328
  init_conditions();
33188
33329
  init_match();
33189
33330
  }
@@ -36010,7 +36151,7 @@ var init_package = __esm({
36010
36151
  "package.json"() {
36011
36152
  package_default = {
36012
36153
  name: "agent-shim",
36013
- version: "11.50.2",
36154
+ version: "11.51.0",
36014
36155
  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.",
36015
36156
  license: "MIT",
36016
36157
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -64959,7 +65100,7 @@ function isAnthropicUsageStale(member, nowMs) {
64959
65100
  function poolIdentityNames(pools, poolName) {
64960
65101
  const seenPools = /* @__PURE__ */ new Set();
64961
65102
  const identities = /* @__PURE__ */ new Set();
64962
- const walk2 = (name) => {
65103
+ const walk3 = (name) => {
64963
65104
  const pool = pools[name];
64964
65105
  if (pool === void 0 || seenPools.has(name)) {
64965
65106
  return;
@@ -64971,11 +65112,11 @@ function poolIdentityNames(pools, poolName) {
64971
65112
  if (nested === void 0) {
64972
65113
  identities.add(member);
64973
65114
  } else {
64974
- walk2(nested);
65115
+ walk3(nested);
64975
65116
  }
64976
65117
  }
64977
65118
  };
64978
- walk2(poolName);
65119
+ walk3(poolName);
64979
65120
  return [...identities];
64980
65121
  }
64981
65122
  function describeError(error63) {
@@ -67168,14 +67309,14 @@ function memberKindOf(ref, models) {
67168
67309
  function expandMembers(name, models) {
67169
67310
  const virtual = models?.virtual ?? {};
67170
67311
  const expanded = [];
67171
- const walk2 = (current, chain) => {
67312
+ const walk3 = (current, chain) => {
67172
67313
  const nested = virtual[current];
67173
67314
  if (nested !== void 0) {
67174
67315
  if (chain.includes(current)) {
67175
67316
  throw new Error(`virtual model cycle: ${[...chain, current].join(" -> ")}`);
67176
67317
  }
67177
67318
  for (const member of nested.members) {
67178
- walk2(member, [...chain, current]);
67319
+ walk3(member, [...chain, current]);
67179
67320
  }
67180
67321
  return;
67181
67322
  }
@@ -67188,7 +67329,7 @@ function expandMembers(name, models) {
67188
67329
  throw new VirtualModelNotFoundError(name);
67189
67330
  }
67190
67331
  for (const member of top.members) {
67191
- walk2(member, [name]);
67332
+ walk3(member, [name]);
67192
67333
  }
67193
67334
  return expanded;
67194
67335
  }
@@ -113936,7 +114077,7 @@ function writePools(paths, pools) {
113936
114077
  applyPatch(paths.globalConfigFile, GlobalConfigSchema, { pools }, { defaults: {} });
113937
114078
  }
113938
114079
  function poolCycleOf(pools, name) {
113939
- const walk2 = (current, path66) => {
114080
+ const walk3 = (current, path66) => {
113940
114081
  for (const entry of pools[current]?.identities ?? []) {
113941
114082
  const nested = poolNameOf(poolMemberIdentity(entry));
113942
114083
  if (nested === void 0) {
@@ -113948,14 +114089,14 @@ function poolCycleOf(pools, name) {
113948
114089
  if (path66.includes(nested)) {
113949
114090
  continue;
113950
114091
  }
113951
- const found = walk2(nested, [...path66, nested]);
114092
+ const found = walk3(nested, [...path66, nested]);
113952
114093
  if (found !== void 0) {
113953
114094
  return found;
113954
114095
  }
113955
114096
  }
113956
114097
  return void 0;
113957
114098
  };
113958
- return walk2(name, [name]);
114099
+ return walk3(name, [name]);
113959
114100
  }
113960
114101
  function validateMembers(pools, name, members2) {
113961
114102
  for (const entry of members2) {
@@ -115117,7 +115258,7 @@ async function resolveFarmConflicts(params) {
115117
115258
  // src/configProfiles.ts
115118
115259
  init_commandDeps();
115119
115260
  init_cliError();
115120
- init_statusline();
115261
+ init_change();
115121
115262
  init_proxyBypass2();
115122
115263
  init_configProfilesStore();
115123
115264
  async function ensureProfileExists(deps, name) {
@@ -115144,28 +115285,12 @@ async function ensureProfileExists(deps, name) {
115144
115285
  function toProfileView(name, profile, globalDefault) {
115145
115286
  return { name, globalDefault: name === globalDefault, ...profile, $schema: void 0 };
115146
115287
  }
115147
- function segmentList(values) {
115148
- return values.length === 1 && values[0] === "none" ? [] : values;
115149
- }
115150
115288
  function statuslineChangeOf(options) {
115151
- const raw = {
115152
- header: options.statuslineHeader === void 0 || options.statuslineHeader === false ? options.statuslineHeader : segmentList(options.statuslineHeader),
115153
- bars: options.statuslineBars === void 0 || options.statuslineBars === false ? options.statuslineBars : segmentList(options.statuslineBars),
115154
- warnAt: options.statuslineWarnAt === void 0 || options.statuslineWarnAt === false ? options.statuslineWarnAt : Number(options.statuslineWarnAt),
115155
- criticalAt: options.statuslineCriticalAt === void 0 || options.statuslineCriticalAt === false ? options.statuslineCriticalAt : Number(options.statuslineCriticalAt),
115156
- fiveHourLabel: options.statuslineFiveHourLabel,
115157
- sevenDayLabel: options.statuslineSevenDayLabel,
115158
- barWidth: options.statuslineBarWidth === void 0 || options.statuslineBarWidth === false ? options.statuslineBarWidth : Number(options.statuslineBarWidth)
115159
- };
115160
- const given = Object.entries(raw).filter(([, value2]) => value2 !== void 0);
115161
- if (given.length === 0) {
115289
+ if (options.statusline === void 0 && options.unsetStatusline === void 0) {
115162
115290
  return void 0;
115163
115291
  }
115164
- const result = StatuslineSchema.safeParse(Object.fromEntries(given.filter(([, value2]) => value2 !== false)));
115165
- if (!result.success) {
115166
- throw new UsageError(`--statusline-*: ${result.error.issues.map((issue2) => `${issue2.path.join(".")}: ${issue2.message}`).join("; ")}.`);
115167
- }
115168
- return Object.fromEntries(given);
115292
+ const assignments = (options.statusline ?? []).map(parseStatuslineAssignment);
115293
+ return { set: Object.fromEntries(assignments.map(({ path: path66, value: value2 }) => [path66, value2])), unset: options.unsetStatusline ?? [] };
115169
115294
  }
115170
115295
  function registerProfileCommand(program2, deps) {
115171
115296
  const { paths } = deps;
@@ -115202,7 +115327,7 @@ function registerProfileCommand(program2, deps) {
115202
115327
  withExamples(
115203
115328
  profile.command("set <name>").description(
115204
115329
  "Update a configuration profile's categories, entries, extends list, description or launch settings. With no options on a terminal, walks through its categories."
115205
- ).option("--category <category=bool>", "Share (true) or hide (false) a whole category (repeatable).", collectBoolPair).option("--entry <path=bool>", "Share (true) or hide (false) one <category>/<path> entry (repeatable).", collectBoolPair).option("--extends <profile>", "Replace the extends list with these profiles (repeatable, in order).", collectRepeated).option("--no-extends", "Clear the extends list.").option("--description <text>", "Replace the description.").option("--no-description", "Clear the description.").option("--launch-skip-permissions", "Launches under this profile skip permission prompts.").option("--no-launch-skip-permissions", "Launches under this profile keep permission prompts.").option("--launch-remote-control", "Launches under this profile enable Remote Control.").option("--no-launch-remote-control", "Launches under this profile leave Remote Control off.").option("--launch-headroom", "Launches under this profile route through headroom.").option("--no-launch-headroom", "Launches under this profile route direct.").option("--launch-track-usage", "Launches under this profile route through the front door so their requests and quota are recorded, with no headroom needed.").option("--no-launch-track-usage", "Launches under this profile are not recorded unless a provider or headroom routes them anyway.").option("--launch-provider <provider>", "Launches under this profile route through this provider.").option("--no-launch-provider", "Clear this profile's provider selection.").option("--launch-claude-version <version>", "Launches under this profile run exactly this installed Claude Code version (such as 2.1.220); a version that is not installed fails the launch.").option("--no-launch-claude-version", "Clear this profile's Claude Code version pin.").option("--launch-delay <duration>", "Launches under this profile wait this long (such as 5s) after the launcher's own output before starting claude, so the output can be read.", parseDurationLiteral).option("--no-launch-delay", "Clear this profile's launch delay.").option("--launch-pause", "Launches under this profile wait for a key press after the launcher's own output before starting claude.").option("--no-launch-pause", "Launches under this profile start claude without waiting for a key press.").option("--launch-explain", "Launches under this profile that pick from a pool list every member the pick ranked and why, in the launcher's report.").option("--no-launch-explain", "Launches under this profile name only the member a pool pick chose.").option("--launch-proxy-bypass <host>", "Launches under this profile keep this host off the front door by adding it to NO_PROXY, so its traffic goes direct (repeatable; replaces the profile's list).", collectRepeated).option("--no-launch-proxy-bypass", "Clear this profile's list of hosts kept off the front door.").option("--statusline-header <segment>", `The statusline header segments to draw, in drawing order (repeatable; one of ${STATUSLINE_HEADER_SEGMENTS.join(", ")}, or "none" to hide the header).`, collectRepeated).option("--no-statusline-header", "Clear this profile's header segment list, restoring the default.").option("--statusline-bars <group>", `The statusline bar groups to draw, in drawing order (repeatable; one of ${STATUSLINE_BAR_GROUPS.join(", ")}, or "none" to hide the bars).`, collectRepeated).option("--no-statusline-bars", "Clear this profile's bar group list, restoring the default.").option("--statusline-warn-at <percent>", "The whole percentage of use at which a statusline bar turns yellow.").option("--no-statusline-warn-at", "Clear this profile's warning threshold.").option("--statusline-critical-at <percent>", "The whole percentage of use at which a statusline bar turns red.").option("--no-statusline-critical-at", "Clear this profile's critical threshold.").option("--statusline-five-hour-label <text>", "The statusline's name for the five-hour window.").option("--no-statusline-five-hour-label", "Clear this profile's five-hour window label.").option("--statusline-seven-day-label <text>", "The statusline's name for the weekly window.").option("--no-statusline-seven-day-label", "Clear this profile's weekly window label.").option("--statusline-bar-width <cells>", "The width of a statusline bar in cells, before the line's spare width is shared out among the bars.").option("--no-statusline-bar-width", "Clear this profile's bar width.").option("--json", "Print the result as JSON.").action(async (name, allOptions) => {
115330
+ ).option("--category <category=bool>", "Share (true) or hide (false) a whole category (repeatable).", collectBoolPair).option("--entry <path=bool>", "Share (true) or hide (false) one <category>/<path> entry (repeatable).", collectBoolPair).option("--extends <profile>", "Replace the extends list with these profiles (repeatable, in order).", collectRepeated).option("--no-extends", "Clear the extends list.").option("--description <text>", "Replace the description.").option("--no-description", "Clear the description.").option("--launch-skip-permissions", "Launches under this profile skip permission prompts.").option("--no-launch-skip-permissions", "Launches under this profile keep permission prompts.").option("--launch-remote-control", "Launches under this profile enable Remote Control.").option("--no-launch-remote-control", "Launches under this profile leave Remote Control off.").option("--launch-headroom", "Launches under this profile route through headroom.").option("--no-launch-headroom", "Launches under this profile route direct.").option("--launch-track-usage", "Launches under this profile route through the front door so their requests and quota are recorded, with no headroom needed.").option("--no-launch-track-usage", "Launches under this profile are not recorded unless a provider or headroom routes them anyway.").option("--launch-provider <provider>", "Launches under this profile route through this provider.").option("--no-launch-provider", "Clear this profile's provider selection.").option("--launch-claude-version <version>", "Launches under this profile run exactly this installed Claude Code version (such as 2.1.220); a version that is not installed fails the launch.").option("--no-launch-claude-version", "Clear this profile's Claude Code version pin.").option("--launch-delay <duration>", "Launches under this profile wait this long (such as 5s) after the launcher's own output before starting claude, so the output can be read.", parseDurationLiteral).option("--no-launch-delay", "Clear this profile's launch delay.").option("--launch-pause", "Launches under this profile wait for a key press after the launcher's own output before starting claude.").option("--no-launch-pause", "Launches under this profile start claude without waiting for a key press.").option("--launch-explain", "Launches under this profile that pick from a pool list every member the pick ranked and why, in the launcher's report.").option("--no-launch-explain", "Launches under this profile name only the member a pool pick chose.").option("--launch-proxy-bypass <host>", "Launches under this profile keep this host off the front door by adding it to NO_PROXY, so its traffic goes direct (repeatable; replaces the profile's list).", collectRepeated).option("--no-launch-proxy-bypass", "Clear this profile's list of hosts kept off the front door.").option("--statusline <setting=value>", "Set one statusline setting for launches under this profile (repeatable; `agent-shim statusline keys` lists them; a list is comma-separated, and an empty value is the empty list).", collectRepeated).option("--unset-statusline <setting>", "Remove one statusline setting from this profile so the shallower layers or the default apply again (repeatable).", collectRepeated).option("--json", "Print the result as JSON.").action(async (name, allOptions) => {
115206
115331
  const { json: json2, ...options } = allOptions;
115207
115332
  requireProfileExists(paths, name);
115208
115333
  if (Object.entries(allOptions).every(([key, value2]) => key === "json" || value2 === void 0)) {
@@ -121899,7 +122024,7 @@ function findDeepMatches(check2, payload, segments = [], maps = [], values = [])
121899
122024
  payload.forEach((v, i10) => {
121900
122025
  findDeepMatches(check2, v, [...segments, i10], maps, values);
121901
122026
  });
121902
- } else if (isPlainObject2(payload)) {
122027
+ } else if (isPlainObject3(payload)) {
121903
122028
  for (const key of Object.keys(payload)) {
121904
122029
  findDeepMatches(check2, payload[key], [...segments, key], maps, values);
121905
122030
  }
@@ -121924,7 +122049,7 @@ function* getConstructors(value2) {
121924
122049
  proto = Object.getPrototypeOf(proto);
121925
122050
  }
121926
122051
  }
121927
- function isPlainObject2(value2) {
122052
+ function isPlainObject3(value2) {
121928
122053
  if (!value2 || typeof value2 !== "object") {
121929
122054
  return false;
121930
122055
  }
@@ -121957,7 +122082,7 @@ function setOwn(object3, key, value2) {
121957
122082
  }
121958
122083
  }
121959
122084
  function mergeTwoLevels(first, second) {
121960
- if (!isPlainObject2(first) || !isPlainObject2(second)) {
122085
+ if (!isPlainObject3(first) || !isPlainObject3(second)) {
121961
122086
  return second;
121962
122087
  }
121963
122088
  const result = { ...first, ...second };
@@ -121967,7 +122092,7 @@ function mergeTwoLevels(first, second) {
121967
122092
  }
121968
122093
  const firstValue = first[key];
121969
122094
  const secondValue = second[key];
121970
- if (isPlainObject2(firstValue) && isPlainObject2(secondValue)) {
122095
+ if (isPlainObject3(firstValue) && isPlainObject3(secondValue)) {
121971
122096
  result[key] = { ...firstValue, ...secondValue };
121972
122097
  }
121973
122098
  }
@@ -121996,7 +122121,7 @@ function cloneWithVisited(value2, visited) {
121996
122121
  }
121997
122122
  return result;
121998
122123
  }
121999
- if (isPlainObject2(value2)) {
122124
+ if (isPlainObject3(value2)) {
122000
122125
  const existing = visited.get(value2);
122001
122126
  if (existing) {
122002
122127
  return existing;
@@ -122021,7 +122146,7 @@ function copyOnWrite(parent, key, original) {
122021
122146
  let copy;
122022
122147
  if (Array.isArray(value2)) {
122023
122148
  copy = value2.slice();
122024
- } else if (isPlainObject2(value2)) {
122149
+ } else if (isPlainObject3(value2)) {
122025
122150
  copy = { ...value2 };
122026
122151
  } else {
122027
122152
  return value2;
@@ -122638,7 +122763,7 @@ function toORPCError(error63) {
122638
122763
  return error63 instanceof ORPCError ? error63 : new ORPCError("INTERNAL_SERVER_ERROR", { cause: error63 });
122639
122764
  }
122640
122765
  function isORPCErrorJson(json2) {
122641
- if (!isPlainObject2(json2)) {
122766
+ if (!isPlainObject3(json2)) {
122642
122767
  return false;
122643
122768
  }
122644
122769
  const validKeys = ["defined", "code", "message", "data"];
@@ -122672,7 +122797,7 @@ function inferMalformedResponseMessage(response) {
122672
122797
  if (typeof response.body === "string" && isInferableMessage(response.body)) {
122673
122798
  return response.body;
122674
122799
  }
122675
- if (isPlainObject2(response.body) && typeof response.body.message === "string" && isInferableMessage(response.body.message)) {
122800
+ if (isPlainObject3(response.body) && typeof response.body.message === "string" && isInferableMessage(response.body.message)) {
122676
122801
  return response.body.message;
122677
122802
  }
122678
122803
  const commonCode = Object.entries(COMMON_ERROR_STATUS_MAP).find(([, status]) => status === response.status)?.[0];
@@ -122963,7 +123088,7 @@ var RPCJsonSerializer = class {
122963
123088
  }
122964
123089
  return json2;
122965
123090
  }
122966
- if (isPlainObject2(data)) {
123091
+ if (isPlainObject3(data)) {
122967
123092
  const json2 = new NullProtoObj();
122968
123093
  for (const k10 of Object.keys(data)) {
122969
123094
  const v = data[k10];
@@ -123209,7 +123334,7 @@ var BracketNotationSerializer = class {
123209
123334
  data.forEach((item, i10) => {
123210
123335
  this.internalSerialize(item, isRoot ? i10.toString() : `${path66}[${i10}]`, false, result);
123211
123336
  });
123212
- } else if (isPlainObject2(data)) {
123337
+ } else if (isPlainObject3(data)) {
123213
123338
  for (const key of Object.keys(data)) {
123214
123339
  this.internalSerialize(data[key], isRoot ? key : `${path66}[${key}]`, false, result);
123215
123340
  }
@@ -123229,7 +123354,7 @@ var BracketNotationSerializer = class {
123229
123354
  const isLast = i10 === segments.length - 1;
123230
123355
  const existing = getOwn(currentRef, nextSegment);
123231
123356
  let child = existing;
123232
- if (!Array.isArray(child) && !isPlainObject2(child)) {
123357
+ if (!Array.isArray(child) && !isPlainObject3(child)) {
123233
123358
  child = [];
123234
123359
  }
123235
123360
  if (Array.isArray(child)) {
@@ -123784,7 +123909,7 @@ var OpenAPIJsonSerializer = class {
123784
123909
  }
123785
123910
  return json2;
123786
123911
  }
123787
- if (isPlainObject2(data)) {
123912
+ if (isPlainObject3(data)) {
123788
123913
  const json2 = new NullProtoObj();
123789
123914
  for (const k10 of Object.keys(data)) {
123790
123915
  const v = data[k10];
@@ -126618,7 +126743,7 @@ function toBodyContent(ctx, direction, schema) {
126618
126743
  if (rest.length > 0) {
126619
126744
  const restSchema = fileSchemasByMediaType.size ? combineJsonSchemasWithComposition("anyOf", rest) : schema;
126620
126745
  const hasNestedFiles = findDeepMatches(
126621
- (v) => isPlainObject2(v) && isJsonFileSchema(v),
126746
+ (v) => isPlainObject3(v) && isJsonFileSchema(v),
126622
126747
  restSchema
126623
126748
  ).values.length > 0;
126624
126749
  const contentType = hasNestedFiles ? "multipart/form-data" : "application/json";
@@ -129117,7 +129242,7 @@ var OpenAPIHandlerCodecCore = class {
129117
129242
  if (!params || Object.keys(params).length < 1) {
129118
129243
  return data;
129119
129244
  }
129120
- if (!isPlainObject2(data)) {
129245
+ if (!isPlainObject3(data)) {
129121
129246
  return params;
129122
129247
  }
129123
129248
  return {
@@ -129177,7 +129302,7 @@ var OpenAPIHandlerCodecCore = class {
129177
129302
  const [, search] = parseStandardUrl(url2);
129178
129303
  const searchParams = new URLSearchParams(search);
129179
129304
  const parsed = this.serializer.deserialize(searchParams);
129180
- if (!styles || !isPlainObject2(parsed)) {
129305
+ if (!styles || !isPlainObject3(parsed)) {
129181
129306
  return parsed;
129182
129307
  }
129183
129308
  Object.entries(styles).forEach(([key, hint]) => {
@@ -129513,7 +129638,6 @@ init_providersStore();
129513
129638
  // src/frontdoor/configSchemas.ts
129514
129639
  init_zod();
129515
129640
  init_schema();
129516
- init_statusline();
129517
129641
  var RemovalConfirmationSchema = external_exports.boolean();
129518
129642
  var CredentialWriteSchema = (targets) => external_exports.strictObject({
129519
129643
  sources: external_exports.array(RemoteCredentialSourceSchema).min(1).optional(),
@@ -129590,7 +129714,10 @@ var ConfigProfileSetInputSchema = external_exports.strictObject({
129590
129714
  pause: external_exports.boolean().optional(),
129591
129715
  explain: external_exports.boolean().optional(),
129592
129716
  proxyBypass: external_exports.union([external_exports.array(external_exports.string().min(1)), external_exports.literal(false)]).optional(),
129593
- statusline: StatuslineChangeSchema.optional()
129717
+ statusline: external_exports.strictObject({
129718
+ set: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
129719
+ unset: external_exports.array(external_exports.string()).optional()
129720
+ }).optional()
129594
129721
  }).optional()
129595
129722
  });
129596
129723
  var ConfigProfileSetOutputSchema = storedMutationOutput("profile", "updated", ProfileValueSchema);
@@ -130607,7 +130734,7 @@ function nextToken(body, from) {
130607
130734
  }
130608
130735
  return SCALAR;
130609
130736
  }
130610
- function walk(body, hashing, parentAfter) {
130737
+ function walk2(body, hashing, parentAfter) {
130611
130738
  const thread = (0, import_node_crypto22.createHash)("sha256");
130612
130739
  const messages = (0, import_node_crypto22.createHash)("sha256");
130613
130740
  let parentDigest;
@@ -130724,12 +130851,12 @@ function lineageOf(body) {
130724
130851
  if (body.length > LINEAGE_BODY_BYTES_LIMIT) {
130725
130852
  return void 0;
130726
130853
  }
130727
- const counted = walk(body, false, void 0);
130854
+ const counted = walk2(body, false, void 0);
130728
130855
  if (counted.abandoned || !counted.sawMessages) {
130729
130856
  return void 0;
130730
130857
  }
130731
130858
  const parentAfter = counted.elements > MESSAGES_PER_TURN ? counted.elements - MESSAGES_PER_TURN : void 0;
130732
- const hashed = walk(body, true, parentAfter);
130859
+ const hashed = walk2(body, true, parentAfter);
130733
130860
  const combine = (messagesDigest) => (0, import_node_crypto22.createHash)("sha256").update(hashed.threadDigest).update(messagesDigest).digest("hex");
130734
130861
  return { ownKey: combine(hashed.messagesDigest), parentKey: hashed.parentDigest === void 0 ? void 0 : combine(hashed.parentDigest) };
130735
130862
  }
@@ -136872,6 +136999,9 @@ function providerScopedState(snapshot, providerName, providerDisplayName) {
136872
136999
  // src/statusline/commands.ts
136873
137000
  init_read();
136874
137001
 
137002
+ // src/statusline/render.ts
137003
+ init_statusline();
137004
+
136875
137005
  // src/statusline/ansi.ts
136876
137006
  var ESCAPE_CHAR_CODE = 27;
136877
137007
  var ESCAPE = String.fromCharCode(ESCAPE_CHAR_CODE);
@@ -136880,9 +137010,6 @@ function visibleLength(text2) {
136880
137010
  return text2.replace(ANSI_REGEX, "").length;
136881
137011
  }
136882
137012
 
136883
- // src/statusline/render.ts
136884
- init_statusline();
136885
-
136886
137013
  // src/statusline/barGrid.ts
136887
137014
  var BRACKET_COLUMNS = 2;
136888
137015
  function chunk(items, size) {
@@ -136953,7 +137080,66 @@ function layoutBarGrid(groups, maxWidth, separator, baseBarCells) {
136953
137080
  return renderGrid(layoutFor(1), maxWidth, separator, baseBarCells);
136954
137081
  }
136955
137082
 
136956
- // src/statusline/render.ts
137083
+ // src/statusline/elements/header/account.ts
137084
+ function tierSuffixOf(tier) {
137085
+ const match = /_(\d+x)$/i.exec(tier ?? "");
137086
+ return match === null ? void 0 : match[1];
137087
+ }
137088
+ function accountPlanLabel(summary) {
137089
+ switch (summary.loginOrganizationType) {
137090
+ case void 0:
137091
+ return planLabelOf(summary.loginRateLimitTier);
137092
+ case "claude_max": {
137093
+ const tier = tierSuffixOf(summary.loginRateLimitTier);
137094
+ return tier === void 0 ? "Max" : `Max ${tier}`;
137095
+ }
137096
+ case "claude_pro":
137097
+ return "Pro";
137098
+ case "claude_team":
137099
+ if (summary.loginSeatTier === "team_standard") {
137100
+ return "Team Standard";
137101
+ }
137102
+ if (summary.loginSeatTier === "team_tier_1") {
137103
+ return "Team Premium";
137104
+ }
137105
+ return "Team";
137106
+ case "claude_enterprise":
137107
+ return "Enterprise";
137108
+ default:
137109
+ return summary.loginOrganizationType;
137110
+ }
137111
+ }
137112
+ function planLabelOf(tier) {
137113
+ if (tier === void 0 || tier === "") {
137114
+ return void 0;
137115
+ }
137116
+ const cleaned = tier.startsWith("default_") ? tier.slice("default_".length) : tier;
137117
+ if (cleaned === "free") {
137118
+ return "Free";
137119
+ }
137120
+ const maxWithMultiplier = /^claude_max_(\d+)x$/.exec(cleaned);
137121
+ if (maxWithMultiplier !== null) {
137122
+ return `Max ${maxWithMultiplier[1] ?? ""}x`;
137123
+ }
137124
+ if (cleaned === "claude_max") {
137125
+ return "Max";
137126
+ }
137127
+ if (cleaned === "claude_pro") {
137128
+ return "Pro";
137129
+ }
137130
+ return cleaned;
137131
+ }
137132
+ function accountSegment({ summary }) {
137133
+ const loginPlan = summary.provider === void 0 ? summary.loginPlan ?? accountPlanLabel(summary) : void 0;
137134
+ const loginOrgName = summary.loginOrganizationType === "claude_team" || summary.loginOrganizationType === "claude_enterprise" ? summary.loginOrganizationName : void 0;
137135
+ const loginParts = [summary.loginAccountEmail, loginOrgName, loginPlan].filter((part) => part !== void 0);
137136
+ if (summary.loginAccountEmail !== void 0 && summary.loginAccountEmail !== summary.providerAccountEmail) {
137137
+ return loginParts.join(" \xB7 ");
137138
+ }
137139
+ return summary.provider === void 0 && loginParts.length > 0 ? loginParts.join(" \xB7 ") : void 0;
137140
+ }
137141
+
137142
+ // src/statusline/style.ts
136957
137143
  var SECONDS_PER_MINUTE2 = 60;
136958
137144
  var MINUTES_PER_HOUR4 = 60;
136959
137145
  var SECONDS_PER_DAY = 86400;
@@ -136961,8 +137147,6 @@ var THOUSAND = 1e3;
136961
137147
  var MILLION = 1e6;
136962
137148
  var TEN = 10;
136963
137149
  var TWENTY = 20;
136964
- var RESERVED_COLUMNS = 4;
136965
- var SEPARATOR2 = " | ";
136966
137150
  var FULL_PERCENT3 = 100;
136967
137151
  var ONE_PERCENT = 1;
136968
137152
  var RESET = `${ESCAPE}[0m`;
@@ -137016,6 +137200,24 @@ function formatDuration(seconds) {
137016
137200
  }
137017
137201
  return `${String(minutes)}m`;
137018
137202
  }
137203
+ function secondsUntil(resetAt, nowMs) {
137204
+ if (resetAt === void 0) {
137205
+ return void 0;
137206
+ }
137207
+ const resetMs = Date.parse(resetAt);
137208
+ return Number.isNaN(resetMs) ? void 0 : Math.max(0, Math.round((resetMs - nowMs) / THOUSAND));
137209
+ }
137210
+ function drawBar(fraction, cells, bands) {
137211
+ const clamped = Math.max(0, Math.min(1, fraction));
137212
+ const filled = Math.round(clamped * cells);
137213
+ const color = statusColor(clamped, true, bands);
137214
+ return color === "" ? `[${"\u2588".repeat(filled)}${"\u2591".repeat(cells - filled)}]` : `[${color}${"\u2588".repeat(filled)}${DIM}${"\u2591".repeat(cells - filled)}${RESET}]`;
137215
+ }
137216
+ function barCell(prefix, suffix, fraction, bands) {
137217
+ return { prefix, suffix, draw: (cells) => drawBar(fraction, cells, bands) };
137218
+ }
137219
+
137220
+ // src/statusline/elements/header/headroom.ts
137019
137221
  function headroomText(stats) {
137020
137222
  if (stats === void 0) {
137021
137223
  return void 0;
@@ -137028,6 +137230,43 @@ function headroomText(stats) {
137028
137230
  ].filter((part) => part !== void 0);
137029
137231
  return parts.length === 0 ? void 0 : `headroom ${parts.join(" \xB7 ")}`;
137030
137232
  }
137233
+ function headroomSegment({ summary }) {
137234
+ return headroomText(summary.headroom);
137235
+ }
137236
+
137237
+ // src/statusline/elements/header/identity.ts
137238
+ function identitySegment({ summary }) {
137239
+ if (summary.identity !== void 0 && summary.provider !== void 0 && summary.identity !== summary.providerAccountEmail && summary.identity !== summary.loginAccountEmail) {
137240
+ return summary.identity;
137241
+ }
137242
+ return void 0;
137243
+ }
137244
+
137245
+ // src/statusline/elements/header/model.ts
137246
+ function choiceNamesProvider(summary) {
137247
+ return summary.modelChoice !== void 0 && (summary.modelChoice.providers.length > 1 || summary.routedTarget !== void 0);
137248
+ }
137249
+ function modelSegment({ summary, view }) {
137250
+ const namesProvider = choiceNamesProvider(summary);
137251
+ const segment = summary.modelChoice !== void 0 && view.modelDisplayName !== void 0 && view.modelDisplayName !== "" ? `${view.modelDisplayName} -> ${namesProvider ? `${summary.modelChoice.provider}/${summary.modelChoice.served}` : summary.modelChoice.served}` : view.modelDisplayName;
137252
+ return segment !== void 0 && segment !== "" ? segment : void 0;
137253
+ }
137254
+
137255
+ // src/statusline/elements/header/provider.ts
137256
+ function providerSegment({ summary }) {
137257
+ if (summary.provider === void 0) {
137258
+ return void 0;
137259
+ }
137260
+ const account = [summary.providerAccountEmail, summary.providerPlan].filter((part) => part !== void 0);
137261
+ return account.length > 0 ? `${summary.provider} \xB7 ${account.join(" \xB7 ")}` : summary.provider;
137262
+ }
137263
+
137264
+ // src/statusline/elements/header/route.ts
137265
+ function routeSegment({ summary }) {
137266
+ return summary.routedTarget !== void 0 && !choiceNamesProvider(summary) ? `via ${summary.routedTarget}` : void 0;
137267
+ }
137268
+
137269
+ // src/statusline/elements/rows/context.ts
137031
137270
  function cacheHitText(hitFraction, bands) {
137032
137271
  const clamped = Math.max(0, Math.min(1, hitFraction));
137033
137272
  return ` (Cache: ${statusColor(clamped, false, bands)}${(clamped * FULL_PERCENT3).toFixed(0)}%${RESET})`;
@@ -137043,70 +137282,54 @@ function cacheShareText(view, bands) {
137043
137282
  }
137044
137283
  return "";
137045
137284
  }
137046
- function tierSuffixOf(tier) {
137047
- const match = /_(\d+x)$/i.exec(tier ?? "");
137048
- return match === null ? void 0 : match[1];
137285
+ function contextRow({ view, bands }) {
137286
+ const cells = [];
137287
+ if (view.contextUsedPercentage !== void 0) {
137288
+ const fraction = Math.max(0, Math.min(1, view.contextUsedPercentage / FULL_PERCENT3));
137289
+ const color = statusColor(fraction, true, bands);
137290
+ const percent2 = `${color}${view.contextUsedPercentage.toFixed(1)}%${RESET}`;
137291
+ const tokens = view.contextTotalTokens !== void 0 && view.contextWindowTokens !== void 0 ? `${formatTokens(view.contextTotalTokens)}/${formatTokens(view.contextWindowTokens)} ` : "";
137292
+ const cache = cacheShareText(view, bands);
137293
+ cells.push(barCell(`Ctx ${tokens}`, ` ${percent2}${cache}`, fraction, bands));
137294
+ }
137295
+ return { kind: "bars", cells };
137049
137296
  }
137050
- function accountPlanLabel(summary) {
137051
- switch (summary.loginOrganizationType) {
137052
- case void 0:
137053
- return planLabelOf(summary.loginRateLimitTier);
137054
- case "claude_max": {
137055
- const tier = tierSuffixOf(summary.loginRateLimitTier);
137056
- return tier === void 0 ? "Max" : `Max ${tier}`;
137297
+
137298
+ // src/statusline/elements/rows/quota.ts
137299
+ function quotaRow({ summary, nowMs, settings: settings2, bands }) {
137300
+ const cells = [];
137301
+ const drawWindow = (label, fraction, resetsAt) => {
137302
+ const clamped = Math.max(0, Math.min(1, fraction));
137303
+ const color = statusColor(clamped, true, bands);
137304
+ cells.push(barCell(`${label} `, ` ${color}${(fraction * FULL_PERCENT3).toFixed(1)}%${RESET} (${formatDuration(secondsUntil(resetsAt, nowMs))})`, clamped, bands));
137305
+ };
137306
+ if (summary.quotaFamilies.length > 0) {
137307
+ for (const window of summary.quotaFamilies) {
137308
+ drawWindow(window.measures, window.utilization, window.resetsAt);
137057
137309
  }
137058
- case "claude_pro":
137059
- return "Pro";
137060
- case "claude_team":
137061
- if (summary.loginSeatTier === "team_standard") {
137062
- return "Team Standard";
137063
- }
137064
- if (summary.loginSeatTier === "team_tier_1") {
137065
- return "Team Premium";
137310
+ } else {
137311
+ if (summary.fiveHourUsed !== void 0) {
137312
+ drawWindow(settings2.labels.fiveHour, summary.fiveHourUsed / FULL_PERCENT3, summary.fiveHourResetAt);
137313
+ }
137314
+ if (summary.sevenDayUsed !== void 0) {
137315
+ drawWindow(settings2.labels.sevenDay, summary.sevenDayUsed / FULL_PERCENT3, summary.sevenDayResetAt);
137316
+ }
137317
+ if (summary.fiveHourUsed === void 0 && summary.sevenDayUsed === void 0) {
137318
+ for (const window of summary.providerQuotaWindows) {
137319
+ drawWindow(window.measures, window.utilization, window.resetsAt);
137066
137320
  }
137067
- return "Team";
137068
- case "claude_enterprise":
137069
- return "Enterprise";
137070
- default:
137071
- return summary.loginOrganizationType;
137072
- }
137073
- }
137074
- function planLabelOf(tier) {
137075
- if (tier === void 0 || tier === "") {
137076
- return void 0;
137077
- }
137078
- const cleaned = tier.startsWith("default_") ? tier.slice("default_".length) : tier;
137079
- if (cleaned === "free") {
137080
- return "Free";
137081
- }
137082
- const maxWithMultiplier = /^claude_max_(\d+)x$/.exec(cleaned);
137083
- if (maxWithMultiplier !== null) {
137084
- return `Max ${maxWithMultiplier[1] ?? ""}x`;
137085
- }
137086
- if (cleaned === "claude_max") {
137087
- return "Max";
137088
- }
137089
- if (cleaned === "claude_pro") {
137090
- return "Pro";
137091
- }
137092
- return cleaned;
137093
- }
137094
- function secondsUntil(resetAt, nowMs) {
137095
- if (resetAt === void 0) {
137096
- return void 0;
137321
+ }
137097
137322
  }
137098
- const resetMs = Date.parse(resetAt);
137099
- return Number.isNaN(resetMs) ? void 0 : Math.max(0, Math.round((resetMs - nowMs) / THOUSAND));
137100
- }
137101
- function drawBar(fraction, cells, bands) {
137102
- const clamped = Math.max(0, Math.min(1, fraction));
137103
- const filled = Math.round(clamped * cells);
137104
- const color = statusColor(clamped, true, bands);
137105
- return color === "" ? `[${"\u2588".repeat(filled)}${"\u2591".repeat(cells - filled)}]` : `[${color}${"\u2588".repeat(filled)}${DIM}${"\u2591".repeat(cells - filled)}${RESET}]`;
137106
- }
137107
- function barCell(prefix, suffix, fraction, bands) {
137108
- return { prefix, suffix, draw: (cells) => drawBar(fraction, cells, bands) };
137323
+ return { kind: "bars", cells };
137109
137324
  }
137325
+
137326
+ // src/statusline/elements/registry.ts
137327
+ var ELEMENTS = {
137328
+ header: { model: modelSegment, provider: providerSegment, route: routeSegment, account: accountSegment, identity: identitySegment, headroom: headroomSegment },
137329
+ rows: { context: contextRow, quota: quotaRow }
137330
+ };
137331
+
137332
+ // src/statusline/headerLayout.ts
137110
137333
  function justify(texts, maxWidth, separator) {
137111
137334
  if (texts.length < 2) {
137112
137335
  return texts.join(separator);
@@ -137156,80 +137379,38 @@ function layoutHeader(texts, maxWidth, separator) {
137156
137379
  }
137157
137380
  return lines.map((line) => justify(line, maxWidth, separator)).join("\n");
137158
137381
  }
137159
- function renderStatuslineBlock(summary, view, terminalWidth, nowMs, settings2 = STATUSLINE_DEFAULTS) {
137160
- const segments = {};
137161
- const choiceNamesProvider = summary.modelChoice !== void 0 && (summary.modelChoice.providers.length > 1 || summary.routedTarget !== void 0);
137162
- const modelSegment = summary.modelChoice !== void 0 && view.modelDisplayName !== void 0 && view.modelDisplayName !== "" ? `${view.modelDisplayName} -> ${choiceNamesProvider ? `${summary.modelChoice.provider}/${summary.modelChoice.served}` : summary.modelChoice.served}` : view.modelDisplayName;
137163
- if (modelSegment !== void 0 && modelSegment !== "") {
137164
- segments.model = modelSegment;
137165
- }
137166
- if (summary.provider !== void 0) {
137167
- const account = [summary.providerAccountEmail, summary.providerPlan].filter((part) => part !== void 0);
137168
- segments.provider = account.length > 0 ? `${summary.provider} \xB7 ${account.join(" \xB7 ")}` : summary.provider;
137169
- }
137170
- if (summary.routedTarget !== void 0 && !choiceNamesProvider) {
137171
- segments.route = `via ${summary.routedTarget}`;
137172
- }
137173
- const loginPlan = summary.provider === void 0 ? summary.loginPlan ?? accountPlanLabel(summary) : void 0;
137174
- const loginOrgName = summary.loginOrganizationType === "claude_team" || summary.loginOrganizationType === "claude_enterprise" ? summary.loginOrganizationName : void 0;
137175
- const loginParts = [summary.loginAccountEmail, loginOrgName, loginPlan].filter((part) => part !== void 0);
137176
- if (summary.loginAccountEmail !== void 0 && summary.loginAccountEmail !== summary.providerAccountEmail) {
137177
- segments.account = loginParts.join(" \xB7 ");
137178
- } else if (summary.provider === void 0 && loginParts.length > 0) {
137179
- segments.account = loginParts.join(" \xB7 ");
137180
- }
137181
- if (summary.identity !== void 0 && summary.provider !== void 0 && summary.identity !== summary.providerAccountEmail && summary.identity !== summary.loginAccountEmail) {
137182
- segments.identity = summary.identity;
137183
- }
137184
- const savings = headroomText(summary.headroom);
137185
- if (savings !== void 0) {
137186
- segments.headroom = savings;
137187
- }
137188
- const header = settings2.header.flatMap((name) => segments[name] ?? []);
137189
- const bands = { warnAt: settings2.warnAt, criticalAt: settings2.criticalAt };
137190
- const contextGroup = [];
137191
- if (view.contextUsedPercentage !== void 0) {
137192
- const fraction = Math.max(0, Math.min(1, view.contextUsedPercentage / FULL_PERCENT3));
137193
- const color = statusColor(fraction, true, bands);
137194
- const percent2 = `${color}${view.contextUsedPercentage.toFixed(1)}%${RESET}`;
137195
- const tokens = view.contextTotalTokens !== void 0 && view.contextWindowTokens !== void 0 ? `${formatTokens(view.contextTotalTokens)}/${formatTokens(view.contextWindowTokens)} ` : "";
137196
- const cache = cacheShareText(view, bands);
137197
- contextGroup.push(barCell(`Ctx ${tokens}`, ` ${percent2}${cache}`, fraction, bands));
137198
- }
137199
- const quotaGroup = [];
137200
- const drawWindow = (label, fraction, resetsAt) => {
137201
- const clamped = Math.max(0, Math.min(1, fraction));
137202
- const color = statusColor(clamped, true, bands);
137203
- quotaGroup.push(barCell(`${label} `, ` ${color}${(fraction * FULL_PERCENT3).toFixed(1)}%${RESET} (${formatDuration(secondsUntil(resetsAt, nowMs))})`, clamped, bands));
137204
- };
137205
- if (summary.quotaFamilies.length > 0) {
137206
- for (const window of summary.quotaFamilies) {
137207
- drawWindow(window.measures, window.utilization, window.resetsAt);
137208
- }
137209
- } else {
137210
- if (summary.fiveHourUsed !== void 0) {
137211
- drawWindow(settings2.fiveHourLabel, summary.fiveHourUsed / FULL_PERCENT3, summary.fiveHourResetAt);
137212
- }
137213
- if (summary.sevenDayUsed !== void 0) {
137214
- drawWindow(settings2.sevenDayLabel, summary.sevenDayUsed / FULL_PERCENT3, summary.sevenDayResetAt);
137215
- }
137216
- if (summary.fiveHourUsed === void 0 && summary.sevenDayUsed === void 0) {
137217
- for (const window of summary.providerQuotaWindows) {
137218
- drawWindow(window.measures, window.utilization, window.resetsAt);
137219
- }
137220
- }
137221
- }
137382
+
137383
+ // src/statusline/render.ts
137384
+ var RESERVED_COLUMNS = 4;
137385
+ var SEPARATOR2 = " | ";
137386
+ function renderStatuslineBlock(summary, view, terminalWidth, nowMs, settings2 = STATUSLINE_DEFAULTS, elements = ELEMENTS) {
137387
+ const context = { summary, view, nowMs, settings: settings2, bands: settings2.bands };
137388
+ const header = settings2.layout.header.flatMap((name) => elements.header[name](context) ?? []);
137222
137389
  const width = Math.max(TWENTY, terminalWidth - RESERVED_COLUMNS);
137223
137390
  const lines = [];
137224
137391
  if (header.length > 0) {
137225
137392
  lines.push(layoutHeader(header, width, SEPARATOR2));
137226
137393
  }
137227
- const groups = { context: contextGroup, quota: quotaGroup };
137228
- lines.push(...layoutBarGrid(settings2.bars.map((name) => groups[name]), width, SEPARATOR2, settings2.barWidth));
137394
+ let barGroups = [];
137395
+ const flushBars = () => {
137396
+ lines.push(...layoutBarGrid(barGroups, width, SEPARATOR2, settings2.bar.width));
137397
+ barGroups = [];
137398
+ };
137399
+ for (const name of settings2.layout.rows) {
137400
+ const output2 = elements.rows[name](context);
137401
+ if (output2.kind === "bars") {
137402
+ barGroups.push(output2.cells);
137403
+ } else {
137404
+ flushBars();
137405
+ lines.push(...output2.lines);
137406
+ }
137407
+ }
137408
+ flushBars();
137229
137409
  return lines.join("\n");
137230
137410
  }
137231
137411
 
137232
137412
  // src/statusline/commands.ts
137413
+ init_keys();
137233
137414
  init_settings2();
137234
137415
 
137235
137416
  // src/statusline/width.ts
@@ -137281,8 +137462,9 @@ async function readAllStdin() {
137281
137462
  }
137282
137463
  var ROUTED_TARGET_LOOKBACK_MS = 36e5;
137283
137464
  function registerStatuslineCommand(program2, deps) {
137465
+ const statusline = program2.command("statusline");
137284
137466
  withExamples(
137285
- 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 () => {
137467
+ 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 () => {
137286
137468
  const stdin2 = await readAllStdin();
137287
137469
  let payload;
137288
137470
  try {
@@ -137370,6 +137552,19 @@ function registerStatuslineCommand(program2, deps) {
137370
137552
  }),
137371
137553
  ["$ agent-shim statusline # a client's statusline setting names this; it renders or delegates"]
137372
137554
  );
137555
+ registerStatuslineKeys(statusline);
137556
+ }
137557
+ function registerStatuslineKeys(statusline) {
137558
+ withExamples(
137559
+ statusline.command("keys").description("List every setting of the built-in statusline with its kind, its default and what it does.").option("--json", "Print the settings as JSON."),
137560
+ ["agent-shim statusline keys", "agent-shim statusline keys --json"]
137561
+ ).action((options) => {
137562
+ if (options.json === true) {
137563
+ printJson(statuslineKeys());
137564
+ return;
137565
+ }
137566
+ console.log(formatStatuslineKeys(statuslineKeys()));
137567
+ });
137373
137568
  }
137374
137569
 
137375
137570
  // node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.0_supports-color@7.2.0_zod@4.6.5/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
@@ -145437,7 +145632,7 @@ var Protocol = class {
145437
145632
  };
145438
145633
  }
145439
145634
  };
145440
- function isPlainObject3(value2) {
145635
+ function isPlainObject4(value2) {
145441
145636
  return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
145442
145637
  }
145443
145638
  function mergeCapabilities(base, additional) {
@@ -145448,7 +145643,7 @@ function mergeCapabilities(base, additional) {
145448
145643
  if (addValue === void 0)
145449
145644
  continue;
145450
145645
  const baseValue = result[k10];
145451
- if (isPlainObject3(baseValue) && isPlainObject3(addValue)) {
145646
+ if (isPlainObject4(baseValue) && isPlainObject4(addValue)) {
145452
145647
  result[k10] = { ...baseValue, ...addValue };
145453
145648
  } else {
145454
145649
  result[k10] = addValue;