Skip to content

Commit a882499

Browse files
0xrinegadeclaude
andcommitted
fix(npm): prevent fork bomb when binary missing
The wrapper script was spawning itself infinitely when the Rust binary wasn't downloaded. Fixed by: - Rename binary to claudev-bin (wrapper stays claudev) - Add size check to detect invalid/missing binary - postinstall.js now renames downloaded binary Closes the infinite spawn loop that consumed 42GB of swap. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent dcc37c4 commit a882499

4 files changed

Lines changed: 26 additions & 8 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "claudev"
3-
version = "0.5.0"
3+
version = "0.5.1"
44
edition = "2021"
55
description = "Analyze AI coding assistant usage patterns, costs, and productivity"
66
license = "MIT"

bin/claudev

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,22 @@ const path = require('path');
55
const fs = require('fs');
66
const os = require('os');
77

8-
const BINARY_NAME = 'claudev' + (os.platform() === 'win32' ? '.exe' : '');
8+
// Binary has different name to avoid spawning this wrapper script
9+
const BINARY_NAME = 'claudev-bin' + (os.platform() === 'win32' ? '.exe' : '');
910
const binaryPath = path.join(__dirname, BINARY_NAME);
1011

12+
// Prevent fork bomb: check if binary exists AND is not this script
13+
const thisScript = __filename;
1114
if (!fs.existsSync(binaryPath)) {
12-
console.error('claudev: Binary not found. Run: npm install -g claudev');
15+
console.error('claudev: Binary not found at', binaryPath);
16+
console.error('claudev: Run: npm install -g claudev (or cargo install claudev)');
17+
process.exit(1);
18+
}
19+
20+
// Extra safety: verify it's actually an executable, not a script
21+
const stats = fs.statSync(binaryPath);
22+
if (stats.size < 10000) {
23+
console.error('claudev: Binary appears invalid (too small). Reinstall with: npm install -g claudev');
1324
process.exit(1);
1425
}
1526

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "claudev",
3-
"version": "0.5.0",
3+
"version": "0.5.1",
44
"description": "Analyze AI coding assistant usage patterns, costs, and productivity",
55
"keywords": [
66
"ai",

scripts/postinstall.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ const { execFileSync } = require('child_process');
1313

1414
const PACKAGE_VERSION = require('../package.json').version;
1515
const REPO = 'openSVM/vibedev';
16-
const BINARY_NAME = 'claudev';
16+
const BINARY_NAME = 'claudev'; // Name in GitHub releases
17+
const LOCAL_BINARY_NAME = 'claudev-bin'; // Local name to avoid fork bomb with wrapper
1718
const DOWNLOAD_TIMEOUT = 60000; // 60 seconds
1819

1920
// Map Node.js platform/arch to Rust target triples
@@ -126,9 +127,10 @@ async function main() {
126127
}
127128

128129
const binDir = path.join(__dirname, '..', 'bin');
129-
const binaryPath = path.join(binDir, BINARY_NAME + getBinaryExtension());
130+
const downloadedPath = path.join(binDir, BINARY_NAME + getBinaryExtension());
131+
const localBinaryPath = path.join(binDir, LOCAL_BINARY_NAME + getBinaryExtension());
130132

131-
if (fs.existsSync(binaryPath)) {
133+
if (fs.existsSync(localBinaryPath)) {
132134
console.log('claudev: Binary exists, skipping download');
133135
return;
134136
}
@@ -149,8 +151,13 @@ async function main() {
149151
extractTarGz(buffer, binDir);
150152
}
151153

154+
// Rename to local binary name to avoid fork bomb with wrapper script
155+
if (fs.existsSync(downloadedPath)) {
156+
fs.renameSync(downloadedPath, localBinaryPath);
157+
}
158+
152159
if (os.platform() !== 'win32') {
153-
fs.chmodSync(binaryPath, 0o755);
160+
fs.chmodSync(localBinaryPath, 0o755);
154161
}
155162

156163
console.log('claudev: Installed successfully!');

0 commit comments

Comments
 (0)