claude-rpc 1.1.2 → 1.1.4
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/doctor.js +42 -5
- package/src/version.js +1 -1
package/package.json
CHANGED
package/src/doctor.js
CHANGED
|
@@ -9,7 +9,7 @@ import { existsSync, readFileSync, statSync, readdirSync } from 'node:fs';
|
|
|
9
9
|
import { join, basename } from 'node:path';
|
|
10
10
|
import {
|
|
11
11
|
IS_PACKAGED, IS_NPM_INSTALL, IS_INSTALLED,
|
|
12
|
-
CONFIG_PATH, CANONICAL_EXE, USER_CONFIG_DIR,
|
|
12
|
+
CONFIG_PATH, CANONICAL_EXE, USER_CONFIG_DIR, HOOK_SCRIPT,
|
|
13
13
|
STATE_PATH, PID_PATH, LOG_PATH,
|
|
14
14
|
AGGREGATE_PATH, SCAN_CACHE_PATH,
|
|
15
15
|
CLAUDE_HOME, CLAUDE_PROJECTS, CLAUDE_SETTINGS,
|
|
@@ -95,6 +95,35 @@ export function classifyClientId(clientId) {
|
|
|
95
95
|
return 'ok';
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
// One wired hook command, classified against the running install. installHooks
|
|
99
|
+
// has written `"<abs node>" "<abs hook.js>" <event>` (npm + dev) or
|
|
100
|
+
// `"<canonical exe>" hook <event>` (packaged) since v0.19.1 — absolute on both
|
|
101
|
+
// tokens, because Claude Code runs hooks through a minimal-PATH shell that,
|
|
102
|
+
// under a version manager, has neither `claude-rpc` nor `node` on it.
|
|
103
|
+
// 'legacy' — PATH-dependent launcher (pre-v0.19.1 `claude-rpc hook <event>` /
|
|
104
|
+
// bare `node "<hook.js>"`): fails as `claude-rpc: command not
|
|
105
|
+
// found` on every tool use.
|
|
106
|
+
// 'dead' — absolute launcher no longer on disk (e.g. nvm pruned the node
|
|
107
|
+
// version the hooks were wired against).
|
|
108
|
+
// 'stale' — runs, but points at a different install than this binary.
|
|
109
|
+
// 'ok' — wired against the current install.
|
|
110
|
+
export function classifyHookCommand(cmd, {
|
|
111
|
+
packaged = IS_PACKAGED,
|
|
112
|
+
npm = IS_NPM_INSTALL,
|
|
113
|
+
canonicalExe = CANONICAL_EXE,
|
|
114
|
+
hookScript = HOOK_SCRIPT,
|
|
115
|
+
exists = existsSync,
|
|
116
|
+
} = {}) {
|
|
117
|
+
const c = String(cmd || '');
|
|
118
|
+
const m = c.match(/^"([^"]+)"|^(\S+)/);
|
|
119
|
+
const launcher = m ? (m[1] ?? m[2]) : '';
|
|
120
|
+
if (launcher && !launcher.includes('/') && !launcher.includes('\\')) return 'legacy';
|
|
121
|
+
if (launcher && !exists(launcher)) return 'dead';
|
|
122
|
+
if (packaged && !c.includes(canonicalExe)) return 'stale';
|
|
123
|
+
if (npm && !c.includes(hookScript.replace(/\\/g, '/'))) return 'stale';
|
|
124
|
+
return 'ok';
|
|
125
|
+
}
|
|
126
|
+
|
|
98
127
|
// Most-recent-wins IPC state inferred from the daemon log tail: 'up'/'down'/'unknown'.
|
|
99
128
|
export function ipcStateFromLog(logText) {
|
|
100
129
|
let ipc = 'unknown';
|
|
@@ -192,26 +221,34 @@ function checkHooks() {
|
|
|
192
221
|
}
|
|
193
222
|
const missing = [];
|
|
194
223
|
const stale = [];
|
|
224
|
+
const broken = [];
|
|
195
225
|
for (const event of HOOK_EVENTS) {
|
|
196
226
|
const bucket = settings.hooks?.[event];
|
|
197
227
|
if (!Array.isArray(bucket) || bucket.length === 0) { missing.push(event); continue; }
|
|
198
228
|
const ours = bucket.flatMap((e) => e.hooks || []).find((h) => isOurHook(h));
|
|
199
229
|
if (!ours) { missing.push(event); continue; }
|
|
200
|
-
|
|
201
|
-
if (
|
|
230
|
+
const cls = classifyHookCommand(ours.command);
|
|
231
|
+
if (cls === 'legacy' || cls === 'dead') broken.push(cls);
|
|
232
|
+
else if (cls === 'stale') stale.push(event);
|
|
202
233
|
}
|
|
203
|
-
if (missing.length === 0 && stale.length === 0) {
|
|
234
|
+
if (missing.length === 0 && stale.length === 0 && broken.length === 0) {
|
|
204
235
|
check(`hooks registered (${HOOK_EVENTS.length}/${HOOK_EVENTS.length})`, 'pass',
|
|
205
236
|
'all events wired against the current binary');
|
|
206
237
|
} else if (missing.length === HOOK_EVENTS.length) {
|
|
207
238
|
check('hooks registered', 'fail', 'no claude-rpc hooks found',
|
|
208
239
|
'run `claude-rpc setup` to register hooks', 'setup');
|
|
240
|
+
} else if (broken.length > 0) {
|
|
241
|
+
check('hooks registered', 'fail',
|
|
242
|
+
broken.includes('legacy')
|
|
243
|
+
? `${broken.length} PATH-dependent (pre-v0.19.1) — fail as \`claude-rpc: command not found\` under Claude Code's hook shell`
|
|
244
|
+
: `${broken.length} pointing at a launcher that's gone from disk`,
|
|
245
|
+
'run `claude-rpc setup` to rewrite hooks as absolute, PATH-independent commands', 'setup');
|
|
209
246
|
} else if (missing.length > 0) {
|
|
210
247
|
check('hooks registered', 'warn', `missing: ${missing.join(', ')}`,
|
|
211
248
|
'run `claude-rpc setup` to add the missing events', 'setup');
|
|
212
249
|
} else if (stale.length > 0) {
|
|
213
250
|
check('hooks registered', 'warn',
|
|
214
|
-
`${stale.length}
|
|
251
|
+
`${stale.length} wired against a different install than this binary`,
|
|
215
252
|
'run `claude-rpc setup` to refresh hook commands against the current binary', 'setup');
|
|
216
253
|
}
|
|
217
254
|
}
|