ccstatusline 1.0.12 → 1.0.13

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.
@@ -311,6 +311,15 @@ var renderSingleLine = (items, terminalWidth, widthDetectionAvailable, settings)
311
311
  const customText = item.customText || "";
312
312
  elements.push(customTextColor(customText));
313
313
  break;
314
+ case "custom-command":
315
+ const cmdText = item.commandPath ? `[cmd: ${item.commandPath.substring(0, 20)}${item.commandPath.length > 20 ? "..." : ""}]` : "[No command]";
316
+ if (!item.preserveColors) {
317
+ const cmdColor = chalk[item.color || "white"] || chalk.white;
318
+ elements.push(cmdColor(cmdText));
319
+ } else {
320
+ elements.push(chalk.white(cmdText));
321
+ }
322
+ break;
314
323
  }
315
324
  });
316
325
  let statusLine = "";
@@ -514,6 +523,12 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
514
523
  const [moveMode, setMoveMode] = useState(false);
515
524
  const [editingText, setEditingText] = useState(false);
516
525
  const [textInput, setTextInput] = useState("");
526
+ const [textCursorPos, setTextCursorPos] = useState(0);
527
+ const [editingCommand, setEditingCommand] = useState(false);
528
+ const [commandInput, setCommandInput] = useState("");
529
+ const [commandCursorPos, setCommandCursorPos] = useState(0);
530
+ const [editingMaxWidth, setEditingMaxWidth] = useState(false);
531
+ const [maxWidthInput, setMaxWidthInput] = useState("");
517
532
  const separatorChars = ["|", "-", ",", " "];
