@owloops/claude-powerline 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Owloops
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,196 @@
1
+ # Claude Powerline
2
+
3
+ A beautiful vim-style powerline statusline for Claude Code with real-time cost tracking, git integration, and custom themes.
4
+
5
+ ![Language:TypeScript](https://img.shields.io/static/v1?label=Language&message=TypeScript&color=blue&style=flat-square)
6
+ ![License:MIT](https://img.shields.io/static/v1?label=License&message=MIT&color=blue&style=flat-square)
7
+ [![npm version](https://img.shields.io/npm/v/claude-powerline?style=flat-square)](https://www.npmjs.com/package/claude-powerline)
8
+
9
+ ## Features
10
+
11
+ - **Vim-style powerline** - Beautiful segmented statusline with proper powerline arrows
12
+ - **Real-time cost tracking** - Session and daily usage costs using [ccusage](https://github.com/ryanschneider/ccusage)
13
+ - **Git integration** - Branch name, status indicators, ahead/behind counts
14
+ - **Dual themes** - Light and dark color schemes optimized for different terminals
15
+ - **Smart directory display** - Project-aware path showing with context
16
+ - **Zero configuration** - Works out of the box with Claude Code hooks
17
+ - **Font management** - Built-in powerline fonts installer
18
+
19
+ ## Screenshots
20
+
21
+ ### Default Theme
22
+
23
+ ![Default colorful theme](images/powerline-default.png)
24
+
25
+ ### Dark Theme
26
+
27
+ ![Dark theme](images/powerline-dark.png)
28
+
29
+ ## Installation
30
+
31
+ ### npm (Recommended)
32
+
33
+ ```bash
34
+ npm install -g claude-powerline
35
+ ```
36
+
37
+ ### Install powerline fonts
38
+
39
+ For proper arrow display, install powerline fonts:
40
+
41
+ ```bash
42
+ claude-powerline --install-fonts
43
+ ```
44
+
45
+ After installation, set your terminal font to:
46
+
47
+ - Source Code Pro Powerline
48
+ - DejaVu Sans Mono Powerline
49
+ - Ubuntu Mono Powerline
50
+
51
+ ### From source
52
+
53
+ ```bash
54
+ git clone https://github.com/user/claude-powerline.git
55
+ cd claude-powerline
56
+ npm install
57
+ npm run build
58
+ npm install -g .
59
+ ```
60
+
61
+ ## Usage
62
+
63
+ ### Claude Code Integration
64
+
65
+ Add to your Claude Code `settings.json`:
66
+
67
+ ```json
68
+ {
69
+ "statusLine": {
70
+ "type": "command",
71
+ "command": "claude-powerline",
72
+ "padding": 0
73
+ }
74
+ }
75
+ ```
76
+
77
+ ### Command Line Options
78
+
79
+ ```bash
80
+ # Default colorful theme
81
+ claude-powerline
82
+
83
+ # Dark theme for dark terminals
84
+ claude-powerline --dark
85
+
86
+ # Install powerline fonts
87
+ claude-powerline --install-fonts
88
+
89
+ # Show help
90
+ claude-powerline --help
91
+ ```
92
+
93
+ ### Manual Testing
94
+
95
+ ```bash
96
+ echo '{
97
+ "model": {"id": "claude-sonnet", "display_name": "Claude 3.5 Sonnet"},
98
+ "workspace": {"current_dir": "/path/to/project", "project_dir": "/path/to/project"},
99
+ "session_id": "abc123",
100
+ "cwd": "/path/to/project",
101
+ "transcript_path": "/path/to/transcript.json",
102
+ "hook_event_name": "Status"
103
+ }' | claude-powerline
104
+ ```
105
+
106
+ ## Statusline Segments
107
+
108
+ The statusline displays information in colored segments from left to right:
109
+
110
+ | Segment | Description | Example |
111
+ |---------|-------------|---------|
112
+ | **Directory** | Current working directory or project name | `myproject` |
113
+ | **Git Branch** | Branch with status and ahead/behind | `master ✓ ↑2` |
114
+ | **Model** | Current Claude model | `Claude 3.5 Sonnet` |
115
+ | **Session** | Current session usage cost | `Session $0.05` |
116
+ | **Daily** | Total daily usage cost | `Today $14.82` |
117
+
118
+ ### Git Status Indicators
119
+
120
+ - `✓` **Clean** - No uncommitted changes
121
+ - `●` **Dirty** - Uncommitted changes present
122
+ - `⚠` **Conflicts** - Merge conflicts detected
123
+ - `↑3` **Ahead** - 3 commits ahead of remote
124
+ - `↓2` **Behind** - 2 commits behind remote
125
+
126
+ ### Cost Information
127
+
128
+ Powered by [ccusage](https://github.com/ryanschneider/ccusage) integration:
129
+
130
+ - Shows current session and daily totals
131
+ - Displays `N/A` if session not found
132
+ - Shows `<$0.01` for small amounts
133
+
134
+ ## Themes
135
+
136
+ **Colors Theme (Default):**
137
+
138
+ - Vibrant segments: orange → blue → purple → pink → green
139
+ - High contrast for light terminals
140
+
141
+ **Dark Theme (`--dark`):**
142
+
143
+ - Subdued segments: brown → gray → dark purple → charcoal
144
+ - Optimized for dark terminals
145
+
146
+ ## Requirements
147
+
148
+ - Node.js ≥ 18.0.0
149
+ - Claude Code with statusline hook support
150
+ - Terminal with powerline font support (use `--install-fonts`)
151
+ - Git (optional, for git integration)
152
+
153
+ ## Development
154
+
155
+ ```bash
156
+ # Install dependencies
157
+ npm install
158
+
159
+ # Build TypeScript
160
+ npm run build
161
+
162
+ # Run tests
163
+ npm test
164
+
165
+ # Lint code
166
+ npm run lint
167
+
168
+ # Development mode with file watching
169
+ npm run dev
170
+ ```
171
+
172
+ ## Troubleshooting
173
+
174
+ **Arrows not displaying?**
175
+
176
+ 1. Run `claude-powerline --install-fonts`
177
+ 2. Restart terminal and set font to a powerline font
178
+ 3. Ensure terminal supports Unicode
179
+
180
+ **Cost showing N/A?**
181
+
182
+ 1. Verify [ccusage](https://github.com/ryanschneider/ccusage) can access Claude data
183
+ 2. Check session ID matches current Claude session
184
+
185
+ **Git info missing?**
186
+
187
+ 1. Ensure you're in a git repository
188
+ 2. Check git is installed and in PATH
189
+
190
+ ## Contributing
191
+
192
+ Contributions are welcome! Please feel free to submit issues or pull requests.
193
+
194
+ ## License
195
+
196
+ This project is licensed under the [MIT License](LICENSE).
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,396 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import process from "process";
5
+ import path from "path";
6
+ import fs from "fs";
7
+ import { execSync as execSync2 } from "child_process";
8
+ import os from "os";
9
+ import getStdin from "get-stdin";
10
+
11
+ // src/powerline.ts
12
+ import { execSync } from "child_process";
13
+ import {
14
+ loadSessionUsageById,
15
+ loadDailyUsageData,
16
+ getClaudePaths
17
+ } from "ccusage/data-loader";
18
+ import { calculateTotals } from "ccusage/calculate-cost";
19
+ import { logger } from "ccusage/logger";
20
+ var PowerlineRenderer = class {
21
+ symbols;
22
+ colors;
23
+ constructor() {
24
+ this.symbols = this.initializeSymbols();
25
+ this.colors = {
26
+ colors: {
27
+ reset: "\x1B[0m",
28
+ modeBg: "\x1B[48;2;255;107;71m",
29
+ modeFg: "\x1B[97m",
30
+ sessionBg: "\x1B[48;2;79;179;217m",
31
+ sessionFg: "\x1B[97m",
32
+ dailyBg: "\x1B[48;2;135;206;235m",
33
+ dailyFg: "\x1B[30m",
34
+ blockBg: "\x1B[48;2;218;112;214m",
35
+ blockFg: "\x1B[97m",
36
+ burnLowBg: "\x1B[48;2;144;238;144m",
37
+ burnFg: "\x1B[97m"
38
+ },
39
+ dark: {
40
+ reset: "\x1B[0m",
41
+ modeBg: "\x1B[48;2;139;69;19m",
42
+ modeFg: "\x1B[97m",
43
+ sessionBg: "\x1B[48;2;64;64;64m",
44
+ sessionFg: "\x1B[97m",
45
+ dailyBg: "\x1B[48;2;45;45;45m",
46
+ dailyFg: "\x1B[97m",
47
+ blockBg: "\x1B[48;2;32;32;32m",
48
+ blockFg: "\x1B[96m",
49
+ burnLowBg: "\x1B[48;2;28;28;28m",
50
+ burnFg: "\x1B[97m"
51
+ }
52
+ };
53
+ }
54
+ initializeSymbols() {
55
+ return {
56
+ right: "\uE0B0",
57
+ branch: "\uE0A0",
58
+ model: "\u26A1",
59
+ git_clean: "\u2713",
60
+ git_dirty: "\u25CF",
61
+ git_conflicts: "\u26A0",
62
+ git_ahead: "\u2191",
63
+ git_behind: "\u2193",
64
+ session_cost: "Session",
65
+ daily_cost: "Today"
66
+ };
67
+ }
68
+ extractBgColor(ansiCode) {
69
+ const match = ansiCode.match(/48;2;(\d+);(\d+);(\d+)/);
70
+ if (match) {
71
+ return `\x1B[38;2;${match[1]};${match[2]};${match[3]}m`;
72
+ }
73
+ return ansiCode.replace("48", "38");
74
+ }
75
+ renderSegment(bgColor, fgColor, text, nextBgColor) {
76
+ let output = `${bgColor}${fgColor} ${text} `;
77
+ if (nextBgColor) {
78
+ const arrowFgColor = this.extractBgColor(bgColor);
79
+ output += `${nextBgColor}${arrowFgColor}${this.symbols.right}`;
80
+ } else {
81
+ const arrowFgColor = this.extractBgColor(bgColor);
82
+ output += `${this.colors.colors.reset}${arrowFgColor}${this.symbols.right}${this.colors.colors.reset}`;
83
+ }
84
+ return output;
85
+ }
86
+ sanitizePath(path2) {
87
+ return path2.replace(/[;&|`$(){}[\]<>'"\\]/g, "");
88
+ }
89
+ getGitInfo(workingDir) {
90
+ try {
91
+ const sanitizedDir = this.sanitizePath(workingDir);
92
+ const branch = execSync("git branch --show-current 2>/dev/null", {
93
+ cwd: sanitizedDir,
94
+ encoding: "utf8",
95
+ timeout: 1e3
96
+ }).trim();
97
+ const gitStatus = execSync("git status --porcelain 2>/dev/null", {
98
+ cwd: sanitizedDir,
99
+ encoding: "utf8",
100
+ timeout: 1e3
101
+ }).trim();
102
+ let status = "clean";
103
+ if (gitStatus) {
104
+ if (gitStatus.includes("UU") || gitStatus.includes("AA") || gitStatus.includes("DD")) {
105
+ status = "conflicts";
106
+ } else {
107
+ status = "dirty";
108
+ }
109
+ }
110
+ let ahead = 0, behind = 0;
111
+ try {
112
+ const aheadResult = execSync(
113
+ "git rev-list --count @{u}..HEAD 2>/dev/null",
114
+ {
115
+ cwd: sanitizedDir,
116
+ encoding: "utf8",
117
+ timeout: 1e3
118
+ }
119
+ ).trim();
120
+ ahead = parseInt(aheadResult) || 0;
121
+ const behindResult = execSync(
122
+ "git rev-list --count HEAD..@{u} 2>/dev/null",
123
+ {
124
+ cwd: sanitizedDir,
125
+ encoding: "utf8",
126
+ timeout: 1e3
127
+ }
128
+ ).trim();
129
+ behind = parseInt(behindResult) || 0;
130
+ } catch {
131
+ }
132
+ return { branch: branch || "detached", status, ahead, behind };
133
+ } catch {
134
+ return null;
135
+ }
136
+ }
137
+ async getCostInfo(sessionId) {
138
+ const originalLevel = logger.level;
139
+ logger.level = 0;
140
+ try {
141
+ const claudePaths = getClaudePaths();
142
+ if (claudePaths.length === 0) {
143
+ logger.level = originalLevel;
144
+ return { sessionCost: null, dailyCost: 0 };
145
+ }
146
+ let sessionCost = null;
147
+ try {
148
+ const sessionData = await loadSessionUsageById(sessionId, {
149
+ mode: "auto"
150
+ });
151
+ if (sessionData != null) {
152
+ sessionCost = sessionData.totalCost;
153
+ }
154
+ } catch {
155
+ }
156
+ let dailyCost = 0;
157
+ try {
158
+ const today = /* @__PURE__ */ new Date();
159
+ const todayStr = today.toISOString().split("T")[0]?.replace(/-/g, "") ?? "";
160
+ const dailyData = await loadDailyUsageData({
161
+ since: todayStr,
162
+ until: todayStr,
163
+ mode: "auto"
164
+ });
165
+ if (dailyData.length > 0) {
166
+ const totals = calculateTotals(dailyData);
167
+ dailyCost = totals.totalCost;
168
+ }
169
+ } catch {
170
+ }
171
+ logger.level = originalLevel;
172
+ return { sessionCost, dailyCost };
173
+ } catch {
174
+ logger.level = originalLevel;
175
+ return { sessionCost: null, dailyCost: 0 };
176
+ }
177
+ }
178
+ formatCost(cost) {
179
+ if (cost === null) return "N/A";
180
+ if (cost < 0.01) return "<$0.01";
181
+ return `$${cost.toFixed(2)}`;
182
+ }
183
+ async generateStatusline(hookData, style = "colors") {
184
+ const modelName = hookData.model?.display_name || "Claude";
185
+ const currentDir = hookData.workspace?.current_dir || hookData.cwd || "/";
186
+ const projectDir = hookData.workspace?.project_dir;
187
+ let dirName;
188
+ if (projectDir && projectDir !== currentDir) {
189
+ const projectName = projectDir.split("/").pop() || "project";
190
+ const currentDirName = currentDir.split("/").pop() || "root";
191
+ dirName = currentDir.includes(projectDir) ? `${projectName}/${currentDirName}` : currentDirName;
192
+ } else {
193
+ dirName = currentDir.split("/").pop() || "root";
194
+ }
195
+ const gitInfo = this.getGitInfo(currentDir);
196
+ const sessionId = hookData.session_id;
197
+ const costInfo = await this.getCostInfo(sessionId);
198
+ const colors = this.colors[style];
199
+ let statusline = "";
200
+ statusline += this.renderSegment(
201
+ colors.modeBg,
202
+ colors.modeFg,
203
+ dirName,
204
+ gitInfo ? colors.sessionBg : colors.dailyBg
205
+ );
206
+ if (gitInfo) {
207
+ let gitStatusIcon = this.symbols.git_clean;
208
+ if (gitInfo.status === "conflicts") {
209
+ gitStatusIcon = this.symbols.git_conflicts;
210
+ } else if (gitInfo.status === "dirty") {
211
+ gitStatusIcon = this.symbols.git_dirty;
212
+ }
213
+ let branchText = `${this.symbols.branch} ${gitInfo.branch} ${gitStatusIcon}`;
214
+ if (gitInfo.ahead > 0 && gitInfo.behind > 0) {
215
+ branchText += ` ${this.symbols.git_ahead}${gitInfo.ahead}${this.symbols.git_behind}${gitInfo.behind}`;
216
+ } else if (gitInfo.ahead > 0) {
217
+ branchText += ` ${this.symbols.git_ahead}${gitInfo.ahead}`;
218
+ } else if (gitInfo.behind > 0) {
219
+ branchText += ` ${this.symbols.git_behind}${gitInfo.behind}`;
220
+ }
221
+ statusline += this.renderSegment(
222
+ colors.sessionBg,
223
+ colors.sessionFg,
224
+ branchText,
225
+ colors.dailyBg
226
+ );
227
+ }
228
+ statusline += this.renderSegment(
229
+ colors.dailyBg,
230
+ colors.dailyFg,
231
+ `${this.symbols.model} ${modelName}`,
232
+ colors.blockBg
233
+ );
234
+ statusline += this.renderSegment(
235
+ colors.blockBg,
236
+ colors.blockFg,
237
+ `${this.symbols.session_cost} ${this.formatCost(costInfo.sessionCost)}`,
238
+ colors.burnLowBg
239
+ );
240
+ statusline += this.renderSegment(
241
+ colors.burnLowBg,
242
+ colors.burnFg,
243
+ `${this.symbols.daily_cost} ${this.formatCost(costInfo.dailyCost)}`
244
+ );
245
+ return statusline;
246
+ }
247
+ };
248
+
249
+ // src/index.ts
250
+ async function installFonts() {
251
+ try {
252
+ const platform = os.platform();
253
+ let fontDir;
254
+ if (platform === "darwin") {
255
+ fontDir = path.join(os.homedir(), "Library", "Fonts");
256
+ } else if (platform === "linux") {
257
+ fontDir = path.join(os.homedir(), ".local", "share", "fonts");
258
+ } else if (platform === "win32") {
259
+ fontDir = path.join(
260
+ os.homedir(),
261
+ "AppData",
262
+ "Local",
263
+ "Microsoft",
264
+ "Windows",
265
+ "Fonts"
266
+ );
267
+ } else {
268
+ console.log("Unsupported platform for font installation");
269
+ return;
270
+ }
271
+ if (!fs.existsSync(fontDir)) {
272
+ fs.mkdirSync(fontDir, { recursive: true });
273
+ }
274
+ console.log("\u{1F4E6} Installing Powerline Fonts...");
275
+ console.log("Downloading from https://github.com/powerline/fonts");
276
+ const tempDir = path.join(os.tmpdir(), "powerline-fonts");
277
+ try {
278
+ if (fs.existsSync(tempDir)) {
279
+ fs.rmSync(tempDir, { recursive: true, force: true });
280
+ }
281
+ console.log("Cloning powerline fonts repository...");
282
+ execSync2(
283
+ "git clone --depth=1 https://github.com/powerline/fonts.git powerline-fonts",
284
+ {
285
+ stdio: "inherit",
286
+ cwd: os.tmpdir()
287
+ }
288
+ );
289
+ console.log("Installing fonts...");
290
+ const installScript = path.join(tempDir, "install.sh");
291
+ if (fs.existsSync(installScript)) {
292
+ fs.chmodSync(installScript, 493);
293
+ execSync2("./install.sh", { stdio: "inherit", cwd: tempDir });
294
+ } else {
295
+ throw new Error(
296
+ "Install script not found in powerline fonts repository"
297
+ );
298
+ }
299
+ console.log("\u2705 Powerline fonts installation complete!");
300
+ console.log(
301
+ "Please restart your terminal and set your terminal font to a powerline font."
302
+ );
303
+ console.log(
304
+ "Popular choices: Source Code Pro Powerline, DejaVu Sans Mono Powerline, Ubuntu Mono Powerline"
305
+ );
306
+ } finally {
307
+ if (fs.existsSync(tempDir)) {
308
+ fs.rmSync(tempDir, { recursive: true, force: true });
309
+ }
310
+ }
311
+ } catch (error) {
312
+ console.error(
313
+ "Error installing fonts:",
314
+ error instanceof Error ? error.message : String(error)
315
+ );
316
+ console.log(
317
+ "\u{1F4A1} You can manually install fonts from: https://github.com/powerline/fonts"
318
+ );
319
+ }
320
+ }
321
+ async function main() {
322
+ try {
323
+ const style = process.argv.includes("--dark") ? "dark" : "colors";
324
+ const showHelp = process.argv.includes("--help") || process.argv.includes("-h");
325
+ const installFontsFlag = process.argv.includes("--install-fonts");
326
+ if (installFontsFlag) {
327
+ await installFonts();
328
+ process.exit(0);
329
+ }
330
+ if (showHelp) {
331
+ console.log(`
332
+ claude-powerline - Beautiful powerline statusline for Claude Code
333
+
334
+ Usage: claude-powerline [options]
335
+
336
+ Options:
337
+ --dark Use dark color scheme
338
+ --install-fonts Install powerline fonts to system
339
+ -h, --help Show this help
340
+
341
+ Usage in Claude Code settings.json:
342
+ {
343
+ "statusLine": {
344
+ "type": "command",
345
+ "command": "claude-powerline",
346
+ "padding": 0
347
+ }
348
+ }
349
+ `);
350
+ process.exit(0);
351
+ }
352
+ const stdin = await getStdin();
353
+ if (stdin.length === 0) {
354
+ console.error("Error: No input provided");
355
+ console.log(`
356
+ claude-powerline - Beautiful powerline statusline for Claude Code
357
+
358
+ Usage: claude-powerline [options]
359
+
360
+ Options:
361
+ --dark Use dark color scheme
362
+ --install-fonts Install powerline fonts to system
363
+ -h, --help Show this help
364
+
365
+ Usage in Claude Code settings.json:
366
+ {
367
+ "statusLine": {
368
+ "type": "command",
369
+ "command": "claude-powerline",
370
+ "padding": 0
371
+ }
372
+ }
373
+ `);
374
+ process.exit(1);
375
+ }
376
+ let hookData;
377
+ try {
378
+ hookData = JSON.parse(stdin.trim());
379
+ } catch (error) {
380
+ console.error(
381
+ "Error: Invalid JSON input:",
382
+ error instanceof Error ? error.message : String(error)
383
+ );
384
+ process.exit(1);
385
+ }
386
+ const renderer = new PowerlineRenderer();
387
+ const statusline = await renderer.generateStatusline(hookData, style);
388
+ console.log(statusline);
389
+ } catch (error) {
390
+ const errorMessage = error instanceof Error ? error.message : String(error);
391
+ console.error("Error generating statusline:", errorMessage);
392
+ process.exit(1);
393
+ }
394
+ }
395
+ main();
396
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/powerline.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport process from \"node:process\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport os from \"node:os\";\nimport getStdin from \"get-stdin\";\nimport { PowerlineRenderer } from \"./powerline.ts\";\nimport type { ClaudeHookData } from \"./types.ts\";\n\nasync function installFonts(): Promise<void> {\n try {\n const platform = os.platform();\n let fontDir: string;\n\n if (platform === \"darwin\") {\n fontDir = path.join(os.homedir(), \"Library\", \"Fonts\");\n } else if (platform === \"linux\") {\n fontDir = path.join(os.homedir(), \".local\", \"share\", \"fonts\");\n } else if (platform === \"win32\") {\n fontDir = path.join(\n os.homedir(),\n \"AppData\",\n \"Local\",\n \"Microsoft\",\n \"Windows\",\n \"Fonts\"\n );\n } else {\n console.log(\"Unsupported platform for font installation\");\n return;\n }\n\n if (!fs.existsSync(fontDir)) {\n fs.mkdirSync(fontDir, { recursive: true });\n }\n\n console.log(\"📦 Installing Powerline Fonts...\");\n console.log(\"Downloading from https://github.com/powerline/fonts\");\n\n const tempDir = path.join(os.tmpdir(), \"powerline-fonts\");\n\n try {\n if (fs.existsSync(tempDir)) {\n fs.rmSync(tempDir, { recursive: true, force: true });\n }\n\n console.log(\"Cloning powerline fonts repository...\");\n execSync(\n \"git clone --depth=1 https://github.com/powerline/fonts.git powerline-fonts\",\n {\n stdio: \"inherit\",\n cwd: os.tmpdir(),\n }\n );\n\n console.log(\"Installing fonts...\");\n const installScript = path.join(tempDir, \"install.sh\");\n\n if (fs.existsSync(installScript)) {\n fs.chmodSync(installScript, 0o755);\n execSync(\"./install.sh\", { stdio: \"inherit\", cwd: tempDir });\n } else {\n throw new Error(\n \"Install script not found in powerline fonts repository\"\n );\n }\n\n console.log(\"✅ Powerline fonts installation complete!\");\n console.log(\n \"Please restart your terminal and set your terminal font to a powerline font.\"\n );\n console.log(\n \"Popular choices: Source Code Pro Powerline, DejaVu Sans Mono Powerline, Ubuntu Mono Powerline\"\n );\n } finally {\n if (fs.existsSync(tempDir)) {\n fs.rmSync(tempDir, { recursive: true, force: true });\n }\n }\n } catch (error) {\n console.error(\n \"Error installing fonts:\",\n error instanceof Error ? error.message : String(error)\n );\n console.log(\n \"💡 You can manually install fonts from: https://github.com/powerline/fonts\"\n );\n }\n}\n\nasync function main(): Promise<void> {\n try {\n const style = process.argv.includes(\"--dark\") ? \"dark\" : \"colors\";\n const showHelp =\n process.argv.includes(\"--help\") || process.argv.includes(\"-h\");\n const installFontsFlag = process.argv.includes(\"--install-fonts\");\n\n if (installFontsFlag) {\n await installFonts();\n process.exit(0);\n }\n\n if (showHelp) {\n console.log(`\nclaude-powerline - Beautiful powerline statusline for Claude Code\n\nUsage: claude-powerline [options]\n\nOptions:\n --dark Use dark color scheme\n --install-fonts Install powerline fonts to system\n -h, --help Show this help\n\nUsage in Claude Code settings.json:\n{\n \"statusLine\": {\n \"type\": \"command\",\n \"command\": \"claude-powerline\",\n \"padding\": 0\n }\n}\n`);\n process.exit(0);\n }\n\n const stdin = await getStdin();\n if (stdin.length === 0) {\n console.error(\"Error: No input provided\");\n console.log(`\nclaude-powerline - Beautiful powerline statusline for Claude Code\n\nUsage: claude-powerline [options]\n\nOptions:\n --dark Use dark color scheme\n --install-fonts Install powerline fonts to system\n -h, --help Show this help\n\nUsage in Claude Code settings.json:\n{\n \"statusLine\": {\n \"type\": \"command\",\n \"command\": \"claude-powerline\",\n \"padding\": 0\n }\n}\n`);\n process.exit(1);\n }\n\n let hookData: ClaudeHookData;\n try {\n hookData = JSON.parse(stdin.trim());\n } catch (error) {\n console.error(\n \"Error: Invalid JSON input:\",\n error instanceof Error ? error.message : String(error)\n );\n process.exit(1);\n }\n\n const renderer = new PowerlineRenderer();\n const statusline = await renderer.generateStatusline(hookData, style);\n\n console.log(statusline);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(\"Error generating statusline:\", errorMessage);\n process.exit(1);\n }\n}\n\nmain();\n","import type { ClaudeHookData, PowerlineColors } from \"./types.ts\";\nimport { execSync } from \"node:child_process\";\nimport {\n loadSessionUsageById,\n loadDailyUsageData,\n getClaudePaths,\n} from \"ccusage/data-loader\";\nimport { calculateTotals } from \"ccusage/calculate-cost\";\nimport { logger } from \"ccusage/logger\";\n\ntype PowerlineStyle = \"colors\" | \"dark\";\n\ninterface PowerlineSymbols {\n right: string;\n branch: string;\n model: string;\n git_clean: string;\n git_dirty: string;\n git_conflicts: string;\n git_ahead: string;\n git_behind: string;\n session_cost: string;\n daily_cost: string;\n}\n\nexport class PowerlineRenderer {\n private readonly symbols: PowerlineSymbols;\n private readonly colors: Record<PowerlineStyle, PowerlineColors>;\n\n constructor() {\n this.symbols = this.initializeSymbols();\n this.colors = {\n colors: {\n reset: \"\\x1b[0m\",\n modeBg: \"\\x1b[48;2;255;107;71m\",\n modeFg: \"\\x1b[97m\",\n sessionBg: \"\\x1b[48;2;79;179;217m\",\n sessionFg: \"\\x1b[97m\",\n dailyBg: \"\\x1b[48;2;135;206;235m\",\n dailyFg: \"\\x1b[30m\",\n blockBg: \"\\x1b[48;2;218;112;214m\",\n blockFg: \"\\x1b[97m\",\n burnLowBg: \"\\x1b[48;2;144;238;144m\",\n burnFg: \"\\x1b[97m\",\n },\n dark: {\n reset: \"\\x1b[0m\",\n modeBg: \"\\x1b[48;2;139;69;19m\",\n modeFg: \"\\x1b[97m\",\n sessionBg: \"\\x1b[48;2;64;64;64m\",\n sessionFg: \"\\x1b[97m\",\n dailyBg: \"\\x1b[48;2;45;45;45m\",\n dailyFg: \"\\x1b[97m\",\n blockBg: \"\\x1b[48;2;32;32;32m\",\n blockFg: \"\\x1b[96m\",\n burnLowBg: \"\\x1b[48;2;28;28;28m\",\n burnFg: \"\\x1b[97m\",\n },\n };\n }\n\n private initializeSymbols(): PowerlineSymbols {\n return {\n right: \"\\uE0B0\",\n branch: \"\\uE0A0\",\n model: \"⚡\",\n git_clean: \"✓\",\n git_dirty: \"●\",\n git_conflicts: \"⚠\",\n git_ahead: \"↑\",\n git_behind: \"↓\",\n session_cost: \"Session\",\n daily_cost: \"Today\",\n };\n }\n\n private extractBgColor(ansiCode: string): string {\n const match = ansiCode.match(/48;2;(\\d+);(\\d+);(\\d+)/);\n if (match) {\n return `\\x1b[38;2;${match[1]};${match[2]};${match[3]}m`;\n }\n return ansiCode.replace(\"48\", \"38\");\n }\n\n private renderSegment(\n bgColor: string,\n fgColor: string,\n text: string,\n nextBgColor?: string\n ): string {\n let output = `${bgColor}${fgColor} ${text} `;\n\n if (nextBgColor) {\n const arrowFgColor = this.extractBgColor(bgColor);\n output += `${nextBgColor}${arrowFgColor}${this.symbols.right}`;\n } else {\n const arrowFgColor = this.extractBgColor(bgColor);\n output += `${this.colors.colors.reset}${arrowFgColor}${this.symbols.right}${this.colors.colors.reset}`;\n }\n\n return output;\n }\n\n private sanitizePath(path: string): string {\n return path.replace(/[;&|`$(){}[\\]<>'\"\\\\]/g, \"\");\n }\n\n private getGitInfo(\n workingDir: string\n ): { branch: string; status: string; ahead: number; behind: number } | null {\n try {\n const sanitizedDir = this.sanitizePath(workingDir);\n\n const branch = execSync(\"git branch --show-current 2>/dev/null\", {\n cwd: sanitizedDir,\n encoding: \"utf8\",\n timeout: 1000,\n }).trim();\n\n const gitStatus = execSync(\"git status --porcelain 2>/dev/null\", {\n cwd: sanitizedDir,\n encoding: \"utf8\",\n timeout: 1000,\n }).trim();\n\n let status = \"clean\";\n if (gitStatus) {\n if (\n gitStatus.includes(\"UU\") ||\n gitStatus.includes(\"AA\") ||\n gitStatus.includes(\"DD\")\n ) {\n status = \"conflicts\";\n } else {\n status = \"dirty\";\n }\n }\n\n let ahead = 0,\n behind = 0;\n try {\n const aheadResult = execSync(\n \"git rev-list --count @{u}..HEAD 2>/dev/null\",\n {\n cwd: sanitizedDir,\n encoding: \"utf8\",\n timeout: 1000,\n }\n ).trim();\n ahead = parseInt(aheadResult) || 0;\n\n const behindResult = execSync(\n \"git rev-list --count HEAD..@{u} 2>/dev/null\",\n {\n cwd: sanitizedDir,\n encoding: \"utf8\",\n timeout: 1000,\n }\n ).trim();\n behind = parseInt(behindResult) || 0;\n } catch {}\n\n return { branch: branch || \"detached\", status, ahead, behind };\n } catch {\n return null;\n }\n }\n\n private async getCostInfo(\n sessionId: string\n ): Promise<{ sessionCost: number | null; dailyCost: number }> {\n const originalLevel = logger.level;\n logger.level = 0;\n\n try {\n const claudePaths = getClaudePaths();\n if (claudePaths.length === 0) {\n logger.level = originalLevel;\n return { sessionCost: null, dailyCost: 0 };\n }\n\n let sessionCost: number | null = null;\n try {\n const sessionData = await loadSessionUsageById(sessionId, {\n mode: \"auto\",\n });\n if (sessionData != null) {\n sessionCost = sessionData.totalCost;\n }\n } catch {}\n\n let dailyCost = 0;\n try {\n const today = new Date();\n const todayStr =\n today.toISOString().split(\"T\")[0]?.replace(/-/g, \"\") ?? \"\";\n\n const dailyData = await loadDailyUsageData({\n since: todayStr,\n until: todayStr,\n mode: \"auto\",\n });\n\n if (dailyData.length > 0) {\n const totals = calculateTotals(dailyData);\n dailyCost = totals.totalCost;\n }\n } catch {}\n\n logger.level = originalLevel;\n return { sessionCost, dailyCost };\n } catch {\n logger.level = originalLevel;\n return { sessionCost: null, dailyCost: 0 };\n }\n }\n\n private formatCost(cost: number | null): string {\n if (cost === null) return \"N/A\";\n if (cost < 0.01) return \"<$0.01\";\n return `$${cost.toFixed(2)}`;\n }\n\n async generateStatusline(\n hookData: ClaudeHookData,\n style: PowerlineStyle = \"colors\"\n ): Promise<string> {\n const modelName = hookData.model?.display_name || \"Claude\";\n const currentDir = hookData.workspace?.current_dir || hookData.cwd || \"/\";\n const projectDir = hookData.workspace?.project_dir;\n\n let dirName: string;\n if (projectDir && projectDir !== currentDir) {\n const projectName = projectDir.split(\"/\").pop() || \"project\";\n const currentDirName = currentDir.split(\"/\").pop() || \"root\";\n dirName = currentDir.includes(projectDir)\n ? `${projectName}/${currentDirName}`\n : currentDirName;\n } else {\n dirName = currentDir.split(\"/\").pop() || \"root\";\n }\n const gitInfo = this.getGitInfo(currentDir);\n const sessionId = hookData.session_id;\n const costInfo = await this.getCostInfo(sessionId);\n\n const colors = this.colors[style];\n\n let statusline = \"\";\n\n statusline += this.renderSegment(\n colors.modeBg,\n colors.modeFg,\n dirName,\n gitInfo ? colors.sessionBg : colors.dailyBg\n );\n\n if (gitInfo) {\n let gitStatusIcon = this.symbols.git_clean;\n if (gitInfo.status === \"conflicts\") {\n gitStatusIcon = this.symbols.git_conflicts;\n } else if (gitInfo.status === \"dirty\") {\n gitStatusIcon = this.symbols.git_dirty;\n }\n\n let branchText = `${this.symbols.branch} ${gitInfo.branch} ${gitStatusIcon}`;\n\n if (gitInfo.ahead > 0 && gitInfo.behind > 0) {\n branchText += ` ${this.symbols.git_ahead}${gitInfo.ahead}${this.symbols.git_behind}${gitInfo.behind}`;\n } else if (gitInfo.ahead > 0) {\n branchText += ` ${this.symbols.git_ahead}${gitInfo.ahead}`;\n } else if (gitInfo.behind > 0) {\n branchText += ` ${this.symbols.git_behind}${gitInfo.behind}`;\n }\n\n statusline += this.renderSegment(\n colors.sessionBg,\n colors.sessionFg,\n branchText,\n colors.dailyBg\n );\n }\n\n statusline += this.renderSegment(\n colors.dailyBg,\n colors.dailyFg,\n `${this.symbols.model} ${modelName}`,\n colors.blockBg\n );\n\n statusline += this.renderSegment(\n colors.blockBg,\n colors.blockFg,\n `${this.symbols.session_cost} ${this.formatCost(costInfo.sessionCost)}`,\n colors.burnLowBg\n );\n\n statusline += this.renderSegment(\n colors.burnLowBg,\n colors.burnFg,\n `${this.symbols.daily_cost} ${this.formatCost(costInfo.dailyCost)}`\n );\n\n return statusline;\n }\n}\n"],"mappings":"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","names":["execSync","path","execSync"]}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@owloops/claude-powerline",
3
+ "version": "1.0.0",
4
+ "description": "Beautiful vim-style powerline statusline for Claude Code with real-time cost tracking, git integration, and custom themes",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "claude-powerline": "./dist/index.js"
11
+ },
12
+ "scripts": {
13
+ "build": "tsup",
14
+ "dev": "tsup --watch",
15
+ "start": "node dist/index.js",
16
+ "lint": "eslint src/",
17
+ "lint:fix": "eslint src/ --fix",
18
+ "test": "jest",
19
+ "test:watch": "jest --watch",
20
+ "test:coverage": "jest --coverage",
21
+ "prepublishOnly": "npm run lint && npm run build"
22
+ },
23
+ "keywords": [
24
+ "claude",
25
+ "powerline",
26
+ "statusline",
27
+ "typescript",
28
+ "claude-code"
29
+ ],
30
+ "author": "Owloops",
31
+ "license": "MIT",
32
+ "homepage": "https://github.com/Owloops/claude-powerline#readme",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/Owloops/claude-powerline.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/Owloops/claude-powerline/issues"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "README.md",
46
+ "LICENSE"
47
+ ],
48
+ "publishConfig": {
49
+ "access": "public",
50
+ "provenance": true
51
+ },
52
+ "dependencies": {
53
+ "ccusage": "^15.9.1",
54
+ "get-stdin": "^9.0.0"
55
+ },
56
+ "devDependencies": {
57
+ "@eslint/js": "^9.33.0",
58
+ "@semantic-release/changelog": "^6.0.3",
59
+ "@semantic-release/git": "^10.0.1",
60
+ "@types/jest": "^30.0.0",
61
+ "@types/node": "^20.0.0",
62
+ "@typescript-eslint/eslint-plugin": "^8.39.0",
63
+ "@typescript-eslint/parser": "^8.39.0",
64
+ "eslint": "^9.33.0",
65
+ "eslint-config-prettier": "^10.1.8",
66
+ "eslint-plugin-prettier": "^5.5.4",
67
+ "jest": "^30.0.5",
68
+ "prettier": "^3.6.2",
69
+ "semantic-release": "^24.2.7",
70
+ "ts-jest": "^29.4.1",
71
+ "tsup": "^8.5.0",
72
+ "typescript": "^5.0.0"
73
+ }
74
+ }