claude-depester 1.3.2 → 1.3.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/README.md +17 -5
- package/bin/claude-depester +162 -2
- package/lib/hooks.js +142 -2
- package/lib/patcher.js +103 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# claude-depester
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/claude-depester)
|
|
4
|
+
[](https://www.npmjs.com/package/claude-depester)
|
|
4
5
|
[](https://opensource.org/licenses/MIT)
|
|
5
6
|
|
|
6
7
|
Remove silly thinking words from Claude Code.
|
|
7
8
|
|
|
8
9
|
Instead of seeing "Flibbertigibbeting", "Discombobulating", "Clauding", etc., you'll see a clean "Thinking".
|
|
9
10
|
|
|
10
|
-
> **Last updated:** 2026-01-
|
|
11
|
+
> **Last updated:** 2026-01-18 | **Tested with:** Claude Code 2.1.4 - 2.1.12 | **Platforms:** Linux, macOS, Windows
|
|
12
|
+
>
|
|
13
|
+
> v1.3.3: Added `--debug` and `--log` flags for troubleshooting auto-patch issues ([#3](https://github.com/ominiverdi/claude-depester/issues/3))
|
|
11
14
|
|
|
12
15
|

|
|
13
16
|

|
|
@@ -72,6 +75,8 @@ That's it! Restart Claude Code for changes to take effect.
|
|
|
72
75
|
| `npx claude-depester --check` | Check patch status |
|
|
73
76
|
| `npx claude-depester --restore` | Restore original from backup |
|
|
74
77
|
| `npx claude-depester --verbose` | Show detailed info |
|
|
78
|
+
| `npx claude-depester --debug` | Show detailed debug info (for troubleshooting) |
|
|
79
|
+
| `npx claude-depester --log` | Write results to `~/.claude/depester.log` |
|
|
75
80
|
| `npx claude-depester --install-hook` | Auto-patch after updates |
|
|
76
81
|
| `npx claude-depester --remove-hook` | Remove auto-patch hook |
|
|
77
82
|
| `npx claude-depester --hook-status` | Check hook status |
|
|
@@ -136,7 +141,7 @@ The `--install-hook` command adds a SessionStart hook to `~/.claude/settings.jso
|
|
|
136
141
|
"hooks": [
|
|
137
142
|
{
|
|
138
143
|
"type": "command",
|
|
139
|
-
"command": "npx claude-depester --silent"
|
|
144
|
+
"command": "npx claude-depester --all --silent --log"
|
|
140
145
|
}
|
|
141
146
|
]
|
|
142
147
|
}
|
|
@@ -145,7 +150,12 @@ The `--install-hook` command adds a SessionStart hook to `~/.claude/settings.jso
|
|
|
145
150
|
}
|
|
146
151
|
```
|
|
147
152
|
|
|
148
|
-
Every time Claude Code starts, it checks and re-applies the patch if needed.
|
|
153
|
+
Every time Claude Code starts, it checks and re-applies the patch if needed. The `--log` flag writes results to `~/.claude/depester.log` (keeps last 50 entries) for troubleshooting.
|
|
154
|
+
|
|
155
|
+
> **Note:** If you installed the hook with an older version, reinstall it to get logging:
|
|
156
|
+
> ```bash
|
|
157
|
+
> npx claude-depester --remove-hook && npx claude-depester --install-hook
|
|
158
|
+
> ```
|
|
149
159
|
|
|
150
160
|
## Troubleshooting
|
|
151
161
|
|
|
@@ -188,8 +198,9 @@ Then **fully restart VS Code** (not just reload window).
|
|
|
188
198
|
|
|
189
199
|
The detection uses content-based matching, so it should survive version updates.
|
|
190
200
|
If the patch fails:
|
|
191
|
-
1.
|
|
192
|
-
2.
|
|
201
|
+
1. Run `npx claude-depester --debug` to see detailed diagnostics
|
|
202
|
+
2. Open an issue with your Claude Code version (`claude --version`)
|
|
203
|
+
3. Include the output of `npx claude-depester --debug`
|
|
193
204
|
|
|
194
205
|
### Want to undo everything
|
|
195
206
|
|
|
@@ -216,6 +227,7 @@ npx claude-depester --remove-hook # Remove auto-patch hook
|
|
|
216
227
|
|
|
217
228
|
- **Backup**: `<original-file>.depester.backup`
|
|
218
229
|
- **Hook config**: `~/.claude/settings.json`
|
|
230
|
+
- **Debug log**: `~/.claude/depester.log` (when using `--log`)
|
|
219
231
|
|
|
220
232
|
## Requirements
|
|
221
233
|
|
package/bin/claude-depester
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const { findCliJs, findAllClaudeCode, getSearchedPaths } = require('../lib/detector');
|
|
12
|
-
const { patch, checkStatus, restoreBackup } = require('../lib/patcher');
|
|
13
|
-
const { installHook, removeHook, getHookStatus } = require('../lib/hooks');
|
|
12
|
+
const { patch, checkStatus, getDebugInfo, restoreBackup } = require('../lib/patcher');
|
|
13
|
+
const { installHook, removeHook, getHookStatus, searchHookLogs, appendLog, readLog, LOG_PATH } = require('../lib/hooks');
|
|
14
14
|
|
|
15
15
|
const VERSION = require('../package.json').version;
|
|
16
16
|
|
|
@@ -27,6 +27,8 @@ const flags = {
|
|
|
27
27
|
hookStatus: args.includes('--hook-status'),
|
|
28
28
|
silent: args.includes('--silent') || args.includes('-s'),
|
|
29
29
|
verbose: args.includes('--verbose'),
|
|
30
|
+
debug: args.includes('--debug') || args.includes('-d'),
|
|
31
|
+
log: args.includes('--log'),
|
|
30
32
|
all: args.includes('--all') || args.includes('-a'),
|
|
31
33
|
list: args.includes('--list') || args.includes('-l')
|
|
32
34
|
};
|
|
@@ -76,6 +78,8 @@ OPTIONS:
|
|
|
76
78
|
|
|
77
79
|
-s, --silent Suppress output (for hook use)
|
|
78
80
|
--verbose Show detailed information
|
|
81
|
+
-d, --debug Show detailed debug info (for troubleshooting)
|
|
82
|
+
--log Write results to ~/.claude/depester.log (keeps last 50 entries)
|
|
79
83
|
-v, --version Show version
|
|
80
84
|
-h, --help Show this help
|
|
81
85
|
|
|
@@ -86,6 +90,7 @@ EXAMPLES:
|
|
|
86
90
|
npx claude-depester --check # Check status
|
|
87
91
|
npx claude-depester --install-hook # Auto-patch after updates
|
|
88
92
|
npx claude-depester --restore # Undo patch
|
|
93
|
+
npx claude-depester --debug # Troubleshoot issues
|
|
89
94
|
|
|
90
95
|
MORE INFO:
|
|
91
96
|
https://github.com/ominiverdi/claude-depester
|
|
@@ -164,6 +169,9 @@ async function main() {
|
|
|
164
169
|
const installations = findAllClaudeCode();
|
|
165
170
|
if (installations.length === 0) {
|
|
166
171
|
error('No Claude Code installations found.');
|
|
172
|
+
if (flags.log) {
|
|
173
|
+
appendLog('No installations found', { action: 'patch-all' });
|
|
174
|
+
}
|
|
167
175
|
if (flags.verbose) {
|
|
168
176
|
showSearchedPaths();
|
|
169
177
|
}
|
|
@@ -175,6 +183,7 @@ async function main() {
|
|
|
175
183
|
let successCount = 0;
|
|
176
184
|
let skipCount = 0;
|
|
177
185
|
let failCount = 0;
|
|
186
|
+
const logResults = [];
|
|
178
187
|
|
|
179
188
|
for (const inst of installations) {
|
|
180
189
|
log(`${inst.method}:`);
|
|
@@ -185,28 +194,55 @@ async function main() {
|
|
|
185
194
|
if (success) {
|
|
186
195
|
log(' -> Restored from backup\n');
|
|
187
196
|
successCount++;
|
|
197
|
+
logResults.push({ path: inst.path, method: inst.method, result: 'restored' });
|
|
188
198
|
} else {
|
|
189
199
|
log(' -> No backup found\n');
|
|
190
200
|
skipCount++;
|
|
201
|
+
logResults.push({ path: inst.path, method: inst.method, result: 'no-backup' });
|
|
191
202
|
}
|
|
192
203
|
} else {
|
|
204
|
+
// Get debug info before patching for the log
|
|
205
|
+
const debugBefore = flags.log ? getDebugInfo(inst.path, { type: inst.type }) : null;
|
|
206
|
+
|
|
193
207
|
const result = patch(inst.path, { dryRun: flags.dryRun, type: inst.type });
|
|
194
208
|
if (result.success) {
|
|
195
209
|
if (result.alreadyPatched) {
|
|
196
210
|
log(' -> Already patched\n');
|
|
197
211
|
skipCount++;
|
|
212
|
+
logResults.push({
|
|
213
|
+
path: inst.path,
|
|
214
|
+
method: inst.method,
|
|
215
|
+
result: 'already-patched',
|
|
216
|
+
debug: debugBefore
|
|
217
|
+
});
|
|
198
218
|
} else if (result.dryRun) {
|
|
199
219
|
const details = formatPatchDetails(result);
|
|
200
220
|
log(` -> Would patch${details}\n`);
|
|
201
221
|
successCount++;
|
|
222
|
+
logResults.push({ path: inst.path, method: inst.method, result: 'dry-run' });
|
|
202
223
|
} else {
|
|
203
224
|
const details = formatPatchDetails(result);
|
|
204
225
|
log(` -> Patched${details}\n`);
|
|
205
226
|
successCount++;
|
|
227
|
+
logResults.push({
|
|
228
|
+
path: inst.path,
|
|
229
|
+
method: inst.method,
|
|
230
|
+
result: 'patched',
|
|
231
|
+
spinnerCount: result.spinnerCount,
|
|
232
|
+
completionCount: result.completionCount,
|
|
233
|
+
debug: debugBefore
|
|
234
|
+
});
|
|
206
235
|
}
|
|
207
236
|
} else {
|
|
208
237
|
log(` -> Failed: ${result.message}\n`);
|
|
209
238
|
failCount++;
|
|
239
|
+
logResults.push({
|
|
240
|
+
path: inst.path,
|
|
241
|
+
method: inst.method,
|
|
242
|
+
result: 'failed',
|
|
243
|
+
error: result.message,
|
|
244
|
+
debug: debugBefore
|
|
245
|
+
});
|
|
210
246
|
}
|
|
211
247
|
}
|
|
212
248
|
}
|
|
@@ -215,6 +251,18 @@ async function main() {
|
|
|
215
251
|
if (!flags.dryRun && successCount > 0) {
|
|
216
252
|
log('Restart Claude Code for changes to take effect.');
|
|
217
253
|
}
|
|
254
|
+
|
|
255
|
+
if (flags.log) {
|
|
256
|
+
appendLog('Patch all completed', {
|
|
257
|
+
action: 'patch-all',
|
|
258
|
+
found: installations.length,
|
|
259
|
+
patched: successCount,
|
|
260
|
+
skipped: skipCount,
|
|
261
|
+
failed: failCount,
|
|
262
|
+
results: logResults
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
218
266
|
process.exit(failCount > 0 ? 1 : 0);
|
|
219
267
|
}
|
|
220
268
|
|
|
@@ -238,6 +286,118 @@ async function main() {
|
|
|
238
286
|
log(`Detection method: ${cliInfo.method}`);
|
|
239
287
|
}
|
|
240
288
|
|
|
289
|
+
// Handle debug
|
|
290
|
+
if (flags.debug) {
|
|
291
|
+
log('=== DEPESTER DEBUG INFO ===\n');
|
|
292
|
+
|
|
293
|
+
// Get debug info for all installations
|
|
294
|
+
const installations = findAllClaudeCode();
|
|
295
|
+
if (installations.length === 0) {
|
|
296
|
+
log('No installations found.\n');
|
|
297
|
+
} else {
|
|
298
|
+
for (const inst of installations) {
|
|
299
|
+
const debug = getDebugInfo(inst.path, { type: inst.type });
|
|
300
|
+
|
|
301
|
+
log(`--- ${inst.method} ---`);
|
|
302
|
+
log(`Path: ${debug.filePath}`);
|
|
303
|
+
log(`File exists: ${debug.fileExists}`);
|
|
304
|
+
if (debug.fileExists) {
|
|
305
|
+
log(`File size: ${debug.fileSize} bytes`);
|
|
306
|
+
log(`File modified: ${debug.fileModified}`);
|
|
307
|
+
log(`Is binary: ${debug.isBinary}`);
|
|
308
|
+
log(`Is webview: ${debug.isWebview}`);
|
|
309
|
+
if (debug.isBinary) {
|
|
310
|
+
log(`Binary extraction OK: ${debug.binaryExtractionOk}`);
|
|
311
|
+
if (debug.extractedJsSize) {
|
|
312
|
+
log(`Extracted JS size: ${debug.extractedJsSize} bytes`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
log(`Has backup: ${debug.hasBackup}`);
|
|
316
|
+
log('');
|
|
317
|
+
log('Detection checks:');
|
|
318
|
+
log(` Has =["Thinking"]: ${debug.hasReplacementPattern}`);
|
|
319
|
+
log(` Has =["Thought"]: ${debug.hasCompletionReplacement}`);
|
|
320
|
+
log(` Has original spinner array: ${debug.hasOriginalSpinnerArray}`);
|
|
321
|
+
log(` Has original completion array: ${debug.hasOriginalCompletionArray}`);
|
|
322
|
+
log(` Marker words found: ${debug.markerWordsFound.length > 0 ? debug.markerWordsFound.join(', ') : 'none'}`);
|
|
323
|
+
log(` Completion verbs found: ${debug.completionVerbsFound.length > 0 ? debug.completionVerbsFound.join(', ') : 'none'}`);
|
|
324
|
+
log('');
|
|
325
|
+
log('Computed status:');
|
|
326
|
+
log(` Spinner patched: ${debug.spinnerPatched}`);
|
|
327
|
+
log(` Completion patched: ${debug.completionPatched}`);
|
|
328
|
+
log(` Has silly words: ${debug.hasSillyWords}`);
|
|
329
|
+
}
|
|
330
|
+
if (debug.error) {
|
|
331
|
+
log(`Error: ${debug.error}`);
|
|
332
|
+
}
|
|
333
|
+
log('');
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Hook status
|
|
338
|
+
const hookStatus = getHookStatus();
|
|
339
|
+
log('--- Hook Status ---');
|
|
340
|
+
log(`Hook installed: ${hookStatus.installed}`);
|
|
341
|
+
log(`Settings file: ${hookStatus.settingsPath}`);
|
|
342
|
+
log('');
|
|
343
|
+
|
|
344
|
+
// Search Claude debug logs for hook activity
|
|
345
|
+
log('--- Recent Hook Activity (from Claude logs) ---');
|
|
346
|
+
const hookLogs = searchHookLogs(5);
|
|
347
|
+
if (hookLogs.length === 0) {
|
|
348
|
+
log('No hook activity found in recent Claude debug logs.');
|
|
349
|
+
} else {
|
|
350
|
+
for (const logFile of hookLogs) {
|
|
351
|
+
log(`\nLog: ${logFile.file} (${logFile.timestamp})`);
|
|
352
|
+
for (const entry of logFile.entries) {
|
|
353
|
+
log(` ${entry.time}: ${entry.message}`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
log('');
|
|
358
|
+
|
|
359
|
+
// Show depester's own log
|
|
360
|
+
log('--- Depester Log (last 10 entries) ---');
|
|
361
|
+
log(`Log file: ${LOG_PATH}`);
|
|
362
|
+
const depesterLogs = readLog();
|
|
363
|
+
if (depesterLogs.length === 0) {
|
|
364
|
+
log('No entries. Enable logging with --log flag.');
|
|
365
|
+
} else {
|
|
366
|
+
const recent = depesterLogs.slice(-10);
|
|
367
|
+
for (const entry of recent) {
|
|
368
|
+
log(`\n${entry.timestamp}: ${entry.message}`);
|
|
369
|
+
if (entry.data) {
|
|
370
|
+
if (entry.data.found !== undefined) {
|
|
371
|
+
log(` Found: ${entry.data.found}, Patched: ${entry.data.patched}, Skipped: ${entry.data.skipped}, Failed: ${entry.data.failed}`);
|
|
372
|
+
}
|
|
373
|
+
// Only show per-installation details if there was a failure or unexpected result
|
|
374
|
+
if (entry.data.results) {
|
|
375
|
+
const hasIssue = entry.data.results.some(r =>
|
|
376
|
+
r.result === 'failed' ||
|
|
377
|
+
(r.result === 'already-patched' && r.debug?.markerWordsFound?.length > 0)
|
|
378
|
+
);
|
|
379
|
+
if (hasIssue) {
|
|
380
|
+
for (const r of entry.data.results) {
|
|
381
|
+
log(` - ${r.method}: ${r.result}`);
|
|
382
|
+
if (r.debug) {
|
|
383
|
+
log(` File modified: ${r.debug.fileModified}`);
|
|
384
|
+
log(` Has =["Thinking"]: ${r.debug.hasReplacementPattern}`);
|
|
385
|
+
log(` Marker words: ${r.debug.markerWordsFound?.length > 0 ? r.debug.markerWordsFound.join(', ') : 'none'}`);
|
|
386
|
+
}
|
|
387
|
+
if (r.error) {
|
|
388
|
+
log(` Error: ${r.error}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
log('');
|
|
397
|
+
|
|
398
|
+
process.exit(0);
|
|
399
|
+
}
|
|
400
|
+
|
|
241
401
|
// Handle check
|
|
242
402
|
if (flags.check) {
|
|
243
403
|
const status = checkStatus(cliInfo.path, { type: cliInfo.type });
|
package/lib/hooks.js
CHANGED
|
@@ -15,8 +15,13 @@ const HOME = os.homedir();
|
|
|
15
15
|
// (on Windows, ~ expands to %USERPROFILE%)
|
|
16
16
|
const SETTINGS_PATH = path.join(HOME, '.claude', 'settings.json');
|
|
17
17
|
|
|
18
|
+
// Log file for debugging hook execution
|
|
19
|
+
const LOG_PATH = path.join(HOME, '.claude', 'depester.log');
|
|
20
|
+
const MAX_LOG_ENTRIES = 50;
|
|
21
|
+
|
|
18
22
|
// Use --all to patch all installations (CLI + VS Code binary + webview)
|
|
19
|
-
|
|
23
|
+
// Use --log to write results to ~/.claude/depester.log for debugging
|
|
24
|
+
const HOOK_COMMAND = 'npx claude-depester --all --silent --log';
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
27
|
* Read Claude Code settings
|
|
@@ -179,11 +184,146 @@ function getHookStatus() {
|
|
|
179
184
|
};
|
|
180
185
|
}
|
|
181
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Search Claude debug logs for hook-related entries
|
|
189
|
+
* @param {number} maxFiles - Maximum number of log files to search (default 5)
|
|
190
|
+
* @returns {Array<{file: string, timestamp: string, entries: Array<{time: string, message: string}>}>}
|
|
191
|
+
*/
|
|
192
|
+
function searchHookLogs(maxFiles = 5) {
|
|
193
|
+
const debugDir = path.join(HOME, '.claude', 'debug');
|
|
194
|
+
const results = [];
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
if (!fs.existsSync(debugDir)) {
|
|
198
|
+
return results;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Get log files sorted by modification time (newest first)
|
|
202
|
+
const files = fs.readdirSync(debugDir)
|
|
203
|
+
.filter(f => f.endsWith('.txt') && f !== 'latest')
|
|
204
|
+
.map(f => ({
|
|
205
|
+
name: f,
|
|
206
|
+
path: path.join(debugDir, f),
|
|
207
|
+
mtime: fs.statSync(path.join(debugDir, f)).mtime
|
|
208
|
+
}))
|
|
209
|
+
.sort((a, b) => b.mtime - a.mtime)
|
|
210
|
+
.slice(0, maxFiles);
|
|
211
|
+
|
|
212
|
+
for (const file of files) {
|
|
213
|
+
const content = fs.readFileSync(file.path, 'utf-8');
|
|
214
|
+
const lines = content.split('\n');
|
|
215
|
+
const hookEntries = [];
|
|
216
|
+
|
|
217
|
+
for (const line of lines) {
|
|
218
|
+
// Look for SessionStart hook entries only (not repo URLs containing "depester")
|
|
219
|
+
if (line.includes('SessionStart') ||
|
|
220
|
+
line.includes('Hook output')) {
|
|
221
|
+
// Parse timestamp from log line: 2026-01-18T09:07:34.119Z [DEBUG] ...
|
|
222
|
+
const match = line.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[.*?\]\s+(.*)$/);
|
|
223
|
+
if (match) {
|
|
224
|
+
hookEntries.push({
|
|
225
|
+
time: match[1],
|
|
226
|
+
message: match[2]
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (hookEntries.length > 0) {
|
|
233
|
+
results.push({
|
|
234
|
+
file: file.name,
|
|
235
|
+
timestamp: file.mtime.toISOString(),
|
|
236
|
+
entries: hookEntries
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
} catch (e) {
|
|
241
|
+
// Ignore errors reading logs
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return results;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Append entry to depester log file, keeping only last MAX_LOG_ENTRIES
|
|
249
|
+
* @param {string} message - Log message
|
|
250
|
+
* @param {object} data - Additional data to log
|
|
251
|
+
*/
|
|
252
|
+
function appendLog(message, data = null) {
|
|
253
|
+
try {
|
|
254
|
+
const timestamp = new Date().toISOString();
|
|
255
|
+
const entry = {
|
|
256
|
+
timestamp,
|
|
257
|
+
message,
|
|
258
|
+
...(data && { data })
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
// Read existing entries
|
|
262
|
+
let entries = [];
|
|
263
|
+
if (fs.existsSync(LOG_PATH)) {
|
|
264
|
+
const content = fs.readFileSync(LOG_PATH, 'utf-8');
|
|
265
|
+
const lines = content.trim().split('\n').filter(l => l);
|
|
266
|
+
entries = lines.map(line => {
|
|
267
|
+
try {
|
|
268
|
+
return JSON.parse(line);
|
|
269
|
+
} catch {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
}).filter(e => e !== null);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Add new entry
|
|
276
|
+
entries.push(entry);
|
|
277
|
+
|
|
278
|
+
// Keep only last MAX_LOG_ENTRIES
|
|
279
|
+
if (entries.length > MAX_LOG_ENTRIES) {
|
|
280
|
+
entries = entries.slice(-MAX_LOG_ENTRIES);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Write back
|
|
284
|
+
const dir = path.dirname(LOG_PATH);
|
|
285
|
+
if (!fs.existsSync(dir)) {
|
|
286
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
287
|
+
}
|
|
288
|
+
fs.writeFileSync(LOG_PATH, entries.map(e => JSON.stringify(e)).join('\n') + '\n', 'utf-8');
|
|
289
|
+
|
|
290
|
+
} catch (e) {
|
|
291
|
+
// Silently ignore logging errors
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Read depester log entries
|
|
297
|
+
* @returns {Array<{timestamp: string, message: string, data?: object}>}
|
|
298
|
+
*/
|
|
299
|
+
function readLog() {
|
|
300
|
+
try {
|
|
301
|
+
if (!fs.existsSync(LOG_PATH)) {
|
|
302
|
+
return [];
|
|
303
|
+
}
|
|
304
|
+
const content = fs.readFileSync(LOG_PATH, 'utf-8');
|
|
305
|
+
const lines = content.trim().split('\n').filter(l => l);
|
|
306
|
+
return lines.map(line => {
|
|
307
|
+
try {
|
|
308
|
+
return JSON.parse(line);
|
|
309
|
+
} catch {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
}).filter(e => e !== null);
|
|
313
|
+
} catch (e) {
|
|
314
|
+
return [];
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
182
318
|
module.exports = {
|
|
183
319
|
installHook,
|
|
184
320
|
removeHook,
|
|
185
321
|
isHookInstalled,
|
|
186
322
|
getHookStatus,
|
|
323
|
+
searchHookLogs,
|
|
324
|
+
appendLog,
|
|
325
|
+
readLog,
|
|
187
326
|
SETTINGS_PATH,
|
|
188
|
-
HOOK_COMMAND
|
|
327
|
+
HOOK_COMMAND,
|
|
328
|
+
LOG_PATH
|
|
189
329
|
};
|
package/lib/patcher.js
CHANGED
|
@@ -450,9 +450,112 @@ function checkStatus(filePath, options = {}) {
|
|
|
450
450
|
}
|
|
451
451
|
}
|
|
452
452
|
|
|
453
|
+
/**
|
|
454
|
+
* Get detailed debug info for troubleshooting
|
|
455
|
+
* @param {string} filePath - Path to cli.js or binary
|
|
456
|
+
* @param {object} options - Options
|
|
457
|
+
* @param {string} options.type - Override type detection: 'binary', 'js', 'webview'
|
|
458
|
+
* @returns {object} Detailed debug information
|
|
459
|
+
*/
|
|
460
|
+
function getDebugInfo(filePath, options = {}) {
|
|
461
|
+
const debug = {
|
|
462
|
+
filePath,
|
|
463
|
+
fileExists: false,
|
|
464
|
+
fileSize: null,
|
|
465
|
+
fileModified: null,
|
|
466
|
+
isBinary: false,
|
|
467
|
+
isWebview: options.type === 'webview',
|
|
468
|
+
binaryExtractionOk: null,
|
|
469
|
+
extractedJsSize: null,
|
|
470
|
+
// Detection details
|
|
471
|
+
hasReplacementPattern: false, // =["Thinking"]
|
|
472
|
+
hasCompletionReplacement: false, // =["Thought"]
|
|
473
|
+
hasOriginalSpinnerArray: false, // ["Accomplishing"..."Zigzagging"]
|
|
474
|
+
hasOriginalCompletionArray: false, // ["Baked"..."Worked"]
|
|
475
|
+
markerWordsFound: [],
|
|
476
|
+
completionVerbsFound: [],
|
|
477
|
+
// Computed status
|
|
478
|
+
spinnerPatched: false,
|
|
479
|
+
completionPatched: false,
|
|
480
|
+
hasSillyWords: false,
|
|
481
|
+
hasBackup: false,
|
|
482
|
+
error: null
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
// File metadata
|
|
487
|
+
if (!fs.existsSync(filePath)) {
|
|
488
|
+
debug.error = 'File does not exist';
|
|
489
|
+
return debug;
|
|
490
|
+
}
|
|
491
|
+
debug.fileExists = true;
|
|
492
|
+
|
|
493
|
+
const stats = fs.statSync(filePath);
|
|
494
|
+
debug.fileSize = stats.size;
|
|
495
|
+
debug.fileModified = stats.mtime.toISOString();
|
|
496
|
+
|
|
497
|
+
// Backup check
|
|
498
|
+
debug.hasBackup = hasBackup(filePath);
|
|
499
|
+
|
|
500
|
+
// Binary detection
|
|
501
|
+
const { type } = options;
|
|
502
|
+
debug.isBinary = type !== 'js' && type !== 'webview' && isNativeBinary(filePath);
|
|
503
|
+
|
|
504
|
+
// Get content
|
|
505
|
+
let content;
|
|
506
|
+
if (debug.isBinary) {
|
|
507
|
+
content = extractClaudeJs(filePath);
|
|
508
|
+
if (!content) {
|
|
509
|
+
debug.binaryExtractionOk = false;
|
|
510
|
+
debug.error = 'Could not extract JavaScript from binary';
|
|
511
|
+
return debug;
|
|
512
|
+
}
|
|
513
|
+
debug.binaryExtractionOk = true;
|
|
514
|
+
debug.extractedJsSize = content.length;
|
|
515
|
+
} else {
|
|
516
|
+
content = fs.readFileSync(filePath);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const str = Buffer.isBuffer(content) ? content.toString('utf-8') : content;
|
|
520
|
+
|
|
521
|
+
// Check for replacement patterns
|
|
522
|
+
debug.hasReplacementPattern = /=\["Thinking"\]/.test(str);
|
|
523
|
+
debug.hasCompletionReplacement = /=\["Thought"\]/.test(str);
|
|
524
|
+
|
|
525
|
+
// Check for original arrays
|
|
526
|
+
debug.hasOriginalSpinnerArray = str.includes('["Accomplishing"') && str.includes('"Zigzagging"]');
|
|
527
|
+
debug.hasOriginalCompletionArray = str.includes('["Baked"') && str.includes('"Worked"]');
|
|
528
|
+
|
|
529
|
+
// Check for individual marker words
|
|
530
|
+
for (const word of MARKER_WORDS) {
|
|
531
|
+
if (str.includes(`"${word}"`)) {
|
|
532
|
+
debug.markerWordsFound.push(word);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Check for individual completion verbs
|
|
537
|
+
for (const verb of COMPLETION_VERBS) {
|
|
538
|
+
if (str.includes(`"${verb}"`)) {
|
|
539
|
+
debug.completionVerbsFound.push(verb);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Compute status using existing functions
|
|
544
|
+
debug.spinnerPatched = isPatched(content);
|
|
545
|
+
debug.completionPatched = isCompletionPatched(content);
|
|
546
|
+
debug.hasSillyWords = hasSillyWords(content);
|
|
547
|
+
|
|
548
|
+
} catch (err) {
|
|
549
|
+
debug.error = err.message;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return debug;
|
|
553
|
+
}
|
|
554
|
+
|
|
453
555
|
module.exports = {
|
|
454
556
|
patch,
|
|
455
557
|
checkStatus,
|
|
558
|
+
getDebugInfo,
|
|
456
559
|
restoreBackup,
|
|
457
560
|
hasBackup,
|
|
458
561
|
hasSillyWords,
|
package/package.json
CHANGED