skill-statusline 2.2.1 → 2.3.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/bin/cli.js +15 -7
- package/bin/statusline-node.js +85 -0
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ const readline = require('readline');
|
|
|
9
9
|
const args = process.argv.slice(2);
|
|
10
10
|
const command = args[0];
|
|
11
11
|
const subcommand = args[1];
|
|
12
|
-
const VERSION = '2.2.
|
|
12
|
+
const VERSION = '2.2.2';
|
|
13
13
|
|
|
14
14
|
const PKG_DIR = path.resolve(__dirname, '..');
|
|
15
15
|
const HOME = os.homedir();
|
|
@@ -352,13 +352,21 @@ async function install() {
|
|
|
352
352
|
writeConfig(config);
|
|
353
353
|
success(`Config: theme=${CYN}${config.theme}${R}, layout=${CYN}${config.layout}${R}`);
|
|
354
354
|
|
|
355
|
-
// Update settings.json
|
|
355
|
+
// Update settings.json — use absolute paths on Windows to avoid WSL bash conflict
|
|
356
356
|
const settings = readSettings();
|
|
357
|
-
if (!settings.statusLine) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
357
|
+
if (!settings.statusLine || settings.statusLine.command === 'bash ~/.claude/statusline-command.sh') {
|
|
358
|
+
const isWin = process.platform === 'win32';
|
|
359
|
+
let cmd;
|
|
360
|
+
if (isWin) {
|
|
361
|
+
// Windows has WSL bash at C:\Windows\System32\bash.exe which resolves ~ to /root/
|
|
362
|
+
// Must use Git Bash explicitly with absolute Windows paths
|
|
363
|
+
const gitBash = 'C:\\\\Program Files\\\\Git\\\\usr\\\\bin\\\\bash.exe';
|
|
364
|
+
const script = SCRIPT_DEST.replace(/\//g, '\\\\');
|
|
365
|
+
cmd = `"${gitBash}" "${script}"`;
|
|
366
|
+
} else {
|
|
367
|
+
cmd = 'bash ~/.claude/statusline-command.sh';
|
|
368
|
+
}
|
|
369
|
+
settings.statusLine = { type: 'command', command: cmd };
|
|
362
370
|
writeSettings(settings);
|
|
363
371
|
success(`${B}statusLine${R} config added to settings.json`);
|
|
364
372
|
} else {
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// skill-statusline v2.3 — Node.js statusline renderer
|
|
3
|
+
// Zero bash dependency — works on Windows, macOS, Linux
|
|
4
|
+
// Synchronous stdin read for maximum speed
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
try {
|
|
10
|
+
const input = fs.readFileSync(0, 'utf8');
|
|
11
|
+
if (input) render(JSON.parse(input));
|
|
12
|
+
} catch (e) { /* silent exit on any error */ }
|
|
13
|
+
|
|
14
|
+
function render(data) {
|
|
15
|
+
const RST = '\x1b[0m', BOLD = '\x1b[1m';
|
|
16
|
+
const CYAN = '\x1b[38;2;6;182;212m', PURPLE = '\x1b[38;2;168;85;247m';
|
|
17
|
+
const GREEN = '\x1b[38;2;34;197;94m', YELLOW = '\x1b[38;2;245;158;11m';
|
|
18
|
+
const RED = '\x1b[38;2;239;68;68m', ORANGE = '\x1b[38;2;251;146;60m';
|
|
19
|
+
const WHITE = '\x1b[38;2;228;228;231m', PINK = '\x1b[38;2;236;72;153m';
|
|
20
|
+
const SEP = '\x1b[38;2;55;55;62m', DIM = '\x1b[38;2;40;40;45m';
|
|
21
|
+
const BLUE = '\x1b[38;2;59;130;246m';
|
|
22
|
+
|
|
23
|
+
// Model — display_name already includes version (e.g. "Opus 4.6")
|
|
24
|
+
const model = data.model?.display_name || 'unknown';
|
|
25
|
+
|
|
26
|
+
// Directory — last 3 path segments
|
|
27
|
+
const cwd = (data.workspace?.current_dir || data.cwd || '').replace(/\\/g, '/').replace(/\/\/+/g, '/');
|
|
28
|
+
const parts = cwd.split('/').filter(Boolean);
|
|
29
|
+
const dir = parts.length > 3 ? parts.slice(-3).join('/') : parts.length > 0 ? parts.join('/') : '~';
|
|
30
|
+
|
|
31
|
+
// Git branch — read .git/HEAD directly (no subprocess, instant)
|
|
32
|
+
let branch = '';
|
|
33
|
+
try {
|
|
34
|
+
const projectDir = data.workspace?.project_dir || data.workspace?.current_dir || data.cwd || '';
|
|
35
|
+
const gitHead = fs.readFileSync(path.join(projectDir, '.git', 'HEAD'), 'utf8').trim();
|
|
36
|
+
branch = gitHead.startsWith('ref: refs/heads/') ? gitHead.slice(16) : gitHead.slice(0, 7);
|
|
37
|
+
} catch (e) { branch = 'no-git'; }
|
|
38
|
+
|
|
39
|
+
// Context — use provided percentage (most accurate)
|
|
40
|
+
let pct = Math.floor(data.context_window?.used_percentage || 0);
|
|
41
|
+
if (pct > 100) pct = 100;
|
|
42
|
+
const ctxClr = pct > 90 ? RED : pct > 75 ? ORANGE : pct > 40 ? YELLOW : WHITE;
|
|
43
|
+
const barW = 40;
|
|
44
|
+
const filled = Math.min(Math.floor(pct * barW / 100), barW);
|
|
45
|
+
const bar = ctxClr + '\u2588'.repeat(filled) + RST + DIM + '\u2591'.repeat(barW - filled) + RST;
|
|
46
|
+
|
|
47
|
+
// Cost
|
|
48
|
+
const costRaw = data.cost?.total_cost_usd || 0;
|
|
49
|
+
const cost = costRaw === 0 ? '$0.00' : costRaw < 0.01 ? `$${costRaw.toFixed(4)}` : `$${costRaw.toFixed(2)}`;
|
|
50
|
+
|
|
51
|
+
// Tokens — show session totals (in / out / total)
|
|
52
|
+
const fmtTok = n => n >= 1000000 ? `${(n/1000000).toFixed(1)}M` : n >= 1000 ? `${(n/1000).toFixed(1)}k` : `${n}`;
|
|
53
|
+
const totIn = data.context_window?.total_input_tokens || 0;
|
|
54
|
+
const totOut = data.context_window?.total_output_tokens || 0;
|
|
55
|
+
const tokTotal = fmtTok(totIn + totOut);
|
|
56
|
+
const tokIn = fmtTok(totIn);
|
|
57
|
+
const tokOut = fmtTok(totOut);
|
|
58
|
+
|
|
59
|
+
// Session duration
|
|
60
|
+
const durMs = data.cost?.total_duration_ms || 0;
|
|
61
|
+
const durMin = Math.floor(durMs / 60000);
|
|
62
|
+
const durSec = Math.floor((durMs % 60000) / 1000);
|
|
63
|
+
const duration = durMin > 0 ? `${durMin}m ${durSec}s` : `${durSec}s`;
|
|
64
|
+
|
|
65
|
+
// Lines changed
|
|
66
|
+
const linesAdded = data.cost?.total_lines_added || 0;
|
|
67
|
+
const linesRemoved = data.cost?.total_lines_removed || 0;
|
|
68
|
+
|
|
69
|
+
// Separator + padding
|
|
70
|
+
const S = ` ${SEP}\u2502${RST} `;
|
|
71
|
+
const rpad = (s, w) => {
|
|
72
|
+
const plain = s.replace(/\x1b\[[0-9;]*m/g, '');
|
|
73
|
+
return s + (plain.length < w ? ' '.repeat(w - plain.length) : '');
|
|
74
|
+
};
|
|
75
|
+
const C1 = 44;
|
|
76
|
+
|
|
77
|
+
// Output 4 rows
|
|
78
|
+
let out = '';
|
|
79
|
+
out += ' ' + rpad(`${PURPLE}Model:${RST} ${PURPLE}${BOLD}${model}${RST}`, C1) + S + `${CYAN}Dir:${RST} ${CYAN}${dir}${RST}\n`;
|
|
80
|
+
out += ' ' + rpad(`${YELLOW}Tokens:${RST} ${YELLOW}${tokIn} in + ${tokOut} out = ${BOLD}${tokTotal}${RST}`, C1) + S + `${GREEN}Cost:${RST} ${GREEN}${cost}${RST}\n`;
|
|
81
|
+
out += ' ' + rpad(`${BLUE}Session:${RST} ${BLUE}${duration}${RST} ${DIM}|${RST} ${GREEN}+${linesAdded}${RST}${DIM}/${RST}${RED}-${linesRemoved}${RST} ${DIM}lines${RST}`, C1) + S + `${WHITE}Git:${RST} ${WHITE}${branch}${RST}\n`;
|
|
82
|
+
out += ` ${ctxClr}Context:${RST} ${bar} ${ctxClr}${pct}%${RST}`;
|
|
83
|
+
|
|
84
|
+
process.stdout.write(out);
|
|
85
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skill-statusline",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Rich, themeable statusline for Claude Code — accurate context tracking, 5 themes, 3 layouts, token/cost/GitHub/skill display. Pure bash, zero deps.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"skill-statusline": "bin/cli.js",
|