claude-use 11.49.2 → 11.50.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -99,6 +99,8 @@ agent-shim profile set <name> [--extends <profile>]... [--no-extends] [--descrip
99
99
  agent-shim profile set <name> [--[no-]launch-skip-permissions] [--[no-]launch-remote-control] [--[no-]launch-headroom] [--[no-]launch-track-usage]
100
100
  agent-shim profile set <name> [--launch-claude-version <version> | --no-launch-claude-version] [--json] [--json]
101
101
  agent-shim profile set <name> [--launch-delay <duration> | --no-launch-delay] [--[no-]launch-pause] [--[no-]launch-explain] [--launch-proxy-bypass <host>... | --no-launch-proxy-bypass] [--json]
102
+ agent-shim profile set <name> [--statusline-header <segment>... | --no-statusline-header] [--statusline-bars <group>... | --no-statusline-bars] [--statusline-warn-at <percent> | --no-statusline-warn-at] [--statusline-critical-at <percent> | --no-statusline-critical-at]
103
+ agent-shim profile set <name> [--statusline-five-hour-label <text> | --no-statusline-five-hour-label] [--statusline-seven-day-label <text> | --no-statusline-seven-day-label] [--statusline-bar-width <cells> | --no-statusline-bar-width]
102
104
  agent-shim profile set <name> [--launch-provider <provider> | --no-launch-provider] [--json]
103
105
  agent-shim profile list [--json]
104
106
  agent-shim profile show <name> [--json]
package/dist/cli.cjs CHANGED
@@ -25036,6 +25036,68 @@ var init_proxyBypass = __esm({
25036
25036
  }
25037
25037
  });
25038
25038
 
25039
+ // src/config/statusline.ts
25040
+ function distinctList(member) {
25041
+ return external_exports.array(member).refine((items) => new Set(items).size === items.length, "must not repeat a segment");
25042
+ }
25043
+ function resolveStatusline(settings2) {
25044
+ const resolved = {
25045
+ header: settings2?.header ?? STATUSLINE_DEFAULTS.header,
25046
+ bars: settings2?.bars ?? STATUSLINE_DEFAULTS.bars,
25047
+ warnAt: settings2?.warnAt ?? STATUSLINE_DEFAULTS.warnAt,
25048
+ criticalAt: settings2?.criticalAt ?? STATUSLINE_DEFAULTS.criticalAt,
25049
+ fiveHourLabel: settings2?.fiveHourLabel ?? STATUSLINE_DEFAULTS.fiveHourLabel,
25050
+ sevenDayLabel: settings2?.sevenDayLabel ?? STATUSLINE_DEFAULTS.sevenDayLabel,
25051
+ barWidth: settings2?.barWidth ?? STATUSLINE_DEFAULTS.barWidth
25052
+ };
25053
+ if (resolved.warnAt >= resolved.criticalAt) {
25054
+ throw new RangeError(`statusline warnAt (${String(resolved.warnAt)}) must be below criticalAt (${String(resolved.criticalAt)})`);
25055
+ }
25056
+ return resolved;
25057
+ }
25058
+ var STATUSLINE_HEADER_SEGMENTS, STATUSLINE_BAR_GROUPS, MAX_PERCENT, MAX_STATUSLINE_LABEL_CHARS, MAX_BAR_CELLS, LABEL_RE2, wholePercent, StatuslineSchema, StatuslineChangeSchema, STATUSLINE_DEFAULTS, STATUSLINE_ENV;
25059
+ var init_statusline = __esm({
25060
+ "src/config/statusline.ts"() {
25061
+ "use strict";
25062
+ init_zod();
25063
+ STATUSLINE_HEADER_SEGMENTS = ["model", "provider", "route", "account", "identity", "headroom"];
25064
+ STATUSLINE_BAR_GROUPS = ["context", "quota"];
25065
+ MAX_PERCENT = 100;
25066
+ MAX_STATUSLINE_LABEL_CHARS = 12;
25067
+ MAX_BAR_CELLS = 40;
25068
+ LABEL_RE2 = /^[^\p{C}\p{Z}]+(?: [^\p{C}\p{Z}]+)*$/u;
25069
+ wholePercent = external_exports.number().int().min(1).max(MAX_PERCENT);
25070
+ StatuslineSchema = external_exports.strictObject({
25071
+ header: distinctList(external_exports.enum(STATUSLINE_HEADER_SEGMENTS)).optional(),
25072
+ bars: distinctList(external_exports.enum(STATUSLINE_BAR_GROUPS)).optional(),
25073
+ warnAt: wholePercent.optional(),
25074
+ criticalAt: wholePercent.optional(),
25075
+ fiveHourLabel: external_exports.string().max(MAX_STATUSLINE_LABEL_CHARS).regex(LABEL_RE2, "must be visible text without control characters").optional(),
25076
+ sevenDayLabel: external_exports.string().max(MAX_STATUSLINE_LABEL_CHARS).regex(LABEL_RE2, "must be visible text without control characters").optional(),
25077
+ barWidth: external_exports.number().int().min(1).max(MAX_BAR_CELLS).optional()
25078
+ });
25079
+ StatuslineChangeSchema = external_exports.strictObject({
25080
+ header: external_exports.union([StatuslineSchema.shape.header.unwrap(), external_exports.literal(false)]).optional(),
25081
+ bars: external_exports.union([StatuslineSchema.shape.bars.unwrap(), external_exports.literal(false)]).optional(),
25082
+ warnAt: external_exports.union([StatuslineSchema.shape.warnAt.unwrap(), external_exports.literal(false)]).optional(),
25083
+ criticalAt: external_exports.union([StatuslineSchema.shape.criticalAt.unwrap(), external_exports.literal(false)]).optional(),
25084
+ fiveHourLabel: external_exports.union([StatuslineSchema.shape.fiveHourLabel.unwrap(), external_exports.literal(false)]).optional(),
25085
+ sevenDayLabel: external_exports.union([StatuslineSchema.shape.sevenDayLabel.unwrap(), external_exports.literal(false)]).optional(),
25086
+ barWidth: external_exports.union([StatuslineSchema.shape.barWidth.unwrap(), external_exports.literal(false)]).optional()
25087
+ });
25088
+ STATUSLINE_DEFAULTS = {
25089
+ header: STATUSLINE_HEADER_SEGMENTS,
25090
+ bars: STATUSLINE_BAR_GROUPS,
25091
+ warnAt: 70,
25092
+ criticalAt: 90,
25093
+ fiveHourLabel: "5h",
25094
+ sevenDayLabel: "Wk",
25095
+ barWidth: 10
25096
+ };
25097
+ STATUSLINE_ENV = "AGENT_SHIM_STATUSLINE";
25098
+ }
25099
+ });
25100
+
25039
25101
  // node_modules/.pnpm/trilean@1.7.1/node_modules/trilean/dist/complex.js
