@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 +21 -0
- package/README.md +196 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +396 -0
- package/dist/index.js.map +1 -0
- package/package.json +74 -0
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
|
+

|
|
6
|
+

|
|
7
|
+
[](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
|
+

|
|
24
|
+
|
|
25
|
+
### Dark Theme
|
|
26
|
+
|
|
27
|
+

|
|
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).
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|