@statforge/claudestat 1.1.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +240 -70
- package/dist/claude-auth.d.ts +7 -0
- package/dist/claude-auth.js +12 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +12 -0
- package/dist/daemon.js +78 -15
- package/dist/db.d.ts +31 -0
- package/dist/db.js +89 -0
- package/dist/doctor.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +192 -70
- package/dist/insights.d.ts +45 -0
- package/dist/insights.js +257 -0
- package/dist/mcp-server.d.ts +9 -0
- package/dist/mcp-server.js +442 -0
- package/dist/notifier.js +24 -6
- package/dist/pattern-analyzer.d.ts +1 -0
- package/dist/pattern-analyzer.js +13 -0
- package/dist/quota-tracker.d.ts +7 -0
- package/dist/quota-tracker.js +83 -31
- package/dist/roast.js +129 -40
- package/dist/routes/events.js +3 -3
- package/dist/routes/projects.js +2 -2
- package/dist/share.js +5 -1
- package/dist/summarizer.js +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Works with Claude Pro, Max 5, and Max 20. Zero cloud dependencies. Pure Node.js.
|
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
[](https://nodejs.org)
|
|
14
14
|
[]()
|
|
15
|
-
[]()
|
|
16
16
|
[](CONTRIBUTING.md)
|
|
17
17
|
|
|
18
18
|
[Installation](#installation) • [Quick Start](#quick-start) • [Commands](#commands) • [Dashboard](#dashboard) • [Contributing](#contributing)
|
|
@@ -43,7 +43,9 @@ Claude Code is powerful — but it's a black box while it runs. You can't see wh
|
|
|
43
43
|
- Quota guard with configurable kill switch (block new sessions at X%)
|
|
44
44
|
- Pattern analyzer: detects loops, Bash overuse, low cache reuse, and more
|
|
45
45
|
- Per-session cost breakdown + cache savings + burn rate
|
|
46
|
+
- Weekly usage insights with actionable tips
|
|
46
47
|
- AI-generated weekly usage reports
|
|
48
|
+
- MCP server: query quota, sessions, and tools from within Claude Code
|
|
47
49
|
|
|
48
50
|
> If claudestat is useful, give it a ⭐ — it helps other developers find it.
|
|
49
51
|
|
|
@@ -137,12 +139,14 @@ That's it. Start a Claude Code session and watch the events flow in.
|
|
|
137
139
|
| `claudestat uninstall` | Remove hooks from Claude Code |
|
|
138
140
|
| `claudestat watch` | Live terminal trace view |
|
|
139
141
|
| `claudestat status` | Show quota, cost, and burn rate |
|
|
140
|
-
| `claudestat status --compact` | One-line output for tmux status bar |
|
|
141
142
|
| `claudestat config` | View or edit configuration |
|
|
142
143
|
| `claudestat top` | Rank tools by cost, call count, or duration |
|
|
143
|
-
| `claudestat
|
|
144
|
-
| `claudestat
|
|
144
|
+
| `claudestat weekly` | Weekly usage summary with actionable tips |
|
|
145
|
+
| `claudestat insights` | Deep usage insights: cost breakdown, cache savings, efficiency, peak hours, model breakdown |
|
|
145
146
|
| `claudestat roast` | Sarcastic usage analysis with roast jokes |
|
|
147
|
+
| `claudestat roast --stats` | Raw stats with visual bars |
|
|
148
|
+
| `claudestat version` | Show version and check for npm updates |
|
|
149
|
+
| `claudestat export [format]` | Export session data to JSON or CSV |
|
|
146
150
|
| `claudestat doctor` | Check installation health and diagnose issues |
|
|
147
151
|
|
|
148
152
|
### `claudestat watch`
|
|
@@ -170,92 +174,214 @@ Ranks your most-used tools by estimated cost, call count, or duration across all
|
|
|
170
174
|
```
|
|
171
175
|
claudestat top
|
|
172
176
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
2
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
🏆 claudestat top by est. cost (last 30 days)
|
|
178
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
179
|
+
|
|
180
|
+
1 Edit ████████████████░░░░ $146.47 21%
|
|
181
|
+
2479 calls · 38.5m
|
|
182
|
+
2 Bash ███████████████░░░░░ $140.66 20%
|
|
183
|
+
2651 calls · 153.6m
|
|
184
|
+
3 Read ██████████████░░░░░░ $126.08 18%
|
|
185
|
+
2315 calls · 34.0m
|
|
186
|
+
4 Grep ████░░░░░░░░░░░░░░░░ $39.93 6%
|
|
187
|
+
699 calls · 9.3m
|
|
188
|
+
5 ToolSearch ██░░░░░░░░░░░░░░░░░░ $21.83 3%
|
|
189
|
+
469 calls · 7.4m
|
|
190
|
+
6 Glob ██░░░░░░░░░░░░░░░░░░ $13.96 2%
|
|
191
|
+
269 calls · 5.7m
|
|
192
|
+
7 Write █░░░░░░░░░░░░░░░░░░░ $12.93 2%
|
|
193
|
+
237 calls · 87.1m
|
|
194
|
+
8 mcp__plugin_engr… █░░░░░░░░░░░░░░░░░░░ $8.10 1%
|
|
195
|
+
149 calls · 2.6m
|
|
196
|
+
9 Agent █░░░░░░░░░░░░░░░░░░░ $8.09 1%
|
|
197
|
+
168 calls · 95.7m
|
|
198
|
+
10 WebFetch █░░░░░░░░░░░░░░░░░░░ $5.86 1%
|
|
199
|
+
106 calls · 9.9m
|
|
200
|
+
Other — $184.79 26%
|
|
201
|
+
|
|
202
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
182
203
|
```
|
|
183
204
|
|
|
184
205
|
Options: `--by cost|count|duration` · `--days 7|30|90` · `--limit N`
|
|
185
206
|
|
|
207
|
+
### `claudestat weekly`
|
|
208
|
+
|
|
209
|
+
Weekly usage summary with an actionable tip. Detects patterns like Bash overuse, low efficiency, high session count, and loop frequency.
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
claudestat weekly
|
|
213
|
+
|
|
214
|
+
📊 claudestat weekly May 8 – May 13
|
|
215
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
216
|
+
|
|
217
|
+
💰 $198.38 total · 40 sessions · 114 loops
|
|
218
|
+
|
|
219
|
+
🔧 Top tool Bash 22% of cost
|
|
220
|
+
|
|
221
|
+
📈 Efficiency ██████████████████░░ 91/100
|
|
222
|
+
|
|
223
|
+
💾 Cache hit ████████████████████ 100%
|
|
224
|
+
|
|
225
|
+
📦 Tokens 73K in + 1.2M out
|
|
226
|
+
|
|
227
|
+
⚡ Tip: 114 loops detected — consider using /compact earlier to prevent context thrashing
|
|
228
|
+
|
|
229
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Options: `--json` for machine-readable output.
|
|
233
|
+
|
|
186
234
|
### `claudestat status`
|
|
187
235
|
|
|
236
|
+
Shows your current quota usage with visual progress bars, plan detection, and burn rate.
|
|
237
|
+
|
|
188
238
|
```
|
|
189
239
|
claudestat status
|
|
190
240
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
241
|
+
📊 claudestat PRO plan
|
|
242
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
243
|
+
|
|
244
|
+
5h ████████████████████ 100% resets 4:10 AM
|
|
245
|
+
|
|
246
|
+
Week ██████░░░░░░░░░░░░░░ 31% resets May 18
|
|
247
|
+
|
|
248
|
+
🔥 490 tok/min · 101 prompts used
|
|
249
|
+
|
|
250
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
195
251
|
```
|
|
196
252
|
|
|
197
|
-
|
|
253
|
+
Options: `--json` for machine-readable output.
|
|
198
254
|
|
|
199
|
-
|
|
255
|
+
### `claudestat insights`
|
|
256
|
+
|
|
257
|
+
Deep usage insights: cost breakdown by project, cache savings, output/input ratio, efficiency trend, peak activity hours, and model breakdown.
|
|
200
258
|
|
|
201
|
-
```bash
|
|
202
|
-
claudestat status --compact
|
|
203
|
-
Current 45%🟡 pro
|
|
204
259
|
```
|
|
260
|
+
claudestat insights
|
|
205
261
|
|
|
206
|
-
|
|
262
|
+
💡 claudestat insights last 7 days
|
|
263
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
207
264
|
|
|
208
|
-
|
|
265
|
+
💰 $4.96/session · 40 sessions · $198.38 total
|
|
209
266
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
267
|
+
🗂 Top projects
|
|
268
|
+
no project █████████░░░░░░░░░░░ $93.69 47%
|
|
269
|
+
|
|
270
|
+
claudestat ████████░░░░░░░░░░░░ $74.60 38%
|
|
271
|
+
|
|
272
|
+
wodrival ███░░░░░░░░░░░░░░░░░ $24.95 13%
|
|
273
|
+
|
|
274
|
+
aprendiendo-in ░░░░░░░░░░░░░░░░░░░░ $3.32 2%
|
|
275
|
+
|
|
276
|
+
other ░░░░░░░░░░░░░░░░░░░░ $1.81 1%
|
|
277
|
+
|
|
278
|
+
⚡ Cache ~$1029.43 saved · 100% hit rate
|
|
279
|
+
|
|
280
|
+
📊 16× output/input · cache-heavy workload
|
|
281
|
+
|
|
282
|
+
📈 Efficiency 91/100 ↓ -2 vs prev period · 114 loops
|
|
283
|
+
|
|
284
|
+
⏰ Activity by time of day
|
|
285
|
+
🌙 00:00–05:59 ████████████████████ 18 sessions
|
|
286
|
+
|
|
287
|
+
🌅 06:00–11:59 ███████░░░░░░░░░░░░░ 6 sessions
|
|
288
|
+
|
|
289
|
+
☀️ 12:00–17:59 ███░░░░░░░░░░░░░░░░░ 3 sessions
|
|
290
|
+
|
|
291
|
+
🌆 18:00–23:59 ██████████████░░░░░░ 13 sessions
|
|
292
|
+
|
|
293
|
+
🤖 Models
|
|
294
|
+
claude-sonnet-4-6 ████████████████████ $197.11 99% · 23 sessions
|
|
295
|
+
|
|
296
|
+
claude-haiku-4-5-20251001 ░░░░░░░░░░░░░░░░░░░░ $1.26 1% · 15 sessions
|
|
297
|
+
|
|
298
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
224
299
|
```
|
|
225
300
|
|
|
226
|
-
Options:
|
|
227
|
-
- `--format ascii|json` — output format (default: ascii)
|
|
228
|
-
- `--copy` — copy to clipboard automatically (macOS only)
|
|
301
|
+
Options: `--days 7|14|30|90` · `--json` for machine-readable output.
|
|
229
302
|
|
|
230
|
-
### `claudestat
|
|
303
|
+
### `claudestat config`
|
|
231
304
|
|
|
232
|
-
|
|
305
|
+
```
|
|
306
|
+
claudestat config
|
|
307
|
+
|
|
308
|
+
⚙️ claudestat config
|
|
309
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
310
|
+
|
|
311
|
+
Plan PRO
|
|
312
|
+
Alerts enabled
|
|
313
|
+
|
|
314
|
+
Kill switch OFF
|
|
315
|
+
████████████████████
|
|
316
|
+
|
|
317
|
+
Cycle thresholds 70%, 85%, 95%
|
|
318
|
+
yellow ████████░░ orange █████████░ red ██████████
|
|
319
|
+
|
|
320
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
321
|
+
```
|
|
233
322
|
|
|
234
323
|
```bash
|
|
235
|
-
|
|
324
|
+
# Enable kill switch at 90% quota
|
|
325
|
+
claudestat config --kill-switch true --threshold 90
|
|
326
|
+
|
|
327
|
+
# Force plan detection
|
|
328
|
+
claudestat config --plan max5 # pro | max5 | max20 | auto
|
|
236
329
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
Bash calls: 1,240
|
|
241
|
-
Loops: 8
|
|
242
|
-
Efficiency: 72/100
|
|
330
|
+
# Toggle daemon rate limit alerts
|
|
331
|
+
claudestat config --alerts false
|
|
332
|
+
```
|
|
243
333
|
|
|
244
|
-
|
|
334
|
+
Config is stored at `~/.claudestat/config.json` (macOS/Linux) or `%USERPROFILE%\.claudestat\config.json` (Windows).
|
|
245
335
|
|
|
246
|
-
|
|
247
|
-
That's once every 2.3 minutes.
|
|
248
|
-
Are you okay?
|
|
336
|
+
### `claudestat roast`
|
|
249
337
|
|
|
250
|
-
|
|
251
|
-
Claude was writing with amnesia half the time.
|
|
338
|
+
Get a sarcastic analysis of your Claude Code usage — humor with insights.
|
|
252
339
|
|
|
253
|
-
|
|
254
|
-
|
|
340
|
+
```bash
|
|
341
|
+
claudestat roast
|
|
255
342
|
|
|
256
|
-
|
|
343
|
+
🔥 Your Claude Code Roast (30 days)
|
|
344
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
345
|
+
|
|
346
|
+
Score ██████████████████░░ 92/100 ★★★★★
|
|
347
|
+
|
|
348
|
+
Scorecard
|
|
349
|
+
┌─────────────────┬──────────────┬──────────────┐
|
|
350
|
+
│ Metric │ Value │ Rating │
|
|
351
|
+
├─────────────────┼──────────────┼──────────────┤
|
|
352
|
+
│ Sessions │ 47 │ normal │
|
|
353
|
+
│ Total cost │ $12.40 │ frugal │
|
|
354
|
+
│ Avg/session │ $0.26/session│ efficient │
|
|
355
|
+
│ Bash calls │ 1240 │ 🔨 overload │
|
|
356
|
+
│ Loops │ 8 │ clean │
|
|
357
|
+
│ Efficiency │ 92/100 │ 🏆 elite │
|
|
358
|
+
│ Tokens │ 4.2M │ — │
|
|
359
|
+
│ Top tool │ Bash 38% │ — │
|
|
360
|
+
└─────────────────┴──────────────┴──────────────┘
|
|
361
|
+
|
|
362
|
+
Roast Cards
|
|
363
|
+
|
|
364
|
+
┌──────────────────────────────────────────────────┐
|
|
365
|
+
│ 🖥️ BASH OVERLOAD │
|
|
366
|
+
│ 1240 calls in 30d — once every 2.3 min │
|
|
367
|
+
│ Are you okay? │
|
|
368
|
+
└──────────────────────────────────────────────────┘
|
|
369
|
+
|
|
370
|
+
┌──────────────────────────────────────────────────┐
|
|
371
|
+
│ 🔄 LOOP MONEY PIT │
|
|
372
|
+
│ $4.20 wasted on loops — that's 14 coffees │
|
|
373
|
+
│ Just saying. │
|
|
374
|
+
└──────────────────────────────────────────────────┘
|
|
375
|
+
|
|
376
|
+
Verdict
|
|
377
|
+
You're a machine. Or maybe you're just not using Claude enough.
|
|
378
|
+
|
|
379
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
380
|
+
github.com/DeibyGS/claudestat
|
|
257
381
|
```
|
|
258
382
|
|
|
383
|
+
Options: `--stats` for raw stats with visual bars · `--months N` to look back N months.
|
|
384
|
+
|
|
259
385
|
### `claudestat doctor`
|
|
260
386
|
|
|
261
387
|
Diagnoses common installation problems — useful if `claudestat start` fails or hooks are not firing.
|
|
@@ -272,6 +398,9 @@ claudestat doctor
|
|
|
272
398
|
✓ Hook script deployed (~/.claudestat/hooks/event.js)
|
|
273
399
|
✓ Daemon running (localhost:7337)
|
|
274
400
|
✓ Global CLI symlink valid
|
|
401
|
+
✓ No duplicate claudestat binaries in PATH
|
|
402
|
+
✓ Version match (installed: v1.2.2)
|
|
403
|
+
✓ NVM prefix matches active binary
|
|
275
404
|
──────────────────────────────────────────────
|
|
276
405
|
All checks passed — claudestat is healthy!
|
|
277
406
|
```
|
|
@@ -280,6 +409,19 @@ If a check fails, `doctor` prints the exact fix command to run.
|
|
|
280
409
|
|
|
281
410
|
---
|
|
282
411
|
|
|
412
|
+
### `claudestat version`
|
|
413
|
+
|
|
414
|
+
Shows the current version and checks npm for updates.
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
claudestat version
|
|
418
|
+
|
|
419
|
+
1.2.2
|
|
420
|
+
latest ✓
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
If a newer version is available, it shows: `latest: 1.3.0 — run npm update`.
|
|
424
|
+
|
|
283
425
|
### `claudestat export`
|
|
284
426
|
|
|
285
427
|
Export session data to JSON or CSV. Supports date and project filters.
|
|
@@ -307,20 +449,36 @@ Each row includes: `id`, `started_at`, `cwd`, `project_path`, `total_cost_usd`,
|
|
|
307
449
|
|
|
308
450
|
---
|
|
309
451
|
|
|
310
|
-
|
|
452
|
+
## MCP Server
|
|
311
453
|
|
|
312
|
-
|
|
313
|
-
# Enable kill switch — block new sessions when quota exceeds 95%
|
|
314
|
-
claudestat config --kill-switch true --threshold 95
|
|
454
|
+
claudestat includes an MCP (Model Context Protocol) server that lets Claude Code query its own usage stats — Claude can tell you its quota, session cost, and top tools in real time.
|
|
315
455
|
|
|
316
|
-
|
|
317
|
-
claudestat config --plan max5 # pro | max5 | max20 | auto
|
|
456
|
+
### Tools exposed
|
|
318
457
|
|
|
319
|
-
|
|
320
|
-
|
|
458
|
+
| Tool | Description |
|
|
459
|
+
|------|------------|
|
|
460
|
+
| `get_quota_status` | 5h cycle usage %, plan, weekly hours, burn rate (with on-demand API refresh + disk cache) |
|
|
461
|
+
| `get_current_session` | Latest session: cost, tokens, efficiency, loops |
|
|
462
|
+
| `get_session_stats` | Aggregated stats for N days |
|
|
463
|
+
| `get_top_tools` | Top 10 tools by cost/count/duration (default 30 days) |
|
|
464
|
+
| `get_usage_insights` | Deep insights: cost per project, cache savings, efficiency trend, peak hours, model breakdown |
|
|
465
|
+
| `get_model_breakdown` | Cost and session count broken down by Claude model (Sonnet, Haiku, Opus) |
|
|
466
|
+
| `get_weekly_insight` | Weekly summary with actionable tip |
|
|
467
|
+
|
|
468
|
+
### Register with Claude Code
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
claude mcp add --transport stdio claudestat -- claudestat-mcp
|
|
321
472
|
```
|
|
322
473
|
|
|
323
|
-
|
|
474
|
+
Once registered, ask Claude things like:
|
|
475
|
+
- *"What's my current quota status?"*
|
|
476
|
+
- *"Show me my latest session cost"*
|
|
477
|
+
- *"What are my top 5 tools by cost this week?"*
|
|
478
|
+
- *"Give me usage insights for the last 14 days"*
|
|
479
|
+
- *"Break down my usage by model"*
|
|
480
|
+
|
|
481
|
+
Zero extra dependencies — stdio JSON-RPC, works without the daemon running. Uses on-demand API refresh with shared disk cache for accurate quota data.
|
|
324
482
|
|
|
325
483
|
---
|
|
326
484
|
|
|
@@ -477,7 +635,7 @@ Whether you want to fix a bug, improve a dashboard view, add a new pattern to th
|
|
|
477
635
|
1. Fork the repository
|
|
478
636
|
2. Create a branch: `git checkout -b feat/your-feature`
|
|
479
637
|
3. Make your changes
|
|
480
|
-
4. Run the test suite: `
|
|
638
|
+
4. Run the test suite: `node --require tsx/cjs tests/index.ts` (243 tests)
|
|
481
639
|
5. Open a PR with a clear description of what you changed and why
|
|
482
640
|
|
|
483
641
|
### Good first areas
|
|
@@ -494,11 +652,23 @@ git clone https://github.com/YOUR_USERNAME/claudestat
|
|
|
494
652
|
cd claudestat
|
|
495
653
|
npm install
|
|
496
654
|
npm run dev:full # starts daemon + dashboard hot-reload together
|
|
497
|
-
|
|
655
|
+
node --require tsx/cjs tests/index.ts # run all tests
|
|
498
656
|
```
|
|
499
657
|
|
|
500
658
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for full guidelines.
|
|
501
659
|
|
|
660
|
+
This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md).
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
## Contributors
|
|
665
|
+
|
|
666
|
+
Thanks to everyone who has contributed to claudestat:
|
|
667
|
+
|
|
668
|
+
[Deiby Gorrin](https://github.com/DeibyGS) — creator and maintainer
|
|
669
|
+
|
|
670
|
+
Want to appear here? Pick a [good-first-issue](https://github.com/DeibyGS/claudestat/labels/good-first-issue) and open a PR.
|
|
671
|
+
|
|
502
672
|
---
|
|
503
673
|
|
|
504
674
|
## FAQ
|
package/dist/claude-auth.d.ts
CHANGED
|
@@ -18,7 +18,14 @@ export interface ClaudeAuthInfo {
|
|
|
18
18
|
expiresAt: number;
|
|
19
19
|
tokenValid: boolean;
|
|
20
20
|
source: 'keychain' | 'file' | 'unknown';
|
|
21
|
+
accessToken?: string;
|
|
21
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Devuelve el accessToken OAuth para autenticar llamadas a la API de Anthropic.
|
|
25
|
+
* Usa el mismo caché de 5 minutos que readClaudeAuth().
|
|
26
|
+
* Retorna null si no hay credenciales disponibles (Linux sin configurar, token expirado).
|
|
27
|
+
*/
|
|
28
|
+
export declare function getOAuthAccessToken(): string | null;
|
|
22
29
|
/**
|
|
23
30
|
* Lee las credenciales de autenticación de Claude Code.
|
|
24
31
|
* Intenta: keychain (macOS) → archivo → unknown.
|
package/dist/claude-auth.js
CHANGED
|
@@ -17,6 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.getOAuthAccessToken = getOAuthAccessToken;
|
|
20
21
|
exports.readClaudeAuth = readClaudeAuth;
|
|
21
22
|
exports.subscriptionTypeToPlan = subscriptionTypeToPlan;
|
|
22
23
|
const child_process_1 = require("child_process");
|
|
@@ -50,6 +51,7 @@ function readFromKeychain() {
|
|
|
50
51
|
expiresAt: oa.expiresAt ?? 0,
|
|
51
52
|
tokenValid: Date.now() < (oa.expiresAt ?? 0),
|
|
52
53
|
source: 'keychain',
|
|
54
|
+
accessToken: oa.accessToken,
|
|
53
55
|
};
|
|
54
56
|
}
|
|
55
57
|
catch {
|
|
@@ -82,6 +84,7 @@ function readFromFile() {
|
|
|
82
84
|
expiresAt: oa.expiresAt ?? 0,
|
|
83
85
|
tokenValid: Date.now() < (oa.expiresAt ?? 0),
|
|
84
86
|
source: 'file',
|
|
87
|
+
accessToken: oa.accessToken,
|
|
85
88
|
};
|
|
86
89
|
}
|
|
87
90
|
catch {
|
|
@@ -90,6 +93,15 @@ function readFromFile() {
|
|
|
90
93
|
}
|
|
91
94
|
return null;
|
|
92
95
|
}
|
|
96
|
+
// ─── Token OAuth para llamadas a la API ───────────────────────────────────────
|
|
97
|
+
/**
|
|
98
|
+
* Devuelve el accessToken OAuth para autenticar llamadas a la API de Anthropic.
|
|
99
|
+
* Usa el mismo caché de 5 minutos que readClaudeAuth().
|
|
100
|
+
* Retorna null si no hay credenciales disponibles (Linux sin configurar, token expirado).
|
|
101
|
+
*/
|
|
102
|
+
function getOAuthAccessToken() {
|
|
103
|
+
return readClaudeAuth().accessToken ?? null;
|
|
104
|
+
}
|
|
93
105
|
// ─── API pública ──────────────────────────────────────────────────────────────
|
|
94
106
|
/**
|
|
95
107
|
* Lee las credenciales de autenticación de Claude Code.
|
package/dist/config.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface ClaudestatConfig {
|
|
|
23
23
|
killSwitchEnabled: boolean;
|
|
24
24
|
killSwitchThreshold: number;
|
|
25
25
|
warnThresholds: number[];
|
|
26
|
+
weeklyWarnThresholds: number[];
|
|
27
|
+
resetReminderMins: number;
|
|
26
28
|
plan: ClaudePlan | null;
|
|
27
29
|
reportsEnabled: boolean;
|
|
28
30
|
reportFrequency: ReportFrequency;
|
package/dist/config.js
CHANGED
|
@@ -34,6 +34,8 @@ const DEFAULTS = {
|
|
|
34
34
|
killSwitchEnabled: false,
|
|
35
35
|
killSwitchThreshold: 95,
|
|
36
36
|
warnThresholds: [70, 85, 95],
|
|
37
|
+
weeklyWarnThresholds: [50, 75, 90],
|
|
38
|
+
resetReminderMins: 10,
|
|
37
39
|
plan: null,
|
|
38
40
|
reportsEnabled: false,
|
|
39
41
|
reportFrequency: 'weekly',
|
|
@@ -80,6 +82,16 @@ function validateConfig(raw) {
|
|
|
80
82
|
}
|
|
81
83
|
if ('plan' in cfg && !VALID_PLANS.has(cfg.plan))
|
|
82
84
|
return `plan debe ser uno de: free, pro, max5, max20 o null`;
|
|
85
|
+
if ('weeklyWarnThresholds' in cfg) {
|
|
86
|
+
const v = cfg.weeklyWarnThresholds;
|
|
87
|
+
if (!Array.isArray(v) || v.length !== 3 || v.some(n => typeof n !== 'number' || isNaN(n) || n < 1 || n > 100))
|
|
88
|
+
return 'weeklyWarnThresholds must be an array of 3 numbers between 1 and 100';
|
|
89
|
+
}
|
|
90
|
+
if ('resetReminderMins' in cfg) {
|
|
91
|
+
const v = cfg.resetReminderMins;
|
|
92
|
+
if (typeof v !== 'number' || isNaN(v) || v < 0 || v > 60)
|
|
93
|
+
return 'resetReminderMins must be a number between 0 and 60';
|
|
94
|
+
}
|
|
83
95
|
if ('alertsEnabled' in cfg && typeof cfg.alertsEnabled !== 'boolean')
|
|
84
96
|
return 'alertsEnabled debe ser boolean';
|
|
85
97
|
if ('reportsEnabled' in cfg && typeof cfg.reportsEnabled !== 'boolean')
|
package/dist/daemon.js
CHANGED
|
@@ -13,6 +13,39 @@
|
|
|
13
13
|
* - Endpoint GET /meta-stats: KPIs de HANDOFF, Engram, config y alertas
|
|
14
14
|
* - Procesa JSONL al conectar nuevo cliente SSE (contexto inmediato)
|
|
15
15
|
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
16
49
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
50
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
51
|
};
|
|
@@ -106,7 +139,7 @@ async function migrateSessionSummaries(limit = 5) {
|
|
|
106
139
|
const summary = await (0, summarizer_1.summarizeSession)(events, s.total_cost_usd ?? 0, projectName);
|
|
107
140
|
if (summary) {
|
|
108
141
|
db_1.dbOps.updateSessionSummary(s.id, summary);
|
|
109
|
-
console.log(`[daemon] Summary
|
|
142
|
+
console.log(`[daemon] Summary generated for session ${s.id.slice(0, 8)}: "${summary}"`);
|
|
110
143
|
}
|
|
111
144
|
}
|
|
112
145
|
catch (err) {
|
|
@@ -142,7 +175,20 @@ const LEVEL_COLOR = {
|
|
|
142
175
|
orange: '\x1b[33m',
|
|
143
176
|
red: '\x1b[31m',
|
|
144
177
|
};
|
|
145
|
-
let
|
|
178
|
+
let _lastCycleAlertLevel = null;
|
|
179
|
+
let _lastWeeklyAlertLevel = null;
|
|
180
|
+
let _resetReminderFired = false;
|
|
181
|
+
function checkAlertLevel(level, lastLevel, logMsg, notifTitle, notifBody) {
|
|
182
|
+
if (!level)
|
|
183
|
+
return null;
|
|
184
|
+
const prevRank = lastLevel ? LEVEL_RANK[lastLevel] ?? 0 : 0;
|
|
185
|
+
const currRank = LEVEL_RANK[level];
|
|
186
|
+
if (currRank > prevRank) {
|
|
187
|
+
process.stderr.write(`${LEVEL_COLOR[level]}${logMsg}\x1b[0m\n`);
|
|
188
|
+
(0, notifier_1.sendDesktopNotification)(notifTitle, notifBody);
|
|
189
|
+
}
|
|
190
|
+
return currRank > prevRank ? level : lastLevel;
|
|
191
|
+
}
|
|
146
192
|
function startAlertPolling() {
|
|
147
193
|
alertInterval = setInterval(() => {
|
|
148
194
|
try {
|
|
@@ -150,20 +196,23 @@ function startAlertPolling() {
|
|
|
150
196
|
if (!cfg.alertsEnabled)
|
|
151
197
|
return;
|
|
152
198
|
const data = (0, quota_tracker_1.computeQuota)(cfg.plan ?? undefined);
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
199
|
+
const resetMins = Math.ceil(data.cycleResetMs / 60000);
|
|
200
|
+
// ── Cycle 5h alerts ──────────────────────────────────────────────────────
|
|
201
|
+
_lastCycleAlertLevel = checkAlertLevel((0, config_1.getWarnLevel)(data.cyclePct, cfg.warnThresholds), _lastCycleAlertLevel, `[claudestat] ⚠️ 5h cycle at ${data.cyclePct}% (${data.cyclePrompts}/${data.cycleLimit} prompts)`, 'claudestat — 5h cycle alert', `${data.cyclePct}% of cycle used · resets in ${resetMins}m`);
|
|
202
|
+
// ── Weekly alerts ────────────────────────────────────────────────────────
|
|
203
|
+
_lastWeeklyAlertLevel = checkAlertLevel((0, config_1.getWarnLevel)(data.weeklyPctAll, cfg.weeklyWarnThresholds), _lastWeeklyAlertLevel, `[claudestat] ⚠️ Weekly usage at ${data.weeklyPctAll}%`, 'claudestat — Weekly usage alert', `${data.weeklyPctAll}% of weekly quota used`);
|
|
204
|
+
// ── Reset reminder ───────────────────────────────────────────────────────
|
|
205
|
+
const reminderMs = (cfg.resetReminderMins ?? 10) * 60000;
|
|
206
|
+
if (reminderMs > 0) {
|
|
207
|
+
if (data.cycleResetMs > reminderMs * 1.5) {
|
|
208
|
+
_resetReminderFired = false; // cycle reset happened — arm reminder again
|
|
209
|
+
}
|
|
210
|
+
else if (data.cycleResetMs <= reminderMs && data.cycleResetMs > 0 && !_resetReminderFired) {
|
|
211
|
+
const mins = Math.ceil(data.cycleResetMs / 60000);
|
|
212
|
+
process.stderr.write(`\x1b[36m[claudestat] ⏰ Quota resets in ${mins}m — good time to wrap up\x1b[0m\n`);
|
|
213
|
+
(0, notifier_1.sendDesktopNotification)('claudestat — Quota reset soon', `Your 5h cycle resets in ${mins} min — good time to start a new task`);
|
|
214
|
+
_resetReminderFired = true;
|
|
165
215
|
}
|
|
166
|
-
_lastAlertLevel = level;
|
|
167
216
|
}
|
|
168
217
|
}
|
|
169
218
|
catch {
|
|
@@ -199,6 +248,19 @@ function startDaemon() {
|
|
|
199
248
|
console.log(`\n● claudestat daemon → http://localhost:${PORT}`);
|
|
200
249
|
console.log(` Waiting for Claude Code events...\n`);
|
|
201
250
|
console.log(` In another terminal: \x1b[36mclaudestat watch\x1b[0m\n`);
|
|
251
|
+
// Weekly insight — se muestra una vez por semana al iniciar el daemon
|
|
252
|
+
Promise.resolve().then(() => __importStar(require('./insights'))).then(({ getWeeklyInsightData, shouldShowInsight, markInsightShown, renderWeeklyInsight }) => {
|
|
253
|
+
try {
|
|
254
|
+
if (!shouldShowInsight())
|
|
255
|
+
return;
|
|
256
|
+
const data = getWeeklyInsightData();
|
|
257
|
+
if (data.total_sessions >= 3) {
|
|
258
|
+
console.log(renderWeeklyInsight(data));
|
|
259
|
+
}
|
|
260
|
+
markInsightShown();
|
|
261
|
+
}
|
|
262
|
+
catch { /* insight is non-critical */ }
|
|
263
|
+
});
|
|
202
264
|
// Etiquetar sesiones históricas que no tienen proyecto asignado
|
|
203
265
|
migrateSessionProjects();
|
|
204
266
|
// Pre-scan de proyectos al arrancar — garantiza respuesta inmediata en el tab
|
|
@@ -235,6 +297,7 @@ function startDaemon() {
|
|
|
235
297
|
}
|
|
236
298
|
// Polling de alertas de rate limit cada 60s
|
|
237
299
|
startAlertPolling();
|
|
300
|
+
// API quota data is refreshed on-demand by the CLI status command (disk cache shared)
|
|
238
301
|
});
|
|
239
302
|
// Manejo de error de puerto ocupado — fuera del callback para capturar EADDRINUSE
|
|
240
303
|
_server.on('error', (err) => {
|