claude-rpc 0.20.2 → 0.20.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-rpc",
3
- "version": "0.20.2",
3
+ "version": "0.20.3",
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/cli.js CHANGED
@@ -10,12 +10,12 @@ import process from 'node:process';
10
10
  if (process.platform === 'win32' && process.stdout.isTTY) {
11
11
  try { spawnSync('chcp.com', ['65001'], { stdio: 'ignore', windowsHide: true }); } catch { /* chcp absent (Wine, custom shell) — accept whatever code page is set */ }
12
12
  }
13
- import { DAEMON_SCRIPT, PID_PATH, STATE_PATH, LOG_PATH, AGGREGATE_PATH, CONFIG_PATH, IS_PACKAGED, IS_NPX, EXE_PATH } from './paths.js';
13
+ import { DAEMON_SCRIPT, STATE_PATH, LOG_PATH, AGGREGATE_PATH, CONFIG_PATH, IS_PACKAGED, IS_NPX, EXE_PATH } from './paths.js';
14
14
  import { readActiveState } from './state.js';
15
15
  import { runHookCli } from './hook.js';
16
16
  import { parseDuration, setPause, clearPause, pauseUntil } from './pause.js';
17
17
  import { loadConfig, hasUserConfig } from './config.js';
18
- import { spawnDaemonDetached } from './ensure-daemon.js';
18
+ import { spawnDaemonDetached, daemonAlive } from './ensure-daemon.js';
19
19
 
20
20
  // ── Lazy-loaded heavy module graph ───────────────────────────────────────────
21
21
  // format→scanner→pricing→languages→git→usage (plus install/tui/insights/nudge/
@@ -116,18 +116,8 @@ function takeValue(v, flag) {
116
116
  return v;
117
117
  }
118
118
 
