lumira 1.12.2 → 1.13.0
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -2
- package/dist/config.js +2 -0
- package/dist/normalize.js +23 -2
- package/dist/render/icons.js +3 -0
- package/dist/render/line1.js +10 -0
- package/dist/render/powerline-line1.js +13 -0
- package/dist/tui/preview.js +2 -2
- package/dist/types.js +10 -3
- package/package.json +1 -1
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
},
|
|
6
6
|
"metadata": {
|
|
7
7
|
"description": "Real-time statusline HUD for Claude Code and Qwen Code — analytics, quota projection, themes, powerline",
|
|
8
|
-
"version": "1.
|
|
8
|
+
"version": "1.13.0"
|
|
9
9
|
},
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "lumira",
|
|
13
13
|
"source": "./",
|
|
14
14
|
"description": "Real-time statusline HUD for Claude Code and Qwen Code. Session analytics, API latency widget, 7-day quota projection, auto-compact warnings, 7 themes, powerline support. Zero runtime dependencies. Run /lumira:setup after install to activate.",
|
|
15
|
-
"version": "1.
|
|
15
|
+
"version": "1.13.0",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Carlos Cativo"
|
|
18
18
|
},
|
|
@@ -32,5 +32,5 @@
|
|
|
32
32
|
]
|
|
33
33
|
}
|
|
34
34
|
],
|
|
35
|
-
"version": "1.
|
|
35
|
+
"version": "1.13.0"
|
|
36
36
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lumira",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Real-time statusline HUD for Claude Code and Qwen Code — session analytics, API latency, 7-day quota projection, auto-compact warnings, 7 themes, powerline. Zero runtime deps.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Carlos Cativo"
|
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ See [`docs/competitive-comparison.md`](docs/competitive-comparison.md) for the f
|
|
|
87
87
|
## Requirements
|
|
88
88
|
|
|
89
89
|
- **Node ≥18**
|
|
90
|
-
- **Nerd Font** (recommended) — for branch, folder, model, and spinner icons. Falls back to plain glyphs via `icons: emoji` or `icons: none`.
|
|
90
|
+
- **Nerd Font** (recommended) — for branch, folder, model, and spinner icons. **Use a recent build (Nerd Fonts v3.0+);** some indicators use newer Material Design Icons codepoints (e.g. the extended-thinking glyph `U+F09D1`) that older font releases render as a blank/tofu cell. Falls back to plain glyphs via `icons: emoji` or `icons: none`.
|
|
91
91
|
- **Truecolor terminal** (for themes / powerline) — auto-detected via `COLORTERM=truecolor`. 256-color terminals get a nearest-index projection; named-ANSI terminals fall back to default colors silently.
|
|
92
92
|
|
|
93
93
|
## Features
|
|
@@ -95,7 +95,7 @@ See [`docs/competitive-comparison.md`](docs/competitive-comparison.md) for the f
|
|
|
95
95
|
- **Context bar with thresholds** — green → yellow → orange → blinking red, plus an actionable `/compact?` hint when fill is high.
|
|
96
96
|
- **Session intelligence** — pace delta (🐢/🏎️) shows whether you're burning quota faster than the time window allows, with ETA when ahead of pace. Live agent count and cache hit rate round it out.
|
|
97
97
|
- **Powerline mode** + 7 separator presets (`arrow`, `flame`, `slant`, `round`, `diamond`, `compatible`, `plain`) across 3 lines.
|
|
98
|
-
- **OSC 8 hyperlinks** — clickable directory and version tag on iTerm2, WezTerm, Kitty, VS Code, Alacritty.
|
|
98
|
+
- **OSC 8 hyperlinks** — clickable directory, repo, PR, and version tag on iTerm2, WezTerm, Kitty, VS Code, Alacritty.
|
|
99
99
|
- **7 hand-curated themes** — `dracula`, `nord`, `tokyo-night`, `catppuccin`, `monokai`, `gruvbox`, `solarized`. WCAG AA contrast guaranteed in CI.
|
|
100
100
|
- **Token + cost metrics** — input/output counts, speed (tok/s), $ total + burn rate ($/h), cache hit rate.
|
|
101
101
|
- **Auto-fits at <70 cols** — switches from 3-line custom mode to single-line minimal automatically.
|
|
@@ -106,6 +106,7 @@ See [`docs/competitive-comparison.md`](docs/competitive-comparison.md) for the f
|
|
|
106
106
|
<summary>Everything else lumira shows</summary>
|
|
107
107
|
|
|
108
108
|
- **Git status** — branch + staged/modified/untracked counts, 5s TTL cache. Branch turns red on dirty repos in powerline mode.
|
|
109
|
+
- **Repo identity** — when Claude Code exposes `workspace.repo`, line1 shows `owner/name` as a segment linked (OSC 8) to the repo on its host. Toggle via `display.repo`.
|
|
109
110
|
- **Rate limits** — 5h/7d usage as a battery glyph (Nerd Font level fill, or 🔋/🪫 in emoji mode) with color tier and reset countdown. Threshold-gated at 50% to stay invisible while you have margin.
|
|
110
111
|
- **Pace delta** — `usedPct − elapsedPct` of the 5h window. Turtle when behind pace (healthy), car with time-to-exhaustion when ahead. Color escalates green → yellow → orange → blinkRed. Toggle independently via `display.paceDelta`.
|
|
111
112
|
- **7d quota projection** — when the current burn rate would exhaust the 7d quota before the window resets, the 7d segment grows a warning: `⚠ ~24h`, `⚠ ~2d`, `⚠ Tue`, or `🔥 ~8h` (critical icon under 12h). Default on. Toggle via `display.quotaProjection`; off in the `minimal` preset. Different from pace delta — pace looks backwards at the 5h window's actual vs proportional burn, projection looks forwards at the 7d window's exhaustion ETA.
|
package/dist/config.js
CHANGED
|
@@ -249,6 +249,7 @@ const PRESET_DEFS = {
|
|
|
249
249
|
display: {
|
|
250
250
|
agents: true,
|
|
251
251
|
pr: true,
|
|
252
|
+
repo: true,
|
|
252
253
|
thinking: true,
|
|
253
254
|
burnRate: false,
|
|
254
255
|
duration: false,
|
|
@@ -297,6 +298,7 @@ const PRESET_DEFS = {
|
|
|
297
298
|
worktreeBreadcrumb: false,
|
|
298
299
|
compactionCount: false,
|
|
299
300
|
pr: false,
|
|
301
|
+
repo: false,
|
|
300
302
|
thinking: false,
|
|
301
303
|
},
|
|
302
304
|
},
|
package/dist/normalize.js
CHANGED
|
@@ -123,7 +123,7 @@ export function normalize(input) {
|
|
|
123
123
|
// For claude-code, honors CLAUDE_CODE_AUTO_COMPACT_WINDOW env var — a fill-%
|
|
124
124
|
// threshold (1-100) that mirrors Claude Code's own auto-compact trigger point.
|
|
125
125
|
// Users who changed this setting in Claude Code should set the same value here.
|
|
126
|
-
// Falls back to the hardcoded
|
|
126
|
+
// Falls back to the hardcoded 84% default when absent or invalid.
|
|
127
127
|
const effectivePct = realUsedPercentage ?? contextWindow.used_percentage ?? 0;
|
|
128
128
|
let platformAutoCompactThreshold = AUTO_COMPACT_THRESHOLD[platform];
|
|
129
129
|
if (platform === 'claude-code') {
|
|
@@ -200,9 +200,24 @@ export function normalize(input) {
|
|
|
200
200
|
pr = { number: n, url: prUrl, reviewState: prReviewState };
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
+
// Repository identity from workspace.repo (CC parses host/owner/name from the
|
|
204
|
+
// origin remote). All three parts must be present and well-formed: the url is
|
|
205
|
+
// rendered as an OSC 8 hyperlink, so each part is validated against a strict
|
|
206
|
+
// pattern to keep a malformed payload from injecting into the link target.
|
|
207
|
+
let repo;
|
|
208
|
+
const rawRepo = input.workspace?.repo;
|
|
209
|
+
if (rawRepo != null) {
|
|
210
|
+
const host = typeof rawRepo.host === 'string' ? sanitizeTermString(rawRepo.host) : '';
|
|
211
|
+
const owner = typeof rawRepo.owner === 'string' ? sanitizeTermString(rawRepo.owner) : '';
|
|
212
|
+
const name = typeof rawRepo.name === 'string' ? sanitizeTermString(rawRepo.name) : '';
|
|
213
|
+
if (/^[a-zA-Z0-9.-]+$/.test(host) && /^[\w.-]+$/.test(owner) && /^[\w.-]+$/.test(name)) {
|
|
214
|
+
repo = { host, owner, name, url: `https://${host}/${owner}/${name}` };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
203
217
|
return {
|
|
204
218
|
platform,
|
|
205
219
|
model: sanitizeTermString(modelName),
|
|
220
|
+
repo,
|
|
206
221
|
sessionId: sanitizeTermString(input.session_id),
|
|
207
222
|
version: input.version ? sanitizeTermString(input.version) : undefined,
|
|
208
223
|
cwd: sanitizeTermString(cwd),
|
|
@@ -235,7 +250,13 @@ export function normalize(input) {
|
|
|
235
250
|
? sanitizeTermString(claude.effort.level)
|
|
236
251
|
: undefined,
|
|
237
252
|
thinkingEnabled: claude?.thinking?.enabled === true ? true : undefined,
|
|
238
|
-
|
|
253
|
+
// Prefer the top-level worktree.name; fall back to workspace.git_worktree,
|
|
254
|
+
// which CC populates for ANY git worktree (verified on v2.1.193) — even
|
|
255
|
+
// sessions not started with --worktree, where worktree.name is absent.
|
|
256
|
+
worktreeName: (() => {
|
|
257
|
+
const n = input.worktree?.name ?? input.workspace?.git_worktree;
|
|
258
|
+
return n ? sanitizeTermString(n) : undefined;
|
|
259
|
+
})(),
|
|
239
260
|
addedDirsCount: (() => {
|
|
240
261
|
const dirs = input.workspace?.added_dirs;
|
|
241
262
|
if (!Array.isArray(dirs) || dirs.length === 0)
|
package/dist/render/icons.js
CHANGED
|
@@ -61,6 +61,7 @@ export const NERD_ICONS = {
|
|
|
61
61
|
turtle: '🐢', // turtle — pace-behind indicator
|
|
62
62
|
lightning: '', // U+F140B — nerd lightning-bolt (was ⚡ emoji); cache hit rate
|
|
63
63
|
pr: '', // nf-cod-git_pull_request
|
|
64
|
+
repo: '', // U+EA62 nf-cod-repo
|
|
64
65
|
thinking: '', // U+F09D1 — clearer "thinking" glyph; nf-md-brain (U+F1824) renders faint in many fonts
|
|
65
66
|
battery: nerdBattery,
|
|
66
67
|
};
|
|
@@ -86,6 +87,7 @@ export const EMOJI_ICONS = {
|
|
|
86
87
|
turtle: '\u{1F422}', // 🐢 — turtle
|
|
87
88
|
lightning: '⚡', // ⚡ — cache hit rate
|
|
88
89
|
pr: '\u{1F500}', // 🔀 — twisted rightwards arrows (PR)
|
|
90
|
+
repo: '\u{1F4E6}', // 📦 — package (repository)
|
|
89
91
|
thinking: '\u{1F4AD}', // 💭 — thought bubble
|
|
90
92
|
battery: (pct) => {
|
|
91
93
|
if (!Number.isFinite(pct) || pct < 0)
|
|
@@ -119,6 +121,7 @@ export const NO_ICONS = {
|
|
|
119
121
|
turtle: '',
|
|
120
122
|
lightning: '',
|
|
121
123
|
pr: 'PR',
|
|
124
|
+
repo: '',
|
|
122
125
|
thinking: 'think',
|
|
123
126
|
// No-icon mode keeps the legacy bolt fallback (currently empty) so users who
|
|
124
127
|
// opted out of icons see no shape change from this feature.
|
package/dist/render/line1.js
CHANGED
|
@@ -40,6 +40,16 @@ export function renderLine1(ctx, c) {
|
|
|
40
40
|
left.push(hyperlink(pathToFileURL(cwd).href, label));
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
// Repo segment — owner/name from workspace.repo, clickable to open the repo
|
|
44
|
+
// on its host. Distinct from the directory breadcrumb above (a local path):
|
|
45
|
+
// this is the canonical remote identity, and surfaces the owner that the
|
|
46
|
+
// bare cwd basename can't.
|
|
47
|
+
if (display.repo && input.repo) {
|
|
48
|
+
const { owner, name, url } = input.repo;
|
|
49
|
+
const repoLen = cols < 80 ? 14 : cols < 120 ? 24 : 36;
|
|
50
|
+
const label = c.brightBlue(`${icons.repo} ${truncField(`${owner}/${name}`, repoLen)}`);
|
|
51
|
+
left.push(hyperlink(url, label));
|
|
52
|
+
}
|
|
43
53
|
// Added dirs badge — only when count > 0; warning color at >= 5
|
|
44
54
|
if (display.addedDirs && input.addedDirsCount != null && input.addedDirsCount > 0) {
|
|
45
55
|
const badge = `+${input.addedDirsCount} dirs`;
|
|
@@ -79,6 +79,19 @@ function buildSegments(ctx, palette, c) {
|
|
|
79
79
|
priority: 60,
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
|
+
if (display.repo && input.repo) {
|
|
83
|
+
const { owner, name, url } = input.repo;
|
|
84
|
+
// Priority 58 — below directory@60 and the addedDirs badge@59. Repo is the
|
|
85
|
+
// canonical remote identity (annotates the local dir), so it cedes first
|
|
86
|
+
// under narrow-terminal pressure. Same dir-family background as directory.
|
|
87
|
+
segments.push({
|
|
88
|
+
text: hyperlink(url, truncField(`${owner}/${name}`, 36)),
|
|
89
|
+
icon: icons.repo,
|
|
90
|
+
bg: palette.dirBg,
|
|
91
|
+
fg: palette.fg,
|
|
92
|
+
priority: 58,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
82
95
|
if (display.addedDirs && input.addedDirsCount != null && input.addedDirsCount > 0) {
|
|
83
96
|
const badge = `+${input.addedDirsCount} dirs`;
|
|
84
97
|
const bg = input.addedDirsCount >= 5 ? palette.taskBg : palette.versionBg;
|
package/dist/tui/preview.js
CHANGED
|
@@ -115,13 +115,13 @@ function buildMockContext(opts) {
|
|
|
115
115
|
* the context-bar auto-compact behavior they'll see in the live statusline.
|
|
116
116
|
*
|
|
117
117
|
* The platform thresholds referenced here are external constraints, not
|
|
118
|
-
* lumira's: Claude Code auto-compacts at ~
|
|
118
|
+
* lumira's: Claude Code auto-compacts at ~84% (hardcoded, reserves headroom
|
|
119
119
|
* for output generation); Qwen Code defaults to 70% via the configurable
|
|
120
120
|
* `model.chatCompression.contextPercentageThreshold`. The ⚠ glyph fires
|
|
121
121
|
* 5pp before whichever applies — independent of user-tunable colour
|
|
122
122
|
* thresholds, which track preference, not the platform's hard ceiling.
|
|
123
123
|
*/
|
|
124
|
-
const CONTEXT_BAR_NOTE = '\n Context bar: ⚠ appears in the 5pp window before auto-compact fires (~
|
|
124
|
+
const CONTEXT_BAR_NOTE = '\n Context bar: ⚠ appears in the 5pp window before auto-compact fires (~84% on Claude Code,\n' +
|
|
125
125
|
' 70% default on Qwen Code). New defaults (warning 65 / critical 78) turn the bar red before\n' +
|
|
126
126
|
' auto-compact triggers. Qwen users with a custom model.chatCompression.contextPercentageThreshold\n' +
|
|
127
127
|
' should mirror that value in lumira\'s contextCriticalThreshold for accurate gating.\n';
|
package/dist/types.js
CHANGED
|
@@ -56,7 +56,7 @@ export const QUOTA_CRITICAL = 85;
|
|
|
56
56
|
* Auto-compact threshold per platform — the % of context window at which
|
|
57
57
|
* the platform automatically compacts the conversation history.
|
|
58
58
|
*
|
|
59
|
-
* - Claude Code: ~
|
|
59
|
+
* - Claude Code: ~84% (hardcoded internally; reserves ~30K tokens for output generation).
|
|
60
60
|
* Not user-configurable in the main conversation. See anthropics/claude-code#34126.
|
|
61
61
|
* - Qwen Code: 70% by default; user-configurable via
|
|
62
62
|
* `model.chatCompression.contextPercentageThreshold` in qwen settings.json.
|
|
@@ -64,13 +64,19 @@ export const QUOTA_CRITICAL = 85;
|
|
|
64
64
|
* `contextCriticalThreshold` — the constant below is the platform default only.
|
|
65
65
|
*/
|
|
66
66
|
export const AUTO_COMPACT_THRESHOLD = {
|
|
67
|
-
|
|
67
|
+
// Measured on CC v2.1.193 by capturing the live statusline payload right up to
|
|
68
|
+
// an auto-compaction: the last render before context dropped was 166177/200000
|
|
69
|
+
// = 83.09% (CC's own "% until auto-compact" is NOT linear, so adding it to the
|
|
70
|
+
// fill over-estimated — only the pre-drop peak is reliable). Set to 84 so the
|
|
71
|
+
// nearAutoCompact warning window [79, 84) keeps the glyph lit through the real
|
|
72
|
+
// ~83.1% trigger (83 would extinguish it a hair before compaction).
|
|
73
|
+
'claude-code': 84,
|
|
68
74
|
'qwen-code': 70,
|
|
69
75
|
};
|
|
70
76
|
/**
|
|
71
77
|
* Gap (in percentage points) before the auto-compact threshold at which the
|
|
72
78
|
* `nearAutoCompact` warning glyph fires. The glyph appears in the window
|
|
73
|
-
* `[AUTO_COMPACT_THRESHOLD - GAP, AUTO_COMPACT_THRESHOLD)` — i.e.,
|
|
79
|
+
* `[AUTO_COMPACT_THRESHOLD - GAP, AUTO_COMPACT_THRESHOLD)` — i.e., 79-84%
|
|
74
80
|
* on Claude, 65-70% on Qwen. This is an immutable system constant (not the
|
|
75
81
|
* same as the user-configurable `contextWarningThreshold`).
|
|
76
82
|
*/
|
|
@@ -110,6 +116,7 @@ export const DEFAULT_DISPLAY = {
|
|
|
110
116
|
worktreeBreadcrumb: true,
|
|
111
117
|
compactionCount: true,
|
|
112
118
|
pr: true,
|
|
119
|
+
repo: true,
|
|
113
120
|
thinking: true,
|
|
114
121
|
contextWarningThreshold: DEFAULT_CONTEXT_WARNING_THRESHOLD,
|
|
115
122
|
contextCriticalThreshold: DEFAULT_CONTEXT_CRITICAL_THRESHOLD,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lumira",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Real-time statusline HUD for Claude Code and Qwen Code. Includes session analytics CLI, API latency overhead widget, 7d quota projection, auto-compact proximity warnings, themes, and powerline. Zero deps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|