ccstatusline 2.0.9 → 2.0.11

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
@@ -22,6 +22,8 @@
22
22
  [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/sirmalloc/ccstatusline/graphs/commit-activity)
23
23
 
24
24
  [![Mentioned in Awesome Claude Code](https://awesome.re/mentioned-badge.svg)](https://github.com/hesreallyhim/awesome-claude-code)
25
+ [![ClaudeLog - A comprehensive knowledge base for Claude](https://claudelog.com/img/claude_log_badge.svg)](https://claudelog.com/)
26
+
25
27
 
26
28
  ![Demo](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/demo.gif)
27
29
 
@@ -42,6 +44,15 @@
42
44
 
43
45
  ## 🆕 Recent Updates
44
46
 
47
+ ### v2.0.11 - Unlimited Status Lines
48
+
49
+ - **🚀 No Line Limit** - Configure as many status lines as you need - the 3-line limitation has been removed
50
+
51
+ ### v2.0.10 - Git Updates
52
+
53
+ - **🌳 Git Worktree widget** - Shows the active worktree name when working with git worktrees
54
+ - **👻 Hide 'no git' message toggle** - Git widgets now support hiding the 'no git' message when not in a repository (toggle with 'h' key while editing the widget)
55
+
45
56
  ### v2.0.8 - Powerline Auto-Alignment
46
57
 
47
58
  ![Powerline Auto-Alignment](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/autoAlign.png)
@@ -92,7 +103,7 @@
92
103
  - **📊 Real-time Metrics** - Display model name, git branch, token usage, session duration, block timer, and more
93
104
  - **🎨 Fully Customizable** - Choose what to display and customize colors for each element
94
105
  - **⚡ Powerline Support** - Beautiful Powerline-style rendering with arrow separators, caps, and custom fonts
95
- - **📐 Multi-line Support** - Configure up to 3 independent status lines
106
+ - **📐 Multi-line Support** - Configure multiple independent status lines
96
107
  - **🖥️ Interactive TUI** - Built-in configuration interface using React/Ink
97
108
  - **⚙️ Global Options** - Apply consistent formatting across all widgets (padding, separators, bold, background)
98
109
  - **🚀 Cross-platform** - Works seamlessly with both Bun and Node.js
@@ -116,7 +127,7 @@ bunx ccstatusline@latest
116
127
  ### Configure ccstatusline
117
128
 
118
129
  The interactive configuration tool provides a terminal UI where you can:
119
- - Configure up to 3 separate status lines
130
+ - Configure multiple separate status lines
120
131
  - Add/remove/reorder status line widgets
121
132
  - Customize colors for each widget
122
133
  - Configure flex separator behavior
@@ -137,6 +148,7 @@ Once configured, ccstatusline automatically formats your Claude Code status line
137
148
  - **Model Name** - Shows the current Claude model (e.g., "Claude 3.5 Sonnet")
138
149
  - **Git Branch** - Displays current git branch name
139
150
  - **Git Changes** - Shows uncommitted insertions/deletions (e.g., "+42,-10")
151
+ - **Git Worktree** - Shows the name of the current git worktree
140
152
  - **Session Clock** - Shows elapsed time since session start (e.g., "2hr 15m")
141
153
  - **Session Cost** - Shows total session cost in USD (e.g., "$1.23")
142
154
  - **Block Timer** - Shows time elapsed in current 5-hour block or progress bar
@@ -285,7 +297,7 @@ When terminal width is detected, status lines automatically truncate with ellips
285
297
 
286
298
  ```bash
287
299
  # Clone the repository
288
- git clone https://github.com/yourusername/ccstatusline.git
300
+ git clone https://github.com/sirmalloc/ccstatusline.git
289
301
  cd ccstatusline
290
302
 
291
303
  # Install dependencies
@@ -31861,6 +31861,333 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
31861
31861
  }
31862
31862
  });
31863
31863
 
31864
+ // node_modules/pluralize/pluralize.js
31865
+ var require_pluralize = __commonJS((exports, module) => {
31866
+ (function(root, pluralize) {
31867
+ if (typeof exports === "object" && typeof module === "object") {
31868
+ module.exports = pluralize();
31869
+ } else if (typeof define === "function" && define.amd) {
31870
+ define(function() {
31871
+ return pluralize();
31872
+ });
31873
+ } else {
31874
+ root.pluralize = pluralize();
31875
+ }
31876
+ })(exports, function() {
31877
+ var pluralRules = [];
31878
+ var singularRules = [];
31879
+ var uncountables = {};
31880
+ var irregularPlurals = {};
31881
+ var irregularSingles = {};
31882
+ function sanitizeRule(rule) {
31883
+ if (typeof rule === "string") {
31884
+ return new RegExp("^" + rule + "$", "i");
31885
+ }
31886
+ return rule;
31887
+ }
31888
+ function restoreCase(word, token) {
31889
+ if (word === token)
31890
+ return token;
31891
+ if (word === word.toLowerCase())
31892
+ return token.toLowerCase();
31893
+ if (word === word.toUpperCase())
31894
+ return token.toUpperCase();
31895
+ if (word[0] === word[0].toUpperCase()) {
31896
+ return token.charAt(0).toUpperCase() + token.substr(1).toLowerCase();
31897
+ }
31898
+ return token.toLowerCase();
31899
+ }
31900
+ function interpolate(str, args) {
31901
+ return str.replace(/\$(\d{1,2})/g, function(match, index) {
31902
+ return args[index] || "";
31903
+ });
31904
+ }
31905
+ function replace(word, rule) {
31906
+ return word.replace(rule[0], function(match, index) {
31907
+ var result = interpolate(rule[1], arguments);
31908
+ if (match === "") {
31909
+ return restoreCase(word[index - 1], result);
31910
+ }
31911
+ return restoreCase(match, result);
31912
+ });
31913
+ }
31914
+ function sanitizeWord(token, word, rules) {
31915
+ if (!token.length || uncountables.hasOwnProperty(token)) {
31916
+ return word;
31917
+ }
31918
+ var len = rules.length;
31919
+ while (len--) {
31920
+ var rule = rules[len];
31921
+ if (rule[0].test(word))
31922
+ return replace(word, rule);
31923
+ }
31924
+ return word;
31925
+ }
31926
+ function replaceWord(replaceMap, keepMap, rules) {
31927
+ return function(word) {
31928
+ var token = word.toLowerCase();
31929
+ if (keepMap.hasOwnProperty(token)) {
31930
+ return restoreCase(word, token);
31931
+ }
31932
+ if (replaceMap.hasOwnProperty(token)) {
31933
+ return restoreCase(word, replaceMap[token]);
31934
+ }
31935
+ return sanitizeWord(token, word, rules);
31936
+ };
31937
+ }
31938
+ function checkWord(replaceMap, keepMap, rules, bool) {
31939
+ return function(word) {
31940
+ var token = word.toLowerCase();
31941
+ if (keepMap.hasOwnProperty(token))
31942
+ return true;
31943
+ if (replaceMap.hasOwnProperty(token))
31944
+ return false;
31945
+ return sanitizeWord(token, token, rules) === token;
31946
+ };
31947
+ }
31948
+ function pluralize(word, count, inclusive) {
31949
+ var pluralized = count === 1 ? pluralize.singular(word) : pluralize.plural(word);
31950
+ return (inclusive ? count + " " : "") + pluralized;
31951
+ }
31952
+ pluralize.plural = replaceWord(irregularSingles, irregularPlurals, pluralRules);
31953
+ pluralize.isPlural = checkWord(irregularSingles, irregularPlurals, pluralRules);
31954
+ pluralize.singular = replaceWord(irregularPlurals, irregularSingles, singularRules);
31955
+ pluralize.isSingular = checkWord(irregularPlurals, irregularSingles, singularRules);
31956
+ pluralize.addPluralRule = function(rule, replacement) {
31957
+ pluralRules.push([sanitizeRule(rule), replacement]);
31958
+ };
31959
+ pluralize.addSingularRule = function(rule, replacement) {
31960
+ singularRules.push([sanitizeRule(rule), replacement]);
31961
+ };
31962
+ pluralize.addUncountableRule = function(word) {
31963
+ if (typeof word === "string") {
31964
+ uncountables[word.toLowerCase()] = true;
31965
+ return;
31966
+ }
31967
+ pluralize.addPluralRule(word, "$0");
31968
+ pluralize.addSingularRule(word, "$0");
31969
+ };
31970
+ pluralize.addIrregularRule = function(single, plural) {
31971
+ plural = plural.toLowerCase();
31972
+ single = single.toLowerCase();
31973
+ irregularSingles[single] = plural;
31974
+ irregularPlurals[plural] = single;
31975
+ };
31976
+ [
31977
+ ["I", "we"],
31978
+ ["me", "us"],
31979
+ ["he", "they"],
31980
+ ["she", "they"],
31981
+ ["them", "them"],
31982
+ ["myself", "ourselves"],
31983
+ ["yourself", "yourselves"],
31984
+ ["itself", "themselves"],
31985
+ ["herself", "themselves"],
31986
+ ["himself", "themselves"],
31987
+ ["themself", "themselves"],
31988
+ ["is", "are"],
31989
+ ["was", "were"],
31990
+ ["has", "have"],
31991
+ ["this", "these"],
31992
+ ["that", "those"],
31993
+ ["echo", "echoes"],
31994
+ ["dingo", "dingoes"],
31995
+ ["volcano", "volcanoes"],
31996
+ ["tornado", "tornadoes"],
31997
+ ["torpedo", "torpedoes"],
31998
+ ["genus", "genera"],
31999
+ ["viscus", "viscera"],
32000
+ ["stigma", "stigmata"],
32001
+ ["stoma", "stomata"],
32002
+ ["dogma", "dogmata"],
32003
+ ["lemma", "lemmata"],
32004
+ ["schema", "schemata"],
32005
+ ["anathema", "anathemata"],
32006
+ ["ox", "oxen"],
32007
+ ["axe", "axes"],
32008
+ ["die", "dice"],
32009
+ ["yes", "yeses"],
32010
+ ["foot", "feet"],
32011
+ ["eave", "eaves"],
32012
+ ["goose", "geese"],
32013
+ ["tooth", "teeth"],
32014
+ ["quiz", "quizzes"],
32015
+ ["human", "humans"],
32016
+ ["proof", "proofs"],
32017
+ ["carve", "carves"],
32018
+ ["valve", "valves"],
32019
+ ["looey", "looies"],
32020
+ ["thief", "thieves"],
32021
+ ["groove", "grooves"],
32022
+ ["pickaxe", "pickaxes"],
32023
+ ["passerby", "passersby"]
32024
+ ].forEach(function(rule) {
32025
+ return pluralize.addIrregularRule(rule[0], rule[1]);
32026
+ });
32027
+ [
32028
+ [/s?$/i, "s"],
32029
+ [/[^\u0000-\u007F]$/i, "$0"],
32030
+ [/([^aeiou]ese)$/i, "$1"],
32031
+ [/(ax|test)is$/i, "$1es"],
32032
+ [/(alias|[^aou]us|t[lm]as|gas|ris)$/i, "$1es"],
32033
+ [/(e[mn]u)s?$/i, "$1s"],
32034
+ [/([^l]ias|[aeiou]las|[ejzr]as|[iu]am)$/i, "$1"],
32035
+ [/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, "$1i"],
32036
+ [/(alumn|alg|vertebr)(?:a|ae)$/i, "$1ae"],
32037
+ [/(seraph|cherub)(?:im)?$/i, "$1im"],
32038
+ [/(her|at|gr)o$/i, "$1oes"],
32039
+ [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i, "$1a"],
32040
+ [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i, "$1a"],
32041
+ [/sis$/i, "ses"],
32042
+ [/(?:(kni|wi|li)fe|(ar|l|ea|eo|oa|hoo)f)$/i, "$1$2ves"],
32043
+ [/([^aeiouy]|qu)y$/i, "$1ies"],
32044
+ [/([^ch][ieo][ln])ey$/i, "$1ies"],
32045
+ [/(x|ch|ss|sh|zz)$/i, "$1es"],
32046
+ [/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i, "$1ices"],
32047
+ [/\b((?:tit)?m|l)(?:ice|ouse)$/i, "$1ice"],
32048
+ [/(pe)(?:rson|ople)$/i, "$1ople"],
32049
+ [/(child)(?:ren)?$/i, "$1ren"],
32050
+ [/eaux$/i, "$0"],
32051
+ [/m[ae]n$/i, "men"],
32052
+ ["thou", "you"]
32053
+ ].forEach(function(rule) {
32054
+ return pluralize.addPluralRule(rule[0], rule[1]);
32055
+ });
32056
+ [
32057
+ [/s$/i, ""],
32058
+ [/(ss)$/i, "$1"],
32059
+ [/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i, "$1fe"],
32060
+ [/(ar|(?:wo|[ae])l|[eo][ao])ves$/i, "$1f"],
32061
+ [/ies$/i, "y"],
32062
+ [/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i, "$1ie"],
32063
+ [/\b(mon|smil)ies$/i, "$1ey"],
32064
+ [/\b((?:tit)?m|l)ice$/i, "$1ouse"],
32065
+ [/(seraph|cherub)im$/i, "$1"],
32066
+ [/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i, "$1"],
32067
+ [/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i, "$1sis"],
32068
+ [/(movie|twelve|abuse|e[mn]u)s$/i, "$1"],
32069
+ [/(test)(?:is|es)$/i, "$1is"],
32070
+ [/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, "$1us"],
32071
+ [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i, "$1um"],
32072
+ [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i, "$1on"],
32073
+ [/(alumn|alg|vertebr)ae$/i, "$1a"],
32074
+ [/(cod|mur|sil|vert|ind)ices$/i, "$1ex"],
32075
+ [/(matr|append)ices$/i, "$1ix"],
32076
+ [/(pe)(rson|ople)$/i, "$1rson"],
32077
+ [/(child)ren$/i, "$1"],
32078
+ [/(eau)x?$/i, "$1"],
32079
+ [/men$/i, "man"]
32080
+ ].forEach(function(rule) {
32081
+ return pluralize.addSingularRule(rule[0], rule[1]);
32082
+ });
32083
+ [
32084
+ "adulthood",
32085
+ "advice",
32086
+ "agenda",
32087
+ "aid",
32088
+ "aircraft",
32089
+ "alcohol",
32090
+ "ammo",
32091
+ "analytics",
32092
+ "anime",
32093
+ "athletics",
32094
+ "audio",
32095
+ "bison",
32096
+ "blood",
32097
+ "bream",
32098
+ "buffalo",
32099
+ "butter",
32100
+ "carp",
32101
+ "cash",
32102
+ "chassis",
32103
+ "chess",
32104
+ "clothing",
32105
+ "cod",
32106
+ "commerce",
32107
+ "cooperation",
32108
+ "corps",
32109
+ "debris",
32110
+ "diabetes",
32111
+ "digestion",
32112
+ "elk",
32113
+ "energy",
32114
+ "equipment",
32115
+ "excretion",
32116
+ "expertise",
32117
+ "firmware",
32118
+ "flounder",
32119
+ "fun",
32120
+ "gallows",
32121
+ "garbage",
32122
+ "graffiti",
32123
+ "hardware",
32124
+ "headquarters",
32125
+ "health",
32126
+ "herpes",
32127
+ "highjinks",
32128
+ "homework",
32129
+ "housework",
32130
+ "information",
32131
+ "jeans",
32132
+ "justice",
32133
+ "kudos",
32134
+ "labour",
32135
+ "literature",
32136
+ "machinery",
32137
+ "mackerel",
32138
+ "mail",
32139
+ "media",
32140
+ "mews",
32141
+ "moose",
32142
+ "music",
32143
+ "mud",
32144
+ "manga",
32145
+ "news",
32146
+ "only",
32147
+ "personnel",
32148
+ "pike",
32149
+ "plankton",
32150
+ "pliers",
32151
+ "police",
32152
+ "pollution",
32153
+ "premises",
32154
+ "rain",
32155
+ "research",
32156
+ "rice",
32157
+ "salmon",
32158
+ "scissors",
32159
+ "series",
32160
+ "sewage",
32161
+ "shambles",
32162
+ "shrimp",
32163
+ "software",
32164
+ "species",
32165
+ "staff",
32166
+ "swine",
32167
+ "tennis",
32168
+ "traffic",
32169
+ "transportation",
32170
+ "trout",
32171
+ "tuna",
32172
+ "wealth",
32173
+ "welfare",
32174
+ "whiting",
32175
+ "wildebeest",
32176
+ "wildlife",
32177
+ "you",
32178
+ /pok[eé]mon$/i,
32179
+ /[^aeiou]ese$/i,
32180
+ /deer$/i,
32181
+ /fish$/i,
32182
+ /measles$/i,
32183
+ /o[iu]s$/i,
32184
+ /pox$/i,
32185
+ /sheep$/i
32186
+ ].forEach(pluralize.addUncountableRule);
32187
+ return pluralize;
32188
+ });
32189
+ });
32190
+
31864
32191
  // node_modules/picomatch/lib/constants.js
31865
32192
  var require_constants3 = __commonJS((exports, module) => {
31866
32193
  var WIN_SLASH = "\\\\/";
@@ -36263,7 +36590,7 @@ function wrapAnsi(string, columns, options) {
36263
36590
  `);
36264
36591
  }
36265
36592
 
36266
- // node_modules/is-fullwidth-code-point/index.js
36593
+ // node_modules/cli-truncate/node_modules/slice-ansi/node_modules/is-fullwidth-code-point/index.js
36267
36594
  function isFullwidthCodePoint(codePoint) {
36268
36595
  if (!Number.isInteger(codePoint)) {
36269
36596
  return false;
@@ -37556,6 +37883,14 @@ function styledCharsToString(chars) {
37556
37883
  }
37557
37884
  return ret;
37558
37885
  }
37886
+ // node_modules/is-fullwidth-code-point/index.js
37887
+ function isFullwidthCodePoint3(codePoint) {
37888
+ if (!Number.isInteger(codePoint)) {
37889
+ return false;
37890
+ }
37891
+ return codePoint >= 4352 && (codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || 11904 <= codePoint && codePoint <= 12871 && codePoint !== 12351 || 12880 <= codePoint && codePoint <= 19903 || 19968 <= codePoint && codePoint <= 42182 || 43360 <= codePoint && codePoint <= 43388 || 44032 <= codePoint && codePoint <= 55203 || 63744 <= codePoint && codePoint <= 64255 || 65040 <= codePoint && codePoint <= 65049 || 65072 <= codePoint && codePoint <= 65131 || 65281 <= codePoint && codePoint <= 65376 || 65504 <= codePoint && codePoint <= 65510 || 110592 <= codePoint && codePoint <= 110593 || 127488 <= codePoint && codePoint <= 127569 || 131072 <= codePoint && codePoint <= 262141);
37892
+ }
37893
+
37559
37894
  // node_modules/@alcalzone/ansi-tokenize/build/tokenize.js
37560
37895
  function findNumberIndex2(str) {
37561
37896
  for (let index = 0;index < str.length; index++) {
@@ -37607,7 +37942,7 @@ function tokenize2(str, endChar = Number.POSITIVE_INFINITY) {
37607
37942
  continue;
37608
37943
  }
37609
37944
  }
37610
- const fullWidth = isFullwidthCodePoint(codePoint);
37945
+ const fullWidth = isFullwidthCodePoint3(codePoint);
37611
37946
  const character = String.fromCodePoint(codePoint);
37612
37947
  ret.push({
37613
37948
  type: "char",
@@ -50573,7 +50908,7 @@ var SettingsSchema_v1 = exports_external.object({
50573
50908
  });
50574
50909
  var SettingsSchema = exports_external.object({
50575
50910
  version: exports_external.number().default(CURRENT_VERSION),
50576
- lines: exports_external.array(exports_external.array(WidgetItemSchema)).min(1).max(3).default([
50911
+ lines: exports_external.array(exports_external.array(WidgetItemSchema)).min(1).default([
50577
50912
  [
50578
50913
  { id: "1", type: "model", color: "cyan" },
50579
50914
  { id: "2", type: "separator" },
@@ -50582,8 +50917,10 @@ var SettingsSchema = exports_external.object({
50582
50917
  { id: "5", type: "git-branch", color: "magenta" },
50583
50918
  { id: "6", type: "separator" },
50584
50919
  { id: "7", type: "git-changes", color: "yellow" }
50585
- ]
50586
- ]).transform((lines) => lines.slice(0, 3)),
50920
+ ],
50921
+ [],
50922
+ []
50923
+ ]),
50587
50924
  flexMode: FlexModeSchema.default("full-minus-40"),
50588
50925
  compactThreshold: exports_external.number().min(1).max(99).default(60),
50589
50926
  colorLevel: ColorLevelSchema.default(2),
@@ -51037,7 +51374,7 @@ import { execSync as execSync3 } from "child_process";
51037
51374
  import * as fs5 from "fs";
51038
51375
  import * as path4 from "path";
51039
51376
  var __dirname = "/Users/sirmalloc/Projects/Personal/ccstatusline/src/utils";
51040
- var PACKAGE_VERSION = "2.0.9";
51377
+ var PACKAGE_VERSION = "2.0.11";
51041
51378
  function getPackageVersion() {
51042
51379
  if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
51043
51380
  return PACKAGE_VERSION;
@@ -51938,16 +52275,38 @@ class GitBranchWidget {
51938
52275
  return "Git Branch";
51939
52276
  }
51940
52277
  getEditorDisplay(item) {
51941
- return { displayText: this.getDisplayName() };
52278
+ const hideNoGit = item.metadata?.hideNoGit === "true";
52279
+ const modifiers = [];
52280
+ if (hideNoGit) {
52281
+ modifiers.push("hide 'no git'");
52282
+ }
52283
+ return {
52284
+ displayText: this.getDisplayName(),
52285
+ modifierText: modifiers.length > 0 ? `(${modifiers.join(", ")})` : undefined
52286
+ };
52287
+ }
52288
+ handleEditorAction(action, item) {
52289
+ if (action === "toggle-nogit") {
52290
+ const currentState = item.metadata?.hideNoGit === "true";
52291
+ return {
52292
+ ...item,
52293
+ metadata: {
52294
+ ...item.metadata,
52295
+ hideNoGit: (!currentState).toString()
52296
+ }
52297
+ };
52298
+ }
52299
+ return null;
51942
52300
  }
51943
52301
  render(item, context, settings) {
52302
+ const hideNoGit = item.metadata?.hideNoGit === "true";
51944
52303
  if (context.isPreview) {
51945
52304
  return item.rawValue ? "main" : "⎇ main";
51946
52305
  }
51947
52306
  const branch = this.getGitBranch();
51948
52307
  if (branch)
51949
52308
  return item.rawValue ? branch : `⎇ ${branch}`;
51950
- return "⎇ no git";
52309
+ return hideNoGit ? null : "⎇ no git";
51951
52310
  }
51952
52311
  getGitBranch() {
51953
52312
  try {
@@ -51960,6 +52319,11 @@ class GitBranchWidget {
51960
52319
  return null;
51961
52320
  }
51962
52321
  }
52322
+ getCustomKeybinds() {
52323
+ return [
52324
+ { key: "h", label: "(h)ide 'no git' message", action: "toggle-nogit" }
52325
+ ];
52326
+ }
51963
52327
  supportsRawValue() {
51964
52328
  return true;
51965
52329
  }
@@ -51981,9 +52345,31 @@ class GitChangesWidget {
51981
52345
  return "Git Changes";
51982
52346
  }
51983
52347
  getEditorDisplay(item) {
51984
- return { displayText: this.getDisplayName() };
52348
+ const hideNoGit = item.metadata?.hideNoGit === "true";
52349
+ const modifiers = [];
52350
+ if (hideNoGit) {
52351
+ modifiers.push("hide 'no git'");
52352
+ }
52353
+ return {
52354
+ displayText: this.getDisplayName(),
52355
+ modifierText: modifiers.length > 0 ? `(${modifiers.join(", ")})` : undefined
52356
+ };
52357
+ }
52358
+ handleEditorAction(action, item) {
52359
+ if (action === "toggle-nogit") {
52360
+ const currentState = item.metadata?.hideNoGit === "true";
52361
+ return {
52362
+ ...item,
52363
+ metadata: {
52364
+ ...item.metadata,
52365
+ hideNoGit: (!currentState).toString()
52366
+ }
52367
+ };
52368
+ }
52369
+ return null;
51985
52370
  }
51986
52371
  render(item, context, settings) {
52372
+ const hideNoGit = item.metadata?.hideNoGit === "true";
51987
52373
  if (context.isPreview) {
51988
52374
  return "(+42,-10)";
51989
52375
  }
@@ -51991,7 +52377,7 @@ class GitChangesWidget {
51991
52377
  if (changes)
51992
52378
  return `(+${changes.insertions},-${changes.deletions})`;
51993
52379
  else
51994
- return "(no git)";
52380
+ return hideNoGit ? null : "(no git)";
51995
52381
  }
51996
52382
  getGitChanges() {
51997
52383
  try {
@@ -52022,6 +52408,11 @@ class GitChangesWidget {
52022
52408
  return null;
52023
52409
  }
52024
52410
  }
52411
+ getCustomKeybinds() {
52412
+ return [
52413
+ { key: "h", label: "(h)ide 'no git' message", action: "toggle-nogit" }
52414
+ ];
52415
+ }
52025
52416
  supportsRawValue() {
52026
52417
  return false;
52027
52418
  }
@@ -52029,6 +52420,78 @@ class GitChangesWidget {
52029
52420
  return true;
52030
52421
  }
52031
52422
  }
52423
+ // src/widgets/GitWorktree.ts
52424
+ import { execSync as execSync6 } from "child_process";
52425
+
52426
+ class GitWorktreeWidget {
52427
+ getDefaultColor() {
52428
+ return "blue";
52429
+ }
52430
+ getDescription() {
52431
+ return "Shows the current git worktree name";
52432
+ }
52433
+ getDisplayName() {
52434
+ return "Git Worktree";
52435
+ }
52436
+ getEditorDisplay(item) {
52437
+ const hideNoGit = item.metadata?.hideNoGit === "true";
52438
+ const modifiers = [];
52439
+ if (hideNoGit) {
52440
+ modifiers.push("hide 'no git'");
52441
+ }
52442
+ return {
52443
+ displayText: this.getDisplayName(),
52444
+ modifierText: modifiers.length > 0 ? `(${modifiers.join(", ")})` : undefined
52445
+ };
52446
+ }
52447
+ handleEditorAction(action, item) {
52448
+ if (action === "toggle-nogit") {
52449
+ const currentState = item.metadata?.hideNoGit === "true";
52450
+ return {
52451
+ ...item,
52452
+ metadata: {
52453
+ ...item.metadata,
52454
+ hideNoGit: (!currentState).toString()
52455
+ }
52456
+ };
52457
+ }
52458
+ return null;
52459
+ }
52460
+ render(item, context) {
52461
+ const hideNoGit = item.metadata?.hideNoGit === "true";
52462
+ if (context.isPreview)
52463
+ return item.rawValue ? "main" : "\uD81A\uDC30 main";
52464
+ const worktree = this.getGitWorktree();
52465
+ if (worktree)
52466
+ return item.rawValue ? worktree : `\uD81A\uDC30 ${worktree}`;
52467
+ return hideNoGit ? null : "\uD81A\uDC30 no git";
52468
+ }
52469
+ getGitWorktree() {
52470
+ try {
52471
+ const worktreeDir = execSync6("git rev-parse --git-dir", {
52472
+ encoding: "utf8",
52473
+ stdio: ["pipe", "pipe", "ignore"]
52474
+ }).trim();
52475
+ if (worktreeDir.endsWith("/.git") || worktreeDir === ".git")
52476
+ return "main";
52477
+ const [, worktree] = worktreeDir.split(".git/worktrees/");
52478
+ return worktree ?? null;
52479
+ } catch {
52480
+ return null;
52481
+ }
52482
+ }
52483
+ getCustomKeybinds() {
52484
+ return [
52485
+ { key: "h", label: "(h)ide 'no git' message", action: "toggle-nogit" }
52486
+ ];
52487
+ }
52488
+ supportsRawValue() {
52489
+ return true;
52490
+ }
52491
+ supportsColors(item) {
52492
+ return true;
52493
+ }
52494
+ }
52032
52495
  // src/utils/renderer.ts
52033
52496
  var ANSI_REGEX = new RegExp(`\\x1b\\[[0-9;]*m`, "g");
52034
52497
  function formatTokens(count) {
@@ -52092,6 +52555,13 @@ function renderPowerlineStatusLine(widgets, settings, context, lineIndex = 0, gl
52092
52555
  }
52093
52556
  const widgetElements = [];
52094
52557
  let widgetColorIndex = 0;
52558
+ const preRenderedIndices = [];
52559
+ for (let i = 0;i < widgets.length; i++) {
52560
+ const widget = widgets[i];
52561
+ if (widget && widget.type !== "separator" && widget.type !== "flex-separator") {
52562
+ preRenderedIndices.push(i);
52563
+ }
52564
+ }
52095
52565
  for (let i = 0;i < filteredWidgets.length; i++) {
52096
52566
  const widget = filteredWidgets[i];
52097
52567
  if (!widget)
@@ -52101,13 +52571,14 @@ function renderPowerlineStatusLine(widgets, settings, context, lineIndex = 0, gl
52101
52571
  if (widget.type === "separator" || widget.type === "flex-separator") {
52102
52572
  continue;
52103
52573
  }
52104
- const preRendered = preRenderedWidgets[i];
52574
+ const actualPreRenderedIndex = preRenderedIndices[i];
52575
+ const preRendered = actualPreRenderedIndex !== undefined ? preRenderedWidgets[actualPreRenderedIndex] : undefined;
52105
52576
  if (preRendered?.content) {
52106
52577
  widgetText = preRendered.content;
52107
- try {
52108
- const widgetImpl = getWidget(widget.type);
52578
+ const widgetImpl = getWidget(widget.type);
52579
+ if (widgetImpl) {
52109
52580
  defaultColor = widgetImpl.getDefaultColor();
52110
- } catch {}
52581
+ }
52111
52582
  }
52112
52583
  if (widgetText) {
52113
52584
  const padding = settings.defaultPadding ?? "";
@@ -52152,7 +52623,7 @@ function renderPowerlineStatusLine(widgets, settings, context, lineIndex = 0, gl
52152
52623
  const element = widgetElements[i];
52153
52624
  const maxWidth = preCalculatedMaxWidths[i];
52154
52625
  if (element && maxWidth !== undefined) {
52155
- const currentLength = element.content.replace(ANSI_REGEX, "").length;
52626
+ const currentLength = stringWidth(element.content.replace(ANSI_REGEX, ""));
52156
52627
  const paddingNeeded = maxWidth - currentLength;
52157
52628
  if (paddingNeeded > 0) {
52158
52629
  element.content += " ".repeat(paddingNeeded);
@@ -52333,19 +52804,12 @@ function preRenderAllWidgets(allLinesWidgets, settings, context) {
52333
52804
  });
52334
52805
  continue;
52335
52806
  }
52336
- let widgetText = "";
52337
- try {
52338
- const widgetImpl = getWidget(widget.type);
52339
- widgetText = widgetImpl.render(widget, context, settings) ?? "";
52340
- } catch {
52341
- preRenderedLine.push({
52342
- content: "",
52343
- plainLength: 0,
52344
- widget
52345
- });
52807
+ const widgetImpl = getWidget(widget.type);
52808
+ if (!widgetImpl) {
52346
52809
  continue;
52347
52810
  }
52348
- const plainLength = widgetText.replace(ANSI_REGEX, "").length;
52811
+ const widgetText = widgetImpl.render(widget, context, settings) ?? "";
52812
+ const plainLength = stringWidth(widgetText.replace(ANSI_REGEX, ""));
52349
52813
  preRenderedLine.push({
52350
52814
  content: widgetText,
52351
52815
  plainLength,
@@ -52435,6 +52899,8 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
52435
52899
  if (!widget)
52436
52900
  continue;
52437
52901
  if (widget.type === "separator") {
52902
+ if (i > 0 && !preRenderedWidgets[i - 1]?.content)
52903
+ continue;
52438
52904
  const sepChar = widget.character ?? (settings.defaultSeparator ?? "|");
52439
52905
  const formattedSep = formatSeparator(sepChar);
52440
52906
  let separatorColor = widget.color ?? "gray";
@@ -52445,12 +52911,8 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
52445
52911
  if (prevWidget && prevWidget.type !== "separator" && prevWidget.type !== "flex-separator") {
52446
52912
  let widgetColor = prevWidget.color;
52447
52913
  if (!widgetColor) {
52448
- try {
52449
- const widgetImpl = getWidget(prevWidget.type);
52450
- widgetColor = widgetImpl.getDefaultColor();
52451
- } catch {
52452
- widgetColor = "white";
52453
- }
52914
+ const widgetImpl = getWidget(prevWidget.type);
52915
+ widgetColor = widgetImpl ? widgetImpl.getDefaultColor() : "white";
52454
52916
  }
52455
52917
  separatorColor = widgetColor;
52456
52918
  separatorBg = prevWidget.backgroundColor;
@@ -52471,10 +52933,10 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
52471
52933
  const preRendered = preRenderedWidgets[i];
52472
52934
  if (preRendered?.content) {
52473
52935
  widgetText = preRendered.content;
52474
- try {
52475
- const widgetImpl = getWidget(widget.type);
52936
+ const widgetImpl = getWidget(widget.type);
52937
+ if (widgetImpl) {
52476
52938
  defaultColor = widgetImpl.getDefaultColor();
52477
- } catch {}
52939
+ }
52478
52940
  }
52479
52941
  if (widgetText) {
52480
52942
  if (widget.type === "custom-command" && widget.preserveColors) {
@@ -52540,7 +53002,7 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
52540
53002
  let widgetColor = prevElem2.widget.color;
52541
53003
  if (!widgetColor && prevElem2.widget.type !== "separator" && prevElem2.widget.type !== "flex-separator") {
52542
53004
  const widgetImpl = getWidget(prevElem2.widget.type);
52543
- widgetColor = widgetImpl.getDefaultColor();
53005
+ widgetColor = widgetImpl ? widgetImpl.getDefaultColor() : "white";
52544
53006
  }
52545
53007
  const coloredSep = applyColorsWithOverride(defaultSep, widgetColor, prevElem2.widget.backgroundColor, prevElem2.widget.bold);
52546
53008
  finalElements.push(coloredSep);
@@ -53070,7 +53532,7 @@ var CustomTextEditor = ({ widget, onComplete, onCancel }) => {
53070
53532
  }, undefined, true, undefined, this);
53071
53533
  };
53072
53534
  // src/widgets/CustomCommand.tsx
53073
- import { execSync as execSync6 } from "child_process";
53535
+ import { execSync as execSync7 } from "child_process";
53074
53536
  var import_react30 = __toESM(require_react(), 1);
53075
53537
  var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
53076
53538
 
@@ -53116,7 +53578,7 @@ class CustomCommandWidget {
53116
53578
  try {
53117
53579
  const timeout = item.timeout ?? 1000;
53118
53580
  const jsonInput = JSON.stringify(context.data);
53119
- let output = execSync6(item.commandPath, {
53581
+ let output = execSync7(item.commandPath, {
53120
53582
  encoding: "utf8",
53121
53583
  input: jsonInput,
53122
53584
  timeout,
@@ -53571,6 +54033,7 @@ var widgetRegistry = new Map([
53571
54033
  ["output-style", new OutputStyleWidget],
53572
54034
  ["git-branch", new GitBranchWidget],
53573
54035
  ["git-changes", new GitChangesWidget],
54036
+ ["git-worktree", new GitWorktreeWidget],
53574
54037
  ["current-working-dir", new CurrentWorkingDirWidget],
53575
54038
  ["tokens-input", new TokensInputWidget],
53576
54039
  ["tokens-output", new TokensOutputWidget],
@@ -53588,11 +54051,7 @@ var widgetRegistry = new Map([
53588
54051
  ["custom-command", new CustomCommandWidget]
53589
54052
  ]);
53590
54053
  function getWidget(type) {
53591
- const widget = widgetRegistry.get(type);
53592
- if (!widget) {
53593
- throw new Error(`Unknown widget type: ${type}`);
53594
- }
53595
- return widget;
54054
+ return widgetRegistry.get(type) ?? null;
53596
54055
  }
53597
54056
  function getAllWidgetTypes(settings) {
53598
54057
  const allTypes = Array.from(widgetRegistry.keys());
@@ -53679,12 +54138,8 @@ var ColorMenu = ({ widgets, lineIndex, settings, onUpdate, onBack }) => {
53679
54138
  if (widget.type === "separator") {
53680
54139
  return showSeparators;
53681
54140
  }
53682
- try {
53683
- const widgetInstance = getWidget(widget.type);
53684
- return widgetInstance.supportsColors(widget);
53685
- } catch {
53686
- return false;
53687
- }
54141
+ const widgetInstance = getWidget(widget.type);
54142
+ return widgetInstance ? widgetInstance.supportsColors(widget) : true;
53688
54143
  });
53689
54144
  const [highlightedItemId, setHighlightedItemId] = import_react33.useState(colorableWidgets[0]?.id ?? null);
53690
54145
  const [editingBackground, setEditingBackground] = import_react33.useState(false);
@@ -53854,7 +54309,9 @@ var ColorMenu = ({ widgets, lineIndex, settings, onUpdate, onBack }) => {
53854
54309
  let defaultColor = "white";
53855
54310
  if (widget.type !== "separator" && widget.type !== "flex-separator") {
53856
54311
  const widgetImpl = getWidget(widget.type);
53857
- defaultColor = widgetImpl.getDefaultColor();
54312
+ if (widgetImpl) {
54313
+ defaultColor = widgetImpl.getDefaultColor();
54314
+ }
53858
54315
  }
53859
54316
  let currentColor2 = widget.color ?? defaultColor;
53860
54317
  if (currentColor2 === "dim") {
@@ -53920,7 +54377,7 @@ var ColorMenu = ({ widgets, lineIndex, settings, onUpdate, onBack }) => {
53920
54377
  return "Flex Separator";
53921
54378
  }
53922
54379
  const widgetImpl = getWidget(widget.type);
53923
- return widgetImpl.getDisplayName();
54380
+ return widgetImpl ? widgetImpl.getDisplayName() : `Unknown: ${widget.type}`;
53924
54381
  };
53925
54382
  const colorOptions = getAvailableColorsForUI();
53926
54383
  const colors = colorOptions.map((c) => c.value || "");
@@ -53932,7 +54389,9 @@ var ColorMenu = ({ widgets, lineIndex, settings, onUpdate, onBack }) => {
53932
54389
  let defaultColor = "white";
53933
54390
  if (widget.type !== "separator" && widget.type !== "flex-separator") {
53934
54391
  const widgetImpl = getWidget(widget.type);
53935
- defaultColor = widgetImpl.getDefaultColor();
54392
+ if (widgetImpl) {
54393
+ defaultColor = widgetImpl.getDefaultColor();
54394
+ }
53936
54395
  }
53937
54396
  const styledLabel = applyColors(label, widget.color ?? defaultColor, widget.backgroundColor, widget.bold, level);
53938
54397
  return {
@@ -53953,7 +54412,7 @@ var ColorMenu = ({ widgets, lineIndex, settings, onUpdate, onBack }) => {
53953
54412
  const currentColor = editingBackground ? selectedWidget?.backgroundColor ?? "" : selectedWidget ? selectedWidget.color ?? (() => {
53954
54413
  if (selectedWidget.type !== "separator" && selectedWidget.type !== "flex-separator") {
53955
54414
  const widgetImpl = getWidget(selectedWidget.type);
53956
- return widgetImpl.getDefaultColor();
54415
+ return widgetImpl ? widgetImpl.getDefaultColor() : "white";
53957
54416
  }
53958
54417
  return "white";
53959
54418
  })() : "white";
@@ -54900,8 +55359,8 @@ var ItemsEditor = ({ widgets, onUpdate, onBack, lineNumber, settings }) => {
54900
55359
  } else if (widgets.length > 0) {
54901
55360
  const currentWidget2 = widgets[selectedIndex];
54902
55361
  if (currentWidget2 && currentWidget2.type !== "separator" && currentWidget2.type !== "flex-separator") {
54903
- try {
54904
- const widgetImpl = getWidget(currentWidget2.type);
55362
+ const widgetImpl = getWidget(currentWidget2.type);
55363
+ if (widgetImpl) {
54905
55364
  if (widgetImpl.getCustomKeybinds) {
54906
55365
  const customKeybinds2 = widgetImpl.getCustomKeybinds();
54907
55366
  const matchedKeybind = customKeybinds2.find((kb) => kb.key === input);
@@ -54920,7 +55379,7 @@ var ItemsEditor = ({ widgets, onUpdate, onBack, lineNumber, settings }) => {
54920
55379
  }
54921
55380
  }
54922
55381
  }
54923
- } catch {}
55382
+ }
54924
55383
  }
54925
55384
  }
54926
55385
  }
@@ -54935,8 +55394,11 @@ var ItemsEditor = ({ widgets, onUpdate, onBack, lineNumber, settings }) => {
54935
55394
  return "Flex Separator";
54936
55395
  }
54937
55396
  const widgetImpl = getWidget(widget.type);
54938
- const { displayText, modifierText } = widgetImpl.getEditorDisplay(widget);
54939
- return displayText + (modifierText ? ` ${modifierText}` : "");
55397
+ if (widgetImpl) {
55398
+ const { displayText, modifierText } = widgetImpl.getEditorDisplay(widget);
55399
+ return displayText + (modifierText ? ` ${modifierText}` : "");
55400
+ }
55401
+ return `Unknown: ${widget.type}`;
54940
55402
  };
54941
55403
  const hasFlexSeparator = widgets.some((widget) => widget.type === "flex-separator");
54942
55404
  const widthDetectionAvailable = canDetectTerminalWidth();
@@ -54946,13 +55408,13 @@ var ItemsEditor = ({ widgets, onUpdate, onBack, lineNumber, settings }) => {
54946
55408
  let canToggleRaw = false;
54947
55409
  let customKeybinds = [];
54948
55410
  if (currentWidget && !isSeparator && !isFlexSeparator) {
54949
- try {
54950
- const widgetImpl = getWidget(currentWidget.type);
55411
+ const widgetImpl = getWidget(currentWidget.type);
55412
+ if (widgetImpl) {
54951
55413
  canToggleRaw = widgetImpl.supportsRawValue();
54952
55414
  if (widgetImpl.getCustomKeybinds) {
54953
55415
  customKeybinds = widgetImpl.getCustomKeybinds();
54954
55416
  }
54955
- } catch {
55417
+ } else {
54956
55418
  canToggleRaw = false;
54957
55419
  }
54958
55420
  }
@@ -55102,12 +55564,8 @@ var ItemsEditor = ({ widgets, onUpdate, onBack, lineNumber, settings }) => {
55102
55564
  } else if (currentWidget.type === "flex-separator") {
55103
55565
  return "Expands to fill available terminal width";
55104
55566
  } else {
55105
- try {
55106
- const widgetImpl = getWidget(currentWidget.type);
55107
- return widgetImpl.getDescription();
55108
- } catch {
55109
- return "Widget description not available";
55110
- }
55567
+ const widgetImpl = getWidget(currentWidget.type);
55568
+ return widgetImpl ? widgetImpl.getDescription() : "Unknown widget type";
55111
55569
  }
55112
55570
  })()
55113
55571
  }, undefined, false, undefined, this)
@@ -55119,26 +55577,73 @@ var ItemsEditor = ({ widgets, onUpdate, onBack, lineNumber, settings }) => {
55119
55577
  }, undefined, true, undefined, this);
55120
55578
  };
55121
55579
  // src/tui/components/LineSelector.tsx
55580
+ var import_pluralize = __toESM(require_pluralize(), 1);
55122
55581
  var import_react37 = __toESM(require_react(), 1);
55123
55582
  var jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
55124
- var LineSelector = ({ lines, onSelect, onBack, initialSelection = 0, title, blockIfPowerlineActive = false, settings }) => {
55583
+ var LineSelector = ({
55584
+ lines,
55585
+ onSelect,
55586
+ onBack,
55587
+ onLinesUpdate,
55588
+ initialSelection = 0,
55589
+ title,
55590
+ blockIfPowerlineActive = false,
55591
+ settings,
55592
+ allowEditing = false
55593
+ }) => {
55125
55594
  const [selectedIndex, setSelectedIndex] = import_react37.useState(initialSelection);
55595
+ const [showDeleteDialog, setShowDeleteDialog] = import_react37.useState(false);
55596
+ const [localLines, setLocalLines] = import_react37.useState(lines);
55597
+ import_react37.useEffect(() => {
55598
+ setLocalLines(lines);
55599
+ }, [lines]);
55600
+ const selectedLine = import_react37.useMemo(() => localLines[selectedIndex], [localLines, selectedIndex]);
55601
+ const appendLine = () => {
55602
+ const newLines = [...localLines, []];
55603
+ setLocalLines(newLines);
55604
+ onLinesUpdate(newLines);
55605
+ setSelectedIndex(newLines.length - 1);
55606
+ };
55607
+ const deleteLine = (lineIndex) => {
55608
+ if (localLines.length <= 1) {
55609
+ return;
55610
+ }
55611
+ const newLines = [...localLines];
55612
+ newLines.splice(lineIndex, 1);
55613
+ setLocalLines(newLines);
55614
+ onLinesUpdate(newLines);
55615
+ };
55126
55616
  const powerlineEnabled = settings ? settings.powerline.enabled : false;
55127
55617
  const powerlineTheme = settings ? settings.powerline.theme : undefined;
55128
55618
  const isThemeManaged = blockIfPowerlineActive && powerlineEnabled && powerlineTheme && powerlineTheme !== "custom";
55129
55619
  use_input_default((input, key) => {
55620
+ if (showDeleteDialog) {
55621
+ return;
55622
+ }
55130
55623
  if (isThemeManaged) {
55131
55624
  onBack();
55132
55625
  return;
55133
55626
  }
55627
+ switch (input) {
55628
+ case "a":
55629
+ if (allowEditing) {
55630
+ appendLine();
55631
+ }
55632
+ return;
55633
+ case "d":
55634
+ if (allowEditing && localLines.length > 1) {
55635
+ setShowDeleteDialog(true);
55636
+ }
55637
+ return;
55638
+ }
55134
55639
  if (key.escape) {
55135
55640
  onBack();
55136
55641
  } else if (key.upArrow) {
55137
55642
  setSelectedIndex(Math.max(0, selectedIndex - 1));
55138
55643
  } else if (key.downArrow) {
55139
- setSelectedIndex(Math.min(3, selectedIndex + 1));
55644
+ setSelectedIndex(Math.min(localLines.length, selectedIndex + 1));
55140
55645
  } else if (key.return) {
55141
- if (selectedIndex === 3) {
55646
+ if (selectedIndex === localLines.length) {
55142
55647
  onBack();
55143
55648
  } else {
55144
55649
  onSelect(selectedIndex);
@@ -55193,69 +55698,130 @@ var LineSelector = ({ lines, onSelect, onBack, initialSelection = 0, title, bloc
55193
55698
  ]
55194
55699
  }, undefined, true, undefined, this);
55195
55700
  }
55196
- return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55197
- flexDirection: "column",
55198
- children: [
55199
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55200
- bold: true,
55201
- children: title ?? "Select Line to Edit"
55202
- }, undefined, false, undefined, this),
55203
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55204
- dimColor: true,
55205
- children: "Choose which status line to configure (up to 3 lines supported)"
55206
- }, undefined, false, undefined, this),
55207
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55208
- dimColor: true,
55209
- children: "Press ESC to go back"
55210
- }, undefined, false, undefined, this),
55211
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55212
- marginTop: 1,
55213
- flexDirection: "column",
55214
- children: [
55215
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55216
- children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55217
- color: selectedIndex === 0 ? "green" : undefined,
55218
- children: [
55219
- selectedIndex === 0 ? "▶ " : " ",
55220
- "☰ Line 1",
55221
- lines[0] && lines[0].length > 0 ? ` (${lines[0].length} widgets)` : " (empty)"
55222
- ]
55223
- }, undefined, true, undefined, this)
55224
- }, undefined, false, undefined, this),
55225
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55226
- children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55227
- color: selectedIndex === 1 ? "green" : undefined,
55228
- children: [
55229
- selectedIndex === 1 ? "▶ " : " ",
55230
- " Line 2",
55231
- lines[1] && lines[1].length > 0 ? ` (${lines[1].length} widgets)` : " (empty)"
55232
- ]
55233
- }, undefined, true, undefined, this)
55234
- }, undefined, false, undefined, this),
55235
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55236
- children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55237
- color: selectedIndex === 2 ? "green" : undefined,
55238
- children: [
55239
- selectedIndex === 2 ? "▶ " : " ",
55240
- "☰ Line 3",
55241
- lines[2] && lines[2].length > 0 ? ` (${lines[2].length} widgets)` : " (empty)"
55242
- ]
55243
- }, undefined, true, undefined, this)
55244
- }, undefined, false, undefined, this),
55245
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55246
- marginTop: 1,
55247
- children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55248
- color: selectedIndex === 3 ? "green" : undefined,
55249
- children: [
55250
- selectedIndex === 3 ? "▶ " : " ",
55251
- "← Back"
55252
- ]
55253
- }, undefined, true, undefined, this)
55701
+ if (showDeleteDialog && selectedLine) {
55702
+ const suffix = selectedLine.length > 0 ? import_pluralize.default("widget", selectedLine.length, true) : "empty";
55703
+ return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55704
+ flexDirection: "column",
55705
+ children: [
55706
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55707
+ flexDirection: "column",
55708
+ gap: 1,
55709
+ children: [
55710
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55711
+ bold: true,
55712
+ children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55713
+ children: [
55714
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55715
+ children: [
55716
+ "☰ Line",
55717
+ " ",
55718
+ selectedIndex + 1
55719
+ ]
55720
+ }, undefined, true, undefined, this),
55721
+ " ",
55722
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55723
+ dimColor: true,
55724
+ children: [
55725
+ "(",
55726
+ suffix,
55727
+ ")"
55728
+ ]
55729
+ }, undefined, true, undefined, this)
55730
+ ]
55731
+ }, undefined, true, undefined, this)
55732
+ }, undefined, false, undefined, this),
55733
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55734
+ bold: true,
55735
+ children: "Are you sure you want to delete line?"
55736
+ }, undefined, false, undefined, this)
55737
+ ]
55738
+ }, undefined, true, undefined, this),
55739
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55740
+ marginTop: 1,
55741
+ children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(ConfirmDialog, {
55742
+ inline: true,
55743
+ onConfirm: () => {
55744
+ deleteLine(selectedIndex);
55745
+ setSelectedIndex(Math.max(0, selectedIndex - 1));
55746
+ setShowDeleteDialog(false);
55747
+ },
55748
+ onCancel: () => {
55749
+ setShowDeleteDialog(false);
55750
+ }
55254
55751
  }, undefined, false, undefined, this)
55255
- ]
55256
- }, undefined, true, undefined, this)
55257
- ]
55258
- }, undefined, true, undefined, this);
55752
+ }, undefined, false, undefined, this)
55753
+ ]
55754
+ }, undefined, true, undefined, this);
55755
+ }
55756
+ return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(jsx_dev_runtime9.Fragment, {
55757
+ children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55758
+ flexDirection: "column",
55759
+ children: [
55760
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55761
+ bold: true,
55762
+ children: title ?? "Select Line to Edit"
55763
+ }, undefined, false, undefined, this),
55764
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55765
+ dimColor: true,
55766
+ children: "Choose which status line to configure"
55767
+ }, undefined, false, undefined, this),
55768
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55769
+ dimColor: true,
55770
+ children: allowEditing ? localLines.length > 1 ? "(a) to append new line, (d) to delete line, ESC to go back" : "(a) to append new line, ESC to go back" : "ESC to go back"
55771
+ }, undefined, false, undefined, this),
55772
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55773
+ marginTop: 1,
55774
+ flexDirection: "column",
55775
+ children: [
55776
+ localLines.map((line, index) => {
55777
+ const isSelected = selectedIndex === index;
55778
+ const suffix = line.length ? import_pluralize.default("widget", line.length, true) : "empty";
55779
+ return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55780
+ children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55781
+ color: isSelected ? "green" : undefined,
55782
+ children: [
55783
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55784
+ children: isSelected ? "▶ " : " "
55785
+ }, undefined, false, undefined, this),
55786
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55787
+ children: [
55788
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55789
+ children: [
55790
+ "☰ Line",
55791
+ " ",
55792
+ index + 1
55793
+ ]
55794
+ }, undefined, true, undefined, this),
55795
+ " ",
55796
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55797
+ dimColor: !isSelected,
55798
+ children: [
55799
+ "(",
55800
+ suffix,
55801
+ ")"
55802
+ ]
55803
+ }, undefined, true, undefined, this)
55804
+ ]
55805
+ }, undefined, true, undefined, this)
55806
+ ]
55807
+ }, undefined, true, undefined, this)
55808
+ }, index, false, undefined, this);
55809
+ }),
55810
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
55811
+ marginTop: 1,
55812
+ children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
55813
+ color: selectedIndex === localLines.length ? "green" : undefined,
55814
+ children: [
55815
+ selectedIndex === localLines.length ? "▶ " : " ",
55816
+ "← Back"
55817
+ ]
55818
+ }, undefined, true, undefined, this)
55819
+ }, undefined, false, undefined, this)
55820
+ ]
55821
+ }, undefined, true, undefined, this)
55822
+ ]
55823
+ }, undefined, true, undefined, this)
55824
+ }, undefined, false, undefined, this);
55259
55825
  };
