claude-depester 1.0.0
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/LICENSE +21 -0
- package/README.md +191 -0
- package/bin/claude-depester +215 -0
- package/lib/bun-binary.js +530 -0
- package/lib/detector.js +184 -0
- package/lib/hooks.js +181 -0
- package/lib/patcher.js +337 -0
- package/package.json +41 -0
package/lib/hooks.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manage Claude Code SessionStart hooks for auto-patching
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
|
|
9
|
+
const HOME = os.homedir();
|
|
10
|
+
const SETTINGS_PATH = path.join(HOME, '.claude', 'settings.json');
|
|
11
|
+
const HOOK_COMMAND = 'npx claude-depester --silent';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Read Claude Code settings
|
|
15
|
+
* @returns {object}
|
|
16
|
+
*/
|
|
17
|
+
function readSettings() {
|
|
18
|
+
try {
|
|
19
|
+
if (fs.existsSync(SETTINGS_PATH)) {
|
|
20
|
+
const content = fs.readFileSync(SETTINGS_PATH, 'utf-8');
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
}
|
|
23
|
+
} catch (e) {
|
|
24
|
+
// File doesn't exist or invalid JSON
|
|
25
|
+
}
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Write Claude Code settings
|
|
31
|
+
* @param {object} settings
|
|
32
|
+
*/
|
|
33
|
+
function writeSettings(settings) {
|
|
34
|
+
const dir = path.dirname(SETTINGS_PATH);
|
|
35
|
+
if (!fs.existsSync(dir)) {
|
|
36
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2), 'utf-8');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if our hook is installed
|
|
43
|
+
* @returns {boolean}
|
|
44
|
+
*/
|
|
45
|
+
function isHookInstalled() {
|
|
46
|
+
const settings = readSettings();
|
|
47
|
+
|
|
48
|
+
if (!settings.hooks?.SessionStart) return false;
|
|
49
|
+
|
|
50
|
+
// Check if any SessionStart hook has our command
|
|
51
|
+
for (const hookGroup of settings.hooks.SessionStart) {
|
|
52
|
+
if (!hookGroup.hooks) continue;
|
|
53
|
+
for (const hook of hookGroup.hooks) {
|
|
54
|
+
if (hook.command && hook.command.includes('claude-depester')) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Install SessionStart hook for auto-patching
|
|
65
|
+
* @returns {{ success: boolean, message: string }}
|
|
66
|
+
*/
|
|
67
|
+
function installHook() {
|
|
68
|
+
try {
|
|
69
|
+
const settings = readSettings();
|
|
70
|
+
|
|
71
|
+
// Initialize hooks structure if needed
|
|
72
|
+
if (!settings.hooks) {
|
|
73
|
+
settings.hooks = {};
|
|
74
|
+
}
|
|
75
|
+
if (!settings.hooks.SessionStart) {
|
|
76
|
+
settings.hooks.SessionStart = [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check if already installed
|
|
80
|
+
if (isHookInstalled()) {
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
message: 'Hook already installed'
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Add our hook
|
|
88
|
+
settings.hooks.SessionStart.push({
|
|
89
|
+
hooks: [
|
|
90
|
+
{
|
|
91
|
+
type: 'command',
|
|
92
|
+
command: HOOK_COMMAND,
|
|
93
|
+
timeout: 30
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
writeSettings(settings);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
success: true,
|
|
102
|
+
message: `Hook installed. Claude Code will auto-patch on startup.\nSettings file: ${SETTINGS_PATH}`
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
} catch (err) {
|
|
106
|
+
return {
|
|
107
|
+
success: false,
|
|
108
|
+
message: `Failed to install hook: ${err.message}`
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Remove our SessionStart hook
|
|
115
|
+
* @returns {{ success: boolean, message: string }}
|
|
116
|
+
*/
|
|
117
|
+
function removeHook() {
|
|
118
|
+
try {
|
|
119
|
+
const settings = readSettings();
|
|
120
|
+
|
|
121
|
+
if (!settings.hooks?.SessionStart) {
|
|
122
|
+
return {
|
|
123
|
+
success: true,
|
|
124
|
+
message: 'No hook to remove'
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Filter out our hooks
|
|
129
|
+
settings.hooks.SessionStart = settings.hooks.SessionStart.filter(hookGroup => {
|
|
130
|
+
if (!hookGroup.hooks) return true;
|
|
131
|
+
// Remove hook groups that only contain our depester hook
|
|
132
|
+
const nonDepesterHooks = hookGroup.hooks.filter(
|
|
133
|
+
hook => !hook.command?.includes('claude-depester')
|
|
134
|
+
);
|
|
135
|
+
if (nonDepesterHooks.length === 0) return false;
|
|
136
|
+
hookGroup.hooks = nonDepesterHooks;
|
|
137
|
+
return true;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Clean up empty arrays
|
|
141
|
+
if (settings.hooks.SessionStart.length === 0) {
|
|
142
|
+
delete settings.hooks.SessionStart;
|
|
143
|
+
}
|
|
144
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
145
|
+
delete settings.hooks;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
writeSettings(settings);
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
success: true,
|
|
152
|
+
message: 'Hook removed'
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
} catch (err) {
|
|
156
|
+
return {
|
|
157
|
+
success: false,
|
|
158
|
+
message: `Failed to remove hook: ${err.message}`
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get hook status
|
|
165
|
+
* @returns {{ installed: boolean, settingsPath: string }}
|
|
166
|
+
*/
|
|
167
|
+
function getHookStatus() {
|
|
168
|
+
return {
|
|
169
|
+
installed: isHookInstalled(),
|
|
170
|
+
settingsPath: SETTINGS_PATH
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
module.exports = {
|
|
175
|
+
installHook,
|
|
176
|
+
removeHook,
|
|
177
|
+
isHookInstalled,
|
|
178
|
+
getHookStatus,
|
|
179
|
+
SETTINGS_PATH,
|
|
180
|
+
HOOK_COMMAND
|
|
181
|
+
};
|
package/lib/patcher.js
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch Claude Code to remove silly thinking words
|
|
3
|
+
* Uses proper Bun binary extraction/repacking via node-lief
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { extractClaudeJs, repackNativeInstallation } = require('./bun-binary');
|
|
9
|
+
|
|
10
|
+
// Distinctive words to verify we found the right array
|
|
11
|
+
const MARKER_WORDS = [
|
|
12
|
+
'Flibbertigibbeting',
|
|
13
|
+
'Discombobulating',
|
|
14
|
+
'Clauding',
|
|
15
|
+
'Smooshing',
|
|
16
|
+
'Wibbling',
|
|
17
|
+
'Schlepping'
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
// What to replace with
|
|
21
|
+
const REPLACEMENT_WORD = 'Thinking';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Check if content contains the silly words array
|
|
25
|
+
* @param {string|Buffer} content - File content
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
function hasSillyWords(content) {
|
|
29
|
+
const str = Buffer.isBuffer(content) ? content.toString('utf-8') : content;
|
|
30
|
+
let found = 0;
|
|
31
|
+
for (const word of MARKER_WORDS) {
|
|
32
|
+
if (str.includes(`"${word}"`)) {
|
|
33
|
+
found++;
|
|
34
|
+
if (found >= 3) return true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Check if content is already patched
|
|
42
|
+
* @param {string|Buffer} content - File content
|
|
43
|
+
* @returns {boolean}
|
|
44
|
+
*/
|
|
45
|
+
function isPatched(content) {
|
|
46
|
+
const str = Buffer.isBuffer(content) ? content.toString('utf-8') : content;
|
|
47
|
+
const hasReplacement = /=\["Thinking"\]/.test(str);
|
|
48
|
+
const hasOriginalArray = str.includes('["Accomplishing"') && str.includes('"Zigzagging"]');
|
|
49
|
+
return hasReplacement && !hasOriginalArray;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Find and replace the silly words array in JavaScript content
|
|
54
|
+
* @param {Buffer} jsContent - JavaScript content as buffer
|
|
55
|
+
* @returns {{ patched: Buffer, count: number } | null}
|
|
56
|
+
*/
|
|
57
|
+
function patchJsContent(jsContent) {
|
|
58
|
+
let str = jsContent.toString('utf-8');
|
|
59
|
+
|
|
60
|
+
// Pattern to match the array assignment: varName=["Accomplishing",...,"Zigzagging"]
|
|
61
|
+
// We need to find arrays that contain our marker words
|
|
62
|
+
const arrayPattern = /([a-zA-Z_$][a-zA-Z0-9_$]*)=\["Accomplishing"[^\]]*"Zigzagging"\]/g;
|
|
63
|
+
|
|
64
|
+
let count = 0;
|
|
65
|
+
str = str.replace(arrayPattern, (match, varName) => {
|
|
66
|
+
// Verify it contains marker words
|
|
67
|
+
let markerCount = 0;
|
|
68
|
+
for (const marker of MARKER_WORDS) {
|
|
69
|
+
if (match.includes(`"${marker}"`)) markerCount++;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (markerCount >= 3) {
|
|
73
|
+
count++;
|
|
74
|
+
return `${varName}=["${REPLACEMENT_WORD}"]`;
|
|
75
|
+
}
|
|
76
|
+
return match;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
if (count === 0) return null;
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
patched: Buffer.from(str, 'utf-8'),
|
|
83
|
+
count
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Create backup of file
|
|
89
|
+
* @param {string} filePath - Path to file
|
|
90
|
+
* @returns {string} - Backup path
|
|
91
|
+
*/
|
|
92
|
+
function createBackup(filePath) {
|
|
93
|
+
const backupPath = filePath + '.depester.backup';
|
|
94
|
+
|
|
95
|
+
if (!fs.existsSync(backupPath)) {
|
|
96
|
+
fs.copyFileSync(filePath, backupPath);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return backupPath;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Restore from backup
|
|
104
|
+
* @param {string} filePath - Path to file
|
|
105
|
+
* @returns {boolean} - Success
|
|
106
|
+
*/
|
|
107
|
+
function restoreBackup(filePath) {
|
|
108
|
+
const backupPath = filePath + '.depester.backup';
|
|
109
|
+
|
|
110
|
+
if (!fs.existsSync(backupPath)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
fs.copyFileSync(backupPath, filePath);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Check if backup exists
|
|
120
|
+
* @param {string} filePath - Path to file
|
|
121
|
+
* @returns {boolean}
|
|
122
|
+
*/
|
|
123
|
+
function hasBackup(filePath) {
|
|
124
|
+
return fs.existsSync(filePath + '.depester.backup');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Detect if file is a native binary (vs plain JS)
|
|
129
|
+
* @param {string} filePath - Path to file
|
|
130
|
+
* @returns {boolean}
|
|
131
|
+
*/
|
|
132
|
+
function isNativeBinary(filePath) {
|
|
133
|
+
try {
|
|
134
|
+
const fd = fs.openSync(filePath, 'r');
|
|
135
|
+
const buffer = Buffer.alloc(4);
|
|
136
|
+
fs.readSync(fd, buffer, 0, 4, 0);
|
|
137
|
+
fs.closeSync(fd);
|
|
138
|
+
|
|
139
|
+
// Check for ELF magic
|
|
140
|
+
if (buffer[0] === 0x7f && buffer[1] === 0x45 && buffer[2] === 0x4c && buffer[3] === 0x46) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
// Check for MachO magic (32/64 bit, both endians)
|
|
144
|
+
const magic = buffer.readUInt32LE(0);
|
|
145
|
+
if (magic === 0xfeedface || magic === 0xfeedfacf ||
|
|
146
|
+
magic === 0xcefaedfe || magic === 0xcffaedfe) {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
// Check for PE (MZ header)
|
|
150
|
+
if (buffer[0] === 0x4d && buffer[1] === 0x5a) {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return false;
|
|
155
|
+
} catch (e) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Main patch function
|
|
162
|
+
* @param {string} filePath - Path to cli.js or binary
|
|
163
|
+
* @param {object} options - Options
|
|
164
|
+
* @returns {{ success: boolean, message: string, alreadyPatched?: boolean }}
|
|
165
|
+
*/
|
|
166
|
+
function patch(filePath, options = {}) {
|
|
167
|
+
const { dryRun = false } = options;
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
const isBinary = isNativeBinary(filePath);
|
|
171
|
+
|
|
172
|
+
if (isBinary) {
|
|
173
|
+
// Native binary - extract JS, patch, repack
|
|
174
|
+
const claudeJs = extractClaudeJs(filePath);
|
|
175
|
+
|
|
176
|
+
if (!claudeJs) {
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
message: 'Could not extract claude.js from binary. Binary format may not be supported.'
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Check if already patched
|
|
184
|
+
if (isPatched(claudeJs)) {
|
|
185
|
+
return {
|
|
186
|
+
success: true,
|
|
187
|
+
message: 'Already patched',
|
|
188
|
+
alreadyPatched: true
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Check for silly words
|
|
193
|
+
if (!hasSillyWords(claudeJs)) {
|
|
194
|
+
return {
|
|
195
|
+
success: false,
|
|
196
|
+
message: 'Could not find silly words array in extracted JavaScript.'
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Patch the JS content
|
|
201
|
+
const result = patchJsContent(claudeJs);
|
|
202
|
+
if (!result) {
|
|
203
|
+
return {
|
|
204
|
+
success: false,
|
|
205
|
+
message: 'Could not locate words array pattern in JavaScript.'
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (dryRun) {
|
|
210
|
+
return {
|
|
211
|
+
success: true,
|
|
212
|
+
message: `Dry run - would patch ${result.count} occurrence(s) of silly words array in binary`,
|
|
213
|
+
dryRun: true
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Create backup
|
|
218
|
+
const backupPath = createBackup(filePath);
|
|
219
|
+
|
|
220
|
+
// Repack binary with patched JS
|
|
221
|
+
repackNativeInstallation(filePath, result.patched, filePath);
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
success: true,
|
|
225
|
+
message: `Patched ${result.count} occurrence(s) successfully. Backup at: ${backupPath}`,
|
|
226
|
+
backupPath
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
} else {
|
|
230
|
+
// Plain JS file (npm installation)
|
|
231
|
+
const content = fs.readFileSync(filePath);
|
|
232
|
+
|
|
233
|
+
if (isPatched(content)) {
|
|
234
|
+
return {
|
|
235
|
+
success: true,
|
|
236
|
+
message: 'Already patched',
|
|
237
|
+
alreadyPatched: true
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (!hasSillyWords(content)) {
|
|
242
|
+
return {
|
|
243
|
+
success: false,
|
|
244
|
+
message: 'Could not find silly words array. Claude Code version may not be supported.'
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const result = patchJsContent(content);
|
|
249
|
+
if (!result) {
|
|
250
|
+
return {
|
|
251
|
+
success: false,
|
|
252
|
+
message: 'Could not locate words array pattern'
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (dryRun) {
|
|
257
|
+
return {
|
|
258
|
+
success: true,
|
|
259
|
+
message: `Dry run - would patch ${result.count} occurrence(s) of silly words array`,
|
|
260
|
+
dryRun: true
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Create backup
|
|
265
|
+
const backupPath = createBackup(filePath);
|
|
266
|
+
|
|
267
|
+
// Write patched content
|
|
268
|
+
fs.writeFileSync(filePath, result.patched);
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
success: true,
|
|
272
|
+
message: `Patched ${result.count} occurrence(s) successfully. Backup at: ${backupPath}`,
|
|
273
|
+
backupPath
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
} catch (err) {
|
|
278
|
+
return {
|
|
279
|
+
success: false,
|
|
280
|
+
message: `Error: ${err.message}`
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Check patch status
|
|
287
|
+
* @param {string} filePath - Path to cli.js or binary
|
|
288
|
+
* @returns {{ patched: boolean, hasSillyWords: boolean, hasBackup: boolean, isBinary: boolean }}
|
|
289
|
+
*/
|
|
290
|
+
function checkStatus(filePath) {
|
|
291
|
+
try {
|
|
292
|
+
const isBinary = isNativeBinary(filePath);
|
|
293
|
+
|
|
294
|
+
let content;
|
|
295
|
+
if (isBinary) {
|
|
296
|
+
content = extractClaudeJs(filePath);
|
|
297
|
+
if (!content) {
|
|
298
|
+
return {
|
|
299
|
+
patched: false,
|
|
300
|
+
hasSillyWords: false,
|
|
301
|
+
hasBackup: hasBackup(filePath),
|
|
302
|
+
isBinary: true,
|
|
303
|
+
error: 'Could not extract JavaScript from binary'
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
content = fs.readFileSync(filePath);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
patched: isPatched(content),
|
|
312
|
+
hasSillyWords: hasSillyWords(content),
|
|
313
|
+
hasBackup: hasBackup(filePath),
|
|
314
|
+
isBinary
|
|
315
|
+
};
|
|
316
|
+
} catch (err) {
|
|
317
|
+
return {
|
|
318
|
+
patched: false,
|
|
319
|
+
hasSillyWords: false,
|
|
320
|
+
hasBackup: false,
|
|
321
|
+
isBinary: false,
|
|
322
|
+
error: err.message
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
module.exports = {
|
|
328
|
+
patch,
|
|
329
|
+
checkStatus,
|
|
330
|
+
restoreBackup,
|
|
331
|
+
hasBackup,
|
|
332
|
+
hasSillyWords,
|
|
333
|
+
isPatched,
|
|
334
|
+
isNativeBinary,
|
|
335
|
+
MARKER_WORDS,
|
|
336
|
+
REPLACEMENT_WORD
|
|
337
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-depester",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Remove silly thinking words from Claude Code. Auto-patches and survives updates via SessionStart hook.",
|
|
5
|
+
"main": "lib/patcher.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"claude-depester": "./bin/claude-depester"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node bin/claude-depester --check"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"claude-code",
|
|
14
|
+
"anthropic",
|
|
15
|
+
"cli",
|
|
16
|
+
"patch",
|
|
17
|
+
"thinking-words"
|
|
18
|
+
],
|
|
19
|
+
"author": "ominiverdi",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/ominiverdi/claude-depester.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/ominiverdi/claude-depester/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/ominiverdi/claude-depester#readme",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=18.0.0"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"bin/",
|
|
34
|
+
"lib/",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"node-lief": "^0.1.8"
|
|
40
|
+
}
|
|
41
|
+
}
|