ccstatusline 2.2.10 โ 2.2.12
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 +8 -3
- package/dist/ccstatusline.js +432 -90
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -47,19 +47,24 @@
|
|
|
47
47
|
|
|
48
48
|
## ๐ Recent Updates
|
|
49
49
|
|
|
50
|
-
### v2.2.9 - v2.2.
|
|
50
|
+
### v2.2.9 - v2.2.12 - GitLab support, reset timers, context, compaction, and git widgets
|
|
51
51
|
|
|
52
52
|
- **๐ฆ GitLab PR/MR support** - `Git Branch` and `Git PR/MR` now support GitHub, GitLab, and compatible self-hosted remotes, using `gh` or `glab` as appropriate.
|
|
53
53
|
- **๐ Status line refresh interval** - Installed configs can set Claude Code's `statusLine.refreshInterval` from the TUI when Claude Code >=2.1.97 supports it.
|
|
54
54
|
- **๐งญ Wrap-around TUI navigation** - Menu/list navigation and move/reorder modes now wrap at the first and last items.
|
|
55
55
|
- **๐ Clone widget shortcut** - Press `k` in the item editor to duplicate the selected widget, with fresh Powerline background color for cloned Powerline items.
|
|
56
56
|
- **๐ Short bar display modes** - Context percentage, Context Bar, Session Usage, Weekly Usage, Block Timer, and reset timer widgets can use compact bar variants.
|
|
57
|
+
- **โฑ๏ธ Usage time cursor** - Session Usage and Weekly Usage progress bars can show the elapsed time position within the current usage window.
|
|
57
58
|
- **๐ Reset timer timestamps** - Block and Weekly Reset Timer widgets can show exact reset timestamps with compact formatting, 12/24-hour display, IANA time zones, and locale selection.
|
|
58
59
|
- **๐ช Context Window widget** - Added a `Context Window` widget for total model window size, keeping `Context Length` focused on current context usage.
|
|
60
|
+
- **๐ Compaction Counter widget** - Added a `Compaction Counter` widget that tracks session context compactions, with icon/text/number formats, optional Nerd Font icon, and hide-when-zero behavior.
|
|
59
61
|
- **๐งฎ Git file status widgets** - Added `Git Staged Files`, `Git Unstaged Files`, `Git Untracked Files`, and `Git Clean Status` for file counts and clean/dirty state.
|
|
60
|
-
-
|
|
62
|
+
- **๐ท๏ธ Clear context percentage labels** - `Context %` and `Context % (usable)` now label rendered values as used or left when toggling used/remaining mode.
|
|
63
|
+
- **โก More Powerline caps** - The Powerline separator editor now supports more than three start/end caps.
|
|
64
|
+
- **๐ง Thinking Effort updates** - Added `xhigh`, show `default` when no effort is set, mark unknown future effort levels with `?`, and track live status JSON plus `/effort` command changes.
|
|
61
65
|
- **๐งฎ More accurate token counts** - Streaming duplicate JSONL entries are deduped so token widgets do not overcount live Claude Code output.
|
|
62
66
|
- **๐ท๏ธ Cleaner model display** - The Model widget strips trailing context suffixes like `(1M context)`; use `Context Window` when you want the total window size shown.
|
|
67
|
+
- **๐งน Cleaner empty-widget separators** - Manual separators now collapse around widgets that render empty, avoiding dangling separators when hide-when-empty widgets disappear.
|
|
63
68
|
- **๐งฑ More resilient Git helpers** - Git widgets handle missing or unusual git command output more defensively.
|
|
64
69
|
|
|
65
70
|
### v2.2.8 - Git widgets, smarter picker search, and minimalist mode
|
|
@@ -192,7 +197,7 @@
|
|
|
192
197
|
|
|
193
198
|
## โจ Features
|
|
194
199
|
|
|
195
|
-
- **๐ Real-time Metrics** - Display model name, git branch, token usage, session duration, block timer, and more
|
|
200
|
+
- **๐ Real-time Metrics** - Display model name, git branch, token usage, session duration, compaction count, block timer, and more
|
|
196
201
|
- **๐จ Fully Customizable** - Choose what to display and customize colors for each element
|
|
197
202
|
- **โก Powerline Support** - Beautiful Powerline-style rendering with arrow separators, caps, and custom fonts
|
|
198
203
|
- **๐ Multi-line Support** - Configure multiple independent status lines
|
package/dist/ccstatusline.js
CHANGED
|
@@ -56010,17 +56010,26 @@ function getContextConfig(modelIdentifier, contextWindowSize) {
|
|
|
56010
56010
|
var DEFAULT_CONTEXT_WINDOW_SIZE = 200000, USABLE_CONTEXT_RATIO = 0.8;
|
|
56011
56011
|
|
|
56012
56012
|
// src/utils/context-percentage.ts
|
|
56013
|
-
function
|
|
56013
|
+
function calculateContextPercentageMetrics(context) {
|
|
56014
56014
|
const contextWindowMetrics = getContextWindowMetrics(context.data);
|
|
56015
|
+
const modelIdentifier = getModelContextIdentifier(context.data?.model);
|
|
56016
|
+
const contextConfig = getContextConfig(modelIdentifier, contextWindowMetrics.windowSize);
|
|
56015
56017
|
if (contextWindowMetrics.usedPercentage !== null) {
|
|
56016
|
-
return
|
|
56018
|
+
return {
|
|
56019
|
+
usedPercentage: contextWindowMetrics.usedPercentage,
|
|
56020
|
+
windowSize: contextConfig.maxTokens
|
|
56021
|
+
};
|
|
56017
56022
|
}
|
|
56018
56023
|
if (!context.tokenMetrics) {
|
|
56019
|
-
return
|
|
56024
|
+
return null;
|
|
56020
56025
|
}
|
|
56021
|
-
|
|
56022
|
-
|
|
56023
|
-
|
|
56026
|
+
return {
|
|
56027
|
+
usedPercentage: Math.min(100, context.tokenMetrics.contextLength / contextConfig.maxTokens * 100),
|
|
56028
|
+
windowSize: contextConfig.maxTokens
|
|
56029
|
+
};
|
|
56030
|
+
}
|
|
56031
|
+
function calculateContextPercentage(context) {
|
|
56032
|
+
return calculateContextPercentageMetrics(context)?.usedPercentage ?? 0;
|
|
56024
56033
|
}
|
|
56025
56034
|
var init_context_percentage = () => {};
|
|
56026
56035
|
|
|
@@ -56127,7 +56136,7 @@ function getTerminalWidth() {
|
|
|
56127
56136
|
function canDetectTerminalWidth() {
|
|
56128
56137
|
return probeTerminalWidth() !== null;
|
|
56129
56138
|
}
|
|
56130
|
-
var __dirname = "/Users/sirmalloc/Projects/Personal/ccstatusline/src/utils", PACKAGE_VERSION = "2.2.
|
|
56139
|
+
var __dirname = "/Users/sirmalloc/Projects/Personal/ccstatusline/src/utils", PACKAGE_VERSION = "2.2.12";
|
|
56131
56140
|
var init_terminal = () => {};
|
|
56132
56141
|
|
|
56133
56142
|
// src/utils/renderer.ts
|
|
@@ -56532,12 +56541,12 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
|
|
|
56532
56541
|
let hasContentBefore = false;
|
|
56533
56542
|
for (let j = i - 1;j >= 0; j--) {
|
|
56534
56543
|
const prevWidget = widgets[j];
|
|
56535
|
-
if (prevWidget
|
|
56536
|
-
|
|
56537
|
-
|
|
56538
|
-
|
|
56539
|
-
|
|
56540
|
-
|
|
56544
|
+
if (!prevWidget)
|
|
56545
|
+
continue;
|
|
56546
|
+
if (prevWidget.type === "separator" || prevWidget.type === "flex-separator")
|
|
56547
|
+
continue;
|
|
56548
|
+
hasContentBefore = Boolean(preRenderedWidgets[j]?.content);
|
|
56549
|
+
break;
|
|
56541
56550
|
}
|
|
56542
56551
|
if (!hasContentBefore)
|
|
56543
56552
|
continue;
|
|
@@ -57118,11 +57127,21 @@ function isUsageProgressMode(mode) {
|
|
|
57118
57127
|
function isUsageSliderMode(mode) {
|
|
57119
57128
|
return mode === "slider" || mode === "slider-only";
|
|
57120
57129
|
}
|
|
57121
|
-
function makeSliderBar(percent, width = SLIDER_WIDTH) {
|
|
57130
|
+
function makeSliderBar(percent, width = SLIDER_WIDTH, options) {
|
|
57122
57131
|
const clamped = Math.max(0, Math.min(100, percent));
|
|
57123
57132
|
const filled = Math.round(clamped / 100 * width);
|
|
57124
|
-
const
|
|
57125
|
-
|
|
57133
|
+
const cursorPos = options?.cursorPercent !== undefined ? Math.min(Math.floor(Math.max(0, Math.min(100, options.cursorPercent)) / 100 * width), width - 1) : -1;
|
|
57134
|
+
let bar = "";
|
|
57135
|
+
for (let i = 0;i < width; i++) {
|
|
57136
|
+
if (i === cursorPos) {
|
|
57137
|
+
bar += "โ";
|
|
57138
|
+
} else if (i < filled) {
|
|
57139
|
+
bar += "โ";
|
|
57140
|
+
} else {
|
|
57141
|
+
bar += "โ";
|
|
57142
|
+
}
|
|
57143
|
+
}
|
|
57144
|
+
return bar;
|
|
57126
57145
|
}
|
|
57127
57146
|
function getUsageProgressBarWidth(mode) {
|
|
57128
57147
|
return mode === "progress" ? 32 : 16;
|
|
@@ -57133,6 +57152,12 @@ function isUsageInverted(item) {
|
|
|
57133
57152
|
function isUsageCompact(item) {
|
|
57134
57153
|
return isMetadataFlagEnabled(item, "compact");
|
|
57135
57154
|
}
|
|
57155
|
+
function isUsageCursorEnabled(item) {
|
|
57156
|
+
return isMetadataFlagEnabled(item, "cursor");
|
|
57157
|
+
}
|
|
57158
|
+
function toggleUsageCursor(item) {
|
|
57159
|
+
return toggleMetadataFlag(item, "cursor");
|
|
57160
|
+
}
|
|
57136
57161
|
function isUsageDateMode(item) {
|
|
57137
57162
|
return isMetadataFlagEnabled(item, "absolute");
|
|
57138
57163
|
}
|
|
@@ -57204,6 +57229,9 @@ function getUsageDisplayModifierText(item, options = {}) {
|
|
|
57204
57229
|
if (isUsageInverted(item)) {
|
|
57205
57230
|
modifiers.push("inverted");
|
|
57206
57231
|
}
|
|
57232
|
+
if (isUsageCursorEnabled(item) && (isUsageProgressMode(mode) || isUsageSliderMode(mode))) {
|
|
57233
|
+
modifiers.push("time cursor");
|
|
57234
|
+
}
|
|
57207
57235
|
if (options.includeCompact && !isUsageProgressMode(mode) && isUsageCompact(item)) {
|
|
57208
57236
|
modifiers.push("compact");
|
|
57209
57237
|
}
|
|
@@ -57231,7 +57259,8 @@ function cycleUsageDisplayMode(item, disabledInProgressKeys = [], includeSlider
|
|
|
57231
57259
|
} else {
|
|
57232
57260
|
nextMode = currentMode === "time" ? "progress" : currentMode === "progress" ? "progress-short" : "time";
|
|
57233
57261
|
}
|
|
57234
|
-
const
|
|
57262
|
+
const keysToRemove = nextMode === "time" ? ["invert", "cursor"] : disabledInProgressKeys;
|
|
57263
|
+
const nextItem = removeMetadataKeys(item, keysToRemove);
|
|
57235
57264
|
const nextMetadata = {
|
|
57236
57265
|
...nextItem.metadata ?? {},
|
|
57237
57266
|
display: nextMode
|
|
@@ -57251,6 +57280,9 @@ function getUsagePercentCustomKeybinds(item) {
|
|
|
57251
57280
|
if (isUsageProgressMode(mode) || isUsageSliderMode(mode)) {
|
|
57252
57281
|
keybinds.push(INVERT_TOGGLE_KEYBIND);
|
|
57253
57282
|
}
|
|
57283
|
+
if (isUsageProgressMode(mode) || isUsageSliderMode(mode)) {
|
|
57284
|
+
keybinds.push(CURSOR_TOGGLE_KEYBIND);
|
|
57285
|
+
}
|
|
57254
57286
|
}
|
|
57255
57287
|
return keybinds;
|
|
57256
57288
|
}
|
|
@@ -57277,12 +57309,13 @@ function getUsageTimerCustomKeybinds(item, options = {}) {
|
|
|
57277
57309
|
}
|
|
57278
57310
|
return keybinds;
|
|
57279
57311
|
}
|
|
57280
|
-
var SLIDER_WIDTH = 10, PROGRESS_TOGGLE_KEYBIND, INVERT_TOGGLE_KEYBIND, COMPACT_TOGGLE_KEYBIND, DATE_TOGGLE_KEYBIND, HOUR_FORMAT_TOGGLE_KEYBIND, TIMEZONE_KEYBIND, LOCALE_KEYBIND;
|
|
57312
|
+
var SLIDER_WIDTH = 10, PROGRESS_TOGGLE_KEYBIND, INVERT_TOGGLE_KEYBIND, COMPACT_TOGGLE_KEYBIND, CURSOR_TOGGLE_KEYBIND, DATE_TOGGLE_KEYBIND, HOUR_FORMAT_TOGGLE_KEYBIND, TIMEZONE_KEYBIND, LOCALE_KEYBIND;
|
|
57281
57313
|
var init_usage_display = __esm(() => {
|
|
57282
57314
|
init_locales2();
|
|
57283
57315
|
PROGRESS_TOGGLE_KEYBIND = { key: "p", label: "(p)rogress toggle", action: "toggle-progress" };
|
|
57284
57316
|
INVERT_TOGGLE_KEYBIND = { key: "v", label: "in(v)ert fill", action: "toggle-invert" };
|
|
57285
57317
|
COMPACT_TOGGLE_KEYBIND = { key: "s", label: "(s)hort time", action: "toggle-compact" };
|
|
57318
|
+
CURSOR_TOGGLE_KEYBIND = { key: "t", label: "(t)ime cursor", action: "toggle-cursor" };
|
|
57286
57319
|
DATE_TOGGLE_KEYBIND = { key: "t", label: "(t)imestamp", action: "toggle-date" };
|
|
57287
57320
|
HOUR_FORMAT_TOGGLE_KEYBIND = { key: "h", label: "12/24 (h)our", action: "toggle-hour-format" };
|
|
57288
57321
|
TIMEZONE_KEYBIND = { key: "z", label: "time(z)one", action: "edit-timezone" };
|
|
@@ -57377,34 +57410,19 @@ class ContextPercentageWidget {
|
|
|
57377
57410
|
}
|
|
57378
57411
|
render(item, context, settings) {
|
|
57379
57412
|
const isInverse = isContextInverse(item);
|
|
57413
|
+
const label = isInverse ? "Ctx Left: " : "Ctx Used: ";
|
|
57380
57414
|
const sliderMode = getContextSliderMode(item);
|
|
57381
|
-
const
|
|
57382
|
-
|
|
57383
|
-
const previewPercent = isInverse ? 90.7 : 9.3;
|
|
57384
|
-
const sliderResult = renderContextSlider(sliderMode, previewPercent);
|
|
57385
|
-
if (sliderResult !== null) {
|
|
57386
|
-
return formatRawOrLabeledValue(item, "Ctx: ", sliderResult);
|
|
57387
|
-
}
|
|
57388
|
-
return formatRawOrLabeledValue(item, "Ctx: ", `${previewPercent.toFixed(1)}%`);
|
|
57389
|
-
}
|
|
57390
|
-
if (contextWindowMetrics.usedPercentage !== null) {
|
|
57391
|
-
const displayPercentage = isInverse ? 100 - contextWindowMetrics.usedPercentage : contextWindowMetrics.usedPercentage;
|
|
57415
|
+
const contextPercentageMetrics = calculateContextPercentageMetrics(context);
|
|
57416
|
+
const formatContextPercentage = (displayPercentage) => {
|
|
57392
57417
|
const sliderResult = renderContextSlider(sliderMode, displayPercentage);
|
|
57393
|
-
|
|
57394
|
-
|
|
57395
|
-
|
|
57396
|
-
return
|
|
57418
|
+
return formatRawOrLabeledValue(item, label, sliderResult ?? `${displayPercentage.toFixed(1)}%`);
|
|
57419
|
+
};
|
|
57420
|
+
if (context.isPreview) {
|
|
57421
|
+
return formatContextPercentage(isInverse ? 90.7 : 9.3);
|
|
57397
57422
|
}
|
|
57398
|
-
if (
|
|
57399
|
-
const
|
|
57400
|
-
|
|
57401
|
-
const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / contextConfig.maxTokens * 100);
|
|
57402
|
-
const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
|
|
57403
|
-
const sliderResult = renderContextSlider(sliderMode, displayPercentage);
|
|
57404
|
-
if (sliderResult !== null) {
|
|
57405
|
-
return formatRawOrLabeledValue(item, "Ctx: ", sliderResult);
|
|
57406
|
-
}
|
|
57407
|
-
return formatRawOrLabeledValue(item, "Ctx: ", `${displayPercentage.toFixed(1)}%`);
|
|
57423
|
+
if (contextPercentageMetrics !== null) {
|
|
57424
|
+
const displayPercentage = isInverse ? 100 - contextPercentageMetrics.usedPercentage : contextPercentageMetrics.usedPercentage;
|
|
57425
|
+
return formatContextPercentage(displayPercentage);
|
|
57408
57426
|
}
|
|
57409
57427
|
return null;
|
|
57410
57428
|
}
|
|
@@ -57422,6 +57440,7 @@ class ContextPercentageWidget {
|
|
|
57422
57440
|
}
|
|
57423
57441
|
}
|
|
57424
57442
|
var init_ContextPercentage = __esm(() => {
|
|
57443
|
+
init_context_percentage();
|
|
57425
57444
|
init_context_inverse();
|
|
57426
57445
|
init_context_slider();
|
|
57427
57446
|
});
|
|
@@ -57458,35 +57477,27 @@ class ContextPercentageUsableWidget {
|
|
|
57458
57477
|
}
|
|
57459
57478
|
render(item, context, settings) {
|
|
57460
57479
|
const isInverse = isContextInverse(item);
|
|
57480
|
+
const label = isInverse ? "Ctx(u) Left: " : "Ctx(u) Used: ";
|
|
57461
57481
|
const sliderMode = getContextSliderMode(item);
|
|
57462
57482
|
const modelIdentifier = getModelContextIdentifier(context.data?.model);
|
|
57463
57483
|
const contextWindowMetrics = getContextWindowMetrics(context.data);
|
|
57464
57484
|
const contextConfig = getContextConfig(modelIdentifier, contextWindowMetrics.windowSize);
|
|
57485
|
+
const formatContextPercentage = (displayPercentage) => {
|
|
57486
|
+
const sliderResult = renderContextSlider(sliderMode, displayPercentage);
|
|
57487
|
+
return formatRawOrLabeledValue(item, label, sliderResult ?? `${displayPercentage.toFixed(1)}%`);
|
|
57488
|
+
};
|
|
57465
57489
|
if (context.isPreview) {
|
|
57466
|
-
|
|
57467
|
-
const sliderResult = renderContextSlider(sliderMode, previewPercent);
|
|
57468
|
-
if (sliderResult !== null) {
|
|
57469
|
-
return formatRawOrLabeledValue(item, "Ctx(u): ", sliderResult);
|
|
57470
|
-
}
|
|
57471
|
-
return formatRawOrLabeledValue(item, "Ctx(u): ", `${previewPercent.toFixed(1)}%`);
|
|
57490
|
+
return formatContextPercentage(isInverse ? 88.4 : 11.6);
|
|
57472
57491
|
}
|
|
57473
57492
|
if (contextWindowMetrics.contextLengthTokens !== null) {
|
|
57474
57493
|
const usedPercentage = Math.min(100, contextWindowMetrics.contextLengthTokens / contextConfig.usableTokens * 100);
|
|
57475
57494
|
const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
|
|
57476
|
-
|
|
57477
|
-
if (sliderResult !== null) {
|
|
57478
|
-
return formatRawOrLabeledValue(item, "Ctx(u): ", sliderResult);
|
|
57479
|
-
}
|
|
57480
|
-
return formatRawOrLabeledValue(item, "Ctx(u): ", `${displayPercentage.toFixed(1)}%`);
|
|
57495
|
+
return formatContextPercentage(displayPercentage);
|
|
57481
57496
|
}
|
|
57482
57497
|
if (context.tokenMetrics) {
|
|
57483
57498
|
const usedPercentage = Math.min(100, context.tokenMetrics.contextLength / contextConfig.usableTokens * 100);
|
|
57484
57499
|
const displayPercentage = isInverse ? 100 - usedPercentage : usedPercentage;
|
|
57485
|
-
|
|
57486
|
-
if (sliderResult !== null) {
|
|
57487
|
-
return formatRawOrLabeledValue(item, "Ctx(u): ", sliderResult);
|
|
57488
|
-
}
|
|
57489
|
-
return formatRawOrLabeledValue(item, "Ctx(u): ", `${displayPercentage.toFixed(1)}%`);
|
|
57500
|
+
return formatContextPercentage(displayPercentage);
|
|
57490
57501
|
}
|
|
57491
57502
|
return null;
|
|
57492
57503
|
}
|
|
@@ -63063,6 +63074,12 @@ function getTranscriptThinkingEffort(transcriptPath) {
|
|
|
63063
63074
|
continue;
|
|
63064
63075
|
}
|
|
63065
63076
|
const visibleContent = getVisibleText(entry.message.content).trim();
|
|
63077
|
+
if (visibleContent.startsWith(EFFORT_STDOUT_PREFIX)) {
|
|
63078
|
+
const effortMatch = EFFORT_STDOUT_REGEX.exec(visibleContent);
|
|
63079
|
+
if (effortMatch) {
|
|
63080
|
+
return normalizeThinkingEffort(effortMatch[1]);
|
|
63081
|
+
}
|
|
63082
|
+
}
|
|
63066
63083
|
if (!visibleContent.startsWith(MODEL_STDOUT_PREFIX)) {
|
|
63067
63084
|
continue;
|
|
63068
63085
|
}
|
|
@@ -63074,13 +63091,14 @@ function getTranscriptThinkingEffort(transcriptPath) {
|
|
|
63074
63091
|
}
|
|
63075
63092
|
return;
|
|
63076
63093
|
}
|
|
63077
|
-
var KNOWN_THINKING_EFFORTS, KNOWN_THINKING_EFFORTS_SET, MODEL_STDOUT_PREFIX = "<local-command-stdout>Set model to ", MODEL_STDOUT_EFFORT_REGEX, UNKNOWN_EFFORT_PATTERN;
|
|
63094
|
+
var KNOWN_THINKING_EFFORTS, KNOWN_THINKING_EFFORTS_SET, MODEL_STDOUT_PREFIX = "<local-command-stdout>Set model to ", MODEL_STDOUT_EFFORT_REGEX, EFFORT_STDOUT_PREFIX = "<local-command-stdout>Set effort level to ", EFFORT_STDOUT_REGEX, UNKNOWN_EFFORT_PATTERN;
|
|
63078
63095
|
var init_jsonl_metadata = __esm(() => {
|
|
63079
63096
|
init_ansi();
|
|
63080
63097
|
init_jsonl_lines();
|
|
63081
63098
|
KNOWN_THINKING_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
63082
63099
|
KNOWN_THINKING_EFFORTS_SET = new Set(KNOWN_THINKING_EFFORTS);
|
|
63083
63100
|
MODEL_STDOUT_EFFORT_REGEX = /^<local-command-stdout>Set model to[\s\S]*? with ([a-zA-Z0-9-]+) effort<\/local-command-stdout>$/i;
|
|
63101
|
+
EFFORT_STDOUT_REGEX = /^<local-command-stdout>Set effort level to ([a-zA-Z0-9-]+)\b/i;
|
|
63084
63102
|
UNKNOWN_EFFORT_PATTERN = /^(?=.*[a-z0-9])[a-z0-9-]{2,20}$/;
|
|
63085
63103
|
});
|
|
63086
63104
|
|
|
@@ -64175,6 +64193,24 @@ class SessionNameWidget {
|
|
|
64175
64193
|
}
|
|
64176
64194
|
var init_SessionName = () => {};
|
|
64177
64195
|
|
|
64196
|
+
// src/widgets/shared/progress-bar.ts
|
|
64197
|
+
function makeTimerProgressBar2(percent, width, options) {
|
|
64198
|
+
const clampedPercent = Math.max(0, Math.min(100, percent));
|
|
64199
|
+
const filledWidth = Math.round(clampedPercent / 100 * width);
|
|
64200
|
+
const cursorPos = options?.cursorPercent !== undefined ? Math.min(Math.floor(Math.max(0, Math.min(100, options.cursorPercent)) / 100 * width), width - 1) : -1;
|
|
64201
|
+
let bar = "";
|
|
64202
|
+
for (let i = 0;i < width; i++) {
|
|
64203
|
+
if (i === cursorPos) {
|
|
64204
|
+
bar += "โ";
|
|
64205
|
+
} else if (i < filledWidth) {
|
|
64206
|
+
bar += "โ";
|
|
64207
|
+
} else {
|
|
64208
|
+
bar += "โ";
|
|
64209
|
+
}
|
|
64210
|
+
}
|
|
64211
|
+
return bar;
|
|
64212
|
+
}
|
|
64213
|
+
|
|
64178
64214
|
// src/widgets/SessionUsage.ts
|
|
64179
64215
|
class SessionUsageWidget {
|
|
64180
64216
|
getDefaultColor() {
|
|
@@ -64202,21 +64238,26 @@ class SessionUsageWidget {
|
|
|
64202
64238
|
if (action === "toggle-invert") {
|
|
64203
64239
|
return toggleUsageInverted(item);
|
|
64204
64240
|
}
|
|
64241
|
+
if (action === "toggle-cursor") {
|
|
64242
|
+
return toggleUsageCursor(item);
|
|
64243
|
+
}
|
|
64205
64244
|
return null;
|
|
64206
64245
|
}
|
|
64207
64246
|
render(item, context, settings) {
|
|
64208
64247
|
const displayMode = getUsageDisplayMode(item);
|
|
64209
64248
|
const inverted = isUsageInverted(item);
|
|
64249
|
+
const showCursor = isUsageCursorEnabled(item);
|
|
64210
64250
|
if (context.isPreview) {
|
|
64211
64251
|
const previewPercent = 20;
|
|
64212
64252
|
const renderedPercent2 = inverted ? 100 - previewPercent : previewPercent;
|
|
64213
64253
|
if (isUsageProgressMode(displayMode)) {
|
|
64214
64254
|
const width = getUsageProgressBarWidth(displayMode);
|
|
64215
|
-
const
|
|
64255
|
+
const progressBar = makeTimerProgressBar2(renderedPercent2, width, showCursor ? { cursorPercent: 50 } : undefined);
|
|
64256
|
+
const progressDisplay = `[${progressBar}] ${renderedPercent2.toFixed(1)}%`;
|
|
64216
64257
|
return formatRawOrLabeledValue(item, "Session: ", progressDisplay);
|
|
64217
64258
|
}
|
|
64218
64259
|
if (isUsageSliderMode(displayMode)) {
|
|
64219
|
-
const slider = makeSliderBar(renderedPercent2);
|
|
64260
|
+
const slider = makeSliderBar(renderedPercent2, undefined, showCursor ? { cursorPercent: 50 } : undefined);
|
|
64220
64261
|
const sliderDisplay = displayMode === "slider" ? `${slider} ${renderedPercent2.toFixed(1)}%` : slider;
|
|
64221
64262
|
return formatRawOrLabeledValue(item, "Session: ", sliderDisplay);
|
|
64222
64263
|
}
|
|
@@ -64229,13 +64270,21 @@ class SessionUsageWidget {
|
|
|
64229
64270
|
return null;
|
|
64230
64271
|
const percent = Math.max(0, Math.min(100, data.sessionUsage));
|
|
64231
64272
|
const renderedPercent = inverted ? 100 - percent : percent;
|
|
64273
|
+
const getCursorOptions = () => {
|
|
64274
|
+
if (!showCursor) {
|
|
64275
|
+
return;
|
|
64276
|
+
}
|
|
64277
|
+
const window2 = resolveUsageWindowWithFallback(data, context.blockMetrics);
|
|
64278
|
+
return window2 ? { cursorPercent: window2.elapsedPercent } : undefined;
|
|
64279
|
+
};
|
|
64232
64280
|
if (isUsageProgressMode(displayMode)) {
|
|
64233
64281
|
const width = getUsageProgressBarWidth(displayMode);
|
|
64234
|
-
const
|
|
64282
|
+
const progressBar = makeTimerProgressBar2(renderedPercent, width, getCursorOptions());
|
|
64283
|
+
const progressDisplay = `[${progressBar}] ${renderedPercent.toFixed(1)}%`;
|
|
64235
64284
|
return formatRawOrLabeledValue(item, "Session: ", progressDisplay);
|
|
64236
64285
|
}
|
|
64237
64286
|
if (isUsageSliderMode(displayMode)) {
|
|
64238
|
-
const slider = makeSliderBar(renderedPercent);
|
|
64287
|
+
const slider = makeSliderBar(renderedPercent, undefined, getCursorOptions());
|
|
64239
64288
|
const sliderDisplay = displayMode === "slider" ? `${slider} ${renderedPercent.toFixed(1)}%` : slider;
|
|
64240
64289
|
return formatRawOrLabeledValue(item, "Session: ", sliderDisplay);
|
|
64241
64290
|
}
|
|
@@ -64283,21 +64332,26 @@ class WeeklyUsageWidget {
|
|
|
64283
64332
|
if (action === "toggle-invert") {
|
|
64284
64333
|
return toggleUsageInverted(item);
|
|
64285
64334
|
}
|
|
64335
|
+
if (action === "toggle-cursor") {
|
|
64336
|
+
return toggleUsageCursor(item);
|
|
64337
|
+
}
|
|
64286
64338
|
return null;
|
|
64287
64339
|
}
|
|
64288
64340
|
render(item, context, settings) {
|
|
64289
64341
|
const displayMode = getUsageDisplayMode(item);
|
|
64290
64342
|
const inverted = isUsageInverted(item);
|
|
64343
|
+
const showCursor = isUsageCursorEnabled(item);
|
|
64291
64344
|
if (context.isPreview) {
|
|
64292
64345
|
const previewPercent = 12;
|
|
64293
64346
|
const renderedPercent2 = inverted ? 100 - previewPercent : previewPercent;
|
|
64294
64347
|
if (isUsageProgressMode(displayMode)) {
|
|
64295
64348
|
const width = getUsageProgressBarWidth(displayMode);
|
|
64296
|
-
const
|
|
64349
|
+
const progressBar = makeTimerProgressBar2(renderedPercent2, width, showCursor ? { cursorPercent: 50 } : undefined);
|
|
64350
|
+
const progressDisplay = `[${progressBar}] ${renderedPercent2.toFixed(1)}%`;
|
|
64297
64351
|
return formatRawOrLabeledValue(item, "Weekly: ", progressDisplay);
|
|
64298
64352
|
}
|
|
64299
64353
|
if (isUsageSliderMode(displayMode)) {
|
|
64300
|
-
const slider = makeSliderBar(renderedPercent2);
|
|
64354
|
+
const slider = makeSliderBar(renderedPercent2, undefined, showCursor ? { cursorPercent: 50 } : undefined);
|
|
64301
64355
|
const sliderDisplay = displayMode === "slider" ? `${slider} ${renderedPercent2.toFixed(1)}%` : slider;
|
|
64302
64356
|
return formatRawOrLabeledValue(item, "Weekly: ", sliderDisplay);
|
|
64303
64357
|
}
|
|
@@ -64310,13 +64364,21 @@ class WeeklyUsageWidget {
|
|
|
64310
64364
|
return null;
|
|
64311
64365
|
const percent = Math.max(0, Math.min(100, data.weeklyUsage));
|
|
64312
64366
|
const renderedPercent = inverted ? 100 - percent : percent;
|
|
64367
|
+
const getCursorOptions = () => {
|
|
64368
|
+
if (!showCursor) {
|
|
64369
|
+
return;
|
|
64370
|
+
}
|
|
64371
|
+
const window2 = resolveWeeklyUsageWindow(data);
|
|
64372
|
+
return window2 ? { cursorPercent: window2.elapsedPercent } : undefined;
|
|
64373
|
+
};
|
|
64313
64374
|
if (isUsageProgressMode(displayMode)) {
|
|
64314
64375
|
const width = getUsageProgressBarWidth(displayMode);
|
|
64315
|
-
const
|
|
64376
|
+
const progressBar = makeTimerProgressBar2(renderedPercent, width, getCursorOptions());
|
|
64377
|
+
const progressDisplay = `[${progressBar}] ${renderedPercent.toFixed(1)}%`;
|
|
64316
64378
|
return formatRawOrLabeledValue(item, "Weekly: ", progressDisplay);
|
|
64317
64379
|
}
|
|
64318
64380
|
if (isUsageSliderMode(displayMode)) {
|
|
64319
|
-
const slider = makeSliderBar(renderedPercent);
|
|
64381
|
+
const slider = makeSliderBar(renderedPercent, undefined, getCursorOptions());
|
|
64320
64382
|
const sliderDisplay = displayMode === "slider" ? `${slider} ${renderedPercent.toFixed(1)}%` : slider;
|
|
64321
64383
|
return formatRawOrLabeledValue(item, "Weekly: ", sliderDisplay);
|
|
64322
64384
|
}
|
|
@@ -64789,7 +64851,7 @@ var init_timezone_editor = __esm(async () => {
|
|
|
64789
64851
|
});
|
|
64790
64852
|
|
|
64791
64853
|
// src/widgets/BlockResetTimer.ts
|
|
64792
|
-
function
|
|
64854
|
+
function makeTimerProgressBar3(percent, width) {
|
|
64793
64855
|
const clampedPercent = Math.max(0, Math.min(100, percent));
|
|
64794
64856
|
const filledWidth = Math.floor(clampedPercent / 100 * width);
|
|
64795
64857
|
const emptyWidth = width - filledWidth;
|
|
@@ -64842,7 +64904,7 @@ class BlockResetTimerWidget {
|
|
|
64842
64904
|
const previewPercent = inverted ? 90 : 10;
|
|
64843
64905
|
if (isUsageProgressMode(displayMode)) {
|
|
64844
64906
|
const barWidth = getUsageProgressBarWidth(displayMode);
|
|
64845
|
-
const progressBar =
|
|
64907
|
+
const progressBar = makeTimerProgressBar3(previewPercent, barWidth);
|
|
64846
64908
|
return formatRawOrLabeledValue(item, "Reset ", `[${progressBar}] ${previewPercent.toFixed(1)}%`);
|
|
64847
64909
|
}
|
|
64848
64910
|
if (dateMode) {
|
|
@@ -64862,7 +64924,7 @@ class BlockResetTimerWidget {
|
|
|
64862
64924
|
if (isUsageProgressMode(displayMode)) {
|
|
64863
64925
|
const barWidth = getUsageProgressBarWidth(displayMode);
|
|
64864
64926
|
const percent = inverted ? window2.remainingPercent : window2.elapsedPercent;
|
|
64865
|
-
const progressBar =
|
|
64927
|
+
const progressBar = makeTimerProgressBar3(percent, barWidth);
|
|
64866
64928
|
const percentage = percent.toFixed(1);
|
|
64867
64929
|
return formatRawOrLabeledValue(item, "Reset ", `[${progressBar}] ${percentage}%`);
|
|
64868
64930
|
}
|
|
@@ -64912,7 +64974,7 @@ var init_BlockResetTimer = __esm(async () => {
|
|
|
64912
64974
|
});
|
|
64913
64975
|
|
|
64914
64976
|
// src/widgets/WeeklyResetTimer.ts
|
|
64915
|
-
function
|
|
64977
|
+
function makeTimerProgressBar4(percent, width) {
|
|
64916
64978
|
const clampedPercent = Math.max(0, Math.min(100, percent));
|
|
64917
64979
|
const filledWidth = Math.floor(clampedPercent / 100 * width);
|
|
64918
64980
|
const emptyWidth = width - filledWidth;
|
|
@@ -65010,7 +65072,7 @@ class WeeklyResetTimerWidget {
|
|
|
65010
65072
|
const previewPercent = inverted ? 90 : 10;
|
|
65011
65073
|
if (isUsageProgressMode(displayMode)) {
|
|
65012
65074
|
const barWidth = getUsageProgressBarWidth(displayMode);
|
|
65013
|
-
const progressBar =
|
|
65075
|
+
const progressBar = makeTimerProgressBar4(previewPercent, barWidth);
|
|
65014
65076
|
return formatRawOrLabeledValue(item, "Weekly Reset ", `[${progressBar}] ${previewPercent.toFixed(1)}%`);
|
|
65015
65077
|
}
|
|
65016
65078
|
if (dateMode) {
|
|
@@ -65030,7 +65092,7 @@ class WeeklyResetTimerWidget {
|
|
|
65030
65092
|
if (isUsageProgressMode(displayMode)) {
|
|
65031
65093
|
const barWidth = getUsageProgressBarWidth(displayMode);
|
|
65032
65094
|
const percent = inverted ? window2.remainingPercent : window2.elapsedPercent;
|
|
65033
|
-
const progressBar =
|
|
65095
|
+
const progressBar = makeTimerProgressBar4(percent, barWidth);
|
|
65034
65096
|
const percentage = percent.toFixed(1);
|
|
65035
65097
|
return formatRawOrLabeledValue(item, "Weekly Reset ", `[${progressBar}] ${percentage}%`);
|
|
65036
65098
|
}
|
|
@@ -65587,6 +65649,13 @@ var init_Skills = __esm(async () => {
|
|
|
65587
65649
|
});
|
|
65588
65650
|
|
|
65589
65651
|
// src/widgets/ThinkingEffort.ts
|
|
65652
|
+
function resolveThinkingEffortFromStatusJson(context) {
|
|
65653
|
+
const effort = context.data?.effort;
|
|
65654
|
+
if (!effort || !("level" in effort)) {
|
|
65655
|
+
return;
|
|
65656
|
+
}
|
|
65657
|
+
return typeof effort.level === "string" ? normalizeThinkingEffort(effort.level) : null;
|
|
65658
|
+
}
|
|
65590
65659
|
function resolveThinkingEffortFromSettings() {
|
|
65591
65660
|
try {
|
|
65592
65661
|
const settings = loadClaudeSettingsSync({ logErrors: false });
|
|
@@ -65595,6 +65664,10 @@ function resolveThinkingEffortFromSettings() {
|
|
|
65595
65664
|
return;
|
|
65596
65665
|
}
|
|
65597
65666
|
function resolveThinkingEffort(context) {
|
|
65667
|
+
const statusEffort = resolveThinkingEffortFromStatusJson(context);
|
|
65668
|
+
if (statusEffort !== undefined) {
|
|
65669
|
+
return statusEffort;
|
|
65670
|
+
}
|
|
65598
65671
|
return getTranscriptThinkingEffort(context.data?.transcript_path) ?? resolveThinkingEffortFromSettings() ?? null;
|
|
65599
65672
|
}
|
|
65600
65673
|
function formatEffort(resolved) {
|
|
@@ -65893,6 +65966,149 @@ class GitWorktreeOriginalBranchWidget {
|
|
|
65893
65966
|
}
|
|
65894
65967
|
}
|
|
65895
65968
|
|
|
65969
|
+
// src/widgets/CompactionCounter.ts
|
|
65970
|
+
function getFormat2(item) {
|
|
65971
|
+
const format = item.metadata?.format;
|
|
65972
|
+
return FORMATS2.includes(format ?? "") ? format : DEFAULT_FORMAT2;
|
|
65973
|
+
}
|
|
65974
|
+
function removeNerdFont(item) {
|
|
65975
|
+
const { [NERD_FONT_METADATA_KEY2]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
|
|
65976
|
+
return {
|
|
65977
|
+
...item,
|
|
65978
|
+
metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
|
|
65979
|
+
};
|
|
65980
|
+
}
|
|
65981
|
+
function setFormat2(item, format) {
|
|
65982
|
+
if (format === DEFAULT_FORMAT2) {
|
|
65983
|
+
const { format: removedFormat, ...restMetadata2 } = item.metadata ?? {};
|
|
65984
|
+
return {
|
|
65985
|
+
...item,
|
|
65986
|
+
metadata: Object.keys(restMetadata2).length > 0 ? restMetadata2 : undefined
|
|
65987
|
+
};
|
|
65988
|
+
}
|
|
65989
|
+
const { [NERD_FONT_METADATA_KEY2]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
|
|
65990
|
+
return {
|
|
65991
|
+
...item,
|
|
65992
|
+
metadata: {
|
|
65993
|
+
...restMetadata,
|
|
65994
|
+
format
|
|
65995
|
+
}
|
|
65996
|
+
};
|
|
65997
|
+
}
|
|
65998
|
+
function isNerdFontEnabled2(item) {
|
|
65999
|
+
return item.metadata?.[NERD_FONT_METADATA_KEY2] === "true" && getFormat2(item) === DEFAULT_FORMAT2;
|
|
66000
|
+
}
|
|
66001
|
+
function isHideZeroEnabled(item) {
|
|
66002
|
+
return item.metadata?.[HIDE_ZERO_METADATA_KEY] === "true";
|
|
66003
|
+
}
|
|
66004
|
+
function toggleHideZero(item) {
|
|
66005
|
+
return {
|
|
66006
|
+
...item,
|
|
66007
|
+
metadata: {
|
|
66008
|
+
...item.metadata ?? {},
|
|
66009
|
+
[HIDE_ZERO_METADATA_KEY]: (!isHideZeroEnabled(item)).toString()
|
|
66010
|
+
}
|
|
66011
|
+
};
|
|
66012
|
+
}
|
|
66013
|
+
function toggleNerdFont2(item) {
|
|
66014
|
+
if (getFormat2(item) !== DEFAULT_FORMAT2) {
|
|
66015
|
+
return removeNerdFont(item);
|
|
66016
|
+
}
|
|
66017
|
+
if (!isNerdFontEnabled2(item)) {
|
|
66018
|
+
return {
|
|
66019
|
+
...item,
|
|
66020
|
+
metadata: {
|
|
66021
|
+
...item.metadata ?? {},
|
|
66022
|
+
[NERD_FONT_METADATA_KEY2]: "true"
|
|
66023
|
+
}
|
|
66024
|
+
};
|
|
66025
|
+
}
|
|
66026
|
+
return removeNerdFont(item);
|
|
66027
|
+
}
|
|
66028
|
+
function formatCount(count, format, icon) {
|
|
66029
|
+
switch (format) {
|
|
66030
|
+
case "icon-space-number":
|
|
66031
|
+
return `${icon} ${count}`;
|
|
66032
|
+
case "text-and-number":
|
|
66033
|
+
return `Compactions: ${count}`;
|
|
66034
|
+
case "number":
|
|
66035
|
+
return String(count);
|
|
66036
|
+
}
|
|
66037
|
+
}
|
|
66038
|
+
|
|
66039
|
+
class CompactionCounterWidget {
|
|
66040
|
+
getDefaultColor() {
|
|
66041
|
+
return "yellow";
|
|
66042
|
+
}
|
|
66043
|
+
getDescription() {
|
|
66044
|
+
return "Count of context compaction events in the current session.";
|
|
66045
|
+
}
|
|
66046
|
+
getDisplayName() {
|
|
66047
|
+
return "Compaction Counter";
|
|
66048
|
+
}
|
|
66049
|
+
getCategory() {
|
|
66050
|
+
return "Context";
|
|
66051
|
+
}
|
|
66052
|
+
getEditorDisplay(item) {
|
|
66053
|
+
const modifiers = [getFormat2(item)];
|
|
66054
|
+
if (isNerdFontEnabled2(item)) {
|
|
66055
|
+
modifiers.push("nerd font");
|
|
66056
|
+
}
|
|
66057
|
+
if (isHideZeroEnabled(item)) {
|
|
66058
|
+
modifiers.push("hide zero");
|
|
66059
|
+
}
|
|
66060
|
+
return {
|
|
66061
|
+
displayText: "Compaction Counter",
|
|
66062
|
+
modifierText: `(${modifiers.join(", ")})`
|
|
66063
|
+
};
|
|
66064
|
+
}
|
|
66065
|
+
handleEditorAction(action, item) {
|
|
66066
|
+
if (action === CYCLE_FORMAT_ACTION2) {
|
|
66067
|
+
const currentFormat = getFormat2(item);
|
|
66068
|
+
const nextFormat = FORMATS2[(FORMATS2.indexOf(currentFormat) + 1) % FORMATS2.length] ?? DEFAULT_FORMAT2;
|
|
66069
|
+
return setFormat2(item, nextFormat);
|
|
66070
|
+
}
|
|
66071
|
+
if (action === TOGGLE_HIDE_ZERO_ACTION) {
|
|
66072
|
+
return toggleHideZero(item);
|
|
66073
|
+
}
|
|
66074
|
+
if (action === TOGGLE_NERD_FONT_ACTION2) {
|
|
66075
|
+
return toggleNerdFont2(item);
|
|
66076
|
+
}
|
|
66077
|
+
return null;
|
|
66078
|
+
}
|
|
66079
|
+
render(item, context, settings) {
|
|
66080
|
+
const format = getFormat2(item);
|
|
66081
|
+
const icon = isNerdFontEnabled2(item) ? COMPACTION_NERD_FONT_ICON : COMPACTION_ICON;
|
|
66082
|
+
if (context.isPreview) {
|
|
66083
|
+
return formatCount(2, format, icon);
|
|
66084
|
+
}
|
|
66085
|
+
const count = context.compactionData?.count ?? 0;
|
|
66086
|
+
if (count === 0 && isHideZeroEnabled(item))
|
|
66087
|
+
return null;
|
|
66088
|
+
return formatCount(count, format, icon);
|
|
66089
|
+
}
|
|
66090
|
+
getCustomKeybinds(item) {
|
|
66091
|
+
const keybinds = [
|
|
66092
|
+
{ key: "f", label: "(f)ormat", action: CYCLE_FORMAT_ACTION2 }
|
|
66093
|
+
];
|
|
66094
|
+
if (item === undefined || getFormat2(item) === DEFAULT_FORMAT2) {
|
|
66095
|
+
keybinds.push({ key: "n", label: "(n)erd font", action: TOGGLE_NERD_FONT_ACTION2 });
|
|
66096
|
+
}
|
|
66097
|
+
keybinds.push({ key: "h", label: "(h)ide when zero", action: TOGGLE_HIDE_ZERO_ACTION });
|
|
66098
|
+
return keybinds;
|
|
66099
|
+
}
|
|
66100
|
+
supportsRawValue() {
|
|
66101
|
+
return false;
|
|
66102
|
+
}
|
|
66103
|
+
supportsColors(item) {
|
|
66104
|
+
return true;
|
|
66105
|
+
}
|
|
66106
|
+
}
|
|
66107
|
+
var COMPACTION_ICON = "โป", COMPACTION_NERD_FONT_ICON = "๏ก", FORMATS2, DEFAULT_FORMAT2 = "icon-space-number", CYCLE_FORMAT_ACTION2 = "cycle-format", TOGGLE_HIDE_ZERO_ACTION = "toggle-hide-zero", TOGGLE_NERD_FONT_ACTION2 = "toggle-nerd-font", HIDE_ZERO_METADATA_KEY = "hideZero", NERD_FONT_METADATA_KEY2 = "nerdFont";
|
|
66108
|
+
var init_CompactionCounter = __esm(() => {
|
|
66109
|
+
FORMATS2 = ["icon-space-number", "text-and-number", "number"];
|
|
66110
|
+
});
|
|
66111
|
+
|
|
65896
66112
|
// src/widgets/index.ts
|
|
65897
66113
|
var init_widgets = __esm(async () => {
|
|
65898
66114
|
init_GitBranch();
|
|
@@ -65926,6 +66142,7 @@ var init_widgets = __esm(async () => {
|
|
|
65926
66142
|
init_FreeMemory();
|
|
65927
66143
|
init_SessionName();
|
|
65928
66144
|
init_VimMode();
|
|
66145
|
+
init_CompactionCounter();
|
|
65929
66146
|
await __promiseAll([
|
|
65930
66147
|
init_TokensInput(),
|
|
65931
66148
|
init_TokensOutput(),
|
|
@@ -66021,7 +66238,8 @@ var init_widget_manifest = __esm(async () => {
|
|
|
66021
66238
|
{ type: "worktree-mode", create: () => new GitWorktreeModeWidget },
|
|
66022
66239
|
{ type: "worktree-name", create: () => new GitWorktreeNameWidget },
|
|
66023
66240
|
{ type: "worktree-branch", create: () => new GitWorktreeBranchWidget },
|
|
66024
|
-
{ type: "worktree-original-branch", create: () => new GitWorktreeOriginalBranchWidget }
|
|
66241
|
+
{ type: "worktree-original-branch", create: () => new GitWorktreeOriginalBranchWidget },
|
|
66242
|
+
{ type: "compaction-counter", create: () => new CompactionCounterWidget }
|
|
66025
66243
|
];
|
|
66026
66244
|
LAYOUT_WIDGET_MANIFEST = [
|
|
66027
66245
|
{
|
|
@@ -70693,7 +70911,7 @@ var PowerlineSeparatorEditor = ({
|
|
|
70693
70911
|
newInvertBgs[selectedIndex] = isLeftFacing;
|
|
70694
70912
|
}
|
|
70695
70913
|
updateSeparators(newSeparators, mode === "separator" ? newInvertBgs : undefined);
|
|
70696
|
-
} else if (
|
|
70914
|
+
} else if (input === "a" || input === "A") {
|
|
70697
70915
|
const newSeparators = [...separators];
|
|
70698
70916
|
const newInvertBgs = mode === "separator" ? [...invertBgs] : [];
|
|
70699
70917
|
const defaultChar = presetSeparators[0]?.char ?? "๎ฐ";
|
|
@@ -70713,7 +70931,7 @@ var PowerlineSeparatorEditor = ({
|
|
|
70713
70931
|
updateSeparators(newSeparators, newInvertBgs);
|
|
70714
70932
|
setSelectedIndex(selectedIndex + 1);
|
|
70715
70933
|
}
|
|
70716
|
-
} else if (
|
|
70934
|
+
} else if (input === "i" || input === "I") {
|
|
70717
70935
|
const newSeparators = [...separators];
|
|
70718
70936
|
const newInvertBgs = mode === "separator" ? [...invertBgs] : [];
|
|
70719
70937
|
const defaultChar = presetSeparators[0]?.char ?? "๎ฐ";
|
|
@@ -70765,7 +70983,6 @@ var PowerlineSeparatorEditor = ({
|
|
|
70765
70983
|
return "Powerline End Cap Configuration";
|
|
70766
70984
|
}
|
|
70767
70985
|
};
|
|
70768
|
-
const canAdd = mode === "separator" || separators.length < 3;
|
|
70769
70986
|
const canDelete = mode !== "separator" || separators.length > 1;
|
|
70770
70987
|
return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
|
|
70771
70988
|
flexDirection: "column",
|
|
@@ -70817,7 +71034,7 @@ var PowerlineSeparatorEditor = ({
|
|
|
70817
71034
|
/* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
|
|
70818
71035
|
children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
|
|
70819
71036
|
dimColor: true,
|
|
70820
|
-
children: `โโ select, โ โ cycle
|
|
71037
|
+
children: `โโ select, โ โ cycle, (a)dd, (i)nsert${canDelete ? ", (d)elete" : ""}, (c)lear, (h)ex${mode === "separator" ? ", (t)oggle invert" : ""}, ESC back`
|
|
70821
71038
|
}, undefined, false, undefined, this)
|
|
70822
71039
|
}, undefined, false, undefined, this),
|
|
70823
71040
|
/* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
|
|
@@ -72668,6 +72885,7 @@ var StatusJSONSchema = exports_external.looseObject({
|
|
|
72668
72885
|
}).optional(),
|
|
72669
72886
|
version: exports_external.string().optional(),
|
|
72670
72887
|
output_style: exports_external.object({ name: exports_external.string().optional() }).optional(),
|
|
72888
|
+
effort: exports_external.object({ level: exports_external.string().nullable().optional() }).nullable().optional(),
|
|
72671
72889
|
cost: exports_external.object({
|
|
72672
72890
|
total_cost_usd: CoercedNumberSchema.optional(),
|
|
72673
72891
|
total_duration_ms: CoercedNumberSchema.optional(),
|
|
@@ -72708,6 +72926,115 @@ var StatusJSONSchema = exports_external.looseObject({
|
|
|
72708
72926
|
// src/ccstatusline.ts
|
|
72709
72927
|
init_ansi();
|
|
72710
72928
|
init_colors();
|
|
72929
|
+
|
|
72930
|
+
// src/utils/compaction.ts
|
|
72931
|
+
init_zod();
|
|
72932
|
+
import * as crypto from "crypto";
|
|
72933
|
+
import * as fs13 from "fs";
|
|
72934
|
+
import * as os13 from "os";
|
|
72935
|
+
import * as path10 from "path";
|
|
72936
|
+
var DEFAULT_DROP_THRESHOLD = 2;
|
|
72937
|
+
var FRESH_PREV_CTX_PCT = -1;
|
|
72938
|
+
var MAX_CACHE_FILE_BYTES = 4096;
|
|
72939
|
+
var SESSION_ID_HASH_HEX_LEN = 32;
|
|
72940
|
+
var FRESH = { count: 0, prevCtxPct: FRESH_PREV_CTX_PCT };
|
|
72941
|
+
var CompactionStateSchema = exports_external.object({
|
|
72942
|
+
count: exports_external.number().int().nonnegative().default(0),
|
|
72943
|
+
prevCtxPct: exports_external.number().default(FRESH_PREV_CTX_PCT),
|
|
72944
|
+
prevWindowSize: exports_external.number().positive().nullable().optional()
|
|
72945
|
+
});
|
|
72946
|
+
function normalizeWindowSize(value) {
|
|
72947
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
72948
|
+
return null;
|
|
72949
|
+
}
|
|
72950
|
+
return value;
|
|
72951
|
+
}
|
|
72952
|
+
function normalizeOptions(options) {
|
|
72953
|
+
if (typeof options === "number") {
|
|
72954
|
+
return { dropThreshold: options, windowSize: null };
|
|
72955
|
+
}
|
|
72956
|
+
const dropThreshold = typeof options.dropThreshold === "number" && Number.isFinite(options.dropThreshold) ? options.dropThreshold : DEFAULT_DROP_THRESHOLD;
|
|
72957
|
+
return { dropThreshold, windowSize: options.windowSize ?? null };
|
|
72958
|
+
}
|
|
72959
|
+
function detectCompaction(currentCtxPct, state, options = DEFAULT_DROP_THRESHOLD) {
|
|
72960
|
+
if (!Number.isFinite(currentCtxPct) || currentCtxPct < 0) {
|
|
72961
|
+
return state;
|
|
72962
|
+
}
|
|
72963
|
+
const { dropThreshold, windowSize } = normalizeOptions(options);
|
|
72964
|
+
const currentWindowSize = normalizeWindowSize(windowSize);
|
|
72965
|
+
const prevWindowSize = normalizeWindowSize(state.prevWindowSize);
|
|
72966
|
+
let { count } = state;
|
|
72967
|
+
const { prevCtxPct } = state;
|
|
72968
|
+
const hasKnownWindowChange = currentWindowSize !== null && prevWindowSize !== null && currentWindowSize !== prevWindowSize;
|
|
72969
|
+
const isLearningWindowSize = currentWindowSize !== null && prevWindowSize === null && prevCtxPct >= 0;
|
|
72970
|
+
if (!hasKnownWindowChange && !isLearningWindowSize && prevCtxPct >= 0 && currentCtxPct < prevCtxPct - dropThreshold) {
|
|
72971
|
+
count += 1;
|
|
72972
|
+
}
|
|
72973
|
+
return {
|
|
72974
|
+
count,
|
|
72975
|
+
prevCtxPct: currentCtxPct,
|
|
72976
|
+
...currentWindowSize !== null ? { prevWindowSize: currentWindowSize } : {}
|
|
72977
|
+
};
|
|
72978
|
+
}
|
|
72979
|
+
function getCacheDir2() {
|
|
72980
|
+
return path10.join(os13.homedir(), ".cache", "ccstatusline", "compaction");
|
|
72981
|
+
}
|
|
72982
|
+
function sanitizeSessionId(sessionId) {
|
|
72983
|
+
const sanitized = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
72984
|
+
if (!sanitized || sanitized !== sessionId) {
|
|
72985
|
+
return crypto.createHash("sha256").update(sessionId).digest("hex").slice(0, SESSION_ID_HASH_HEX_LEN);
|
|
72986
|
+
}
|
|
72987
|
+
return sanitized;
|
|
72988
|
+
}
|
|
72989
|
+
function getStatePath(sessionId) {
|
|
72990
|
+
return path10.join(getCacheDir2(), `compaction-${sanitizeSessionId(sessionId)}.json`);
|
|
72991
|
+
}
|
|
72992
|
+
function loadCompactionState(sessionId) {
|
|
72993
|
+
const statePath = getStatePath(sessionId);
|
|
72994
|
+
let fd = null;
|
|
72995
|
+
try {
|
|
72996
|
+
fd = fs13.openSync(statePath, fs13.constants.O_RDONLY | fs13.constants.O_NOFOLLOW);
|
|
72997
|
+
const stats = fs13.fstatSync(fd);
|
|
72998
|
+
if (!stats.isFile() || stats.size > MAX_CACHE_FILE_BYTES) {
|
|
72999
|
+
return FRESH;
|
|
73000
|
+
}
|
|
73001
|
+
const raw = JSON.parse(fs13.readFileSync(fd, "utf-8"));
|
|
73002
|
+
const result2 = CompactionStateSchema.safeParse(raw);
|
|
73003
|
+
return result2.success ? result2.data : FRESH;
|
|
73004
|
+
} catch {
|
|
73005
|
+
return FRESH;
|
|
73006
|
+
} finally {
|
|
73007
|
+
if (fd !== null) {
|
|
73008
|
+
try {
|
|
73009
|
+
fs13.closeSync(fd);
|
|
73010
|
+
} catch {}
|
|
73011
|
+
}
|
|
73012
|
+
}
|
|
73013
|
+
}
|
|
73014
|
+
function saveCompactionState(sessionId, state) {
|
|
73015
|
+
let tmpPath = null;
|
|
73016
|
+
try {
|
|
73017
|
+
const dir = getCacheDir2();
|
|
73018
|
+
if (!fs13.existsSync(dir)) {
|
|
73019
|
+
fs13.mkdirSync(dir, { recursive: true });
|
|
73020
|
+
}
|
|
73021
|
+
const targetPath = getStatePath(sessionId);
|
|
73022
|
+
tmpPath = `${targetPath}.tmp.${process.pid}.${crypto.randomBytes(4).toString("hex")}`;
|
|
73023
|
+
fs13.writeFileSync(tmpPath, JSON.stringify(state) + `
|
|
73024
|
+
`);
|
|
73025
|
+
fs13.renameSync(tmpPath, targetPath);
|
|
73026
|
+
tmpPath = null;
|
|
73027
|
+
} catch {
|
|
73028
|
+
if (tmpPath !== null) {
|
|
73029
|
+
try {
|
|
73030
|
+
fs13.unlinkSync(tmpPath);
|
|
73031
|
+
} catch {}
|
|
73032
|
+
}
|
|
73033
|
+
}
|
|
73034
|
+
}
|
|
73035
|
+
|
|
73036
|
+
// src/ccstatusline.ts
|
|
73037
|
+
init_context_percentage();
|
|
72711
73038
|
await __promiseAll([
|
|
72712
73039
|
init_config(),
|
|
72713
73040
|
init_jsonl()
|
|
@@ -72715,23 +73042,23 @@ await __promiseAll([
|
|
|
72715
73042
|
await init_renderer2();
|
|
72716
73043
|
|
|
72717
73044
|
// src/utils/skills.ts
|
|
72718
|
-
import * as
|
|
72719
|
-
import * as
|
|
72720
|
-
import * as
|
|
73045
|
+
import * as fs14 from "fs";
|
|
73046
|
+
import * as os14 from "os";
|
|
73047
|
+
import * as path11 from "path";
|
|
72721
73048
|
var EMPTY = { totalInvocations: 0, uniqueSkills: [], lastSkill: null };
|
|
72722
73049
|
function getSkillsDir() {
|
|
72723
|
-
return
|
|
73050
|
+
return path11.join(os14.homedir(), ".cache", "ccstatusline", "skills");
|
|
72724
73051
|
}
|
|
72725
73052
|
function getSkillsFilePath(sessionId) {
|
|
72726
|
-
return
|
|
73053
|
+
return path11.join(getSkillsDir(), `skills-${sessionId}.jsonl`);
|
|
72727
73054
|
}
|
|
72728
73055
|
function getSkillsMetrics(sessionId) {
|
|
72729
73056
|
const filePath = getSkillsFilePath(sessionId);
|
|
72730
|
-
if (!
|
|
73057
|
+
if (!fs14.existsSync(filePath)) {
|
|
72731
73058
|
return EMPTY;
|
|
72732
73059
|
}
|
|
72733
73060
|
try {
|
|
72734
|
-
const invocations =
|
|
73061
|
+
const invocations = fs14.readFileSync(filePath, "utf-8").trim().split(`
|
|
72735
73062
|
`).filter((line) => line.trim()).map((line) => {
|
|
72736
73063
|
try {
|
|
72737
73064
|
return JSON.parse(line);
|
|
@@ -72880,6 +73207,20 @@ async function renderMultipleLines(data) {
|
|
|
72880
73207
|
if (data.session_id) {
|
|
72881
73208
|
skillsMetrics = getSkillsMetrics(data.session_id);
|
|
72882
73209
|
}
|
|
73210
|
+
let compactionCount = 0;
|
|
73211
|
+
const hasCompactionWidget = lines.some((line) => line.some((item) => item.type === "compaction-counter"));
|
|
73212
|
+
if (hasCompactionWidget && data.session_id) {
|
|
73213
|
+
const prevState = loadCompactionState(data.session_id);
|
|
73214
|
+
compactionCount = prevState.count;
|
|
73215
|
+
const contextPercentageMetrics = calculateContextPercentageMetrics({ data, tokenMetrics });
|
|
73216
|
+
if (contextPercentageMetrics !== null) {
|
|
73217
|
+
const newState = detectCompaction(contextPercentageMetrics.usedPercentage, prevState, { windowSize: contextPercentageMetrics.windowSize });
|
|
73218
|
+
if (newState.count !== prevState.count || newState.prevCtxPct !== prevState.prevCtxPct || newState.prevWindowSize !== prevState.prevWindowSize) {
|
|
73219
|
+
saveCompactionState(data.session_id, newState);
|
|
73220
|
+
}
|
|
73221
|
+
compactionCount = newState.count;
|
|
73222
|
+
}
|
|
73223
|
+
}
|
|
72883
73224
|
const context = {
|
|
72884
73225
|
data,
|
|
72885
73226
|
tokenMetrics,
|
|
@@ -72888,6 +73229,7 @@ async function renderMultipleLines(data) {
|
|
|
72888
73229
|
usageData,
|
|
72889
73230
|
sessionDuration,
|
|
72890
73231
|
skillsMetrics,
|
|
73232
|
+
compactionData: hasCompactionWidget ? { count: compactionCount } : null,
|
|
72891
73233
|
isPreview: false,
|
|
72892
73234
|
minimalist: settings.minimalistMode
|
|
72893
73235
|
};
|
|
@@ -72974,16 +73316,16 @@ async function handleHook() {
|
|
|
72974
73316
|
return;
|
|
72975
73317
|
}
|
|
72976
73318
|
const filePath = getSkillsFilePath(sessionId);
|
|
72977
|
-
const
|
|
72978
|
-
const
|
|
72979
|
-
|
|
73319
|
+
const fs15 = await import("fs");
|
|
73320
|
+
const path12 = await import("path");
|
|
73321
|
+
fs15.mkdirSync(path12.dirname(filePath), { recursive: true });
|
|
72980
73322
|
const entry = JSON.stringify({
|
|
72981
73323
|
timestamp: new Date().toISOString(),
|
|
72982
73324
|
session_id: sessionId,
|
|
72983
73325
|
skill: skillName,
|
|
72984
73326
|
source: data.hook_event_name
|
|
72985
73327
|
});
|
|
72986
|
-
|
|
73328
|
+
fs15.appendFileSync(filePath, entry + `
|
|
72987
73329
|
`);
|
|
72988
73330
|
} catch {}
|
|
72989
73331
|
console.log("{}");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccstatusline",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.12",
|
|
4
4
|
"description": "A customizable status line formatter for Claude Code CLI",
|
|
5
5
|
"module": "src/ccstatusline.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"strip-ansi": "^7.1.0",
|
|
46
46
|
"tinyglobby": "^0.2.14",
|
|
47
47
|
"typedoc": "^0.28.12",
|
|
48
|
-
"typescript": "^
|
|
48
|
+
"typescript": "^6.0.2",
|
|
49
49
|
"typescript-eslint": "^8.39.1",
|
|
50
50
|
"vitest": "^4.0.18",
|
|
51
51
|
"zod": "^4.0.17"
|