agent-shim 11.51.0 → 11.52.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
@@ -25040,6 +25040,9 @@ 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 isSingleVisibleGrapheme(text2) {
25044
+ return [...GRAPHEMES.segment(text2)].length === 1 && !/[\p{C}\p{Z}]/u.test(text2);
25045
+ }
25043
25046
  function isPlainObject2(value2) {
25044
25047
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
25045
25048
  }
@@ -25060,17 +25063,41 @@ function resolveStatusline(settings2) {
25060
25063
  }
25061
25064
  return resolved;
25062
25065
  }
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;
25066
+ var STATUSLINE_HEADER_SEGMENTS, STATUSLINE_ROWS, STATUSLINE_COLOUR_NAMES, MAX_PERCENT, MAX_STATUSLINE_PALETTE_INDEX, MAX_STATUSLINE_LABEL_CHARS, MAX_BAR_CELLS, LABEL_RE2, colourValue, GRAPHEMES, barCharacter, labelText, wholePercent, SHAPES, StatuslineSchema, ResolvedStatuslineSchema, STATUSLINE_DEFAULTS, STATUSLINE_ENV;
25064
25067
  var init_statusline = __esm({
25065
25068
  "src/config/statusline.ts"() {
25066
25069
  "use strict";
25067
25070
  init_zod();
25068
25071
  STATUSLINE_HEADER_SEGMENTS = ["model", "provider", "route", "account", "identity", "headroom"];
25069
25072
  STATUSLINE_ROWS = ["context", "quota"];
25073
+ STATUSLINE_COLOUR_NAMES = [
25074
+ "default",
25075
+ "dim",
25076
+ "black",
25077
+ "red",
25078
+ "green",
25079
+ "yellow",
25080
+ "blue",
25081
+ "magenta",
25082
+ "cyan",
25083
+ "white",
25084
+ "brightBlack",
25085
+ "brightRed",
25086
+ "brightGreen",
25087
+ "brightYellow",
25088
+ "brightBlue",
25089
+ "brightMagenta",
25090
+ "brightCyan",
25091
+ "brightWhite"
25092
+ ];
25070
25093
  MAX_PERCENT = 100;
25094
+ MAX_STATUSLINE_PALETTE_INDEX = 255;
25071
25095
  MAX_STATUSLINE_LABEL_CHARS = 12;
25072
25096
  MAX_BAR_CELLS = 40;
25073
25097
  LABEL_RE2 = /^[^\p{C}\p{Z}]+(?: [^\p{C}\p{Z}]+)*$/u;
25098
+ colourValue = external_exports.union([external_exports.enum(STATUSLINE_COLOUR_NAMES), external_exports.number().int().min(0).max(MAX_STATUSLINE_PALETTE_INDEX), external_exports.string().regex(/^#[0-9a-fA-F]{6}$/, "must be a colour name, a palette index from 0 to 255 or #rrggbb")]);
25099
+ GRAPHEMES = new Intl.Segmenter(void 0, { granularity: "grapheme" });
25100
+ barCharacter = external_exports.string().refine(isSingleVisibleGrapheme, "must be a single visible character");
25074
25101
  labelText = external_exports.string().max(MAX_STATUSLINE_LABEL_CHARS).regex(LABEL_RE2, "must be visible text without control characters");
25075
25102
  wholePercent = external_exports.number().int().min(1).max(MAX_PERCENT);
25076
25103
  SHAPES = {
@@ -25087,26 +25114,50 @@ var init_statusline = __esm({
25087
25114
  sevenDay: labelText.describe("The name of the weekly subscription window.")
25088
25115
  },
25089
25116
  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.")
25117
+ 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."),
25118
+ filled: barCharacter.describe("The character that draws the used part of a bar."),
25119
+ empty: barCharacter.describe("The character that draws the unused part of a bar.")
25120
+ },
25121
+ colours: {
25122
+ context: colourValue.describe("The colour of the context bar and its figures below the warning threshold."),
25123
+ usage: colourValue.describe("The colour of the quota bars and their figures below the warning threshold."),
25124
+ warning: colourValue.describe("The colour of the context bar at or above bands.warnAt, and of a cache hit share that is middling."),
25125
+ usageWarning: colourValue.describe("The colour of a quota bar at or above bands.warnAt."),
25126
+ critical: colourValue.describe("The colour of a bar at or above bands.criticalAt, and of a cache hit share that is nearly nothing."),
25127
+ model: colourValue.describe("The colour of the model and provider segments."),
25128
+ label: colourValue.describe("The colour of labels and secondary text: row labels, and the route, account, identity and headroom segments."),
25129
+ empty: colourValue.describe("The colour of the unused part of a bar.")
25091
25130
  }
25092
25131
  };
25093
25132
  StatuslineSchema = external_exports.strictObject({
25094
25133
  layout: external_exports.strictObject(SHAPES.layout).partial().optional(),
25095
25134
  bands: external_exports.strictObject(SHAPES.bands).partial().optional(),
25096
25135
  labels: external_exports.strictObject(SHAPES.labels).partial().optional(),
25097
- bar: external_exports.strictObject(SHAPES.bar).partial().optional()
25136
+ bar: external_exports.strictObject(SHAPES.bar).partial().optional(),
25137
+ colours: external_exports.strictObject(SHAPES.colours).partial().optional()
25098
25138
  });
25099
25139
  ResolvedStatuslineSchema = external_exports.strictObject({
25100
25140
  layout: external_exports.strictObject(SHAPES.layout),
25101
25141
  bands: external_exports.strictObject(SHAPES.bands),
25102
25142
  labels: external_exports.strictObject(SHAPES.labels),
25103
- bar: external_exports.strictObject(SHAPES.bar)
25143
+ bar: external_exports.strictObject(SHAPES.bar),
25144
+ colours: external_exports.strictObject(SHAPES.colours)
25104
25145
  });
25105
25146
  STATUSLINE_DEFAULTS = {
25106
25147
  layout: { header: [...STATUSLINE_HEADER_SEGMENTS], rows: [...STATUSLINE_ROWS] },
25107
25148
  bands: { warnAt: 70, criticalAt: 90 },
25108
25149
  labels: { fiveHour: "5h", sevenDay: "Wk" },
25109
- bar: { width: 10 }
25150
+ bar: { width: 10, filled: "\u2588", empty: "\u2591" },
25151
+ colours: {
25152
+ context: "green",
25153
+ usage: "green",
25154
+ warning: "yellow",
25155
+ usageWarning: "yellow",
25156
+ critical: "red",
25157
+ model: "default",
25158
+ label: "default",
25159
+ empty: "brightBlack"
25160
+ }
25110
25161
  };
25111
25162
  STATUSLINE_ENV = "AGENT_SHIM_STATUSLINE";
25112
25163
  }
@@ -31901,6 +31952,9 @@ function keyOf(path66, leaf) {
31901
31952
  if (leaf instanceof external_exports.ZodString) {
31902
31953
  return { ...common, kind: "text", choices: [] };
31903
31954
  }
31955
+ if (leaf instanceof external_exports.ZodUnion) {
31956
+ return { ...common, kind: "colour", choices: [...STATUSLINE_COLOUR_NAMES] };
31957
+ }
31904
31958
  if (leaf instanceof external_exports.ZodEnum) {
31905
31959
  return { ...common, kind: "choice", choices: Object.values(leaf.enum).map(String) };
31906
31960
  }
@@ -31917,7 +31971,7 @@ function statuslineKeys() {
31917
31971
  }
31918
31972
  function formatStatuslineKeys(keys) {
31919
31973
  return keys.map((key) => {
31920
- const takes = key.kind === "choice" || key.kind === "list" ? `${key.kind} of ${key.choices.join(", ")}` : key.kind;
31974
+ const takes = key.kind === "choice" || key.kind === "list" || key.kind === "colour" ? `${key.kind} of ${key.choices.join(", ")}` : key.kind;
31921
31975
  return `${key.path} (${takes}; default ${JSON.stringify(key.defaultValue)})
31922
31976
  ${key.description}`;
31923
31977
  }).join("\n");
@@ -31957,6 +32011,8 @@ function parseStatuslineAssignment(text2) {
31957
32011
  case "text":
31958
32012
  case "choice":
31959
32013
  return { path: path66, value: raw };
32014
+ case "colour":
32015
+ return { path: path66, value: /^\d+$/.test(raw) ? Number(raw) : raw };
31960
32016
  case "list":
31961
32017
  return { path: path66, value: raw === "" ? [] : raw.split(",") };
31962
32018
  default:
@@ -36151,7 +36207,7 @@ var init_package = __esm({
36151
36207
  "package.json"() {
36152
36208
  package_default = {
36153
36209
  name: "agent-shim",
36154
- version: "11.51.0",
36210
+ version: "11.52.0",
36155
36211
  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.",
36156
36212
  license: "MIT",
36157
36213
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -137139,6 +137195,62 @@ function accountSegment({ summary }) {
137139
137195
  return summary.provider === void 0 && loginParts.length > 0 ? loginParts.join(" \xB7 ") : void 0;
137140
137196
  }
137141
137197
 
137198
+ // src/statusline/palette.ts
137199
+ init_statusline();
137200
+ var RESET = `${ESCAPE}[0m`;
137201
+ var SGR_BY_NAME = {
137202
+ default: "",
137203
+ dim: "2",
137204
+ black: "30",
137205
+ red: "31",
137206
+ green: "32",
137207
+ yellow: "33",
137208
+ blue: "34",
137209
+ magenta: "35",
137210
+ cyan: "36",
137211
+ white: "37",
137212
+ brightBlack: "90",
137213
+ brightRed: "91",
137214
+ brightGreen: "92",
137215
+ brightYellow: "93",
137216
+ brightBlue: "94",
137217
+ brightMagenta: "95",
137218
+ brightCyan: "96",
137219
+ brightWhite: "97"
137220
+ };
137221
+ function isColourName(value2) {
137222
+ return STATUSLINE_COLOUR_NAMES.some((name) => name === value2);
137223
+ }
137224
+ var CHANNELS = 3;
137225
+ var CHANNEL_DIGITS = 2;
137226
+ var HEX_RADIX2 = 16;
137227
+ function sgrOf(value2) {
137228
+ if (typeof value2 === "number") {
137229
+ return `38;5;${String(value2)}`;
137230
+ }
137231
+ if (value2.startsWith("#")) {
137232
+ const channels = Array.from({ length: CHANNELS }, (_, index) => Number.parseInt(value2.slice(1 + index * CHANNEL_DIGITS, 1 + (index + 1) * CHANNEL_DIGITS), HEX_RADIX2));
137233
+ return `38;2;${channels.join(";")}`;
137234
+ }
137235
+ return isColourName(value2) ? SGR_BY_NAME[value2] : "";
137236
+ }
137237
+ function colourEnabled(env) {
137238
+ return env.NO_COLOR === void 0;
137239
+ }
137240
+ function createPalette(colours, enabled) {
137241
+ const ansi = (role) => {
137242
+ const sgr = enabled ? sgrOf(colours[role]) : "";
137243
+ return sgr === "" ? "" : `${ESCAPE}[${sgr}m`;
137244
+ };
137245
+ return {
137246
+ ansi,
137247
+ paint: (role, text2) => {
137248
+ const start = ansi(role);
137249
+ return start === "" ? text2 : `${start}${text2}${RESET}`;
137250
+ }
137251
+ };
137252
+ }
137253
+
137142
137254
  // src/statusline/style.ts
137143
137255
  var SECONDS_PER_MINUTE2 = 60;
137144
137256
  var MINUTES_PER_HOUR4 = 60;
@@ -137149,30 +137261,24 @@ var TEN = 10;
137149
137261
  var TWENTY = 20;
137150
137262
  var FULL_PERCENT3 = 100;
137151
137263
  var ONE_PERCENT = 1;
137152
- var RESET = `${ESCAPE}[0m`;
137153
- var DIM = `${ESCAPE}[90m`;
137154
- var GREEN = `${ESCAPE}[32m`;
137155
- var YELLOW = `${ESCAPE}[33m`;
137156
- var RED = `${ESCAPE}[31m`;
137157
- function colorize() {
137158
- return process.env.NO_COLOR === void 0;
137159
- }
137160
- function statusColor(fraction, isUsedMetric, bands) {
137161
- if (!colorize()) {
137162
- return "";
137163
- }
137164
- const yellowAt = bands.warnAt / FULL_PERCENT3;
137165
- const redAt = bands.criticalAt / FULL_PERCENT3;
137264
+ function withColor(color, text2) {
137265
+ return color === "" ? text2 : `${color}${text2}${RESET}`;
137266
+ }
137267
+ function statusColor(fraction, isUsedMetric, style) {
137268
+ const yellowAt = style.bands.warnAt / FULL_PERCENT3;
137269
+ const redAt = style.bands.criticalAt / FULL_PERCENT3;
137270
+ const warningRole = style.okRole === "usage" ? "usageWarning" : "warning";
137271
+ const { ansi } = style.palette;
137166
137272
  if (isUsedMetric) {
137167
137273
  if (fraction >= redAt) {
137168
- return RED;
137274
+ return ansi("critical");
137169
137275
  }
137170
- return fraction >= yellowAt ? YELLOW : GREEN;
137276
+ return fraction >= yellowAt ? ansi(warningRole) : ansi(style.okRole);
137171
137277
  }
137172
137278
  if (fraction <= 1 - redAt) {
137173
- return RED;
137279
+ return ansi("critical");
137174
137280
  }
137175
- return fraction <= 1 - yellowAt ? YELLOW : GREEN;
137281
+ return fraction <= 1 - yellowAt ? ansi(warningRole) : ansi(style.okRole);
137176
137282
  }
137177
137283
  function formatTokens(num) {
137178
137284
  if (num >= MILLION) {
@@ -137207,14 +137313,19 @@ function secondsUntil(resetAt, nowMs) {
137207
137313
  const resetMs = Date.parse(resetAt);
137208
137314
  return Number.isNaN(resetMs) ? void 0 : Math.max(0, Math.round((resetMs - nowMs) / THOUSAND));
137209
137315
  }
137210
- function drawBar(fraction, cells, bands) {
137316
+ function drawBar(fraction, cells, style) {
137211
137317
  const clamped = Math.max(0, Math.min(1, fraction));
137212
137318
  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}]`;
137319
+ const color = statusColor(clamped, true, style);
137320
+ const emptyColor = style.palette.ansi("empty");
137321
+ const body = `${style.filled.repeat(filled)}${style.empty.repeat(cells - filled)}`;
137322
+ if (color === "" && emptyColor === "") {
137323
+ return `[${body}]`;
137324
+ }
137325
+ return `[${color}${style.filled.repeat(filled)}${emptyColor}${style.empty.repeat(cells - filled)}${RESET}]`;
137215
137326
  }
137216
- function barCell(prefix, suffix, fraction, bands) {
137217
- return { prefix, suffix, draw: (cells) => drawBar(fraction, cells, bands) };
137327
+ function barCell(prefix, suffix, fraction, style) {
137328
+ return { prefix, suffix, draw: (cells) => drawBar(fraction, cells, style) };
137218
137329
  }
137219
137330
 
137220
137331
  // src/statusline/elements/header/headroom.ts
@@ -137266,42 +137377,51 @@ function routeSegment({ summary }) {
137266
137377
  return summary.routedTarget !== void 0 && !choiceNamesProvider(summary) ? `via ${summary.routedTarget}` : void 0;
137267
137378
  }
137268
137379
 
137380
+ // src/statusline/elements/context.ts
137381
+ function barStyleOf({ settings: settings2, palette }, okRole) {
137382
+ return { bands: settings2.bands, palette, okRole, filled: settings2.bar.filled, empty: settings2.bar.empty };
137383
+ }
137384
+
137269
137385
  // src/statusline/elements/rows/context.ts
137270
- function cacheHitText(hitFraction, bands) {
137386
+ function cacheHitText(hitFraction, style) {
137271
137387
  const clamped = Math.max(0, Math.min(1, hitFraction));
137272
- return ` (Cache: ${statusColor(clamped, false, bands)}${(clamped * FULL_PERCENT3).toFixed(0)}%${RESET})`;
137388
+ return ` (Cache: ${withColor(statusColor(clamped, false, style), `${(clamped * FULL_PERCENT3).toFixed(0)}%`)})`;
137273
137389
  }
137274
- function cacheShareText(view, bands) {
137390
+ function cacheShareText(view, style) {
137275
137391
  const hitRatio = view.cacheHitRatio;
137276
137392
  if (hitRatio !== void 0 && Number.isFinite(hitRatio)) {
137277
- return cacheHitText(hitRatio, bands);
137393
+ return cacheHitText(hitRatio, style);
137278
137394
  }
137279
137395
  const promptTotal = (view.cacheReadTokens ?? 0) + (view.freshInputTokens ?? 0);
137280
137396
  if (promptTotal > 0 && (view.cacheReadTokens ?? 0) > 0) {
137281
- return cacheHitText((view.cacheReadTokens ?? 0) / promptTotal, bands);
137397
+ return cacheHitText((view.cacheReadTokens ?? 0) / promptTotal, style);
137282
137398
  }
137283
137399
  return "";
137284
137400
  }
137285
- function contextRow({ view, bands }) {
137401
+ function contextRow(context) {
137402
+ const { view, palette } = context;
137403
+ const style = barStyleOf(context, "context");
137286
137404
  const cells = [];
137287
137405
  if (view.contextUsedPercentage !== void 0) {
137288
137406
  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}`;
137407
+ const color = statusColor(fraction, true, style);
137408
+ const percent2 = withColor(color, `${view.contextUsedPercentage.toFixed(1)}%`);
137291
137409
  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));
137410
+ const cache = cacheShareText(view, style);
137411
+ cells.push(barCell(palette.paint("label", `Ctx ${tokens}`), ` ${percent2}${cache}`, fraction, style));
137294
137412
  }
137295
137413
  return { kind: "bars", cells };
137296
137414
  }
137297
137415
 
137298
137416
  // src/statusline/elements/rows/quota.ts
137299
- function quotaRow({ summary, nowMs, settings: settings2, bands }) {
137417
+ function quotaRow(context) {
137418
+ const { summary, nowMs, settings: settings2, palette } = context;
137419
+ const style = barStyleOf(context, "usage");
137300
137420
  const cells = [];
137301
137421
  const drawWindow = (label, fraction, resetsAt) => {
137302
137422
  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));
137423
+ const color = statusColor(clamped, true, style);
137424
+ cells.push(barCell(palette.paint("label", `${label} `), ` ${withColor(color, `${(fraction * FULL_PERCENT3).toFixed(1)}%`)} (${formatDuration(secondsUntil(resetsAt, nowMs))})`, clamped, style));
137305
137425
  };
137306
137426
  if (summary.quotaFamilies.length > 0) {
137307
137427
  for (const window of summary.quotaFamilies) {
@@ -137324,6 +137444,14 @@ function quotaRow({ summary, nowMs, settings: settings2, bands }) {
137324
137444
  }
137325
137445
 
137326
137446
  // src/statusline/elements/registry.ts
137447
+ var HEADER_ROLES = {
137448
+ model: "model",
137449
+ provider: "model",
137450
+ route: "label",
137451
+ account: "label",
137452
+ identity: "label",
137453
+ headroom: "label"
137454
+ };
137327
137455
  var ELEMENTS = {
137328
137456
  header: { model: modelSegment, provider: providerSegment, route: routeSegment, account: accountSegment, identity: identitySegment, headroom: headroomSegment },
137329
137457
  rows: { context: contextRow, quota: quotaRow }
@@ -137383,9 +137511,12 @@ function layoutHeader(texts, maxWidth, separator) {
137383
137511
  // src/statusline/render.ts
137384
137512
  var RESERVED_COLUMNS = 4;
137385
137513
  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) ?? []);
137514
+ function renderStatuslineBlock(summary, view, terminalWidth, nowMs, settings2 = STATUSLINE_DEFAULTS, elements = ELEMENTS, env = process.env) {
137515
+ const context = { summary, view, nowMs, settings: settings2, palette: createPalette(settings2.colours, colourEnabled(env)) };
137516
+ const header = settings2.layout.header.flatMap((name) => {
137517
+ const text2 = elements.header[name](context);
137518
+ return text2 === void 0 ? [] : context.palette.paint(HEADER_ROLES[name], text2);
137519
+ });
137389
137520
  const width = Math.max(TWENTY, terminalWidth - RESERVED_COLUMNS);
137390
137521
  const lines = [];
137391
137522
  if (header.length > 0) {
package/dist/index.cjs CHANGED
@@ -142,6 +142,9 @@ var init_proxyBypass = __esm({
142
142
  function distinctList(member) {
143
143
  return import_zod.z.array(member).refine((items) => new Set(items).size === items.length, "must not repeat a segment");
144
144
  }
145
+ function isSingleVisibleGrapheme(text) {
146
+ return [...GRAPHEMES.segment(text)].length === 1 && !/[\p{C}\p{Z}]/u.test(text);
147
+ }
145
148
  function isPlainObject(value) {
146
149
  return typeof value === "object" && value !== null && !Array.isArray(value);
147
150
  }
@@ -162,17 +165,41 @@ function resolveStatusline(settings) {
162
165
  }
163
166
  return resolved;
164
167
  }
165
- var import_zod, 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;
168
+ var import_zod, STATUSLINE_HEADER_SEGMENTS, STATUSLINE_ROWS, STATUSLINE_COLOUR_NAMES, MAX_PERCENT, MAX_STATUSLINE_PALETTE_INDEX, MAX_STATUSLINE_LABEL_CHARS, MAX_BAR_CELLS, LABEL_RE2, colourValue, GRAPHEMES, barCharacter, labelText, wholePercent, SHAPES, StatuslineSchema, ResolvedStatuslineSchema, STATUSLINE_DEFAULTS, STATUSLINE_ENV;
166
169
  var init_statusline = __esm({
167
170
  "src/config/statusline.ts"() {
168
171
  "use strict";
169
172
  import_zod = require("zod");
170
173
  STATUSLINE_HEADER_SEGMENTS = ["model", "provider", "route", "account", "identity", "headroom"];
171
174
  STATUSLINE_ROWS = ["context", "quota"];
175
+ STATUSLINE_COLOUR_NAMES = [
176
+ "default",
177
+ "dim",
178
+ "black",
179
+ "red",
180
+ "green",
181
+ "yellow",
182
+ "blue",
183
+ "magenta",
184
+ "cyan",
185
+ "white",
186
+ "brightBlack",
187
+ "brightRed",
188
+ "brightGreen",
189
+ "brightYellow",
190
+ "brightBlue",
191
+ "brightMagenta",
192
+ "brightCyan",
193
+ "brightWhite"
194
+ ];
172
195
  MAX_PERCENT = 100;
196
+ MAX_STATUSLINE_PALETTE_INDEX = 255;
173
197
  MAX_STATUSLINE_LABEL_CHARS = 12;
174
198
  MAX_BAR_CELLS = 40;
175
199
  LABEL_RE2 = /^[^\p{C}\p{Z}]+(?: [^\p{C}\p{Z}]+)*$/u;
200
+ colourValue = import_zod.z.union([import_zod.z.enum(STATUSLINE_COLOUR_NAMES), import_zod.z.number().int().min(0).max(MAX_STATUSLINE_PALETTE_INDEX), import_zod.z.string().regex(/^#[0-9a-fA-F]{6}$/, "must be a colour name, a palette index from 0 to 255 or #rrggbb")]);
201
+ GRAPHEMES = new Intl.Segmenter(void 0, { granularity: "grapheme" });
202
+ barCharacter = import_zod.z.string().refine(isSingleVisibleGrapheme, "must be a single visible character");
176
203
  labelText = import_zod.z.string().max(MAX_STATUSLINE_LABEL_CHARS).regex(LABEL_RE2, "must be visible text without control characters");
177
204
  wholePercent = import_zod.z.number().int().min(1).max(MAX_PERCENT);
178
205
  SHAPES = {
@@ -189,26 +216,50 @@ var init_statusline = __esm({
189
216
  sevenDay: labelText.describe("The name of the weekly subscription window.")
190
217
  },
191
218
  bar: {
192
- width: import_zod.z.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.")
219
+ width: import_zod.z.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."),
220
+ filled: barCharacter.describe("The character that draws the used part of a bar."),
221
+ empty: barCharacter.describe("The character that draws the unused part of a bar.")
222
+ },
223
+ colours: {
224
+ context: colourValue.describe("The colour of the context bar and its figures below the warning threshold."),
225
+ usage: colourValue.describe("The colour of the quota bars and their figures below the warning threshold."),
226
+ warning: colourValue.describe("The colour of the context bar at or above bands.warnAt, and of a cache hit share that is middling."),
227
+ usageWarning: colourValue.describe("The colour of a quota bar at or above bands.warnAt."),
228
+ critical: colourValue.describe("The colour of a bar at or above bands.criticalAt, and of a cache hit share that is nearly nothing."),
229
+ model: colourValue.describe("The colour of the model and provider segments."),
230
+ label: colourValue.describe("The colour of labels and secondary text: row labels, and the route, account, identity and headroom segments."),
231
+ empty: colourValue.describe("The colour of the unused part of a bar.")
193
232
  }
194
233
  };
195
234
  StatuslineSchema = import_zod.z.strictObject({
196
235
  layout: import_zod.z.strictObject(SHAPES.layout).partial().optional(),
197
236
  bands: import_zod.z.strictObject(SHAPES.bands).partial().optional(),
198
237
  labels: import_zod.z.strictObject(SHAPES.labels).partial().optional(),
199
- bar: import_zod.z.strictObject(SHAPES.bar).partial().optional()
238
+ bar: import_zod.z.strictObject(SHAPES.bar).partial().optional(),
239
+ colours: import_zod.z.strictObject(SHAPES.colours).partial().optional()
200
240
  });
201
241
  ResolvedStatuslineSchema = import_zod.z.strictObject({
202
242
  layout: import_zod.z.strictObject(SHAPES.layout),
203
243
  bands: import_zod.z.strictObject(SHAPES.bands),
204
244
  labels: import_zod.z.strictObject(SHAPES.labels),
205
- bar: import_zod.z.strictObject(SHAPES.bar)
245
+ bar: import_zod.z.strictObject(SHAPES.bar),
246
+ colours: import_zod.z.strictObject(SHAPES.colours)
206
247
  });
207
248
  STATUSLINE_DEFAULTS = {
208
249
  layout: { header: [...STATUSLINE_HEADER_SEGMENTS], rows: [...STATUSLINE_ROWS] },
209
250
  bands: { warnAt: 70, criticalAt: 90 },
210
251
  labels: { fiveHour: "5h", sevenDay: "Wk" },
211
- bar: { width: 10 }
252
+ bar: { width: 10, filled: "\u2588", empty: "\u2591" },
253
+ colours: {
254
+ context: "green",
255
+ usage: "green",
256
+ warning: "yellow",
257
+ usageWarning: "yellow",
258
+ critical: "red",
259
+ model: "default",
260
+ label: "default",
261
+ empty: "brightBlack"
262
+ }
212
263
  };
213
264
  STATUSLINE_ENV = "AGENT_SHIM_STATUSLINE";
214
265
  }
@@ -4274,7 +4325,7 @@ var init_package = __esm({
4274
4325
  "package.json"() {
4275
4326
  package_default = {
4276
4327
  name: "agent-shim",
4277
- version: "11.51.0",
4328
+ version: "11.52.0",
4278
4329
  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.",
4279
4330
  license: "MIT",
4280
4331
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -7453,6 +7504,9 @@ function keyOf(path43, leaf) {
7453
7504
  if (leaf instanceof import_zod15.z.ZodString) {
7454
7505
  return { ...common, kind: "text", choices: [] };
7455
7506
  }
7507
+ if (leaf instanceof import_zod15.z.ZodUnion) {
7508
+ return { ...common, kind: "colour", choices: [...STATUSLINE_COLOUR_NAMES] };
7509
+ }
7456
7510
  if (leaf instanceof import_zod15.z.ZodEnum) {
7457
7511
  return { ...common, kind: "choice", choices: Object.values(leaf.enum).map(String) };
7458
7512
  }
package/dist/index.mjs CHANGED
@@ -121,6 +121,9 @@ import { z } from "zod";
121
121
  function distinctList(member) {
122
122
  return z.array(member).refine((items) => new Set(items).size === items.length, "must not repeat a segment");
123
123
  }
124
+ function isSingleVisibleGrapheme(text) {
125
+ return [...GRAPHEMES.segment(text)].length === 1 && !/[\p{C}\p{Z}]/u.test(text);
126
+ }
124
127
  function isPlainObject(value) {
125
128
  return typeof value === "object" && value !== null && !Array.isArray(value);
126
129
  }
@@ -141,16 +144,40 @@ function resolveStatusline(settings) {
141
144
  }
142
145
  return resolved;
143
146
  }
144
- 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;
147
+ var STATUSLINE_HEADER_SEGMENTS, STATUSLINE_ROWS, STATUSLINE_COLOUR_NAMES, MAX_PERCENT, MAX_STATUSLINE_PALETTE_INDEX, MAX_STATUSLINE_LABEL_CHARS, MAX_BAR_CELLS, LABEL_RE2, colourValue, GRAPHEMES, barCharacter, labelText, wholePercent, SHAPES, StatuslineSchema, ResolvedStatuslineSchema, STATUSLINE_DEFAULTS, STATUSLINE_ENV;
145
148
  var init_statusline = __esm({
146
149
  "src/config/statusline.ts"() {
147
150
  "use strict";
148
151
  STATUSLINE_HEADER_SEGMENTS = ["model", "provider", "route", "account", "identity", "headroom"];
149
152
  STATUSLINE_ROWS = ["context", "quota"];
153
+ STATUSLINE_COLOUR_NAMES = [
154
+ "default",
155
+ "dim",
156
+ "black",
157
+ "red",
158
+ "green",
159
+ "yellow",
160
+ "blue",
161
+ "magenta",
162
+ "cyan",
163
+ "white",
164
+ "brightBlack",
165
+ "brightRed",
166
+ "brightGreen",
167
+ "brightYellow",
168
+ "brightBlue",
169
+ "brightMagenta",
170
+ "brightCyan",
171
+ "brightWhite"
172
+ ];
150
173
  MAX_PERCENT = 100;
174
+ MAX_STATUSLINE_PALETTE_INDEX = 255;
151
175
  MAX_STATUSLINE_LABEL_CHARS = 12;
152
176
  MAX_BAR_CELLS = 40;
153
177
  LABEL_RE2 = /^[^\p{C}\p{Z}]+(?: [^\p{C}\p{Z}]+)*$/u;
178
+ colourValue = z.union([z.enum(STATUSLINE_COLOUR_NAMES), z.number().int().min(0).max(MAX_STATUSLINE_PALETTE_INDEX), z.string().regex(/^#[0-9a-fA-F]{6}$/, "must be a colour name, a palette index from 0 to 255 or #rrggbb")]);
179
+ GRAPHEMES = new Intl.Segmenter(void 0, { granularity: "grapheme" });
180
+ barCharacter = z.string().refine(isSingleVisibleGrapheme, "must be a single visible character");
154
181
  labelText = z.string().max(MAX_STATUSLINE_LABEL_CHARS).regex(LABEL_RE2, "must be visible text without control characters");
155
182
  wholePercent = z.number().int().min(1).max(MAX_PERCENT);
156
183
  SHAPES = {
@@ -167,26 +194,50 @@ var init_statusline = __esm({
167
194
  sevenDay: labelText.describe("The name of the weekly subscription window.")
168
195
  },
169
196
  bar: {
170
- width: z.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.")
197
+ width: z.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."),
198
+ filled: barCharacter.describe("The character that draws the used part of a bar."),
199
+ empty: barCharacter.describe("The character that draws the unused part of a bar.")
200
+ },
201
+ colours: {
202
+ context: colourValue.describe("The colour of the context bar and its figures below the warning threshold."),
203
+ usage: colourValue.describe("The colour of the quota bars and their figures below the warning threshold."),
204
+ warning: colourValue.describe("The colour of the context bar at or above bands.warnAt, and of a cache hit share that is middling."),
205
+ usageWarning: colourValue.describe("The colour of a quota bar at or above bands.warnAt."),
206
+ critical: colourValue.describe("The colour of a bar at or above bands.criticalAt, and of a cache hit share that is nearly nothing."),
207
+ model: colourValue.describe("The colour of the model and provider segments."),
208
+ label: colourValue.describe("The colour of labels and secondary text: row labels, and the route, account, identity and headroom segments."),
209
+ empty: colourValue.describe("The colour of the unused part of a bar.")
171
210
  }
172
211
  };
173
212
  StatuslineSchema = z.strictObject({
174
213
  layout: z.strictObject(SHAPES.layout).partial().optional(),
175
214
  bands: z.strictObject(SHAPES.bands).partial().optional(),
176
215
  labels: z.strictObject(SHAPES.labels).partial().optional(),
177
- bar: z.strictObject(SHAPES.bar).partial().optional()
216
+ bar: z.strictObject(SHAPES.bar).partial().optional(),
217
+ colours: z.strictObject(SHAPES.colours).partial().optional()
178
218
  });
179
219
  ResolvedStatuslineSchema = z.strictObject({
180
220
  layout: z.strictObject(SHAPES.layout),
181
221
  bands: z.strictObject(SHAPES.bands),
182
222
  labels: z.strictObject(SHAPES.labels),
183
- bar: z.strictObject(SHAPES.bar)
223
+ bar: z.strictObject(SHAPES.bar),
224
+ colours: z.strictObject(SHAPES.colours)
184
225
  });
185
226
  STATUSLINE_DEFAULTS = {
186
227
  layout: { header: [...STATUSLINE_HEADER_SEGMENTS], rows: [...STATUSLINE_ROWS] },
187
228
  bands: { warnAt: 70, criticalAt: 90 },
188
229
  labels: { fiveHour: "5h", sevenDay: "Wk" },
189
- bar: { width: 10 }
230
+ bar: { width: 10, filled: "\u2588", empty: "\u2591" },
231
+ colours: {
232
+ context: "green",
233
+ usage: "green",
234
+ warning: "yellow",
235
+ usageWarning: "yellow",
236
+ critical: "red",
237
+ model: "default",
238
+ label: "default",
239
+ empty: "brightBlack"
240
+ }
190
241
  };
191
242
  STATUSLINE_ENV = "AGENT_SHIM_STATUSLINE";
192
243
  }
@@ -4250,7 +4301,7 @@ var init_package = __esm({
4250
4301
  "package.json"() {
4251
4302
  package_default = {
4252
4303
  name: "agent-shim",
4253
- version: "11.51.0",
4304
+ version: "11.52.0",
4254
4305
  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.",
4255
4306
  license: "MIT",
4256
4307
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -7428,6 +7479,9 @@ function keyOf(path43, leaf) {
7428
7479
  if (leaf instanceof z15.ZodString) {
7429
7480
  return { ...common, kind: "text", choices: [] };
7430
7481
  }
7482
+ if (leaf instanceof z15.ZodUnion) {
7483
+ return { ...common, kind: "colour", choices: [...STATUSLINE_COLOUR_NAMES] };
7484
+ }
7431
7485
  if (leaf instanceof z15.ZodEnum) {
7432
7486
  return { ...common, kind: "choice", choices: Object.values(leaf.enum).map(String) };
7433
7487
  }