@willh/copilotstatusline 0.2.3 → 0.2.4

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Matthew Breedlove (https://github.com/sirmalloc)
3
+ Copyright (c) 2025 Will 保哥, Matthew Breedlove (https://github.com/sirmalloc)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/README.md CHANGED
@@ -26,6 +26,8 @@ Choose `Install or repair Copilot integration`, or install non-interactively:
26
26
  npx -y @willh/copilotstatusline@latest --install npm
27
27
  ```
28
28
 
29
+ Interactive menus support both the arrow keys and Vim-style navigation: `j` moves down and `k` moves up. Text and search inputs continue to treat these keys as ordinary characters.
30
+
29
31
  The installer merges the following keys into the existing Copilot settings and preserves unrelated settings:
30
32
 
31
33
  ```json
@@ -15623,6 +15623,9 @@ function renderValue(config2, label, value) {
15623
15623
  return `${config2.prefix}${body}${config2.suffix}`;
15624
15624
  }
15625
15625
  function numericValue(config2, label, value, formatter = formatTokens) {
15626
+ if (value === undefined) {
15627
+ return null;
15628
+ }
15626
15629
  if (config2.hideWhenZero && value === 0) {
15627
15630
  return null;
15628
15631
  }
@@ -15632,7 +15635,7 @@ function contextUsed(status) {
15632
15635
  if (status.context.usedPercentage !== undefined) {
15633
15636
  return status.context.usedPercentage;
15634
15637
  }
15635
- if (status.context.limitTokens <= 0) {
15638
+ if (status.context.currentTokens === undefined || status.context.limitTokens === undefined || status.context.limitTokens <= 0) {
15636
15639
  return null;
15637
15640
  }
15638
15641
  return status.context.currentTokens / status.context.limitTokens * 100;
@@ -15684,7 +15687,7 @@ function renderWidget(config2, context) {
15684
15687
  case "model":
15685
15688
  return status.modelName === undefined ? null : renderValue(config2, "Model", status.modelName);
15686
15689
  case "model-id":
15687
- return status.modelId === undefined ? null : renderValue(config2, "Model", status.modelId);
15690
+ return status.modelId === undefined ? null : renderValue(config2, "Model ID", status.modelId);
15688
15691
  case "reasoning":
15689
15692
  return status.reasoningEffort === undefined ? null : renderValue(config2, "Effort", status.reasoningEffort);
15690
15693
  case "copilot-version":
@@ -15692,7 +15695,7 @@ function renderWidget(config2, context) {
15692
15695
  case "session-id":
15693
15696
  return status.sessionId === undefined ? null : renderValue(config2, "Session", status.sessionId);
15694
15697
  case "session-name":
15695
- return status.sessionName === undefined ? null : renderValue(config2, "Session", status.sessionName);
15698
+ return status.sessionName === undefined ? null : renderValue(config2, "Session Name", status.sessionName);
15696
15699
  case "cwd":
15697
15700
  return status.cwd === undefined ? null : renderValue(config2, "", status.cwd);
15698
15701
  case "context-used": {
@@ -15714,7 +15717,7 @@ function renderWidget(config2, context) {
15714
15717
  case "lines-removed":
15715
15718
  return numericValue(config2, "-", status.cost.linesRemoved, (value) => String(value));
15716
15719
  case "allow-all":
15717
- return status.allowAll === true ? renderValue(config2, "", "YOLO") : null;
15720
+ return status.allowAll === undefined ? null : renderValue(config2, "Allow All", status.allowAll ? "ON" : "OFF");
15718
15721
  case "git-branch": {
15719
15722
  const branch = cachedCommand(`git-branch:${status.cwd ?? ""}`, context.gitCacheTtlSeconds, () => runFile("git", ["--no-optional-locks", "branch", "--show-current"], status.cwd));
15720
15723
  return branch === null ? null : renderValue(config2, "", branch);
@@ -15786,7 +15789,7 @@ var init_catalog = __esm(() => {
15786
15789
  { type: "session-duration", name: "Session Duration", description: "累計 session 時間", defaultColor: "brightBlack" },
15787
15790
  { type: "lines-added", name: "Lines Added", description: "本 session 新增行數", defaultColor: "green" },
15788
15791
  { type: "lines-removed", name: "Lines Removed", description: "本 session 刪除行數", defaultColor: "red" },
15789
- { type: "allow-all", name: "Allow All", description: "Allow-all/YOLO 狀態", defaultColor: "brightRed" },
15792
+ { type: "allow-all", name: "Allow All", description: "是否啟用所有工具與路徑權限", defaultColor: "brightRed" },
15790
15793
  { type: "git-branch", name: "Git Branch", description: "目前 Git branch", defaultColor: "magenta" },
15791
15794
  { type: "git-changes", name: "Git Changes", description: "Git staged/unstaged/untracked 數量", defaultColor: "yellow" },
15792
15795
  { type: "jj-change", name: "Jujutsu Change", description: "目前 jj change ID", defaultColor: "magenta" },
@@ -54312,7 +54315,7 @@ var package_default;
54312
54315
  var init_package = __esm(() => {
54313
54316
  package_default = {
54314
54317
  name: "@willh/copilotstatusline",
54315
- version: "0.2.3",
54318
+ version: "0.2.4",
54316
54319
  bugs: {
54317
54320
  url: "https://github.com/doggy8088/copilotstatusline/issues"
54318
54321
  },
@@ -54398,6 +54401,26 @@ var init_package = __esm(() => {
54398
54401
  };
54399
54402
  });
54400
54403
 
54404
+ // src/tui/vertical-navigation.ts
54405
+ function getVerticalNavigationDirection(input, key) {
54406
+ if (key.upArrow) {
54407
+ return -1;
54408
+ }
54409
+ if (key.downArrow) {
54410
+ return 1;
54411
+ }
54412
+ if (key.ctrl || key.meta) {
54413
+ return null;
54414
+ }
54415
+ if (input === "k") {
54416
+ return -1;
54417
+ }
54418
+ if (input === "j") {
54419
+ return 1;
54420
+ }
54421
+ return null;
54422
+ }
54423
+
54401
54424
  // node_modules/react/cjs/react-jsx-dev-runtime.development.js
54402
54425
  var require_react_jsx_dev_runtime_development = __commonJS((exports) => {
54403
54426
  var React11 = __toESM(require_react());
@@ -54649,14 +54672,13 @@ function List({
54649
54672
  latestSelectionChange.current?.(selectedValue, selectedIndex);
54650
54673
  }
54651
54674
  }, [selectedIndex, selectedValue]);
54652
- use_input_default((_, key) => {
54675
+ use_input_default((input, key) => {
54653
54676
  if (selectableItems.length === 0) {
54654
54677
  return;
54655
54678
  }
54656
- if (key.upArrow) {
54657
- setSelectedIndex((index) => index === 0 ? selectableItems.length - 1 : index - 1);
54658
- } else if (key.downArrow) {
54659
- setSelectedIndex((index) => index === selectableItems.length - 1 ? 0 : index + 1);
54679
+ const direction = getVerticalNavigationDirection(input, key);
54680
+ if (direction !== null) {
54681
+ setSelectedIndex((index) => (index + direction + selectableItems.length) % selectableItems.length);
54660
54682
  } else if (key.return && selectedItem !== undefined) {
54661
54683
  onSelect(selectedItem.value, selectedIndex);
54662
54684
  }
@@ -54799,13 +54821,13 @@ function ColorEditor({
54799
54821
  }
54800
54822
  return;
54801
54823
  }
54802
- if (key.upArrow || key.downArrow) {
54803
- const direction = key.upArrow ? -1 : 1;
54804
- setSelectedIndex((selectedIndex + direction + widgets.length) % widgets.length);
54824
+ const direction = getVerticalNavigationDirection(input, key);
54825
+ if (direction !== null) {
54826
+ setSelectedIndex((index) => (index + direction + widgets.length) % widgets.length);
54805
54827
  } else if ((key.leftArrow || key.rightArrow) && selectedWidget !== undefined) {
54806
- const direction = key.leftArrow ? -1 : 1;
54828
+ const direction2 = key.leftArrow ? -1 : 1;
54807
54829
  const field = editingBackground ? "backgroundColor" : "color";
54808
- onUpdate(widgets.map((widget2, index) => index === selectedIndex ? { ...widget2, [field]: cycleColor(widget2[field], direction) } : widget2));
54830
+ onUpdate(widgets.map((widget2, index) => index === selectedIndex ? { ...widget2, [field]: cycleColor(widget2[field], direction2) } : widget2));
54809
54831
  } else if (input === "f") {
54810
54832
  setEditingBackground((value) => !value);
54811
54833
  } else if (input === "b" && selectedWidget !== undefined) {
@@ -54881,7 +54903,7 @@ function ColorEditor({
54881
54903
  /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
54882
54904
  dimColor: true,
54883
54905
  children: [
54884
- "↑↓ select, ←→ cycle",
54906
+ "↑↓/j/k select, ←→ cycle",
54885
54907
  " ",
54886
54908
  editingBackground ? "background" : "foreground",
54887
54909
  ", (f) toggle bg/fg, (b)old, (r)eset, (c)lear all, ESC back"
@@ -55014,8 +55036,8 @@ function LineSelector({
55014
55036
  return;
55015
55037
  }
55016
55038
  if (moveMode) {
55017
- if ((key.upArrow || key.downArrow) && lines.length > 1) {
55018
- const direction = key.upArrow ? -1 : 1;
55039
+ const direction = getVerticalNavigationDirection(input, key);
55040
+ if (direction !== null && lines.length > 1) {
55019
55041
  const target = (selectedIndex + direction + lines.length) % lines.length;
55020
55042
  const reordered = [...lines];
55021
55043
  const current = reordered[selectedIndex];
@@ -55080,7 +55102,7 @@ function LineSelector({
55080
55102
  }, undefined, false, undefined, this),
55081
55103
  /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
55082
55104
  dimColor: true,
55083
- children: moveMode ? "↑↓ to move line, ESC or Enter to exit move mode" : allowEditing ? "(a) append line, (d) delete line, (m) move line, ESC back" : "ESC to go back"
55105
+ children: moveMode ? "↑↓/j/k to move line, ESC or Enter to exit move mode" : allowEditing ? "↑↓/j/k select, (a) append line, (d) delete line, (m) move line, ESC back" : "↑↓/j/k select, ESC to go back"
55084
55106
  }, undefined, false, undefined, this),
55085
55107
  moveMode ? /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
55086
55108
  marginTop: 1,
@@ -55209,6 +55231,10 @@ function MainMenu({
55209
55231
  bold: true,
55210
55232
  children: "Main Menu"
55211
55233
  }, undefined, false, undefined, this),
55234
+ /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
55235
+ dimColor: true,
55236
+ children: "↑↓ or j/k to select, Enter to open"
55237
+ }, undefined, false, undefined, this),
55212
55238
  /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(List, {
55213
55239
  items: menuItems(integration, hasChanges),
55214
55240
  marginTop: 1,
@@ -55464,8 +55490,8 @@ function WidgetEditor({
55464
55490
  return;
55465
55491
  }
55466
55492
  const current = pickerIndex < 0 ? 0 : pickerIndex;
55467
- const direction = key.upArrow ? -1 : 1;
55468
- const nextIndex = (current + direction + filteredCatalog.length) % filteredCatalog.length;
55493
+ const direction2 = key.upArrow ? -1 : 1;
55494
+ const nextIndex = (current + direction2 + filteredCatalog.length) % filteredCatalog.length;
55469
55495
  setPicker({ ...picker, selectedType: filteredCatalog[nextIndex]?.type ?? null });
55470
55496
  } else if (key.return && selectedPickerEntry !== undefined) {
55471
55497
  applyPicker(selectedPickerEntry.type);
@@ -55481,9 +55507,9 @@ function WidgetEditor({
55481
55507
  return;
55482
55508
  }
55483
55509
  if (moveMode) {
55484
- if ((key.upArrow || key.downArrow) && widgets.length > 1) {
55485
- const direction = key.upArrow ? -1 : 1;
55486
- const target = (selectedIndex + direction + widgets.length) % widgets.length;
55510
+ const direction2 = getVerticalNavigationDirection(input, key);
55511
+ if (direction2 !== null && widgets.length > 1) {
55512
+ const target = (selectedIndex + direction2 + widgets.length) % widgets.length;
55487
55513
  const reordered = [...widgets];
55488
55514
  const current = reordered[selectedIndex];
55489
55515
  const replacement = reordered[target];
@@ -55506,9 +55532,9 @@ function WidgetEditor({
55506
55532
  if (globalKeyAction === "ignore") {
55507
55533
  return;
55508
55534
  }
55509
- if ((key.upArrow || key.downArrow) && widgets.length > 0) {
55510
- const direction = key.upArrow ? -1 : 1;
55511
- setSelectedIndex((selectedIndex + direction + widgets.length) % widgets.length);
55535
+ const direction = getVerticalNavigationDirection(input, key);
55536
+ if (direction !== null && widgets.length > 0) {
55537
+ setSelectedIndex((index) => (index + direction + widgets.length) % widgets.length);
55512
55538
  } else if ((key.leftArrow || key.rightArrow) && currentWidget !== undefined) {
55513
55539
  openPicker("change");
55514
55540
  } else if (key.return && currentWidget !== undefined) {
@@ -55521,7 +55547,7 @@ function WidgetEditor({
55521
55547
  const next = widgets.filter((_, index) => index !== selectedIndex);
55522
55548
  onUpdate(next);
55523
55549
  setSelectedIndex(Math.max(0, Math.min(selectedIndex, next.length - 1)));
55524
- } else if (input === "k" && currentWidget !== undefined) {
55550
+ } else if (input === "y" && currentWidget !== undefined) {
55525
55551
  const clone3 = { ...currentWidget, id: randomUUID() };
55526
55552
  const next = [...widgets];
55527
55553
  next.splice(selectedIndex + 1, 0, clone3);
@@ -55686,7 +55712,7 @@ function WidgetEditor({
55686
55712
  }, undefined, true, undefined, this),
55687
55713
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
55688
55714
  dimColor: true,
55689
- children: moveMode ? "↑↓ move widget, ESC or Enter exit move mode" : "↑↓ select, ←→ change, Enter move, (a)dd, (i)nsert, (k) clone, (d)elete, (c)lear"
55715
+ children: moveMode ? "↑↓/j/k move widget, ESC or Enter exit move mode" : "↑↓/j/k select, ←→ change, Enter move, (a)dd, (i)nsert, (y) clone, (d)elete, (c)lear"
55690
55716
  }, undefined, false, undefined, this),
55691
55717
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
55692
55718
  dimColor: true,
@@ -56484,7 +56510,7 @@ var CopilotStatusSchema = exports_external.looseObject({
56484
56510
  allow_all: exports_external.boolean().optional()
56485
56511
  });
56486
56512
  function finiteNumber(value) {
56487
- return typeof value === "number" && Number.isFinite(value) ? value : 0;
56513
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
56488
56514
  }
56489
56515
  function normalizeCopilotStatus(status) {
56490
56516
  const model = status.model;
@@ -56497,7 +56523,15 @@ function normalizeCopilotStatus(status) {
56497
56523
  const cacheWriteTokens = finiteNumber(context?.total_cache_write_tokens);
56498
56524
  const reasoningTokens = finiteNumber(context?.total_reasoning_tokens);
56499
56525
  const reportedTotal = finiteNumber(context?.total_tokens);
56500
- const totalTokens = reportedTotal > 0 ? reportedTotal : inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens + reasoningTokens;
56526
+ const componentTokens = [
56527
+ inputTokens,
56528
+ outputTokens,
56529
+ cacheReadTokens,
56530
+ cacheWriteTokens,
56531
+ reasoningTokens
56532
+ ];
56533
+ const derivedTotal = componentTokens.some((value) => value !== undefined) ? componentTokens.reduce((sum, value) => sum + (value ?? 0), 0) : undefined;
56534
+ const totalTokens = reportedTotal ?? derivedTotal;
56501
56535
  return {
56502
56536
  sessionId: status.session_id,
56503
56537
  sessionName: status.session_name ?? undefined,
@@ -56699,22 +56733,44 @@ async function loadState(statePath, copilotHome, sessionId, updatedAt, updatedAt
56699
56733
  };
56700
56734
  }
56701
56735
  }
56702
- function assertTokenCounters(status) {
56703
- const counters = [
56736
+ function tokenCounters(status) {
56737
+ const cumulative = [
56704
56738
  status.context.inputTokens,
56705
56739
  status.context.outputTokens,
56706
56740
  status.context.cacheReadTokens,
56707
56741
  status.context.cacheWriteTokens,
56708
56742
  status.context.reasoningTokens,
56709
- status.context.totalTokens,
56743
+ status.context.totalTokens
56744
+ ];
56745
+ const optional2 = [
56710
56746
  status.context.lastCallInputTokens,
56711
56747
  status.context.lastCallOutputTokens,
56712
56748
  status.context.currentTokens,
56713
56749
  status.context.limitTokens
56714
56750
  ];
56715
- if (!counters.every((value) => Number.isSafeInteger(value) && value >= 0)) {
56751
+ const present = [...cumulative, ...optional2].filter((value) => value !== undefined);
56752
+ if (!present.every((value) => Number.isSafeInteger(value) && value >= 0)) {
56716
56753
  throw new Error("token counters must be non-negative safe integers");
56717
56754
  }
56755
+ if (cumulative.some((value) => value === undefined)) {
56756
+ return;
56757
+ }
56758
+ const [
56759
+ inputTokens,
56760
+ outputTokens,
56761
+ cacheReadTokens,
56762
+ cacheWriteTokens,
56763
+ reasoningTokens,
56764
+ totalTokens
56765
+ ] = cumulative;
56766
+ return {
56767
+ inputTokens: inputTokens ?? 0,
56768
+ outputTokens: outputTokens ?? 0,
56769
+ cacheReadTokens: cacheReadTokens ?? 0,
56770
+ cacheWriteTokens: cacheWriteTokens ?? 0,
56771
+ reasoningTokens: reasoningTokens ?? 0,
56772
+ totalTokens: totalTokens ?? 0
56773
+ };
56718
56774
  }
56719
56775
  function delta(current, previous) {
56720
56776
  return Math.max(0, current - (previous ?? 0));
@@ -56740,7 +56796,10 @@ async function recordTokenUsage(status, options = {}) {
56740
56796
  if (sessionId === undefined || sessionId.trim() === "") {
56741
56797
  return { recorded: false };
56742
56798
  }
56743
- assertTokenCounters(status);
56799
+ const counters = tokenCounters(status);
56800
+ if (counters === undefined) {
56801
+ return { recorded: false };
56802
+ }
56744
56803
  const now = options.now ?? new Date;
56745
56804
  const timestamp = localIsoTimestamp(now);
56746
56805
  const copilotHome = options.copilotHome ?? getCopilotHome();
@@ -56756,12 +56815,12 @@ async function recordTokenUsage(status, options = {}) {
56756
56815
  const previous = state.sessions[sessionKey] ?? state.sessions[sessionId];
56757
56816
  const model = status.modelName ?? status.modelId ?? "unknown";
56758
56817
  const modelId = status.modelId ?? "unknown";
56759
- const deltaInput = delta(status.context.inputTokens, previous?.inputTokens);
56760
- const deltaOutput = delta(status.context.outputTokens, previous?.outputTokens);
56761
- const deltaCacheRead = delta(status.context.cacheReadTokens, previous?.cacheReadTokens);
56762
- const deltaCacheWrite = delta(status.context.cacheWriteTokens, previous?.cacheWriteTokens);
56763
- const deltaReasoning = delta(status.context.reasoningTokens, previous?.reasoningTokens);
56764
- const deltaTotal = delta(status.context.totalTokens, previous?.totalTokens);
56818
+ const deltaInput = delta(counters.inputTokens, previous?.inputTokens);
56819
+ const deltaOutput = delta(counters.outputTokens, previous?.outputTokens);
56820
+ const deltaCacheRead = delta(counters.cacheReadTokens, previous?.cacheReadTokens);
56821
+ const deltaCacheWrite = delta(counters.cacheWriteTokens, previous?.cacheWriteTokens);
56822
+ const deltaReasoning = delta(counters.reasoningTokens, previous?.reasoningTokens);
56823
+ const deltaTotal = delta(counters.totalTokens, previous?.totalTokens);
56765
56824
  const previousModel = previous?.model ?? "";
56766
56825
  const modelChanged = previousModel !== "" && previousModel !== model;
56767
56826
  const turnNo = (previous?.turnNo ?? 0) + (deltaTotal > 0 ? 1 : 0);
@@ -56779,12 +56838,12 @@ async function recordTokenUsage(status, options = {}) {
56779
56838
  previous_model: previousModel,
56780
56839
  model_changed: modelChanged,
56781
56840
  tokens: {
56782
- input: status.context.inputTokens,
56783
- output: status.context.outputTokens,
56784
- cache_read: status.context.cacheReadTokens,
56785
- cache_write: status.context.cacheWriteTokens,
56786
- reasoning: status.context.reasoningTokens,
56787
- total: status.context.totalTokens,
56841
+ input: counters.inputTokens,
56842
+ output: counters.outputTokens,
56843
+ cache_read: counters.cacheReadTokens,
56844
+ cache_write: counters.cacheWriteTokens,
56845
+ reasoning: counters.reasoningTokens,
56846
+ total: counters.totalTokens,
56788
56847
  last_call_input: status.context.lastCallInputTokens,
56789
56848
  last_call_output: status.context.lastCallOutputTokens
56790
56849
  },
@@ -56820,12 +56879,12 @@ async function recordTokenUsage(status, options = {}) {
56820
56879
  turnNo,
56821
56880
  model,
56822
56881
  modelId,
56823
- inputTokens: status.context.inputTokens,
56824
- outputTokens: status.context.outputTokens,
56825
- cacheReadTokens: status.context.cacheReadTokens,
56826
- cacheWriteTokens: status.context.cacheWriteTokens,
56827
- reasoningTokens: status.context.reasoningTokens,
56828
- totalTokens: status.context.totalTokens,
56882
+ inputTokens: counters.inputTokens,
56883
+ outputTokens: counters.outputTokens,
56884
+ cacheReadTokens: counters.cacheReadTokens,
56885
+ cacheWriteTokens: counters.cacheWriteTokens,
56886
+ reasoningTokens: counters.reasoningTokens,
56887
+ totalTokens: counters.totalTokens,
56829
56888
  updatedAt: timestamp,
56830
56889
  updatedAtEpochMs: now.getTime()
56831
56890
  };
@@ -56841,7 +56900,7 @@ async function recordTokenUsage(status, options = {}) {
56841
56900
  }
56842
56901
 
56843
56902
  // src/copilotstatusline.ts
56844
- var PACKAGE_VERSION = "0.2.3";
56903
+ var PACKAGE_VERSION = "0.2.4";
56845
56904
  async function readStdin() {
56846
56905
  process.stdin.setEncoding("utf8");
56847
56906
  const chunks = [];
package/docs/USAGE.md CHANGED
@@ -67,6 +67,8 @@ Uninstallation removes `statusLine` only when its command is recognized as belon
67
67
 
68
68
  ## Formatter settings
69
69
 
70
+ The interactive editor accepts Up/Down arrows or Vim-style `k`/`j` for vertical navigation. The same shortcuts move lines and widgets while move mode is active. Widget search and text-editing fields keep `j` and `k` as normal text input. In the widget editor, `y` clones the selected widget.
71
+
70
72
  Default path:
71
73
 
72
74
  ```text
@@ -141,6 +143,21 @@ The normalized widgets currently use:
141
143
  - cost: API duration, total duration, premium requests, and added/removed lines;
142
144
  - permission state: `allow_all`.
143
145
 
146
+ Widget availability is divided by source:
147
+
148
+ | Source | Widgets | Availability |
149
+ | --- | --- | --- |
150
+ | Copilot payload | Model, Model ID, Copilot Version, Session ID, Current Directory | Shown when Copilot supplies the corresponding field or supported alias. |
151
+ | Optional Copilot payload | Reasoning, Session Name | Hidden when the active model has no reasoning effort or the session has no name. |
152
+ | Copilot token payload | Input Tokens, Output Tokens, Cache Read, Cache Write, Reasoning Tokens, Total Tokens, Last Call Input, Last Call Output | Zero is shown as a real value; a missing field is hidden instead of being converted to zero. |
153
+ | Copilot context payload | Current Context, Context Limit, Context Used, Context Remaining | Used percentage comes from the payload, or is derived when both the current value and limit are available. |
154
+ | Copilot cost payload | Premium Requests, API Duration, Session Duration, Lines Added, Lines Removed | Shown when the corresponding cumulative counter is available. |
155
+ | Copilot permission payload | Allow All | `Allow All: ON` and `Allow All: OFF` are rendered distinctly; a missing field is hidden. |
156
+ | Repository probes | Git Branch, Git Changes, Jujutsu Change | Requires the matching executable and repository. Failed or timed-out probes are hidden. |
157
+ | Local runtime | Terminal Width, Free Memory | Read from the current terminal and operating system. |
158
+ | User configuration | Custom Text, Custom Command | Requires configured text or a command that produces output. |
159
+ | Layout | Separator, Flex | Always available as formatting controls and does not represent Copilot payload data. |
160
+
144
161
  ## Diagnostics
145
162
 
146
163
  Inspect integration status:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@willh/copilotstatusline",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "bugs": {
5
5
  "url": "https://github.com/doggy8088/copilotstatusline/issues"
6
6
  },