rskim 0.7.0 → 0.9.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/bin/skim ADDED
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env node
2
+ const { spawnSync, execSync } = require('child_process');
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const os = require('os');
6
+
7
+ /**
8
+ * Cached result for musl detection (null = not yet computed)
9
+ */
10
+ let _muslCached = null;
11
+
12
+ /**
13
+ * Detect if running on musl-based Linux (Alpine, Void, etc.)
14
+ * Result is cached at module level since it cannot change during execution.
15
+ *
16
+ * ARCHITECTURE NOTE: This function is intentionally duplicated in scripts/postinstall.js.
17
+ * Postinstall scripts run before node_modules is fully available, so that script
18
+ * must be self-contained with no external dependencies. Do not extract to a shared
19
+ * module - it would break postinstall execution.
20
+ */
21
+ function isMusl() {
22
+ if (_muslCached !== null) {
23
+ return _muslCached;
24
+ }
25
+ _muslCached = detectMusl();
26
+ return _muslCached;
27
+ }
28
+
29
+ /**
30
+ * Internal musl detection logic
31
+ */
32
+ function detectMusl() {
33
+ if (process.platform !== 'linux') {
34
+ return false;
35
+ }
36
+
37
+ // Check for Alpine Linux (most common musl distro)
38
+ try {
39
+ const osRelease = fs.readFileSync('/etc/os-release', 'utf8');
40
+ if (osRelease.includes('Alpine')) {
41
+ return true;
42
+ }
43
+ } catch {
44
+ // File doesn't exist, continue checking
45
+ }
46
+
47
+ // Check ldd output for musl
48
+ try {
49
+ const lddOutput = execSync('ldd --version 2>&1 || true', { encoding: 'utf8' });
50
+ if (lddOutput.includes('musl')) {
51
+ return true;
52
+ }
53
+ } catch {
54
+ // ldd not available, continue checking
55
+ }
56
+
57
+ // Check for musl dynamic linker
58
+ try {
59
+ const files = fs.readdirSync('/lib');
60
+ if (files.some(f => f.startsWith('ld-musl'))) {
61
+ return true;
62
+ }
63
+ } catch {
64
+ // /lib doesn't exist or not readable
65
+ }
66
+
67
+ return false;
68
+ }
69
+
70
+ /**
71
+ * Get the platform-specific package name
72
+ */
73
+ function getPlatformPackage() {
74
+ const platform = process.platform;
75
+ const arch = process.arch;
76
+ const musl = isMusl();
77
+
78
+ const packages = {
79
+ 'darwin-arm64': '@rskim/cli-darwin-arm64',
80
+ 'darwin-x64': '@rskim/cli-darwin-x64',
81
+ 'linux-arm64': musl ? '@rskim/cli-linux-arm64-musl' : '@rskim/cli-linux-arm64',
82
+ 'linux-x64': musl ? '@rskim/cli-linux-x64-musl' : '@rskim/cli-linux-x64',
83
+ 'win32-x64': '@rskim/cli-win32-x64',
84
+ };
85
+
86
+ const key = `${platform}-${arch}`;
87
+ return packages[key];
88
+ }
89
+
90
+ /**
91
+ * Find installed platform package binary using walktree algorithm.
92
+ *
93
+ * Walks up the directory tree looking for node_modules containing the platform package.
94
+ * This approach is package-manager agnostic and works with npm, pnpm, yarn (classic & berry),
95
+ * bun, and arbitrary monorepo nesting depths.
96
+ */
97
+ function findPlatformBinary(packageName) {
98
+ if (!packageName) {
99
+ return null;
100
+ }
101
+
102
+ const binaryName = process.platform === 'win32' ? 'skim.exe' : 'skim';
103
+ let currentDir = __dirname;
104
+
105
+ // Walk up the directory tree looking for node_modules
106
+ for (let i = 0; i < 10; i++) {
107
+ const candidate = path.join(currentDir, 'node_modules', packageName, binaryName);
108
+ if (fs.existsSync(candidate)) {
109
+ return candidate;
110
+ }
111
+ const parent = path.dirname(currentDir);
112
+ if (parent === currentDir) break; // Hit filesystem root
113
+ currentDir = parent;
114
+ }
115
+
116
+ return null;
117
+ }
118
+
119
+ /**
120
+ * Find fallback binary in local bin directory (from postinstall)
121
+ */
122
+ function findFallbackBinary() {
123
+ const binaryName = process.platform === 'win32' ? 'skim.exe' : 'skim';
124
+ const fallbackPath = path.join(__dirname, binaryName);
125
+
126
+ if (fs.existsSync(fallbackPath)) {
127
+ return fallbackPath;
128
+ }
129
+
130
+ return null;
131
+ }
132
+
133
+ /**
134
+ * Get the binary path, with helpful error messages
135
+ */
136
+ function getBinaryPath() {
137
+ const platform = process.platform;
138
+ const arch = process.arch;
139
+ const musl = isMusl();
140
+
141
+ // Get the platform-specific package
142
+ const packageName = getPlatformPackage();
143
+
144
+ if (!packageName) {
145
+ console.error(`ERROR: Platform ${platform}-${arch} is not supported.`);
146
+ console.error('');
147
+ console.error('Supported platforms:');
148
+ console.error(' - darwin-arm64 (macOS Apple Silicon)');
149
+ console.error(' - darwin-x64 (macOS Intel)');
150
+ console.error(' - linux-arm64 (Linux ARM64, glibc)');
151
+ console.error(' - linux-arm64-musl (Linux ARM64, Alpine/musl)');
152
+ console.error(' - linux-x64 (Linux x64, glibc)');
153
+ console.error(' - linux-x64-musl (Linux x64, Alpine/musl)');
154
+ console.error(' - win32-x64 (Windows x64)');
155
+ console.error('');
156
+ console.error('Workaround: Install via Cargo instead:');
157
+ console.error(' cargo install rskim');
158
+ console.error('');
159
+ console.error('Report issues: https://github.com/dean0x/skim/issues');
160
+ process.exit(1);
161
+ }
162
+
163
+ // Try to find the platform package binary
164
+ let binaryPath = findPlatformBinary(packageName);
165
+
166
+ // Fallback to local binary (from postinstall)
167
+ if (!binaryPath) {
168
+ binaryPath = findFallbackBinary();
169
+ }
170
+
171
+ if (!binaryPath) {
172
+ console.error(`ERROR: Could not find skim binary.`);
173
+ console.error('');
174
+ console.error(`Expected platform package: ${packageName}`);
175
+ if (musl) {
176
+ console.error('Detected: musl-based Linux (Alpine, Void, etc.)');
177
+ }
178
+ console.error('');
179
+ console.error('The platform-specific package may have failed to install.');
180
+ console.error('This can happen with npm\'s optional dependencies.');
181
+ console.error('');
182
+ console.error('Try reinstalling:');
183
+ console.error(' npm uninstall -g rskim && npm install -g rskim');
184
+ console.error('');
185
+ console.error('Or install via Cargo:');
186
+ console.error(' cargo install rskim');
187
+ console.error('');
188
+ console.error('Report issues: https://github.com/dean0x/skim/issues');
189
+ process.exit(1);
190
+ }
191
+
192
+ // Verify binary is executable
193
+ try {
194
+ const testResult = spawnSync(binaryPath, ['--version'], {
195
+ timeout: 5000,
196
+ stdio: 'pipe',
197
+ });
198
+
199
+ if (testResult.error) {
200
+ const errorMsg = testResult.error.message || '';
201
+
202
+ console.error('ERROR: Binary exists but cannot be executed.');
203
+ console.error(`Path: ${binaryPath}`);
204
+ console.error(`Error: ${errorMsg}`);
205
+ console.error('');
206
+
207
+ if (errorMsg.includes('ENOENT') || errorMsg.includes('libc') || errorMsg.includes('GLIBC')) {
208
+ console.error('This appears to be a C library compatibility issue.');
209
+ if (musl) {
210
+ console.error('You are on musl-based Linux but may have a glibc binary.');
211
+ } else {
212
+ console.error('You may be on Alpine/musl but have a glibc binary.');
213
+ }
214
+ console.error('');
215
+ console.error('For Alpine Linux:');
216
+ console.error(' apk add cargo');
217
+ console.error(' cargo install rskim');
218
+ } else {
219
+ console.error('Workaround: Install via Cargo:');
220
+ console.error(' cargo install rskim');
221
+ }
222
+ console.error('');
223
+ console.error('Report issues: https://github.com/dean0x/skim/issues');
224
+ process.exit(1);
225
+ }
226
+ } catch {
227
+ // Non-fatal, proceed with execution
228
+ }
229
+
230
+ return binaryPath;
231
+ }
232
+
233
+ // Main execution
234
+ const binaryPath = getBinaryPath();
235
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
236
+ stdio: 'inherit',
237
+ });
238
+
239
+ if (result.error) {
240
+ console.error(`ERROR: Failed to execute skim: ${result.error.message}`);
241
+ process.exit(1);
242
+ }
243
+
244
+ process.exit(result.status || 0);
package/package.json CHANGED
@@ -1,14 +1,7 @@
1
1
  {
2
2
  "name": "rskim",
3
- "version": "0.7.0",
3
+ "version": "0.9.4",
4
4
  "description": "Smart code reader - streaming code transformation for AI agents",
5
- "bin": {
6
- "skim": "./bin/skim.js"
7
- },
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/dean0x/skim.git"
11
- },
12
5
  "keywords": [
13
6
  "code",
14
7
  "ast",
@@ -18,17 +11,35 @@
18
11
  ],