518
533
  useInput((input, key) => {
519
534
  if (editingText) {
@@ -526,13 +541,83 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
526
541
  }
527
542
  setEditingText(false);
528
543
  setTextInput("");
544
+ setTextCursorPos(0);
529
545
  } else if (key.escape) {
530
546
  setEditingText(false);
531
547
  setTextInput("");
548
+ setTextCursorPos(0);
549
+ } else if (key.leftArrow) {
550
+ setTextCursorPos(Math.max(0, textCursorPos - 1));
551
+ } else if (key.rightArrow) {
552
+ setTextCursorPos(Math.min(textInput.length, textCursorPos + 1));
553
+ } else if (key.ctrl && key.leftArrow) {
554
+ setTextCursorPos(0);
555
+ } else if (key.ctrl && key.rightArrow) {
556
+ setTextCursorPos(textInput.length);
532
557
  } else if (key.backspace || key.delete) {
533
- setTextInput(textInput.slice(0, -1));
558
+ if (textCursorPos > 0) {
559
+ setTextInput(textInput.slice(0, textCursorPos - 1) + textInput.slice(textCursorPos));
560
+ setTextCursorPos(textCursorPos - 1);
561
+ }
534
562
  } else if (input && input.length === 1) {
535
- setTextInput(textInput + input);
563
+ setTextInput(textInput.slice(0, textCursorPos) + input + textInput.slice(textCursorPos));
564
+ setTextCursorPos(textCursorPos + 1);
565
+ }
566
+ } else if (editingCommand) {
567
+ if (key.return) {
568
+ const currentItem2 = items[selectedIndex];
569
+ if (currentItem2) {
570
+ const newItems = [...items];
571
+ newItems[selectedIndex] = { ...currentItem2, commandPath: commandInput };
572
+ onUpdate(newItems);
573
+ }
574
+ setEditingCommand(false);
575
+ setCommandInput("");
576
+ setCommandCursorPos(0);
577
+ } else if (key.escape) {
578
+ setEditingCommand(false);
579
+ setCommandInput("");
580
+ setCommandCursorPos(0);
581
+ } else if (key.leftArrow) {
582
+ setCommandCursorPos(Math.max(0, commandCursorPos - 1));
583
+ } else if (key.rightArrow) {
584
+ setCommandCursorPos(Math.min(commandInput.length, commandCursorPos + 1));
585
+ } else if (key.ctrl && key.leftArrow) {
586
+ setCommandCursorPos(0);
587
+ } else if (key.ctrl && key.rightArrow) {
588
+ setCommandCursorPos(commandInput.length);
589
+ } else if (key.backspace || key.delete) {
590
+ if (commandCursorPos > 0) {
591
+ setCommandInput(commandInput.slice(0, commandCursorPos - 1) + commandInput.slice(commandCursorPos));
592
+ setCommandCursorPos(commandCursorPos - 1);
593
+ }
594
+ } else if (input) {
595
+ setCommandInput(commandInput.slice(0, commandCursorPos) + input + commandInput.slice(commandCursorPos));
596
+ setCommandCursorPos(commandCursorPos + input.length);
597
+ }
598
+ } else if (editingMaxWidth) {
599
+ if (key.return) {
600
+ const currentItem2 = items[selectedIndex];
601
+ if (currentItem2) {
602
+ const width = parseInt(maxWidthInput, 10);
603
+ const newItems = [...items];
604
+ if (!isNaN(width) && width > 0) {
605
+ newItems[selectedIndex] = { ...currentItem2, maxWidth: width };
606
+ } else {
607
+ const { maxWidth, ...rest } = currentItem2;
608
+ newItems[selectedIndex] = rest;
609
+ }
610
+ onUpdate(newItems);
611
+ }
612
+ setEditingMaxWidth(false);
613
+ setMaxWidthInput("");
614
+ } else if (key.escape) {
615
+ setEditingMaxWidth(false);
616
+ setMaxWidthInput("");
617
+ } else if (key.backspace || key.delete) {
618
+ setMaxWidthInput(maxWidthInput.slice(0, -1));
619
+ } else if (input && /\d/.test(input)) {
620
+ setMaxWidthInput(maxWidthInput + input);
536
621
  }
537
622
  } else if (moveMode) {
538
623
  if (key.upArrow && selectedIndex > 0) {
@@ -577,7 +662,8 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
577
662
  "terminal-width",
578
663
  "version",
579
664
  "flex-separator",
580
- "custom-text"
665
+ "custom-text",
666
+ "custom-command"
581
667
  ];
582
668
  const currentItem2 = items[selectedIndex];
583
669
  if (currentItem2) {
@@ -607,7 +693,8 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
607
693
  "terminal-width",
608
694
  "version",
609
695
  "flex-separator",
610
- "custom-text"
696
+ "custom-text",
697
+ "custom-command"
611
698
  ];
612
699
  const currentItem2 = items[selectedIndex];
613
700
  if (currentItem2) {
@@ -668,8 +755,28 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
668
755
  } else if (input === "e" && items.length > 0) {
669
756
  const currentItem2 = items[selectedIndex];
670
757
  if (currentItem2 && currentItem2.type === "custom-text") {
671
- setTextInput(currentItem2.customText || "");
758
+ const text = currentItem2.customText || "";
759
+ setTextInput(text);
760
+ setTextCursorPos(text.length);
672
761
  setEditingText(true);
762
+ } else if (currentItem2 && currentItem2.type === "custom-command") {
763
+ const cmd = currentItem2.commandPath || "";
764
+ setCommandInput(cmd);
765
+ setCommandCursorPos(cmd.length);
766
+ setEditingCommand(true);
767
+ }
768
+ } else if (input === "w" && items.length > 0) {
769
+ const currentItem2 = items[selectedIndex];
770
+ if (currentItem2 && currentItem2.type === "custom-command") {
771
+ setMaxWidthInput(currentItem2.maxWidth ? currentItem2.maxWidth.toString() : "");
772
+ setEditingMaxWidth(true);
773
+ }
774
+ } else if (input === "p" && items.length > 0) {
775
+ const currentItem2 = items[selectedIndex];
776
+ if (currentItem2 && currentItem2.type === "custom-command") {
777
+ const newItems = [...items];
778
+ newItems[selectedIndex] = { ...currentItem2, preserveColors: !currentItem2.preserveColors };
779
+ onUpdate(newItems);
673
780
  }
674
781
  } else if (key.escape) {
675
782
  onBack();
@@ -712,6 +819,10 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
712
819
  case "custom-text":
713
820
  const text = item.customText || "Empty";
714
821
  return chalk.white(`Custom Text (${text})`);
822
+ case "custom-command":
823
+ const cmd = item.commandPath || "No command";
824
+ const truncatedCmd = cmd.length > 30 ? `${cmd.substring(0, 27)}...` : cmd;
825
+ return chalk.yellow(`Custom Command (${truncatedCmd})`);
715
826
  }
716
827
  };
717
828
  const hasFlexSeparator = items.some((item) => item.type === "flex-separator");