119
- function isAlive(pid) {
120
- try { process.kill(pid, 0); return true; } catch { return false; }
121
- }
122
-
123
- function daemonPid() {
124
- if (!existsSync(PID_PATH)) return null;
125
- const pid = Number(readFileSync(PID_PATH, 'utf8'));
126
- return pid && isAlive(pid) ? pid : null;
127
- }
128
-
129
119
  function startDaemon({ quiet = false } = {}) {
130
- const pid = daemonPid();
120
+ const pid = daemonAlive();
131
121
  if (pid) {
132
122
  if (!quiet) console.log(` ${c.yellow}!${c.reset} ${'daemon running'.padEnd(16)}${c.dim}already up (pid ${pid}) · bounce it with ${c.reset}${c.cyan}claude-rpc restart${c.reset}`);
133
123
  return false;
@@ -154,7 +144,7 @@ async function confirmDaemonUp({ timeoutMs = 3000, intervalMs = 100 } = {}) {
154
144
  const deadline = Date.now() + timeoutMs;
155
145
  for (;;) {
156
146
  await new Promise((r) => setTimeout(r, intervalMs));
157
- if (daemonPid()) {
147
+ if (daemonAlive()) {
158
148
  console.log(` ${c.green}✓${c.reset} ${'daemon confirmed'.padEnd(16)}${c.dim}up — connecting to Discord${c.reset}`);
159
149
  return true;
160
150
  }
@@ -166,7 +156,7 @@ async function confirmDaemonUp({ timeoutMs = 3000, intervalMs = 100 } = {}) {
166
156
  }
167
157
 
168
158
  function stopDaemon({ quiet = false } = {}) {
169
- const pid = daemonPid();
159
+ const pid = daemonAlive();
170
160
  if (!pid) { if (!quiet) console.log(` ${c.cyan}·${c.reset} daemon not running`); return false; }
171
161
  try {
172
162
  process.kill(pid, 'SIGTERM');
@@ -186,9 +176,9 @@ function restartDaemon() {
186
176
  // one exited. Give up after ~3s, force-kill the wedged pid, and start anyway.
187
177
  const deadline = Date.now() + 3000;
188
178
  const tick = () => {
189
- if (!daemonPid()) { startDaemon(); return; }
179
+ if (!daemonAlive()) { startDaemon(); return; }
190
180
  if (Date.now() >= deadline) {
191
- const pid = daemonPid();
181
+ const pid = daemonAlive();
192
182
  if (pid) { try { process.kill(pid, 'SIGKILL'); } catch { /* already gone */ } }
193
183
  startDaemon();
194
184
  return;
@@ -411,7 +401,7 @@ function showStatus() {
411
401
  state.liveSessions = live;
412
402
  state.usage = readUsageCache();
413
403
  const vars = buildVars(state, config, aggregate);
414
- const pid = daemonPid();
404
+ const pid = daemonAlive();
415
405
 
416
406
  console.log('');
417
407
  console.log(` ${c.bold}${c.magenta}◆ Claude RPC${c.reset} ${c.dim}— Discord Rich Presence for Claude Code${c.reset}`);
@@ -1863,7 +1853,7 @@ function tailLog() {
1863
1853
  function overview() {
1864
1854
  const setUp = hasUserConfig();
1865
1855
  const cfg = loadConfig();
1866
- const pid = daemonPid();
1856
+ const pid = daemonAlive();
1867
1857
 
1868
1858
  console.log('');
1869
1859
  console.log(` ${c.bold}${c.magenta}◆ claude-rpc${c.reset} ${c.dim}v${VERSION} — Discord Rich Presence for Claude Code${c.reset}`);
@@ -2045,7 +2035,7 @@ process.on('unhandledRejection', (e) => {
2045
2035
  // console, the grandchild node allocates a fresh one, and Windows 11
2046
2036
  // pops it as a visible Windows Terminal window whose closure kills
2047
2037
  // the daemon.
2048
- if (!daemonPid()) {
2038
+ if (!daemonAlive()) {
2049
2039
  let script = null;
2050
2040
  try {
2051
2041
  const r = spawnSync('npm', ['root', '-g'], {
@@ -2065,7 +2055,7 @@ process.on('unhandledRejection', (e) => {
2065
2055
  child.unref();
2066
2056
  console.log(` ${c.green}✓${c.reset} ${'daemon launched'.padEnd(16)}${c.dim}pid ${c.reset}${c.cyan}${child.pid}${c.reset}${c.dim} · log ${shortPath(LOG_PATH)}${c.reset}`);
2067
2057
  } else {
2068
- console.log(` ${c.cyan}·${c.reset} ${'daemon running'.padEnd(16)}${c.dim}pid ${daemonPid()}${c.reset}`);
2058
+ console.log(` ${c.cyan}·${c.reset} ${'daemon running'.padEnd(16)}${c.dim}pid ${daemonAlive()}${c.reset}`);
2069
2059
  }
2070
2060
  } else {
2071
2061
  startDaemon();
package/src/format.js CHANGED
@@ -870,7 +870,9 @@ export function applyIdle(state, cfg = {}) {
870
870
  if (state.status === 'notification') {
871
871
  const notifAge = now - (state.lastNotification || 0);
872
872
  if (notifAge <= notificationMs) return state;
873
- state = { ...state, status: 'idle' };
873
+ // Going idle after a notification — wipe the current-activity slots so idle
874
+ // frames don't render stale file/tool names (same as the idle path below).
875
+ state = { ...state, status: 'idle', currentTool: null, currentFile: null, filesOpened: [], filesEdited: [], filesRead: [] };
874
876
  }
875
877
 
876
878
  // Truly dormant: no live transcripts AND local state is old → stale.
package/src/scanner.js CHANGED
@@ -699,18 +699,22 @@ function writeCache(cache) {
699
699
  // Per-day notification counts come from a hook-side append log, since
700
700
  // transcripts don't carry Notification events reliably.
701
701
  function readNotificationsByDay() {
702
- if (!existsSync(EVENTS_LOG_PATH)) return {};
703
702
  const out = {};
704
- try {
705
- const raw = readFileSync(EVENTS_LOG_PATH, 'utf8');
706
- for (const line of raw.split('\n')) {
707
- if (!line) continue;
708
- const e = safeJson(line);
709
- if (!e || e.type !== 'notification' || !e.ts) continue;
710
- const k = dayKey(e.ts);
711
- out[k] = (out[k] || 0) + 1;
712
- }
713
- } catch { /* events log unreadable/truncated return whatever we got, the aggregate will just under-count notifications */ }
703
+ // The hook rotates events.jsonl to `.1` at 5MB; read both (oldest first) so a
704
+ // rotation doesn't silently drop a day's notification counts.
705
+ for (const path of [EVENTS_LOG_PATH + '.1', EVENTS_LOG_PATH]) {
706
+ if (!existsSync(path)) continue;
707
+ try {
708
+ const raw = readFileSync(path, 'utf8');
709
+ for (const line of raw.split('\n')) {
710
+ if (!line) continue;
711
+ const e = safeJson(line);
712
+ if (!e || e.type !== 'notification' || !e.ts) continue;
713
+ const k = dayKey(e.ts);
714
+ out[k] = (out[k] || 0) + 1;
715
+ }
716
+ } catch { /* a rotation file unreadable/truncated — count what we can */ }
717
+ }
714
718
  return out;
715
719
  }
716
720
 
package/src/version.js CHANGED
@@ -11,7 +11,7 @@ import { readFileSync } from 'node:fs';
11
11
  import { join } from 'node:path';
12
12
  import { ROOT } from './paths.js';
13
13
 
14
- const BAKED = '0.20.2';
14
+ const BAKED = '0.20.3';
15
15
 
16
16
  function readPkgVersion() {
17
17
  try {