claude-use 11.60.2 → 11.62.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
@@ -25412,6 +25412,15 @@ var init_graphemes = __esm({
25412
25412
  }
25413
25413
  });
25414
25414
 
25415
+ // src/statusline/messages/languages.ts
25416
+ var STATUSLINE_LANGUAGES;
25417
+ var init_languages = __esm({
25418
+ "src/statusline/messages/languages.ts"() {
25419
+ "use strict";
25420
+ STATUSLINE_LANGUAGES = ["en", "zh-Hans", "zh-Hant"];
25421
+ }
25422
+ });
25423
+
25415
25424
  // src/config/statusline.ts
25416
25425
  function distinctList(member) {
25417
25426
  return external_exports.array(member).refine((items) => new Set(items).size === items.length, "must not repeat an entry");
@@ -25422,10 +25431,13 @@ function isSingleVisibleGrapheme(text5) {
25422
25431
  function unsettable(setting) {
25423
25432
  return setting.unwrap().nullable().optional().describe(`${setting.description ?? ""} ${UNSET_NOTE}`);
25424
25433
  }
25434
+ function canonicalLanguage(tag) {
25435
+ return tag === "zh" || tag === "zh-TW" ? LANGUAGE_ALIASES[tag] : tag;
25436
+ }
25425
25437
  function isPlainObject2(value2) {
25426
25438
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
25427
25439
  }
25428
- function mergeStatuslineSettings(base, over) {
25440
+ function mergeKeys(base, over) {
25429
25441
  if (!isPlainObject2(over)) {
25430
25442
  return over === void 0 ? base : over;
25431
25443
  }
@@ -25434,7 +25446,7 @@ function mergeStatuslineSettings(base, over) {
25434
25446
  if (value2 === null) {
25435
25447
  Reflect.deleteProperty(merged, key);
25436
25448
  } else {
25437
- merged[key] = mergeStatuslineSettings(merged[key], value2);
25449
+ merged[key] = mergeKeys(merged[key], value2);
25438
25450
  }
25439
25451
  }
25440
25452
  return merged;
@@ -25442,6 +25454,13 @@ function mergeStatuslineSettings(base, over) {
25442
25454
  function contextBands({ bands, context }) {
25443
25455
  return { warnAt: context.warnAt ?? bands.warnAt, criticalAt: context.criticalAt ?? bands.criticalAt };
25444
25456
  }
25457
+ function isPresetName(value2) {
25458
+ return STATUSLINE_PRESETS.some((name) => name === value2);
25459
+ }
25460
+ function mergeStatuslineSettings(base, over) {
25461
+ const preset = isPlainObject2(over) ? over.preset : void 0;
25462
+ return mergeKeys(isPresetName(preset) ? mergeKeys(base, PRESET_BUNDLES[preset]) : base, over);
25463
+ }
25445
25464
  function resolveStatusline(settings2) {
25446
25465
  const resolved = ResolvedStatuslineSchema.parse(mergeStatuslineSettings(STATUSLINE_DEFAULTS, settings2));
25447
25466
  if (resolved.bands.warnAt >= resolved.bands.criticalAt) {
@@ -25451,9 +25470,17 @@ function resolveStatusline(settings2) {
25451
25470
  if (forContext.warnAt >= forContext.criticalAt) {
25452
25471
  throw new RangeError(`statusline context.warnAt (${String(forContext.warnAt)}) must be below context.criticalAt (${String(forContext.criticalAt)}), each following bands while it is unset`);
25453
25472
  }
25473
+ const merged = new Set(resolved.layout.merge.flat());
25474
+ const unmerged = resolved.layout.rightAlign.filter((row) => !merged.has(row));
25475
+ if (unmerged.length > 0) {
25476
+ throw new RangeError(`statusline layout.rightAlign names ${unmerged.join(", ")}, which no group in layout.merge contains`);
25477
+ }
25478
+ if (resolved.layout.forceMaxWidth && resolved.layout.maxWidth === 0) {
25479
+ throw new RangeError("statusline layout.forceMaxWidth needs layout.maxWidth to be set");
25480
+ }
25454
25481
  return resolved;
25455
25482
  }
25456
- var STATUSLINE_HEADER_SEGMENTS, STATUSLINE_ROWS, STATUSLINE_SESSION_TIME_PARTS, PROMPT_CACHE_TTL_SECONDS, STATUSLINE_COLOUR_NAMES, DEFAULT_HEADER_SEGMENTS, DEFAULT_ROWS, STATUSLINE_PATH_LEVELS, STATUSLINE_USAGE_VALUES, STATUSLINE_TIME_FORMATS, STATUSLINE_HOUR_CYCLES, MAX_PERCENT, MAX_STATUSLINE_PALETTE_INDEX, MAX_STATUSLINE_LABEL_COLUMNS, MAX_BAR_CELLS, MAX_ACCOUNT_USER_CHARS, MAX_DISPLAY_TEXT_CHARS, LABEL_RE2, OPTIONAL_LABEL_RE, colourValue, barCharacter, STATUSLINE_CONTEXT_VALUES, STATUSLINE_CONTEXT_ESTIMATES, AUTOCOMPACT_RESERVE_FRACTION, AUTOCOMPACT_RESERVE_RAMP_START, AUTOCOMPACT_RESERVE_RAMP_END, labelText, overrideText, wholePercent, thresholdPercent, SHAPES, UNSET_NOTE, StatuslineSchema, ResolvedStatuslineSchema, STATUSLINE_DEFAULTS, STATUSLINE_ENV;
25483
+ var STATUSLINE_HEADER_SEGMENTS, STATUSLINE_ROWS, STATUSLINE_SESSION_TIME_PARTS, PROMPT_CACHE_TTL_SECONDS, STATUSLINE_COLOUR_NAMES, DEFAULT_HEADER_SEGMENTS, DEFAULT_ROWS, STATUSLINE_PRESETS, GIT_WITH_DIRTY_MARKER, JJ_OFF, PRESET_BUNDLES, STATUSLINE_PATH_LEVELS, STATUSLINE_USAGE_VALUES, STATUSLINE_TIME_FORMATS, STATUSLINE_HOUR_CYCLES, MAX_PERCENT, MAX_STATUSLINE_PALETTE_INDEX, MAX_STATUSLINE_LABEL_COLUMNS, MIN_STATUSLINE_COLUMNS, MAX_STATUSLINE_COLUMNS, MAX_BAR_CELLS, MAX_ACCOUNT_USER_CHARS, MAX_DISPLAY_TEXT_CHARS, LABEL_RE2, OPTIONAL_LABEL_RE, mergeGroups, colourValue, barCharacter, STATUSLINE_CONTEXT_VALUES, STATUSLINE_CONTEXT_ESTIMATES, AUTOCOMPACT_RESERVE_FRACTION, AUTOCOMPACT_RESERVE_RAMP_START, AUTOCOMPACT_RESERVE_RAMP_END, labelWithinColumns, labelWithinColumnsMessage, labelShowsSomething, labelShowsSomethingMessage, labelIsPlainText, labelIsPlainTextMessage, windowLabel, overrideText, wholePercent, thresholdPercent, SHAPES, UNSET_NOTE, LANGUAGE_DESCRIPTION, LANGUAGE_TAGS, LANGUAGE_ALIASES, TOP_LEVEL, StatuslineSchema, ResolvedStatuslineSchema, STATUSLINE_DEFAULTS, STATUSLINE_ENV;
25457
25484
  var init_statusline = __esm({
25458
25485
  "src/config/statusline.ts"() {
25459
25486
  "use strict";
@@ -25461,6 +25488,7 @@ var init_statusline = __esm({
25461
25488
  init_zod();
25462
25489
  init_blank();
25463
25490
  init_graphemes();
25491
+ init_languages();
25464
25492
  STATUSLINE_HEADER_SEGMENTS = ["model", "provider", "route", "account", "identity", "headroom", "project", "vcs", "effort", "advisor", "version", "outputStyle", "cost", "dailyCost", "sessionName", "duration", "speed"];
25465
25493
  STATUSLINE_ROWS = ["context", "quota", "addedDirs", "gitFiles", "memory", "environment", "sessionTime", "promptCache", "compactions", "tokens"];
25466
25494
  STATUSLINE_SESSION_TIME_PARTS = ["started", "lastReply"];
@@ -25487,6 +25515,21 @@ var init_statusline = __esm({
25487
25515
  ];
25488
25516
  DEFAULT_HEADER_SEGMENTS = ["model", "provider", "route", "account", "identity", "headroom"];
25489
25517
  DEFAULT_ROWS = ["context", "quota"];
25518
+ STATUSLINE_PRESETS = ["standard", "full", "essential", "minimal"];
25519
+ GIT_WITH_DIRTY_MARKER = { enabled: true, showDirty: true, showAheadBehind: false, showLineDiff: false };
25520
+ JJ_OFF = { enabled: false, showDirty: true, showConflicts: true };
25521
+ PRESET_BUNDLES = {
25522
+ standard: { layout: { header: DEFAULT_HEADER_SEGMENTS, rows: DEFAULT_ROWS }, git: GIT_WITH_DIRTY_MARKER, jj: JJ_OFF, usage: { resetLabel: false }, context: { breakdown: "never" } },
25523
+ full: {
25524
+ layout: { header: ["model", "project", "vcs", "effort", "advisor", "version", "outputStyle", "cost", "sessionName", "duration"], rows: ["context", "quota", "addedDirs", "memory", "environment", "promptCache", "compactions", "tokens"] },
25525
+ git: GIT_WITH_DIRTY_MARKER,
25526
+ jj: { enabled: true, showDirty: true, showConflicts: true },
25527
+ usage: { resetLabel: true },
25528
+ context: { breakdown: "critical" }
25529
+ },
25530
+ essential: { layout: { header: ["model", "project", "vcs", "duration"], rows: ["context", "addedDirs"] }, git: GIT_WITH_DIRTY_MARKER, jj: JJ_OFF, usage: { resetLabel: true }, context: { breakdown: "never" } },
25531
+ minimal: { layout: { header: ["model", "project", "vcs"], rows: ["context", "addedDirs"] }, git: GIT_WITH_DIRTY_MARKER, jj: JJ_OFF, usage: { resetLabel: true }, context: { breakdown: "never" } }
25532
+ };
25490
25533
  STATUSLINE_PATH_LEVELS = ["1", "2", "3", "full"];
25491
25534
  STATUSLINE_USAGE_VALUES = ["used", "remaining"];
25492
25535
  STATUSLINE_TIME_FORMATS = ["relative", "absolute", "both", "elapsed", "elapsedAndAbsolute"];
@@ -25494,11 +25537,17 @@ var init_statusline = __esm({
25494
25537
  MAX_PERCENT = 100;
25495
25538
  MAX_STATUSLINE_PALETTE_INDEX = 255;
25496
25539
  MAX_STATUSLINE_LABEL_COLUMNS = 12;
25540
+ MIN_STATUSLINE_COLUMNS = 20;
25541
+ MAX_STATUSLINE_COLUMNS = 1e3;
25497
25542
  MAX_BAR_CELLS = 40;
25498
25543
  MAX_ACCOUNT_USER_CHARS = 254;
25499
25544
  MAX_DISPLAY_TEXT_CHARS = 80;
25500
25545
  LABEL_RE2 = /^[^\p{C}\p{Z}]+(?: [^\p{C}\p{Z}]+)*$/u;
25501
25546
  OPTIONAL_LABEL_RE = /^(?:[^\p{C}\p{Z}]+(?: [^\p{C}\p{Z}]+)*)?$/u;
25547
+ mergeGroups = external_exports.array(distinctList(external_exports.enum(STATUSLINE_ROWS)).min(2)).refine((groups) => {
25548
+ const rows = groups.flat();
25549
+ return new Set(rows).size === rows.length;
25550
+ }, "must not name a row in more than one group");
25502
25551
  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")]);
25503
25552
  barCharacter = external_exports.string().refine(isSingleVisibleGrapheme, "must be a single visible character that takes one terminal column");
25504
25553
  STATUSLINE_CONTEXT_VALUES = ["both", "percent", "tokens", "remaining"];
@@ -25506,14 +25555,27 @@ var init_statusline = __esm({
25506
25555
  AUTOCOMPACT_RESERVE_FRACTION = 0.165;
25507
25556
  AUTOCOMPACT_RESERVE_RAMP_START = 0.05;
25508
25557
  AUTOCOMPACT_RESERVE_RAMP_END = 0.5;
25509
- labelText = external_exports.string().refine((text5) => stringWidth(text5) <= MAX_STATUSLINE_LABEL_COLUMNS, `must take no more than ${String(MAX_STATUSLINE_LABEL_COLUMNS)} terminal columns`).refine((text5) => !drawsNothing(text5), "must show something: a label of only combining marks or blank characters draws nothing").regex(LABEL_RE2, "must be visible text without control characters");
25558
+ labelWithinColumns = (text5) => stringWidth(text5) <= MAX_STATUSLINE_LABEL_COLUMNS;
25559
+ labelWithinColumnsMessage = `must take no more than ${String(MAX_STATUSLINE_LABEL_COLUMNS)} terminal columns`;
25560
+ labelShowsSomething = (text5) => !drawsNothing(text5);
25561
+ labelShowsSomethingMessage = "must show something: a label of only combining marks or blank characters draws nothing";
25562
+ labelIsPlainText = (text5) => LABEL_RE2.test(text5);
25563
+ labelIsPlainTextMessage = "must be visible text without control characters";
25564
+ windowLabel = external_exports.string().refine((text5) => text5 === "" || labelWithinColumns(text5), labelWithinColumnsMessage).refine((text5) => text5 === "" || labelShowsSomething(text5), labelShowsSomethingMessage).refine((text5) => text5 === "" || labelIsPlainText(text5), labelIsPlainTextMessage);
25510
25565
  overrideText = external_exports.string().max(MAX_DISPLAY_TEXT_CHARS).regex(OPTIONAL_LABEL_RE, "must be visible text without control characters");
25511
25566
  wholePercent = external_exports.number().int().min(1).max(MAX_PERCENT);
25512
25567
  thresholdPercent = external_exports.number().int().min(0).max(MAX_PERCENT);
25513
25568
  SHAPES = {
25514
25569
  layout: {
25515
25570
  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."),
25516
- 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.")
25571
+ 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."),
25572
+ mode: external_exports.enum(["expanded", "compact"]).describe("How the statusline is laid out: expanded draws the header and then the rows, each on lines of its own as layout.merge allows, and compact draws the header segments and every row's content on one line, starting a new line only where the line would be wider than the width. layout.mergeBars, layout.merge, layout.rightAlign and layout.rule have no effect in compact."),
25573
+ rule: external_exports.enum(["none", "belowHeader"]).describe(`Whether a rule is drawn across the line between the header and the rows beneath it, as wide as the header's widest line (at least ${String(MIN_STATUSLINE_COLUMNS)} columns, at most the width); it is drawn only when both the header and the rows have something to show, and not in the compact layout.`),
25574
+ mergeBars: external_exports.boolean().describe("Whether bar rows that sit next to each other in layout.rows share a line, and one grid, when they fit (the context and quota bars do by default); when false each bar row is on a line of its own, its bars still aligned to its neighbours'. A row of text is never joined by this setting, whichever form the quota row takes: layout.merge does that."),
25575
+ merge: mergeGroups.describe("Groups of rows that share a line when they sit next to each other in layout.rows and fit on one line together, and are drawn on lines of their own when they do not; each group names at least two rows, and no row belongs to two groups. A group may mix bar rows and rows of text, which are joined with the separator when every member is a single line. Bar rows outside a group follow layout.mergeBars. A group in which no row has anything to show draws nothing: one with a row of text in it still ends a run of bars sharing a line, as an empty row of text does, and one of bar rows alone is left out, so the bars either side of it share as if it were not there."),
25576
+ rightAlign: distinctList(external_exports.enum(STATUSLINE_ROWS)).describe("Rows that start the right-aligned part of a merged line: the first of them to appear on a line, and the rows after it, are pushed to the right edge, with the gap padded by spaces. A row named here must belong to a group in layout.merge, and it has no effect when it is the first row of its line."),
25577
+ maxWidth: external_exports.number().int().min(0).max(MAX_STATUSLINE_COLUMNS).refine((columns) => columns === 0 || columns >= MIN_STATUSLINE_COLUMNS, `must be 0, or at least ${String(MIN_STATUSLINE_COLUMNS)} columns`).describe(`The exact width in columns lines are drawn to when the client reports none and the COLUMNS environment variable names none, in place of the default width it would assume for the terminal; unlike a terminal's width, it is not reduced by the columns Claude Code keeps back for itself. It is 0, to leave it unset, or from ${String(MIN_STATUSLINE_COLUMNS)} to ${String(MAX_STATUSLINE_COLUMNS)}; a value outside that is refused, not clamped.`),
25578
+ forceMaxWidth: external_exports.boolean().describe("Whether maxWidth is the exact width lines are drawn to for whatever the client reports, even when the terminal is narrower or wider; it needs maxWidth to be set.")
25517
25579
  },
25518
25580
  model: {
25519
25581
  format: external_exports.enum(["full", "compact", "short"]).describe("How the model's name is written: full is the name as the client gives it, compact drops a context-window suffix such as (1M context), and short also drops a leading Claude."),
@@ -25547,8 +25609,8 @@ var init_statusline = __esm({
25547
25609
  criticalAt: wholePercent.describe("The whole percentage of use at which a bar turns red.")
25548
25610
  },
25549
25611
  labels: {
25550
- fiveHour: labelText.describe("The name of the five-hour subscription window."),
25551
- sevenDay: labelText.describe("The name of the weekly subscription window.")
25612
+ fiveHour: windowLabel.describe("The name of the five-hour subscription window; empty uses the language's own name for it."),
25613
+ sevenDay: windowLabel.describe("The name of the weekly subscription window; empty uses the language's own name for it.")
25552
25614
  },
25553
25615
  bar: {
25554
25616
  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."),
@@ -25614,7 +25676,16 @@ var init_statusline = __esm({
25614
25676
  }
25615
25677
  };
25616
25678
  UNSET_NOTE = "A layer may write null to return it to unset when a shallower layer sets it.";
25679
+ LANGUAGE_DESCRIPTION = "The language of the words the statusline writes (labels, units of waiting such as `ago`, the names of effort levels): en, zh-Hans for Chinese in simplified characters, and zh-Hant for traditional; zh and zh-TW are read as zh-Hans and zh-Hant, and any other tag is refused. Durations, token counts, the dollar sign and clock times are written the same in every language, and a clock time follows the system locale and the clock settings.";
25680
+ LANGUAGE_TAGS = [...STATUSLINE_LANGUAGES, "zh", "zh-TW"];
25681
+ LANGUAGE_ALIASES = { zh: "zh-Hans", "zh-TW": "zh-Hant" };
25682
+ TOP_LEVEL = {
25683
+ language: external_exports.enum(STATUSLINE_LANGUAGES).describe(LANGUAGE_DESCRIPTION),
25684
+ preset: external_exports.enum(STATUSLINE_PRESETS).describe("A named bundle of settings (layout.header, layout.rows, git.enabled, git.showDirty, git.showAheadBehind, git.showLineDiff, jj.enabled, jj.showDirty, jj.showConflicts, usage.resetLabel and context.breakdown) that this layer sets beneath the keys it names itself and above everything the shallower layers set: standard is the statusline's own; full, essential and minimal are claude-hud's presets. Each draws the model, project and version control segments and the context row; full adds the effort, advisor, version, output style, cost, session name and duration segments and the quota, added directories, memory, environment, prompt cache, compactions and session tokens rows, with the token breakdown at high use, essential adds the duration and the added directories row, and minimal adds the added directories row alone.")
25685
+ };
25617
25686
  StatuslineSchema = external_exports.strictObject({
25687
+ language: external_exports.enum(LANGUAGE_TAGS).transform(canonicalLanguage).describe(LANGUAGE_DESCRIPTION).optional(),
25688
+ preset: TOP_LEVEL.preset.optional(),
25618
25689
  layout: external_exports.strictObject(SHAPES.layout).partial().optional(),
25619
25690
  model: external_exports.strictObject(SHAPES.model).partial().optional(),
25620
25691
  provider: external_exports.strictObject(SHAPES.provider).partial().optional(),
@@ -25637,6 +25708,8 @@ var init_statusline = __esm({
25637
25708
  jj: external_exports.strictObject(SHAPES.jj).partial().optional()
25638
25709
  });
25639
25710
  ResolvedStatuslineSchema = external_exports.strictObject({
25711
+ language: TOP_LEVEL.language,
25712
+ preset: TOP_LEVEL.preset,
25640
25713
  layout: external_exports.strictObject(SHAPES.layout),
25641
25714
  model: external_exports.strictObject(SHAPES.model),
25642
25715
  provider: external_exports.strictObject(SHAPES.provider),
@@ -25659,7 +25732,9 @@ var init_statusline = __esm({
25659
25732
  jj: external_exports.strictObject(SHAPES.jj)
25660
25733
  });
25661
25734
  STATUSLINE_DEFAULTS = {
25662
- layout: { header: [...DEFAULT_HEADER_SEGMENTS], rows: [...DEFAULT_ROWS] },
25735
+ language: "en",
25736
+ preset: "standard",
25737
+ layout: { header: [...DEFAULT_HEADER_SEGMENTS], rows: [...DEFAULT_ROWS], mode: "expanded", rule: "none", mergeBars: true, merge: [], rightAlign: [], maxWidth: 0, forceMaxWidth: false },
25663
25738
  model: { format: "full", override: "", source: "client" },
25664
25739
  provider: { name: "" },
25665
25740
  account: { parts: ["user", "organisation", "plan"], userLength: 0 },
@@ -25667,7 +25742,7 @@ var init_statusline = __esm({
25667
25742
  advisor: { override: "" },
25668
25743
  context: { bar: "shown", value: "both", estimate: "never", breakdown: "never" },
25669
25744
  bands: { warnAt: 70, criticalAt: 90 },
25670
- labels: { fiveHour: "5h", sevenDay: "Wk" },
25745
+ labels: { fiveHour: "", sevenDay: "" },
25671
25746
  bar: { width: 10, filled: "\u2588", empty: "\u2591" },
25672
25747
  usage: { value: "used", bar: true, compact: false, resetLabel: false, modelScoped: false, timeFormat: "relative", threshold: 0, sevenDayThreshold: 0 },
25673
25748
  clock: { hourCycle: "auto", seconds: false },
@@ -32600,6 +32675,9 @@ function keyOf(path70, declared) {
32600
32675
  if (leaf instanceof external_exports.ZodArray && leaf.element instanceof external_exports.ZodEnum) {
32601
32676
  return { ...common, kind: "list", choices: Object.values(leaf.element.enum).map(String) };
32602
32677
  }
32678
+ if (leaf instanceof external_exports.ZodArray && leaf.element instanceof external_exports.ZodArray && leaf.element.element instanceof external_exports.ZodEnum) {
32679
+ return { ...common, kind: "groups", choices: Object.values(leaf.element.element.enum).map(String) };
32680
+ }
32603
32681
  throw new TypeError(`statusline setting ${path70.join(".")} has a kind the key listing does not describe`);
32604
32682
  }
32605
32683
  function walk(shape, prefix) {
@@ -32610,7 +32688,7 @@ function statuslineKeys() {
32610
32688
  }
32611
32689
  function formatStatuslineKeys(keys) {
32612
32690
  return keys.map((key) => {
32613
- const takes = key.kind === "choice" || key.kind === "list" || key.kind === "colour" ? `${key.kind} of ${key.choices.join(", ")}` : key.kind;
32691
+ const takes = key.kind === "choice" || key.kind === "list" || key.kind === "groups" || key.kind === "colour" ? `${key.kind} of ${key.choices.join(", ")}` : key.kind;
32614
32692
  return `${key.path} (${takes}; ${key.optional ? "no default; none unsets it over shallower layers" : `default ${JSON.stringify(key.defaultValue)}`})
32615
32693
  ${key.description}`;
32616
32694
  }).join("\n");
@@ -32662,6 +32740,8 @@ function parseStatuslineAssignment(text5) {
32662
32740
  return { path: path70, value: /^\d+$/.test(raw) ? Number(raw) : raw };
32663
32741
  case "list":
32664
32742
  return { path: path70, value: raw === "" ? [] : raw.split(",") };
32743
+ case "groups":
32744
+ return { path: path70, value: raw === "" ? [] : raw.split(";").map((group) => group.split(",")) };
32665
32745
  default:
32666
32746
  return key.kind;
32667
32747
  }
@@ -36952,7 +37032,7 @@ var init_package = __esm({
36952
37032
  "package.json"() {
36953
37033
  package_default = {
36954
37034
  name: "claude-use",
36955
- version: "11.60.2",
37035
+ version: "11.62.0",
36956
37036
  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.",
36957
37037
  license: "MIT",
36958
37038
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -116251,7 +116331,7 @@ function registerProfileCommand(program2, deps) {
116251
116331
  withExamples(
116252
116332
  profile.command("set <name>").description(
116253
116333
  "Update a configuration profile's categories, entries, extends list, description or launch settings. With no options on a terminal, walks through its categories."
116254
- ).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) => {
116334
+ ).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, a list of groups such as layout.merge is groups separated by semicolons with commas inside each group, 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) => {
116255
116335
  const { json: json2, ...options } = allOptions;
116256
116336
  requireProfileExists(paths, name);
116257
116337
  if (Object.entries(allOptions).every(([key, value2]) => key === "json" || value2 === void 0)) {
@@ -138264,106 +138344,6 @@ function realStatuslinePorts(env, stateDirectory) {
138264
138344
  // src/statusline/render.ts
138265
138345
  init_statusline();
138266
138346
 
138267
- // src/statusline/ansi.ts
138268
- init_string_width();
138269
- init_graphemes();
138270
- var ESCAPE_CHAR_CODE = 27;
138271
- var ESCAPE = String.fromCharCode(ESCAPE_CHAR_CODE);
138272
- var BELL = "\\u0007";
138273
- var ESCAPE_SEQUENCE_PATTERN = [`${ESCAPE}\\[[0-?]*[ -/]*[@-~]`, `${ESCAPE}\\][^${BELL}${ESCAPE}]*(?:${BELL}|${ESCAPE}\\\\)?`, `${ESCAPE}[@-Z\\\\-_]`].join("|");
138274
- var SPLIT_ON_ESCAPES = new RegExp(`(${ESCAPE_SEQUENCE_PATTERN})`);
138275
- function visibleLength(text5) {
138276
- return stringWidth(text5);
138277
- }
138278
- function truncateToColumns(text5, columns) {
138279
- let used = 0;
138280
- let kept = "";
138281
- text5.split(SPLIT_ON_ESCAPES).forEach((part, index) => {
138282
- if (index % 2 === 1) {
138283
- kept += part;
138284
- return;
138285
- }
138286
- for (const grapheme of graphemesOf(part)) {
138287
- used += visibleLength(grapheme);
138288
- if (used > columns) {
138289
- return;
138290
- }
138291
- kept += grapheme;
138292
- }
138293
- });
138294
- return kept;
138295
- }
138296
-
138297
- // src/statusline/barGrid.ts
138298
- var BRACKET_COLUMNS = 2;
138299
- function chunk(items, size) {
138300
- const chunks = [];
138301
- for (let start = 0; start < items.length; start += size) {
138302
- chunks.push(items.slice(start, start + size));
138303
- }
138304
- return chunks;
138305
- }
138306
- function lastColumnOf(index, rowLength, columns) {
138307
- return index === rowLength - 1 ? columns - 1 : index;
138308
- }
138309
- function measureGrid(rows, separatorLength, baseBarCells) {
138310
- const columns = Math.max(...rows.map((row) => row.length));
138311
- const prefixWidths = Array.from({ length: columns }, () => 0);
138312
- const suffixWidths = Array.from({ length: columns }, () => 0);
138313
- for (const row of rows) {
138314
- row.forEach((cell, index) => {
138315
- const last = lastColumnOf(index, row.length, columns);
138316
- prefixWidths[index] = Math.max(prefixWidths[index] ?? 0, visibleLength(cell.prefix));
138317
- suffixWidths[last] = Math.max(suffixWidths[last] ?? 0, visibleLength(cell.suffix));
138318
- });
138319
- }
138320
- const fixed = [...prefixWidths, ...suffixWidths].reduce((total, width) => total + width, 0) + columns * (baseBarCells + BRACKET_COLUMNS);
138321
- return { rows, columns, prefixWidths, suffixWidths, baseWidth: fixed + separatorLength * (columns - 1) };
138322
- }
138323
- function padTo(text5, width) {
138324
- return text5 + " ".repeat(Math.max(0, width - visibleLength(text5)));
138325
- }
138326
- function renderGrid(grid, maxWidth, separator, baseBarCells) {
138327
- const separatorLength = visibleLength(separator);
138328
- const spare = Math.max(0, maxWidth - grid.baseWidth);
138329
- const barCells = Array.from({ length: grid.columns }, (_, column) => baseBarCells + Math.floor(spare / grid.columns) + (column < spare % grid.columns ? 1 : 0));
138330
- const blockWidths = barCells.map((cells) => cells + BRACKET_COLUMNS);
138331
- return grid.rows.map(
138332
- (row) => row.map((cell, index) => {
138333
- const last = lastColumnOf(index, row.length, grid.columns);
138334
- let blockWidth = blockWidths[index] ?? 0;
138335
- for (let column = index + 1; column <= last; column += 1) {
138336
- blockWidth += separatorLength + (grid.suffixWidths[column - 1] ?? 0) + (grid.prefixWidths[column] ?? 0) + (blockWidths[column] ?? 0);
138337
- }
138338
- const prefix = padTo(cell.prefix, grid.prefixWidths[index] ?? 0);
138339
- const bar = cell.draw(blockWidth - BRACKET_COLUMNS);
138340
- const suffix = index === row.length - 1 ? cell.suffix : padTo(cell.suffix, grid.suffixWidths[last] ?? 0);
138341
- return `${prefix}${bar}${suffix}`;
138342
- }).join(separator)
138343
- );
138344
- }
138345
- function layoutBarGrid(groups, maxWidth, separator, baseBarCells) {
138346
- const nonEmpty = groups.filter((group) => group.length > 0);
138347
- if (nonEmpty.length === 0) {
138348
- return [];
138349
- }
138350
- const separatorLength = visibleLength(separator);
138351
- const widest = Math.max(...nonEmpty.map((group) => group.length));
138352
- const layoutFor = (perRow) => measureGrid(nonEmpty.flatMap((group) => chunk(group, perRow)), separatorLength, baseBarCells);
138353
- const candidates = [measureGrid([nonEmpty.flat()], separatorLength, baseBarCells)];
138354
- for (let perRow = widest; perRow > 1; perRow -= 1) {
138355
- candidates.push(layoutFor(perRow));
138356
- }
138357
- const fitting = candidates.find((grid) => grid.baseWidth <= maxWidth);
138358
- if (fitting !== void 0) {
138359
- return renderGrid(fitting, maxWidth, separator, baseBarCells);
138360
- }
138361
- if (nonEmpty.length > 1) {
138362
- return nonEmpty.flatMap((group) => layoutBarGrid([group], maxWidth, separator, baseBarCells));
138363
- }
138364
- return renderGrid(layoutFor(1), maxWidth, separator, baseBarCells);
138365
- }
138366
-
138367
138347
  // src/statusline/elements/header/account.ts
138368
138348
  init_graphemes();
138369
138349
  function tierSuffixOf(tier) {
@@ -138433,6 +138413,38 @@ function accountSegment({ summary, settings: settings2 }) {
138433
138413
 
138434
138414
  // src/statusline/sanitise.ts
138435
138415
  init_statusline();
138416
+
138417
+ // src/statusline/ansi.ts
138418
+ init_string_width();
138419
+ init_graphemes();
138420
+ var ESCAPE_CHAR_CODE = 27;
138421
+ var ESCAPE = String.fromCharCode(ESCAPE_CHAR_CODE);
138422
+ var BELL = "\\u0007";
138423
+ var ESCAPE_SEQUENCE_PATTERN = [`${ESCAPE}\\[[0-?]*[ -/]*[@-~]`, `${ESCAPE}\\][^${BELL}${ESCAPE}]*(?:${BELL}|${ESCAPE}\\\\)?`, `${ESCAPE}[@-Z\\\\-_]`].join("|");
138424
+ var SPLIT_ON_ESCAPES = new RegExp(`(${ESCAPE_SEQUENCE_PATTERN})`);
138425
+ function visibleLength(text5) {
138426
+ return stringWidth(text5);
138427
+ }
138428
+ function truncateToColumns(text5, columns) {
138429
+ let used = 0;
138430
+ let kept = "";
138431
+ text5.split(SPLIT_ON_ESCAPES).forEach((part, index) => {
138432
+ if (index % 2 === 1) {
138433
+ kept += part;
138434
+ return;
138435
+ }
138436
+ for (const grapheme of graphemesOf(part)) {
138437
+ used += visibleLength(grapheme);
138438
+ if (used > columns) {
138439
+ return;
138440
+ }
138441
+ kept += grapheme;
138442
+ }
138443
+ });
138444
+ return kept;
138445
+ }
138446
+
138447
+ // src/statusline/sanitise.ts
138436
138448
  init_blank();
138437
138449
  init_graphemes();
138438
138450
  var ESCAPE_SEQUENCES = new RegExp(ESCAPE_SEQUENCE_PATTERN, "g");
@@ -138470,13 +138482,13 @@ function prettifyModelId(id2) {
138470
138482
  const version2 = major === void 0 ? "" : ` ${major}${minor === void 0 ? "" : `.${minor}`}`;
138471
138483
  return `${family.charAt(0).toUpperCase()}${family.slice(1).toLowerCase()}${version2}`;
138472
138484
  }
138473
- function advisorSegment({ settings: settings2, transcriptIdentity }) {
138485
+ function advisorSegment({ settings: settings2, transcriptIdentity, t: t10 }) {
138474
138486
  if (settings2.advisor.override !== "") {
138475
- return `Advisor: ${settings2.advisor.override}`;
138487
+ return t10("advisor.name", { name: settings2.advisor.override });
138476
138488
  }
138477
138489
  const recorded = transcriptIdentity().advisor;
138478
138490
  const advisor = recorded === void 0 ? "" : boundedDisplayText(prettifyModelId(recorded));
138479
- return advisor === "" ? void 0 : `Advisor: ${advisor}`;
138491
+ return advisor === "" ? void 0 : t10("advisor.name", { name: advisor });
138480
138492
  }
138481
138493
 
138482
138494
  // src/statusline/elements/header/effort.ts
@@ -138487,20 +138499,37 @@ var EFFORT_SYMBOLS = /* @__PURE__ */ new Map([
138487
138499
  ["xhigh", "\u25D5"],
138488
138500
  ["max", "\u25CF"]
138489
138501
  ]);
138502
+ function effortName(level, t10) {
138503
+ switch (level) {
138504
+ case "low":
138505
+ return t10("effort.low");
138506
+ case "medium":
138507
+ return t10("effort.medium");
138508
+ case "high":
138509
+ return t10("effort.high");
138510
+ case "xhigh":
138511
+ return t10("effort.xhigh");
138512
+ case "max":
138513
+ return t10("effort.max");
138514
+ default:
138515
+ return level;
138516
+ }
138517
+ }
138490
138518
  function effortLevelOf(effort) {
138491
138519
  const level = boundedDisplayText((typeof effort === "string" ? effort : effort?.level) ?? "").toLowerCase();
138492
138520
  return level === "" ? void 0 : level;
138493
138521
  }
138494
- function formatEffort(level, format) {
138522
+ function formatEffort(level, format, t10) {
138495
138523
  const symbol3 = EFFORT_SYMBOLS.get(level);
138524
+ const name = effortName(level, t10);
138496
138525
  if (symbol3 === void 0 || format === "text") {
138497
- return level;
138526
+ return name;
138498
138527
  }
138499
- return format === "symbol" ? symbol3 : `${symbol3} ${level}`;
138528
+ return format === "symbol" ? symbol3 : `${symbol3} ${name}`;
138500
138529
  }
138501
- function effortSegment({ payload, settings: settings2 }) {
138530
+ function effortSegment({ payload, settings: settings2, t: t10 }) {
138502
138531
  const level = effortLevelOf(payload.effort);
138503
- return level === void 0 ? void 0 : formatEffort(level, settings2.effort.format);
138532
+ return level === void 0 ? void 0 : formatEffort(level, settings2.effort.format, t10);
138504
138533
  }
138505
138534
 
138506
138535
  // src/statusline/dailyLedger.ts
@@ -138580,11 +138609,11 @@ function costSegment(context) {
138580
138609
  if (cost === void 0) {
138581
138610
  return void 0;
138582
138611
  }
138583
- return `${cost.source === "native" ? "Cost" : "Est."} ${formatUsd(cost.usd)}`;
138612
+ return context.t(cost.source === "native" ? "cost.session" : "cost.estimated", { amount: formatUsd(cost.usd) });
138584
138613
  }
138585
138614
  function dailyCostSegment(context) {
138586
138615
  const spend = recordDailySpend(context.ports, context.nowMs, context.payload.session_id, resolveSessionCost(context));
138587
- return spend === void 0 ? void 0 : `Today ${formatUsd(spend)}`;
138616
+ return spend === void 0 ? void 0 : context.t("cost.today", { amount: formatUsd(spend) });
138588
138617
  }
138589
138618
 
138590
138619
  // src/statusline/elements/sessionFormat.ts
@@ -138605,23 +138634,23 @@ function formatElapsed(ms2) {
138605
138634
  function twoUnits(larger2, smaller, largerUnit, smallerUnit) {
138606
138635
  return smaller > 0 ? `${String(larger2)}${largerUnit} ${String(smaller)}${smallerUnit}` : `${String(larger2)}${largerUnit}`;
138607
138636
  }
138608
- function formatAgo(ms2) {
138637
+ function formatAgo(ms2, t10) {
138609
138638
  if (ms2 < 0) {
138610
- return "just now";
138639
+ return t10("time.justNow");
138611
138640
  }
138612
138641
  const seconds = Math.floor(ms2 / MS_PER_SECOND18);
138613
138642
  if (seconds < SECONDS_PER_MINUTE2) {
138614
- return `${String(seconds)}s ago`;
138643
+ return t10("time.ago", { value: `${String(seconds)}s` });
138615
138644
  }
138616
138645
  const minutes = Math.floor(seconds / SECONDS_PER_MINUTE2);
138617
138646
  if (minutes < MINUTES_PER_HOUR4) {
138618
- return `${String(minutes)}m ago`;
138647
+ return t10("time.ago", { value: `${String(minutes)}m` });
138619
138648
  }
138620
138649
  const hours = Math.floor(minutes / MINUTES_PER_HOUR4);
138621
138650
  if (hours < HOURS_PER_DAY9) {
138622
- return `${twoUnits(hours, minutes % MINUTES_PER_HOUR4, "h", "m")} ago`;
138651
+ return t10("time.ago", { value: twoUnits(hours, minutes % MINUTES_PER_HOUR4, "h", "m") });
138623
138652
  }
138624
- return `${twoUnits(Math.floor(hours / HOURS_PER_DAY9), hours % HOURS_PER_DAY9, "d", "h")} ago`;
138653
+ return t10("time.ago", { value: twoUnits(Math.floor(hours / HOURS_PER_DAY9), hours % HOURS_PER_DAY9, "d", "h") });
138625
138654
  }
138626
138655
 
138627
138656
  // src/statusline/elements/header/duration.ts
@@ -138693,7 +138722,6 @@ var SECONDS_PER_DAY = 86400;
138693
138722
  var THOUSAND = 1e3;
138694
138723
  var MILLION = 1e6;
138695
138724
  var TEN = 10;
138696
- var TWENTY = 20;
138697
138725
  var FULL_PERCENT3 = 100;
138698
138726
  var ONE_PERCENT = 1;
138699
138727
  function withColor(color, text5) {
@@ -138726,9 +138754,9 @@ function formatTokens(num) {
138726
138754
  }
138727
138755
  return String(Math.round(num));
138728
138756
  }
138729
- function formatDuration(seconds) {
138757
+ function formatDuration(seconds, t10) {
138730
138758
  if (seconds === void 0 || seconds <= 0) {
138731
- return "available";
138759
+ return t10("quota.available");
138732
138760
  }
138733
138761
  if (seconds < SECONDS_PER_MINUTE3) {
138734
138762
  return `${String(seconds)}s`;
@@ -138767,20 +138795,20 @@ function barCell(prefix, suffix, fraction, style) {
138767
138795
  }
138768
138796
 
138769
138797
  // src/statusline/elements/header/headroom.ts
138770
- function headroomText(stats) {
138798
+ function headroomText(stats, t10) {
138771
138799
  if (stats === void 0) {
138772
138800
  return void 0;
138773
138801
  }
138774
- const overall = stats.savingsPercent === void 0 ? void 0 : `${stats.savingsPercent.toFixed(stats.savingsPercent < ONE_PERCENT ? 2 : 1)}% overall`;
138802
+ const overall = stats.savingsPercent === void 0 ? void 0 : t10("headroom.overall", { percent: stats.savingsPercent.toFixed(stats.savingsPercent < ONE_PERCENT ? 2 : 1) });
138775
138803
  const parts = [
138776
- stats.tokensSaved === void 0 ? void 0 : `${formatTokens(stats.tokensSaved)} saved`,
138804
+ stats.tokensSaved === void 0 ? void 0 : t10("headroom.saved", { tokens: formatTokens(stats.tokensSaved) }),
138777
138805
  overall,
138778
138806
  stats.savingsUsd === void 0 ? void 0 : `$${stats.savingsUsd.toFixed(2)}`
138779
138807
  ].filter((part) => part !== void 0);
138780
- return parts.length === 0 ? void 0 : `headroom ${parts.join(" \xB7 ")}`;
138808
+ return parts.length === 0 ? void 0 : t10("headroom.label", { parts: parts.join(" \xB7 ") });
138781
138809
  }
138782
- function headroomSegment({ summary }) {
138783
- return headroomText(summary.headroom);
138810
+ function headroomSegment({ summary, t: t10 }) {
138811
+ return headroomText(summary.headroom, t10);
138784
138812
  }
138785
138813
 
138786
138814
  // src/statusline/elements/header/identity.ts
@@ -138850,7 +138878,7 @@ function outputStyleIn(file2, readText2) {
138850
138878
  const style = settings2.success ? boundedDisplayText(settings2.data.outputStyle ?? "") : "";
138851
138879
  return style === "" ? void 0 : style;
138852
138880
  }
138853
- function outputStyleSegment({ payload, ports }) {
138881
+ function outputStyleSegment({ payload, ports, t: t10 }) {
138854
138882
  const pinned = ports.env.CLAUDE_CONFIG_DIR;
138855
138883
  const configDirectory = pinned === void 0 || pinned === "" ? import_node_path56.default.join(ports.homeDirectory, ".claude") : pinned;
138856
138884
  const projectDirectory = payload.cwd ?? payload.workspace?.current_dir;
@@ -138860,7 +138888,7 @@ function outputStyleSegment({ payload, ports }) {
138860
138888
  ...projectDirectory === void 0 ? [] : [import_node_path56.default.join(projectDirectory, ".claude", "settings.json"), import_node_path56.default.join(projectDirectory, ".claude", "settings.local.json")]
138861
138889
  ];
138862
138890
  const style = files.map((file2) => outputStyleIn(file2, ports.readText)).findLast((name) => name !== void 0);
138863
- return style === void 0 ? void 0 : `style: ${style}`;
138891
+ return style === void 0 ? void 0 : t10("outputStyle.name", { name: style });
138864
138892
  }
138865
138893
 
138866
138894
  // src/statusline/projectPath.ts
@@ -138904,9 +138932,9 @@ function workingDirectoryOf(payload) {
138904
138932
  }
138905
138933
 
138906
138934
  // src/statusline/elements/header/project.ts
138907
- function inlineAddedDirs({ payload, palette }) {
138935
+ function inlineAddedDirs({ payload, palette, t: t10 }) {
138908
138936
  const { names, more } = addedDirNames(payload.workspace?.added_dirs);
138909
- const drawn = [...names.map((name) => `+${name}`), ...more > 0 ? [`+${String(more)} more`] : []];
138937
+ const drawn = [...names.map((name) => `+${name}`), ...more > 0 ? [t10("more", { count: more })] : []];
138910
138938
  return drawn.length === 0 ? void 0 : drawn.map((text5) => palette.paint("label", text5)).join(" ");
138911
138939
  }
138912
138940
  function projectSegment(context) {
@@ -138927,14 +138955,14 @@ function providerSegment({ summary, settings: settings2 }) {
138927
138955
  }
138928
138956
 
138929
138957
  // src/statusline/elements/header/route.ts
138930
- function routeSegment({ summary }) {
138931
- return summary.routedTarget !== void 0 && !choiceNamesProvider(summary) ? `via ${summary.routedTarget}` : void 0;
138958
+ function routeSegment({ summary, t: t10 }) {
138959
+ return summary.routedTarget !== void 0 && !choiceNamesProvider(summary) ? t10("route.via", { target: summary.routedTarget }) : void 0;
138932
138960
  }
138933
138961
 
138934
138962
  // src/statusline/elements/header/version.ts
138935
- function versionSegment({ payload }) {
138963
+ function versionSegment({ payload, t: t10 }) {
138936
138964
  const version2 = boundedDisplayText(payload.version ?? "");
138937
- return version2 === "" ? void 0 : `CC v${version2}`;
138965
+ return version2 === "" ? void 0 : t10("version.label", { version: version2 });
138938
138966
  }
138939
138967
 
138940
138968
  // src/statusline/elements/header/sessionName.ts
@@ -139044,7 +139072,7 @@ function speedSegment(context) {
139044
139072
  }
139045
139073
  const outputTokens = context.payload.context_window?.current_usage?.output_tokens;
139046
139074
  const tokensPerSecond = trackSpeed(context.ports, transcriptPath, { at: context.nowMs, outputTokens, transcriptBytes: outputTokens === void 0 ? context.transcript()?.bytes : void 0 });
139047
- return tokensPerSecond === void 0 ? void 0 : `out: ${tokensPerSecond.toFixed(1)} tok/s`;
139075
+ return tokensPerSecond === void 0 ? void 0 : context.t("speed.rate", { rate: tokensPerSecond.toFixed(1) });
139048
139076
  }
139049
139077
 
139050
139078
  // src/statusline/vcs/git.ts
@@ -139139,10 +139167,10 @@ function parseNumstat(output2) {
139139
139167
  function detachedName(ports, cwd) {
139140
139168
  const tag = ports.run(GIT, ["describe", "--tags", "--exact-match", "HEAD"], cwd)?.trim();
139141
139169
  if (tag !== void 0 && tag !== "") {
139142
- return tag;
139170
+ return { name: tag, detached: false };
139143
139171
  }
139144
139172
  const commit = ports.run(GIT, ["rev-parse", "--short", "HEAD"], cwd)?.trim();
139145
- return commit === void 0 || commit === "" ? void 0 : `detached:${commit}`;
139173
+ return commit === void 0 || commit === "" ? void 0 : { name: commit, detached: true };
139146
139174
  }
139147
139175
  function byRecency(ports, cwd, files) {
139148
139176
  const root = ports.run(GIT, ["rev-parse", "--show-toplevel"], cwd)?.trim();
@@ -139155,16 +139183,16 @@ function byRecency(ports, cwd, files) {
139155
139183
  function readGitStatus(ports, cwd, query) {
139156
139184
  if (!query.workingTree) {
139157
139185
  const abbreviated = ports.run(GIT, ["rev-parse", "--abbrev-ref", "HEAD"], cwd)?.trim();
139158
- const branch2 = abbreviated === DETACHED_ABBREV ? detachedName(ports, cwd) : abbreviated;
139159
- return branch2 === void 0 || branch2 === "" ? void 0 : { kind: "git", branch: sanitiseDisplayText(branch2), dirty: false, conflict: false, ahead: 0, behind: 0, lineDiff: void 0, files: void 0 };
139186
+ const head2 = abbreviated === DETACHED_ABBREV ? detachedName(ports, cwd) : { name: abbreviated, detached: false };
139187
+ return head2?.name === void 0 || head2.name === "" ? void 0 : { kind: "git", branch: sanitiseDisplayText(head2.name), detached: head2.detached, dirty: false, conflict: false, ahead: 0, behind: 0, lineDiff: void 0, files: void 0 };
139160
139188
  }
139161
139189
  const output2 = ports.run(GIT, ["--no-optional-locks", "status", "--porcelain=v2", "--branch", "-z"], cwd);
139162
139190
  if (output2 === void 0) {
139163
139191
  return void 0;
139164
139192
  }
139165
139193
  const status = parseStatus(output2);
139166
- const branch = status.head === DETACHED_HEAD ? detachedName(ports, cwd) : status.head;
139167
- if (status.noCommitYet || branch === void 0 || branch === "") {
139194
+ const head = status.head === DETACHED_HEAD ? detachedName(ports, cwd) : { name: status.head, detached: false };
139195
+ if (status.noCommitYet || head?.name === void 0 || head.name === "") {
139168
139196
  return void 0;
139169
139197
  }
139170
139198
  const numstat = query.lineDiff && status.dirty ? ports.run(GIT, ["--no-optional-locks", "diff", "--numstat", "-z", "HEAD"], cwd) : void 0;
@@ -139172,7 +139200,8 @@ function readGitStatus(ports, cwd, query) {
139172
139200
  const tracked = query.files && status.tracked.length > 0 ? byRecency(ports, cwd, status.tracked) : status.tracked;
139173
139201
  return {
139174
139202
  kind: "git",
139175
- branch: sanitiseDisplayText(branch),
139203
+ branch: sanitiseDisplayText(head.name),
139204
+ detached: head.detached,
139176
139205
  dirty: status.dirty,
139177
139206
  conflict: false,
139178
139207
  ahead: status.ahead,
@@ -139245,7 +139274,7 @@ function parse4(output2) {
139245
139274
  return void 0;
139246
139275
  }
139247
139276
  const branch = label(bookmarks[0] ?? changeId);
139248
- return branch === void 0 ? void 0 : { kind: "jj", branch, dirty: dirtyFlag === "1", conflict: conflictFlag === "1", ahead: 0, behind: 0, lineDiff: void 0, files: void 0 };
139277
+ return branch === void 0 ? void 0 : { kind: "jj", branch, detached: false, dirty: dirtyFlag === "1", conflict: conflictFlag === "1", ahead: 0, behind: 0, lineDiff: void 0, files: void 0 };
139249
139278
  }
139250
139279
  function readJjStatus(ports, cwd) {
139251
139280
  const directory = ports.realPath(cwd);
@@ -139299,7 +139328,7 @@ function vcsSegment(context) {
139299
139328
  const { settings: settings2, palette } = context;
139300
139329
  const isGit = status.kind === "git";
139301
139330
  const showDirty = isGit ? settings2.git.showDirty : settings2.jj.showDirty;
139302
- const inner = [palette.paint("gitBranch", status.branch + (showDirty && status.dirty ? "*" : ""))];
139331
+ const inner = [palette.paint("gitBranch", (status.detached ? context.t("vcs.detached", { commit: status.branch }) : status.branch) + (showDirty && status.dirty ? "*" : ""))];
139303
139332
  if (isGit && settings2.git.showAheadBehind) {
139304
139333
  if (status.ahead > 0) {
139305
139334
  inner.push(aheadText(status.ahead, context));
@@ -139316,19 +139345,54 @@ function vcsSegment(context) {
139316
139345
  }
139317
139346
  }
139318
139347
  if (!isGit && settings2.jj.showConflicts && status.conflict) {
139319
- inner.push(palette.paint("critical", "!conflict"));
139348
+ inner.push(palette.paint("critical", context.t("vcs.conflict")));
139320
139349
  }
139321
139350
  return `${status.kind}:(${inner.join(" ")}${palette.paint("git", ")")}`;
139322
139351
  }
139323
139352
 
139353
+ // src/statusline/messages/around.ts
139354
+ var VALUE_MARK = String.fromCharCode(1);
139355
+ function paintCore(text5, paint) {
139356
+ const core = text5.trim();
139357
+ if (core === "") {
139358
+ return text5;
139359
+ }
139360
+ const start = text5.indexOf(core);
139361
+ return `${text5.slice(0, start)}${paint(core)}${text5.slice(start + core.length)}`;
139362
+ }
139363
+ function aroundValue(message, value2, paint) {
139364
+ const sides = message.split(VALUE_MARK);
139365
+ const [before, after] = sides;
139366
+ if (sides.length !== 2 || before === void 0 || after === void 0) {
139367
+ throw new TypeError(`message "${message}" must hold the value mark exactly once, and holds it ${String(sides.length - 1)} times`);
139368
+ }
139369
+ return `${paintCore(before, paint)}${value2}${paintCore(after, paint)}`;
139370
+ }
139371
+ function marked(t10, id2) {
139372
+ switch (id2) {
139373
+ case "sessionTime.started":
139374
+ return t10(id2, { time: VALUE_MARK });
139375
+ case "sessionTime.lastReply":
139376
+ return t10(id2, { ago: VALUE_MARK });
139377
+ case "addedDirs.label":
139378
+ return t10(id2, { dirs: VALUE_MARK });
139379
+ default:
139380
+ return id2;
139381
+ }
139382
+ }
139383
+ function writeAround(t10, id2, value2, paint) {
139384
+ return aroundValue(marked(t10, id2), value2, paint);
139385
+ }
139386
+
139324
139387
  // src/statusline/elements/rows/addedDirs.ts
139325
- function addedDirsRow({ payload, settings: settings2, palette }) {
139388
+ function addedDirsRow({ payload, settings: settings2, palette, t: t10 }) {
139326
139389
  const { names, more } = addedDirNames(payload.workspace?.added_dirs);
139327
139390
  if (settings2.project.addedDirsLayout !== "row" || names.length === 0) {
139328
139391
  return { kind: "text", lines: [] };
139329
139392
  }
139330
- const drawn = [...names, ...more > 0 ? [`+${String(more)} more`] : []].map((text5) => palette.paint("label", text5));
139331
- return { kind: "text", lines: [`${palette.paint("label", "Added dirs:")} ${drawn.join(palette.paint("label", ", "))}`] };
139393
+ const label2 = (text5) => palette.paint("label", text5);
139394
+ const drawn = [...names, ...more > 0 ? [t10("more", { count: more })] : []].map(label2);
139395
+ return { kind: "text", lines: [writeAround(t10, "addedDirs.label", drawn.join(label2(t10("list.separator"))), label2)] };
139332
139396
  }
139333
139397
 
139334
139398
  // src/statusline/elements/rows/compactions.ts
@@ -139337,7 +139401,7 @@ function compactionsRow(context) {
139337
139401
  if (transcript === void 0 || transcript.session.compactions === 0) {
139338
139402
  return { kind: "text", lines: [] };
139339
139403
  }
139340
- return { kind: "text", lines: [context.palette.paint("label", `Compactions: ${String(transcript.session.compactions)}${transcript.complete ? "" : "+"}`)] };
139404
+ return { kind: "text", lines: [context.palette.paint("label", context.t("compactions.label", { count: `${String(transcript.session.compactions)}${transcript.complete ? "" : "+"}` }))] };
139341
139405
  }
139342
139406
 
139343
139407
  // src/statusline/elements/rows/context.ts
@@ -139349,18 +139413,18 @@ function barStyleOf({ settings: settings2, palette }, okRole) {
139349
139413
  }
139350
139414
 
139351
139415
  // src/statusline/elements/rows/context.ts
139352
- function cacheHitText(hitFraction, style) {
139416
+ function cacheHitText(hitFraction, style, t10) {
139353
139417
  const clamped = Math.max(0, Math.min(1, hitFraction));
139354
- return ` (Cache: ${withColor(statusColor(clamped, false, style), `${(clamped * FULL_PERCENT3).toFixed(0)}%`)})`;
139418
+ return ` (${t10("context.cacheShare", { percent: withColor(statusColor(clamped, false, style), `${(clamped * FULL_PERCENT3).toFixed(0)}%`) })})`;
139355
139419
  }
139356
- function cacheShareText(view, style) {
139420
+ function cacheShareText(view, style, t10) {
139357
139421
  const hitRatio = view.cacheHitRatio;
139358
139422
  if (hitRatio !== void 0 && Number.isFinite(hitRatio)) {
139359
- return cacheHitText(hitRatio, style);
139423
+ return cacheHitText(hitRatio, style, t10);
139360
139424
  }
139361
139425
  const promptTotal = (view.cacheReadTokens ?? 0) + (view.freshInputTokens ?? 0);
139362
139426
  if (promptTotal > 0 && (view.cacheReadTokens ?? 0) > 0) {
139363
- return cacheHitText((view.cacheReadTokens ?? 0) / promptTotal, style);
139427
+ return cacheHitText((view.cacheReadTokens ?? 0) / promptTotal, style, t10);
139364
139428
  }
139365
139429
  return "";
139366
139430
  }
@@ -139387,13 +139451,13 @@ function usedPercentOf(context) {
139387
139451
  function estimateOf(kind, tokens, windowTokens) {
139388
139452
  return kind === "buffered" ? bufferedPercent(tokens, windowTokens) : Math.min(FULL_PERCENT3, tokens / windowTokens * FULL_PERCENT3);
139389
139453
  }
139390
- function breakdownText({ payload }) {
139454
+ function breakdownText({ payload, t: t10 }) {
139391
139455
  const usage = payload.context_window?.current_usage;
139392
139456
  if (usage === void 0) {
139393
139457
  return void 0;
139394
139458
  }
139395
139459
  const cached2 = (usage.cache_creation_input_tokens ?? 0) + (usage.cache_read_input_tokens ?? 0);
139396
- return ` (in: ${formatTokens(usage.input_tokens ?? 0)}, cache: ${formatTokens(cached2)})`;
139460
+ return ` (${t10("context.breakdown", { input: formatTokens(usage.input_tokens ?? 0), cached: formatTokens(cached2) })})`;
139397
139461
  }
139398
139462
  function contextRow(context) {
139399
139463
  const { view, palette, settings: settings2 } = context;
@@ -139438,8 +139502,8 @@ function contextRow(context) {
139438
139502
  if (settings2.context.bar === "hidden" && afterBar.length === 0) {
139439
139503
  return { kind: "text", lines: [] };
139440
139504
  }
139441
- const trailer = `${cacheShareText(view, style)}${high === void 0 ? "" : palette.paint("label", high)}`;
139442
- const label2 = ["Ctx", ...beforeBar].join(" ");
139505
+ const trailer = `${cacheShareText(view, style, context.t)}${high === void 0 ? "" : palette.paint("label", high)}`;
139506
+ const label2 = [context.t("context.label"), ...beforeBar].join(" ");
139443
139507
  if (settings2.context.bar === "shown") {
139444
139508
  const suffix = afterBar.length === 0 ? trailer : ` ${afterBar.join(" ")}${trailer}`;
139445
139509
  return { kind: "bars", cells: [barCell(palette.paint("label", `${label2} `), suffix, fraction, { ...style, bands })] };
@@ -139456,7 +139520,7 @@ var KIND_MARKS = {
139456
139520
  modified: { mark: "~", role: "warning" }
139457
139521
  };
139458
139522
  function gitFilesRow(context) {
139459
- const { palette, terminalWidth } = context;
139523
+ const { palette, terminalWidth, t: t10 } = context;
139460
139524
  const none = { kind: "text", lines: [] };
139461
139525
  const files = terminalWidth < MIN_COLUMNS ? void 0 : vcsStatusOf(context)?.files;
139462
139526
  if (files === void 0 || files.tracked.length === 0 && files.untracked === 0) {
@@ -139472,7 +139536,7 @@ function gitFilesRow(context) {
139472
139536
  });
139473
139537
  const overflow = files.tracked.length - shown.length;
139474
139538
  if (overflow > 0) {
139475
- entries.push(palette.paint("label", `+${String(overflow)} more`));
139539
+ entries.push(palette.paint("label", t10("more", { count: overflow })));
139476
139540
  }
139477
139541
  if (files.untracked > 0) {
139478
139542
  entries.push(palette.paint("label", `?${String(files.untracked)}`));
@@ -139680,17 +139744,41 @@ function layoutHeader(texts, maxWidth, separator) {
139680
139744
  }
139681
139745
 
139682
139746
  // src/statusline/elements/rows/environment.ts
139683
- function counted(count2, singular, plural2) {
139684
- return count2 === 0 ? void 0 : `${String(count2)} ${count2 === 1 ? singular : plural2}`;
139747
+ function counted(count2, one2, other) {
139748
+ if (count2 === 0) {
139749
+ return void 0;
139750
+ }
139751
+ return count2 === 1 ? one2(count2) : other(count2);
139685
139752
  }
139686
139753
  function environmentRow(context) {
139687
- const { payload, settings: settings2, palette, ports } = context;
139754
+ const { payload, settings: settings2, palette, ports, t: t10 } = context;
139688
139755
  const counts = countConfiguration(ports, payload.cwd ?? payload.workspace?.current_dir);
139689
139756
  const total = counts.claudeMd + counts.rules + counts.mcpServers + counts.hookEvents;
139690
139757
  if (total === 0 || total < settings2.environment.threshold) {
139691
139758
  return { kind: "text", lines: [] };
139692
139759
  }
139693
- const parts = [counted(counts.claudeMd, "CLAUDE.md", "CLAUDE.md"), counted(counts.rules, "rule", "rules"), counted(counts.mcpServers, "MCP", "MCPs"), counted(counts.hookEvents, "hook", "hooks")].filter((part) => part !== void 0);
139760
+ const parts = [
139761
+ counted(
139762
+ counts.claudeMd,
139763
+ (count2) => t10("environment.claudeMd.one", { count: count2 }),
139764
+ (count2) => t10("environment.claudeMd.other", { count: count2 })
139765
+ ),
139766
+ counted(
139767
+ counts.rules,
139768
+ (count2) => t10("environment.rules.one", { count: count2 }),
139769
+ (count2) => t10("environment.rules.other", { count: count2 })
139770
+ ),
139771
+ counted(
139772
+ counts.mcpServers,
139773
+ (count2) => t10("environment.mcp.one", { count: count2 }),
139774
+ (count2) => t10("environment.mcp.other", { count: count2 })
139775
+ ),
139776
+ counted(
139777
+ counts.hookEvents,
139778
+ (count2) => t10("environment.hooks.one", { count: count2 }),
139779
+ (count2) => t10("environment.hooks.other", { count: count2 })
139780
+ )
139781
+ ].filter((part) => part !== void 0);
139694
139782
  return { kind: "text", lines: packLines(parts.map((part) => palette.paint("label", part)), context.width, SEPARATOR2).map((line) => line.join(SEPARATOR2)) };
139695
139783
  }
139696
139784
 
@@ -139702,7 +139790,7 @@ function memoryRow(context) {
139702
139790
  const style = barStyleOf(context, "usage");
139703
139791
  const fraction = Math.max(0, Math.min(1, use2.usedBytes / use2.totalBytes));
139704
139792
  const percent2 = withColor(statusColor(fraction, true, style), `${(fraction * FULL_PERCENT3).toFixed(1)}%`);
139705
- cells.push(barCell(context.palette.paint("label", "RAM "), ` ${percent2} (${formatBytes(use2.usedBytes)} / ${formatBytes(use2.totalBytes)})`, fraction, style));
139793
+ cells.push(barCell(context.palette.paint("label", `${context.t("memory.label")} `), ` ${percent2} (${formatBytes(use2.usedBytes)} / ${formatBytes(use2.totalBytes)})`, fraction, style));
139706
139794
  }
139707
139795
  return { kind: "bars", cells };
139708
139796
  }
@@ -139745,16 +139833,16 @@ function promptCacheRow(context) {
139745
139833
  if (cache === void 0) {
139746
139834
  return { kind: "text", lines: [] };
139747
139835
  }
139748
- const { palette, nowMs, settings: settings2 } = context;
139836
+ const { palette, nowMs, settings: settings2, t: t10 } = context;
139749
139837
  const ttlSeconds = cache.ttlSeconds ?? settings2.promptCache.ttlSeconds;
139750
139838
  const expiresAtMs = cache.anchorAtMs + ttlSeconds * MS_PER_SECOND21;
139751
139839
  const remainingMs = expiresAtMs - nowMs;
139752
- const name = palette.paint("label", "Cache");
139840
+ const name = palette.paint("label", t10("promptCache.label"));
139753
139841
  if (remainingMs <= 0) {
139754
- return { kind: "text", lines: [`${name} ${palette.paint("label", "\u23F1 expired")}`] };
139842
+ return { kind: "text", lines: [`${name} ${palette.paint("label", `\u23F1 ${t10("promptCache.expired")}`)}`] };
139755
139843
  }
139756
139844
  const role = remainingMs <= warningSecondsOf(ttlSeconds) * MS_PER_SECOND21 ? "warning" : "context";
139757
- return { kind: "text", lines: [`${name} ${palette.paint(role, `\u23F1 until ${formatWallClock(expiresAtMs, nowMs, context.ports.clock, settings2.clock)}`)}`] };
139845
+ return { kind: "text", lines: [`${name} ${palette.paint(role, `\u23F1 ${t10("promptCache.until", { time: formatWallClock(expiresAtMs, nowMs, context.ports.clock, settings2.clock) })}`)}`] };
139758
139846
  }
139759
139847
 
139760
139848
  // src/statusline/elements/rows/quota.ts
@@ -139762,7 +139850,6 @@ init_statusline();
139762
139850
  init_pick();
139763
139851
 
139764
139852
  // src/statusline/resetTime.ts
139765
- var AVAILABLE = formatDuration(void 0);
139766
139853
  function elapsedPercent(resetMs, periodMs, nowMs) {
139767
139854
  if (!Number.isFinite(resetMs) || periodMs === void 0) {
139768
139855
  return void 0;
@@ -139770,25 +139857,33 @@ function elapsedPercent(resetMs, periodMs, nowMs) {
139770
139857
  const share = (nowMs - (resetMs - periodMs)) / periodMs * FULL_PERCENT3;
139771
139858
  return Math.max(0, Math.min(FULL_PERCENT3, Math.round(share)));
139772
139859
  }
139773
- function formatResetTime(window, nowMs, settings2, clock) {
139860
+ function formatResetTime(window, nowMs, settings2, clock, t10, labelled) {
139774
139861
  const resetMs = window.resetsAt === void 0 ? Number.NaN : Date.parse(window.resetsAt);
139775
139862
  const secondsLeft = secondsUntil(window.resetsAt, nowMs);
139776
139863
  const pending = secondsLeft !== void 0 && secondsLeft > 0;
139777
- const relative = formatDuration(secondsLeft);
139778
- const absolute = pending ? `at ${formatWallClock(resetMs, nowMs, clock, settings2.clock)}` : AVAILABLE;
139864
+ const available = t10("quota.available");
139865
+ if (!pending && settings2.usage.timeFormat !== "elapsed" && settings2.usage.timeFormat !== "elapsedAndAbsolute") {
139866
+ return { text: settings2.usage.timeFormat === "relative" ? formatDuration(secondsLeft, t10) : available, pending };
139867
+ }
139868
+ const introduced = labelled && pending;
139869
+ const relative = formatDuration(secondsLeft, t10);
139870
+ const time4 = pending ? formatWallClock(resetMs, nowMs, clock, settings2.clock) : "";
139779
139871
  const elapsed = elapsedPercent(resetMs, window.periodMs, nowMs);
139780
- const elapsedText = elapsed === void 0 ? void 0 : `${String(elapsed)}% elapsed`;
139872
+ const elapsedText = elapsed === void 0 ? void 0 : t10("quota.elapsed", { percent: elapsed });
139781
139873
  switch (settings2.usage.timeFormat) {
139782
139874
  case "relative":
139783
- return { text: relative, pending };
139875
+ return { text: introduced ? t10("quota.resetsIn", { time: relative }) : relative, pending };
139784
139876
  case "absolute":
139785
- return { text: absolute, pending };
139877
+ return { text: introduced ? t10("quota.resetsAt", { time: time4 }) : t10("quota.at", { time: time4 }), pending };
139786
139878
  case "both":
139787
- return { text: pending ? `${relative}, ${absolute}` : AVAILABLE, pending };
139879
+ return { text: introduced ? t10("quota.resetsInAt", { relative, time: time4 }) : t10("quota.relativeAt", { relative, time: time4 }), pending };
139788
139880
  case "elapsed":
139789
139881
  return { text: elapsedText ?? "", pending };
139790
139882
  case "elapsedAndAbsolute":
139791
- return { text: [elapsedText, pending ? absolute : void 0].filter((part) => part !== void 0).join(", "), pending };
139883
+ if (elapsedText === void 0) {
139884
+ return { text: pending ? t10("quota.at", { time: time4 }) : "", pending };
139885
+ }
139886
+ return { text: pending ? t10("quota.elapsedAt", { elapsed: elapsedText, time: time4 }) : elapsedText, pending };
139792
139887
  default:
139793
139888
  return settings2.usage.timeFormat;
139794
139889
  }
@@ -139814,10 +139909,10 @@ function candidateWindows(context) {
139814
139909
  }
139815
139910
  const windows = [];
139816
139911
  if (summary.fiveHourUsed !== void 0) {
139817
- windows.push({ label: settings2.labels.fiveHour, fraction: summary.fiveHourUsed / FULL_PERCENT3, resetsAt: summary.fiveHourResetAt, periodMs: FIVE_HOUR_WINDOW_MS, weekly: false });
139912
+ windows.push({ label: settings2.labels.fiveHour === "" ? context.t("quota.fiveHour") : settings2.labels.fiveHour, fraction: summary.fiveHourUsed / FULL_PERCENT3, resetsAt: summary.fiveHourResetAt, periodMs: FIVE_HOUR_WINDOW_MS, weekly: false });
139818
139913
  }
139819
139914
  if (summary.sevenDayUsed !== void 0) {
139820
- windows.push({ label: settings2.labels.sevenDay, fraction: summary.sevenDayUsed / FULL_PERCENT3, resetsAt: summary.sevenDayResetAt, periodMs: SEVEN_DAY_WINDOW_MS, weekly: true });
139915
+ windows.push({ label: settings2.labels.sevenDay === "" ? context.t("quota.sevenDay") : settings2.labels.sevenDay, fraction: summary.sevenDayUsed / FULL_PERCENT3, resetsAt: summary.sevenDayResetAt, periodMs: SEVEN_DAY_WINDOW_MS, weekly: true });
139821
139916
  }
139822
139917
  if (summary.fiveHourUsed === void 0 && summary.sevenDayUsed === void 0) {
139823
139918
  windows.push(...summary.providerQuotaWindows.map((window) => ({ label: window.measures, fraction: window.utilization, resetsAt: window.resetsAt, periodMs: window.periodMs, weekly: false })));
@@ -139842,19 +139937,12 @@ function figuresOf(window, context, style) {
139842
139937
  const clamped = Math.max(0, Math.min(1, window.fraction));
139843
139938
  const used = window.fraction * FULL_PERCENT3;
139844
139939
  const shown = settings2.usage.value === "remaining" ? Math.max(0, FULL_PERCENT3 - used) : used;
139845
- const { text: text5, pending } = formatResetTime(window, nowMs, settings2, ports.clock);
139846
- return { value: withColor(statusColor(clamped, true, style), `${shown.toFixed(1)}%`), reset: text5, pending };
139940
+ const reset = formatResetTime(window, nowMs, settings2, ports.clock, context.t, settings2.usage.resetLabel).text;
139941
+ const plainReset = settings2.usage.resetLabel ? formatResetTime(window, nowMs, settings2, ports.clock, context.t, false).text : reset;
139942
+ return { value: withColor(statusColor(clamped, true, style), `${shown.toFixed(1)}%`), reset, plainReset };
139847
139943
  }
139848
- function resetSuffix(reset, pending, context) {
139849
- if (reset === "") {
139850
- return "";
139851
- }
139852
- const { usage } = context.settings;
139853
- const elapsedForm = usage.timeFormat === "elapsed" || usage.timeFormat === "elapsedAndAbsolute";
139854
- if (!usage.resetLabel || !pending || elapsedForm) {
139855
- return `(${reset})`;
139856
- }
139857
- return `(${usage.timeFormat === "absolute" ? "resets" : "resets in"} ${reset})`;
139944
+ function parenthesised(reset) {
139945
+ return reset === "" ? "" : `(${reset})`;
139858
139946
  }
139859
139947
  function wrapped(windows, width) {
139860
139948
  return packLines(windows, width, SEPARATOR2).map((line) => line.join(SEPARATOR2));
@@ -139864,11 +139952,11 @@ function quotaRow(context) {
139864
139952
  const style = barStyleOf(context, "usage");
139865
139953
  const windows = visibleWindows(context);
139866
139954
  const parts = windows.map((window) => {
139867
- const { value: value2, reset, pending } = figuresOf(window, context, style);
139868
- return { window, value: value2, reset, suffix: resetSuffix(reset, pending, context) };
139955
+ const { value: value2, reset, plainReset } = figuresOf(window, context, style);
139956
+ return { window, value: value2, plainReset, suffix: parenthesised(reset) };
139869
139957
  });
139870
139958
  if (settings2.usage.compact) {
139871
- const lines = parts.map(({ window, value: value2, reset }) => `${palette.paint("label", `${window.label}:`)} ${value2}${reset === "" ? "" : ` ${palette.paint("label", `(${reset})`)}`}`);
139959
+ const lines = parts.map(({ window, value: value2, plainReset }) => `${paintCore(context.t("quota.compactLabel", { label: window.label }), (text5) => palette.paint("label", text5))}${value2}${plainReset === "" ? "" : ` ${palette.paint("label", `(${plainReset})`)}`}`);
139872
139960
  return { kind: "text", lines: wrapped(lines, context.width) };
139873
139961
  }
139874
139962
  if (!settings2.usage.bar) {
@@ -139882,12 +139970,13 @@ function quotaRow(context) {
139882
139970
  // src/statusline/elements/rows/sessionTime.ts
139883
139971
  function sessionTimeRow(context) {
139884
139972
  const session = context.transcript()?.session;
139885
- const { palette, nowMs, settings: settings2 } = context;
139973
+ const { palette, nowMs, settings: settings2, t: t10 } = context;
139974
+ const label2 = (text5) => palette.paint("label", text5);
139886
139975
  const parts = settings2.sessionTime.parts.flatMap((part) => {
139887
139976
  if (part === "started") {
139888
- return session?.startedAtMs === void 0 ? [] : `${palette.paint("label", "Started:")} ${formatWallClock(session.startedAtMs, nowMs, context.ports.clock, settings2.clock)}`;
139977
+ return session?.startedAtMs === void 0 ? [] : writeAround(t10, "sessionTime.started", formatWallClock(session.startedAtMs, nowMs, context.ports.clock, settings2.clock), label2);
139889
139978
  }
139890
- return session?.lastResponseAtMs === void 0 ? [] : `${palette.paint("label", "Last reply:")} ${formatAgo(nowMs - session.lastResponseAtMs)}`;
139979
+ return session?.lastResponseAtMs === void 0 ? [] : writeAround(t10, "sessionTime.lastReply", formatAgo(nowMs - session.lastResponseAtMs, t10), label2);
139891
139980
  });
139892
139981
  return { kind: "text", lines: parts.length === 0 ? [] : [parts.join(` ${palette.paint("label", "\u2502")} `)] };
139893
139982
  }
@@ -139948,19 +140037,19 @@ function foldTokens(state, record2) {
139948
140037
  }
139949
140038
 
139950
140039
  // src/statusline/elements/rows/tokens.ts
139951
- function tokensRow({ palette, transcript }) {
140040
+ function tokensRow({ palette, transcript, t: t10 }) {
139952
140041
  const facts = transcript();
139953
140042
  const total = facts === void 0 ? 0 : totalTokens(facts.tokens);
139954
140043
  if (facts === void 0 || total === 0) {
139955
140044
  return { kind: "text", lines: [] };
139956
140045
  }
139957
140046
  const { tokens } = facts;
139958
- const parts = [`in: ${formatTokens(tokens.inputTokens)}`, `out: ${formatTokens(tokens.outputTokens)}`];
140047
+ const parts = [t10("tokens.input", { count: formatTokens(tokens.inputTokens) }), t10("tokens.output", { count: formatTokens(tokens.outputTokens) })];
139959
140048
  const cached2 = tokens.cacheCreationTokens + tokens.cacheReadTokens;
139960
140049
  if (cached2 > 0) {
139961
- parts.push(`cache: ${formatTokens(cached2)}`);
140050
+ parts.push(t10("tokens.cache", { count: formatTokens(cached2) }));
139962
140051
  }
139963
- return { kind: "text", lines: [palette.paint("label", `Tokens ${formatTokens(total)}${facts.complete ? "" : "+"} (${parts.join(", ")})`)] };
140052
+ return { kind: "text", lines: [palette.paint("label", t10("tokens.summary", { total: `${formatTokens(total)}${facts.complete ? "" : "+"}`, parts: parts.join(t10("list.separator")) }))] };
139964
140053
  }
139965
140054
 
139966
140055
  // src/statusline/elements/registry.ts
@@ -140096,6 +140185,373 @@ function readTranscriptIdentity(ports, transcriptPath) {
140096
140185
  return floor === 0 ? identityOfLine(decoder.decode(joined2(carry))) ?? NOT_FOUND : NOT_FOUND;
140097
140186
  }
140098
140187
 
140188
+ // src/statusline/messages/en.ts
140189
+ var EN2 = {
140190
+ "context.label": "Ctx",
140191
+ "context.cacheShare": "Cache: {percent}",
140192
+ "context.breakdown": "in: {input}, cache: {cached}",
140193
+ "quota.fiveHour": "5h",
140194
+ "quota.sevenDay": "Wk",
140195
+ "quota.resetsIn": "resets in {time}",
140196
+ "quota.resetsAt": "resets at {time}",
140197
+ "quota.resetsInAt": "resets in {relative}, at {time}",
140198
+ "quota.at": "at {time}",
140199
+ "quota.relativeAt": "{relative}, at {time}",
140200
+ "quota.compactLabel": "{label}: ",
140201
+ "quota.available": "available",
140202
+ "quota.elapsed": "{percent}% elapsed",
140203
+ "quota.elapsedAt": "{elapsed}, at {time}",
140204
+ "memory.label": "RAM",
140205
+ "cost.session": "Cost {amount}",
140206
+ "cost.estimated": "Est. {amount}",
140207
+ "cost.today": "Today {amount}",
140208
+ "advisor.name": "Advisor: {name}",
140209
+ "outputStyle.name": "style: {name}",
140210
+ "route.via": "via {target}",
140211
+ "speed.rate": "out: {rate} tok/s",
140212
+ "headroom.label": "headroom {parts}",
140213
+ "headroom.saved": "{tokens} saved",
140214
+ "headroom.overall": "{percent}% overall",
140215
+ "version.label": "CC v{version}",
140216
+ "vcs.conflict": "!conflict",
140217
+ "vcs.detached": "detached:{commit}",
140218
+ "effort.low": "low",
140219
+ "effort.medium": "medium",
140220
+ "effort.high": "high",
140221
+ "effort.xhigh": "xhigh",
140222
+ "effort.max": "max",
140223
+ "more": "+{count} more",
140224
+ "addedDirs.label": "Added dirs: {dirs}",
140225
+ "sessionTime.started": "Started: {time}",
140226
+ "sessionTime.lastReply": "Last reply: {ago}",
140227
+ "time.justNow": "just now",
140228
+ "time.ago": "{value} ago",
140229
+ "promptCache.label": "Cache",
140230
+ "promptCache.expired": "expired",
140231
+ "promptCache.until": "until {time}",
140232
+ "tokens.summary": "Tokens {total} ({parts})",
140233
+ "tokens.input": "in: {count}",
140234
+ "tokens.output": "out: {count}",
140235
+ "tokens.cache": "cache: {count}",
140236
+ "list.separator": ", ",
140237
+ "compactions.label": "Compactions: {count}",
140238
+ "environment.claudeMd.one": "{count} CLAUDE.md",
140239
+ "environment.claudeMd.other": "{count} CLAUDE.md",
140240
+ "environment.rules.one": "{count} rule",
140241
+ "environment.rules.other": "{count} rules",
140242
+ "environment.mcp.one": "{count} MCP",
140243
+ "environment.mcp.other": "{count} MCPs",
140244
+ "environment.hooks.one": "{count} hook",
140245
+ "environment.hooks.other": "{count} hooks"
140246
+ };
140247
+
140248
+ // src/statusline/messages/zhHans.ts
140249
+ var ZH_HANS = {
140250
+ "context.label": "\u4E0A\u4E0B\u6587",
140251
+ "context.breakdown": "\u8F93\u5165\uFF1A{input}\uFF0C\u7F13\u5B58\uFF1A{cached}",
140252
+ "context.cacheShare": "\u7F13\u5B58\uFF1A{percent}",
140253
+ "quota.fiveHour": "5\u5C0F\u65F6",
140254
+ "quota.sevenDay": "\u672C\u5468",
140255
+ "quota.resetsIn": "\u8DDD\u91CD\u7F6E {time}",
140256
+ "quota.resetsAt": "\u91CD\u7F6E\u4E8E {time}",
140257
+ "quota.resetsInAt": "\u8DDD\u91CD\u7F6E {relative}\uFF0C\u4E8E {time}",
140258
+ "quota.at": "{time} \u91CD\u7F6E",
140259
+ "quota.relativeAt": "{relative}\uFF0C{time} \u91CD\u7F6E",
140260
+ "quota.compactLabel": "{label}\uFF1A",
140261
+ "quota.available": "\u53EF\u7528",
140262
+ "quota.elapsed": "\u5DF2\u8FC7 {percent}%",
140263
+ "quota.elapsedAt": "{elapsed}\uFF0C{time} \u91CD\u7F6E",
140264
+ "memory.label": "\u5185\u5B58",
140265
+ "cost.session": "\u8D39\u7528 {amount}",
140266
+ "cost.estimated": "\u4F30\u7B97 {amount}",
140267
+ "cost.today": "\u4ECA\u65E5 {amount}",
140268
+ "advisor.name": "\u987E\u95EE\uFF1A{name}",
140269
+ "outputStyle.name": "\u8F93\u51FA\u98CE\u683C\uFF1A{name}",
140270
+ "route.via": "\u7ECF\u7531 {target}",
140271
+ "speed.rate": "\u8F93\u51FA\uFF1A{rate} tok/s",
140272
+ "headroom.label": "headroom {parts}",
140273
+ "headroom.saved": "\u5DF2\u8282\u7701 {tokens}",
140274
+ "headroom.overall": "\u603B\u8BA1 {percent}%",
140275
+ "version.label": "CC v{version}",
140276
+ "vcs.conflict": "!\u51B2\u7A81",
140277
+ "vcs.detached": "\u5206\u79BB\u4E8E {commit}",
140278
+ "effort.low": "\u4F4E",
140279
+ "effort.medium": "\u4E2D",
140280
+ "effort.high": "\u9AD8",
140281
+ "effort.xhigh": "\u8D85\u9AD8",
140282
+ "effort.max": "\u6700\u9AD8",
140283
+ "more": "\u53E6\u6709 {count} \u4E2A",
140284
+ "addedDirs.label": "\u9644\u52A0\u76EE\u5F55\uFF1A{dirs}",
140285
+ "sessionTime.started": "\u5F00\u59CB\uFF1A{time}",
140286
+ "sessionTime.lastReply": "\u4E0A\u6B21\u56DE\u590D\uFF1A{ago}",
140287
+ "time.justNow": "\u521A\u521A",
140288
+ "time.ago": "{value}\u524D",
140289
+ "promptCache.label": "\u7F13\u5B58",
140290
+ "promptCache.expired": "\u5DF2\u8FC7\u671F",
140291
+ "promptCache.until": "\u81F3 {time}",
140292
+ "tokens.summary": "\u8BCD\u5143 {total}\uFF08{parts}\uFF09",
140293
+ "tokens.input": "\u8F93\u5165 {count}",
140294
+ "tokens.output": "\u8F93\u51FA {count}",
140295
+ "tokens.cache": "\u7F13\u5B58 {count}",
140296
+ "list.separator": "\uFF0C",
140297
+ "compactions.label": "\u538B\u7F29\u6B21\u6570\uFF1A{count}",
140298
+ "environment.claudeMd.one": "{count} \u4E2A CLAUDE.md",
140299
+ "environment.claudeMd.other": "{count} \u4E2A CLAUDE.md",
140300
+ "environment.rules.one": "{count} \u6761\u89C4\u5219",
140301
+ "environment.rules.other": "{count} \u6761\u89C4\u5219",
140302
+ "environment.mcp.one": "{count} \u4E2A MCP",
140303
+ "environment.mcp.other": "{count} \u4E2A MCP",
140304
+ "environment.hooks.one": "{count} \u4E2A\u94A9\u5B50",
140305
+ "environment.hooks.other": "{count} \u4E2A\u94A9\u5B50"
140306
+ };
140307
+
140308
+ // src/statusline/messages/zhHant.ts
140309
+ var ZH_HANT = {
140310
+ "context.label": "\u4E0A\u4E0B\u6587",
140311
+ "context.breakdown": "\u8F38\u5165\uFF1A{input}\uFF0C\u5FEB\u53D6\uFF1A{cached}",
140312
+ "context.cacheShare": "\u5FEB\u53D6\uFF1A{percent}",
140313
+ "quota.fiveHour": "5\u5C0F\u6642",
140314
+ "quota.sevenDay": "\u672C\u9031",
140315
+ "quota.resetsIn": "\u8DDD\u91CD\u8A2D {time}",
140316
+ "quota.resetsAt": "\u91CD\u8A2D\u65BC {time}",
140317
+ "quota.resetsInAt": "\u8DDD\u91CD\u8A2D {relative}\uFF0C\u65BC {time}",
140318
+ "quota.at": "{time} \u91CD\u8A2D",
140319
+ "quota.relativeAt": "{relative}\uFF0C{time} \u91CD\u8A2D",
140320
+ "quota.compactLabel": "{label}\uFF1A",
140321
+ "quota.available": "\u53EF\u7528",
140322
+ "quota.elapsed": "\u5DF2\u904E {percent}%",
140323
+ "quota.elapsedAt": "{elapsed}\uFF0C{time} \u91CD\u8A2D",
140324
+ "memory.label": "\u8A18\u61B6\u9AD4",
140325
+ "cost.session": "\u8CBB\u7528 {amount}",
140326
+ "cost.estimated": "\u4F30\u7B97 {amount}",
140327
+ "cost.today": "\u4ECA\u65E5 {amount}",
140328
+ "advisor.name": "\u9867\u554F\uFF1A{name}",
140329
+ "outputStyle.name": "\u8F38\u51FA\u98A8\u683C\uFF1A{name}",
140330
+ "route.via": "\u7D93\u7531 {target}",
140331
+ "speed.rate": "\u8F38\u51FA\uFF1A{rate} tok/s",
140332
+ "headroom.label": "headroom {parts}",
140333
+ "headroom.saved": "\u5DF2\u7BC0\u7701 {tokens}",
140334
+ "headroom.overall": "\u7E3D\u8A08 {percent}%",
140335
+ "version.label": "CC v{version}",
140336
+ "vcs.conflict": "!\u885D\u7A81",
140337
+ "vcs.detached": "\u5206\u96E2\u65BC {commit}",
140338
+ "effort.low": "\u4F4E",
140339
+ "effort.medium": "\u4E2D",
140340
+ "effort.high": "\u9AD8",
140341
+ "effort.xhigh": "\u8D85\u9AD8",
140342
+ "effort.max": "\u6700\u9AD8",
140343
+ "more": "\u53E6\u6709 {count} \u500B",
140344
+ "addedDirs.label": "\u9644\u52A0\u76EE\u9304\uFF1A{dirs}",
140345
+ "sessionTime.started": "\u958B\u59CB\uFF1A{time}",
140346
+ "sessionTime.lastReply": "\u4E0A\u6B21\u56DE\u8986\uFF1A{ago}",
140347
+ "time.justNow": "\u525B\u525B",
140348
+ "time.ago": "{value}\u524D",
140349
+ "promptCache.label": "\u5FEB\u53D6",
140350
+ "promptCache.expired": "\u5DF2\u904E\u671F",
140351
+ "promptCache.until": "\u81F3 {time}",
140352
+ "tokens.summary": "\u8A5E\u5143 {total}\uFF08{parts}\uFF09",
140353
+ "tokens.input": "\u8F38\u5165 {count}",
140354
+ "tokens.output": "\u8F38\u51FA {count}",
140355
+ "tokens.cache": "\u5FEB\u53D6 {count}",
140356
+ "list.separator": "\uFF0C",
140357
+ "compactions.label": "\u58D3\u7E2E\u6B21\u6578\uFF1A{count}",
140358
+ "environment.claudeMd.one": "{count} \u500B CLAUDE.md",
140359
+ "environment.claudeMd.other": "{count} \u500B CLAUDE.md",
140360
+ "environment.rules.one": "{count} \u689D\u898F\u5247",
140361
+ "environment.rules.other": "{count} \u689D\u898F\u5247",
140362
+ "environment.mcp.one": "{count} \u500B MCP",
140363
+ "environment.mcp.other": "{count} \u500B MCP",
140364
+ "environment.hooks.one": "{count} \u500B\u9264\u5B50",
140365
+ "environment.hooks.other": "{count} \u500B\u9264\u5B50"
140366
+ };
140367
+
140368
+ // src/statusline/messages/catalogues.ts
140369
+ var CATALOGUES = { en: EN2, "zh-Hans": ZH_HANS, "zh-Hant": ZH_HANT };
140370
+ var PLACEHOLDER = /\{(\w+)\}/g;
140371
+ function fillPlaceholders(pattern, values) {
140372
+ return pattern.replace(PLACEHOLDER, (_placeholder, name) => {
140373
+ const value2 = values[name];
140374
+ if (value2 === void 0) {
140375
+ throw new TypeError(`message "${pattern}" needs a value for {${name}}`);
140376
+ }
140377
+ return String(value2);
140378
+ });
140379
+ }
140380
+ function translatorFor(language) {
140381
+ const messages = CATALOGUES[language];
140382
+ return (id2, ...values) => fillPlaceholders(messages[id2], values[0] ?? {});
140383
+ }
140384
+
140385
+ // src/statusline/barGrid.ts
140386
+ var BRACKET_COLUMNS = 2;
140387
+ function chunk(items, size) {
140388
+ const chunks = [];
140389
+ for (let start = 0; start < items.length; start += size) {
140390
+ chunks.push(items.slice(start, start + size));
140391
+ }
140392
+ return chunks;
140393
+ }
140394
+ function lastColumnOf(index, rowLength, columns) {
140395
+ return index === rowLength - 1 ? columns - 1 : index;
140396
+ }
140397
+ function measureGrid(rows, separatorLength, baseBarCells) {
140398
+ const columns = Math.max(...rows.map((row) => row.length));
140399
+ const prefixWidths = Array.from({ length: columns }, () => 0);
140400
+ const suffixWidths = Array.from({ length: columns }, () => 0);
140401
+ for (const row of rows) {
140402
+ row.forEach((cell, index) => {
140403
+ const last = lastColumnOf(index, row.length, columns);
140404
+ prefixWidths[index] = Math.max(prefixWidths[index] ?? 0, visibleLength(cell.prefix));
140405
+ suffixWidths[last] = Math.max(suffixWidths[last] ?? 0, visibleLength(cell.suffix));
140406
+ });
140407
+ }
140408
+ const fixed = [...prefixWidths, ...suffixWidths].reduce((total, width) => total + width, 0) + columns * (baseBarCells + BRACKET_COLUMNS);
140409
+ return { rows, columns, prefixWidths, suffixWidths, baseWidth: fixed + separatorLength * (columns - 1) };
140410
+ }
140411
+ function padTo(text5, width) {
140412
+ return text5 + " ".repeat(Math.max(0, width - visibleLength(text5)));
140413
+ }
140414
+ function renderGrid(grid, maxWidth, separator, baseBarCells) {
140415
+ const separatorLength = visibleLength(separator);
140416
+ const spare = Math.max(0, maxWidth - grid.baseWidth);
140417
+ const barCells = Array.from({ length: grid.columns }, (_, column) => baseBarCells + Math.floor(spare / grid.columns) + (column < spare % grid.columns ? 1 : 0));
140418
+ const blockWidths = barCells.map((cells) => cells + BRACKET_COLUMNS);
140419
+ return grid.rows.map(
140420
+ (row) => row.map((cell, index) => {
140421
+ const last = lastColumnOf(index, row.length, grid.columns);
140422
+ let blockWidth = blockWidths[index] ?? 0;
140423
+ for (let column = index + 1; column <= last; column += 1) {
140424
+ blockWidth += separatorLength + (grid.suffixWidths[column - 1] ?? 0) + (grid.prefixWidths[column] ?? 0) + (blockWidths[column] ?? 0);
140425
+ }
140426
+ const prefix = padTo(cell.prefix, grid.prefixWidths[index] ?? 0);
140427
+ const bar = cell.draw(blockWidth - BRACKET_COLUMNS);
140428
+ const suffix = index === row.length - 1 ? cell.suffix : padTo(cell.suffix, grid.suffixWidths[last] ?? 0);
140429
+ return `${prefix}${bar}${suffix}`;
140430
+ }).join(separator)
140431
+ );
140432
+ }
140433
+ function drawInline(group, separator, baseBarCells) {
140434
+ return group.map((cell) => `${cell.prefix}${cell.draw(baseBarCells)}${cell.suffix}`).join(separator);
140435
+ }
140436
+ function layoutBarGrid(units, maxWidth, separator, baseBarCells) {
140437
+ const nonEmpty = units.map((unit) => unit.filter((group) => group.length > 0)).filter((unit) => unit.length > 0);
140438
+ if (nonEmpty.length === 0) {
140439
+ return [];
140440
+ }
140441
+ const separatorLength = visibleLength(separator);
140442
+ const groups = nonEmpty.flat();
140443
+ const candidates = [measureGrid(nonEmpty.map((unit) => unit.flat()), separatorLength, baseBarCells)];
140444
+ const chunked = (perRow) => measureGrid(groups.flatMap((group) => chunk(group, perRow)), separatorLength, baseBarCells);
140445
+ const fewest = nonEmpty.length > 1 ? 1 : 2;
140446
+ for (let perRow = Math.max(...groups.map((group) => group.length)); perRow >= fewest; perRow -= 1) {
140447
+ candidates.push(chunked(perRow));
140448
+ }
140449
+ const fitting = candidates.find((grid) => grid.baseWidth <= maxWidth);
140450
+ if (fitting !== void 0) {
140451
+ return renderGrid(fitting, maxWidth, separator, baseBarCells);
140452
+ }
140453
+ if (groups.length > 1) {
140454
+ return groups.flatMap((group) => layoutBarGrid([[group]], maxWidth, separator, baseBarCells));
140455
+ }
140456
+ return renderGrid(chunked(1), maxWidth, separator, baseBarCells);
140457
+ }
140458
+
140459
+ // src/statusline/rowsLayout.ts
140460
+ var BREAK = { kind: "lines", lines: [] };
140461
+ function isEmpty(output2) {
140462
+ return output2.kind === "bars" ? output2.cells.length === 0 : output2.lines.length === 0;
140463
+ }
140464
+ function oneLineOf(output2, barCells) {
140465
+ if (output2.kind === "bars") {
140466
+ return drawInline(output2.cells, SEPARATOR2, barCells);
140467
+ }
140468
+ return output2.lines.length === 1 ? output2.lines[0] : void 0;
140469
+ }
140470
+ function alignRight(lines, rightAlign, width) {
140471
+ const split = lines.findIndex(({ name }) => rightAlign.has(name));
140472
+ if (split < 1) {
140473
+ return void 0;
140474
+ }
140475
+ const left = lines.slice(0, split).map(({ text: text5 }) => text5).join(SEPARATOR2);
140476
+ const right = lines.slice(split).map(({ text: text5 }) => text5).join(SEPARATOR2);
140477
+ return `${left}${" ".repeat(width - visibleLength(left) - visibleLength(right))}${right}`;
140478
+ }
140479
+ function itemOf(row) {
140480
+ return row.output.kind === "bars" ? { kind: "bars", unit: [row.output.cells] } : { kind: "lines", lines: row.output.lines };
140481
+ }
140482
+ function mergedItems(rows, settings2, width) {
140483
+ const rightAlign = new Set(settings2.rightAlign);
140484
+ const aligned = rows.some((row, index) => index > 0 && rightAlign.has(row.name));
140485
+ if (!aligned && rows.every((row) => row.output.kind === "bars")) {
140486
+ return [{ kind: "bars", unit: rows.flatMap((row) => row.output.kind === "bars" ? [row.output.cells] : []) }];
140487
+ }
140488
+ const lines = rows.map((row) => ({ name: row.name, text: oneLineOf(row.output, settings2.barCells) }));
140489
+ const texts = lines.flatMap(({ name, text: text5 }) => text5 === void 0 ? [] : [{ name, text: text5 }]);
140490
+ if (texts.length === rows.length) {
140491
+ const joined3 = texts.map(({ text: text5 }) => text5).join(SEPARATOR2);
140492
+ if (visibleLength(joined3) <= width) {
140493
+ return [{ kind: "lines", lines: [alignRight(texts, rightAlign, width) ?? joined3] }];
140494
+ }
140495
+ }
140496
+ return rows.map(itemOf);
140497
+ }
140498
+ var BARS_RUN = -1;
140499
+ function runsOf(rows, settings2) {
140500
+ const groupOf2 = new Map(settings2.merge.flatMap((group, index) => group.map((name) => [name, index])));
140501
+ const keyOf3 = (row) => groupOf2.get(row.name) ?? (settings2.mergeBars && row.output.kind === "bars" ? BARS_RUN : void 0);
140502
+ const runs = [];
140503
+ const add = (key, row) => {
140504
+ const last = runs.at(-1);
140505
+ if (last !== void 0 && key !== void 0 && last.key === key) {
140506
+ last.rows.push(row);
140507
+ } else {
140508
+ runs.push({ key, rows: [row] });
140509
+ }
140510
+ };
140511
+ for (const row of rows) {
140512
+ add(keyOf3(row), row);
140513
+ }
140514
+ const silent = (run) => run.rows.every((row) => isEmpty(row.output) && row.output.kind === "bars");
140515
+ const kept = [];
140516
+ for (const run of runs.filter((candidate) => !silent(candidate))) {
140517
+ const last = kept.at(-1);
140518
+ if (last !== void 0 && run.key === BARS_RUN && last.key === BARS_RUN) {
140519
+ last.rows.push(...run.rows);
140520
+ } else {
140521
+ kept.push(run);
140522
+ }
140523
+ }
140524
+ return kept.map((run) => run.rows);
140525
+ }
140526
+ function layoutRows(rows, settings2, width) {
140527
+ const items = runsOf(rows, settings2).flatMap((run) => {
140528
+ const present = run.filter((row) => !isEmpty(row.output));
140529
+ if (present.length === 0) {
140530
+ return [BREAK];
140531
+ }
140532
+ return present.length > 1 ? mergedItems(present, settings2, width) : present.map(itemOf);
140533
+ });
140534
+ const lines = [];
140535
+ let units = [];
140536
+ const flushBars = () => {
140537
+ lines.push(...layoutBarGrid(units, width, SEPARATOR2, settings2.barCells));
140538
+ units = [];
140539
+ };
140540
+ for (const item of items) {
140541
+ if (item.kind === "bars") {
140542
+ units.push(item.unit);
140543
+ } else {
140544
+ flushBars();
140545
+ lines.push(...item.lines);
140546
+ }
140547
+ }
140548
+ flushBars();
140549
+ return lines;
140550
+ }
140551
+ function compactUnits(rows, barCells) {
140552
+ return rows.flatMap(({ output: output2 }) => output2.kind === "bars" ? output2.cells.map((cell) => drawInline([cell], SEPARATOR2, barCells)) : [...output2.lines]);
140553
+ }
140554
+
140099
140555
  // src/statusline/transcript/reader.ts
140100
140556
  var import_node_crypto27 = require("node:crypto");
140101
140557
  init_zod();
@@ -140375,6 +140831,9 @@ function foldNewer(state, bytes, offset) {
140375
140831
 
140376
140832
  // src/statusline/render.ts
140377
140833
  var RESERVED_COLUMNS = 4;
140834
+ function lineWidthOf(terminalColumns) {
140835
+ return Math.max(MIN_STATUSLINE_COLUMNS, terminalColumns - RESERVED_COLUMNS);
140836
+ }
140378
140837
  function once2(read) {
140379
140838
  let kept;
140380
140839
  return () => {
@@ -140382,9 +140841,14 @@ function once2(read) {
140382
140841
  return kept.value;
140383
140842
  };
140384
140843
  }
140844
+ var RULE_CHARACTER = "\u2500";
140845
+ function ruleLine(headerLines, width, palette) {
140846
+ const widest = Math.max(MIN_STATUSLINE_COLUMNS, ...headerLines.map(visibleLength));
140847
+ return palette.paint("label", RULE_CHARACTER.repeat(Math.min(width, widest)));
140848
+ }
140385
140849
  function renderStatuslineBlock(input2) {
140386
140850
  const { terminalWidth, settings: settings2 = STATUSLINE_DEFAULTS, elements = ELEMENTS } = input2;
140387
- const width = Math.max(TWENTY, terminalWidth - RESERVED_COLUMNS);
140851
+ const width = input2.lineWidth ?? lineWidthOf(terminalWidth);
140388
140852
  const context = {
140389
140853
  summary: input2.summary,
140390
140854
  view: input2.view,
@@ -140393,6 +140857,7 @@ function renderStatuslineBlock(input2) {
140393
140857
  terminalWidth,
140394
140858
  width,
140395
140859
  settings: settings2,
140860
+ t: translatorFor(settings2.language),
140396
140861
  palette: createPalette(settings2.colours, colourEnabled(input2.ports.env)),
140397
140862
  ports: input2.ports,
140398
140863
  transcriptIdentity: once2(() => input2.payload.transcript_path === void 0 ? { model: void 0, advisor: void 0 } : readTranscriptIdentity(input2.ports, input2.payload.transcript_path)),
@@ -140406,26 +140871,14 @@ function renderStatuslineBlock(input2) {
140406
140871
  return text5 === void 0 ? [] : { name, text: context.palette.paint(HEADER_ROLES[name], text5) };
140407
140872
  });
140408
140873
  const header = headerUnits(parts, settings2.git.branchOverflow);
140409
- const lines = [];
140410
- if (header.length > 0) {
140411
- lines.push(layoutHeader(header, width, SEPARATOR2));
140874
+ const drawn = settings2.layout.rows.map((name) => ({ name, output: elements.rows[name](context) }));
140875
+ if (settings2.layout.mode === "compact") {
140876
+ return packLines([...header, ...compactUnits(drawn, settings2.bar.width)], width, SEPARATOR2).map((line) => line.join(SEPARATOR2)).join("\n");
140412
140877
  }
140413
- let barGroups = [];
140414
- const flushBars = () => {
140415
- lines.push(...layoutBarGrid(barGroups, width, SEPARATOR2, settings2.bar.width));
140416
- barGroups = [];
140417
- };
140418
- for (const name of settings2.layout.rows) {
140419
- const output2 = elements.rows[name](context);
140420
- if (output2.kind === "bars") {
140421
- barGroups.push(output2.cells);
140422
- } else {
140423
- flushBars();
140424
- lines.push(...output2.lines);
140425
- }
140426
- }
140427
- flushBars();
140428
- return lines.join("\n");
140878
+ const headerLines = header.length > 0 ? layoutHeader(header, width, SEPARATOR2).split("\n") : [];
140879
+ const rowLines = layoutRows(drawn, { mergeBars: settings2.layout.mergeBars, merge: settings2.layout.merge, rightAlign: settings2.layout.rightAlign, barCells: settings2.bar.width }, width);
140880
+ const rule = settings2.layout.rule === "belowHeader" && headerLines.length > 0 && rowLines.length > 0 ? [ruleLine(headerLines, width, context.palette)] : [];
140881
+ return [...headerLines, ...rule, ...rowLines].join("\n");
140429
140882
  }
140430
140883
 
140431
140884
  // src/statusline/commands.ts
@@ -140433,13 +140886,22 @@ init_keys();
140433
140886
  init_settings2();
140434
140887
 
140435
140888
  // src/statusline/width.ts
140889
+ init_statusline();
140436
140890
  var DEFAULT_COLUMNS = 80;
140437
- function terminalWidthOf(payload, env) {
140891
+ function widthsOf(payload, env, layout) {
140892
+ const configured = { terminal: layout.maxWidth, line: layout.maxWidth };
140893
+ if (layout.forceMaxWidth) {
140894
+ return configured;
140895
+ }
140896
+ const reported = (terminal) => ({ terminal, line: lineWidthOf(terminal) });
140438
140897
  if (typeof payload === "object" && payload !== null && "terminal_width" in payload && typeof payload.terminal_width === "number" && Number.isFinite(payload.terminal_width) && payload.terminal_width > 0) {
140439
- return Math.floor(payload.terminal_width);
140898
+ return reported(Math.floor(payload.terminal_width));
140440
140899
  }
140441
140900
  const columns = Number.parseInt(env.COLUMNS ?? "", 10);
140442
- return Number.isFinite(columns) && columns > 0 ? columns : DEFAULT_COLUMNS;
140901
+ if (Number.isFinite(columns) && columns > 0) {
140902
+ return reported(columns);
140903
+ }
140904
+ return layout.maxWidth >= MIN_STATUSLINE_COLUMNS ? configured : reported(DEFAULT_COLUMNS);
140443
140905
  }
140444
140906
 
140445
140907
  // src/statusline/commands.ts
@@ -140548,7 +141010,8 @@ function registerStatuslineCommand(program2, deps) {
140548
141010
  }
140549
141011
  }
140550
141012
  const view = { ...viewOf(clientPayload), ...stackedUnderDefault ? { modelDisplayName: void 0 } : {} };
140551
- console.log(renderStatuslineBlock({ summary, view, payload: clientPayload, terminalWidth: terminalWidthOf(payload, process.env), nowMs, settings: settings2, ports: realStatuslinePorts(process.env, deps.paths.statuslineDir) }));
141013
+ const widths = widthsOf(payload, process.env, settings2.layout);
141014
+ console.log(renderStatuslineBlock({ summary, view, payload: clientPayload, terminalWidth: widths.terminal, lineWidth: widths.line, nowMs, settings: settings2, ports: realStatuslinePorts(process.env, deps.paths.statuslineDir) }));
140552
141015
  }),
140553
141016
  ["$ agent-shim statusline # a client's statusline setting names this; it renders or delegates"]
140554
141017
  );