@@ -720,7 +831,8 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
720
831
  const isSeparator = currentItem?.type === "separator";
721
832
  const isFlexSeparator = currentItem?.type === "flex-separator";
722
833
  const isCustomText = currentItem?.type === "custom-text";
723
- const canToggleRaw = currentItem && !isSeparator && !isFlexSeparator && !isCustomText;
834
+ const isCustomCommand = currentItem?.type === "custom-command";
835
+ const canToggleRaw = currentItem && !isSeparator && !isFlexSeparator && !isCustomText && !isCustomCommand;
724
836
  let helpText = "↑↓ select, ←→ change type";
725
837
  if (isSeparator) {
726
838
  helpText += ", Space edit separator";
@@ -728,6 +840,9 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
728
840
  if (isCustomText) {
729
841
  helpText += ", (e)dit text";
730
842
  }
843
+ if (isCustomCommand) {
844
+ helpText += ", (e)dit cmd, (w)idth, (p)reserve colors";
845
+ }
731
846
  helpText += ", Enter to move, (a)dd, (i)nsert, (d)elete, (c)lear line";
732
847
  if (canToggleRaw) {
733
848
  helpText += ", (r)aw value";
@@ -754,7 +869,47 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
754
869
  /* @__PURE__ */ jsxDEV(Text, {
755
870
  children: [
756
871
  "Enter custom text: ",
757
- textInput
872
+ textInput.slice(0, textCursorPos),
873
+ /* @__PURE__ */ jsxDEV(Text, {
874
+ backgroundColor: "gray",
875
+ color: "black",
876
+ children: textInput[textCursorPos] || " "
877
+ }, undefined, false, undefined, this),
878
+ textInput.slice(textCursorPos + 1)
879
+ ]
880
+ }, undefined, true, undefined, this),
881
+ /* @__PURE__ */ jsxDEV(Text, {
882
+ dimColor: true,
883
+ children: "←→ move cursor, Ctrl+←→ jump to start/end, Enter save, ESC cancel"
884
+ }, undefined, false, undefined, this)
885
+ ]
886
+ }, undefined, true, undefined, this) : editingCommand ? /* @__PURE__ */ jsxDEV(Box, {
887
+ flexDirection: "column",
888
+ children: [
889
+ /* @__PURE__ */ jsxDEV(Text, {
890
+ children: [
891
+ "Enter command path: ",
892
+ commandInput.slice(0, commandCursorPos),
893
+ /* @__PURE__ */ jsxDEV(Text, {
894
+ backgroundColor: "gray",
895
+ color: "black",
896
+ children: commandInput[commandCursorPos] || " "
897
+ }, undefined, false, undefined, this),
898
+ commandInput.slice(commandCursorPos + 1)
899
+ ]
900
+ }, undefined, true, undefined, this),
901
+ /* @__PURE__ */ jsxDEV(Text, {
902
+ dimColor: true,
903
+ children: "←→ move cursor, Ctrl+←→ jump to start/end, Enter save, ESC cancel"
904
+ }, undefined, false, undefined, this)
905
+ ]
906
+ }, undefined, true, undefined, this) : editingMaxWidth ? /* @__PURE__ */ jsxDEV(Box, {
907
+ flexDirection: "column",
908
+ children: [
909
+ /* @__PURE__ */ jsxDEV(Text, {
910
+ children: [
911
+ "Enter max width (blank for no limit): ",
912
+ maxWidthInput
758
913
  ]
759
914
  }, undefined, true, undefined, this),
760
915
  /* @__PURE__ */ jsxDEV(Text, {
@@ -799,6 +954,18 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
799
954
  item.rawValue && /* @__PURE__ */ jsxDEV(Text, {
800
955
  dimColor: true,
801
956
  children: " (raw value)"
957
+ }, undefined, false, undefined, this),
958
+ item.type === "custom-command" && item.maxWidth && /* @__PURE__ */ jsxDEV(Text, {
959
+ dimColor: true,
960
+ children: [
961
+ " (max: ",
962
+ item.maxWidth,
963
+ ")"
964
+ ]
965
+ }, undefined, true, undefined, this),
966
+ item.type === "custom-command" && item.preserveColors && /* @__PURE__ */ jsxDEV(Text, {
967
+ dimColor: true,
968
+ children: " (preserve colors)"
802
969
  }, undefined, false, undefined, this)
803
970
  ]
804
971
  }, undefined, true, undefined, this)
@@ -808,7 +975,7 @@ var ItemsEditor = ({ items, onUpdate, onBack, lineNumber }) => {
808
975
  }, undefined, true, undefined, this);
809
976
  };