19
12
  "author": "Skim Contributors",
20
13
  "license": "MIT",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/dean0x/skim.git"
17
+ },
21
18
  "bugs": {
22
19
  "url": "https://github.com/dean0x/skim/issues"
23
20
  },
24
21
  "homepage": "https://github.com/dean0x/skim#readme",
25
- "os": [
26
- "darwin",
27
- "linux",
28
- "win32"
22
+ "bin": {
23
+ "skim": "bin/skim",
24
+ "rskim": "bin/skim"
25
+ },
26
+ "files": [
27
+ "bin",
28
+ "scripts"
29
29
  ],
30
- "cpu": [
31
- "x64",
32
- "arm64"
33
- ]
30
+ "scripts": {
31
+ "postinstall": "node scripts/postinstall.js"
32
+ },
33
+ "engines": {
34
+ "node": ">=16"
35
+ },
36
+ "optionalDependencies": {
37
+ "@rskim/cli-darwin-arm64": "0.9.4",
38
+ "@rskim/cli-darwin-x64": "0.9.4",
39
+ "@rskim/cli-linux-arm64": "0.9.4",
40
+ "@rskim/cli-linux-x64": "0.9.4",
41
+ "@rskim/cli-linux-arm64-musl": "0.9.4",
42
+ "@rskim/cli-linux-x64-musl": "0.9.4",
43
+ "@rskim/cli-win32-x64": "0.9.4"
44
+ }
34
45
  }
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Postinstall script for rskim npm package.
4
+ *
5
+ * This script runs after `npm install` to ensure the binary is available.
6
+ * It downloads the platform-specific binary as a fallback if the optional
7
+ * dependency failed to install (common with npm's optional deps).
8
+ *
9
+ * IMPORTANT: This script only uses Node.js built-in modules (no dependencies).
10
+ */
11
+ const { execSync, spawn } = require('child_process');
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const https = require('https');
15
+ const os = require('os');
16
+
17
+ /**
18
+ * Detect if running on musl-based Linux
19
+ *
20
+ * ARCHITECTURE NOTE: This function is intentionally duplicated in bin/skim.
21
+ * Postinstall scripts run before node_modules is fully available, so this script
22
+ * must be self-contained with no external dependencies. Do not extract to a shared
23
+ * module - it would break postinstall execution.
24
+ */
25
+ function isMusl() {
26
+ if (process.platform !== 'linux') {
27
+ return false;
28
+ }
29
+
30
+ try {
31
+ const osRelease = fs.readFileSync('/etc/os-release', 'utf8');
32
+ if (osRelease.includes('Alpine')) {
33
+ return true;
34
+ }
35
+ } catch {
36
+ // Continue checking
37
+ }
38
+
39
+ try {
40
+ const lddOutput = execSync('ldd --version 2>&1 || true', { encoding: 'utf8' });
41
+ if (lddOutput.includes('musl')) {
42
+ return true;
43
+ }
44
+ } catch {
45
+ // Continue checking
46
+ }
47
+
48
+ try {
49
+ const files = fs.readdirSync('/lib');
50
+ if (files.some(f => f.startsWith('ld-musl'))) {
51
+ return true;
52
+ }
53
+ } catch {
54
+ // Not musl
55
+ }
56
+
57
+ return false;
58
+ }
59
+
60
+ /**
61
+ * Get platform-specific package name
62
+ */
63
+ function getPlatformPackage() {
64
+ const platform = process.platform;
65
+ const arch = process.arch;
66
+ const musl = isMusl();
67
+
68
+ const packages = {
69
+ 'darwin-arm64': '@rskim/cli-darwin-arm64',
70
+ 'darwin-x64': '@rskim/cli-darwin-x64',
71
+ 'linux-arm64': musl ? '@rskim/cli-linux-arm64-musl' : '@rskim/cli-linux-arm64',
72
+ 'linux-x64': musl ? '@rskim/cli-linux-x64-musl' : '@rskim/cli-linux-x64',
73
+ 'win32-x64': '@rskim/cli-win32-x64',
74
+ };
75
+
76
+ return packages[`${platform}-${arch}`];
77
+ }
78
+
79
+ /**
80
+ * Check if platform package is already installed using walktree algorithm.
81
+ *
82
+ * Walks up the directory tree looking for node_modules containing the platform package.
83
+ * This approach is package-manager agnostic and works with npm, pnpm, yarn (classic & berry),
84
+ * bun, and arbitrary monorepo nesting depths.
85
+ */
86
+ function isPlatformPackageInstalled(packageName) {
87
+ const binaryName = process.platform === 'win32' ? 'skim.exe' : 'skim';
88
+ let currentDir = __dirname;
89
+
90
+ // Walk up the directory tree looking for node_modules
91
+ for (let i = 0; i < 10; i++) {
92
+ const candidate = path.join(currentDir, 'node_modules', packageName, binaryName);
93
+ if (fs.existsSync(candidate)) {
94
+ return true;
95
+ }
96
+ const parent = path.dirname(currentDir);
97
+ if (parent === currentDir) break; // Hit filesystem root
98
+ currentDir = parent;
99
+ }
100
+
101
+ return false;
102
+ }
103
+
104
+ /**
105
+ * Check if fallback binary already exists
106
+ */
107
+ function isFallbackInstalled() {
108
+ const binaryName = process.platform === 'win32' ? 'skim.exe' : 'skim';
109
+ const fallbackPath = path.join(__dirname, '..', 'bin', binaryName);
110
+ return fs.existsSync(fallbackPath);
111
+ }
112
+
113
+ /**
114
+ * Trusted domains for redirect validation.
115
+ * Only follow redirects to these domains to prevent redirect attacks.
116
+ */
117
+ const TRUSTED_DOMAINS = [
118
+ 'registry.npmjs.org',
119
+ 'registry.yarnpkg.com',
120
+ 'registry.npmmirror.com',
121
+ ];
122
+
123
+ /**
124
+ * Validate that a URL is within trusted domains
125
+ */
126
+ function isUrlTrusted(urlString) {
127
+ try {
128
+ const url = new URL(urlString);
129
+ return TRUSTED_DOMAINS.some(domain => url.hostname === domain || url.hostname.endsWith('.' + domain));
130
+ } catch {
131
+ return false;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Download file with redirect handling
137
+ */
138
+ function downloadToFile(url, destPath, maxRedirects = 5) {
139
+ return new Promise((resolve, reject) => {
140
+ if (maxRedirects <= 0) {
141
+ reject(new Error('Too many redirects'));
142
+ return;
143
+ }
144
+
145
+ const file = fs.createWriteStream(destPath);
146
+
147
+ https.get(url, (response) => {
148
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
149
+ file.close();
150
+ fs.unlinkSync(destPath);
151
+
152
+ // Validate redirect URL stays within trusted domains
153
+ const redirectUrl = response.headers.location;
154
+ if (!isUrlTrusted(redirectUrl)) {
155
+ reject(new Error(`Redirect to untrusted domain blocked: ${redirectUrl}`));
156
+ return;
157
+ }
158
+
159
+ downloadToFile(redirectUrl, destPath, maxRedirects - 1)
160
+ .then(resolve)
161
+ .catch(reject);
162
+ return;
163
+ }
164
+
165
+ if (response.statusCode !== 200) {
166
+ file.close();
167
+ fs.unlinkSync(destPath);
168
+ reject(new Error(`HTTP ${response.statusCode}: ${url}`));
169
+ return;
170
+ }
171
+
172
+ response.pipe(file);
173
+ file.on('finish', () => {
174
+ file.close();
175
+ resolve();
176
+ });
177
+ file.on('error', (err) => {
178
+ file.close();
179
+ fs.unlinkSync(destPath);
180
+ reject(err);
181
+ });
182
+ }).on('error', (err) => {
183
+ file.close();
184
+ try { fs.unlinkSync(destPath); } catch {}
185
+ reject(err);
186
+ });
187
+ });
188
+ }
189
+
190
+ /**
191
+ * Get the npm registry tarball URL for a package
192
+ * Uses the abbreviated metadata endpoint (/{package}/{version}) for efficiency.
193
+ */
194
+ async function getPackageTarballUrl(packageName, version) {
195
+ return new Promise((resolve, reject) => {
196
+ // Use abbreviated metadata endpoint - returns only the specific version data
197
+ const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/${encodeURIComponent(version)}`;
198
+
199
+ https.get(url, (response) => {
200
+ if (response.statusCode !== 200) {
201
+ reject(new Error(`Failed to fetch package info: HTTP ${response.statusCode}`));
202
+ return;
203
+ }
204
+
205
+ let data = '';
206
+ response.on('data', chunk => data += chunk);
207
+ response.on('end', () => {
208
+ try {
209
+ const versionData = JSON.parse(data);
210
+ if (!versionData.dist || !versionData.dist.tarball) {
211
+ reject(new Error(`Tarball URL not found for ${packageName}@${version}`));
212
+ return;
213
+ }
214
+ resolve(versionData.dist.tarball);
215
+ } catch (e) {
216
+ reject(new Error(`Failed to parse package info: ${e.message}`));
217
+ }
218
+ });
219
+ }).on('error', reject);
220
+ });
221
+ }
222
+
223
+ /**
224
+ * Extract binary from npm tarball using system tar command
225
+ */
226
+ async function extractBinaryFromTarball(tarballUrl, destPath) {
227
+ const binaryName = process.platform === 'win32' ? 'skim.exe' : 'skim';
228
+
229
+ // Create a temporary directory for extraction
230
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rskim-'));
231
+ const tarballPath = path.join(tempDir, 'package.tgz');
232
+
233
+ try {
234
+ // Download the tarball
235
+ await downloadToFile(tarballUrl, tarballPath);
236
+
237
+ // Extract using system tar command
238
+ // The tarball contains: package/<binaryName>
239
+ await new Promise((resolve, reject) => {
240
+ const tarArgs = ['-xzf', tarballPath, '-C', tempDir];
241
+ const tar = spawn('tar', tarArgs, { stdio: 'inherit' });
242
+ tar.on('close', (code) => {
243
+ if (code === 0) {
244
+ resolve();
245
+ } else {
246
+ reject(new Error(`tar exited with code ${code}`));
247
+ }
248
+ });
249
+ tar.on('error', reject);
250
+ });
251
+
252
+ // Find the extracted binary (it will be in package/<binaryName>)
253
+ const extractedBinary = path.join(tempDir, 'package', binaryName);
254
+ if (!fs.existsSync(extractedBinary)) {
255
+ throw new Error(`Binary not found in tarball: ${binaryName}`);
256
+ }
257
+
258
+ // Ensure destination directory exists
259
+ const destDir = path.dirname(destPath);
260
+ if (!fs.existsSync(destDir)) {
261
+ fs.mkdirSync(destDir, { recursive: true });
262
+ }
263
+
264
+ // Copy to destination
265
+ fs.copyFileSync(extractedBinary, destPath);
266
+
267
+ // Make executable (Unix only)
268
+ if (process.platform !== 'win32') {
269
+ fs.chmodSync(destPath, 0o755);
270
+ }
271
+ } finally {
272
+ // Cleanup temp directory
273
+ try {
274
+ fs.rmSync(tempDir, { recursive: true, force: true });
275
+ } catch {
276
+ // Ignore cleanup errors
277
+ }
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Main postinstall logic
283
+ */
284
+ async function main() {
285
+ const packageName = getPlatformPackage();
286
+
287
+ if (!packageName) {
288
+ // Unsupported platform, wrapper will show error at runtime
289
+ return;
290
+ }
291
+
292
+ // Check if platform package is already installed
293
+ if (isPlatformPackageInstalled(packageName)) {
294
+ // Already installed via optional dependency
295
+ return;
296
+ }
297
+
298
+ // Check if fallback binary already exists
299
+ if (isFallbackInstalled()) {
300
+ return;
301
+ }
302
+
303
+ // Read our version from package.json
304
+ const pkgJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
305
+ const version = pkgJson.version;
306
+
307
+ console.log(`rskim: Downloading ${packageName}@${version}...`);
308
+
309
+ try {
310
+ const tarballUrl = await getPackageTarballUrl(packageName, version);
311
+ const binaryName = process.platform === 'win32' ? 'skim.exe' : 'skim';
312
+ const destPath = path.join(__dirname, '..', 'bin', binaryName);
313
+
314
+ await extractBinaryFromTarball(tarballUrl, destPath);
315
+ console.log('rskim: Binary downloaded successfully');
316
+ } catch (error) {
317
+ // Non-fatal - wrapper will show helpful error at runtime
318
+ console.warn(`rskim: Failed to download binary: ${error.message}`);
319
+ console.warn('rskim: You may need to install via: cargo install rskim');
320
+ }
321
+ }
322
+
323
+ // Run main and handle errors gracefully
324
+ main().catch(error => {
325
+ // Non-fatal - wrapper will handle missing binary
326
+ console.warn(`rskim postinstall: ${error.message}`);
327
+ });
Binary file
Binary file
Binary file
Binary file
package/bin/skim.js DELETED
@@ -1,93 +0,0 @@
1
- #!/usr/bin/env node
2
- const { spawnSync } = require('child_process');
3
- const path = require('path');
4
- const fs = require('fs');
5
-
6
- function getBinaryPath() {
7
- const platform = process.platform;
8
- const arch = process.arch;
9
-
10
- // Define supported platforms and their binary paths
11
- const supportedPlatforms = {
12
- 'linux-x64': 'bin/linux/x64/skim',
13
- 'linux-arm64': 'bin/linux/arm64/skim',
14
- 'darwin-x64': 'bin/darwin/x64/skim',
15
- 'darwin-arm64': 'bin/darwin/arm64/skim',
16
- 'win32-x64': 'bin/win32/x64/skim.exe',
17
- };
18
-
19
- const platformKey = `${platform}-${arch}`;
20
- const binaryRelativePath = supportedPlatforms[platformKey];
21
-
22
- // Check if platform is supported
23
- if (!binaryRelativePath) {
24
- console.error(`ERROR: Platform ${platform}-${arch} is not supported by the npm package.`);
25
- console.error('');
26
- console.error('Supported platforms:');
27
- Object.keys(supportedPlatforms).forEach(p => {
28
- console.error(` - ${p}`);
29
- });
30
- console.error('');
31
- console.error('Workaround: Install via Cargo instead:');
32
- console.error(' cargo install rskim');
33
- console.error('');
34
- console.error('If you believe this platform should be supported, please report:');
35
- console.error(' https://github.com/dean0x/skim/issues');
36
- process.exit(1);
37
- }
38
-
39
- // Check if binary exists in package
40
- const binaryPath = path.join(__dirname, '..', binaryRelativePath);
41
- if (!fs.existsSync(binaryPath)) {
42
- console.error('ERROR: Binary missing from npm package');
43
- console.error(`Expected location: ${binaryPath}`);
44
- console.error(`Platform: ${platformKey}`);
45
- console.error('');
46
- console.error('This is a packaging bug. Please report:');
47
- console.error(' https://github.com/dean0x/skim/issues');
48
- console.error('');
49
- console.error('Workaround: Install via Cargo instead:');
50
- console.error(' cargo install rskim');
51
- process.exit(1);
52
- }
53
-
54
- // Quick check if binary is executable (catches glibc/musl issues)
55
- try {
56
- const testResult = spawnSync(binaryPath, ['--version'], {
57
- timeout: 5000,
58
- stdio: 'pipe'
59
- });
60
-
61
- if (testResult.error) {
62
- console.error('ERROR: Binary exists but cannot be executed');
63
- console.error(`Reason: ${testResult.error.message}`);
64
- console.error('');
65
-
66
- if (testResult.error.code === 'ENOENT' || testResult.error.message.includes('libc')) {
67
- console.error('This may be a C library incompatibility issue.');
68
- console.error('Common cause: Alpine Linux (musl) vs glibc binary mismatch');
69
- console.error('');
70
- console.error('If you are using Alpine Linux, install via Cargo instead:');
71
- console.error(' apk add cargo');
72
- console.error(' cargo install rskim');
73
- } else {
74
- console.error('Workaround: Install via Cargo instead:');
75
- console.error(' cargo install rskim');
76
- }
77
- console.error('');
78
- console.error('For more help, see: https://github.com/dean0x/skim/issues');
79
- process.exit(1);
80
- }
81
- } catch (e) {
82
- // Non-fatal, just proceed
83
- }
84
-
85
- return binaryPath;
86
- }
87
-
88
- const binary = getBinaryPath();
89
- const result = spawnSync(binary, process.argv.slice(2), {
90
- stdio: 'inherit',
91
- });
92
-
93
- process.exit(result.status || 0);
Binary file