claude-rpc 0.5.0 → 0.6.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 CHANGED
@@ -8,7 +8,7 @@
8
8
  # claude-rpc
9
9
 
10
10
  **Discord Rich Presence for [Claude Code](https://claude.com/claude-code).**
11
- Your model, project, current tool, tokens, and lifetime stats — live in your Discord profile.
11
+ Your model, project, current tool, tokens, and lifetime stats — live in your Discord profile. Driven by Claude Code's hooks. Zero polling, zero overhead between sessions.
12
12
 
13
13
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
14
14
  [![Node 18+](https://img.shields.io/badge/node-%3E%3D18-43853d.svg?logo=node.js&logoColor=white)](https://nodejs.org)
@@ -23,17 +23,47 @@ Your model, project, current tool, tokens, and lifetime stats — live in your D
23
23
  <img src="docs/demo.gif" width="560" alt="Discord Rich Presence card: Claude Code, working in claude-rpc on Opus 4.7" />
24
24
  </div>
25
25
 
26
- Driven entirely by Claude Code's hook system. Zero polling, zero overhead between sessions.
26
+ ## Install
27
27
 
28
- <div align="center">
28
+ **Windows** (no Node required) — [grab the latest portable exe](https://github.com/rar-file/claude-rpc/releases/latest):
29
29
 
30
- <sub>Sample badges (your numbers, your README):</sub>
30
+ ```sh
31
+ claude-rpc setup
32
+ claude-rpc start
33
+ ```
31
34
 
32
- <img src="https://img.shields.io/badge/claude%20%C2%B7%207d-12.4h-4c1" alt="hours" />&nbsp;<img src="https://img.shields.io/badge/streak-23%20days-fe7d37" alt="streak" />&nbsp;<img src="https://img.shields.io/badge/claude%20cost%20%C2%B7%2030d-$48.20-3a7" alt="cost" />&nbsp;<img src="https://img.shields.io/badge/lines%20%C2%B7%20all--time-24.1k-08c" alt="lines" />&nbsp;<img src="https://img.shields.io/badge/prompts%20%C2%B7%2030d-1.2k-5865F2" alt="prompts" />
35
+ That's it. Open Claude Code in any project the daemon picks it up within a second.
33
36
 
34
- </div>
37
+ The Discord *desktop* app must be running (the browser client doesn't expose the local IPC). Something looks wrong? `claude-rpc doctor`.
38
+
39
+ <details>
40
+ <summary><b>Other platforms / from source</b></summary>
41
+
42
+ ```sh
43
+ git clone https://github.com/rar-file/claude-rpc.git
44
+ cd claude-rpc
45
+ npm install
46
+ node ./src/cli.js setup
47
+ node ./src/cli.js start
48
+ ```
49
+
50
+ Or `npm install -g claude-rpc` for the global bin.
51
+ </details>
52
+
53
+ <details>
54
+ <summary><b>Use your own Discord app</b></summary>
55
+
56
+ A working Discord application is bundled into the default config — you don't need to register your own to get started. To use a different app name on the card, create one in the [Discord Developer Portal](https://discord.com/developers/applications), copy the Application ID, and put it into `clientId` in your config:
57
+
58
+ ```sh
59
+ # Linux / macOS
60
+ echo '{ "clientId": "YOUR_ID" }' > ~/.config/claude-rpc/config.json
61
+ # Windows
62
+ echo { "clientId": "YOUR_ID" } > %APPDATA%\claude-rpc\config.json
63
+ ```
35
64
 
36
- > **What's new in v0.2.0** — Cost estimation, code churn, languages, MCP/built-in split, bash + web + subagent leaderboards, redesigned web dashboard with SSE push, six-tab Electron settings GUI, new `insights` and `badge` subcommands. [Full release notes →](https://github.com/rar-file/claude-rpc/releases/tag/v0.2.0)
65
+ Run `claude-rpc upgrade-config` afterwards if you carry forward a v0.3-era config.
66
+ </details>
37
67
 
38
68
  ## Features
39
69
 
@@ -45,18 +75,19 @@ Driven entirely by Claude Code's hook system. Zero polling, zero overhead betwee
45
75
  | 🎞️ **Status art** | Large image swaps between *working*, *thinking*, *idle*, *stale*, *notification* |
46
76
  | 🔁 **Rotation frames** | Cycle through today's stats, streak, top file, lifetime totals, anything you template |
47
77
  | 🐙 **Auto GitHub button** | When your cwd is a git repo with a github origin, a *View on GitHub* button appears |
78
+ | 🔒 **Privacy mode** | Per-project `.claude-rpc.json`, runtime `claude-rpc private` toggle, glob-pattern matchers, and auto-detection of GitHub private repos via `gh` |
48
79
 
49
80
  **Beyond Discord**
50
81
 
51
82
  | | |
52
83
  | :--- | :--- |
53
- | 📊 **All-time aggregates** | Hours, prompts, tokens, streaks, hotspots, **lines changed, languages, cost, bash usage, web domains, subagent runs** — incremental scanner over `~/.claude/projects/*.jsonl` |
84
+ | 📊 **All-time aggregates** | Hours, prompts, tokens, streaks, hotspots, lines changed, languages, cost, bash usage, web domains, subagent runs — incremental scanner over `~/.claude/projects/*.jsonl` |
54
85
  | 💰 **Cost estimate** | Per-model spend (Opus/Sonnet/Haiku) using public list prices — editable in `src/pricing.js` |
55
86
  | 🧠 **Insights** | `claude-rpc insights` generates 3–5 contextual lines: weekly trend, peak weekday, hotspot file, cost pace, streak progress |
56
87
  | 🖥️ **CLI dashboard** | `claude-rpc status` — heatmap, hour histogram, top tools / files / projects / languages / bash commands / cost |
57
- | 🌐 **Web dashboard** | `claude-rpc serve` — range selector (7d / 30d / 90d / 1y / All), live SSE updates, project drilldown, day-detail modal, achievements, theme toggle |
58
- | 🪪 **README badges** | `claude-rpc badge --metric hours --range 7d --out h.svg` (or live at `/api/badge.svg?metric=…`) |
59
- | ⚙️ **Config GUI** | Electron app with six tabs: Presence (drag-reorder, variable autocomplete, presets), Discord, Assets, Timing, Daemon (start/stop/restart, tail log), Stats |
88
+ | 🌐 **Web dashboard** | `claude-rpc serve` — range selector (7d / 30d / 90d / 1y / All), live SSE updates, project drilldown, day-detail modal, theme toggle |
89
+ | 🪪 **Badges & cards** | `claude-rpc badge --metric hours --range 7d` (Shields-style SVG) and `claude-rpc card --range year` (poster-style summary) |
90
+ | ⚙️ **Config GUI** | Electron app six tabs: Presence, Discord, Assets, Timing, Daemon, Stats |
60
91
 
61
92
  ## Screens
62
93
 
@@ -67,69 +98,32 @@ Driven entirely by Claude Code's hook system. Zero polling, zero overhead betwee
67
98
  </tr>
68
99
  </table>
69
100
 
70
- ## Install
71
-
72
- **Windows (no Node required)** — grab the latest portable exe:
73
-
74
- ```sh
75
- # From https://github.com/rar-file/claude-rpc/releases/latest
76
- # Download claude-rpc.exe, drop it anywhere on PATH.
77
- claude-rpc setup
78
- claude-rpc start
79
- ```
80
-
81
- **Any OS (from source)** — Node 18+:
82
-
83
- ```sh
84
- git clone https://github.com/rar-file/claude-rpc.git
85
- cd claude-rpc
86
- npm install
87
- cp config.example.json config.json
88
- npm link # optional, makes `claude-rpc` global
89
- ```
90
-
91
- Requires the Discord **desktop** client (RPC IPC is unavailable in the browser client) and Claude Code with hook support.
92
-
93
- ## Quick start
94
-
95
- ```sh
96
- node ./src/cli.js setup # register hooks into ~/.claude/settings.json
97
- node ./src/cli.js start # launch the daemon (detached)
98
- node ./src/cli.js status # CLI dashboard
99
- node ./src/cli.js serve # web dashboard at http://127.0.0.1:47474
100
- ```
101
-
102
- Open Claude Code in any project. Hooks fire on `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `Notification`, `Stop`, and `SessionEnd`, and the daemon pushes updated presence to Discord within a second.
103
-
104
- If you `npm link` (or install the packaged exe), every command above becomes `claude-rpc <command>`.
105
-
106
- ## Discord app setup
107
-
108
- 1. Open the [Discord Developer Portal](https://discord.com/developers/applications) and create a new application named something like `Claude Code`.
109
- 2. Copy the **Application ID** into `config.json` under `clientId`.
110
- 3. *(Optional)* Under **Rich Presence → Art Assets**, upload images named `claude`, `working`, `thinking`, `idle`, `notification` to match the keys in `statusAssets`.
111
- 4. Or skip uploading and use direct URLs in `statusAssets` (e.g. `"https://example.com/working.gif"`). Modern Discord clients fetch them through their media proxy.
112
-
113
101
  ## Commands
114
102
 
115
- | Command | Description |
116
- | ------------- | -------------------------------------------------------- |
117
- | `setup` | Install hooks into `~/.claude/settings.json` |
118
- | `uninstall` | Remove hooks |
119
- | `start` | Start the daemon (detached) |
120
- | `stop` | Stop the daemon |
121
- | `restart` | Stop then start |
122
- | `status` | Current session + all-time dashboard |
123
- | `today` | Today's stats + 24h histogram |
124
- | `week` | This week's stats + daily breakdown |
125
- | `serve` | Open the local web dashboard (port 47474) |
126
- | `preview` | Show how each rotation frame renders right now |
127
- | `scan` | Incrementally rescan `~/.claude/projects` for aggregates |
128
- | `rescan` | Force re-parse every transcript |
129
- | `insights` | Print 3–5 auto-generated insight lines |
130
- | `badge` | Render a Shields-style SVG (`--metric hours\|streak\|cost\|lines`, `--range 7d\|30d\|all`, `--out file.svg`) |
131
- | `tail` | Tail the daemon log |
132
- | `daemon` | Run the daemon in the foreground (for debugging) |
103
+ | Command | Description |
104
+ | ---------------- | -------------------------------------------------------- |
105
+ | `setup` | Install Claude Code hooks (`~/.claude/settings.json`) |
106
+ | `uninstall` | Remove Claude Code hooks |
107
+ | `upgrade-config` | Re-run idempotent migrations on `config.json` |
108
+ | `start` | Start the daemon (detached) |
109
+ | `stop` | Stop the daemon |
110
+ | `restart` | Stop then start |
111
+ | `status` | Current session + all-time stats (interactive TUI or `--dump`) |
112
+ | `today` | Today's stats + 24h histogram |
113
+ | `week` | This week's stats + daily breakdown |
114
+ | `serve` | Open the local web dashboard (port 47474) |
115
+ | `preview` | Show how each rotation frame renders right now |
116
+ | `scan` / `rescan`| Incremental / forced re-parse of `~/.claude/projects` |
117
+ | `backfill <dir>` | Import transcripts from any folder (backup, other machine) |
118
+ | `insights` | Print 3–5 auto-generated insight lines |
119
+ | `badge` | Render a Shields-style SVG (`--metric` `--range` `--out`)|
120
+ | `card` | Poster-style SVG summary (`--range year\|month\|week\|all`) |
121
+ | `private` / `public` / `privacy` | Per-cwd visibility toggles + status |
122
+ | `doctor` | Diagnostic checklist — common-failure triage |
123
+ | `tail` / `logs` | Tail the daemon log |
124
+ | `daemon` | Run the daemon in the foreground (debug) |
125
+
126
+ Exit codes: `0` ok · `1` user error · `2` system error · `3` wrong state. `--version` and `--help` work as expected.
133
127
 
134
128
  ## Config GUI
135
129
 
@@ -137,7 +131,8 @@ If you `npm link` (or install the packaged exe), every command above becomes `cl
137
131
  cd dashboard
138
132
  npm install
139
133
  npm start # dev mode
140
- npm run build # → dist/claude-rpc-dashboard.exe (Windows portable)
134
+ npm run dist:mac # → .dmg
135
+ npm run dist:win # → portable .exe
141
136
  ```
142
137
 
143
138
  The Electron app reads and writes `config.json` directly. The daemon hot-reloads.
@@ -162,11 +157,11 @@ Three cooperating pieces, glued by JSON files on disk.
162
157
  └────────────┘
163
158
  ```
164
159
 
165
- 1. **Hook** (`src/hook.js`) — Claude Code spawns it on every lifecycle event. Parses the event JSON from stdin and mutates the shared state file.
166
- 2. **Daemon** (`src/daemon.js`) — Long-running. Connects to Discord's local IPC, watches the state file plus periodic transcript scans, pushes presence frames every few seconds.
167
- 3. **Scanner** (`src/scanner.js`) — Walks `~/.claude/projects/**/*.jsonl` transcripts for all-time aggregates (active time, prompts, tool calls, tokens, streaks, hour-of-day, top files / projects). Cached at `~/.claude-rpc/aggregate.json` for incremental updates.
160
+ 1. **Hook** (`src/hook.js`) — Claude Code spawns it on every lifecycle event. Parses the JSON event from stdin and mutates the shared state file.
161
+ 2. **Daemon** (`src/daemon.js`) — Long-running. Connects to Discord's local IPC, watches the state file plus periodic transcript scans, pushes presence frames every few seconds. Exponential backoff with jitter on reconnect.
162
+ 3. **Scanner** (`src/scanner.js`) — Walks `~/.claude/projects/**/*.jsonl` transcripts for all-time aggregates. Cached at `~/.claude-rpc/aggregate.json` for incremental updates.
168
163
 
169
- Persistent state lives in a few well-known places:
164
+ Persistent state:
170
165
 
171
166
  | Path | What |
172
167
  | ---- | ---- |
@@ -175,54 +170,34 @@ Persistent state lives in a few well-known places:
175
170
  | `~/.claude-rpc/scan-cache.json` | Per-transcript scan cache |
176
171
  | `~/.claude/settings.json` | Hook registrations (managed by `setup`) |
177
172
 
173
+ User config lives at `%APPDATA%\claude-rpc\config.json` (Windows), `~/Library/Application Support/claude-rpc/config.json` (macOS), or `$XDG_CONFIG_HOME/claude-rpc/config.json` (Linux). It only needs to hold *overrides* — defaults are baked into the binary.
174
+
178
175
  <details>
179
176
  <summary><b>Configuration reference</b></summary>
180
177
 
181
- `config.json` keys, all optional unless noted:
178
+ Every key is optional. The shipped defaults work out of the box. Override what you want:
182
179
 
183
180
  | Key | Default | Notes |
184
181
  | ------------------------- | ------- | ------------------------------------------------------------------- |
185
- | `clientId` | | **Required.** Discord application ID |
182
+ | `clientId` | bundled | Discord application ID (a working public app ships by default) |
186
183
  | `updateIntervalMs` | `4000` | How often the daemon pushes to Discord |
187
184
  | `rotationIntervalMs` | `12000` | How fast rotation frames cycle |
188
185
  | `rescanIntervalSec` | `300` | How often transcripts are re-aggregated |
189
186
  | `idleThresholdSec` | `60` | No activity for this long → status `idle` |
190
- | `staleSessionMin` | `5` | No activity for this long (minutes) → status `stale`; presence is cleared |
187
+ | `staleSessionMin` | `5` | No activity (minutes) → status `stale`; presence cleared |
191
188
  | `notificationWindowSec` | `8` | How long the `notification` status sticks |
192
189
  | `showElapsed` | `true` | Include the elapsed timer |
193
190
  | `activityType` | `0` | `0` Playing, `2` Listening, `3` Watching, `5` Competing |
194
- | `statusAssets` | `{}` | Image per status (working / thinking / idle / stale / notification) |
195
- | `presence.largeImageKey` | | Fallback large image when no `statusAssets` match |
196
- | `presence.largeImageText` | — | Tooltip on hover |
197
- | `presence.smallImageKey` | | Small badge in the corner of the large image |
198
- | `presence.smallImageText` | | Tooltip on hover |
199
- | `presence.rotation` | `[]` | Array of frames, each `{ details, state, requires? }` |
200
- | `presence.buttons` | `[]` | Up to 2 `{ label, url }` buttons |
201
- | `statusIcons` | `{}` | Small image key per status (empty string hides it) |
202
-
203
- ### Rotation frames
204
-
205
- ```jsonc
206
- {
207
- "presence": {
208
- "rotation": [
209
- { "details": "{statusVerbose} in {project}", "state": "{modelPretty}" },
210
- { "details": "{currentToolPretty} · {currentFilePretty}",
211
- "state": "{tokensFmt} tokens",
212
- "requires": ["currentFile"] },
213
- { "details": "Today · {todayHours}",
214
- "state": "{todayPromptsLabel}",
215
- "requires": ["todayActiveMs"] }
216
- ]
217
- }
218
- }
219
- ```
220
-
221
- Each frame has:
191
+ | `statusAssets` | gifs | Image per status (working / thinking / idle / stale / notification) |
192
+ | `presence.byStatus` | full | Per-status template block (preferred over `rotation`) |
193
+ | `presence.rotation` | — | Legacy: flat array of `{ details, state, requires? }` |
194
+ | `presence.buttons` | one | Up to 2 `{ label, url }` buttons |
195
+ | `presence.largeImageKey` | gif | Fallback large image when no `statusAssets` match |
196
+ | `presence.largeImageText` | tpl | Tooltip on hover |
197
+ | `privacy.patterns` | `[]` | Glob list of cwd basenames to treat as private |
198
+ | `privacy.mode` | hidden | What `patterns` does `hidden` / `name-only` / `public` |
222
199
 
223
- - `details` bold first line (Discord max 128 chars)
224
- - `state` — lighter second line (Discord max 128 chars)
225
- - `requires` *(optional)* — a variable name or array of names. The frame is skipped if any required variable is empty / `0`. Lets you have context-dependent frames (e.g. only show the *current tool* frame when there's actually a tool running).
200
+ Image precedence: `statusAssets[status]` `modelAssets[opus|sonnet|haiku]` `presence.largeImageKey`.
226
201
 
227
202
  </details>
228
203
 
@@ -240,60 +215,45 @@ Both `details` and `state` (and button labels and URLs) support `{name}` substit
240
215
  | `{currentFilePretty}` | `src/app/page.tsx` |
241
216
  | `{tokensFmt}` | `2.3k` |
242
217
  | `{messagesLabel}` | `8 prompts` |
243
- | `{projectSessionLabel}` | `Session #1` |
244
- | `{projectHours}` | `22m` |
245
218
  | `{todayHours}` | `56m` |
246
219
  | `{weekHours}` | `3.1h` |
247
220
  | `{streakLabel}` | `7-day streak` |
248
- | `{daysSinceFirstLabel}` | `Day 31` |
249
221
  | `{allHours}` | `52h` |
250
222
  | `{allTokensFmt}` | `2.82B` |
251
223
  | `{peakHour}` | `22:00` |
252
224
  | `{topEditedFile}` | `index.html` |
253
225
  | `{linesAddedFmt}` | `24k` |
254
- | `{todayLinesAddedFmt}` | `320` |
255
- | `{linesNetFmt}` | `+18k` |
256
226
  | `{topLanguage}` | `TypeScript` |
257
- | `{languagesLabel}` | `TypeScript · Python · Rust` |
258
- | `{topBashCmdLabel}` | `git × 820` |
259
- | `{topDomainLabel}` | `docs.anthropic.com × 28` |
260
- | `{subagentLabel}` | `Explore × 18` |
261
- | `{mcpToolPercentLabel}` | `12% MCP` |
262
227
  | `{todayCostFmt}` | `$1.23` |
263
228
  | `{allCostFmt}` | `$89.42` |
264
- | `{weekdayLabel}` | `Thursday` |
265
- | `{startTimeLabel}` | `started 09:14` |
229
+ | `{gitBranch}` | `main` |
266
230
 
267
- Run `node ./src/cli.js preview` to see every frame rendered with your real data, including which ones would be hidden by their `requires`.
231
+ Run `claude-rpc preview` to see every frame rendered with your real data, including which ones would be hidden by their `requires`. Run `claude-rpc vars` for the full machine-readable list.
268
232
 
269
233
  </details>
270
234
 
271
235
  ## Badges
272
236
 
273
- Generate a Shields-style SVG you can drop into a README:
274
-
275
237
  ```sh
276
- claude-rpc badge --metric hours --range 7d --out claude-hours.svg
238
+ claude-rpc badge --metric hours --range 7d --out claude-hours.svg
277
239
  claude-rpc badge --metric streak --out claude-streak.svg
278
240
  claude-rpc badge --metric cost --range 30d --out claude-cost.svg
279
241
  claude-rpc badge --metric lines --range all --out claude-lines.svg
280
242
  ```
281
243
 
282
- While the daemon's `serve` command is running, the same data is also available live at:
244
+ Live via the dashboard too: `http://127.0.0.1:47474/api/badge.svg?metric=hours&range=7d`.
283
245
 
284
- ```
285
- http://127.0.0.1:47474/api/badge.svg?metric=hours&range=7d
286
- ```
287
-
288
- Cost numbers come from `src/pricing.js`, seeded with **approximate** public list prices for Anthropic models. Edit that file to override — your actual Claude Code subscription bill is unrelated.
246
+ Cost numbers come from `src/pricing.js`, seeded with **approximate** public list prices. Your actual Claude Code subscription bill is unrelated.
289
247
 
290
248
  ## Troubleshooting
291
249
 
292
- **Discord doesn't pick up presence.** The Discord *desktop* app must be running. The browser client doesn't expose the local IPC bridge. Verify `clientId` matches your Discord application, and run `claude-rpc tail` to watch the daemon log live.
250
+ **First step is always `claude-rpc doctor`.** It checks Node version, hook registration, daemon liveness, Discord connection, aggregate freshness, and privacy resolution with a one-line fix hint per failure.
251
+
252
+ **Discord doesn't pick up presence.** The Discord *desktop* app must be running. The browser client doesn't expose the local IPC. Run `claude-rpc tail` to watch the daemon log live.
293
253
 
294
- **Hooks don't fire.** Run `claude-rpc setup` and check the `hooks` section of `~/.claude/settings.json`. Restart Claude Code afterwards so it re-reads the hook config.
254
+ **Hooks don't fire.** Run `claude-rpc setup` and check the `hooks` section of `~/.claude/settings.json`. Restart Claude Code so it re-reads hook config. `setup` now test-fires a SessionStart through the same launcher Claude Code will use, so a broken hook command should be caught at install time.
295
255
 
296
- **Elapsed timer resets on rotation.** Update to the current version. Older builds passed timestamps in seconds; Discord expects milliseconds.
256
+ **Config error.** A bad `config.json` won't brick the daemon any more it logs one line and falls back to baked-in defaults. Check the daemon log via `claude-rpc tail` to see the parse error.
297
257
 
298
258
  ## License
299
259
 
@@ -1,67 +1,4 @@
1
1
  {
2
- "clientId": "1506443909406920948",
3
- "appName": "Claude Code",
4
- "updateIntervalMs": 4000,
5
- "rotationIntervalMs": 12000,
6
- "rescanIntervalSec": 300,
7
- "idleThresholdSec": 60,
8
- "staleSessionMin": 5,
9
- "hideWhenStale": true,
10
- "notificationWindowSec": 8,
11
- "showElapsed": true,
12
- "activityType": 0,
13
- "statusAssets": {
14
- "working": "https://cdn.qualit.ly/clawd-working-building.gif",
15
- "thinking": "https://cdn.qualit.ly/clawd-working-typing.gif",
16
- "idle": "https://cdn.qualit.ly/clawd-sleeping.gif",
17
- "stale": "https://cdn.qualit.ly/clawd-sleeping.gif",
18
- "notification": "https://cdn.qualit.ly/clawd-notification.gif"
19
- },
20
- "presence": {
21
- "largeImageKey": "https://cdn.qualit.ly/clawd-sleeping.gif",
22
- "largeImageText": "{modelPretty} · {allHours} on Claude · {streakLabel}",
23
- "smallImageKey": "{statusIcon}",
24
- "smallImageText": "{statusVerbose}",
25
- "byStatus": {
26
- "working": {
27
- "details": "Working in {project}",
28
- "state": "{currentToolPretty} · {currentFilePretty} · {tokensFmt} tokens",
29
- "largeImageText": "Working on a {fileLang} file"
30
- },
31
- "thinking": {
32
- "details": "Thinking in {project}",
33
- "state": "{modelPretty} · {messagesLabel} · {tokensFmt} tokens",
34
- "largeImageText": "Reasoning with {modelPretty}"
35
- },
36
- "notification": {
37
- "details": "Waiting on you · {project}",
38
- "state": "{modelPretty} · {messagesLabel}",
39
- "largeImageText": "Permission needed"
40
- },
41
- "idle": {
42
- "details": "Idle in {project}",
43
- "state": "{modelPretty} · {todayHours} today",
44
- "largeImageText": "Idle · {modelPretty}",
45
- "rotation": [
46
- { "details": "This week · {weekHours}", "state": "{weekPromptsLabel} · {weekTokensFmt} tokens", "requires": ["weekActiveMs"] },
47
- { "details": "{streakLabel}", "state": "{daysSinceFirstLabel} · {allSessionsLabel}", "requires": ["streakIsMilestone"] },
48
- { "details": "Hotspot · {topEditedFile}", "state": "{topEditedCountLabel} all-time", "requires": ["topEditedCount"] },
49
- { "details": "{allHours} on Claude all-time", "state": "{allSessionsLabel} · {allMessagesFmt} prompts", "requires": ["allSessions"] },
50
- { "details": "Lifetime · {allTokensFmt} tokens", "state": "{allToolsFmt} tool calls · {allFilesFmt} files", "requires": ["allTools"] },
51
- { "details": "Code churn · {linesAddedFmt} added","state": "{linesNetFmt} net · {topLanguage}", "requires": ["topLanguage"] },
52
- { "details": "Cost · {todayCostFmt} today", "state": "{allCostFmt} all-time", "requires": ["allCost"] }
53
- ]
54
- }
55
- },
56
- "buttons": [
57
- { "label": "Claude Code", "url": "https://claude.com/claude-code" }
58
- ]
59
- },
60
- "statusIcons": {
61
- "working": "working",
62
- "thinking": "thinking",
63
- "idle": "idle",
64
- "notification": "",
65
- "stale": ""
66
- }
2
+ "_comment": "Two lines is enough. Defaults for everything else are baked into the binary (see src/default-config.js). Override any key here and it deep-merges over the shipped defaults — no need to copy the full shape.",
3
+ "clientId": "1506443909406920948"
67
4
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-rpc",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Discord Rich Presence for Claude Code — live model, project, tokens, and lifetime stats driven by Claude Code's hook system.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/card.js CHANGED
@@ -14,6 +14,7 @@
14
14
  import { dayKey } from './scanner.js';
15
15
  import { fmtCost } from './pricing.js';
16
16
  import { rangeToDays, rangeLabel, pickWindow } from './badge.js';
17
+ import { VERSION } from './version.js';
17
18
 
18
19
  const W = 880;
19
20
  const H = 540;
@@ -273,7 +274,7 @@ export function renderCard(aggregate, { range = 'year', generatedAt = new Date()
273
274
  font-size="13"
274
275
  fill="${PALETTE.inkMute}">${subtitle}</text>
275
276
  </g>
276
- ${tapeSticker(W - 220, 40, 'claude-rpc · v0.4', { rotate: 3 })}
277
+ ${tapeSticker(W - 220, 40, `claude-rpc · v${VERSION}`, { rotate: 3 })}
277
278
 
278
279
  <!-- ── hero hours card ── -->
279
280
  <g transform="translate(60 130)">