ctxline-claude 0.0.1 → 0.0.2

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 CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Mithun Wijayasiri
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.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mithun Wijayasiri
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 CHANGED
@@ -1,167 +1,154 @@
1
- # Claude Code Enhanced Statusline
2
-
3
- ![preview](preview.png)
4
-
5
- A real-time statusline for [Claude Code](https://github.com/anthropics/claude-code) that shows your current directory, model, context window usage, and session token limits at a glance. The usage bar pulls directly from Anthropic's API, the same data you get from `/usage`, so it's always accurate. One script, zero config. Auto-detects subscription vs API key.
6
-
7
- ## Why This Statusline
8
-
9
- Two metrics have the biggest impact on a Claude Code session: **context window usage** and **remaining session usage**. Model output quality tends to degrade as the context window fills (often called "context rot"), so keeping an eye on it helps you compact or reset at the right time. Session usage tells you how much of your current limit remains, so you can plan work before hitting a reset. This statusline surfaces both at a glance, letting you stay focused on the task rather than guessing where you stand.
10
-
11
- ## Requirements
12
-
13
- - [Claude Code](https://github.com/anthropics/claude-code) installed
14
- - Node.js (comes with Claude Code)
15
- - Authenticated Claude account (for usage tracking on subscription plans)
16
-
17
- ## Installation
18
-
19
- ### Quick Install (Recommended)
20
-
21
- ```bash
22
- npx ctxline-claude
23
- ```
24
-
25
- Or with bun:
26
-
27
- ```bash
28
- bunx ctxline-claude
29
- ```
30
-
31
- Restart Claude Code or start a new session.
32
-
33
- ### Clone & Install
34
-
35
- ```bash
36
- git clone https://github.com/MithunWijayasiri/claudecode-statusline.git
37
- cd claudecode-statusline
38
-
39
- # macOS / Linux
40
- ./install.sh
41
-
42
- # Windows (PowerShell)
43
- ./install.ps1
44
- ```
45
-
46
- ### Manual Install
47
-
48
- 1. **Download the script:**
49
-
50
- ```bash
51
- curl -o ~/.claude/hooks/statusline.js https://raw.githubusercontent.com/MithunWijayasiri/claudecode-statusline/main/statusline.js
52
- ```
53
-
54
- 2. **Make it executable:**
55
-
56
- ```bash
57
- chmod +x ~/.claude/hooks/statusline.js
58
- ```
59
-
60
- 3. **Update Claude Code settings:**
61
-
62
- Edit `~/.claude/settings.json` and add/modify the `statusLine` section:
63
-
64
- ```json
65
- {
66
- "statusLine": {
67
- "type": "command",
68
- "command": "node ~/.claude/hooks/statusline.js"
69
- }
70
- }
71
- ```
72
-
73
- 4. **Restart Claude Code** or start a new session.
74
-
75
- ## Uninstall
76
-
77
- ### Quick Uninstall (Recommended)
78
-
79
- ```bash
80
- npx ctxline-claude uninstall
81
- ```
82
-
83
- This removes the `statusLine` entry from `~/.claude/settings.json` (backing the file up first, and leaving any other settings intact), deletes `~/.claude/hooks/statusline.js`, and clears the cached usage data. Restart Claude Code afterward. If `settings.json` points to a different statusline, it's left untouched.
84
-
85
- ### Manual Uninstall
86
-
87
- The installer only does two things: it copies `statusline.js` into `~/.claude/hooks/` and adds a `statusLine` block to `~/.claude/settings.json`. To fully remove it, undo both.
88
-
89
- 1. **Remove the `statusLine` block from `~/.claude/settings.json`.**
90
-
91
- Open the file and delete this section:
92
-
93
- ```json
94
- "statusLine": {
95
- "type": "command",
96
- "command": "node ~/.claude/hooks/statusline.js"
97
- }
98
- ```
99
-
100
- (The installer saved a timestamped backup, e.g. `settings.json.backup.<number>`, if you'd rather restore that.)
101
-
102
- 2. **Delete the script (and optional cache):**
103
-
104
- ```bash
105
- # macOS / Linux
106
- rm ~/.claude/hooks/statusline.js
107
- rm -f ~/.claude/cache/usage-cache.json # optional: clears cached usage data
108
- ```
109
-
110
- ```powershell
111
- # Windows (PowerShell)
112
- Remove-Item "$env:USERPROFILE\.claude\hooks\statusline.js"
113
- Remove-Item "$env:USERPROFILE\.claude\cache\usage-cache.json" -ErrorAction SilentlyContinue
114
- ```
115
-
116
- 3. **Restart Claude Code** or start a new session. The statusline is gone.
117
-
118
- ## Features
119
-
120
- - **Context Usage**: Visual bar showing token usage (green → yellow → orange → red)
121
- - **API Usage**: Real-time 5-hour session limit tracking with countdown timer (subscription users)
122
- - **Current Directory**: Shows your working directory
123
- - **Model Name**: Displays which Claude model you're using (Opus, Sonnet, Haiku)
124
- - **Auto-Detection**: Detects API key vs subscription and adapts automatically
125
- - **Adaptive Performance**: Fast after first prompt (1.2s vs 1.5s)
126
- - **Smart Caching**: Shares usage data across sessions, fallback on API timeout
127
-
128
- **Color Coding:**
129
-
130
- - 🟢 Green: < 50% usage
131
- - 🟡 Yellow: 50-75% usage
132
- - 🟠 Orange: 75-90% usage
133
- - 🔴 Red (blinking): > 90% usage
134
-
135
- ## How It Works
136
-
137
- ### Adaptive Timing
138
-
139
- - **First prompt**: Uses 1500ms timeout (cold start, OAuth validation)
140
- - **Subsequent prompts**: Uses 1200ms timeout (faster, connection reused)
141
- - **Result**: Smooth experience after initial setup
142
-
143
- ### Caching System
144
-
145
- - Usage data is cached in `~/.claude/cache/usage-cache.json`, shared across all sessions
146
- - **Cache-first**: within 30 seconds the cache is used directly and the API call is skipped (faster renders, fewer calls)
147
- - **Stale fallback**: if a live API call fails or times out, the last known usage (up to 10 minutes old) is shown instead of disappearing
148
- - The reset countdown is recomputed on every render, so it keeps ticking even when shown from cache
149
-
150
- ### API Usage
151
-
152
- - Fetches from `https://api.anthropic.com/api/oauth/usage`
153
- - Tracks 5-hour session limits
154
- - Shows percentage used + time until reset
155
- - Fails gracefully (no statusline breakage)
156
-
157
- ## License
158
-
159
- MIT
160
-
161
- ## Credits
162
-
163
- Originally created by [@TahaSabir0](https://github.com/TahaSabir0).
164
-
165
- Built for the [Claude Code](https://github.com/anthropics/claude-code) community.
166
-
167
- ---
1
+ <h1 align="center">Claude Code Statusline</h1>
2
+
3
+ <p align="center">
4
+ A lightweight, zero-config statusline for Claude Code.
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/ctxline-claude">
9
+ <img src="https://img.shields.io/npm/v/ctxline-claude" alt="npm version">
10
+ </a>
11
+ <a href="https://www.npmjs.com/package/ctxline-claude">
12
+ <img src="https://img.shields.io/npm/dm/ctxline-claude" alt="npm downloads">
13
+ </a>
14
+ <a href="LICENSE">
15
+ <img src="https://img.shields.io/github/license/MithunWijayasiri/claudecode-statusline" alt="license">
16
+ </a>
17
+ <a href="https://github.com/MithunWijayasiri/claudecode-statusline/stargazers">
18
+ <img src="https://img.shields.io/github/stars/MithunWijayasiri/claudecode-statusline" alt="stars">
19
+ </a>
20
+ </p>
21
+
22
+ <p align="center">
23
+ <img src="preview.svg" alt="Claude Code Statusline">
24
+ </p>
25
+
26
+ <p align="center">
27
+ Monitor context usage, session limits, and weekly allowance without leaving Claude Code.
28
+ </p>
29
+
30
+ See your **current directory**, **active model**, **context window usage**, and **Claude usage limits** at a glance — including both your **current 5-hour session** and **weekly allowance**.
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ npx ctxline-claude # or: bunx ctxline-claude
36
+ ```
37
+
38
+ Then restart Claude Code or start a new session. That's it.
39
+
40
+ <details>
41
+ <summary>Other install methods</summary>
42
+
43
+ **Clone & run the installer:**
44
+
45
+ ```bash
46
+ git clone https://github.com/MithunWijayasiri/claudecode-statusline.git
47
+ cd claudecode-statusline
48
+ ./install.sh # macOS / Linux
49
+ ./install.ps1 # Windows (PowerShell)
50
+ ```
51
+
52
+ **Manual:** download the script, then point `~/.claude/settings.json` at it.
53
+
54
+ ```bash
55
+ curl -o ~/.claude/hooks/statusline.js https://raw.githubusercontent.com/MithunWijayasiri/claudecode-statusline/main/statusline.js
56
+ chmod +x ~/.claude/hooks/statusline.js
57
+ ```
58
+
59
+ ```json
60
+ {
61
+ "statusLine": {
62
+ "type": "command",
63
+ "command": "node ~/.claude/hooks/statusline.js"
64
+ }
65
+ }
66
+ ```
67
+
68
+ </details>
69
+
70
+ ## Uninstall
71
+
72
+ ```bash
73
+ npx ctxline-claude uninstall
74
+ ```
75
+
76
+ Removes the `statusLine` entry from `settings.json` (backed up first, other settings untouched), deletes the hook script, and clears the usage cache. If `settings.json` points at a different statusline, it's left alone.
77
+
78
+ <details>
79
+ <summary>Manual uninstall</summary>
80
+
81
+ Undo the two things the installer did — remove the `statusLine` block from `~/.claude/settings.json` (a timestamped `settings.json.backup.<n>` exists if you'd rather restore), then delete the script:
82
+
83
+ ```bash
84
+ # macOS / Linux
85
+ rm ~/.claude/hooks/statusline.js
86
+ rm -f ~/.claude/cache/usage-cache.json # optional: clears cached usage
87
+ ```
88
+
89
+ ```powershell
90
+ # Windows (PowerShell)
91
+ Remove-Item "$env:USERPROFILE\.claude\hooks\statusline.js"
92
+ Remove-Item "$env:USERPROFILE\.claude\cache\usage-cache.json" -ErrorAction SilentlyContinue
93
+ ```
94
+
95
+ </details>
96
+
97
+ ## What it shows
98
+
99
+ | Segment | Detail |
100
+ |---|---|
101
+ | **Directory** | Current working directory |
102
+ | **Model** | Active Claude model (Opus / Sonnet / Haiku) |
103
+ | **Context** | Visual bar of context-window usage |
104
+ | **Current** | Live 5-hour session limit + reset countdown (subscription users) |
105
+ | **Weekly** | Weekly usage allowance + time until the weekly reset (subscription users) |
106
+ | **Task** | The in-progress todo, when there is one |
107
+
108
+ > \[!NOTE\] Usage bars change color automatically as you approach your
109
+ > limits.
110
+
111
+ ## How it works
112
+
113
+ - **Source** — context comes from Claude Code's session data; both usage bars are fetched from `https://api.anthropic.com/api/oauth/usage` (the `/usage` data — 5-hour and weekly limits). API-key users skip the usage fetch.
114
+ - **Adaptive timing** — 1.5s timeout on the first prompt (cold start), 1.2s after (connection reused).
115
+ - **Caching** — usage is cached at `~/.claude/cache/usage-cache.json`, shared across sessions. Within 30s the cache renders directly (the API call is skipped); if a live call fails, the last value (up to 10 min old) is shown so the bar never vanishes. The reset countdown recomputes every render.
116
+ - **Never breaks** every failure path falls back silently; the statusline always prints.
117
+
118
+ ## FAQ
119
+
120
+ <details>
121
+ <summary>Does this use the same data as /usage?</summary>
122
+
123
+ Yes. Usage information comes directly from Anthropic's usage API.
124
+
125
+ </details>
126
+
127
+ <details>
128
+ <summary>Does it work with API keys?</summary>
129
+
130
+ Yes. The statusline automatically detects subscription vs API-key usage.
131
+
132
+ </details>
133
+
134
+ <details>
135
+ <summary>Can it break Claude Code?</summary>
136
+
137
+ No. All failures are handled silently and the statusline always renders.
138
+
139
+ </details>
140
+
141
+ <details>
142
+ <summary>Does it expose my API keys / auth tokens?</summary>
143
+
144
+ No. Your credentials never leave your machine. The OAuth token is read locally (from `~/.claude/.credentials.json` or the macOS keychain) only to authenticate the request to Anthropic's own usage API — the same endpoint `/usage` uses. Nothing is sent to any third party, logged, or cached; only the resulting usage percentages are stored locally.
145
+
146
+ </details>
147
+
148
+ ## License
149
+
150
+ MIT
151
+
152
+ ## Credits
153
+
154
+ Thanks to [@TahaSabir0](https://github.com/TahaSabir0) for the base config.
package/bin/install.js CHANGED
@@ -1,135 +1,135 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
-
7
- const claudeDir = path.join(os.homedir(), '.claude');
8
- const hooksDir = path.join(claudeDir, 'hooks');
9
- const settingsFile = path.join(claudeDir, 'settings.json');
10
- const scriptDest = path.join(hooksDir, 'statusline.js');
11
- const scriptSrc = path.join(__dirname, '..', 'statusline.js');
12
-
13
- const green = '\x1b[32m';
14
- const red = '\x1b[31m';
15
- const yellow = '\x1b[33m';
16
- const cyan = '\x1b[36m';
17
- const reset = '\x1b[0m';
18
-
19
- // Uninstall mode: `npx ctxline-claude uninstall` (additive — plain install is unchanged)
20
- const mode = (process.argv[2] || '').toLowerCase();
21
- if (mode === 'uninstall' || mode === 'remove') {
22
- runUninstall();
23
- process.exit(0);
24
- }
25
-
26
- console.log(`${cyan}======================================${reset}`);
27
- console.log(`${cyan} Claude Code Statusline Installer${reset}`);
28
- console.log(`${cyan}======================================${reset}\n`);
29
-
30
- // Check Claude Code is installed
31
- if (!fs.existsSync(claudeDir)) {
32
- console.log(`${red}Error: Claude Code not found!${reset}`);
33
- console.log('Please install Claude Code first: https://github.com/anthropics/claude-code');
34
- process.exit(1);
35
- }
36
-
37
- // Create hooks directory
38
- if (!fs.existsSync(hooksDir)) {
39
- fs.mkdirSync(hooksDir, { recursive: true });
40
- }
41
-
42
- // Copy statusline script
43
- console.log(`${yellow}Installing statusline...${reset}`);
44
- fs.copyFileSync(scriptSrc, scriptDest);
45
- fs.chmodSync(scriptDest, 0o755);
46
- console.log(`${green}✓ Installed statusline.js${reset}`);
47
-
48
- // Update settings.json
49
- console.log(`${yellow}Updating settings...${reset}`);
50
-
51
- let settings = {};
52
- if (fs.existsSync(settingsFile)) {
53
- // Backup existing settings
54
- const backup = `${settingsFile}.backup.${Date.now()}`;
55
- fs.copyFileSync(settingsFile, backup);
56
- console.log(`${green}✓ Backed up existing settings${reset}`);
57
-
58
- try {
59
- settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
60
- } catch (e) {
61
- settings = {};
62
- }
63
- }
64
-
65
- settings.statusLine = {
66
- type: 'command',
67
- command: `node ${scriptDest.replace(/\\/g, '/')}`
68
- };
69
-
70
- fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2));
71
- console.log(`${green}✓ Updated settings.json${reset}`);
72
-
73
- console.log(`\n${green}======================================${reset}`);
74
- console.log(`${green} Installation Complete!${reset}`);
75
- console.log(`${green}======================================${reset}`);
76
- console.log('\nRestart Claude Code or start a new session.');
77
- console.log('The statusline will auto-detect your setup (subscription vs API key).\n');
78
-
79
- function runUninstall() {
80
- console.log(`${cyan}======================================${reset}`);
81
- console.log(`${cyan} Claude Code Statusline Uninstaller${reset}`);
82
- console.log(`${cyan}======================================${reset}\n`);
83
-
84
- if (!fs.existsSync(claudeDir)) {
85
- console.log(`${yellow}Nothing to remove — ~/.claude was not found.${reset}\n`);
86
- return;
87
- }
88
-
89
- // 1. Remove our statusLine entry from settings.json (preserving everything else)
90
- if (fs.existsSync(settingsFile)) {
91
- try {
92
- const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
93
- const command = ((settings.statusLine && settings.statusLine.command) || '').replace(/\\/g, '/');
94
- // Match our hook path only (covers absolute + manual `~` installs), not any statusline.js.
95
- const isOurs = command.includes('/.claude/hooks/statusline.js');
96
- if (settings.statusLine && isOurs) {
97
- const backup = `${settingsFile}.backup.${Date.now()}`;
98
- fs.copyFileSync(settingsFile, backup);
99
- delete settings.statusLine;
100
- fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2));
101
- console.log(`${green}✓ Removed statusLine from settings.json (backup: ${path.basename(backup)})${reset}`);
102
- } else if (settings.statusLine) {
103
- console.log(`${yellow}! settings.json has a different statusLine — leaving it untouched.${reset}`);
104
- } else {
105
- console.log(`${green}✓ No statusLine entry in settings.json${reset}`);
106
- }
107
- } catch (e) {
108
- console.log(`${red}✗ Could not parse settings.json — remove the "statusLine" block manually.${reset}`);
109
- }
110
- }
111
-
112
- // 2. Delete the hook script
113
- if (fs.existsSync(scriptDest)) {
114
- try {
115
- fs.unlinkSync(scriptDest);
116
- console.log(`${green}✓ Deleted ${scriptDest}${reset}`);
117
- } catch (e) {
118
- console.log(`${red}✗ Could not delete ${scriptDest}: ${e.message}${reset}`);
119
- console.log(`${yellow} Remove it manually.${reset}`);
120
- }
121
- } else {
122
- console.log(`${green}✓ No statusline.js found in hooks${reset}`);
123
- }
124
-
125
- // 3. Clear cached usage data (best-effort)
126
- const cacheFile = path.join(claudeDir, 'cache', 'usage-cache.json');
127
- if (fs.existsSync(cacheFile)) {
128
- try {
129
- fs.unlinkSync(cacheFile);
130
- console.log(`${green}✓ Cleared usage cache${reset}`);
131
- } catch (e) {}
132
- }
133
-
134
- console.log(`\n${green}Uninstall complete.${reset} Restart Claude Code or start a new session.\n`);
135
- }
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+
7
+ const claudeDir = path.join(os.homedir(), '.claude');
8
+ const hooksDir = path.join(claudeDir, 'hooks');
9
+ const settingsFile = path.join(claudeDir, 'settings.json');
10
+ const scriptDest = path.join(hooksDir, 'statusline.js');
11
+ const scriptSrc = path.join(__dirname, '..', 'statusline.js');
12
+
13
+ const green = '\x1b[32m';
14
+ const red = '\x1b[31m';
15
+ const yellow = '\x1b[33m';
16
+ const cyan = '\x1b[36m';
17
+ const reset = '\x1b[0m';
18
+
19
+ // Uninstall mode: `npx ctxline-claude uninstall` (additive — plain install is unchanged)
20
+ const mode = (process.argv[2] || '').toLowerCase();
21
+ if (mode === 'uninstall' || mode === 'remove') {
22
+ runUninstall();
23
+ process.exit(0);
24
+ }
25
+
26
+ console.log(`${cyan}======================================${reset}`);
27
+ console.log(`${cyan} Claude Code Statusline Installer${reset}`);
28
+ console.log(`${cyan}======================================${reset}\n`);
29
+
30
+ // Check Claude Code is installed
31
+ if (!fs.existsSync(claudeDir)) {
32
+ console.log(`${red}Error: Claude Code not found!${reset}`);
33
+ console.log('Please install Claude Code first: https://github.com/anthropics/claude-code');
34
+ process.exit(1);
35
+ }
36
+
37
+ // Create hooks directory
38
+ if (!fs.existsSync(hooksDir)) {
39
+ fs.mkdirSync(hooksDir, { recursive: true });
40
+ }
41
+
42
+ // Copy statusline script
43
+ console.log(`${yellow}Installing statusline...${reset}`);
44
+ fs.copyFileSync(scriptSrc, scriptDest);
45
+ fs.chmodSync(scriptDest, 0o755);
46
+ console.log(`${green}✓ Installed statusline.js${reset}`);
47
+
48
+ // Update settings.json
49
+ console.log(`${yellow}Updating settings...${reset}`);
50
+
51
+ let settings = {};
52
+ if (fs.existsSync(settingsFile)) {
53
+ // Backup existing settings
54
+ const backup = `${settingsFile}.backup.${Date.now()}`;
55
+ fs.copyFileSync(settingsFile, backup);
56
+ console.log(`${green}✓ Backed up existing settings${reset}`);
57
+
58
+ try {
59
+ settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
60
+ } catch (e) {
61
+ settings = {};
62
+ }
63
+ }
64
+
65
+ settings.statusLine = {
66
+ type: 'command',
67
+ command: `node ${scriptDest.replace(/\\/g, '/')}`
68
+ };
69
+
70
+ fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2));
71
+ console.log(`${green}✓ Updated settings.json${reset}`);
72
+
73
+ console.log(`\n${green}======================================${reset}`);
74
+ console.log(`${green} Installation Complete!${reset}`);
75
+ console.log(`${green}======================================${reset}`);
76
+ console.log('\nRestart Claude Code or start a new session.');
77
+ console.log('The statusline will auto-detect your setup (subscription vs API key).\n');
78
+
79
+ function runUninstall() {
80
+ console.log(`${cyan}======================================${reset}`);
81
+ console.log(`${cyan} Claude Code Statusline Uninstaller${reset}`);
82
+ console.log(`${cyan}======================================${reset}\n`);
83
+
84
+ if (!fs.existsSync(claudeDir)) {
85
+ console.log(`${yellow}Nothing to remove — ~/.claude was not found.${reset}\n`);
86
+ return;
87
+ }
88
+
89
+ // 1. Remove our statusLine entry from settings.json (preserving everything else)
90
+ if (fs.existsSync(settingsFile)) {
91
+ try {
92
+ const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
93
+ const command = ((settings.statusLine && settings.statusLine.command) || '').replace(/\\/g, '/');
94
+ // Match our hook path only (covers absolute + manual `~` installs), not any statusline.js.
95
+ const isOurs = command.includes('/.claude/hooks/statusline.js');
96
+ if (settings.statusLine && isOurs) {
97
+ const backup = `${settingsFile}.backup.${Date.now()}`;
98
+ fs.copyFileSync(settingsFile, backup);
99
+ delete settings.statusLine;
100
+ fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2));
101
+ console.log(`${green}✓ Removed statusLine from settings.json (backup: ${path.basename(backup)})${reset}`);
102
+ } else if (settings.statusLine) {
103
+ console.log(`${yellow}! settings.json has a different statusLine — leaving it untouched.${reset}`);
104
+ } else {
105
+ console.log(`${green}✓ No statusLine entry in settings.json${reset}`);
106
+ }
107
+ } catch (e) {
108
+ console.log(`${red}✗ Could not parse settings.json — remove the "statusLine" block manually.${reset}`);
109
+ }
110
+ }
111
+
112
+ // 2. Delete the hook script
113
+ if (fs.existsSync(scriptDest)) {
114
+ try {
115
+ fs.unlinkSync(scriptDest);
116
+ console.log(`${green}✓ Deleted ${scriptDest}${reset}`);
117
+ } catch (e) {
118
+ console.log(`${red}✗ Could not delete ${scriptDest}: ${e.message}${reset}`);
119
+ console.log(`${yellow} Remove it manually.${reset}`);
120
+ }
121
+ } else {
122
+ console.log(`${green}✓ No statusline.js found in hooks${reset}`);
123
+ }
124
+
125
+ // 3. Clear cached usage data (best-effort)
126
+ const cacheFile = path.join(claudeDir, 'cache', 'usage-cache.json');
127
+ if (fs.existsSync(cacheFile)) {
128
+ try {
129
+ fs.unlinkSync(cacheFile);
130
+ console.log(`${green}✓ Cleared usage cache${reset}`);
131
+ } catch (e) {}
132
+ }
133
+
134
+ console.log(`\n${green}Uninstall complete.${reset} Restart Claude Code or start a new session.\n`);
135
+ }