55260
55826
  // src/tui/components/MainMenu.tsx
55261
55827
  var import_react38 = __toESM(require_react(), 1);
@@ -56488,7 +57054,9 @@ var TerminalOptionsMenu = ({ settings, onUpdate, onBack }) => {
56488
57054
  if (widget.color?.startsWith("hex:")) {
56489
57055
  if (widget.type !== "separator" && widget.type !== "flex-separator") {
56490
57056
  const widgetImpl = getWidget(widget.type);
56491
- newWidget.color = widgetImpl.getDefaultColor();
57057
+ if (widgetImpl) {
57058
+ newWidget.color = widgetImpl.getDefaultColor();
57059
+ }
56492
57060
  }
56493
57061
  }
56494
57062
  if (widget.backgroundColor?.startsWith("hex:")) {
@@ -56498,7 +57066,9 @@ var TerminalOptionsMenu = ({ settings, onUpdate, onBack }) => {
56498
57066
  if (widget.color?.startsWith("ansi256:")) {
56499
57067
  if (widget.type !== "separator" && widget.type !== "flex-separator") {
56500
57068
  const widgetImpl = getWidget(widget.type);
56501
- newWidget.color = widgetImpl.getDefaultColor();
57069
+ if (widgetImpl) {
57070
+ newWidget.color = widgetImpl.getDefaultColor();
57071
+ }
56502
57072
  }
56503
57073
  }
56504
57074
  if (widget.backgroundColor?.startsWith("ansi256:")) {
@@ -56508,7 +57078,9 @@ var TerminalOptionsMenu = ({ settings, onUpdate, onBack }) => {
56508
57078
  if (widget.color?.startsWith("ansi256:") || widget.color?.startsWith("hex:")) {
56509
57079
  if (widget.type !== "separator" && widget.type !== "flex-separator") {
56510
57080
  const widgetImpl = getWidget(widget.type);
56511
- newWidget.color = widgetImpl.getDefaultColor();
57081
+ if (widgetImpl) {
57082
+ newWidget.color = widgetImpl.getDefaultColor();
57083
+ }
56512
57084
  }
56513
57085
  }
56514
57086
  if (widget.backgroundColor?.startsWith("ansi256:") || widget.backgroundColor?.startsWith("hex:")) {
@@ -56534,7 +57106,9 @@ var TerminalOptionsMenu = ({ settings, onUpdate, onBack }) => {
56534
57106
  if (widget.color?.startsWith("ansi256:") || widget.color?.startsWith("hex:")) {
56535
57107
  if (widget.type !== "separator" && widget.type !== "flex-separator") {
56536
57108
  const widgetImpl = getWidget(widget.type);
56537
- newWidget.color = widgetImpl.getDefaultColor();
57109
+ if (widgetImpl) {
57110
+ newWidget.color = widgetImpl.getDefaultColor();
57111
+ }
56538
57112
  }
56539
57113
  }
56540
57114
  if (widget.backgroundColor?.startsWith("ansi256:") || widget.backgroundColor?.startsWith("hex:")) {
@@ -56902,9 +57476,6 @@ var App2 = () => {
56902
57476
  getExistingStatusLine().then(setExistingStatusLine);
56903
57477
  loadSettings().then((loadedSettings) => {
56904
57478
  source_default.level = loadedSettings.colorLevel;
56905
- while (loadedSettings.lines.length < 3) {
56906
- loadedSettings.lines.push([]);
56907
- }
56908
57479
  setSettings(loadedSettings);
56909
57480
  setOriginalSettings(JSON.parse(JSON.stringify(loadedSettings)));
56910
57481
  });
@@ -57009,6 +57580,9 @@ var App2 = () => {
57009
57580
  newLines[lineIndex] = widgets;
57010
57581
  setSettings({ ...settings, lines: newLines });
57011
57582
  };
57583
+ const updateLines = (newLines) => {
57584
+ setSettings({ ...settings, lines: newLines });
57585
+ };
57012
57586
  const handleLineSelect = (lineIndex) => {
57013
57587
  setSelectedLine(lineIndex);
57014
57588
  setScreen("items");
@@ -57074,12 +57648,14 @@ var App2 = () => {
57074
57648
  setMenuSelections({ ...menuSelections, lines: line });
57075
57649
  handleLineSelect(line);
57076
57650
  },
57651
+ onLinesUpdate: updateLines,
57077
57652
  onBack: () => {
57078
57653
  setMenuSelections({ ...menuSelections, main: 0 });
57079
57654
  setScreen("main");
57080
57655
  },
57081
57656
  initialSelection: menuSelections.lines,
57082
- title: "Select Line to Edit Items"
57657
+ title: "Select Line to Edit Items",
57658
+ allowEditing: true
57083
57659
  }, undefined, false, undefined, this),
57084
57660
  screen === "items" && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(ItemsEditor, {
57085
57661
  widgets: settings.lines[selectedLine] ?? [],
@@ -57095,6 +57671,7 @@ var App2 = () => {
57095
57671
  }, undefined, false, undefined, this),
57096
57672
  screen === "colorLines" && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(LineSelector, {
57097
57673
  lines: settings.lines,
57674
+ onLinesUpdate: updateLines,
57098
57675
  onSelect: (line) => {
57099
57676
  setMenuSelections({ ...menuSelections, lines: line });
57100
57677
  setSelectedLine(line);
@@ -57107,7 +57684,8 @@ var App2 = () => {
57107
57684
  initialSelection: menuSelections.lines,
57108
57685
  title: "Select Line to Edit Colors",
57109
57686
  blockIfPowerlineActive: true,
57110
- settings
57687
+ settings,
57688
+ allowEditing: false
57111
57689
  }, undefined, false, undefined, this),
57112
57690
  screen === "colors" && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(ColorMenu, {
57113
57691
  widgets: settings.lines[selectedLine] ?? [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline",
3
- "version": "2.0.9",
3
+ "version": "2.0.11",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",
@@ -11,13 +11,13 @@
11
11
  "dist/"
12
12
  ],
13
13
  "scripts": {
14
- "start": "bun run patch && bun run src/ccstatusline.ts",
15
- "statusline": "bun run src/ccstatusline.ts",
16
- "patch": "patch-package",
17
- "build": "bun run patch && rm -rf dist/* && bun build src/ccstatusline.ts --target=node --outfile=dist/ccstatusline.js --target-version=14",
14
+ "start": "bun run src/ccstatusline.ts",
15
+ "build": "rm -rf dist/* && bun build src/ccstatusline.ts --target=node --outfile=dist/ccstatusline.js --target-version=14",
18
16
  "postbuild": "bun run scripts/replace-version.ts",
17
+ "example": "cat scripts/payload.example.json | bun start",
19
18
  "prepublishOnly": "bun run build",
20
- "lint": "bun tsc --noEmit; eslint . --config eslint.config.js --max-warnings=999999 --fix"
19
+ "lint": "bun tsc --noEmit; eslint . --config eslint.config.js --max-warnings=999999 --fix",
20
+ "test": "bun vitest"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@eslint/js": "^9.33.0",
@@ -34,14 +34,16 @@
34
34
  "ink": "^6.2.0",
35
35
  "ink-gradient": "^3.0.0",
36
36
  "ink-select-input": "^6.2.0",
37
- "patch-package": "^8.0.0",
38
37
  "react": "^19.1.1",
39
38
  "react-devtools-core": "^6.1.5",
40
39
  "strip-ansi": "^7.1.0",
41
40
  "tinyglobby": "^0.2.14",
42
41
  "typescript": "^5.9.2",
43
42
  "typescript-eslint": "^8.39.1",
44
- "zod": "^4.0.17"
43
+ "vitest": "^3.2.4",
44
+ "zod": "^4.0.17",
45
+ "pluralize": "^8.0.0",
46
+ "@types/pluralize": "^0.0.33"
45
47
  },
46
48
  "keywords": [
47
49
  "claude",
@@ -61,5 +63,8 @@
61
63
  },
62
64
  "trustedDependencies": [
63
65
  "unrs-resolver"
64
- ]
66
+ ],
67
+ "patchedDependencies": {
68
+ "ink@6.2.0": "patches/ink@6.2.0.patch"
69
+ }
65
70
  }