claude-depester 1.3.3 → 1.3.5
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 +41 -15
- package/lib/bun-binary.js +36 -15
- package/lib/patcher.js +193 -63
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,17 +4,26 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/claude-depester)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Patches Claude Code CLI and VS Code extension to replace whimsical loading words with simple 'Thinking'.
|
|
8
8
|
|
|
9
9
|
Instead of seeing "Flibbertigibbeting", "Discombobulating", "Clauding", etc., you'll see a clean "Thinking".
|
|
10
10
|
|
|
11
|
-
> **Last updated:** 2026-01-
|
|
11
|
+
> **Last updated:** 2026-01-22 | **Tested with:** Claude Code 2.1.15 | **Platforms:** Linux, macOS, Windows
|
|
12
12
|
>
|
|
13
|
-
> v1.3.
|
|
13
|
+
> v1.3.5: Fix VS Code binary completion verbs patching for new bytecode array structure
|
|
14
|
+
|
|
15
|
+
**CLI - Spinner:**
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
**CLI - Completion:**
|
|
14
20
|
|
|
15
|
-

|
|
16
21
|

|
|
17
22
|
|
|
23
|
+
**VS Code Extension:**
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
|
|
18
27
|
## The Problem
|
|
19
28
|
|
|
20
29
|
Claude Code displays random silly words while thinking:
|
|
@@ -45,12 +54,20 @@ npx claude-depester --dry-run
|
|
|
45
54
|
|
|
46
55
|
# Patch Claude Code
|
|
47
56
|
npx claude-depester
|
|
57
|
+
```
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
|
|
59
|
+
Restart Claude Code for changes to take effect.
|
|
60
|
+
|
|
61
|
+
### Auto-patch after updates (recommended)
|
|
62
|
+
|
|
63
|
+
Add a shell wrapper that patches before each invocation:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Add to your .bashrc or .zshrc
|
|
67
|
+
cl() { npx claude-depester --all --silent --log ; claude "$@" ; }
|
|
51
68
|
```
|
|
52
69
|
|
|
53
|
-
|
|
70
|
+
Then use `cl` instead of `claude`. This ensures patching happens *before* Claude loads.
|
|
54
71
|
|
|
55
72
|
## Features
|
|
56
73
|
|
|
@@ -60,7 +77,7 @@ That's it! Restart Claude Code for changes to take effect.
|
|
|
60
77
|
- **Patches VS Code/VSCodium extension webview** (the UI that shows spinner text)
|
|
61
78
|
- Auto-detects your Claude Code installation
|
|
62
79
|
- Creates backup before patching (can restore anytime)
|
|
63
|
-
-
|
|
80
|
+
- Shell wrapper for reliable auto-patching before Claude loads
|
|
64
81
|
- Content-based detection survives version updates
|
|
65
82
|
- Cross-platform: Linux, macOS, Windows (WSL/Git Bash)
|
|
66
83
|
|
|
@@ -117,7 +134,7 @@ The tool auto-detects your installation. Use `--list` to see all found installat
|
|
|
117
134
|
|
|
118
135
|
## After Claude Code Updates
|
|
119
136
|
|
|
120
|
-
|
|
137
|
+
If you're using the shell wrapper (recommended), patching happens automatically before each session.
|
|
121
138
|
|
|
122
139
|
Otherwise, just run `npx claude-depester` again after updating.
|
|
123
140
|
|
|
@@ -129,7 +146,9 @@ npx claude-depester --restore
|
|
|
129
146
|
|
|
130
147
|
This restores from the backup created during patching.
|
|
131
148
|
|
|
132
|
-
##
|
|
149
|
+
## SessionStart Hook (Alternative)
|
|
150
|
+
|
|
151
|
+
> **Note:** The shell wrapper is the recommended approach. The SessionStart hook has a limitation: it runs *after* Claude is already loaded into memory, so the patch only takes effect on the *next* session after an update.
|
|
133
152
|
|
|
134
153
|
The `--install-hook` command adds a SessionStart hook to `~/.claude/settings.json`:
|
|
135
154
|
|
|
@@ -150,11 +169,11 @@ The `--install-hook` command adds a SessionStart hook to `~/.claude/settings.jso
|
|
|
150
169
|
}
|
|
151
170
|
```
|
|
152
171
|
|
|
153
|
-
|
|
172
|
+
This patches the file on disk at session start, but the current session may still show silly words until you restart. The `--log` flag writes results to `~/.claude/depester.log` (keeps last 50 entries) for troubleshooting.
|
|
154
173
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
174
|
+
To install or update the hook:
|
|
175
|
+
```bash
|
|
176
|
+
npx claude-depester --install-hook
|
|
158
177
|
> ```
|
|
159
178
|
|
|
160
179
|
## Troubleshooting
|
|
@@ -206,7 +225,8 @@ If the patch fails:
|
|
|
206
225
|
|
|
207
226
|
```bash
|
|
208
227
|
npx claude-depester --restore --all # Restore all installations
|
|
209
|
-
npx claude-depester --remove-hook # Remove
|
|
228
|
+
npx claude-depester --remove-hook # Remove hook (if installed)
|
|
229
|
+
# Remove the shell wrapper from your .bashrc/.zshrc if added
|
|
210
230
|
```
|
|
211
231
|
|
|
212
232
|
## Technical Details
|
|
@@ -269,6 +289,12 @@ This project builds upon work by:
|
|
|
269
289
|
- [vemv's gist](https://gist.github.com/vemv/c6333d53ede16198a23eb95425051b7b) - Original simple patch idea
|
|
270
290
|
- [heromantf's bun extractor](https://gist.github.com/heromantf/7db88edcb7b1c0c35067244584a01afc) - Bun binary structure documentation
|
|
271
291
|
|
|
292
|
+
## Donors
|
|
293
|
+
|
|
294
|
+
Thanks to these generous supporters:
|
|
295
|
+
|
|
296
|
+
- [@gyohng](https://github.com/gyohng)
|
|
297
|
+
|
|
272
298
|
## License
|
|
273
299
|
|
|
274
300
|
MIT - see [LICENSE](LICENSE)
|
package/lib/bun-binary.js
CHANGED
|
@@ -261,14 +261,32 @@ function extractClaudeJs(binaryPath) {
|
|
|
261
261
|
const binary = LIEF.parse(binaryPath);
|
|
262
262
|
const { bunOffsets, bunData } = getBunData(binary);
|
|
263
263
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
264
|
+
let target = null;
|
|
265
|
+
|
|
266
|
+
mapModules(bunData, bunOffsets, (module, moduleName) => {
|
|
267
|
+
// Check contents
|
|
267
268
|
const moduleContents = getStringPointerContent(bunData, module.contents);
|
|
268
|
-
|
|
269
|
+
if (moduleContents.includes('Flibbertigibbeting')) {
|
|
270
|
+
target = { content: moduleContents, moduleName, type: 'contents' };
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Check bytecode (for new versions where source is embedded in bytecode)
|
|
275
|
+
const moduleBytecode = getStringPointerContent(bunData, module.bytecode);
|
|
276
|
+
if (moduleBytecode.includes('Flibbertigibbeting')) {
|
|
277
|
+
target = { content: moduleBytecode, moduleName, type: 'bytecode' };
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Fallback
|
|
282
|
+
if (isClaudeModule(moduleName) && !target) {
|
|
283
|
+
target = { content: moduleContents, moduleName, type: 'contents' };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return undefined;
|
|
269
287
|
});
|
|
270
288
|
|
|
271
|
-
return
|
|
289
|
+
return target;
|
|
272
290
|
} catch (error) {
|
|
273
291
|
return null;
|
|
274
292
|
}
|
|
@@ -277,7 +295,7 @@ function extractClaudeJs(binaryPath) {
|
|
|
277
295
|
/**
|
|
278
296
|
* Rebuild Bun data with modified claude.js
|
|
279
297
|
*/
|
|
280
|
-
function rebuildBunData(bunData, bunOffsets, modifiedClaudeJs) {
|
|
298
|
+
function rebuildBunData(bunData, bunOffsets, modifiedClaudeJs, targetModuleName, targetType) {
|
|
281
299
|
// Collect all string data and module metadata
|
|
282
300
|
const stringsData = [];
|
|
283
301
|
const modulesMetadata = [];
|
|
@@ -285,16 +303,18 @@ function rebuildBunData(bunData, bunOffsets, modifiedClaudeJs) {
|
|
|
285
303
|
mapModules(bunData, bunOffsets, (module, moduleName) => {
|
|
286
304
|
const nameBytes = getStringPointerContent(bunData, module.name);
|
|
287
305
|
|
|
288
|
-
|
|
289
|
-
let
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
306
|
+
let contentsBytes = getStringPointerContent(bunData, module.contents);
|
|
307
|
+
let bytecodeBytes = getStringPointerContent(bunData, module.bytecode);
|
|
308
|
+
|
|
309
|
+
if (modifiedClaudeJs && moduleName === targetModuleName) {
|
|
310
|
+
if (targetType === 'bytecode') {
|
|
311
|
+
bytecodeBytes = modifiedClaudeJs;
|
|
312
|
+
} else {
|
|
313
|
+
contentsBytes = modifiedClaudeJs;
|
|
314
|
+
}
|
|
294
315
|
}
|
|
295
316
|
|
|
296
317
|
const sourcemapBytes = getStringPointerContent(bunData, module.sourcemap);
|
|
297
|
-
const bytecodeBytes = getStringPointerContent(bunData, module.bytecode);
|
|
298
318
|
|
|
299
319
|
modulesMetadata.push({
|
|
300
320
|
name: nameBytes,
|
|
@@ -503,12 +523,13 @@ function repackPE(peBinary, binaryPath, newBunBuffer, outputPath, sectionHeaderS
|
|
|
503
523
|
/**
|
|
504
524
|
* Repack native installation with modified claude.js
|
|
505
525
|
*/
|
|
506
|
-
function repackNativeInstallation(binaryPath, modifiedClaudeJs, outputPath) {
|
|
526
|
+
function repackNativeInstallation(binaryPath, modifiedClaudeJs, outputPath, targetModuleName, targetType) {
|
|
507
527
|
LIEF.logging.disable();
|
|
508
528
|
const binary = LIEF.parse(binaryPath);
|
|
509
529
|
|
|
510
530
|
const { bunOffsets, bunData, sectionHeaderSize } = getBunData(binary);
|
|
511
|
-
|
|
531
|
+
// Pass targetModuleName and targetType
|
|
532
|
+
const newBuffer = rebuildBunData(bunData, bunOffsets, modifiedClaudeJs, targetModuleName, targetType);
|
|
512
533
|
|
|
513
534
|
switch (binary.format) {
|
|
514
535
|
case 'MachO':
|
package/lib/patcher.js
CHANGED
|
@@ -46,21 +46,26 @@ const COMPLETION_REPLACEMENT = 'Thought';
|
|
|
46
46
|
*/
|
|
47
47
|
function hasSillyWords(content) {
|
|
48
48
|
const str = Buffer.isBuffer(content) ? content.toString('utf-8') : content;
|
|
49
|
-
|
|
50
|
-
// Check for spinner words
|
|
51
|
-
let
|
|
49
|
+
|
|
50
|
+
// Check for spinner words (need 3+ matches)
|
|
51
|
+
let spinnerFound = 0;
|
|
52
52
|
for (const word of MARKER_WORDS) {
|
|
53
53
|
if (str.includes(`"${word}"`)) {
|
|
54
|
-
|
|
55
|
-
if (
|
|
54
|
+
spinnerFound++;
|
|
55
|
+
if (spinnerFound >= 3) return true;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
|
|
59
|
-
// Also check for completion verbs (
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
|
|
59
|
+
// Also check for completion verbs (need 3+ matches)
|
|
60
|
+
// Uses same approach as hasCompletionVerbs for consistency
|
|
61
|
+
let completionFound = 0;
|
|
62
|
+
for (const word of COMPLETION_VERBS) {
|
|
63
|
+
if (str.includes(`"${word}"`)) {
|
|
64
|
+
completionFound++;
|
|
65
|
+
if (completionFound >= 3) return true;
|
|
66
|
+
}
|
|
62
67
|
}
|
|
63
|
-
|
|
68
|
+
|
|
64
69
|
return false;
|
|
65
70
|
}
|
|
66
71
|
|
|
@@ -71,7 +76,12 @@ function hasSillyWords(content) {
|
|
|
71
76
|
*/
|
|
72
77
|
function hasCompletionVerbs(content) {
|
|
73
78
|
const str = Buffer.isBuffer(content) ? content.toString('utf-8') : content;
|
|
74
|
-
|
|
79
|
+
|
|
80
|
+
let found = 0;
|
|
81
|
+
for (const word of COMPLETION_VERBS) {
|
|
82
|
+
if (str.includes(`"${word}"`)) found++;
|
|
83
|
+
}
|
|
84
|
+
return found >= 3;
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
/**
|
|
@@ -80,10 +90,10 @@ function hasCompletionVerbs(content) {
|
|
|
80
90
|
* @returns {boolean}
|
|
81
91
|
*/
|
|
82
92
|
function isPatched(content) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return
|
|
93
|
+
// If silly words are gone, it's patched.
|
|
94
|
+
// We don't check for ["Thinking"] presence because newer versions
|
|
95
|
+
// include it natively even when unpatched.
|
|
96
|
+
return !hasSillyWords(content);
|
|
87
97
|
}
|
|
88
98
|
|
|
89
99
|
/**
|
|
@@ -92,10 +102,122 @@ function isPatched(content) {
|
|
|
92
102
|
* @returns {boolean}
|
|
93
103
|
*/
|
|
94
104
|
function isCompletionPatched(content) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
return !hasCompletionVerbs(content);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Find array boundaries around a marker word in binary content
|
|
110
|
+
* @param {Buffer} buffer - Binary content
|
|
111
|
+
* @param {string} markerWord - Word to search for as anchor
|
|
112
|
+
* @param {string[]} validationWords - Words that should be present in the array
|
|
113
|
+
* @param {number} minValidationCount - Minimum number of validation words required
|
|
114
|
+
* @returns {{ startIdx: number, endIdx: number } | null}
|
|
115
|
+
*/
|
|
116
|
+
function findArrayBoundaries(buffer, markerWord, validationWords, minValidationCount) {
|
|
117
|
+
const marker = Buffer.from(markerWord);
|
|
118
|
+
const idx = buffer.indexOf(marker);
|
|
119
|
+
|
|
120
|
+
if (idx === -1) return null;
|
|
121
|
+
|
|
122
|
+
// Scan back for '['
|
|
123
|
+
let startIdx = idx;
|
|
124
|
+
const START_LIMIT = 5000;
|
|
125
|
+
let steps = 0;
|
|
126
|
+
while (startIdx > 0 && buffer[startIdx] !== 0x5B && steps < START_LIMIT) {
|
|
127
|
+
startIdx--;
|
|
128
|
+
steps++;
|
|
129
|
+
}
|
|
130
|
+
if (steps >= START_LIMIT || buffer[startIdx] !== 0x5B) return null;
|
|
131
|
+
|
|
132
|
+
// Scan forward for ']'
|
|
133
|
+
let endIdx = idx;
|
|
134
|
+
const END_LIMIT = 20000;
|
|
135
|
+
steps = 0;
|
|
136
|
+
while (endIdx < buffer.length && buffer[endIdx] !== 0x5D && steps < END_LIMIT) {
|
|
137
|
+
endIdx++;
|
|
138
|
+
steps++;
|
|
139
|
+
}
|
|
140
|
+
if (steps >= END_LIMIT || buffer[endIdx] !== 0x5D) return null;
|
|
141
|
+
|
|
142
|
+
// Verify validation words in range
|
|
143
|
+
const range = buffer.subarray(startIdx, endIdx + 1);
|
|
144
|
+
const rangeStr = range.toString('utf-8');
|
|
145
|
+
|
|
146
|
+
let foundCount = 0;
|
|
147
|
+
for (const word of validationWords) {
|
|
148
|
+
if (rangeStr.includes(`"${word}"`)) foundCount++;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (foundCount < minValidationCount) return null;
|
|
152
|
+
|
|
153
|
+
return { startIdx, endIdx };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Replace array in buffer with padded replacement, preserving length
|
|
158
|
+
* @param {Buffer} buffer - Binary content
|
|
159
|
+
* @param {number} startIdx - Start index of array
|
|
160
|
+
* @param {number} endIdx - End index of array (inclusive)
|
|
161
|
+
* @param {string} replacement - Replacement string (e.g. '["Thinking"]')
|
|
162
|
+
* @returns {Buffer | null}
|
|
163
|
+
*/
|
|
164
|
+
function replaceArrayInBuffer(buffer, startIdx, endIdx, replacement) {
|
|
165
|
+
const originalLen = endIdx - startIdx + 1;
|
|
166
|
+
const replacementBuf = Buffer.from(replacement);
|
|
167
|
+
|
|
168
|
+
if (replacementBuf.length > originalLen) return null;
|
|
169
|
+
|
|
170
|
+
const padding = Buffer.alloc(originalLen - replacementBuf.length, 0x20); // Space
|
|
171
|
+
const newContent = Buffer.concat([replacementBuf, padding]);
|
|
172
|
+
|
|
173
|
+
return Buffer.concat([
|
|
174
|
+
buffer.subarray(0, startIdx),
|
|
175
|
+
newContent,
|
|
176
|
+
buffer.subarray(endIdx + 1)
|
|
177
|
+
]);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Patch binary content by finding array boundaries around marker words
|
|
182
|
+
* Preserves exact length by padding with spaces.
|
|
183
|
+
* Safe for patching bytecode sections where offset preservation is critical.
|
|
184
|
+
* @param {Buffer} buffer - Binary content
|
|
185
|
+
* @returns {{ patched: Buffer, count: number, spinnerCount: number, completionCount: number } | null}
|
|
186
|
+
*/
|
|
187
|
+
function patchBinaryContent(buffer) {
|
|
188
|
+
let patched = buffer;
|
|
189
|
+
let spinnerCount = 0;
|
|
190
|
+
let completionCount = 0;
|
|
191
|
+
|
|
192
|
+
// Patch spinner words array (anchor: "Flibbertigibbeting")
|
|
193
|
+
const spinnerBounds = findArrayBoundaries(patched, 'Flibbertigibbeting', MARKER_WORDS, 3);
|
|
194
|
+
if (spinnerBounds) {
|
|
195
|
+
const result = replaceArrayInBuffer(patched, spinnerBounds.startIdx, spinnerBounds.endIdx, `["${REPLACEMENT_WORD}"]`);
|
|
196
|
+
if (result) {
|
|
197
|
+
patched = result;
|
|
198
|
+
spinnerCount = 1;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Patch completion verbs array (anchor: "Cogitated")
|
|
203
|
+
const completionBounds = findArrayBoundaries(patched, 'Cogitated', COMPLETION_VERBS, 3);
|
|
204
|
+
if (completionBounds) {
|
|
205
|
+
const result = replaceArrayInBuffer(patched, completionBounds.startIdx, completionBounds.endIdx, `["${COMPLETION_REPLACEMENT}"]`);
|
|
206
|
+
if (result) {
|
|
207
|
+
patched = result;
|
|
208
|
+
completionCount = 1;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const count = spinnerCount + completionCount;
|
|
213
|
+
if (count === 0) return null;
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
patched,
|
|
217
|
+
count,
|
|
218
|
+
spinnerCount,
|
|
219
|
+
completionCount
|
|
220
|
+
};
|
|
99
221
|
}
|
|
100
222
|
|
|
101
223
|
/**
|
|
@@ -108,45 +230,40 @@ function isCompletionPatched(content) {
|
|
|
108
230
|
function patchJsContent(jsContent, options = {}) {
|
|
109
231
|
let str = jsContent.toString('utf-8');
|
|
110
232
|
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
// We need to find arrays that contain our marker words
|
|
116
|
-
// Note: Webview uses longer var names like "Tte", binaries use shorter like "ouI"
|
|
117
|
-
const spinnerPatterns = [
|
|
118
|
-
/([a-zA-Z_$][a-zA-Z0-9_$]*)=\["Accomplishing"[^\]]*"Zigzagging"\]/g, // CLI binary
|
|
119
|
-
/([a-zA-Z_$][a-zA-Z0-9_$]*)=\["Accomplishing"[^\]]*"Wrangling"\]/g, // Webview
|
|
120
|
-
];
|
|
233
|
+
// Generic pattern to match any string array assignment: varName=["str","str"...]
|
|
234
|
+
// Capture group 1: varName
|
|
235
|
+
// Capture group 2: array content including brackets
|
|
236
|
+
const arrayPattern = /([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=\s*(\[[^\]]+\])/g;
|
|
121
237
|
|
|
122
238
|
let spinnerCount = 0;
|
|
123
|
-
for (const arrayPattern of spinnerPatterns) {
|
|
124
|
-
str = str.replace(arrayPattern, (match, varName) => {
|
|
125
|
-
// Verify it contains marker words
|
|
126
|
-
let markerCount = 0;
|
|
127
|
-
for (const marker of MARKER_WORDS) {
|
|
128
|
-
if (match.includes(`"${marker}"`)) markerCount++;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (markerCount >= 3) {
|
|
132
|
-
spinnerCount++;
|
|
133
|
-
return `${varName}=["${REPLACEMENT_WORD}"]`;
|
|
134
|
-
}
|
|
135
|
-
return match;
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Pattern to match the completion verbs array: varName=["Baked",...,"Worked"]
|
|
140
|
-
// This array only exists in the binary, not in the webview
|
|
141
|
-
const completionPattern = /([a-zA-Z_$][a-zA-Z0-9_$]*)=\["Baked"[^\]]*"Worked"\]/g;
|
|
142
|
-
|
|
143
239
|
let completionCount = 0;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
240
|
+
|
|
241
|
+
str = str.replace(arrayPattern, (match, varName, arrayContent) => {
|
|
242
|
+
// Check for spinner words in this array
|
|
243
|
+
let markerCount = 0;
|
|
244
|
+
for (const marker of MARKER_WORDS) {
|
|
245
|
+
if (arrayContent.includes(`"${marker}"`)) markerCount++;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// If we found enough marker words, this is the spinner array
|
|
249
|
+
if (markerCount >= 3) {
|
|
250
|
+
spinnerCount++;
|
|
251
|
+
return `${varName}=["${REPLACEMENT_WORD}"]`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Check for completion verbs in this array
|
|
255
|
+
// (Only exists in the binary, not in the webview)
|
|
256
|
+
let completionMarkerCount = 0;
|
|
257
|
+
for (const verb of COMPLETION_VERBS) {
|
|
258
|
+
if (arrayContent.includes(`"${verb}"`)) completionMarkerCount++;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// If we found enough completion verbs, this is the completion array
|
|
262
|
+
if (completionMarkerCount >= 3) {
|
|
147
263
|
completionCount++;
|
|
148
264
|
return `${varName}=["${COMPLETION_REPLACEMENT}"]`;
|
|
149
265
|
}
|
|
266
|
+
|
|
150
267
|
return match;
|
|
151
268
|
});
|
|
152
269
|
|
|
@@ -276,15 +393,19 @@ function patch(filePath, options = {}) {
|
|
|
276
393
|
|
|
277
394
|
if (isBinary) {
|
|
278
395
|
// Native binary - extract JS, patch, repack
|
|
279
|
-
const
|
|
396
|
+
const extraction = extractClaudeJs(filePath);
|
|
280
397
|
|
|
281
|
-
if (!
|
|
398
|
+
if (!extraction) {
|
|
282
399
|
return {
|
|
283
400
|
success: false,
|
|
284
401
|
message: 'Could not extract claude.js from binary. Binary format may not be supported.'
|
|
285
402
|
};
|
|
286
403
|
}
|
|
287
404
|
|
|
405
|
+
const claudeJs = extraction.content;
|
|
406
|
+
const targetModuleName = extraction.moduleName;
|
|
407
|
+
const targetType = extraction.type;
|
|
408
|
+
|
|
288
409
|
// Check if already patched
|
|
289
410
|
if (isPatched(claudeJs)) {
|
|
290
411
|
return {
|
|
@@ -298,16 +419,23 @@ function patch(filePath, options = {}) {
|
|
|
298
419
|
if (!hasSillyWords(claudeJs)) {
|
|
299
420
|
return {
|
|
300
421
|
success: false,
|
|
301
|
-
message: 'Could not find silly words array in extracted
|
|
422
|
+
message: 'Could not find silly words array in extracted content.'
|
|
302
423
|
};
|
|
303
424
|
}
|
|
304
425
|
|
|
305
|
-
// Patch the
|
|
306
|
-
|
|
426
|
+
// Patch the content
|
|
427
|
+
// Use binary patching for bytecode to preserve length/offsets
|
|
428
|
+
let result;
|
|
429
|
+
if (targetType === 'bytecode') {
|
|
430
|
+
result = patchBinaryContent(claudeJs);
|
|
431
|
+
} else {
|
|
432
|
+
result = patchJsContent(claudeJs);
|
|
433
|
+
}
|
|
434
|
+
|
|
307
435
|
if (!result) {
|
|
308
436
|
return {
|
|
309
437
|
success: false,
|
|
310
|
-
message: 'Could not locate words array pattern in
|
|
438
|
+
message: 'Could not locate words array pattern in content.'
|
|
311
439
|
};
|
|
312
440
|
}
|
|
313
441
|
|
|
@@ -325,7 +453,7 @@ function patch(filePath, options = {}) {
|
|
|
325
453
|
const backupPath = createBackup(filePath);
|
|
326
454
|
|
|
327
455
|
// Repack binary with patched JS
|
|
328
|
-
repackNativeInstallation(filePath, result.patched, filePath);
|
|
456
|
+
repackNativeInstallation(filePath, result.patched, filePath, targetModuleName, targetType);
|
|
329
457
|
|
|
330
458
|
return {
|
|
331
459
|
success: true,
|
|
@@ -412,8 +540,8 @@ function checkStatus(filePath, options = {}) {
|
|
|
412
540
|
|
|
413
541
|
let content;
|
|
414
542
|
if (isBinary) {
|
|
415
|
-
|
|
416
|
-
if (!
|
|
543
|
+
const extraction = extractClaudeJs(filePath);
|
|
544
|
+
if (!extraction) {
|
|
417
545
|
return {
|
|
418
546
|
patched: false,
|
|
419
547
|
hasSillyWords: false,
|
|
@@ -425,6 +553,7 @@ function checkStatus(filePath, options = {}) {
|
|
|
425
553
|
error: 'Could not extract JavaScript from binary'
|
|
426
554
|
};
|
|
427
555
|
}
|
|
556
|
+
content = extraction.content;
|
|
428
557
|
} else {
|
|
429
558
|
content = fs.readFileSync(filePath);
|
|
430
559
|
}
|
|
@@ -504,12 +633,13 @@ function getDebugInfo(filePath, options = {}) {
|
|
|
504
633
|
// Get content
|
|
505
634
|
let content;
|
|
506
635
|
if (debug.isBinary) {
|
|
507
|
-
|
|
508
|
-
if (!
|
|
636
|
+
const extraction = extractClaudeJs(filePath);
|
|
637
|
+
if (!extraction) {
|
|
509
638
|
debug.binaryExtractionOk = false;
|
|
510
639
|
debug.error = 'Could not extract JavaScript from binary';
|
|
511
640
|
return debug;
|
|
512
641
|
}
|
|
642
|
+
content = extraction.content;
|
|
513
643
|
debug.binaryExtractionOk = true;
|
|
514
644
|
debug.extractedJsSize = content.length;
|
|
515
645
|
} else {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-depester",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.3.5",
|
|
4
|
+
"description": "Patches Claude Code CLI and VS Code extension to show 'Thinking' instead of whimsical words.",
|
|
5
5
|
"main": "lib/patcher.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"claude-depester": "./bin/claude-depester"
|