25040
25102
  var complexFromPolar;
25041
25103
  var init_complex = __esm({
@@ -27037,6 +27099,7 @@ var init_schema = __esm({
27037
27099
  "src/config/schema.ts"() {
27038
27100
  "use strict";
27039
27101
  init_proxyBypass();
27102
+ init_statusline();
27040
27103
  import_node_path4 = __toESM(require("node:path"), 1);
27041
27104
  init_zod();
27042
27105
  init_dist2();
@@ -27088,7 +27151,9 @@ var init_schema = __esm({
27088
27151
  context.addIssue({ code: "custom", message: `"${entry}" ${problem}` });
27089
27152
  }
27090
27153
  })
27091
- ).optional()
27154
+ ).optional(),
27155
+ /** How the launched session's built-in statusline looks, exported to it as `AGENT_SHIM_STATUSLINE`. Merged key by key across layers, unlike the flags above, which are single values. */
27156
+ statusline: StatuslineSchema.optional()
27092
27157
  });
27093
27158
  CREDENTIAL_TARGETS = ["bearer", "apiKey", "oauthToken"];
27094
27159
  PROVIDER_CREDENTIAL_TARGETS = ["bearer", "apiKey"];
@@ -31902,6 +31967,17 @@ function removeProfile(paths, name) {
31902
31967
  requireProfileExists(paths, name);
31903
31968
  import_node_fs5.default.rmSync(profileJsonPath(paths, name));
31904
31969
  }
