claude-use 11.64.0 → 11.65.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
@@ -24812,10 +24812,6 @@ function spawnSyncBlocking(operation, command, args, options) {
24812
24812
  refuseToBlockInRole(operation);
24813
24813
  return (0, import_node_child_process2.spawnSync)(command, args, options ?? {});
24814
24814
  }
24815
- function execFileSyncBlocking(operation, file2, args, options) {
24816
- refuseToBlockInRole(operation);
24817
- return (0, import_node_child_process2.execFileSync)(file2, args, options ?? {});
24818
- }
24819
24815
  var import_node_child_process2;
24820
24816
  var init_blockingSpawn = __esm({
24821
24817
  "src/blockingSpawn.ts"() {
@@ -25391,18 +25387,37 @@ var init_string_width = __esm({
25391
25387
  function drawsNothing(text5) {
25392
25388
  return stringWidth(text5.replace(BLANK_CELLS, "")) === 0;
25393
25389
  }
25394
- var BLANK_CELLS;
25390
+ var BLANK_CELLS, BLANK_CELLS_BUT_SPACE;
25395
25391
  var init_blank = __esm({
25396
25392
  "src/statusline/blank.ts"() {
25397
25393
  "use strict";
25398
25394
  init_string_width();
25399
25395
  BLANK_CELLS = /[\p{Zs}\u2800\u3164\uFFA0]/gu;
25396
+ BLANK_CELLS_BUT_SPACE = new RegExp(`[${BLANK_CELLS.source}--[ ]]`, "gv");
25400
25397
  }
25401
25398
  });
25402
25399
 
25403
25400
  // src/statusline/graphemes.ts
25401
+ function* graphemeStream(text5) {
25402
+ for (const part of SEGMENTER.segment(text5)) {
25403
+ yield part.segment;
25404
+ }
25405
+ }
25404
25406
  function graphemesOf(text5) {
25405
- return Array.from(SEGMENTER.segment(text5), (part) => part.segment);
25407
+ return Array.from(graphemeStream(text5));
25408
+ }
25409
+ function leadingGraphemes(text5, count2) {
25410
+ const taken = [];
25411
+ if (count2 <= 0) {
25412
+ return taken;
25413
+ }
25414
+ for (const grapheme of graphemeStream(text5)) {
25415
+ taken.push(grapheme);
25416
+ if (taken.length >= count2) {
25417
+ break;
25418
+ }
25419
+ }
25420
+ return taken;
25406
25421
  }
25407
25422
  var SEGMENTER;
25408
25423
  var init_graphemes = __esm({
@@ -25480,7 +25495,7 @@ function resolveStatusline(settings2) {
25480
25495
  }
25481
25496
  return resolved;
25482
25497
  }
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;
25498
+ var STATUSLINE_HEADER_SEGMENTS, STATUSLINE_ROWS, STATUSLINE_SESSION_TIME_PARTS, PROMPT_CACHE_TTL_SECONDS, ORANGE_PALETTE_INDEX, 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, MAX_EXTRA_COMMAND_ARGUMENTS, MAX_EXTRA_COMMAND_ARGUMENT_CHARS, STATUSLINE_EXTRA_GROUP, commandArgument, 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;
25484
25499
  var init_statusline = __esm({
25485
25500
  "src/config/statusline.ts"() {
25486
25501
  "use strict";
@@ -25489,10 +25504,11 @@ var init_statusline = __esm({
25489
25504
  init_blank();
25490
25505
  init_graphemes();
25491
25506
  init_languages();
25492
- STATUSLINE_HEADER_SEGMENTS = ["model", "provider", "route", "account", "identity", "headroom", "project", "vcs", "effort", "advisor", "version", "outputStyle", "cost", "dailyCost", "sessionName", "duration", "speed"];
25507
+ STATUSLINE_HEADER_SEGMENTS = ["model", "provider", "route", "account", "identity", "headroom", "project", "vcs", "effort", "advisor", "version", "outputStyle", "cost", "dailyCost", "sessionName", "duration", "speed", "extra"];
25493
25508
  STATUSLINE_ROWS = ["context", "quota", "addedDirs", "gitFiles", "memory", "environment", "sessionTime", "promptCache", "compactions", "tokens", "tools", "skills", "mcp", "agents", "todos"];
25494
25509
  STATUSLINE_SESSION_TIME_PARTS = ["started", "lastReply"];
25495
25510
  PROMPT_CACHE_TTL_SECONDS = { fiveMinutes: 300, oneHour: 3600 };
25511
+ ORANGE_PALETTE_INDEX = 208;
25496
25512
  STATUSLINE_COLOUR_NAMES = [
25497
25513
  "default",
25498
25514
  "dim",
@@ -25521,14 +25537,14 @@ var init_statusline = __esm({
25521
25537
  PRESET_BUNDLES = {
25522
25538
  standard: { layout: { header: DEFAULT_HEADER_SEGMENTS, rows: DEFAULT_ROWS }, git: GIT_WITH_DIRTY_MARKER, jj: JJ_OFF, usage: { resetLabel: false }, context: { breakdown: "never" } },
25523
25539
  full: {
25524
- layout: { header: ["model", "project", "vcs", "effort", "advisor", "version", "outputStyle", "cost", "sessionName", "duration"], rows: ["context", "quota", "addedDirs", "memory", "environment", "tools", "skills", "mcp", "agents", "todos", "promptCache", "compactions", "tokens"] },
25540
+ layout: { header: ["model", "project", "vcs", "effort", "advisor", "version", "extra", "outputStyle", "cost", "sessionName", "duration"], rows: ["context", "quota", "addedDirs", "memory", "environment", "tools", "skills", "mcp", "agents", "todos", "promptCache", "compactions", "tokens"] },
25525
25541
  git: GIT_WITH_DIRTY_MARKER,
25526
25542
  jj: { enabled: true, showDirty: true, showConflicts: true },
25527
25543
  usage: { resetLabel: true },
25528
25544
  context: { breakdown: "critical" }
25529
25545
  },
25530
- essential: { layout: { header: ["model", "project", "vcs", "duration"], rows: ["context", "addedDirs", "tools", "agents", "todos"] }, 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" } }
25546
+ essential: { layout: { header: ["model", "project", "vcs", "extra", "duration"], rows: ["context", "addedDirs", "tools", "agents", "todos"] }, git: GIT_WITH_DIRTY_MARKER, jj: JJ_OFF, usage: { resetLabel: true }, context: { breakdown: "never" } },
25547
+ minimal: { layout: { header: ["model", "project", "vcs", "extra"], rows: ["context", "addedDirs"] }, git: GIT_WITH_DIRTY_MARKER, jj: JJ_OFF, usage: { resetLabel: true }, context: { breakdown: "never" } }
25532
25548
  };
25533
25549
  STATUSLINE_PATH_LEVELS = ["1", "2", "3", "full"];
25534
25550
  STATUSLINE_USAGE_VALUES = ["used", "remaining"];
@@ -25542,6 +25558,10 @@ var init_statusline = __esm({
25542
25558
  MAX_BAR_CELLS = 40;
25543
25559
  MAX_ACCOUNT_USER_CHARS = 254;
25544
25560
  MAX_DISPLAY_TEXT_CHARS = 80;
25561
+ MAX_EXTRA_COMMAND_ARGUMENTS = 16;
25562
+ MAX_EXTRA_COMMAND_ARGUMENT_CHARS = 1024;
25563
+ STATUSLINE_EXTRA_GROUP = "extra";
25564
+ commandArgument = external_exports.string().max(MAX_EXTRA_COMMAND_ARGUMENT_CHARS).refine((argument) => !argument.includes("\0"), "must not contain a NUL character");
25545
25565
  LABEL_RE2 = /^[^\p{C}\p{Z}]+(?: [^\p{C}\p{Z}]+)*$/u;
25546
25566
  OPTIONAL_LABEL_RE = /^(?:[^\p{C}\p{Z}]+(?: [^\p{C}\p{Z}]+)*)?$/u;
25547
25567
  mergeGroups = external_exports.array(distinctList(external_exports.enum(STATUSLINE_ROWS)).min(2)).refine((groups) => {
@@ -25604,6 +25624,15 @@ var init_statusline = __esm({
25604
25624
  estimate: external_exports.enum(STATUSLINE_CONTEXT_ESTIMATES).describe(`What to draw when the client reports no percentage of the window in use, or reports 0 while tokens are already held (which is how a client says it has not worked it out yet): never (nothing is estimated: a percentage reported, 0 included, is drawn as it is, and none reported draws nothing), raw (the tokens held over the window), or buffered (that, plus the ${String(AUTOCOMPACT_RESERVE_FRACTION * MAX_PERCENT)}% of the window Claude Code reserves for compaction, rising from nothing at ${String(AUTOCOMPACT_RESERVE_RAMP_START * MAX_PERCENT)}% of the window held to the whole reserve at ${String(AUTOCOMPACT_RESERVE_RAMP_END * MAX_PERCENT)}%).`),
25605
25625
  breakdown: external_exports.enum(["never", "critical"]).describe("Whether to add the input and cache tokens of the last request to the context row once its use reaches context.criticalAt.")
25606
25626
  },
25627
+ customLine: {
25628
+ text: overrideText.describe(`A line of your own text to draw, in colours.custom; empty draws nothing. It is refused when longer than ${String(MAX_DISPLAY_TEXT_CHARS)} characters or when it holds control, format or separator characters, and words are separated by single spaces. A character that passes but draws nothing, such as a braille blank, is removed, and the line is cut to the usable width.`),
25629
+ position: external_exports.enum(["first", "last"]).describe("Where the custom line sits: first draws it above the header, and last below the last row, as a line of its own in either layout mode.")
25630
+ },
25631
+ extra: {
25632
+ command: external_exports.array(commandArgument).max(MAX_EXTRA_COMMAND_ARGUMENTS).refine((command) => command[0]?.startsWith("-") !== true, "the program, the first item, must not start with a dash, which the system would read as an option: name it by an absolute path").describe(
25633
+ `The program and arguments the extra segment runs, as a list and not a shell string (for example ["git", "describe", "--tags"]). The first line of its standard output that shows something, or the label of a JSON object it prints, is the segment; a line with nothing a person could see in it, such as spaces, zero-width characters or an escape sequence alone, is skipped. Escape sequences are removed from the whole output first, so an operating system command with no terminator removes everything up to the next escape character or the end of the output, line breaks included. A command that fails or prints nothing draws nothing. It is refused when it has more than ${String(MAX_EXTRA_COMMAND_ARGUMENTS)} arguments (the program included), when an argument is longer than ${String(MAX_EXTRA_COMMAND_ARGUMENT_CHARS)} characters or holds a NUL, and when the program starts with a dash. It runs on every refresh with your privileges and the statusline's whole environment. Its output is written to a file the system limits in size. That limit applies to every file it writes and every process it starts, so a program that writes a large cache is stopped and draws nothing, and so does one whose output reaches the limit. A process it starts is left running when it is killed for outrunning its time limit or when a newer update cancels the refresh. Because it runs a program with your privileges, only your own configuration may set it. That means the global config, a profile in your config-profiles directory, a directory rule or a command-line assignment. A project file such as .agent-shim.json is refused, though it may select one of your profiles by name, and a config write through the door's API (an MCP agent or the web client with the writes grant) is refused the extra settings for the same reason.`
25634
+ )
25635
+ },
25607
25636
  bands: {
25608
25637
  warnAt: wholePercent.describe("The whole percentage of use at which a bar turns yellow; it must be below criticalAt."),
25609
25638
  criticalAt: wholePercent.describe("The whole percentage of use at which a bar turns red.")
@@ -25660,7 +25689,8 @@ var init_statusline = __esm({
25660
25689
  git: colourValue.describe("The colour of the version control segment's wrapper text (`git:(` and `)`)."),
25661
25690
  gitBranch: colourValue.describe("The colour of the branch or bookmark and its ahead, behind and dirty markers."),
25662
25691
  activity: colourValue.describe("The colour of the names of the tools, skills and MCP servers the tools, skills and mcp rows draw. Their running markers take colours.warning and their finished markers colours.context."),
25663
- agent: colourValue.describe("The colour of an agent's type in the agents row.")
25692
+ agent: colourValue.describe("The colour of an agent's type in the agents row."),
25693
+ custom: colourValue.describe("The colour of the custom line.")
25664
25694
  },
25665
25695
  project: {
25666
25696
  pathLevels: external_exports.enum(STATUSLINE_PATH_LEVELS).describe("How many trailing directories of the working directory the project segment shows: 1, 2 or 3, or full for the whole absolute path."),
@@ -25687,7 +25717,7 @@ var init_statusline = __esm({
25687
25717
  LANGUAGE_ALIASES = { zh: "zh-Hans", "zh-TW": "zh-Hant" };
25688
25718
  TOP_LEVEL = {
25689
25719
  language: external_exports.enum(STATUSLINE_LANGUAGES).describe(LANGUAGE_DESCRIPTION),
25690
- 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, tools, skills, mcp, agents, todos, prompt cache, compactions and session tokens rows, with the token breakdown at high use, essential adds the duration, the added directories row and the tools, agents and todos rows, and minimal adds the added directories row alone.")
25720
+ 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, the extra segment once extra.command is set, 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, tools, skills, mcp, agents, todos, prompt cache, compactions and session tokens rows, with the token breakdown at high use, essential adds the duration, the added directories row and the tools, agents and todos rows, and minimal adds the added directories row alone.")
25691
25721
  };
25692
25722
  StatuslineSchema = external_exports.strictObject({
25693
25723
  language: external_exports.enum(LANGUAGE_TAGS).transform(canonicalLanguage).describe(LANGUAGE_DESCRIPTION).optional(),
@@ -25699,6 +25729,8 @@ var init_statusline = __esm({
25699
25729
  effort: external_exports.strictObject(SHAPES.effort).partial().optional(),
25700
25730
  advisor: external_exports.strictObject(SHAPES.advisor).partial().optional(),
25701
25731
  context: external_exports.strictObject({ ...SHAPES.context, warnAt: unsettable(SHAPES.context.warnAt), criticalAt: unsettable(SHAPES.context.criticalAt), autoCompactWindow: unsettable(SHAPES.context.autoCompactWindow) }).partial().optional(),
25732
+ customLine: external_exports.strictObject(SHAPES.customLine).partial().optional(),
25733
+ extra: external_exports.strictObject(SHAPES.extra).partial().optional(),
25702
25734
  bands: external_exports.strictObject(SHAPES.bands).partial().optional(),
25703
25735
  labels: external_exports.strictObject(SHAPES.labels).partial().optional(),
25704
25736
  bar: external_exports.strictObject(SHAPES.bar).partial().optional(),
@@ -25724,6 +25756,8 @@ var init_statusline = __esm({
25724
25756
  effort: external_exports.strictObject(SHAPES.effort),
25725
25757
  advisor: external_exports.strictObject(SHAPES.advisor),
25726
25758
  context: external_exports.strictObject(SHAPES.context),
25759
+ customLine: external_exports.strictObject(SHAPES.customLine),
25760
+ extra: external_exports.strictObject(SHAPES.extra),
25727
25761
  bands: external_exports.strictObject(SHAPES.bands),
25728
25762
  labels: external_exports.strictObject(SHAPES.labels),
25729
25763
  bar: external_exports.strictObject(SHAPES.bar),
@@ -25749,6 +25783,8 @@ var init_statusline = __esm({
25749
25783
  effort: { format: "full" },
25750
25784
  advisor: { override: "" },
25751
25785
  context: { bar: "shown", value: "both", estimate: "never", breakdown: "never" },
25786
+ customLine: { text: "", position: "last" },
25787
+ extra: { command: [] },
25752
25788
  bands: { warnAt: 70, criticalAt: 90 },
25753
25789
  labels: { fiveHour: "", sevenDay: "" },
25754
25790
  bar: { width: 10, filled: "\u2588", empty: "\u2591" },
@@ -25772,7 +25808,8 @@ var init_statusline = __esm({
25772
25808
  git: "magenta",
25773
25809
  gitBranch: "cyan",
25774
25810
  activity: "cyan",
25775
- agent: "magenta"
25811
+ agent: "magenta",
25812
+ custom: ORANGE_PALETTE_INDEX
25776
25813
  },
25777
25814
  project: { pathLevels: "1", addedDirsLayout: "inline" },
25778
25815
  git: { enabled: true, showDirty: true, showAheadBehind: false, showLineDiff: false, branchOverflow: "truncate", pushWarnAt: 0, pushCriticalAt: 0 },
@@ -28148,6 +28185,10 @@ var init_schema = __esm({
28148
28185
  configProfile: FileNameSchema.optional(),
28149
28186
  identity: IdentitySelectorSchema.optional(),
28150
28187
  when: WhenSchema.optional()
28188
+ }).superRefine((config2, context) => {
28189
+ if (config2.launch?.statusline?.[STATUSLINE_EXTRA_GROUP] !== void 0) {
28190
+ context.addIssue({ code: "custom", path: ["launch", "statusline", STATUSLINE_EXTRA_GROUP], message: "a project file cannot set the statusline's extra command: it runs a program, so only your own configuration (the global config, a profile, a directory rule) may set it" });
28191
+ }
28151
28192
  });
28152
28193
  HEADROOM_MODES = ["cache", "token"];
28153
28194
  HEADROOM_CCR_MODES = ["default", "lossless", "none"];
@@ -32690,6 +32731,9 @@ function keyOf(path71, declared) {
32690
32731
  if (leaf instanceof external_exports.ZodArray && leaf.element instanceof external_exports.ZodArray && leaf.element.element instanceof external_exports.ZodEnum) {
32691
32732
  return { ...common, kind: "groups", choices: Object.values(leaf.element.element.enum).map(String) };
32692
32733
  }
32734
+ if (leaf instanceof external_exports.ZodArray && leaf.element instanceof external_exports.ZodString) {
32735
+ return { ...common, kind: "textList", choices: [] };
32736
+ }
32693
32737
  throw new TypeError(`statusline setting ${path71.join(".")} has a kind the key listing does not describe`);
32694
32738
  }
32695
32739
  function walk(shape, prefix) {
@@ -32721,6 +32765,21 @@ function keyNamed(path71) {
32721
32765
  }
32722
32766
  return found;
32723
32767
  }
32768
+ function textListOf(path71, raw) {
32769
+ if (raw === "") {
32770
+ return [];
32771
+ }
32772
+ let parsed;
32773
+ try {
32774
+ parsed = JSON.parse(raw);
32775
+ } catch {
32776
+ throw new UsageError(`${path71}: "${raw}" is not a JSON array of strings such as ["git","describe"].`);
32777
+ }
32778
+ if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== "string")) {
32779
+ throw new UsageError(`${path71}: "${raw}" is not a JSON array of strings such as ["git","describe"].`);
32780
+ }
32781
+ return parsed;
32782
+ }
32724
32783
  function parseStatuslineAssignment(text5) {
32725
32784
  const split = text5.indexOf("=");
32726
32785
  if (split < 1) {
@@ -32754,6 +32813,8 @@ function parseStatuslineAssignment(text5) {
32754
32813
  return { path: path71, value: raw === "" ? [] : raw.split(",") };
32755
32814
  case "groups":
32756
32815
  return { path: path71, value: raw === "" ? [] : raw.split(";").map((group) => group.split(",")) };
32816
+ case "textList":
32817
+ return { path: path71, value: textListOf(path71, raw) };
32757
32818
  default:
32758
32819
  return key.kind;
32759
32820
  }
@@ -37084,7 +37145,7 @@ var init_package = __esm({
37084
37145
  "package.json"() {
37085
37146
  package_default = {
37086
37147
  name: "claude-use",
37087
- version: "11.64.0",
37148
+ version: "11.65.0",
37088
37149
  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.",
37089
37150
  license: "MIT",
37090
37151
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -37156,7 +37217,7 @@ var init_package = __esm({
37156
37217
  "@semantic-release/npm": "^13.1.5",
37157
37218
  "@types/node": "^26.5.1",
37158
37219
  "@types/picomatch": "^4.0.3",
37159
- "@vitest/coverage-v8": "^4.1.11",
37220
+ "@vitest/coverage-v8": "^4.1.12",
37160
37221
  "conventional-changelog-conventionalcommits": "^10.4.0",
37161
37222
  esbuild: "^0.28.2",
37162
37223
  eslint: "^10.10.0",
@@ -37171,7 +37232,7 @@ var init_package = __esm({
37171
37232
  turbo: "^2.11.5",
37172
37233
  typescript: "^6.0.3",
37173
37234
  "typescript-eslint": "^8.70.0",
37174
- vitest: "^4.1.11"
37235
+ vitest: "^4.1.12"
37175
37236
  },
37176
37237
  main: "dist/index.cjs",
37177
37238
  module: "dist/index.mjs",
@@ -116425,7 +116486,7 @@ function registerProfileCommand(program2, deps) {
116425
116486
  withExamples(
116426
116487
  profile.command("set <name>").description(
116427
116488
  "Update a configuration profile's categories, entries, extends list, description or launch settings. With no options on a terminal, walks through its categories."
116428
- ).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) => {
116489
+ ).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, a list of free text such as extra.command is a JSON array of strings, 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) => {
116429
116490
  const { json: json2, ...options } = allOptions;
116430
116491
  requireProfileExists(paths, name);
116431
116492
  if (Object.entries(allOptions).every(([key, value2]) => key === "json" || value2 === void 0)) {
@@ -130844,6 +130905,7 @@ init_providersStore();
130844
130905
  // src/frontdoor/configSchemas.ts
130845
130906
  init_zod();
130846
130907
  init_schema();
130908
+ init_statusline();
130847
130909
  var RemovalConfirmationSchema = external_exports.boolean();
130848
130910
  var CredentialWriteSchema = (targets) => external_exports.strictObject({
130849
130911
  sources: external_exports.array(RemoteCredentialSourceSchema).min(1).optional(),
@@ -130896,6 +130958,13 @@ var ConfigIdentitySetInputSchema = external_exports.strictObject({
130896
130958
  var ConfigIdentitySetOutputSchema = storedMutationOutput("identity", "updated", IdentityValueSchema);
130897
130959
  var ConfigIdentityRemoveInputSchema = external_exports.strictObject({ name: external_exports.string().min(1), confirm: RemovalConfirmationSchema });
130898
130960
  var ConfigIdentityRemoveOutputSchema = mutationOutput("identity", "removed");
130961
+ var ConfigStatuslineSetSchema = external_exports.record(external_exports.string(), external_exports.unknown()).superRefine((settings2, context) => {
130962
+ for (const key of Object.keys(settings2)) {
130963
+ if (key === STATUSLINE_EXTRA_GROUP || key.startsWith(`${STATUSLINE_EXTRA_GROUP}.`)) {
130964
+ context.addIssue({ code: "custom", path: [key], message: `a config write through the API cannot set "${key}": the extra segment's command runs a program, so only your own configuration (the global config, a profile you edit yourself, a directory rule or a command-line assignment) may set it` });
130965
+ }
130966
+ }
130967
+ });
130899
130968
  var ConfigIdentityUseOutputSchema = mutationOutput("identity", "selected");
130900
130969
  var ConfigProfileAddInputSchema = external_exports.strictObject({
130901
130970
  name: external_exports.string().min(1),
@@ -130921,7 +130990,7 @@ var ConfigProfileSetInputSchema = external_exports.strictObject({
130921
130990
  explain: external_exports.boolean().optional(),
130922
130991
  proxyBypass: external_exports.union([external_exports.array(external_exports.string().min(1)), external_exports.literal(false)]).optional(),
130923
130992
  statusline: external_exports.strictObject({
130924
- set: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
130993
+ set: ConfigStatuslineSetSchema.optional(),
130925
130994
  unset: external_exports.array(external_exports.string()).optional()
130926
130995
  }).optional()
130927
130996
  }).optional()
@@ -138686,14 +138755,78 @@ function memoryUseFromMeminfo(text5) {
138686
138755
 
138687
138756
  // src/statusline/ports.ts
138688
138757
  var RUN_TIMEOUT_MS = 2e3;
138689
- var RUN_MAX_BUFFER_BYTES = 1048576;
138690
- function runProgram(file2, args, cwd) {
138758
+ var STATE_FILE_MODE = 384;
138759
+ var STATE_DIRECTORY_MODE = 448;
138760
+ var RUN_MAX_OUTPUT_BYTES = 1048576;
138761
+ var ULIMIT_BLOCK_BYTES = 512;
138762
+ var RUN_DIRECTORY_PREFIX = "agent-shim-run-";
138763
+ var RUN_DIRECTORY = "run";
138764
+ var RUN_FILE_MODE = 384;
138765
+ var STALE_AFTER_TIMEOUTS = 10;
138766
+ var STALE_RUN_DIRECTORY_MS = RUN_TIMEOUT_MS * STALE_AFTER_TIMEOUTS;
138767
+ function fileSizeLimitedCommand(shell, file2, args) {
138768
+ return { command: shell, args: ["-c", `ulimit -f ${String(RUN_MAX_OUTPUT_BYTES / ULIMIT_BLOCK_BYTES)}; exec "$0" "$@"`, file2, ...args] };
138769
+ }
138770
+ function readOutput(descriptor) {
138771
+ const { size } = import_node_fs23.default.fstatSync(descriptor);
138772
+ if (size >= RUN_MAX_OUTPUT_BYTES) {
138773
+ return void 0;
138774
+ }
138775
+ const buffer2 = Buffer.alloc(size);
138776
+ const read = import_node_fs23.default.readSync(descriptor, buffer2, 0, size, 0);
138777
+ return buffer2.toString("utf8", 0, read);
138778
+ }
138779
+ function sweepStaleRunDirectories(root) {
138780
+ let names;
138781
+ try {
138782
+ names = import_node_fs23.default.readdirSync(root);
138783
+ } catch {
138784
+ return;
138785
+ }
138786
+ for (const name of names.filter((entry) => entry.startsWith(RUN_DIRECTORY_PREFIX))) {
138787
+ const directory = import_node_path55.default.join(root, name);
138788
+ try {
138789
+ if (Date.now() - import_node_fs23.default.lstatSync(directory).mtimeMs > STALE_RUN_DIRECTORY_MS) {
138790
+ discard(directory);
138791
+ }
138792
+ } catch {
138793
+ continue;
138794
+ }
138795
+ }
138796
+ }
138797
+ function runProgram(runRoot, file2, args, cwd, options = {}) {
138798
+ return options.outputInFile === true ? runWithOutputInFile(runRoot, file2, args, cwd) : runWithPipe(file2, args, cwd);
138799
+ }
138800
+ function runWithPipe(file2, args, cwd) {
138691
138801
  try {
138692
- return execFileSyncBlocking("a statusline command", file2, args, { cwd, encoding: "utf8", timeout: RUN_TIMEOUT_MS, maxBuffer: RUN_MAX_BUFFER_BYTES, stdio: ["ignore", "pipe", "ignore"], windowsHide: true });
138802
+ const result = spawnSyncBlocking("a statusline command", file2, args, { cwd, encoding: "utf8", timeout: RUN_TIMEOUT_MS, killSignal: "SIGKILL", maxBuffer: RUN_MAX_OUTPUT_BYTES, stdio: ["ignore", "pipe", "ignore"], windowsHide: true });
138803
+ return result.error === void 0 && result.status === 0 ? result.stdout : void 0;
138693
138804
  } catch {
138694
138805
  return void 0;
138695
138806
  }
138696
138807
  }
138808
+ function runWithOutputInFile(runRoot, file2, args, cwd) {
138809
+ let directory;
138810
+ try {
138811
+ sweepStaleRunDirectories(runRoot);
138812
+ import_node_fs23.default.mkdirSync(runRoot, { recursive: true, mode: STATE_DIRECTORY_MODE });
138813
+ directory = import_node_fs23.default.mkdtempSync(import_node_path55.default.join(runRoot, RUN_DIRECTORY_PREFIX));
138814
+ const descriptor = import_node_fs23.default.openSync(import_node_path55.default.join(directory, "stdout"), "wx+", RUN_FILE_MODE);
138815
+ try {
138816
+ const limited = process.platform === "win32" ? { command: file2, args } : fileSizeLimitedCommand("/bin/sh", file2, args);
138817
+ const result = spawnSyncBlocking("a statusline command", limited.command, limited.args, { cwd, timeout: RUN_TIMEOUT_MS, killSignal: "SIGKILL", stdio: ["ignore", descriptor, "ignore"], windowsHide: true });
138818
+ return result.error === void 0 && result.status === 0 ? readOutput(descriptor) : void 0;
138819
+ } finally {
138820
+ import_node_fs23.default.closeSync(descriptor);
138821
+ }
138822
+ } catch {
138823
+ return void 0;
138824
+ } finally {
138825
+ if (directory !== void 0) {
138826
+ discard(directory);
138827
+ }
138828
+ }
138829
+ }
138697
138830
  function readText(file2) {
138698
138831
  try {
138699
138832
  return import_node_fs23.default.readFileSync(file2, "utf8");
@@ -138701,8 +138834,6 @@ function readText(file2) {
138701
138834
  return void 0;
138702
138835
  }
138703
138836
  }
138704
- var STATE_FILE_MODE = 384;
138705
- var STATE_DIRECTORY_MODE = 448;
138706
138837
  function discard(target) {
138707
138838
  try {
138708
138839
  import_node_fs23.default.rmSync(target, { force: true, recursive: true });
@@ -138713,7 +138844,7 @@ function discard(target) {
138713
138844
  function readMemoryUse() {
138714
138845
  const totalBytes = import_node_os12.default.totalmem();
138715
138846
  if (process.platform === "darwin") {
138716
- const output2 = runProgram("/usr/bin/vm_stat", [], process.cwd());
138847
+ const output2 = runWithPipe("/usr/bin/vm_stat", [], process.cwd());
138717
138848
  const usedBytes = output2 === void 0 ? void 0 : usedBytesFromVmStat(output2);
138718
138849
  return usedBytes === void 0 ? void 0 : { usedBytes, totalBytes };
138719
138850
  }
@@ -138746,7 +138877,7 @@ function realStatuslinePorts(env, stateDirectory) {
138746
138877
  return void 0;
138747
138878
  }
138748
138879
  },
138749
- run: runProgram,
138880
+ run: (file2, args, cwd, options) => runProgram(import_node_path55.default.join(stateDirectory, RUN_DIRECTORY), file2, args, cwd, options),
138750
138881
  entryKind: (target) => {
138751
138882
  try {
138752
138883
  return import_node_fs23.default.lstatSync(target).isDirectory() ? "directory" : "other";
@@ -138916,25 +139047,110 @@ function truncateWithEllipsis(text5, columns, ellipsis) {
138916
139047
  init_blank();
138917
139048
  init_graphemes();
138918
139049
  var ESCAPE_SEQUENCES = new RegExp(ESCAPE_SEQUENCE_PATTERN, "g");
139050
+ function stripEscapeSequences(text5) {
139051
+ return text5.replace(ESCAPE_SEQUENCES, "");
139052
+ }
138919
139053
  var CONTROL_AND_BIDI = /[\p{Cc}\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069\u206a-\u206f]/gu;
138920
139054
  function sanitiseDisplayText(text5) {
138921
- return text5.replace(ESCAPE_SEQUENCES, "").replace(CONTROL_AND_BIDI, "");
139055
+ return stripEscapeSequences(text5).replace(CONTROL_AND_BIDI, "");
138922
139056
  }
138923
139057
  function boundedDisplayText(text5) {
138924
- return graphemesOf(sanitiseDisplayText(text5).trim()).slice(0, MAX_DISPLAY_TEXT_CHARS).join("").trim();
139058
+ return leadingGraphemes(sanitiseDisplayText(text5).trim(), MAX_DISPLAY_TEXT_CHARS).join("").trim();
138925
139059
  }
138926
139060
  var TAG_SEQUENCE2 = "\\u{1F3F4}[\\u{E0020}-\\u{E007E}]+\\u{E007F}";
138927
139061
  var INVISIBLE_FORMAT = new RegExp(`(${TAG_SEQUENCE2})|(?![\\u200C\\u200D])\\p{Cf}`, "gu");
138928
139062
  var LINE_SEPARATORS = /[\u2028\u2029]/gu;
138929
139063
  var HANGUL_JAMO = "\\u1100-\\u115E\\u1161-\\u11FF\\uA960-\\uA97F\\uD7B0-\\uD7FF";
138930
139064
  var STANDALONE_HANGUL_FILLER = new RegExp(`(?<![${HANGUL_JAMO}])[\\u115F\\u1160](?![${HANGUL_JAMO}])`, "gu");
138931
- function visibleDisplayText(text5) {
138932
- const cleaned = sanitiseDisplayText(text5).replace(LINE_SEPARATORS, "").replace(BLANK_CELLS, " ").replace(STANDALONE_HANGUL_FILLER, " ").replace(INVISIBLE_FORMAT, (_match, tagSequence) => tagSequence ?? "");
138933
- return graphemesOf(cleaned).map((grapheme) => {
139065
+ var PREPEND_LETTERS = "\\u0D4E\\u{111C2}\\u{111C3}\\u{113D1}\\u{1193F}\\u{11941}\\u{11A84}-\\u{11A89}\\u{11D46}\\u{11F02}";
139066
+ var SPACE_WITH_ATTACHMENTS = new RegExp(`(?<![${PREPEND_LETTERS}]) (?=([\\p{Mn}\\p{Me}\\u200c\\u200d]+))\\1(?![\\p{Mc}\\p{Grapheme_Extend}\\p{Emoji_Modifier}\\u0e33\\u0eb3])`, "gu");
139067
+ function shortenBlankRuns(text5, cap) {
139068
+ return text5.replace(SPACE_WITH_ATTACHMENTS, " ").replace(/ +/gu, (run) => run.length > cap ? " ".repeat(cap) : run);
139069
+ }
139070
+ function visibleDisplayText(text5, limit = Number.POSITIVE_INFINITY) {
139071
+ const cleaned = sanitiseDisplayText(text5).replace(LINE_SEPARATORS, "").replace(BLANK_CELLS_BUT_SPACE, " ").replace(STANDALONE_HANGUL_FILLER, " ").replace(INVISIBLE_FORMAT, (_match, tagSequence) => tagSequence ?? "");
139072
+ const kept = [];
139073
+ for (const grapheme of graphemeStream(Number.isFinite(limit) ? shortenBlankRuns(cleaned, limit + 1) : cleaned)) {
138934
139074
  const body = grapheme.replace(/^ /u, "");
138935
139075
  const space = body === grapheme ? "" : " ";
138936
- return drawsNothing(body) ? space : grapheme;
138937
- }).join("").trim();
139076
+ const drawn = drawsNothing(body) ? space : grapheme;
139077
+ if (drawn === "") {
139078
+ continue;
139079
+ }
139080
+ kept.push(drawn);
139081
+ if (drawn.trim() !== "" && kept.length > limit && graphemesOf(kept.join("").trimStart()).length > limit) {
139082
+ break;
139083
+ }
139084
+ }
139085
+ return kept.join("").trim();
139086
+ }
139087
+ var NOT_SEPARATOR = /[^\t-\r\u0085\u2028\u2029]/gu;
139088
+ var SEPARATOR2 = /[\t-\r\u0085\u2028\u2029]/gu;
139089
+ var COULD_SHOW = /[^\p{Cf}\p{Cc}\p{Cs}\p{Zs}\p{Zl}\p{Zp}\p{Mn}\p{Me}\p{Default_Ignorable_Code_Point}\u2800]/u;
139090
+ var LONE_HIGH_SURROGATE = /[\uD800-\uDBFF]/gu;
139091
+ var LONE_LOW_SURROGATE = /[\uDC00-\uDFFF]/gy;
139092
+ var NOT_REMOVED_BY_CLEANING = new RegExp("[^[\\p{Cc}\\p{Cf}\\u2028\\u2029]--[\\u200c\\u200d]]", "gv");
139093
+ function joinsSurrogates(text5) {
139094
+ LONE_HIGH_SURROGATE.lastIndex = 0;
139095
+ for (let high = LONE_HIGH_SURROGATE.exec(text5); high !== null; high = LONE_HIGH_SURROGATE.exec(text5)) {
139096
+ NOT_REMOVED_BY_CLEANING.lastIndex = high.index + 1;
139097
+ const next = NOT_REMOVED_BY_CLEANING.exec(text5);
139098
+ if (next === null) {
139099
+ return false;
139100
+ }
139101
+ LONE_LOW_SURROGATE.lastIndex = next.index;
139102
+ if (LONE_LOW_SURROGATE.test(text5)) {
139103
+ return true;
139104
+ }
139105
+ }
139106
+ return false;
139107
+ }
139108
+ function couldShowSomething(text5) {
139109
+ return COULD_SHOW.test(text5) || joinsSurrogates(text5);
139110
+ }
139111
+ function* piecesOf(text5) {
139112
+ let from = 0;
139113
+ for (; ; ) {
139114
+ NOT_SEPARATOR.lastIndex = from;
139115
+ const begins = NOT_SEPARATOR.exec(text5);
139116
+ if (begins === null) {
139117
+ return;
139118
+ }
139119
+ SEPARATOR2.lastIndex = begins.index;
139120
+ const ends = SEPARATOR2.exec(text5);
139121
+ if (ends === null) {
139122
+ yield text5.slice(begins.index);
139123
+ return;
139124
+ }
139125
+ yield text5.slice(begins.index, ends.index);
139126
+ from = SEPARATOR2.lastIndex;
139127
+ }
139128
+ }
139129
+ function visibleWords(text5, limit = Number.POSITIVE_INFINITY, clean = visibleDisplayText) {
139130
+ const words = [];
139131
+ let used = 0;
139132
+ let last = "";
139133
+ for (const piece of piecesOf(stripEscapeSequences(text5))) {
139134
+ if (used > limit) {
139135
+ break;
139136
+ }
139137
+ if (!couldShowSomething(piece)) {
139138
+ continue;
139139
+ }
139140
+ const word = clean(piece, limit - used + 1);
139141
+ if (word !== "") {
139142
+ if (Number.isFinite(limit)) {
139143
+ const joinedEnd = graphemesOf(`${last}${words.length > 0 ? " " : ""}${word}`);
139144
+ used += joinedEnd.length - (words.length > 0 ? 1 : 0);
139145
+ last = joinedEnd[joinedEnd.length - 1] ?? "";
139146
+ }
139147
+ words.push(word);
139148
+ }
139149
+ }
139150
+ return words.join(" ");
139151
+ }
139152
+ function boundedVisibleWords(text5, clean = visibleDisplayText) {
139153
+ return boundedDisplayText(visibleWords(text5, MAX_DISPLAY_TEXT_CHARS, clean));
138938
139154
  }
138939
139155
 
138940
139156
  // src/statusline/elements/header/advisor.ts
@@ -138995,6 +139211,55 @@ function effortSegment({ payload, settings: settings2, t: t10 }) {
138995
139211
  return level === void 0 ? void 0 : formatEffort(level, settings2.effort.format, t10);
138996
139212
  }
138997
139213
 
139214
+ // src/statusline/elements/header/extra.ts
139215
+ init_zod();
139216
+ var LabelObjectSchema = external_exports.looseObject({ label: external_exports.string() });
139217
+ function* linesOf(text5) {
139218
+ let start = 0;
139219
+ for (; ; ) {
139220
+ const end = text5.indexOf("\n", start);
139221
+ if (end === -1) {
139222
+ yield text5.slice(start);
139223
+ return;
139224
+ }
139225
+ yield text5.slice(start, end);
139226
+ start = end + 1;
139227
+ }
139228
+ }
139229
+ var BYTE_ORDER_MARK = /^\uFEFF/u;
139230
+ function labelOf2(output2) {
139231
+ const text5 = stripEscapeSequences(output2).replace(BYTE_ORDER_MARK, "");
139232
+ let parsed;
139233
+ try {
139234
+ parsed = JSON.parse(text5);
139235
+ } catch {
139236
+ parsed = void 0;
139237
+ }
139238
+ const object3 = LabelObjectSchema.safeParse(parsed);
139239
+ if (object3.success) {
139240
+ return boundedVisibleWords(object3.data.label);
139241
+ }
139242
+ for (const line of linesOf(text5)) {
139243
+ const label2 = couldShowSomething(line) ? boundedVisibleWords(line) : "";
139244
+ if (label2 !== "") {
139245
+ return label2;
139246
+ }
139247
+ }
139248
+ return "";
139249
+ }
139250
+ function extraSegment({ settings: settings2, payload, ports }) {
139251
+ const [program2, ...args] = settings2.extra.command;
139252
+ if (program2 === void 0) {
139253
+ return void 0;
139254
+ }
139255
+ const output2 = ports.run(program2, args, payload.cwd ?? payload.workspace?.current_dir ?? ports.homeDirectory, { outputInFile: true });
139256
+ if (output2 === void 0) {
139257
+ return void 0;
139258
+ }
139259
+ const label2 = labelOf2(output2);
139260
+ return label2 === "" ? void 0 : label2;
139261
+ }
139262
+
138998
139263
  // src/statusline/dailyLedger.ts
138999
139264
  var import_node_path56 = __toESM(require("node:path"), 1);
139000
139265
  init_zod();
@@ -139872,7 +140137,7 @@ function addedDirsRow({ payload, settings: settings2, palette, t: t10 }) {
139872
140137
  }
139873
140138
 
139874
140139
  // src/statusline/headerLayout.ts
139875
- var SEPARATOR2 = " | ";
140140
+ var SEPARATOR3 = " | ";
139876
140141
  function headerUnits(parts, overflow) {
139877
140142
  const units = [];
139878
140143
  parts.forEach((part, index) => {
@@ -140341,7 +140606,7 @@ function environmentRow(context) {
140341
140606
  (count2) => t10("environment.hooks.other", { count: count2 })
140342
140607
  )
140343
140608
  ].filter((part) => part !== void 0);
140344
- return { kind: "text", lines: packLines(parts.map((part) => palette.paint("label", part)), context.width, SEPARATOR2).map((line) => line.join(SEPARATOR2)) };
140609
+ return { kind: "text", lines: packLines(parts.map((part) => palette.paint("label", part)), context.width, SEPARATOR3).map((line) => line.join(SEPARATOR3)) };
140345
140610
  }
140346
140611
 
140347
140612
  // src/statusline/elements/rows/mcp.ts
@@ -140513,7 +140778,7 @@ function parenthesised(reset) {
140513
140778
  return reset === "" ? "" : `(${reset})`;
140514
140779
  }
140515
140780
  function wrapped(windows, width) {
140516
- return packLines(windows, width, SEPARATOR2).map((line) => line.join(SEPARATOR2));
140781
+ return packLines(windows, width, SEPARATOR3).map((line) => line.join(SEPARATOR3));
140517
140782
  }
140518
140783
  function quotaRow(context) {
140519
140784
  const { palette, settings: settings2 } = context;
@@ -140634,7 +140899,7 @@ function toolsRow(context) {
140634
140899
  if (named.length < kinds.length) {
140635
140900
  parts.push(label2(t10("more", { count: kinds.length - named.length })));
140636
140901
  }
140637
- return parts.length === 0 ? NO_LINES : { kind: "text", lines: packLines(parts.map((part) => fitToWidth(part, width)), width, SEPARATOR2).map((line) => line.join(SEPARATOR2)) };
140902
+ return parts.length === 0 ? NO_LINES : { kind: "text", lines: packLines(parts.map((part) => fitToWidth(part, width)), width, SEPARATOR3).map((line) => line.join(SEPARATOR3)) };
140638
140903
  }
140639
140904
 
140640
140905
  // src/statusline/transcript/tokens.ts
@@ -140726,7 +140991,8 @@ var HEADER_ROLES = {
140726
140991
  dailyCost: "label",
140727
140992
  sessionName: "label",
140728
140993
  duration: "label",
140729
- speed: "label"
140994
+ speed: "label",
140995
+ extra: "label"
140730
140996
  };
140731
140997
  var ELEMENTS = {
140732
140998
  header: {
@@ -140746,11 +141012,18 @@ var ELEMENTS = {
140746
141012
  dailyCost: dailyCostSegment,
140747
141013
  sessionName: sessionNameSegment,
140748
141014
  duration: durationSegment,
140749
- speed: speedSegment
141015
+ speed: speedSegment,
141016
+ extra: extraSegment
140750
141017
  },
140751
141018
  rows: { context: contextRow, quota: quotaRow, addedDirs: addedDirsRow, gitFiles: gitFilesRow, memory: memoryRow, environment: environmentRow, sessionTime: sessionTimeRow, promptCache: promptCacheRow, compactions: compactionsRow, tokens: tokensRow, tools: toolsRow, skills: skillsRow, mcp: mcpRow, agents: agentsRow, todos: todosRow }
140752
141019
  };
140753
141020
 
141021
+ // src/statusline/elements/customLine.ts
141022
+ function customLineOf({ settings: settings2, palette, width }) {
141023
+ const text5 = visibleDisplayText(settings2.customLine.text);
141024
+ return text5 === "" ? void 0 : palette.paint("custom", truncateToColumns(text5, width));
141025
+ }
141026
+
140754
141027
  // src/statusline/identityTranscript.ts
140755
141028
  init_zod();
140756
141029
  var TRANSCRIPT_CHUNK_BYTES = 65536;
@@ -141158,7 +141431,7 @@ function isEmpty(output2) {
141158
141431
  }
141159
141432
  function oneLineOf(output2, barCells) {
141160
141433
  if (output2.kind === "bars") {
141161
- return drawInline(output2.cells, SEPARATOR2, barCells);
141434
+ return drawInline(output2.cells, SEPARATOR3, barCells);
141162
141435
  }
141163
141436
  return output2.lines.length === 1 ? output2.lines[0] : void 0;
141164
141437
  }
@@ -141167,8 +141440,8 @@ function alignRight(lines, rightAlign, width) {
141167
141440
  if (split < 1) {
141168
141441
  return void 0;
141169
141442
  }
141170
- const left = lines.slice(0, split).map(({ text: text5 }) => text5).join(SEPARATOR2);
141171
- const right = lines.slice(split).map(({ text: text5 }) => text5).join(SEPARATOR2);
141443
+ const left = lines.slice(0, split).map(({ text: text5 }) => text5).join(SEPARATOR3);
141444
+ const right = lines.slice(split).map(({ text: text5 }) => text5).join(SEPARATOR3);
141172
141445
  return `${left}${" ".repeat(width - visibleLength(left) - visibleLength(right))}${right}`;
141173
141446
  }
141174
141447
  function itemOf(row) {
@@ -141183,7 +141456,7 @@ function mergedItems(rows, settings2, width) {
141183
141456
  const lines = rows.map((row) => ({ name: row.name, text: oneLineOf(row.output, settings2.barCells) }));
141184
141457
  const texts = lines.flatMap(({ name, text: text5 }) => text5 === void 0 ? [] : [{ name, text: text5 }]);
141185
141458
  if (texts.length === rows.length) {
141186
- const joined3 = texts.map(({ text: text5 }) => text5).join(SEPARATOR2);
141459
+ const joined3 = texts.map(({ text: text5 }) => text5).join(SEPARATOR3);
141187
141460
  if (visibleLength(joined3) <= width) {
141188
141461
  return [{ kind: "lines", lines: [alignRight(texts, rightAlign, width) ?? joined3] }];
141189
141462
  }
@@ -141229,7 +141502,7 @@ function layoutRows(rows, settings2, width) {
141229
141502
  const lines = [];
141230
141503
  let units = [];
141231
141504
  const flushBars = () => {
141232
- lines.push(...layoutBarGrid(units, width, SEPARATOR2, settings2.barCells));
141505
+ lines.push(...layoutBarGrid(units, width, SEPARATOR3, settings2.barCells));
141233
141506
  units = [];
141234
141507
  };
141235
141508
  for (const item of items) {
@@ -141244,7 +141517,7 @@ function layoutRows(rows, settings2, width) {
141244
141517
  return lines;
141245
141518
  }
141246
141519
  function compactUnits(rows, barCells) {
141247
- return rows.flatMap(({ output: output2 }) => output2.kind === "bars" ? output2.cells.map((cell) => drawInline([cell], SEPARATOR2, barCells)) : [...output2.lines]);
141520
+ return rows.flatMap(({ output: output2 }) => output2.kind === "bars" ? output2.cells.map((cell) => drawInline([cell], SEPARATOR3, barCells)) : [...output2.lines]);
141248
141521
  }
141249
141522
 
141250
141523
  // src/statusline/transcript/reader.ts
@@ -141770,7 +142043,7 @@ function isLive(startedAtMs, nowMs, maxMs) {
141770
142043
  return startedAtMs === void 0 || nowMs - startedAtMs <= maxMs;
141771
142044
  }
141772
142045
  function visibleNames(set3) {
141773
- const names = [...new Set(set3.names.map(visibleDisplayText).filter((name) => name !== ""))];
142046
+ const names = [...new Set(set3.names.map((name) => visibleDisplayText(name)).filter((name) => name !== ""))];
141774
142047
  return { names, total: names.length + set3.others.length, exact: set3.overflowed !== true };
141775
142048
  }
141776
142049
  function activityFactsOf(state, nowMs, limits, newer) {
@@ -142048,6 +142321,12 @@ function ruleLine(headerLines, width, palette) {
142048
142321
  const widest = Math.max(MIN_STATUSLINE_COLUMNS, ...headerLines.map(visibleLength));
142049
142322
  return palette.paint("label", RULE_CHARACTER.repeat(Math.min(width, widest)));
142050
142323
  }
142324
+ function expandedLines(header, drawn, width, palette, settings2) {
142325
+ const headerLines = header.length > 0 ? layoutHeader(header, width, SEPARATOR3).split("\n") : [];
142326
+ const rowLines = layoutRows(drawn, { mergeBars: settings2.layout.mergeBars, merge: settings2.layout.merge, rightAlign: settings2.layout.rightAlign, barCells: settings2.bar.width }, width);
142327
+ const rule = settings2.layout.rule === "belowHeader" && headerLines.length > 0 && rowLines.length > 0 ? [ruleLine(headerLines, width, palette)] : [];
142328
+ return [...headerLines, ...rule, ...rowLines];
142329
+ }
142051
142330
  function renderStatuslineBlock(input2) {
142052
142331
  const { terminalWidth, settings: settings2 = STATUSLINE_DEFAULTS, elements = ELEMENTS } = input2;
142053
142332
  const width = input2.lineWidth ?? lineWidthOf(terminalWidth);
@@ -142074,13 +142353,12 @@ function renderStatuslineBlock(input2) {
142074
142353
  });
142075
142354
  const header = headerUnits(parts, settings2.git.branchOverflow);
142076
142355
  const drawn = settings2.layout.rows.map((name) => ({ name, output: elements.rows[name](context) }));
142077
- if (settings2.layout.mode === "compact") {
142078
- return packLines([...header, ...compactUnits(drawn, settings2.bar.width)], width, SEPARATOR2).map((line) => line.join(SEPARATOR2)).join("\n");
142356
+ const body = settings2.layout.mode === "compact" ? packLines([...header, ...compactUnits(drawn, settings2.bar.width)], width, SEPARATOR3).map((line) => line.join(SEPARATOR3)) : expandedLines(header, drawn, width, context.palette, settings2);
142357
+ const custom2 = customLineOf(context);
142358
+ if (custom2 === void 0) {
142359
+ return body.join("\n");
142079
142360
  }
142080
- const headerLines = header.length > 0 ? layoutHeader(header, width, SEPARATOR2).split("\n") : [];
142081
- const rowLines = layoutRows(drawn, { mergeBars: settings2.layout.mergeBars, merge: settings2.layout.merge, rightAlign: settings2.layout.rightAlign, barCells: settings2.bar.width }, width);
142082
- const rule = settings2.layout.rule === "belowHeader" && headerLines.length > 0 && rowLines.length > 0 ? [ruleLine(headerLines, width, context.palette)] : [];
142083
- return [...headerLines, ...rule, ...rowLines].join("\n");
142361
+ return (settings2.customLine.position === "first" ? [custom2, ...body] : [...body, custom2]).join("\n");
142084
142362
  }
142085
142363
 
142086
142364
  // src/statusline/commands.ts