@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 CHANGED
@@ -12,7 +12,7 @@ Works with Claude Pro, Max 5, and Max 20. Zero cloud dependencies. Pure Node.js.
12
12
  [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
13
13
  [![Node.js](https://img.shields.io/badge/node-%3E%3D22-brightgreen)](https://nodejs.org)
14
14
  [![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-brightgreen)]()
15
- [![Tests](https://img.shields.io/badge/tests-214%2F214-brightgreen)]()
15
+ [![Tests](https://img.shields.io/badge/tests-243%2F243-brightgreen)]()
16
16
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](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 export [format]` | Export session data to JSON or CSV |
144
- | `claudestat share [session-id]` | Generate shareable session card (ASCII/JSON) |
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
- 🏆 claudestat topby est. cost (last 30 days)
174
-
175
- # Tool Calls Duration Est. Cost %
176
- ── ───────────────── ──────── ───────────── ───────── ────
177
- 1 Bash 1,240 18.3m $1.24 38%
178
- 2 Read 890 4.1m $0.87 27%
179
- 3 Edit 430 2.8m $0.61 19%
180
- 4 Agent (haiku) 120 9.2m $0.38 12%
181
- 5 Write 210 1.1m $0.12 4%
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
- Quota 5h 45/50 prompts (90%) | reset in 22m
192
- Plan MAX5
193
- Sonnet 3.2h / 5h this week
194
- Burn rate 1,240 tok/min
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
- ### `claudestat status --compact`
253
+ Options: `--json` for machine-readable output.
198
254
 
199
- One-line output for tmux status bar or scripting. Shows the 5h cycle quota percentage.
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
- ### `claudestat share`
262
+ 💡 claudestat insights last 7 days
263
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
207
264
 
208
- Generate a shareable session card — perfect for sharing on social media or in bug reports.
265
+ 💰 $4.96/session · 40 sessions · $198.38 total
209
266
 
210
- ```bash
211
- claudestat share
212
- ╔═══════════════════════════════════╗
213
- Session Report · claudestat
214
- ╠═══════════════════════════════════╣
215
- Project my-project ║
216
- ║ Duration 2h 14m ║
217
- Tools 847 calls ║
218
- ║ Cost $0.84 ║
219
- Cache hit 27% saved ($0.31) ║
220
- ║ Top tool Bash (38%) ║
221
- Efficiency 91 / 100 ║
222
- ╚═══════════════════════════════════╝
223
- github.com/DeibyGS/claudestat
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 roast`
303
+ ### `claudestat config`
231
304
 
232
- Get a sarcastic analysis of your Claude Code usage — humor with insights.
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
- claudestat roast
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
- === Claude Code Stats (last 30 days) ===
238
- Sessions: 47
239
- Total cost: $12.40
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
- 🔥 Your Claude Code Roast
334
+ Config is stored at `~/.claudestat/config.json` (macOS/Linux) or `%USERPROFILE%\.claudestat\config.json` (Windows).
245
335
 
246
- You called Bash 1,240 times last month.
247
- That's once every 2.3 minutes.
248
- Are you okay?
336
+ ### `claudestat roast`
249
337
 
250
- You hit 90%+ context in 12 sessions.
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
- You spent $4.20 on loops you never noticed.
254
- That's 14 coffees. Just saying.
340
+ ```bash
341
+ claudestat roast
255
342
 
256
- Efficiency: 72/100 room for growth, champ.
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
- ### `claudestat config`
452
+ ## MCP Server
311
453
 
312
- ```bash
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
- # Force plan detection instead of auto
317
- claudestat config --plan max5 # pro | max5 | max20 | auto
456
+ ### Tools exposed
318
457
 
319
- # Disable daemon rate limit alerts
320
- claudestat config --alerts false
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
- Config is stored at `~/.claudestat/config.json` (macOS/Linux) or `%USERPROFILE%\.claudestat\config.json` (Windows).
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: `npm test` (208 tests)
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
- npm test # run all tests
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
@@ -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.
@@ -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 generado para sesión ${s.id.slice(0, 8)}: "${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 _lastAlertLevel = null;
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 level = (0, config_1.getWarnLevel)(data.cyclePct, cfg.warnThresholds);
154
- if (!level) {
155
- _lastAlertLevel = null;
156
- return;
157
- }
158
- const prevRank = _lastAlertLevel ? LEVEL_RANK[_lastAlertLevel] ?? 0 : 0;
159
- const currRank = LEVEL_RANK[level] ?? 0;
160
- if (currRank > prevRank) {
161
- const color = LEVEL_COLOR[level];
162
- process.stderr.write(`${color}[claudestat] ⚠️ Rate limit alert: ${data.cyclePct}% of quota used (${data.cyclePrompts}/${data.cycleLimit} prompts)\x1b[0m\n`);
163
- if (data.cyclePct >= cfg.killSwitchThreshold) {
164
- (0, notifier_1.sendDesktopNotification)('claudestat Rate limit warning', `${data.cyclePct}% of 5h quota used (${data.cyclePrompts}/${data.cycleLimit} prompts)`);
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) => {