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 +1 -1
- package/src/cli.js +11 -21
- package/src/format.js +3 -1
- package/src/scanner.js +15 -11
- package/src/version.js +1 -1
package/package.json
CHANGED
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,
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 (!
|
|
179
|
+
if (!daemonAlive()) { startDaemon(); return; }
|
|
190
180
|
if (Date.now() >= deadline) {
|
|
191
|
-
const pid =
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
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 ${
|
|
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
|
-
|
|
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
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
const
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
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
|
|