@chongdashu/cc-statusline 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/CHANGELOG.md ADDED
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2025-08-13
9
+
10
+ ### Added
11
+ - Initial release of cc-statusline
12
+ - Interactive configuration wizard with 2 simple prompts
13
+ - Bash script generation with optimized performance
14
+ - Real-time ccusage integration for usage statistics
15
+ - Preview mode for testing statusline scripts with mock data
16
+ - Auto-installation with settings.json configuration
17
+ - Support for directory, git, model, usage, session, token, and burn rate features
18
+ - TTY-aware color support with NO_COLOR environment variable respect
19
+ - Manual configuration instructions when auto-update fails
20
+ - Comprehensive documentation and examples
21
+ - Performance analysis and validation in preview mode
22
+ - Timestamp and npm URL in generated script headers
23
+
24
+ ### Features
25
+ - šŸ“ Working Directory display with `~` abbreviation
26
+ - 🌿 Git Branch integration
27
+ - šŸ¤– Model Name & Version display
28
+ - šŸ’µ Real-time Usage & Cost tracking
29
+ - āŒ› Session Time Remaining with progress bars
30
+ - šŸ“Š Token Statistics (optional)
31
+ - ⚔ Burn Rate monitoring (optional)
32
+
33
+ ### Technical
34
+ - TypeScript with strict type checking
35
+ - ESM module support
36
+ - Commander.js for CLI interface
37
+ - Inquirer.js for interactive prompts
38
+ - Chalk for colorized output
39
+ - Ora for loading spinners
40
+ - Comprehensive error handling and validation
41
+ - Modular architecture for easy maintenance
42
+
43
+ [1.0.0]: https://github.com/chongdashu/cc-statusline/releases/tag/v1.0.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Chong-U Lim (AIOriented)
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,211 @@
1
+ # cc-statusline
2
+
3
+ šŸš€ **Dead simple statusline generator for Claude Code**
4
+
5
+ Transform your Claude Code experience with a beautiful, informative statusline showing directory, git branch, model info, usage stats, and more.
6
+
7
+ ## ⚔ Super Quick Start
8
+
9
+ **Just run this one command:**
10
+
11
+ ```bash
12
+ npx @chongdashu/cc-statusline init
13
+ ```
14
+
15
+ That's it! Answer 2 simple questions and restart Claude Code. Done! šŸŽ‰
16
+
17
+ ### What you get:
18
+ - šŸ“ Current directory
19
+ - 🌿 Git branch
20
+ - šŸ¤– Claude model info
21
+ - šŸ’µ Real-time costs
22
+ - āŒ› Session time remaining
23
+ - Plus optional token stats and burn rate
24
+
25
+ ### Sample result:
26
+ ```
27
+ šŸ“ ~/my-project 🌿 main šŸ¤– Opus 4.1 šŸ’µ $2.48 ($12.50/h) āŒ› 2h 15m until reset (68%)
28
+ ```
29
+
30
+ ## šŸŽÆ More Options
31
+
32
+ ```bash
33
+ # Preview an existing statusline.sh with mock data
34
+ cc-statusline preview .claude/statusline.sh
35
+
36
+ # Generate to custom location
37
+ cc-statusline init --output ./my-statusline.sh
38
+
39
+ # Skip auto-installation
40
+ cc-statusline init --no-install
41
+ ```
42
+
43
+ **How preview works:**
44
+ The `preview` command takes a path to an existing `statusline.sh` file and:
45
+ 1. **Loads** your actual statusline script
46
+ 2. **Runs** it with fake Claude Code data (directory: `/home/user/projects/my-project`, model: `Opus 4.1`, mock usage stats)
47
+ 3. **Shows** you exactly what the output looks like
48
+ 4. **Reports** performance and basic functionality
49
+
50
+ Perfect for testing your statusline changes before restarting Claude Code.
51
+
52
+ ### Global Installation
53
+ ```bash
54
+ # If you prefer global install
55
+ npm install -g @chongdashu/cc-statusline
56
+ cc-statusline init
57
+ ```
58
+
59
+ ## šŸŽ›ļø Available Features
60
+
61
+ **Default features (pre-selected):**
62
+ - šŸ“ **Working Directory** - Current folder with `~` shorthand
63
+ - 🌿 **Git Branch** - Current branch name
64
+ - šŸ¤– **Model Name** - Which Claude model you're using
65
+ - šŸ’µ **Usage & Cost** - Real-time cost tracking (requires ccusage)
66
+ - āŒ› **Session Time** - Time until usage limit resets
67
+
68
+ **Optional features:**
69
+ - šŸ“Š **Token Statistics** - Total tokens used this session
70
+ - ⚔ **Burn Rate** - Tokens consumed per minute
71
+
72
+ ## āš™ļø How It Works
73
+
74
+ **Two simple questions:**
75
+ 1. **What to show** - Pick features from a checklist (directory, git, model, costs, etc.)
76
+ 2. **Colors & emojis** - Enable/disable colors and emoji icons
77
+
78
+ **Then it:**
79
+ - Generates a bash script optimized for speed
80
+ - Auto-installs to `.claude/statusline.sh`
81
+ - Updates your `.claude/settings.json`
82
+ - Shows you a preview of what it looks like
83
+
84
+ **Requirements:**
85
+ - Claude Code (obviously! šŸ˜„)
86
+ - `jq` command (usually pre-installed)
87
+ - `ccusage` for usage stats (works via `npx ccusage@latest` - no install needed)
88
+
89
+ ## šŸŽØ Example Outputs
90
+
91
+ **Minimal setup:**
92
+ ```
93
+ šŸ“ ~/my-app 🌿 main šŸ¤– Claude Sonnet
94
+ ```
95
+
96
+ **With usage tracking:**
97
+ ```
98
+ šŸ“ ~/my-app 🌿 main šŸ¤– Opus 4.1 šŸ’µ $2.48 ($12.50/h)
99
+ ```
100
+
101
+ **Full features:**
102
+ ```
103
+ šŸ“ ~/projects/my-app 🌿 main šŸ¤– Opus 4.1 āŒ› 2h 15m until reset (68%) [======----] šŸ’µ $2.48 ($12.50/h)
104
+ ```
105
+
106
+ ## šŸ“‹ Dependencies
107
+
108
+ **Required:**
109
+ - Claude Code (the tool you're already using!)
110
+ - `jq` for JSON processing (pre-installed on most systems)
111
+
112
+ **Optional:**
113
+ - `git` for branch display
114
+ - `ccusage` for usage stats (auto-installs via npx when needed)
115
+
116
+ **Check if you're ready:**
117
+ ```bash
118
+ command -v jq && echo "āœ… Ready to go!"
119
+ ```
120
+
121
+ ## šŸ“‚ What Gets Created
122
+
123
+ After running `cc-statusline init`, you'll have:
124
+
125
+ ```
126
+ .claude/
127
+ ā”œā”€ā”€ statusline.sh # Your custom statusline script
128
+ └── settings.json # Auto-updated with statusline config
129
+ ```
130
+
131
+ **Manual Setup (if auto-config fails):**
132
+ If the tool can't update your settings.json automatically, just add this:
133
+
134
+ ```json
135
+ {
136
+ "statusLine": {
137
+ "type": "command",
138
+ "command": ".claude/statusline.sh",
139
+ "padding": 0
140
+ }
141
+ }
142
+ ```
143
+
144
+ ## Troubleshooting
145
+
146
+ ### Statusline not showing
147
+ 1. Restart Claude Code after installation
148
+ 2. Verify `.claude/settings.json` contains:
149
+ ```json
150
+ {
151
+ "statusLine": {
152
+ "type": "command",
153
+ "command": ".claude/statusline.sh",
154
+ "padding": 0
155
+ }
156
+ }
157
+ ```
158
+
159
+ ### Performance Issues
160
+ - Use `cc-statusline preview` to check execution time
161
+ - Reduce number of features if >500ms execution time
162
+ - Disable ccusage integration if not needed
163
+
164
+ ### Missing Features
165
+ - Ensure `jq` is installed: `brew install jq` (macOS) or `apt install jq` (Ubuntu)
166
+ - Usage stats require ccusage (works automatically via `npx ccusage@latest`)
167
+ - Check script permissions: `chmod +x .claude/statusline.sh`
168
+
169
+ ## Development
170
+
171
+ ```bash
172
+ # Clone repository
173
+ git clone https://github.com/chongdashu/cc-statusline
174
+ cd cc-statusline
175
+
176
+ # Install dependencies
177
+ npm install
178
+
179
+ # Build project
180
+ npm run build
181
+
182
+ # Test locally
183
+ npm run dev
184
+ ```
185
+
186
+ ## Contributing
187
+
188
+ Contributions welcome! Please read our [Contributing Guide](CONTRIBUTING.md).
189
+
190
+ 1. Fork the repository
191
+ 2. Create feature branch (`git checkout -b feature/amazing-feature`)
192
+ 3. Commit changes (`git commit -m 'Add amazing feature'`)
193
+ 4. Push to branch (`git push origin feature/amazing-feature`)
194
+ 5. Open Pull Request
195
+
196
+ ## License
197
+
198
+ MIT License - see [LICENSE](LICENSE) file for details.
199
+
200
+ ## Related Projects
201
+
202
+ - [ccusage](https://github.com/ryoppippi/ccusage) - Claude Code usage analytics
203
+ - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) - Official documentation
204
+
205
+ ## Changelog
206
+
207
+ See [CHANGELOG.md](CHANGELOG.md) for detailed release history.
208
+
209
+ ---
210
+
211
+ **Made by [Chong-U](https://github.com/chongdashu) @ [AIOriented](https://aioriented.dev)**
package/dist/index.js ADDED
@@ -0,0 +1,789 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // node_modules/tsup/assets/esm_shims.js
13
+ import path from "path";
14
+ import { fileURLToPath } from "url";
15
+ var init_esm_shims = __esm({
16
+ "node_modules/tsup/assets/esm_shims.js"() {
17
+ "use strict";
18
+ }
19
+ });
20
+
21
+ // src/utils/tester.ts
22
+ var tester_exports = {};
23
+ __export(tester_exports, {
24
+ analyzeTestResult: () => analyzeTestResult,
25
+ generateMockCcusageOutput: () => generateMockCcusageOutput,
26
+ generateMockClaudeInput: () => generateMockClaudeInput,
27
+ testStatuslineScript: () => testStatuslineScript
28
+ });
29
+ import { spawn } from "child_process";
30
+ import { promises as fs2 } from "fs";
31
+ import path3 from "path";
32
+ async function testStatuslineScript(script, mockData) {
33
+ const startTime = Date.now();
34
+ try {
35
+ const tempDir = "/tmp";
36
+ const scriptPath = path3.join(tempDir, `statusline-test-${Date.now()}.sh`);
37
+ await fs2.writeFile(scriptPath, script, { mode: 493 });
38
+ const input = mockData || generateMockClaudeInput();
39
+ const result = await executeScript(scriptPath, JSON.stringify(input));
40
+ await fs2.unlink(scriptPath).catch(() => {
41
+ });
42
+ const executionTime = Date.now() - startTime;
43
+ return {
44
+ success: result.success,
45
+ output: result.output,
46
+ error: result.error,
47
+ executionTime
48
+ };
49
+ } catch (error) {
50
+ return {
51
+ success: false,
52
+ output: "",
53
+ error: error instanceof Error ? error.message : String(error),
54
+ executionTime: Date.now() - startTime
55
+ };
56
+ }
57
+ }
58
+ function generateMockClaudeInput(config) {
59
+ return {
60
+ session_id: "test-session-123",
61
+ transcript_path: "/home/user/.claude/conversations/test.jsonl",
62
+ cwd: "/home/user/projects/my-project",
63
+ workspace: {
64
+ current_dir: "/home/user/projects/my-project"
65
+ },
66
+ model: {
67
+ id: "claude-opus-4-1-20250805",
68
+ display_name: "Opus 4.1",
69
+ version: "20250805"
70
+ }
71
+ };
72
+ }
73
+ function generateMockCcusageOutput() {
74
+ return {
75
+ blocks: [
76
+ {
77
+ id: "2025-08-13T08:00:00.000Z",
78
+ startTime: "2025-08-13T08:00:00.000Z",
79
+ endTime: "2025-08-13T13:00:00.000Z",
80
+ usageLimitResetTime: "2025-08-13T13:00:00.000Z",
81
+ actualEndTime: "2025-08-13T09:30:34.698Z",
82
+ isActive: true,
83
+ isGap: false,
84
+ entries: 12,
85
+ tokenCounts: {
86
+ inputTokens: 1250,
87
+ outputTokens: 2830,
88
+ cacheCreationInputTokens: 15e3,
89
+ cacheReadInputTokens: 45e3
90
+ },
91
+ totalTokens: 64080,
92
+ costUSD: 3.42,
93
+ models: ["claude-opus-4-1-20250805"],
94
+ burnRate: {
95
+ tokensPerMinute: 850.5,
96
+ tokensPerMinuteForIndicator: 850,
97
+ costPerHour: 12.45
98
+ },
99
+ projection: {
100
+ totalTokens: 128e3,
101
+ totalCost: 6.84,
102
+ remainingMinutes: 210
103
+ }
104
+ }
105
+ ]
106
+ };
107
+ }
108
+ async function executeScript(scriptPath, input) {
109
+ return new Promise((resolve) => {
110
+ const process2 = spawn("bash", [scriptPath], {
111
+ stdio: ["pipe", "pipe", "pipe"]
112
+ });
113
+ let stdout = "";
114
+ let stderr = "";
115
+ process2.stdout.on("data", (data) => {
116
+ stdout += data.toString();
117
+ });
118
+ process2.stderr.on("data", (data) => {
119
+ stderr += data.toString();
120
+ });
121
+ process2.on("close", (code) => {
122
+ resolve({
123
+ success: code === 0,
124
+ output: stdout.trim(),
125
+ error: stderr.trim() || void 0
126
+ });
127
+ });
128
+ process2.on("error", (err) => {
129
+ resolve({
130
+ success: false,
131
+ output: "",
132
+ error: err.message
133
+ });
134
+ });
135
+ process2.stdin.write(input);
136
+ process2.stdin.end();
137
+ setTimeout(() => {
138
+ process2.kill();
139
+ resolve({
140
+ success: false,
141
+ output: stdout,
142
+ error: "Script execution timed out (5s)"
143
+ });
144
+ }, 5e3);
145
+ });
146
+ }
147
+ function analyzeTestResult(result, config) {
148
+ const issues = [];
149
+ const suggestions = [];
150
+ let performance;
151
+ if (result.executionTime > 1e3) {
152
+ performance = "timeout";
153
+ issues.push("Script execution is very slow (>1s)");
154
+ } else if (result.executionTime > 500) {
155
+ performance = "slow";
156
+ issues.push("Script execution is slow (>500ms)");
157
+ } else if (result.executionTime > 100) {
158
+ performance = "good";
159
+ } else {
160
+ performance = "excellent";
161
+ }
162
+ let hasRequiredFeatures = true;
163
+ if (config.features.includes("directory") && !result.output.includes("projects")) {
164
+ hasRequiredFeatures = false;
165
+ issues.push("Directory feature not working properly");
166
+ }
167
+ if (config.features.includes("model") && !result.output.includes("Opus")) {
168
+ hasRequiredFeatures = false;
169
+ issues.push("Model feature not working properly");
170
+ }
171
+ if (config.features.includes("git") && config.ccusageIntegration && !result.output.includes("git")) {
172
+ suggestions.push("Git integration may require actual git repository");
173
+ }
174
+ if (result.error) {
175
+ issues.push(`Script errors: ${result.error}`);
176
+ }
177
+ if (!result.success) {
178
+ issues.push("Script failed to execute successfully");
179
+ }
180
+ if (config.features.length > 6) {
181
+ suggestions.push("Consider reducing number of features for better performance");
182
+ }
183
+ if (config.ccusageIntegration && result.executionTime > 200) {
184
+ suggestions.push("ccusage integration may slow down statusline - consider caching");
185
+ }
186
+ return {
187
+ performance,
188
+ hasRequiredFeatures,
189
+ issues,
190
+ suggestions
191
+ };
192
+ }
193
+ var init_tester = __esm({
194
+ "src/utils/tester.ts"() {
195
+ "use strict";
196
+ init_esm_shims();
197
+ }
198
+ });
199
+
200
+ // src/cli/preview.ts
201
+ var preview_exports = {};
202
+ __export(preview_exports, {
203
+ previewCommand: () => previewCommand
204
+ });
205
+ import { promises as fs3 } from "fs";
206
+ import chalk2 from "chalk";
207
+ import ora2 from "ora";
208
+ async function previewCommand(scriptPath) {
209
+ console.log(chalk2.cyan("\u{1F50D} Statusline Preview Mode\n"));
210
+ let script;
211
+ try {
212
+ const spinner = ora2(`Loading statusline script from ${scriptPath}...`).start();
213
+ script = await fs3.readFile(scriptPath, "utf-8");
214
+ spinner.succeed("Script loaded!");
215
+ const headerMatch = script.match(/# Theme: (\w+) \| Colors: (\w+) \| Features: ([^\n]+)/i);
216
+ if (headerMatch) {
217
+ console.log(chalk2.yellow("Detected Configuration:"));
218
+ console.log(` Theme: ${headerMatch[1]}`);
219
+ console.log(` Colors: ${headerMatch[2]}`);
220
+ console.log(` Features: ${headerMatch[3]}
221
+ `);
222
+ }
223
+ const generationMatch = script.match(/# Generated by cc-statusline.*\n# Custom Claude Code statusline - Created: ([^\n]+)/i);
224
+ if (generationMatch) {
225
+ console.log(chalk2.gray(`Generated: ${generationMatch[1]}
226
+ `));
227
+ }
228
+ } catch (error) {
229
+ console.error(chalk2.red(`\u274C Failed to load script: ${error instanceof Error ? error.message : String(error)}`));
230
+ return;
231
+ }
232
+ const testSpinner = ora2("Testing statusline with mock data...").start();
233
+ const mockInput = generateMockClaudeInput();
234
+ console.log(chalk2.gray("\nMock Claude Code Input:"));
235
+ console.log(chalk2.gray(JSON.stringify(mockInput, null, 2)));
236
+ const testResult = await testStatuslineScript(script, mockInput);
237
+ if (testResult.success) {
238
+ testSpinner.succeed(`Test completed in ${testResult.executionTime}ms`);
239
+ console.log(chalk2.green("\n\u2705 Statusline Output:"));
240
+ console.log(chalk2.white("\u2501".repeat(60)));
241
+ console.log(testResult.output);
242
+ console.log(chalk2.white("\u2501".repeat(60)));
243
+ console.log(chalk2.cyan(`
244
+ \u{1F4CA} Performance: ${getPerformanceEmoji(getPerformanceLevel(testResult.executionTime))} ${getPerformanceLevel(testResult.executionTime)} (${testResult.executionTime}ms)`));
245
+ if (testResult.output.includes("\u{1F4C1}") || testResult.output.includes("\u{1F33F}") || testResult.output.includes("\u{1F916}")) {
246
+ console.log(chalk2.green("\u2705 Statusline features appear to be working"));
247
+ } else {
248
+ console.log(chalk2.yellow("\u26A0\uFE0F Basic features may not be displaying correctly"));
249
+ }
250
+ } else {
251
+ testSpinner.fail("Test failed");
252
+ console.error(chalk2.red(`
253
+ \u274C Error: ${testResult.error}`));
254
+ if (testResult.output) {
255
+ console.log(chalk2.gray("\nPartial output:"));
256
+ console.log(testResult.output);
257
+ }
258
+ }
259
+ console.log(chalk2.green("\n\u2728 Preview complete! Use `cc-statusline init` to generate a new statusline."));
260
+ }
261
+ function getPerformanceEmoji(performance) {
262
+ switch (performance) {
263
+ case "excellent":
264
+ return "\u{1F680}";
265
+ case "good":
266
+ return "\u2705";
267
+ case "slow":
268
+ return "\u26A0\uFE0F";
269
+ case "timeout":
270
+ return "\u{1F40C}";
271
+ default:
272
+ return "\u2753";
273
+ }
274
+ }
275
+ function getPerformanceLevel(executionTime) {
276
+ if (executionTime > 1e3) return "timeout";
277
+ if (executionTime > 500) return "slow";
278
+ if (executionTime > 100) return "good";
279
+ return "excellent";
280
+ }
281
+ var init_preview = __esm({
282
+ "src/cli/preview.ts"() {
283
+ "use strict";
284
+ init_esm_shims();
285
+ init_tester();
286
+ }
287
+ });
288
+
289
+ // src/index.ts
290
+ init_esm_shims();
291
+ import { Command } from "commander";
292
+
293
+ // src/cli/commands.ts
294
+ init_esm_shims();
295
+
296
+ // src/cli/prompts.ts
297
+ init_esm_shims();
298
+ import inquirer from "inquirer";
299
+ async function collectConfiguration() {
300
+ console.log("\u{1F680} Welcome to cc-statusline! Let's create your custom Claude Code statusline.\n");
301
+ const config = await inquirer.prompt([
302
+ {
303
+ type: "checkbox",
304
+ name: "features",
305
+ message: "What would you like to display in your statusline?",
306
+ choices: [
307
+ { name: "\u{1F4C1} Working Directory", value: "directory", checked: true },
308
+ { name: "\u{1F33F} Git Branch", value: "git", checked: true },
309
+ { name: "\u{1F916} Model Name & Version", value: "model", checked: true },
310
+ { name: "\u{1F4B5} Usage & Cost", value: "usage", checked: true },
311
+ { name: "\u231B Session Time Remaining", value: "session", checked: true },
312
+ { name: "\u{1F4CA} Token Statistics", value: "tokens", checked: false },
313
+ { name: "\u26A1 Burn Rate (tokens/min)", value: "burnrate", checked: false }
314
+ ],
315
+ validate: (answer) => {
316
+ if (answer.length < 1) {
317
+ return "You must choose at least one feature.";
318
+ }
319
+ return true;
320
+ }
321
+ },
322
+ {
323
+ type: "confirm",
324
+ name: "colors",
325
+ message: "Enable colors and emojis?",
326
+ default: true
327
+ }
328
+ ]);
329
+ return {
330
+ features: config.features,
331
+ runtime: "bash",
332
+ colors: config.colors,
333
+ theme: "detailed",
334
+ ccusageIntegration: true,
335
+ // Always enabled since npx works
336
+ logging: false,
337
+ customEmojis: false
338
+ };
339
+ }
340
+
341
+ // src/generators/bash-generator.ts
342
+ init_esm_shims();
343
+
344
+ // src/features/colors.ts
345
+ init_esm_shims();
346
+ function generateColorBashCode(config) {
347
+ if (!config.enabled) {
348
+ return `
349
+ # ---- color helpers (disabled) ----
350
+ use_color=0
351
+ C() { :; }
352
+ RST() { :; }
353
+ `;
354
+ }
355
+ return `
356
+ # ---- color helpers (TTY-aware, respect NO_COLOR) ----
357
+ use_color=1
358
+ [ -t 1 ] || use_color=0
359
+ [ -n "$NO_COLOR" ] && use_color=0
360
+
361
+ C() { if [ "$use_color" -eq 1 ]; then printf '\\033[%sm' "$1"; fi; }
362
+ RST() { if [ "$use_color" -eq 1 ]; then printf '\\033[0m'; fi; }
363
+ `;
364
+ }
365
+ function generateBasicColors() {
366
+ return `
367
+ # ---- basic colors ----
368
+ dir_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;36m'; fi; } # cyan
369
+ model_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;35m'; fi; } # magenta
370
+ version_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;33m'; fi; } # yellow
371
+ rst() { if [ "$use_color" -eq 1 ]; then printf '\\033[0m'; fi; }
372
+ `;
373
+ }
374
+
375
+ // src/features/git.ts
376
+ init_esm_shims();
377
+ function generateGitBashCode(config, colors) {
378
+ if (!config.enabled) return "";
379
+ const colorCode = colors ? `
380
+ # ---- git colors ----
381
+ git_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;32m'; fi; }
382
+ rst() { if [ "$use_color" -eq 1 ]; then printf '\\033[0m'; fi; }
383
+ ` : `
384
+ git_color() { :; }
385
+ rst() { :; }
386
+ `;
387
+ return `${colorCode}
388
+ # ---- git ----
389
+ git_branch=""
390
+ if git rev-parse --git-dir >/dev/null 2>&1; then
391
+ git_branch=$(git branch --show-current 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)
392
+ fi`;
393
+ }
394
+ function generateGitDisplayCode(config, colors, emojis) {
395
+ if (!config.enabled) return "";
396
+ const branchEmoji = emojis ? "\u{1F33F}" : "git:";
397
+ let displayCode = `
398
+ # git display
399
+ if [ -n "$git_branch" ]; then
400
+ printf ' ${branchEmoji} %s%s%s' "$(git_color)" "$git_branch" "$(rst)"
401
+ fi`;
402
+ return displayCode;
403
+ }
404
+ function generateGitUtilities() {
405
+ return `
406
+ # git utilities
407
+ num_or_zero() { v="$1"; [[ "$v" =~ ^[0-9]+$ ]] && echo "$v" || echo 0; }`;
408
+ }
409
+
410
+ // src/features/usage.ts
411
+ init_esm_shims();
412
+ function generateUsageBashCode(config, colors) {
413
+ if (!config.enabled) return "";
414
+ const colorCode = colors ? `
415
+ # ---- usage colors ----
416
+ usage_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;35m'; fi; }
417
+ cost_color() { if [ "$use_color" -eq 1 ]; then printf '\\033[1;36m'; fi; }
418
+ session_color() {
419
+ rem_pct=$(( 100 - session_pct ))
420
+ if (( rem_pct <= 10 )); then SCLR='1;31'
421
+ elif (( rem_pct <= 25 )); then SCLR='1;33'
422
+ else SCLR='1;32'; fi
423
+ if [ "$use_color" -eq 1 ]; then printf '\\033[%sm' "$SCLR"; fi
424
+ }
425
+ ` : `
426
+ usage_color() { :; }
427
+ cost_color() { :; }
428
+ session_color() { :; }
429
+ `;
430
+ return `${colorCode}
431
+ # ---- ccusage integration ----
432
+ session_txt=""; session_pct=0; session_bar=""
433
+ cost_usd=""; cost_per_hour=""; tpm=""; tot_tokens=""
434
+
435
+ if command -v jq >/dev/null 2>&1; then
436
+ blocks_output=$(npx ccusage@latest blocks --json 2>/dev/null || ccusage blocks --json 2>/dev/null)
437
+ if [ -n "$blocks_output" ]; then
438
+ active_block=$(echo "$blocks_output" | jq -c '.blocks[] | select(.isActive == true)' 2>/dev/null | head -n1)
439
+ if [ -n "$active_block" ]; then${config.showCost ? `
440
+ cost_usd=$(echo "$active_block" | jq -r '.costUSD // empty')
441
+ cost_per_hour=$(echo "$active_block" | jq -r '.burnRate.costPerHour // empty')` : ""}${config.showTokens ? `
442
+ tot_tokens=$(echo "$active_block" | jq -r '.totalTokens // empty')` : ""}${config.showBurnRate ? `
443
+ tpm=$(echo "$active_block" | jq -r '.burnRate.tokensPerMinute // empty')` : ""}${config.showSession || config.showProgressBar ? `
444
+
445
+ # Session time calculation
446
+ reset_time_str=$(echo "$active_block" | jq -r '.usageLimitResetTime // .endTime // empty')
447
+ start_time_str=$(echo "$active_block" | jq -r '.startTime // empty')
448
+
449
+ if [ -n "$reset_time_str" ] && [ -n "$start_time_str" ]; then
450
+ start_sec=$(to_epoch "$start_time_str"); end_sec=$(to_epoch "$reset_time_str"); now_sec=$(date +%s)
451
+ total=$(( end_sec - start_sec )); (( total<1 )) && total=1
452
+ elapsed=$(( now_sec - start_sec )); (( elapsed<0 ))&&elapsed=0; (( elapsed>total ))&&elapsed=$total
453
+ session_pct=$(( elapsed * 100 / total ))
454
+ remaining=$(( end_sec - now_sec )); (( remaining<0 )) && remaining=0
455
+ rh=$(( remaining / 3600 )); rm=$(( (remaining % 3600) / 60 ))
456
+ end_hm=$(fmt_time_hm "$end_sec")${config.showSession ? `
457
+ session_txt="$(printf '%dh %dm until reset at %s (%d%%)' "$rh" "$rm" "$end_hm" "$session_pct")"` : ""}${config.showProgressBar ? `
458
+ session_bar=$(progress_bar "$session_pct" 10)` : ""}
459
+ fi` : ""}
460
+ fi
461
+ fi
462
+ fi`;
463
+ }
464
+ function generateUsageUtilities() {
465
+ return `
466
+ # ---- time helpers ----
467
+ to_epoch() {
468
+ ts="$1"
469
+ if command -v gdate >/dev/null 2>&1; then gdate -d "$ts" +%s 2>/dev/null && return; fi
470
+ date -u -j -f "%Y-%m-%dT%H:%M:%S%z" "\${ts/Z/+0000}" +%s 2>/dev/null && return
471
+ python3 - "$ts" <<'PY' 2>/dev/null
472
+ import sys, datetime
473
+ s=sys.argv[1].replace('Z','+00:00')
474
+ print(int(datetime.datetime.fromisoformat(s).timestamp()))
475
+ PY
476
+ }
477
+
478
+ fmt_time_hm() {
479
+ epoch="$1"
480
+ if date -r 0 +%s >/dev/null 2>&1; then date -r "$epoch" +"%H:%M"; else date -d "@$epoch" +"%H:%M"; fi
481
+ }
482
+
483
+ progress_bar() {
484
+ pct="\${1:-0}"; width="\${2:-10}"
485
+ [[ "$pct" =~ ^[0-9]+$ ]] || pct=0; ((pct<0))&&pct=0; ((pct>100))&&pct=100
486
+ filled=$(( pct * width / 100 )); empty=$(( width - filled ))
487
+ printf '%*s' "$filled" '' | tr ' ' '='
488
+ printf '%*s' "$empty" '' | tr ' ' '-'
489
+ }`;
490
+ }
491
+ function generateUsageDisplayCode(config, colors, emojis) {
492
+ if (!config.enabled) return "";
493
+ let displayCode = "";
494
+ if (config.showSession) {
495
+ const sessionEmoji = emojis ? "\u231B" : "session:";
496
+ displayCode += `
497
+ # session time
498
+ if [ -n "$session_txt" ]; then
499
+ printf ' ${sessionEmoji} %s%s%s' "$(session_color)" "$session_txt" "$(rst)"${config.showProgressBar ? `
500
+ printf ' %s[%s]%s' "$(session_color)" "$session_bar" "$(rst)"` : ""}
501
+ fi`;
502
+ }
503
+ if (config.showCost) {
504
+ const costEmoji = emojis ? "\u{1F4B5}" : "$";
505
+ displayCode += `
506
+ # cost
507
+ if [ -n "$cost_usd" ] && [[ "$cost_usd" =~ ^[0-9.]+$ ]]; then
508
+ if [ -n "$cost_per_hour" ] && [[ "$cost_per_hour" =~ ^[0-9.]+$ ]]; then
509
+ printf ' ${costEmoji} %s$%.2f ($%.2f/h)%s' "$(cost_color)" "$cost_usd" "$cost_per_hour" "$(rst)"
510
+ else
511
+ printf ' ${costEmoji} %s$%.2f%s' "$(cost_color)" "$cost_usd" "$(rst)"
512
+ fi
513
+ fi`;
514
+ }
515
+ if (config.showTokens) {
516
+ const tokenEmoji = emojis ? "\u{1F4CA}" : "tok:";
517
+ displayCode += `
518
+ # tokens
519
+ if [ -n "$tot_tokens" ] && [[ "$tot_tokens" =~ ^[0-9]+$ ]]; then
520
+ if [ -n "$tpm" ] && [[ "$tpm" =~ ^[0-9.]+$ ]] && ${config.showBurnRate ? "true" : "false"}; then
521
+ printf ' ${tokenEmoji} %s%s tok (%.0f tpm)%s' "$(usage_color)" "$tot_tokens" "$tpm" "$(rst)"
522
+ else
523
+ printf ' ${tokenEmoji} %s%s tok%s' "$(usage_color)" "$tot_tokens" "$(rst)"
524
+ fi
525
+ fi`;
526
+ }
527
+ return displayCode;
528
+ }
529
+
530
+ // src/generators/bash-generator.ts
531
+ function generateBashStatusline(config) {
532
+ const hasGit = config.features.includes("git");
533
+ const hasUsage = config.features.some((f) => ["usage", "session", "tokens", "burnrate"].includes(f));
534
+ const hasDirectory = config.features.includes("directory");
535
+ const hasModel = config.features.includes("model");
536
+ const usageConfig = {
537
+ enabled: hasUsage && config.ccusageIntegration,
538
+ showCost: config.features.includes("usage"),
539
+ showTokens: config.features.includes("tokens"),
540
+ showBurnRate: config.features.includes("burnrate"),
541
+ showSession: config.features.includes("session"),
542
+ showProgressBar: config.theme !== "minimal" && config.features.includes("session")
543
+ };
544
+ const gitConfig = {
545
+ enabled: hasGit,
546
+ showBranch: hasGit,
547
+ showChanges: false,
548
+ // Removed delta changes per user request
549
+ compactMode: config.theme === "compact"
550
+ };
551
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
552
+ const script = `#!/bin/bash
553
+ # Generated by cc-statusline (https://www.npmjs.com/package/@chongdashu/cc-statusline)
554
+ # Custom Claude Code statusline - Created: ${timestamp}
555
+ # Theme: ${config.theme} | Colors: ${config.colors} | Features: ${config.features.join(", ")}
556
+
557
+ ${config.logging ? generateLoggingCode() : ""}
558
+ input=$(cat)
559
+ ${generateColorBashCode({ enabled: config.colors, theme: config.theme })}
560
+ ${config.colors ? generateBasicColors() : ""}
561
+ ${hasUsage ? generateUsageUtilities() : ""}
562
+ ${hasGit ? generateGitUtilities() : ""}
563
+ ${generateBasicDataExtraction(hasDirectory, hasModel)}
564
+ ${hasGit ? generateGitBashCode(gitConfig, config.colors) : ""}
565
+ ${hasUsage ? generateUsageBashCode(usageConfig, config.colors) : ""}
566
+ ${config.logging ? generateLoggingOutput() : ""}
567
+ ${generateDisplaySection(config, gitConfig, usageConfig)}
568
+ `;
569
+ return script.replace(/\n\n\n+/g, "\n\n").trim() + "\n";
570
+ }
571
+ function generateLoggingCode() {
572
+ return `
573
+ LOG_FILE="\${HOME}/.claude/statusline.log"
574
+ TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
575
+
576
+ # ---- logging ----
577
+ {
578
+ echo "[$TIMESTAMP] Status line triggered with input:"
579
+ (echo "$input" | jq . 2>/dev/null) || echo "$input"
580
+ echo "---"
581
+ } >> "$LOG_FILE" 2>/dev/null
582
+ `;
583
+ }
584
+ function generateBasicDataExtraction(hasDirectory, hasModel) {
585
+ return `
586
+ # ---- basics ----
587
+ if command -v jq >/dev/null 2>&1; then${hasDirectory ? `
588
+ current_dir=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // "unknown"' 2>/dev/null | sed "s|^$HOME|~|g")` : ""}${hasModel ? `
589
+ model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"' 2>/dev/null)
590
+ model_version=$(echo "$input" | jq -r '.model.version // ""' 2>/dev/null)` : ""}
591
+ else${hasDirectory ? `
592
+ current_dir="unknown"` : ""}${hasModel ? `
593
+ model_name="Claude"; model_version=""` : ""}
594
+ fi
595
+ `;
596
+ }
597
+ function generateLoggingOutput() {
598
+ return `
599
+ # ---- log extracted data ----
600
+ {
601
+ echo "[$TIMESTAMP] Extracted: dir=\${current_dir:-}, model=\${model_name:-}, version=\${model_version:-}, git=\${git_branch:-}, cost=\${cost_usd:-}, cost_ph=\${cost_per_hour:-}, tokens=\${tot_tokens:-}, tpm=\${tpm:-}, session_pct=\${session_pct:-}"
602
+ } >> "$LOG_FILE" 2>/dev/null
603
+ `;
604
+ }
605
+ function generateDisplaySection(config, gitConfig, usageConfig) {
606
+ const emojis = config.colors && !config.customEmojis;
607
+ let displayCode = `
608
+ # ---- render statusline ----`;
609
+ if (config.features.includes("directory")) {
610
+ const dirEmoji = emojis ? "\u{1F4C1}" : "dir:";
611
+ displayCode += `
612
+ printf '${dirEmoji} %s%s%s' "$(dir_color)" "$current_dir" "$(rst)"`;
613
+ }
614
+ displayCode += generateGitDisplayCode(gitConfig, config.colors, emojis);
615
+ if (config.features.includes("model")) {
616
+ const modelEmoji = emojis ? "\u{1F916}" : "model:";
617
+ displayCode += `
618
+ printf ' ${modelEmoji} %s%s%s' "$(model_color)" "$model_name" "$(rst)"
619
+ if [ -n "$model_version" ] && [ "$model_version" != "null" ]; then
620
+ printf ' \u{1F3F7}\uFE0F %s%s%s' "$(version_color)" "$model_version" "$(rst)"
621
+ fi`;
622
+ }
623
+ displayCode += generateUsageDisplayCode(usageConfig, config.colors, emojis);
624
+ return displayCode;
625
+ }
626
+
627
+ // src/utils/validator.ts
628
+ init_esm_shims();
629
+ function validateConfig(config) {
630
+ const errors = [];
631
+ const warnings = [];
632
+ if (!config.features || config.features.length === 0) {
633
+ errors.push("At least one display feature must be selected");
634
+ }
635
+ if (!["bash", "python", "node"].includes(config.runtime)) {
636
+ errors.push(`Invalid runtime: ${config.runtime}`);
637
+ }
638
+ if (!["minimal", "detailed", "compact"].includes(config.theme)) {
639
+ errors.push(`Invalid theme: ${config.theme}`);
640
+ }
641
+ const usageFeatures = ["usage", "session", "tokens", "burnrate"];
642
+ const hasUsageFeatures = config.features.some((f) => usageFeatures.includes(f));
643
+ if (hasUsageFeatures && !config.ccusageIntegration) {
644
+ warnings.push("Usage features selected but ccusage integration is disabled. Some features may not work properly.");
645
+ }
646
+ if (config.features.length > 5) {
647
+ warnings.push("Many features selected. This may impact statusline performance.");
648
+ }
649
+ if (config.customEmojis && !config.colors) {
650
+ warnings.push("Custom emojis enabled but colors disabled. Visual distinction may be limited.");
651
+ }
652
+ return {
653
+ isValid: errors.length === 0,
654
+ errors,
655
+ warnings
656
+ };
657
+ }
658
+
659
+ // src/utils/installer.ts
660
+ init_esm_shims();
661
+ import { promises as fs } from "fs";
662
+ import path2 from "path";
663
+ async function installStatusline(script, outputPath, config) {
664
+ try {
665
+ const dir = path2.dirname(outputPath);
666
+ await fs.mkdir(dir, { recursive: true });
667
+ await fs.writeFile(outputPath, script, { mode: 493 });
668
+ await updateSettingsJson(dir, path2.basename(outputPath));
669
+ } catch (error) {
670
+ throw new Error(`Failed to install statusline: ${error instanceof Error ? error.message : String(error)}`);
671
+ }
672
+ }
673
+ async function updateSettingsJson(claudeDir, scriptName) {
674
+ const settingsPath = path2.join(claudeDir, "settings.json");
675
+ try {
676
+ let settings = {};
677
+ try {
678
+ const settingsContent = await fs.readFile(settingsPath, "utf-8");
679
+ settings = JSON.parse(settingsContent);
680
+ } catch {
681
+ }
682
+ settings.statusLine = {
683
+ type: "command",
684
+ command: `.claude/${scriptName}`,
685
+ padding: 0
686
+ };
687
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
688
+ } catch (error) {
689
+ console.warn(`Warning: Could not update settings.json: ${error instanceof Error ? error.message : String(error)}`);
690
+ throw new Error("SETTINGS_UPDATE_FAILED");
691
+ }
692
+ }
693
+
694
+ // src/cli/commands.ts
695
+ import chalk from "chalk";
696
+ import ora from "ora";
697
+ import path4 from "path";
698
+ async function initCommand(options) {
699
+ try {
700
+ const spinner = ora("Initializing statusline generator...").start();
701
+ await new Promise((resolve) => setTimeout(resolve, 500));
702
+ spinner.stop();
703
+ const config = await collectConfiguration();
704
+ const validation = validateConfig(config);
705
+ if (!validation.isValid) {
706
+ console.error(chalk.red("\u274C Configuration validation failed:"));
707
+ validation.errors.forEach((error) => console.error(chalk.red(` \u2022 ${error}`)));
708
+ process.exit(1);
709
+ }
710
+ const generationSpinner = ora("Generating statusline script...").start();
711
+ const script = generateBashStatusline(config);
712
+ const filename = "statusline.sh";
713
+ generationSpinner.succeed("Statusline script generated!");
714
+ console.log(chalk.cyan("\n\u2728 Your statusline will look like:"));
715
+ console.log(chalk.white("\u2501".repeat(60)));
716
+ const { testStatuslineScript: testStatuslineScript2, generateMockClaudeInput: generateMockClaudeInput2 } = await Promise.resolve().then(() => (init_tester(), tester_exports));
717
+ const mockInput = generateMockClaudeInput2();
718
+ const testResult = await testStatuslineScript2(script, mockInput);
719
+ if (testResult.success) {
720
+ console.log(testResult.output);
721
+ } else {
722
+ console.log(chalk.gray("\u{1F4C1} ~/projects/my-app \u{1F33F} main \u{1F916} Claude \u{1F4B5} $2.48 ($12.50/h)"));
723
+ console.log(chalk.gray("(Preview unavailable - will work when Claude Code runs it)"));
724
+ }
725
+ console.log(chalk.white("\u2501".repeat(60)));
726
+ const outputPath = options.output || `./.claude/${filename}`;
727
+ const resolvedPath = path4.resolve(outputPath);
728
+ if (options.install !== false) {
729
+ const installSpinner = ora("Installing statusline...").start();
730
+ try {
731
+ await installStatusline(script, resolvedPath, config);
732
+ installSpinner.succeed("\u2705 Statusline installed!");
733
+ console.log(chalk.green("\n\u{1F389} Success! Your custom statusline is ready!"));
734
+ console.log(chalk.cyan(`
735
+ \u{1F4C1} Generated file: ${chalk.white(resolvedPath)}`));
736
+ console.log(chalk.cyan("\nNext steps:"));
737
+ console.log(chalk.white(" 1. Restart Claude Code to see your new statusline"));
738
+ console.log(chalk.white(" 2. Usage statistics work via: npx ccusage@latest"));
739
+ } catch (error) {
740
+ installSpinner.fail("Failed to install statusline");
741
+ if (error instanceof Error && error.message === "SETTINGS_UPDATE_FAILED") {
742
+ console.log(chalk.yellow("\n\u26A0\uFE0F Settings.json could not be updated automatically."));
743
+ console.log(chalk.cyan("\nManual Configuration Required:"));
744
+ console.log(chalk.white("Add this to your .claude/settings.json file:"));
745
+ console.log(chalk.gray("\n{"));
746
+ console.log(chalk.gray(' "statusLine": {'));
747
+ console.log(chalk.gray(' "type": "command",'));
748
+ console.log(chalk.gray(` "command": ".claude/statusline.sh",`));
749
+ console.log(chalk.gray(' "padding": 0'));
750
+ console.log(chalk.gray(" }"));
751
+ console.log(chalk.gray("}"));
752
+ console.log(chalk.cyan(`
753
+ \u{1F4C1} Statusline script saved to: ${chalk.white(resolvedPath)}`));
754
+ } else {
755
+ console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
756
+ console.log(chalk.cyan(`
757
+ \u{1F4C1} You can manually save the script to: ${chalk.white(resolvedPath)}`));
758
+ }
759
+ }
760
+ } else {
761
+ console.log(chalk.green("\n\u2705 Statusline generated successfully!"));
762
+ console.log(chalk.cyan(`
763
+ \u{1F4C1} Save this script to: ${chalk.white(resolvedPath)}`));
764
+ console.log(chalk.cyan("\nThen restart Claude Code to see your new statusline."));
765
+ }
766
+ } catch (error) {
767
+ console.error(chalk.red("\u274C An error occurred:"));
768
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
769
+ process.exit(1);
770
+ }
771
+ }
772
+
773
+ // src/index.ts
774
+ import chalk3 from "chalk";
775
+ var program = new Command();
776
+ program.name("cc-statusline").description("Interactive CLI tool for generating custom Claude Code statuslines").version("1.0.0");
777
+ program.command("init").description("Create a custom statusline with interactive prompts").option("-o, --output <path>", "Output path for statusline.sh", "./.claude/statusline.sh").option("--no-install", "Don't automatically install to .claude/statusline.sh").action(initCommand);
778
+ program.command("preview").description("Preview existing statusline.sh with mock data").argument("<script-path>", "Path to statusline.sh file to preview").action(async (scriptPath) => {
779
+ const { previewCommand: previewCommand2 } = await Promise.resolve().then(() => (init_preview(), preview_exports));
780
+ await previewCommand2(scriptPath);
781
+ });
782
+ program.command("test").description("Test statusline with real Claude Code JSON input").option("-c, --config <path>", "Configuration file to test").action(() => {
783
+ console.log(chalk3.yellow("Test command coming soon!"));
784
+ });
785
+ if (!process.argv.slice(2).length) {
786
+ program.outputHelp();
787
+ }
788
+ program.parse(process.argv);
789
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/utils/tester.ts","../src/cli/preview.ts","../src/index.ts","../src/cli/commands.ts","../src/cli/prompts.ts","../src/generators/bash-generator.ts","../src/features/colors.ts","../src/features/git.ts","../src/features/usage.ts","../src/utils/validator.ts","../src/utils/installer.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { StatuslineConfig } from '../cli/prompts.js'\nimport { spawn } from 'child_process'\nimport { promises as fs } from 'fs'\nimport path from 'path'\n\nexport interface TestResult {\n success: boolean\n output: string\n error?: string\n executionTime: number\n}\n\nexport async function testStatuslineScript(script: string, mockData?: any): Promise<TestResult> {\n const startTime = Date.now()\n \n try {\n // Create temporary script file\n const tempDir = '/tmp'\n const scriptPath = path.join(tempDir, `statusline-test-${Date.now()}.sh`)\n \n await fs.writeFile(scriptPath, script, { mode: 0o755 })\n \n // Generate mock input if not provided\n const input = mockData || generateMockClaudeInput()\n \n // Execute script\n const result = await executeScript(scriptPath, JSON.stringify(input))\n \n // Cleanup\n await fs.unlink(scriptPath).catch(() => {}) // Ignore cleanup errors\n \n const executionTime = Date.now() - startTime\n \n return {\n success: result.success,\n output: result.output,\n error: result.error,\n executionTime\n }\n \n } catch (error) {\n return {\n success: false,\n output: '',\n error: error instanceof Error ? error.message : String(error),\n executionTime: Date.now() - startTime\n }\n }\n}\n\nexport function generateMockClaudeInput(config?: Partial<StatuslineConfig>): any {\n return {\n session_id: \"test-session-123\",\n transcript_path: \"/home/user/.claude/conversations/test.jsonl\",\n cwd: \"/home/user/projects/my-project\",\n workspace: {\n current_dir: \"/home/user/projects/my-project\"\n },\n model: {\n id: \"claude-opus-4-1-20250805\",\n display_name: \"Opus 4.1\",\n version: \"20250805\"\n }\n }\n}\n\nexport function generateMockCcusageOutput(): any {\n return {\n blocks: [\n {\n id: \"2025-08-13T08:00:00.000Z\",\n startTime: \"2025-08-13T08:00:00.000Z\",\n endTime: \"2025-08-13T13:00:00.000Z\",\n usageLimitResetTime: \"2025-08-13T13:00:00.000Z\",\n actualEndTime: \"2025-08-13T09:30:34.698Z\",\n isActive: true,\n isGap: false,\n entries: 12,\n tokenCounts: {\n inputTokens: 1250,\n outputTokens: 2830,\n cacheCreationInputTokens: 15000,\n cacheReadInputTokens: 45000\n },\n totalTokens: 64080,\n costUSD: 3.42,\n models: [\"claude-opus-4-1-20250805\"],\n burnRate: {\n tokensPerMinute: 850.5,\n tokensPerMinuteForIndicator: 850,\n costPerHour: 12.45\n },\n projection: {\n totalTokens: 128000,\n totalCost: 6.84,\n remainingMinutes: 210\n }\n }\n ]\n }\n}\n\nasync function executeScript(scriptPath: string, input: string): Promise<{ success: boolean, output: string, error?: string }> {\n return new Promise((resolve) => {\n const process = spawn('bash', [scriptPath], {\n stdio: ['pipe', 'pipe', 'pipe']\n })\n \n let stdout = ''\n let stderr = ''\n \n process.stdout.on('data', (data) => {\n stdout += data.toString()\n })\n \n process.stderr.on('data', (data) => {\n stderr += data.toString()\n })\n \n process.on('close', (code) => {\n resolve({\n success: code === 0,\n output: stdout.trim(),\n error: stderr.trim() || undefined\n })\n })\n \n process.on('error', (err) => {\n resolve({\n success: false,\n output: '',\n error: err.message\n })\n })\n \n // Send input and close stdin\n process.stdin.write(input)\n process.stdin.end()\n \n // Timeout after 5 seconds\n setTimeout(() => {\n process.kill()\n resolve({\n success: false,\n output: stdout,\n error: 'Script execution timed out (5s)'\n })\n }, 5000)\n })\n}\n\nexport function analyzeTestResult(result: TestResult, config: StatuslineConfig): {\n performance: 'excellent' | 'good' | 'slow' | 'timeout'\n hasRequiredFeatures: boolean\n issues: string[]\n suggestions: string[]\n} {\n const issues: string[] = []\n const suggestions: string[] = []\n \n // Performance analysis\n let performance: 'excellent' | 'good' | 'slow' | 'timeout'\n if (result.executionTime > 1000) {\n performance = 'timeout'\n issues.push('Script execution is very slow (>1s)')\n } else if (result.executionTime > 500) {\n performance = 'slow'\n issues.push('Script execution is slow (>500ms)')\n } else if (result.executionTime > 100) {\n performance = 'good'\n } else {\n performance = 'excellent'\n }\n \n // Feature validation\n let hasRequiredFeatures = true\n \n if (config.features.includes('directory') && !result.output.includes('projects')) {\n hasRequiredFeatures = false\n issues.push('Directory feature not working properly')\n }\n \n if (config.features.includes('model') && !result.output.includes('Opus')) {\n hasRequiredFeatures = false\n issues.push('Model feature not working properly')\n }\n \n if (config.features.includes('git') && config.ccusageIntegration && !result.output.includes('git')) {\n suggestions.push('Git integration may require actual git repository')\n }\n \n // Error analysis\n if (result.error) {\n issues.push(`Script errors: ${result.error}`)\n }\n \n if (!result.success) {\n issues.push('Script failed to execute successfully')\n }\n \n // Performance suggestions\n if (config.features.length > 6) {\n suggestions.push('Consider reducing number of features for better performance')\n }\n \n if (config.ccusageIntegration && result.executionTime > 200) {\n suggestions.push('ccusage integration may slow down statusline - consider caching')\n }\n \n return {\n performance,\n hasRequiredFeatures,\n issues,\n suggestions\n }\n}","import { StatuslineConfig } from './prompts.js'\nimport { generateBashStatusline } from '../generators/bash-generator.js'\nimport { testStatuslineScript, generateMockClaudeInput, analyzeTestResult } from '../utils/tester.js'\nimport { promises as fs } from 'fs'\nimport chalk from 'chalk'\nimport ora from 'ora'\n\nexport async function previewCommand(scriptPath: string): Promise<void> {\n console.log(chalk.cyan('šŸ” Statusline Preview Mode\\n'))\n \n let script: string\n \n // Load existing statusline script\n try {\n const spinner = ora(`Loading statusline script from ${scriptPath}...`).start()\n script = await fs.readFile(scriptPath, 'utf-8')\n spinner.succeed('Script loaded!')\n \n // Try to extract config info from the script header\n const headerMatch = script.match(/# Theme: (\\w+) \\| Colors: (\\w+) \\| Features: ([^\\n]+)/i)\n if (headerMatch) {\n console.log(chalk.yellow('Detected Configuration:'))\n console.log(` Theme: ${headerMatch[1]}`)\n console.log(` Colors: ${headerMatch[2]}`) \n console.log(` Features: ${headerMatch[3]}\\n`)\n }\n \n // Extract generation info if available\n const generationMatch = script.match(/# Generated by cc-statusline.*\\n# Custom Claude Code statusline - Created: ([^\\n]+)/i)\n if (generationMatch) {\n console.log(chalk.gray(`Generated: ${generationMatch[1]}\\n`))\n }\n \n } catch (error) {\n console.error(chalk.red(`āŒ Failed to load script: ${error instanceof Error ? error.message : String(error)}`))\n return\n }\n \n // Test the script\n const testSpinner = ora('Testing statusline with mock data...').start()\n const mockInput = generateMockClaudeInput()\n \n console.log(chalk.gray('\\nMock Claude Code Input:'))\n console.log(chalk.gray(JSON.stringify(mockInput, null, 2)))\n \n const testResult = await testStatuslineScript(script, mockInput)\n \n if (testResult.success) {\n testSpinner.succeed(`Test completed in ${testResult.executionTime}ms`)\n \n console.log(chalk.green('\\nāœ… Statusline Output:'))\n console.log(chalk.white('━'.repeat(60)))\n console.log(testResult.output)\n console.log(chalk.white('━'.repeat(60)))\n \n // Basic performance analysis\n console.log(chalk.cyan(`\\nšŸ“Š Performance: ${getPerformanceEmoji(getPerformanceLevel(testResult.executionTime))} ${getPerformanceLevel(testResult.executionTime)} (${testResult.executionTime}ms)`))\n \n // Basic output validation\n if (testResult.output.includes('šŸ“') || testResult.output.includes('🌿') || testResult.output.includes('šŸ¤–')) {\n console.log(chalk.green('āœ… Statusline features appear to be working'))\n } else {\n console.log(chalk.yellow('āš ļø Basic features may not be displaying correctly'))\n }\n \n } else {\n testSpinner.fail('Test failed')\n console.error(chalk.red(`\\nāŒ Error: ${testResult.error}`))\n if (testResult.output) {\n console.log(chalk.gray('\\nPartial output:'))\n console.log(testResult.output)\n }\n }\n \n console.log(chalk.green('\\n✨ Preview complete! Use `cc-statusline init` to generate a new statusline.'))\n}\n\nfunction getPerformanceEmoji(performance: string): string {\n switch (performance) {\n case 'excellent': return 'šŸš€'\n case 'good': return 'āœ…'\n case 'slow': return 'āš ļø'\n case 'timeout': return '🐌'\n default: return 'ā“'\n }\n}\n\nfunction getPerformanceLevel(executionTime: number): string {\n if (executionTime > 1000) return 'timeout'\n if (executionTime > 500) return 'slow'\n if (executionTime > 100) return 'good'\n return 'excellent'\n}","import { Command } from 'commander'\nimport { initCommand } from './cli/commands.js'\nimport chalk from 'chalk'\n\nconst program = new Command()\n\nprogram\n .name('cc-statusline')\n .description('Interactive CLI tool for generating custom Claude Code statuslines')\n .version('1.0.0')\n\nprogram\n .command('init')\n .description('Create a custom statusline with interactive prompts')\n .option('-o, --output <path>', 'Output path for statusline.sh', './.claude/statusline.sh')\n .option('--no-install', 'Don\\'t automatically install to .claude/statusline.sh')\n .action(initCommand)\n\nprogram\n .command('preview')\n .description('Preview existing statusline.sh with mock data')\n .argument('<script-path>', 'Path to statusline.sh file to preview')\n .action(async (scriptPath) => {\n const { previewCommand } = await import('./cli/preview.js')\n await previewCommand(scriptPath)\n })\n\nprogram\n .command('test')\n .description('Test statusline with real Claude Code JSON input')\n .option('-c, --config <path>', 'Configuration file to test')\n .action(() => {\n console.log(chalk.yellow('Test command coming soon!'))\n })\n\n// Show help if no command provided\nif (!process.argv.slice(2).length) {\n program.outputHelp()\n}\n\nprogram.parse(process.argv)","import { collectConfiguration, displayConfigSummary } from './prompts.js'\nimport { generateBashStatusline } from '../generators/bash-generator.js'\nimport { validateConfig } from '../utils/validator.js'\nimport { installStatusline } from '../utils/installer.js'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport path from 'path'\n\ninterface InitOptions {\n output?: string\n install?: boolean\n}\n\nexport async function initCommand(options: InitOptions): Promise<void> {\n try {\n const spinner = ora('Initializing statusline generator...').start()\n await new Promise(resolve => setTimeout(resolve, 500)) // Brief pause for UX\n spinner.stop()\n\n // Collect user configuration\n const config = await collectConfiguration()\n \n // Validate configuration\n const validation = validateConfig(config)\n if (!validation.isValid) {\n console.error(chalk.red('āŒ Configuration validation failed:'))\n validation.errors.forEach(error => console.error(chalk.red(` • ${error}`)))\n process.exit(1)\n }\n\n // Generate statusline script\n const generationSpinner = ora('Generating statusline script...').start()\n \n const script = generateBashStatusline(config)\n const filename = 'statusline.sh'\n \n generationSpinner.succeed('Statusline script generated!')\n\n // Show preview of what it will look like\n console.log(chalk.cyan('\\n✨ Your statusline will look like:'))\n console.log(chalk.white('━'.repeat(60)))\n \n // Generate preview using the test function\n const { testStatuslineScript, generateMockClaudeInput } = await import('../utils/tester.js')\n const mockInput = generateMockClaudeInput()\n const testResult = await testStatuslineScript(script, mockInput)\n \n if (testResult.success) {\n console.log(testResult.output)\n } else {\n console.log(chalk.gray('šŸ“ ~/projects/my-app 🌿 main šŸ¤– Claude šŸ’µ $2.48 ($12.50/h)'))\n console.log(chalk.gray('(Preview unavailable - will work when Claude Code runs it)'))\n }\n \n console.log(chalk.white('━'.repeat(60)))\n\n // Determine output path\n const outputPath = options.output || `./.claude/${filename}`\n const resolvedPath = path.resolve(outputPath)\n\n // Install the statusline\n if (options.install !== false) {\n const installSpinner = ora('Installing statusline...').start()\n \n try {\n await installStatusline(script, resolvedPath, config)\n installSpinner.succeed('āœ… Statusline installed!')\n \n console.log(chalk.green('\\nšŸŽ‰ Success! Your custom statusline is ready!'))\n console.log(chalk.cyan(`\\nšŸ“ Generated file: ${chalk.white(resolvedPath)}`))\n console.log(chalk.cyan('\\nNext steps:'))\n console.log(chalk.white(' 1. Restart Claude Code to see your new statusline'))\n console.log(chalk.white(' 2. Usage statistics work via: npx ccusage@latest'))\n \n } catch (error) {\n installSpinner.fail('Failed to install statusline')\n \n if (error instanceof Error && error.message === 'SETTINGS_UPDATE_FAILED') {\n console.log(chalk.yellow('\\nāš ļø Settings.json could not be updated automatically.'))\n console.log(chalk.cyan('\\nManual Configuration Required:'))\n console.log(chalk.white('Add this to your .claude/settings.json file:'))\n console.log(chalk.gray('\\n{'))\n console.log(chalk.gray(' \"statusLine\": {'))\n console.log(chalk.gray(' \"type\": \"command\",'))\n console.log(chalk.gray(` \"command\": \".claude/statusline.sh\",`))\n console.log(chalk.gray(' \"padding\": 0'))\n console.log(chalk.gray(' }'))\n console.log(chalk.gray('}'))\n console.log(chalk.cyan(`\\nšŸ“ Statusline script saved to: ${chalk.white(resolvedPath)}`))\n } else {\n console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`))\n console.log(chalk.cyan(`\\nšŸ“ You can manually save the script to: ${chalk.white(resolvedPath)}`))\n }\n }\n } else {\n // Just display where to save it\n console.log(chalk.green('\\nāœ… Statusline generated successfully!'))\n console.log(chalk.cyan(`\\nšŸ“ Save this script to: ${chalk.white(resolvedPath)}`))\n console.log(chalk.cyan('\\nThen restart Claude Code to see your new statusline.'))\n }\n\n } catch (error) {\n console.error(chalk.red('āŒ An error occurred:'))\n console.error(chalk.red(error instanceof Error ? error.message : String(error)))\n process.exit(1)\n }\n}","import inquirer from 'inquirer'\n\nexport interface StatuslineConfig {\n features: string[]\n runtime: 'bash' | 'python' | 'node'\n colors: boolean\n theme: 'minimal' | 'detailed' | 'compact'\n ccusageIntegration: boolean\n logging: boolean\n customEmojis: boolean\n}\n\nexport async function collectConfiguration(): Promise<StatuslineConfig> {\n console.log('šŸš€ Welcome to cc-statusline! Let\\'s create your custom Claude Code statusline.\\n')\n\n const config = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'features',\n message: 'What would you like to display in your statusline?',\n choices: [\n { name: 'šŸ“ Working Directory', value: 'directory', checked: true },\n { name: '🌿 Git Branch', value: 'git', checked: true },\n { name: 'šŸ¤– Model Name & Version', value: 'model', checked: true },\n { name: 'šŸ’µ Usage & Cost', value: 'usage', checked: true },\n { name: 'āŒ› Session Time Remaining', value: 'session', checked: true },\n { name: 'šŸ“Š Token Statistics', value: 'tokens', checked: false },\n { name: '⚔ Burn Rate (tokens/min)', value: 'burnrate', checked: false }\n ],\n validate: (answer: string[]) => {\n if (answer.length < 1) {\n return 'You must choose at least one feature.'\n }\n return true\n }\n },\n {\n type: 'confirm',\n name: 'colors',\n message: 'Enable colors and emojis?',\n default: true\n }\n ])\n\n // Set intelligent defaults\n return {\n features: config.features,\n runtime: 'bash',\n colors: config.colors,\n theme: 'detailed',\n ccusageIntegration: true, // Always enabled since npx works\n logging: false,\n customEmojis: false\n } as StatuslineConfig\n}\n\nexport function displayConfigSummary(config: StatuslineConfig): void {\n console.log('\\nāœ… Configuration Summary:')\n console.log(` Runtime: ${config.runtime}`)\n console.log(` Theme: ${config.theme}`)\n console.log(` Colors: ${config.colors ? 'āœ…' : 'āŒ'}`)\n console.log(` Features: ${config.features.join(', ')}`)\n \n if (config.ccusageIntegration) {\n console.log(' šŸ“Š ccusage integration enabled')\n }\n \n if (config.logging) {\n console.log(' šŸ“ Debug logging enabled')\n }\n \n console.log('')\n}","import { StatuslineConfig } from '../cli/prompts.js'\nimport { generateColorBashCode, generateBasicColors } from '../features/colors.js'\nimport { generateGitBashCode, generateGitDisplayCode, generateGitUtilities } from '../features/git.js'\nimport { generateUsageBashCode, generateUsageDisplayCode, generateUsageUtilities } from '../features/usage.js'\n\nexport function generateBashStatusline(config: StatuslineConfig): string {\n const hasGit = config.features.includes('git')\n const hasUsage = config.features.some(f => ['usage', 'session', 'tokens', 'burnrate'].includes(f))\n const hasDirectory = config.features.includes('directory')\n const hasModel = config.features.includes('model')\n\n // Build usage feature config\n const usageConfig = {\n enabled: hasUsage && config.ccusageIntegration,\n showCost: config.features.includes('usage'),\n showTokens: config.features.includes('tokens'),\n showBurnRate: config.features.includes('burnrate'),\n showSession: config.features.includes('session'),\n showProgressBar: config.theme !== 'minimal' && config.features.includes('session')\n }\n\n // Build git feature config\n const gitConfig = {\n enabled: hasGit,\n showBranch: hasGit,\n showChanges: false, // Removed delta changes per user request\n compactMode: config.theme === 'compact'\n }\n\n const timestamp = new Date().toISOString()\n const script = `#!/bin/bash\n# Generated by cc-statusline (https://www.npmjs.com/package/@chongdashu/cc-statusline)\n# Custom Claude Code statusline - Created: ${timestamp}\n# Theme: ${config.theme} | Colors: ${config.colors} | Features: ${config.features.join(', ')}\n\n${config.logging ? generateLoggingCode() : ''}\ninput=$(cat)\n${generateColorBashCode({ enabled: config.colors, theme: config.theme })}\n${config.colors ? generateBasicColors() : ''}\n${hasUsage ? generateUsageUtilities() : ''}\n${hasGit ? generateGitUtilities() : ''}\n${generateBasicDataExtraction(hasDirectory, hasModel)}\n${hasGit ? generateGitBashCode(gitConfig, config.colors) : ''}\n${hasUsage ? generateUsageBashCode(usageConfig, config.colors) : ''}\n${config.logging ? generateLoggingOutput() : ''}\n${generateDisplaySection(config, gitConfig, usageConfig)}\n`\n\n return script.replace(/\\n\\n\\n+/g, '\\n\\n').trim() + '\\n'\n}\n\nfunction generateLoggingCode(): string {\n return `\nLOG_FILE=\"\\${HOME}/.claude/statusline.log\"\nTIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')\n\n# ---- logging ----\n{\n echo \"[$TIMESTAMP] Status line triggered with input:\"\n (echo \"$input\" | jq . 2>/dev/null) || echo \"$input\"\n echo \"---\"\n} >> \"$LOG_FILE\" 2>/dev/null\n`\n}\n\nfunction generateBasicDataExtraction(hasDirectory: boolean, hasModel: boolean): string {\n return `\n# ---- basics ----\nif command -v jq >/dev/null 2>&1; then${hasDirectory ? `\n current_dir=$(echo \"$input\" | jq -r '.workspace.current_dir // .cwd // \"unknown\"' 2>/dev/null | sed \"s|^$HOME|~|g\")` : ''}${hasModel ? `\n model_name=$(echo \"$input\" | jq -r '.model.display_name // \"Claude\"' 2>/dev/null)\n model_version=$(echo \"$input\" | jq -r '.model.version // \"\"' 2>/dev/null)` : ''}\nelse${hasDirectory ? `\n current_dir=\"unknown\"` : ''}${hasModel ? `\n model_name=\"Claude\"; model_version=\"\"` : ''}\nfi\n`\n}\n\nfunction generateLoggingOutput(): string {\n return `\n# ---- log extracted data ----\n{\n echo \"[\\$TIMESTAMP] Extracted: dir=\\${current_dir:-}, model=\\${model_name:-}, version=\\${model_version:-}, git=\\${git_branch:-}, cost=\\${cost_usd:-}, cost_ph=\\${cost_per_hour:-}, tokens=\\${tot_tokens:-}, tpm=\\${tpm:-}, session_pct=\\${session_pct:-}\"\n} >> \"$LOG_FILE\" 2>/dev/null\n`\n}\n\nfunction generateDisplaySection(config: StatuslineConfig, gitConfig: any, usageConfig: any): string {\n const emojis = config.colors && !config.customEmojis\n\n let displayCode = `\n# ---- render statusline ----`\n\n // Directory\n if (config.features.includes('directory')) {\n const dirEmoji = emojis ? 'šŸ“' : 'dir:'\n displayCode += `\nprintf '${dirEmoji} %s%s%s' \"$(dir_color)\" \"$current_dir\" \"$(rst)\"`\n }\n\n // Git\n displayCode += generateGitDisplayCode(gitConfig, config.colors, emojis)\n\n // Model\n if (config.features.includes('model')) {\n const modelEmoji = emojis ? 'šŸ¤–' : 'model:'\n displayCode += `\nprintf ' ${modelEmoji} %s%s%s' \"$(model_color)\" \"$model_name\" \"$(rst)\"\nif [ -n \"$model_version\" ] && [ \"$model_version\" != \"null\" ]; then\n printf ' šŸ·ļø %s%s%s' \"$(version_color)\" \"$model_version\" \"$(rst)\"\nfi`\n }\n\n // Usage features\n displayCode += generateUsageDisplayCode(usageConfig, config.colors, emojis)\n\n return displayCode\n}","export interface ColorConfig {\n enabled: boolean\n theme: 'minimal' | 'detailed' | 'compact'\n}\n\nexport function generateColorBashCode(config: ColorConfig): string {\n if (!config.enabled) {\n return `\n# ---- color helpers (disabled) ----\nuse_color=0\nC() { :; }\nRST() { :; }\n`\n }\n\n return `\n# ---- color helpers (TTY-aware, respect NO_COLOR) ----\nuse_color=1\n[ -t 1 ] || use_color=0\n[ -n \"$NO_COLOR\" ] && use_color=0\n\nC() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[%sm' \"$1\"; fi; }\nRST() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[0m'; fi; }\n`\n}\n\nexport function generateBasicColors(): string {\n return `\n# ---- basic colors ----\ndir_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;36m'; fi; } # cyan\nmodel_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;35m'; fi; } # magenta \nversion_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;33m'; fi; } # yellow\nrst() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[0m'; fi; }\n`\n}\n\nexport const COLOR_CODES = {\n // Basic colors\n BLACK: '30',\n RED: '31', \n GREEN: '32',\n YELLOW: '33',\n BLUE: '34',\n MAGENTA: '35',\n CYAN: '36',\n WHITE: '37',\n \n // Bright colors (bold)\n BRIGHT_BLACK: '1;30',\n BRIGHT_RED: '1;31',\n BRIGHT_GREEN: '1;32', \n BRIGHT_YELLOW: '1;33',\n BRIGHT_BLUE: '1;34',\n BRIGHT_MAGENTA: '1;35',\n BRIGHT_CYAN: '1;36',\n BRIGHT_WHITE: '1;37',\n \n // Reset\n RESET: '0'\n} as const\n\nexport function getThemeColors(theme: 'minimal' | 'detailed' | 'compact') {\n switch (theme) {\n case 'minimal':\n return {\n directory: COLOR_CODES.CYAN,\n git: COLOR_CODES.GREEN,\n model: COLOR_CODES.MAGENTA,\n usage: COLOR_CODES.YELLOW,\n session: COLOR_CODES.BLUE\n }\n case 'detailed':\n return {\n directory: COLOR_CODES.BRIGHT_CYAN,\n git: COLOR_CODES.BRIGHT_GREEN,\n model: COLOR_CODES.BRIGHT_MAGENTA,\n usage: COLOR_CODES.BRIGHT_YELLOW,\n session: COLOR_CODES.BRIGHT_BLUE\n }\n case 'compact':\n return {\n directory: COLOR_CODES.CYAN,\n git: COLOR_CODES.GREEN,\n model: COLOR_CODES.BLUE,\n usage: COLOR_CODES.YELLOW,\n session: COLOR_CODES.RED\n }\n }\n}","export interface GitFeature {\n enabled: boolean\n showBranch: boolean\n showChanges: boolean\n compactMode: boolean\n}\n\nexport function generateGitBashCode(config: GitFeature, colors: boolean): string {\n if (!config.enabled) return ''\n\n const colorCode = colors ? `\n# ---- git colors ----\ngit_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;32m'; fi; }\nrst() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[0m'; fi; }\n` : `\ngit_color() { :; }\nrst() { :; }\n`\n\n return `${colorCode}\n# ---- git ----\ngit_branch=\"\"\nif git rev-parse --git-dir >/dev/null 2>&1; then\n git_branch=$(git branch --show-current 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)\nfi`\n}\n\nexport function generateGitDisplayCode(config: GitFeature, colors: boolean, emojis: boolean): string {\n if (!config.enabled) return ''\n\n const branchEmoji = emojis ? '🌿' : 'git:'\n\n let displayCode = `\n# git display\nif [ -n \"$git_branch\" ]; then\n printf ' ${branchEmoji} %s%s%s' \"$(git_color)\" \"$git_branch\" \"$(rst)\"\nfi`\n\n return displayCode\n}\n\nexport function generateGitUtilities(): string {\n return `\n# git utilities\nnum_or_zero() { v=\"$1\"; [[ \"$v\" =~ ^[0-9]+$ ]] && echo \"$v\" || echo 0; }`\n}","export interface UsageFeature {\n enabled: boolean\n showCost: boolean\n showTokens: boolean\n showBurnRate: boolean\n showSession: boolean\n showProgressBar: boolean\n}\n\nexport function generateUsageBashCode(config: UsageFeature, colors: boolean): string {\n if (!config.enabled) return ''\n\n const colorCode = colors ? `\n# ---- usage colors ----\nusage_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;35m'; fi; }\ncost_color() { if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[1;36m'; fi; }\nsession_color() { \n rem_pct=$(( 100 - session_pct ))\n if (( rem_pct <= 10 )); then SCLR='1;31'\n elif (( rem_pct <= 25 )); then SCLR='1;33'\n else SCLR='1;32'; fi\n if [ \"$use_color\" -eq 1 ]; then printf '\\\\033[%sm' \"$SCLR\"; fi\n}\n` : `\nusage_color() { :; }\ncost_color() { :; }\nsession_color() { :; }\n`\n\n return `${colorCode}\n# ---- ccusage integration ----\nsession_txt=\"\"; session_pct=0; session_bar=\"\"\ncost_usd=\"\"; cost_per_hour=\"\"; tpm=\"\"; tot_tokens=\"\"\n\nif command -v jq >/dev/null 2>&1; then\n blocks_output=$(npx ccusage@latest blocks --json 2>/dev/null || ccusage blocks --json 2>/dev/null)\n if [ -n \"$blocks_output\" ]; then\n active_block=$(echo \"$blocks_output\" | jq -c '.blocks[] | select(.isActive == true)' 2>/dev/null | head -n1)\n if [ -n \"$active_block\" ]; then${config.showCost ? `\n cost_usd=$(echo \"$active_block\" | jq -r '.costUSD // empty')\n cost_per_hour=$(echo \"$active_block\" | jq -r '.burnRate.costPerHour // empty')` : ''}${config.showTokens ? `\n tot_tokens=$(echo \"$active_block\" | jq -r '.totalTokens // empty')` : ''}${config.showBurnRate ? `\n tpm=$(echo \"$active_block\" | jq -r '.burnRate.tokensPerMinute // empty')` : ''}${config.showSession || config.showProgressBar ? `\n \n # Session time calculation\n reset_time_str=$(echo \"$active_block\" | jq -r '.usageLimitResetTime // .endTime // empty')\n start_time_str=$(echo \"$active_block\" | jq -r '.startTime // empty')\n \n if [ -n \"$reset_time_str\" ] && [ -n \"$start_time_str\" ]; then\n start_sec=$(to_epoch \"$start_time_str\"); end_sec=$(to_epoch \"$reset_time_str\"); now_sec=$(date +%s)\n total=$(( end_sec - start_sec )); (( total<1 )) && total=1\n elapsed=$(( now_sec - start_sec )); (( elapsed<0 ))&&elapsed=0; (( elapsed>total ))&&elapsed=$total\n session_pct=$(( elapsed * 100 / total ))\n remaining=$(( end_sec - now_sec )); (( remaining<0 )) && remaining=0\n rh=$(( remaining / 3600 )); rm=$(( (remaining % 3600) / 60 ))\n end_hm=$(fmt_time_hm \"$end_sec\")${config.showSession ? `\n session_txt=\"$(printf '%dh %dm until reset at %s (%d%%)' \"$rh\" \"$rm\" \"$end_hm\" \"$session_pct\")\"` : ''}${config.showProgressBar ? `\n session_bar=$(progress_bar \"$session_pct\" 10)` : ''}\n fi` : ''}\n fi\n fi\nfi`\n}\n\nexport function generateUsageUtilities(): string {\n return `\n# ---- time helpers ----\nto_epoch() {\n ts=\"$1\"\n if command -v gdate >/dev/null 2>&1; then gdate -d \"$ts\" +%s 2>/dev/null && return; fi\n date -u -j -f \"%Y-%m-%dT%H:%M:%S%z\" \"\\${ts/Z/+0000}\" +%s 2>/dev/null && return\n python3 - \"$ts\" <<'PY' 2>/dev/null\nimport sys, datetime\ns=sys.argv[1].replace('Z','+00:00')\nprint(int(datetime.datetime.fromisoformat(s).timestamp()))\nPY\n}\n\nfmt_time_hm() {\n epoch=\"$1\"\n if date -r 0 +%s >/dev/null 2>&1; then date -r \"$epoch\" +\"%H:%M\"; else date -d \"@$epoch\" +\"%H:%M\"; fi\n}\n\nprogress_bar() {\n pct=\"\\${1:-0}\"; width=\"\\${2:-10}\"\n [[ \"$pct\" =~ ^[0-9]+$ ]] || pct=0; ((pct<0))&&pct=0; ((pct>100))&&pct=100\n filled=$(( pct * width / 100 )); empty=$(( width - filled ))\n printf '%*s' \"$filled\" '' | tr ' ' '='\n printf '%*s' \"$empty\" '' | tr ' ' '-'\n}`\n}\n\nexport function generateUsageDisplayCode(config: UsageFeature, colors: boolean, emojis: boolean): string {\n if (!config.enabled) return ''\n\n let displayCode = ''\n\n if (config.showSession) {\n const sessionEmoji = emojis ? 'āŒ›' : 'session:'\n displayCode += `\n# session time\nif [ -n \"$session_txt\" ]; then\n printf ' ${sessionEmoji} %s%s%s' \"$(session_color)\" \"$session_txt\" \"$(rst)\"${config.showProgressBar ? `\n printf ' %s[%s]%s' \"$(session_color)\" \"$session_bar\" \"$(rst)\"` : ''}\nfi`\n }\n\n if (config.showCost) {\n const costEmoji = emojis ? 'šŸ’µ' : '$'\n displayCode += `\n# cost\nif [ -n \"$cost_usd\" ] && [[ \"$cost_usd\" =~ ^[0-9.]+$ ]]; then\n if [ -n \"$cost_per_hour\" ] && [[ \"$cost_per_hour\" =~ ^[0-9.]+$ ]]; then\n printf ' ${costEmoji} %s$%.2f ($%.2f/h)%s' \"$(cost_color)\" \"$cost_usd\" \"$cost_per_hour\" \"$(rst)\"\n else\n printf ' ${costEmoji} %s$%.2f%s' \"$(cost_color)\" \"$cost_usd\" \"$(rst)\"\n fi\nfi`\n }\n\n if (config.showTokens) {\n const tokenEmoji = emojis ? 'šŸ“Š' : 'tok:'\n displayCode += `\n# tokens\nif [ -n \"$tot_tokens\" ] && [[ \"$tot_tokens\" =~ ^[0-9]+$ ]]; then\n if [ -n \"$tpm\" ] && [[ \"$tpm\" =~ ^[0-9.]+$ ]] && ${config.showBurnRate ? 'true' : 'false'}; then\n printf ' ${tokenEmoji} %s%s tok (%.0f tpm)%s' \"$(usage_color)\" \"$tot_tokens\" \"$tpm\" \"$(rst)\"\n else\n printf ' ${tokenEmoji} %s%s tok%s' \"$(usage_color)\" \"$tot_tokens\" \"$(rst)\"\n fi\nfi`\n }\n\n return displayCode\n}","import { StatuslineConfig } from '../cli/prompts.js'\n\nexport interface ValidationResult {\n isValid: boolean\n errors: string[]\n warnings: string[]\n}\n\nexport function validateConfig(config: StatuslineConfig): ValidationResult {\n const errors: string[] = []\n const warnings: string[] = []\n\n // Validate features\n if (!config.features || config.features.length === 0) {\n errors.push('At least one display feature must be selected')\n }\n\n // Validate runtime\n if (!['bash', 'python', 'node'].includes(config.runtime)) {\n errors.push(`Invalid runtime: ${config.runtime}`)\n }\n\n // Validate theme\n if (!['minimal', 'detailed', 'compact'].includes(config.theme)) {\n errors.push(`Invalid theme: ${config.theme}`)\n }\n\n // Check for usage features without ccusage integration\n const usageFeatures = ['usage', 'session', 'tokens', 'burnrate']\n const hasUsageFeatures = config.features.some(f => usageFeatures.includes(f))\n \n if (hasUsageFeatures && !config.ccusageIntegration) {\n warnings.push('Usage features selected but ccusage integration is disabled. Some features may not work properly.')\n }\n\n // Warn about performance with many features\n if (config.features.length > 5) {\n warnings.push('Many features selected. This may impact statusline performance.')\n }\n\n // Validate color/emoji consistency\n if (config.customEmojis && !config.colors) {\n warnings.push('Custom emojis enabled but colors disabled. Visual distinction may be limited.')\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n }\n}\n\nexport function validateDependencies(): {\n jq: boolean\n git: boolean\n ccusage: boolean\n python?: boolean\n node?: boolean\n} {\n // This would check system dependencies\n // For now, return placeholder\n return {\n jq: true, // Would check: command -v jq >/dev/null 2>&1\n git: true, // Would check: command -v git >/dev/null 2>&1\n ccusage: false, // Would check: command -v ccusage >/dev/null 2>&1\n python: true, // Would check: command -v python3 >/dev/null 2>&1\n node: true // Would check: command -v node >/dev/null 2>&1\n }\n}","import { StatuslineConfig } from '../cli/prompts.js'\nimport { promises as fs } from 'fs'\nimport path from 'path'\n\nexport async function installStatusline(\n script: string,\n outputPath: string,\n config: StatuslineConfig\n): Promise<void> {\n try {\n // Ensure the directory exists\n const dir = path.dirname(outputPath)\n await fs.mkdir(dir, { recursive: true })\n\n // Write the script\n await fs.writeFile(outputPath, script, { mode: 0o755 })\n\n // Update .claude/settings.json if it exists\n await updateSettingsJson(dir, path.basename(outputPath))\n\n // Note: statusline-config.json removed per user feedback - not needed\n // The statusline script contains all necessary configuration info\n\n } catch (error) {\n throw new Error(`Failed to install statusline: ${error instanceof Error ? error.message : String(error)}`)\n }\n}\n\nasync function updateSettingsJson(claudeDir: string, scriptName: string): Promise<void> {\n const settingsPath = path.join(claudeDir, 'settings.json')\n \n try {\n let settings: any = {}\n \n // Try to read existing settings\n try {\n const settingsContent = await fs.readFile(settingsPath, 'utf-8')\n settings = JSON.parse(settingsContent)\n } catch {\n // File doesn't exist or invalid JSON, start fresh\n }\n\n // Update statusLine configuration\n settings.statusLine = {\n type: 'command',\n command: `.claude/${scriptName}`,\n padding: 0\n }\n\n // Write updated settings\n await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2))\n \n } catch (error) {\n // Settings update failed, but don't fail the entire installation\n console.warn(`Warning: Could not update settings.json: ${error instanceof Error ? error.message : String(error)}`)\n throw new Error('SETTINGS_UPDATE_FAILED') // Signal that manual config is needed\n }\n}\n\nexport async function checkClaudeCodeSetup(): Promise<{\n hasClaudeDir: boolean\n hasSettings: boolean\n currentStatusline?: string\n}> {\n const claudeDir = './.claude'\n const settingsPath = path.join(claudeDir, 'settings.json')\n \n try {\n const dirExists = await fs.access(claudeDir).then(() => true).catch(() => false)\n const settingsExists = await fs.access(settingsPath).then(() => true).catch(() => false)\n \n let currentStatusline: string | undefined\n \n if (settingsExists) {\n try {\n const settings = JSON.parse(await fs.readFile(settingsPath, 'utf-8'))\n currentStatusline = settings.statusLine?.command\n } catch {\n // Ignore JSON parse errors\n }\n }\n \n return {\n hasClaudeDir: dirExists,\n hasSettings: settingsExists,\n currentStatusline\n }\n } catch {\n return {\n hasClaudeDir: false,\n hasSettings: false\n }\n }\n}"],"mappings":"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","names":["fs","path","process","fs","chalk","ora","path","path","testStatuslineScript","generateMockClaudeInput","chalk","previewCommand"]}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@chongdashu/cc-statusline",
3
+ "version": "1.0.0",
4
+ "description": "Interactive CLI tool for generating custom Claude Code statuslines",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "cc-statusline": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsup",
12
+ "dev": "tsup --watch",
13
+ "start": "node dist/index.js",
14
+ "test": "npm run build && node dist/test.js",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "claude-code",
19
+ "claude",
20
+ "statusline",
21
+ "status-line",
22
+ "cli",
23
+ "terminal",
24
+ "productivity",
25
+ "development",
26
+ "anthropic",
27
+ "ai-tools"
28
+ ],
29
+ "author": {
30
+ "name": "Chong-U",
31
+ "email": "chong-u@aioriented.dev",
32
+ "url": "https://github.com/chongdashu"
33
+ },
34
+ "license": "MIT",
35
+ "dependencies": {
36
+ "commander": "^11.1.0",
37
+ "inquirer": "^9.2.12",
38
+ "chalk": "^5.3.0",
39
+ "ora": "^7.0.1"
40
+ },
41
+ "devDependencies": {
42
+ "@types/inquirer": "^9.0.7",
43
+ "@types/node": "^20.10.5",
44
+ "tsup": "^8.0.1",
45
+ "typescript": "^5.3.3"
46
+ },
47
+ "engines": {
48
+ "node": ">=16.0.0"
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/chongdashu/cc-statusline.git"
53
+ },
54
+ "bugs": {
55
+ "url": "https://github.com/chongdashu/cc-statusline/issues"
56
+ },
57
+ "homepage": "https://github.com/chongdashu/cc-statusline#readme"
58
+ }