cc-api-statusline 0.1.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/README.md ADDED
@@ -0,0 +1,579 @@
1
+ # cc-api-statusline
2
+
3
+ > Claude Code statusline widget for monitoring API usage from third-party proxy backends
4
+
5
+ A high-performance TUI statusline tool that polls API usage data from Claude API proxy services (sub2api, claude-relay-service, or custom providers) and renders a configurable one-line status display.
6
+
7
+ ## Features
8
+
9
+ - ⚡ **Fast piped mode** — <25ms warm cache, <100ms p95
10
+ - 🎨 **Highly configurable** — Layouts, colors, bar styles, display modes
11
+ - 🔌 **Provider autodetection** — Works with sub2api, claude-relay-service, custom providers
12
+ - 💾 **Smart caching** — Disk cache with atomic writes, TTL validation
13
+ - 🎯 **Claude Code integration** — Auto-setup with `--install` command
14
+ - 📊 **Multiple components** — Daily/weekly/monthly quotas, balance, tokens, rate limits
15
+ - 🐛 **Debug logging** — Detailed execution logs for troubleshooting
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # Using npm
21
+ npm install -g cc-api-statusline
22
+
23
+ # Using bun
24
+ bun add -g cc-api-statusline
25
+
26
+ # From source
27
+ git clone https://github.com/liafonx/cc-api-statusline
28
+ cd cc-api-statusline
29
+ bun install
30
+ bun run build
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ### Claude Code Integration (Recommended)
36
+
37
+ The easiest way to use cc-api-statusline is with auto-setup:
38
+
39
+ ```bash
40
+ # Set required environment variables first
41
+ export ANTHROPIC_BASE_URL="https://your-proxy.example.com"
42
+ export ANTHROPIC_AUTH_TOKEN="your-api-token"
43
+
44
+ # Install as Claude Code statusline widget
45
+ npx cc-api-statusline --install
46
+
47
+ # Or with bunx (auto-detects if available)
48
+ bunx cc-api-statusline --install --runner bunx
49
+
50
+ # Uninstall
51
+ npx cc-api-statusline --uninstall
52
+ ```
53
+
54
+ This automatically adds to `~/.claude/settings.json`:
55
+
56
+ ```json
57
+ {
58
+ "statusLine": {
59
+ "type": "command",
60
+ "command": "bunx -y cc-api-statusline@latest",
61
+ "padding": 0
62
+ }
63
+ }
64
+ ```
65
+
66
+ ### Standalone Mode
67
+
68
+ ```bash
69
+ # Set required environment variables
70
+ export ANTHROPIC_BASE_URL="https://your-proxy.example.com"
71
+ export ANTHROPIC_AUTH_TOKEN="your-api-token"
72
+
73
+ # Run once and exit
74
+ cc-api-statusline --once
75
+
76
+ # Run with custom config
77
+ cc-api-statusline --config ./my-config.json
78
+ ```
79
+
80
+ ### ccstatusline Custom Command (Legacy)
81
+
82
+ Add to your `~/.claude/ccstatusline/config.json`:
83
+
84
+ ```json
85
+ {
86
+ "customCommands": {
87
+ "usage": {
88
+ "command": "cc-api-statusline",
89
+ "description": "API usage statusline",
90
+ "type": "piped"
91
+ }
92
+ },
93
+ "widgets": [
94
+ {
95
+ "type": "customCommand",
96
+ "command": "usage",
97
+ "refreshIntervalMs": 30000,
98
+ "maxWidth": 80,
99
+ "preserveColors": true
100
+ }
101
+ ]
102
+ }
103
+ ```
104
+
105
+ ## Configuration
106
+
107
+ Configuration file: `~/.claude/cc-api-statusline/config.json`
108
+
109
+ ### User-Agent Spoofing (Optional)
110
+
111
+ Some API providers restrict requests to only come from Claude Code clients. Enable User-Agent spoofing to bypass these restrictions:
112
+
113
+ ```json
114
+ {
115
+ "spoofClaudeCodeUA": true
116
+ }
117
+ ```
118
+
119
+ **Options:**
120
+ - `false` / `undefined` — No User-Agent header (default)
121
+ - `true` — Auto-detect Claude Code version, fallback to `claude-cli/2.1.56 (external, cli)`
122
+ - `"string"` — Use custom User-Agent string
123
+
124
+ **Per-provider override (custom providers only):**
125
+
126
+ ```json
127
+ {
128
+ "spoofClaudeCodeUA": true,
129
+ "customProviders": {
130
+ "my-provider": {
131
+ "spoofClaudeCodeUA": "custom-client/1.0.0"
132
+ }
133
+ }
134
+ }
135
+ ```
136
+
137
+ ### Example Configuration
138
+
139
+ ```json
140
+ {
141
+ "display": {
142
+ "layout": "standard",
143
+ "displayMode": "bar",
144
+ "barSize": "medium",
145
+ "barStyle": "classic",
146
+ "separator": " | ",
147
+ "maxWidth": 80,
148
+ "clockFormat": "24h"
149
+ },
150
+ "components": {
151
+ "daily": true,
152
+ "weekly": true,
153
+ "monthly": true,
154
+ "balance": true,
155
+ "tokens": false,
156
+ "rateLimit": false,
157
+ "plan": false
158
+ },
159
+ "colors": {
160
+ "auto": {
161
+ "low": "green",
162
+ "medium": "yellow",
163
+ "high": "red",
164
+ "lowThreshold": 50,
165
+ "highThreshold": 80
166
+ }
167
+ },
168
+ "pollIntervalSeconds": 30,
169
+ "pipedRequestTimeoutMs": 800
170
+ }
171
+ ```
172
+
173
+ ### Display Options
174
+
175
+ #### Layouts
176
+
177
+ - `standard` — Full labels (e.g., "Daily 24%")
178
+ - `compact` — Single-letter labels (e.g., "D 24%")
179
+ - `minimal` — No labels (e.g., "24%")
180
+ - `percent-first` — Percentage before bar (e.g., "Daily 24% ━━──")
181
+
182
+ #### Display Modes
183
+
184
+ - `bar` — Progress bar visualization
185
+ - `percentage` — Percentage only (no bar)
186
+ - `icon-pct` — Nerd-font icon + percentage
187
+
188
+ #### Bar Styles
189
+
190
+ - `classic` — `━━━━────` (default)
191
+ - `block` — `████░░░░`
192
+ - `shade` — `▓▓▓▓░░░░`
193
+ - `pipe` — `||||····`
194
+ - `dot` — `●●●●○○○○`
195
+ - `braille` — `⣿⣿⣿⣿⠀⠀⠀⠀` (smooth gradients)
196
+ - `square` — `■■■■□□□□`
197
+ - `star` — `★★★★☆☆☆☆`
198
+ - Custom — `{"fill": "▰", "empty": "▱"}`
199
+
200
+ #### Bar Sizes
201
+
202
+ - `small` — 4 chars
203
+ - `small-medium` — 6 chars
204
+ - `medium` — 8 chars (default)
205
+ - `medium-large` — 10 chars
206
+ - `large` — 12 chars
207
+
208
+ ### Per-Component Configuration
209
+
210
+ Override global settings per component:
211
+
212
+ ```json
213
+ {
214
+ "components": {
215
+ "daily": {
216
+ "barStyle": "dot",
217
+ "color": "chill",
218
+ "countdown": {
219
+ "format": "duration",
220
+ "divider": " · ",
221
+ "prefix": "⏱ "
222
+ }
223
+ },
224
+ "weekly": {
225
+ "layout": "compact",
226
+ "displayMode": "icon-pct"
227
+ },
228
+ "balance": {
229
+ "label": "Credits"
230
+ }
231
+ }
232
+ }
233
+ ```
234
+
235
+ **Note:** Countdown divider defaults to ` · ` (space-dot-space) for clean spacing.
236
+
237
+ ### Color Configuration
238
+
239
+ #### Named Colors
240
+
241
+ `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, `dim`, `bright-red`, `bright-green`, etc.
242
+
243
+ #### Hex Colors
244
+
245
+ ```json
246
+ {
247
+ "components": {
248
+ "daily": {
249
+ "color": "#00ff00"
250
+ }
251
+ }
252
+ }
253
+ ```
254
+
255
+ #### Dynamic Color Aliases
256
+
257
+ ```json
258
+ {
259
+ "colors": {
260
+ "auto": {
261
+ "low": "green",
262
+ "medium": "yellow",
263
+ "high": "red",
264
+ "lowThreshold": 50,
265
+ "highThreshold": 80
266
+ },
267
+ "chill": {
268
+ "low": "cyan",
269
+ "medium": "blue",
270
+ "high": "magenta",
271
+ "lowThreshold": 60,
272
+ "highThreshold": 90
273
+ }
274
+ }
275
+ }
276
+ ```
277
+
278
+ #### Per-Part Coloring
279
+
280
+ ```json
281
+ {
282
+ "components": {
283
+ "daily": {
284
+ "colors": {
285
+ "label": "#8a8a8a",
286
+ "bar": "auto",
287
+ "value": "white",
288
+ "countdown": "#666666"
289
+ }
290
+ }
291
+ }
292
+ }
293
+ ```
294
+
295
+ ## Environment Variables
296
+
297
+ | Variable | Required | Description |
298
+ |----------|----------|-------------|
299
+ | `ANTHROPIC_BASE_URL` | Yes | API endpoint (e.g., `https://api.sub2api.com`) |
300
+ | `ANTHROPIC_AUTH_TOKEN` | Yes | API key or token |
301
+ | `CC_STATUSLINE_PROVIDER` | No | Override provider detection (`sub2api`, `claude-relay-service`, or custom) |
302
+ | `CC_STATUSLINE_POLL` | No | Override poll interval (seconds, min 5) |
303
+ | `CC_STATUSLINE_TIMEOUT` | No | Piped mode timeout (milliseconds, default 1000) |
304
+ | `DEBUG` or `CC_STATUSLINE_DEBUG` | No | Enable debug logging to `~/.claude/cc-api-statusline/debug.log` |
305
+
306
+ ## Provider Setup
307
+
308
+ ### sub2api
309
+
310
+ ```bash
311
+ export ANTHROPIC_BASE_URL="https://api.sub2api.com"
312
+ export ANTHROPIC_AUTH_TOKEN="sk-sub2api-..."
313
+ ```
314
+
315
+ ### claude-relay-service
316
+
317
+ ```bash
318
+ export ANTHROPIC_BASE_URL="https://relay.example.com"
319
+ export ANTHROPIC_AUTH_TOKEN="your-relay-token"
320
+ ```
321
+
322
+ ### Custom Providers
323
+
324
+ Define custom providers in config.json:
325
+
326
+ ```json
327
+ {
328
+ "customProviders": {
329
+ "my-provider": {
330
+ "urlPatterns": ["my-proxy.example.com"],
331
+ "endpoint": "/api/usage",
332
+ "method": "GET",
333
+ "authMode": "bearer",
334
+ "responseMapping": {
335
+ "billingMode": "$.mode",
336
+ "daily.used": "$.usage.daily",
337
+ "daily.limit": "$.limits.daily"
338
+ }
339
+ }
340
+ }
341
+ }
342
+ ```
343
+
344
+ ## CLI Usage
345
+
346
+ ```bash
347
+ # Show help
348
+ cc-api-statusline --help
349
+
350
+ # Show version
351
+ cc-api-statusline --version
352
+
353
+ # Fetch once and exit
354
+ cc-api-statusline --once
355
+
356
+ # Use custom config file
357
+ cc-api-statusline --config /path/to/config.json
358
+
359
+ # Install as Claude Code statusline widget
360
+ cc-api-statusline --install
361
+ cc-api-statusline --install --runner bunx
362
+ cc-api-statusline --install --force # Overwrite existing
363
+
364
+ # Uninstall from Claude Code
365
+ cc-api-statusline --uninstall
366
+ ```
367
+
368
+ ## Debug Logging
369
+
370
+ Enable detailed execution logs for troubleshooting:
371
+
372
+ ```bash
373
+ # Enable debug logging
374
+ DEBUG=1 cc-api-statusline --once
375
+
376
+ # For Claude Code widget, add to settings.json:
377
+ {
378
+ "statusLine": {
379
+ "type": "command",
380
+ "command": "DEBUG=1 bunx -y cc-api-statusline@latest",
381
+ "padding": 0
382
+ }
383
+ }
384
+
385
+ # View logs in real-time
386
+ tail -f ~/.claude/cc-api-statusline/debug.log
387
+
388
+ # View recent logs
389
+ tail -20 ~/.claude/cc-api-statusline/debug.log
390
+
391
+ # Search for errors
392
+ grep "ERROR" ~/.claude/cc-api-statusline/debug.log
393
+ ```
394
+
395
+ Debug logs include:
396
+ - Execution start/finish timestamps
397
+ - Mode detection (piped vs TTY)
398
+ - Environment variables (sanitized)
399
+ - Config and cache status
400
+ - Execution paths taken (A/B/C/D)
401
+ - Fetch timing and performance metrics
402
+ - Cache operations
403
+ - Error details with fallback behavior
404
+
405
+ ## Performance
406
+
407
+ Piped mode performance targets (1000ms timeout):
408
+
409
+ - **Path A (warm cache)**: ≤25ms (p95 ≤100ms)
410
+ - **Path B (re-render)**: ≤55ms (p95 ≤100ms)
411
+ - **Path C (fetch)**: ≤840ms worst case
412
+ - **Path D (fallback)**: ≤25ms
413
+
414
+ Cache validation:
415
+ - TTL check
416
+ - Provider match
417
+ - Base URL match
418
+ - Version match
419
+ - Token hash match
420
+
421
+ Exit code behavior:
422
+ - Returns `0` when stale cache is shown with error indicators (output is still useful)
423
+ - Returns `1` only when no data can be shown (prevents confusing `[Exit: 1]` in widgets)
424
+
425
+ ## Troubleshooting
426
+
427
+ ### "Missing required environment variable"
428
+
429
+ Set `ANTHROPIC_BASE_URL` and `ANTHROPIC_AUTH_TOKEN`:
430
+
431
+ ```bash
432
+ export ANTHROPIC_BASE_URL="https://your-proxy.example.com"
433
+ export ANTHROPIC_AUTH_TOKEN="your-token"
434
+ ```
435
+
436
+ Or add to `~/.claude/settings.json`:
437
+
438
+ ```json
439
+ {
440
+ "env": {
441
+ "ANTHROPIC_BASE_URL": "https://your-proxy.example.com",
442
+ "ANTHROPIC_AUTH_TOKEN": "your-token"
443
+ }
444
+ }
445
+ ```
446
+
447
+ ### "Unknown provider"
448
+
449
+ Provider autodetection failed. Explicitly set provider:
450
+
451
+ ```bash
452
+ export CC_STATUSLINE_PROVIDER="sub2api"
453
+ ```
454
+
455
+ Or define a custom provider in config.json.
456
+
457
+ ### "[offline]" or "[stale]" indicator
458
+
459
+ Network error or cache staleness. Enable debug logging to investigate:
460
+
461
+ ```bash
462
+ DEBUG=1 cc-api-statusline --once
463
+ tail -f ~/.claude/cc-api-statusline/debug.log
464
+ ```
465
+
466
+ Check:
467
+ - Network connectivity to `ANTHROPIC_BASE_URL`
468
+ - API endpoint is responding
469
+ - Token is valid and not expired
470
+
471
+ ### Slow performance in piped mode
472
+
473
+ Check cache validity:
474
+ - Run `cc-api-statusline --once` standalone to warm cache
475
+ - Verify `~/.claude/cc-api-statusline/cache-*.json` exists
476
+ - Check `pipedRequestTimeoutMs` config (default 800ms)
477
+ - Enable debug logging to see fetch timing
478
+
479
+ ### Widget shows `[Exit: 1]` in Claude Code
480
+
481
+ This indicates the statusline command failed. Enable debug logging:
482
+
483
+ ```json
484
+ {
485
+ "statusLine": {
486
+ "type": "command",
487
+ "command": "DEBUG=1 bunx -y cc-api-statusline@latest",
488
+ "padding": 0
489
+ }
490
+ }
491
+ ```
492
+
493
+ Then check logs: `tail -f ~/.claude/cc-api-statusline/debug.log`
494
+
495
+ ## Development
496
+
497
+ ```bash
498
+ # Install dependencies
499
+ bun install
500
+
501
+ # Quick dev fetch (--once mode)
502
+ bun run start
503
+
504
+ # Simulate piped mode
505
+ bun run example
506
+
507
+ # Run tests
508
+ bun test
509
+
510
+ # Lint
511
+ bun run lint
512
+
513
+ # Build
514
+ bun run build
515
+
516
+ # Run all checks
517
+ bun run check
518
+ ```
519
+
520
+ ## Architecture
521
+
522
+ ```
523
+ ┌─────────────┐
524
+ │ main.ts │ ← Entry point, CLI orchestration, install/uninstall
525
+ └──────┬──────┘
526
+
527
+ ├──────────────────────────────────────┐
528
+ │ │
529
+ ┌──────▼────────┐ ┌────────▼────────┐
530
+ │ services/ │ │ providers/ │
531
+ │ - env │ │ - sub2api │
532
+ │ - cache │ │ - relay │
533
+ │ - config │ │ - custom │
534
+ │ - settings │ ← settings.json │ - autodetect │
535
+ │ - logger │ ← debug logging └────────┬────────┘
536
+ └──────┬────────┘ │
537
+ │ │
538
+ ├──────────────────────────────────────┘
539
+
540
+ ┌──────▼────────┐
541
+ │ execute-cycle │ ← Unified execution (Path A/B/C/D)
542
+ └──────┬────────┘
543
+
544
+ ┌──────▼────────┐
545
+ │ renderer/ │
546
+ │ - component │ ← Per-component rendering
547
+ │ - bar │ ← Progress bars
548
+ │ - colors │ ← ANSI color system
549
+ │ - countdown │ ← Time-to-reset
550
+ │ - error │ ← Error states
551
+ │ - icons │ ← Nerd-font glyphs
552
+ │ - truncate │ ← Terminal width
553
+ │ - index │ ← Main pipeline
554
+ └───────────────┘
555
+ ```
556
+
557
+ ## Testing
558
+
559
+ - **356 tests** across **21 test files**
560
+ - Unit tests for all services and renderers
561
+ - Core execution path tests (A/B/C/D)
562
+ - E2E smoke tests with isolated environments
563
+ - Performance tests (p95 < 600ms verification)
564
+ - CI/CD via GitHub Actions
565
+
566
+ Run: `bun run check`
567
+
568
+ ## License
569
+
570
+ MIT
571
+
572
+ ## Links
573
+
574
+ - [Implementation Handbook](docs/implementation-handbook.md)
575
+ - [Current Implementation](docs/current-implementation.md)
576
+ - [TUI Style Spec](docs/spec-tui-style.md)
577
+ - [API Polling Spec](docs/spec-api-polling.md)
578
+ - [Custom Providers Spec](docs/spec-custom-providers.md)
579
+ - [AGENTS.md](AGENTS.md) - Development handoff guide