31970
+ function withStatuslineChange(existing, change) {
31971
+ const merged = new Map(Object.entries({ ...existing }));
31972
+ for (const [key, value2] of Object.entries(change)) {
31973
+ if (value2 === false) {
31974
+ merged.delete(key);
31975
+ } else {
31976
+ merged.set(key, value2);
31977
+ }
31978
+ }
31979
+ return merged.size === 0 ? void 0 : StatuslineSchema.parse(Object.fromEntries(merged));
31980
+ }
31905
31981
  function applyProfileChange(paths, name, change) {
31906
31982
  let touched = false;
31907
31983
  if (change.category !== void 0) {
@@ -31950,6 +32026,9 @@ function applyProfileChange(paths, name, change) {
31950
32026
  if (change.launchExplain !== void 0) {
31951
32027
  launchPatch.explain = change.launchExplain;
31952
32028
  }
32029
+ if (change.launchStatusline !== void 0) {
32030
+ launchPatch.statusline = withStatuslineChange(readProfile(paths, name)?.launch?.statusline, change.launchStatusline);
32031
+ }
31953
32032
  if (Object.keys(launchPatch).length > 0) {
31954
32033
  setProfileLaunchFlags(paths, name, launchPatch);
31955
32034
  touched = true;
@@ -31965,6 +32044,7 @@ var init_configProfilesStore = __esm({
31965
32044
  init_store();
31966
32045
  init_schema();
31967
32046
  init_cliError();
32047
+ init_statusline();
31968
32048
  init_load();
31969
32049
  ProfileNotFoundError = class extends CliError {
31970
32050
  constructor(profileName) {
@@ -32922,6 +33002,9 @@ function flattenLayers(layers, options) {
32922
33002
  if (layer.launch.proxyBypass !== void 0) {
32923
33003
  launch.proxyBypass = layer.launch.proxyBypass;
32924
33004
  }
33005
+ if (layer.launch.statusline !== void 0) {
33006
+ launch.statusline = { ...launch.statusline, ...layer.launch.statusline };
33007
+ }
32925
33008
  }
32926
33009
  if (layer.models !== void 0) {
32927
33010
  models = mergeModels(models, layer.models);
@@ -35927,7 +36010,7 @@ var init_package = __esm({
35927
36010
  "package.json"() {
35928
36011
  package_default = {
35929
36012
  name: "claude-use",
35930
- version: "11.49.2",
36013
+ version: "11.50.1",
35931
36014
  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.",
35932
36015
  license: "MIT",
35933
36016
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -65268,8 +65351,39 @@ var init_headers = __esm({
65268
65351
  }
65269
65352
  });
65270
65353
 
65354
+ // src/statusline/settings.ts
65355
+ function checkedStatusline(settings2, source) {
65356
+ try {
65357
+ resolveStatusline(settings2);
65358
+ } catch (error63) {
65359
+ throw new UsageError(`${source}: ${error63 instanceof Error ? error63.message : String(error63)}.`);
65360
+ }
65361
+ return settings2;
65362
+ }
65363
+ function statuslineSettingsFromEnv(raw, source) {
65364
+ let parsed;
65365
+ try {
65366
+ parsed = JSON.parse(raw);
65367
+ } catch {
65368
+ throw new UsageError(`${source}: not valid JSON.`);
65369
+ }
65370
+ const result = StatuslineSchema.safeParse(parsed);
65371
+ if (!result.success) {
65372
+ throw new UsageError(`${source}: ${result.error.issues.map((issue2) => `${issue2.path.join(".") || "(root)"}: ${issue2.message}`).join("; ")}.`);
65373
+ }
65374
+ return checkedStatusline(result.data, source);
65375
+ }
65376
+ var init_settings2 = __esm({
65377
+ "src/statusline/settings.ts"() {
65378
+ "use strict";
65379
+ init_cliError();
65380
+ init_statusline();
65381
+ }
65382
+ });
65383
+
65271
65384
  // src/launcher/flags.ts
65272
65385
  function resolveLaunchFlags(params) {
65386
+ const statusline = resolveStatuslineSettings(params);
65273
65387
  return {
65274
65388
  skipPermissions: params.flags?.skipPermissions ?? parseEnvBool("AGENT_SHIM_SKIP_PERMISSIONS", params.env.AGENT_SHIM_SKIP_PERMISSIONS) ?? params.cascade?.skipPermissions ?? false,
65275
65389
  remoteControl: params.flags?.remoteControl ?? parseEnvBool("AGENT_SHIM_REMOTE_CONTROL", params.env.AGENT_SHIM_REMOTE_CONTROL) ?? params.cascade?.remoteControl ?? false,
@@ -65278,9 +65392,17 @@ function resolveLaunchFlags(params) {
65278
65392
  pause: params.flags?.pause ?? parseEnvBool("AGENT_SHIM_PAUSE", params.env.AGENT_SHIM_PAUSE) ?? params.cascade?.pause ?? false,
65279
65393
  explain: params.flags?.explain ?? parseEnvBool("AGENT_SHIM_EXPLAIN", params.env.AGENT_SHIM_EXPLAIN) ?? params.cascade?.explain ?? false,
65280
65394
  delayMs: resolveDelayMs(params),
65281
- proxyBypass: resolveProxyBypass(params)
65395
+ proxyBypass: resolveProxyBypass(params),
65396
+ ...statusline === void 0 ? {} : { statusline }
65282
65397
  };
65283
65398
  }
65399
+ function resolveStatuslineSettings(params) {
65400
+ const fromEnv = params.env[STATUSLINE_ENV] === "" ? void 0 : params.env[STATUSLINE_ENV];
65401
+ if (fromEnv !== void 0) {
65402
+ return statuslineSettingsFromEnv(fromEnv, STATUSLINE_ENV);
65403
+ }
65404
+ return params.cascade?.statusline === void 0 ? void 0 : checkedStatusline(params.cascade.statusline, "launch.statusline");
65405
+ }
65284
65406
  function resolveProxyBypass(params) {
65285
65407
  const fromEnv = params.env.AGENT_SHIM_PROXY_BYPASS === "" ? void 0 : params.env.AGENT_SHIM_PROXY_BYPASS;
65286
65408
  return fromEnv !== void 0 ? checkedProxyBypass(fromEnv.split(",").map((entry) => entry.trim()), "AGENT_SHIM_PROXY_BYPASS") : checkedProxyBypass(params.cascade?.proxyBypass ?? [], "launch.proxyBypass");
@@ -65364,6 +65486,9 @@ function buildEnv(params) {
65364
65486
  env.NO_PROXY = withBypassHosts(env.NO_PROXY, bypassed);
65365
65487
  env.no_proxy = withBypassHosts(env.no_proxy, bypassed);
65366
65488
  }
65489
+ if (params.statusline !== void 0) {
65490
+ env[STATUSLINE_ENV] = JSON.stringify(params.statusline);
65491
+ }
65367
65492
  return env;
65368
65493
  }
65369
65494
  var import_node_path42, LOOPBACK_HOSTS, PROVIDER_SESSION_PLACEHOLDER;
@@ -65379,6 +65504,8 @@ var init_flags = __esm({
65379
65504
  init_headers();
65380
65505
  init_capability();
65381
65506
  init_route();
65507
+ init_statusline();
65508
+ init_settings2();
65382
65509
  init_proxyBypass2();
65383
65510
  LOOPBACK_HOSTS = ["127.0.0.1", "localhost", "::1"];
65384
65511
  PROVIDER_SESSION_PLACEHOLDER = "agent-shim-provider-session";
@@ -67880,7 +68007,8 @@ function prepareLaunch(params) {
67880
68007
  sessionId,
67881
68008
  remoteControl: resolvedFlags.remoteControl,
67882
68009
  ...decided.models?.tiers === void 0 ? {} : { tierModels: decided.models.tiers },
67883
- proxyBypass: resolvedFlags.proxyBypass
68010
+ proxyBypass: resolvedFlags.proxyBypass,
68011
+ ...resolvedFlags.statusline === void 0 ? {} : { statusline: resolvedFlags.statusline }
67884
68012
  });
67885
68013
  const releases = [...headroom === void 0 || headroomPort === void 0 ? [] : [headroomPort.release], ...frontDoorRelease === void 0 ? [] : [frontDoorRelease]];
67886
68014
  const release = () => {
@@ -67908,7 +68036,8 @@ function resolveLaunch(params) {
67908
68036
  ...decided.flags.headroom ? { headroom: { socketPath: "", projectId: "" } } : {},
67909
68037
  sessionId: "",
67910
68038
  remoteControl: decided.flags.remoteControl,
67911
- proxyBypass: decided.flags.proxyBypass
68039
+ proxyBypass: decided.flags.proxyBypass,
68040
+ ...decided.flags.statusline === void 0 ? {} : { statusline: decided.flags.statusline }
67912
68041
  });
67913
68042
  const credentialNames = decided.identityCredentialBlock === void 0 ? [] : Object.keys(credentialVariables(decided.identityCredentialBlock.target ?? "bearer", ""));
67914
68043
  const environment = [.../* @__PURE__ */ new Set([...Object.keys(built).filter((name) => built[name] !== env[name]), ...credentialNames])].sort();
@@ -114988,6 +115117,7 @@ async function resolveFarmConflicts(params) {
114988
115117
  // src/configProfiles.ts
114989
115118
  init_commandDeps();
114990
115119
  init_cliError();
115120
+ init_statusline();
114991
115121
  init_proxyBypass2();
114992
115122
  init_configProfilesStore();
114993
115123
  async function ensureProfileExists(deps, name) {
@@ -115014,6 +115144,29 @@ async function ensureProfileExists(deps, name) {
115014
115144
  function toProfileView(name, profile, globalDefault) {
115015
115145
  return { name, globalDefault: name === globalDefault, ...profile, $schema: void 0 };
115016
115146
  }
115147
+ function segmentList(values) {
115148
+ return values.length === 1 && values[0] === "none" ? [] : values;
115149
+ }
115150
+ function statuslineChangeOf(options) {
115151
+ const raw = {
115152
+ header: options.statuslineHeader === void 0 || options.statuslineHeader === false ? options.statuslineHeader : segmentList(options.statuslineHeader),
115153
+ bars: options.statuslineBars === void 0 || options.statuslineBars === false ? options.statuslineBars : segmentList(options.statuslineBars),
115154
+ warnAt: options.statuslineWarnAt === void 0 || options.statuslineWarnAt === false ? options.statuslineWarnAt : Number(options.statuslineWarnAt),
115155
+ criticalAt: options.statuslineCriticalAt === void 0 || options.statuslineCriticalAt === false ? options.statuslineCriticalAt : Number(options.statuslineCriticalAt),
115156
+ fiveHourLabel: options.statuslineFiveHourLabel,
115157
+ sevenDayLabel: options.statuslineSevenDayLabel,
115158
+ barWidth: options.statuslineBarWidth === void 0 || options.statuslineBarWidth === false ? options.statuslineBarWidth : Number(options.statuslineBarWidth)
115159
+ };
115160
+ const given = Object.entries(raw).filter(([, value2]) => value2 !== void 0);
115161
+ if (given.length === 0) {
115162
+ return void 0;
115163
+ }
115164
+ const result = StatuslineSchema.safeParse(Object.fromEntries(given.filter(([, value2]) => value2 !== false)));
115165
+ if (!result.success) {
115166
+ throw new UsageError(`--statusline-*: ${result.error.issues.map((issue2) => `${issue2.path.join(".")}: ${issue2.message}`).join("; ")}.`);
115167
+ }
115168
+ return Object.fromEntries(given);
115169
+ }
115017
115170
  function registerProfileCommand(program2, deps) {
115018
115171
  const { paths } = deps;
115019
115172
  const profile = withExamples(
@@ -115049,7 +115202,7 @@ function registerProfileCommand(program2, deps) {
115049
115202
  withExamples(
115050
115203
  profile.command("set <name>").description(
115051
115204
  "Update a configuration profile's categories, entries, extends list, description or launch settings. With no options on a terminal, walks through its categories."
115052
- ).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("--json", "Print the result as JSON.").action(async (name, allOptions) => {
115205
+ ).option("--category <category=bool>", "Share (true) or hide (false) a whole category (repeatable).", collectBoolPair).option("--entry <path=bool>", "Share (true) or hide (false) one <category>/<path> entry (repeatable).", collectBoolPair).option("--extends <profile>", "Replace the extends list with these profiles (repeatable, in order).", collectRepeated).option("--no-extends", "Clear the extends list.").option("--description <text>", "Replace the description.").option("--no-description", "Clear the description.").option("--launch-skip-permissions", "Launches under this profile skip permission prompts.").option("--no-launch-skip-permissions", "Launches under this profile keep permission prompts.").option("--launch-remote-control", "Launches under this profile enable Remote Control.").option("--no-launch-remote-control", "Launches under this profile leave Remote Control off.").option("--launch-headroom", "Launches under this profile route through headroom.").option("--no-launch-headroom", "Launches under this profile route direct.").option("--launch-track-usage", "Launches under this profile route through the front door so their requests and quota are recorded, with no headroom needed.").option("--no-launch-track-usage", "Launches under this profile are not recorded unless a provider or headroom routes them anyway.").option("--launch-provider <provider>", "Launches under this profile route through this provider.").option("--no-launch-provider", "Clear this profile's provider selection.").option("--launch-claude-version <version>", "Launches under this profile run exactly this installed Claude Code version (such as 2.1.220); a version that is not installed fails the launch.").option("--no-launch-claude-version", "Clear this profile's Claude Code version pin.").option("--launch-delay <duration>", "Launches under this profile wait this long (such as 5s) after the launcher's own output before starting claude, so the output can be read.", parseDurationLiteral).option("--no-launch-delay", "Clear this profile's launch delay.").option("--launch-pause", "Launches under this profile wait for a key press after the launcher's own output before starting claude.").option("--no-launch-pause", "Launches under this profile start claude without waiting for a key press.").option("--launch-explain", "Launches under this profile that pick from a pool list every member the pick ranked and why, in the launcher's report.").option("--no-launch-explain", "Launches under this profile name only the member a pool pick chose.").option("--launch-proxy-bypass <host>", "Launches under this profile keep this host off the front door by adding it to NO_PROXY, so its traffic goes direct (repeatable; replaces the profile's list).", collectRepeated).option("--no-launch-proxy-bypass", "Clear this profile's list of hosts kept off the front door.").option("--statusline-header <segment>", `The statusline header segments to draw, in drawing order (repeatable; one of ${STATUSLINE_HEADER_SEGMENTS.join(", ")}, or "none" to hide the header).`, collectRepeated).option("--no-statusline-header", "Clear this profile's header segment list, restoring the default.").option("--statusline-bars <group>", `The statusline bar groups to draw, in drawing order (repeatable; one of ${STATUSLINE_BAR_GROUPS.join(", ")}, or "none" to hide the bars).`, collectRepeated).option("--no-statusline-bars", "Clear this profile's bar group list, restoring the default.").option("--statusline-warn-at <percent>", "The whole percentage of use at which a statusline bar turns yellow.").option("--no-statusline-warn-at", "Clear this profile's warning threshold.").option("--statusline-critical-at <percent>", "The whole percentage of use at which a statusline bar turns red.").option("--no-statusline-critical-at", "Clear this profile's critical threshold.").option("--statusline-five-hour-label <text>", "The statusline's name for the five-hour window.").option("--no-statusline-five-hour-label", "Clear this profile's five-hour window label.").option("--statusline-seven-day-label <text>", "The statusline's name for the weekly window.").option("--no-statusline-seven-day-label", "Clear this profile's weekly window label.").option("--statusline-bar-width <cells>", "The width of a statusline bar in cells, before the line's spare width is shared out among the bars.").option("--no-statusline-bar-width", "Clear this profile's bar width.").option("--json", "Print the result as JSON.").action(async (name, allOptions) => {
115053
115206
  const { json: json2, ...options } = allOptions;
115054
115207
  requireProfileExists(paths, name);
115055
115208
  if (Object.entries(allOptions).every(([key, value2]) => key === "json" || value2 === void 0)) {
@@ -115062,8 +115215,10 @@ function registerProfileCommand(program2, deps) {
115062
115215
  throw new PromptCancelledError();
115063
115216
  }
115064
115217
  } else {
115218
+ const launchStatusline = statuslineChangeOf(options);
115065
115219
  applyProfileChange(paths, name, {
115066
115220
  ...options,
115221
+ ...launchStatusline === void 0 ? {} : { launchStatusline },
115067
115222
  ...options.launchProxyBypass === void 0 || options.launchProxyBypass === false ? {} : { launchProxyBypass: checkedProxyBypass(options.launchProxyBypass, "--launch-proxy-bypass") }
115068
115223
  });
115069
115224
  }
@@ -129358,6 +129513,7 @@ init_providersStore();
129358
129513
  // src/frontdoor/configSchemas.ts
129359
129514
  init_zod();
129360
129515
  init_schema();
129516
+ init_statusline();
129361
129517
  var RemovalConfirmationSchema = external_exports.boolean();
129362
129518
  var CredentialWriteSchema = (targets) => external_exports.strictObject({
129363
129519
  sources: external_exports.array(RemoteCredentialSourceSchema).min(1).optional(),
@@ -129433,7 +129589,8 @@ var ConfigProfileSetInputSchema = external_exports.strictObject({
129433
129589
  delay: external_exports.union([external_exports.string().regex(DURATION_RE), external_exports.literal(false)]).optional(),
129434
129590
  pause: external_exports.boolean().optional(),
129435
129591
  explain: external_exports.boolean().optional(),
129436
- proxyBypass: external_exports.union([external_exports.array(external_exports.string().min(1)), external_exports.literal(false)]).optional()
129592
+ proxyBypass: external_exports.union([external_exports.array(external_exports.string().min(1)), external_exports.literal(false)]).optional(),
129593
+ statusline: StatuslineChangeSchema.optional()
129437
129594
  }).optional()
129438
129595
  });
129439
129596
  var ConfigProfileSetOutputSchema = storedMutationOutput("profile", "updated", ProfileValueSchema);
@@ -129646,7 +129803,8 @@ function createConfigApiRouter(deps) {
129646
129803
  ...launch?.delay === void 0 ? {} : { launchDelay: launch.delay },
129647
129804
  ...launch?.pause === void 0 ? {} : { launchPause: launch.pause },
129648
129805
  ...launch?.explain === void 0 ? {} : { launchExplain: launch.explain },
129649
- ...launch?.proxyBypass === void 0 ? {} : { launchProxyBypass: launch.proxyBypass === false ? false : checkedProxyBypass(launch.proxyBypass, "launch.proxyBypass") }
129806
+ ...launch?.proxyBypass === void 0 ? {} : { launchProxyBypass: launch.proxyBypass === false ? false : checkedProxyBypass(launch.proxyBypass, "launch.proxyBypass") },
129807
+ ...launch?.statusline === void 0 ? {} : { launchStatusline: launch.statusline }
129650
129808
  });
129651
129809
  return { action: "updated", kind: "profile", name: input2.name, value: profileValue(input2.name, paths) };
129652
129810
  })
@@ -129917,6 +130075,7 @@ init_cliError();
129917
130075
  // src/frontdoor/launchSchemas.ts
129918
130076
  var import_node_path51 = __toESM(require("node:path"), 1);
129919
130077
  init_zod();
130078
+ init_statusline();
129920
130079
  init_claudeVersion();
129921
130080
  init_identity();
129922
130081
  var LaunchResolveInputSchema = external_exports.strictObject({
@@ -129951,7 +130110,9 @@ var LaunchFlagsSchema = external_exports.strictObject({
129951
130110
  /** How long the launch waits after its own output before it starts claude, in milliseconds. */
129952
130111
  delayMs: external_exports.number(),
129953
130112
  /** The hosts the launch keeps off the front door by adding them to the child's `NO_PROXY`. */
129954
- proxyBypass: external_exports.array(external_exports.string()).readonly()
130113
+ proxyBypass: external_exports.array(external_exports.string()).readonly(),
130114
+ /** How the session's built-in statusline looks, when the launch configures any of it. */
130115
+ statusline: StatuslineSchema.optional()
129955
130116
  });
129956
130117
  var LaunchResolveOutputSchema = external_exports.strictObject({
129957
130118
  decision: LaunchDecisionSchema,
@@ -136394,6 +136555,7 @@ var import_node_child_process7 = require("node:child_process");
136394
136555
  var import_node_os12 = __toESM(require("node:os"), 1);
136395
136556
  var import_node_path56 = __toESM(require("node:path"), 1);
136396
136557
  init_commandDeps();
136558
+ init_statusline();
136397
136559
  init_providersStore();
136398
136560
  init_realPorts();
136399
136561
  init_account();
@@ -136718,6 +136880,9 @@ function visibleLength(text2) {
136718
136880
  return text2.replace(ANSI_REGEX, "").length;
136719
136881
  }
136720
136882
 
136883
+ // src/statusline/render.ts
136884
+ init_statusline();
136885
+
136721
136886
  // src/statusline/barGrid.ts
136722
136887
  var BRACKET_COLUMNS = 2;
136723
136888
  function chunk(items, size) {
@@ -136789,7 +136954,6 @@ function layoutBarGrid(groups, maxWidth, separator, baseBarCells) {
136789
136954
  }
136790
136955
 
136791
136956
  // src/statusline/render.ts
136792
- var BAR_WIDTH = 10;
136793
136957
  var SECONDS_PER_MINUTE2 = 60;
136794
136958
  var MINUTES_PER_HOUR4 = 60;
136795
136959
  var SECONDS_PER_DAY = 86400;
@@ -136801,8 +136965,6 @@ var RESERVED_COLUMNS = 4;
136801
136965
  var SEPARATOR2 = " | ";
136802
136966
  var FULL_PERCENT3 = 100;
136803
136967
  var ONE_PERCENT = 1;
136804
- var USED_RED_AT = 0.9;
136805
- var USED_YELLOW_AT = 0.7;
136806
136968
  var RESET = `${ESCAPE}[0m`;
136807
136969
  var DIM = `${ESCAPE}[90m`;
136808
136970
  var GREEN = `${ESCAPE}[32m`;
@@ -136811,20 +136973,22 @@ var RED = `${ESCAPE}[31m`;
136811
136973
  function colorize() {
136812
136974
  return process.env.NO_COLOR === void 0;
136813
136975
  }
136814
- function statusColor(fraction, isUsedMetric) {
136976
+ function statusColor(fraction, isUsedMetric, bands) {
136815
136977
  if (!colorize()) {
136816
136978
  return "";
136817
136979
  }
136980
+ const yellowAt = bands.warnAt / FULL_PERCENT3;
136981
+ const redAt = bands.criticalAt / FULL_PERCENT3;
136818
136982
  if (isUsedMetric) {
136819
- if (fraction >= USED_RED_AT) {
136983
+ if (fraction >= redAt) {
136820
136984
  return RED;
136821
136985
  }
136822
- return fraction >= USED_YELLOW_AT ? YELLOW : GREEN;
136986
+ return fraction >= yellowAt ? YELLOW : GREEN;
136823
136987
  }
136824
- if (fraction <= 1 - USED_RED_AT) {
136988
+ if (fraction <= 1 - redAt) {
136825
136989
  return RED;
136826
136990
  }
136827
- return fraction <= 1 - USED_YELLOW_AT ? YELLOW : GREEN;
136991
+ return fraction <= 1 - yellowAt ? YELLOW : GREEN;
136828
136992
  }
136829
136993
  function formatTokens(num) {
136830
136994
  if (num >= MILLION) {
@@ -136864,18 +137028,18 @@ function headroomText(stats) {
136864
137028
  ].filter((part) => part !== void 0);
136865
137029
  return parts.length === 0 ? void 0 : `headroom ${parts.join(" \xB7 ")}`;
136866
137030
  }
136867
- function cacheHitText(hitFraction) {
137031
+ function cacheHitText(hitFraction, bands) {
136868
137032
  const clamped = Math.max(0, Math.min(1, hitFraction));
136869
- return ` (Cache: ${statusColor(clamped, false)}${(clamped * FULL_PERCENT3).toFixed(0)}%${RESET})`;
137033
+ return ` (Cache: ${statusColor(clamped, false, bands)}${(clamped * FULL_PERCENT3).toFixed(0)}%${RESET})`;
136870
137034
  }
136871
- function cacheShareText(view) {
137035
+ function cacheShareText(view, bands) {
136872
137036
  const hitRatio = view.cacheHitRatio;
136873
137037
  if (hitRatio !== void 0 && Number.isFinite(hitRatio)) {
136874
- return cacheHitText(hitRatio);
137038
+ return cacheHitText(hitRatio, bands);
136875
137039
  }
136876
137040
  const promptTotal = (view.cacheReadTokens ?? 0) + (view.freshInputTokens ?? 0);
136877
137041
  if (promptTotal > 0 && (view.cacheReadTokens ?? 0) > 0) {
136878
- return cacheHitText((view.cacheReadTokens ?? 0) / promptTotal);
137042
+ return cacheHitText((view.cacheReadTokens ?? 0) / promptTotal, bands);
136879
137043
  }
136880
137044
  return "";
136881
137045
  }
@@ -136934,14 +137098,14 @@ function secondsUntil(resetAt, nowMs) {
136934
137098
  const resetMs = Date.parse(resetAt);
136935
137099
  return Number.isNaN(resetMs) ? void 0 : Math.max(0, Math.round((resetMs - nowMs) / THOUSAND));
136936
137100
  }
136937
- function drawBar(fraction, cells) {
137101
+ function drawBar(fraction, cells, bands) {
136938
137102
  const clamped = Math.max(0, Math.min(1, fraction));
136939
137103
  const filled = Math.round(clamped * cells);
136940
- const color = statusColor(clamped, true);
137104
+ const color = statusColor(clamped, true, bands);
136941
137105
  return color === "" ? `[${"\u2588".repeat(filled)}${"\u2591".repeat(cells - filled)}]` : `[${color}${"\u2588".repeat(filled)}${DIM}${"\u2591".repeat(cells - filled)}${RESET}]`;
136942
137106
  }
136943
- function barCell(prefix, suffix, fraction) {
136944
- return { prefix, suffix, draw: (cells) => drawBar(fraction, cells) };
137107
+ function barCell(prefix, suffix, fraction, bands) {
137108
+ return { prefix, suffix, draw: (cells) => drawBar(fraction, cells, bands) };
136945
137109
  }
136946
137110
  function justify(texts, maxWidth, separator) {
136947
137111
  if (texts.length < 2) {
@@ -136992,49 +137156,51 @@ function layoutHeader(texts, maxWidth, separator) {
136992
137156
  }
136993
137157
  return lines.map((line) => justify(line, maxWidth, separator)).join("\n");
136994
137158
  }
136995
- function renderStatuslineBlock(summary, view, terminalWidth, nowMs) {
136996
- const header = [];
137159
+ function renderStatuslineBlock(summary, view, terminalWidth, nowMs, settings2 = STATUSLINE_DEFAULTS) {
137160
+ const segments = {};
136997
137161
  const choiceNamesProvider = summary.modelChoice !== void 0 && (summary.modelChoice.providers.length > 1 || summary.routedTarget !== void 0);
136998
137162
  const modelSegment = summary.modelChoice !== void 0 && view.modelDisplayName !== void 0 && view.modelDisplayName !== "" ? `${view.modelDisplayName} -> ${choiceNamesProvider ? `${summary.modelChoice.provider}/${summary.modelChoice.served}` : summary.modelChoice.served}` : view.modelDisplayName;
136999
137163
  if (modelSegment !== void 0 && modelSegment !== "") {
137000
- header.push(modelSegment);
137164
+ segments.model = modelSegment;
137001
137165
  }
137002
137166
  if (summary.provider !== void 0) {
137003
137167
  const account = [summary.providerAccountEmail, summary.providerPlan].filter((part) => part !== void 0);
137004
- header.push(account.length > 0 ? `${summary.provider} \xB7 ${account.join(" \xB7 ")}` : summary.provider);
137168
+ segments.provider = account.length > 0 ? `${summary.provider} \xB7 ${account.join(" \xB7 ")}` : summary.provider;
137005
137169
  }
137006
137170
  if (summary.routedTarget !== void 0 && !choiceNamesProvider) {
137007
- header.push(`via ${summary.routedTarget}`);
137171
+ segments.route = `via ${summary.routedTarget}`;
137008
137172
  }
137009
137173
  const loginPlan = summary.provider === void 0 ? summary.loginPlan ?? accountPlanLabel(summary) : void 0;
137010
137174
  const loginOrgName = summary.loginOrganizationType === "claude_team" || summary.loginOrganizationType === "claude_enterprise" ? summary.loginOrganizationName : void 0;
137011
137175
  const loginParts = [summary.loginAccountEmail, loginOrgName, loginPlan].filter((part) => part !== void 0);
137012
137176
  if (summary.loginAccountEmail !== void 0 && summary.loginAccountEmail !== summary.providerAccountEmail) {
137013
- header.push(loginParts.join(" \xB7 "));
137177
+ segments.account = loginParts.join(" \xB7 ");
137014
137178
  } else if (summary.provider === void 0 && loginParts.length > 0) {
137015
- header.push(loginParts.join(" \xB7 "));
137179
+ segments.account = loginParts.join(" \xB7 ");
137016
137180
  }
137017
137181
  if (summary.identity !== void 0 && summary.provider !== void 0 && summary.identity !== summary.providerAccountEmail && summary.identity !== summary.loginAccountEmail) {
137018
- header.push(summary.identity);
137182
+ segments.identity = summary.identity;
137019
137183
  }
137020
137184
  const savings = headroomText(summary.headroom);
137021
137185
  if (savings !== void 0) {
137022
- header.push(savings);
137186
+ segments.headroom = savings;
137023
137187
  }
137188
+ const header = settings2.header.flatMap((name) => segments[name] ?? []);
137189
+ const bands = { warnAt: settings2.warnAt, criticalAt: settings2.criticalAt };
137024
137190
  const contextGroup = [];
137025
137191
  if (view.contextUsedPercentage !== void 0) {
137026
137192
  const fraction = Math.max(0, Math.min(1, view.contextUsedPercentage / FULL_PERCENT3));
137027
- const color = statusColor(fraction, true);
137193
+ const color = statusColor(fraction, true, bands);
137028
137194
  const percent2 = `${color}${view.contextUsedPercentage.toFixed(1)}%${RESET}`;
137029
137195
  const tokens = view.contextTotalTokens !== void 0 && view.contextWindowTokens !== void 0 ? `${formatTokens(view.contextTotalTokens)}/${formatTokens(view.contextWindowTokens)} ` : "";
137030
- const cache = cacheShareText(view);
137031
- contextGroup.push(barCell(`Ctx ${tokens}`, ` ${percent2}${cache}`, fraction));
137196
+ const cache = cacheShareText(view, bands);
137197
+ contextGroup.push(barCell(`Ctx ${tokens}`, ` ${percent2}${cache}`, fraction, bands));
137032
137198
  }
137033
137199
  const quotaGroup = [];
137034
137200
  const drawWindow = (label, fraction, resetsAt) => {
137035
137201
  const clamped = Math.max(0, Math.min(1, fraction));
137036
- const color = statusColor(clamped, true);
137037
- quotaGroup.push(barCell(`${label} `, ` ${color}${(fraction * FULL_PERCENT3).toFixed(1)}%${RESET} (${formatDuration(secondsUntil(resetsAt, nowMs))})`, clamped));
137202
+ const color = statusColor(clamped, true, bands);
137203
+ quotaGroup.push(barCell(`${label} `, ` ${color}${(fraction * FULL_PERCENT3).toFixed(1)}%${RESET} (${formatDuration(secondsUntil(resetsAt, nowMs))})`, clamped, bands));
137038
137204
  };
137039
137205
  if (summary.quotaFamilies.length > 0) {
137040
137206
  for (const window of summary.quotaFamilies) {
@@ -137042,10 +137208,10 @@ function renderStatuslineBlock(summary, view, terminalWidth, nowMs) {
137042
137208
  }
137043
137209
  } else {
137044
137210
  if (summary.fiveHourUsed !== void 0) {
137045
- drawWindow("5h", summary.fiveHourUsed / FULL_PERCENT3, summary.fiveHourResetAt);
137211
+ drawWindow(settings2.fiveHourLabel, summary.fiveHourUsed / FULL_PERCENT3, summary.fiveHourResetAt);
137046
137212
  }
137047
137213
  if (summary.sevenDayUsed !== void 0) {
137048
- drawWindow("Wk", summary.sevenDayUsed / FULL_PERCENT3, summary.sevenDayResetAt);
137214
+ drawWindow(settings2.sevenDayLabel, summary.sevenDayUsed / FULL_PERCENT3, summary.sevenDayResetAt);
137049
137215
  }
137050
137216
  if (summary.fiveHourUsed === void 0 && summary.sevenDayUsed === void 0) {
137051
137217
  for (const window of summary.providerQuotaWindows) {
@@ -137058,10 +137224,14 @@ function renderStatuslineBlock(summary, view, terminalWidth, nowMs) {
137058
137224
  if (header.length > 0) {
137059
137225
  lines.push(layoutHeader(header, width, SEPARATOR2));
137060
137226
  }
137061
- lines.push(...layoutBarGrid([contextGroup, quotaGroup], width, SEPARATOR2, BAR_WIDTH));
137227
+ const groups = { context: contextGroup, quota: quotaGroup };
137228
+ lines.push(...layoutBarGrid(settings2.bars.map((name) => groups[name]), width, SEPARATOR2, settings2.barWidth));
137062
137229
  return lines.join("\n");
137063
137230
  }
137064
137231
 
137232
+ // src/statusline/commands.ts
137233
+ init_settings2();
137234
+
137065
137235
  // src/statusline/width.ts
137066
137236
  var DEFAULT_COLUMNS = 80;
137067
137237
  function terminalWidthOf(payload, env) {
@@ -137194,7 +137364,9 @@ function registerStatuslineCommand(program2, deps) {
137194
137364
  }
137195
137365
  }
137196
137366
  const view = { ...payloadViewOf(payload), ...stackedUnderDefault ? { modelDisplayName: void 0 } : {} };
137197
- console.log(renderStatuslineBlock(summary, view, terminalWidthOf(payload, process.env), nowMs));
137367
+ const rawSettings = process.env[STATUSLINE_ENV];
137368
+ const settings2 = resolveStatusline(rawSettings === void 0 || rawSettings === "" ? void 0 : statuslineSettingsFromEnv(rawSettings, STATUSLINE_ENV));
137369
+ console.log(renderStatuslineBlock(summary, view, terminalWidthOf(payload, process.env), nowMs, settings2));
137198
137370
  }),
137199
137371
  ["$ agent-shim statusline # a client's statusline setting names this; it renders or delegates"]
137200
137372
  );