810
977
  var ColorMenu = ({ items, onUpdate, onBack }) => {
811
- const colorableItems = items.filter((item) => ["model", "git-branch", "tokens-input", "tokens-output", "tokens-cached", "tokens-total", "context-length", "context-percentage", "session-clock", "version", "custom-text"].includes(item.type));
978
+ const colorableItems = items.filter((item) => ["model", "git-branch", "git-changes", "tokens-input", "tokens-output", "tokens-cached", "tokens-total", "context-length", "context-percentage", "session-clock", "terminal-width", "version", "custom-text", "custom-command"].includes(item.type) && !(item.type === "custom-command" && item.preserveColors));
812
979
  const [selectedIndex, setSelectedIndex] = useState(0);
813
980
  useInput((input, key) => {
814
981
  if (key.escape) {
@@ -871,10 +1038,14 @@ var ColorMenu = ({ items, onUpdate, onBack }) => {
871
1038
  return "Context Percentage";
872
1039
  case "session-clock":
873
1040
  return "Session Clock";
1041
+ case "terminal-width":
1042
+ return "Terminal Width";
874
1043
  case "version":
875
1044
  return "Version";
876
1045
  case "custom-text":
877
1046
  return `Custom Text (${item.customText || "Empty"})`;
1047
+ case "custom-command":
1048
+ return `Custom Command (${item.commandPath ? item.commandPath.substring(0, 20) + (item.commandPath.length > 20 ? "..." : "") : "No command"})`;
878
1049
  default:
879
1050
  return item.type;
880
1051
  }
@@ -1682,6 +1853,58 @@ function renderSingleLine2(items, settings, data, tokenMetrics, sessionDuration)
1682
1853
  const customText = item.customText || "";
1683
1854
  elements.push({ content: customTextColor(customText), type: "custom-text" });
1684
1855
  break;
1856
+ case "custom-command":
1857
+ if (item.commandPath) {
1858
+ try {
1859
+ const output = execSync2(item.commandPath, {
1860
+ encoding: "utf8",
1861
+ stdio: ["pipe", "pipe", "ignore"],
1862
+ timeout: 1000
1863
+ }).trim();
1864
+ if (output) {
1865
+ let finalOutput = output;
1866
+ if (item.maxWidth && item.maxWidth > 0) {
1867
+ const plainLength = output.replace(/\x1b\[[0-9;]*m/g, "").length;
1868
+ if (plainLength > item.maxWidth) {
1869
+ let truncated = "";
1870
+ let currentLength = 0;
1871
+ let inAnsiCode = false;
1872
+ let ansiBuffer = "";
1873
+ for (let i = 0;i < output.length; i++) {
1874
+ const char = output[i];
1875
+ if (char === "\x1B") {
1876
+ inAnsiCode = true;
1877
+ ansiBuffer = char;
1878
+ } else if (inAnsiCode) {
1879
+ ansiBuffer += char;
1880
+ if (char === "m") {
1881
+ truncated += ansiBuffer;
1882
+ inAnsiCode = false;
1883
+ ansiBuffer = "";
1884
+ }
1885
+ } else {
1886
+ if (currentLength < item.maxWidth) {
1887
+ truncated += char;
1888
+ currentLength++;
1889
+ } else {
1890
+ break;
1891
+ }
1892
+ }
1893
+ }
1894
+ finalOutput = truncated;
1895
+ }
1896
+ }
1897
+ if (!item.preserveColors) {
1898
+ const stripped = finalOutput.replace(/\x1b\[[0-9;]*m/g, "");
1899
+ const cmdColor = chalk2[item.color || "white"] || chalk2.white;
1900
+ elements.push({ content: cmdColor(stripped), type: "custom-command" });
1901
+ } else {
1902
+ elements.push({ content: finalOutput, type: "custom-command" });
1903
+ }
1904
+ }
1905
+ } catch {}
1906
+ }
1907
+ break;
1685
1908
  }
1686
1909
  }
1687
1910
  if (elements.length === 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",