keyspy 1.0.4 → 1.0.6
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 +74 -94
- package/package.json +9 -8
- package/scripts/download-binaries.js +79 -79
package/README.md
CHANGED
@@ -1,19 +1,43 @@
|
|
1
|
-
#
|
1
|
+
# keyspy 🕵️
|
2
2
|
|
3
3
|
> A powerful, cross-platform keyboard and mouse event listener for Node.js
|
4
4
|
|
5
|
-
|
5
|
+
keyspy is a modern, lightweight library that provides global keyboard and mouse event monitoring across Windows, macOS, and Linux. Unlike other solutions, keyspy uses pre-compiled native binaries and a multi-process architecture for maximum stability and compatibility.
|
6
|
+
|
7
|
+
## 🤔 Why keyspy?
|
8
|
+
|
9
|
+
Choosing the right keyboard listener for your Node.js project can be challenging. Here's how keyspy compares to other popular solutions:
|
10
|
+
|
11
|
+
| Feature | Electron globalShortcut | IOHook | **keyspy** |
|
12
|
+
|---------|-------------------------|---------|------------|
|
13
|
+
| **Zero compilation** | ❌ Electron required | ❌ node-gyp required | ✅ Pre-compiled binaries |
|
14
|
+
| **Package size** | 🟡 Large (Electron) | 🟡 Medium | ✅ Small (on-demand download) |
|
15
|
+
| **System shortcuts** | ✅ Yes | ✅ Yes | ✅ Yes |
|
16
|
+
| **Event blocking** | ✅ Yes | ✅ Yes | ✅ Yes |
|
17
|
+
| **Cross-platform** | ✅ Yes | ✅ Yes | ✅ Yes |
|
18
|
+
| **TypeScript** | ✅ Built-in | 🟡 Community types | ✅ Built-in |
|
19
|
+
| **Stability** | ✅ Very stable | 🟡 Can crash Node.js | ✅ Multi-process isolation |
|
20
|
+
|
21
|
+
### 🎯 **keyspy Advantages**
|
22
|
+
|
23
|
+
- **🚀 Zero Setup**: Pre-compiled binaries downloaded automatically, no compilation required
|
24
|
+
- **📦 Smaller Package**: Binaries downloaded on-demand (not bundled), reducing package size by ~90%
|
25
|
+
- **📱 Universal macOS**: ARM64 + x86_64 universal binaries for all Apple Silicon and Intel Macs
|
26
|
+
- **🔄 Modern Stack**: TypeScript, automated testing, and modern development tools
|
27
|
+
- **🏗️ Automated Releases**: GitHub Actions handle cross-platform compilation and publishing
|
28
|
+
- **🛡️ Stable Architecture**: Multi-process design prevents Node.js crashes
|
29
|
+
- **⚡ High Performance**: Optimized native implementations for each platform
|
30
|
+
|
31
|
+
> **📚 Project Origin**: keyspy is a modernized version of [node-global-key-listener](https://github.com/LaunchMenu/node-global-key-listener), rebuilt with modern tooling and enhanced features.
|
6
32
|
|
7
33
|
## ✨ Features
|
8
34
|
|
9
|
-
- 🌍 **Cross-platform**:
|
10
|
-
-
|
11
|
-
- 🔒 **System-level capture**: Can intercept system shortcuts like Ctrl+Alt+Delete, Cmd+Space
|
35
|
+
- 🌍 **Cross-platform**: Windows, macOS, and Linux (X11) support
|
36
|
+
- 🔒 **System-level capture**: Intercept any key combination, including OS shortcuts
|
12
37
|
- 🎯 **Event blocking**: Prevent captured events from reaching other applications
|
13
|
-
- 📦 **TypeScript ready**: Full
|
14
|
-
-
|
38
|
+
- 📦 **TypeScript ready**: Full type definitions included
|
39
|
+
- 🛡️ **Stable architecture**: Multi-process design prevents crashes
|
15
40
|
- ⚡ **High performance**: Optimized native implementations for each platform
|
16
|
-
- 📥 **Smart installation**: Automatically downloads platform-specific binaries from GitHub Releases
|
17
41
|
|
18
42
|
## 🔧 Platform Support
|
19
43
|
|
@@ -106,89 +130,69 @@ keyspy.kill(); // Removes all listeners and stops the key server
|
|
106
130
|
```bash
|
107
131
|
npm install keyspy
|
108
132
|
# or
|
109
|
-
pnpm add keyspy
|
110
|
-
# or
|
111
133
|
yarn add keyspy
|
112
134
|
```
|
113
135
|
|
114
|
-
|
115
|
-
1. 📦 Downloads the main package (TypeScript code)
|
116
|
-
2. 🔍 Detects your platform (Windows/macOS/Linux) and architecture
|
117
|
-
3. 📥 Automatically downloads the appropriate pre-compiled binary from GitHub Releases
|
118
|
-
4. ✅ Ready to use immediately!
|
136
|
+
The package automatically detects your platform and downloads the appropriate pre-compiled binary during installation. No compilation required!
|
119
137
|
|
120
|
-
## 🤔 Why KeySpy?
|
121
138
|
|
122
|
-
Choosing the right keyboard listener for your Node.js project can be challenging. Here's how KeySpy compares to other popular solutions:
|
123
|
-
|
124
|
-
| Feature | Electron globalShortcut | IOHook | **KeySpy** |
|
125
|
-
|---------|------------------------|--------|------------|
|
126
|
-
| **Setup Complexity** | Simple | Complex (node-gyp) | **Simple** |
|
127
|
-
| **System Shortcuts** | ❌ Limited | ✅ Full | **✅ Full** |
|
128
|
-
| **Event Blocking** | ❌ No | ✅ Yes | **✅ Yes** |
|
129
|
-
| **Node.js Compatibility** | ❌ Electron only | ⚠️ Version dependent | **✅ All versions** |
|
130
|
-
| **Compilation Required** | ❌ No | ❌ Yes | **✅ No** |
|
131
|
-
| **Arbitrary Key Support** | ❌ Limited | ⚠️ Limited | **✅ Full** |
|
132
|
-
| **Process Architecture** | In-process | In-process | **Multi-process** |
|
133
|
-
|
134
|
-
### 🎯 **KeySpy Advantages**
|
135
|
-
|
136
|
-
- **🔧 Zero Setup**: Pre-compiled binaries work out of the box
|
137
|
-
- **🌐 Universal**: Compatible with all Node.js versions (14+)
|
138
|
-
- **🔒 System-Level**: Capture any key combination, including OS shortcuts
|
139
|
-
- **🛡️ Stable**: Multi-process architecture prevents crashes
|
140
|
-
- **📝 TypeScript**: Full type definitions included
|
141
|
-
- **🎮 Flexible**: Listen to individual keys or complex combinations
|
142
|
-
|
143
|
-
### ⚠️ **Considerations**
|
144
|
-
|
145
|
-
- **Permissions**: macOS requires Accessibility permissions
|
146
|
-
- **Antivirus**: Some antivirus software may flag the native binaries
|
147
|
-
- **Performance**: Small overhead due to inter-process communication
|
148
139
|
|
149
140
|
## 🛠️ Development
|
150
141
|
|
151
|
-
### Quick Development Setup
|
152
|
-
|
153
142
|
```bash
|
154
143
|
# Clone and setup
|
155
144
|
git clone https://github.com/teomyth/keyspy.git
|
156
145
|
cd keyspy
|
157
|
-
|
146
|
+
npm install
|
147
|
+
|
148
|
+
# Build native binary for development
|
149
|
+
npm run build:native
|
158
150
|
|
159
|
-
# Development
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
151
|
+
# Development commands
|
152
|
+
npm run dev # TypeScript watch mode
|
153
|
+
npm run build # Production build
|
154
|
+
npm test # Run all tests
|
155
|
+
npm run test:manual # Interactive testing
|
164
156
|
```
|
165
157
|
|
166
158
|
### Building Native Binaries
|
167
159
|
|
168
|
-
|
160
|
+
For development, you can rebuild the native binaries:
|
169
161
|
|
170
162
|
```bash
|
171
|
-
#
|
172
|
-
|
173
|
-
|
174
|
-
|
163
|
+
# Auto-detect your platform
|
164
|
+
npm run build:native
|
165
|
+
|
166
|
+
# Force specific platform
|
167
|
+
npm run build:native -- --platform darwin # macOS (requires Xcode)
|
168
|
+
npm run build:native -- --platform linux # Linux (requires X11 dev libraries)
|
169
|
+
npm run build:native -- --platform win32 # Windows (requires MinGW)
|
170
|
+
|
171
|
+
# Show detailed build output
|
172
|
+
npm run build:native -- --verbose
|
175
173
|
```
|
176
174
|
|
177
175
|
### Code Quality
|
178
176
|
|
179
177
|
```bash
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
178
|
+
npm run lint # Check code quality with Biome
|
179
|
+
npm run lint:fix # Auto-fix issues
|
180
|
+
npm run format # Format code
|
181
|
+
npm run clean # Remove build artifacts
|
182
|
+
|
183
|
+
# Release management
|
184
|
+
npm run release:patch # Bump patch version (1.0.0 → 1.0.1)
|
185
|
+
npm run release:minor # Bump minor version (1.0.0 → 1.1.0)
|
186
|
+
npm run release:major # Bump major version (1.0.0 → 2.0.0)
|
187
|
+
npm run release:dry # Preview release without publishing
|
184
188
|
```
|
185
189
|
|
186
190
|
### Testing
|
187
191
|
|
188
192
|
```bash
|
189
|
-
|
190
|
-
|
191
|
-
|
193
|
+
npm run test:unit # Unit tests
|
194
|
+
npm run test:integration # Integration tests
|
195
|
+
npm run test:manual # Manual interactive testing
|
192
196
|
```
|
193
197
|
|
194
198
|
## 📋 API Reference
|
@@ -236,36 +240,17 @@ interface IGlobalKeyEvent {
|
|
236
240
|
|
237
241
|
## 🔧 Troubleshooting
|
238
242
|
|
239
|
-
###
|
240
|
-
|
241
|
-
If the automatic binary download fails during installation:
|
242
|
-
|
243
|
-
```bash
|
244
|
-
# Option 1: Manual download from GitHub Releases
|
245
|
-
# Visit: https://github.com/teomyth/keyspy/releases
|
246
|
-
# Download the appropriate file for your platform
|
247
|
-
|
248
|
-
# Option 2: Build from source
|
249
|
-
npm run build:swift # macOS
|
250
|
-
npm run build:x11 # Linux
|
251
|
-
npm run build:win # Windows
|
252
|
-
|
253
|
-
# Option 3: Skip download in CI environments
|
254
|
-
export KEYSPY_SKIP_DOWNLOAD=true
|
255
|
-
npm install keyspy
|
256
|
-
```
|
243
|
+
### Common Issues
|
257
244
|
|
258
|
-
|
245
|
+
1. **Binary download fails**: Visit [GitHub Releases](https://github.com/teomyth/keyspy/releases) to download manually, or build from source with `npm run build:native`
|
246
|
+
2. **Permission denied**: Make sure the binary has execute permissions (`chmod +x bin/*`)
|
247
|
+
3. **CI environments**: Set `KEYSPY_SKIP_DOWNLOAD=true` to skip binary download
|
259
248
|
|
260
|
-
|
261
|
-
- **Linux**: x64 only, requires X11
|
262
|
-
- **Windows**: x64 only
|
249
|
+
### Platform Requirements
|
263
250
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
2. **Permission denied**: Make sure the binary has execute permissions (`chmod +x`)
|
268
|
-
3. **Network issues**: Check your internet connection and GitHub access
|
251
|
+
- **macOS**: macOS 10.14+, supports both Intel and Apple Silicon
|
252
|
+
- **Linux**: X11 display server, x64 architecture
|
253
|
+
- **Windows**: Windows 10+, x64 architecture
|
269
254
|
|
270
255
|
## 🤝 Contributing
|
271
256
|
|
@@ -280,8 +265,3 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
|
|
280
265
|
## 📄 License
|
281
266
|
|
282
267
|
MIT License - see [LICENSE](LICENSE) file for details.
|
283
|
-
|
284
|
-
## 🙏 Acknowledgments
|
285
|
-
|
286
|
-
- Original concept inspired by [LaunchMenu](https://github.com/LaunchMenu/LaunchMenu)
|
287
|
-
- Built with modern tooling: TypeScript, Biome, Jest, and Turbo
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "keyspy",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.6",
|
4
4
|
"description": "A cross-platform global keyboard and mouse listener for Node.js",
|
5
5
|
"types": "build/index.d.ts",
|
6
6
|
"main": "build/index.js",
|
@@ -13,28 +13,29 @@
|
|
13
13
|
"engines": {
|
14
14
|
"node": ">=14.0.0"
|
15
15
|
},
|
16
|
-
"packageManager": "pnpm@8.0.0",
|
17
16
|
"scripts": {
|
18
17
|
"dev": "tsc --watch",
|
19
18
|
"build": "tsc",
|
20
19
|
"postinstall": "node scripts/download-binaries.js",
|
21
|
-
"build:
|
22
|
-
"build:mac": "mkdir -p bin && swiftc src/bin/MacKeyServer/main.swift -o bin/MacKeyServer",
|
23
|
-
"build:win": ".\\scripts\\compile-win.bat",
|
24
|
-
"build:x11": "scripts/compile-x11.sh",
|
20
|
+
"build:native": "node scripts/build-native.js",
|
25
21
|
"test": "jest",
|
26
22
|
"test:unit": "jest tests/unit",
|
27
23
|
"test:integration": "jest tests/integration",
|
24
|
+
"test:coverage": "jest --coverage",
|
25
|
+
"test:watch": "jest --watch",
|
28
26
|
"test:manual": "npx ts-node examples/manual-test.ts",
|
29
27
|
"lint": "biome lint .",
|
30
28
|
"lint:fix": "biome lint --write .",
|
31
29
|
"format": "biome format --write .",
|
32
30
|
"format:check": "biome format .",
|
33
|
-
"clean": "rm -rf build dist coverage test-
|
31
|
+
"clean": "rm -rf build dist coverage test-results .turbo",
|
34
32
|
"prepare": "npm run build",
|
35
33
|
"prepublishOnly": "npm run build && npm run test",
|
36
34
|
"release": "release-it",
|
37
|
-
"release:dry": "release-it --dry-run"
|
35
|
+
"release:dry": "release-it --dry-run",
|
36
|
+
"release:patch": "release-it patch",
|
37
|
+
"release:minor": "release-it minor",
|
38
|
+
"release:major": "release-it major"
|
38
39
|
},
|
39
40
|
"repository": {
|
40
41
|
"type": "git",
|
@@ -1,11 +1,11 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
2
|
|
3
|
-
const fs = require(
|
4
|
-
const path = require(
|
5
|
-
const https = require(
|
6
|
-
const { execSync } = require(
|
3
|
+
const fs = require("node:fs");
|
4
|
+
const path = require("node:path");
|
5
|
+
const https = require("node:https");
|
6
|
+
const { execSync } = require("node:child_process");
|
7
7
|
|
8
|
-
const packageJson = require(
|
8
|
+
const packageJson = require("../package.json");
|
9
9
|
const version = packageJson.version;
|
10
10
|
|
11
11
|
// Platform detection
|
@@ -14,16 +14,16 @@ const arch = process.arch;
|
|
14
14
|
|
15
15
|
// Binary mapping
|
16
16
|
const binaryMap = {
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
darwin: {
|
18
|
+
arm64: { file: "MacKeyServer", archive: "keyspy-darwin-arm64.tar.gz" },
|
19
|
+
x64: { file: "MacKeyServer", archive: "keyspy-darwin-x64.tar.gz" },
|
20
20
|
},
|
21
|
-
|
22
|
-
|
21
|
+
linux: {
|
22
|
+
x64: { file: "X11KeyServer", archive: "keyspy-linux-x64.tar.gz" },
|
23
|
+
},
|
24
|
+
win32: {
|
25
|
+
x64: { file: "WinKeyServer.exe", archive: "keyspy-win32-x64.tar.gz" },
|
23
26
|
},
|
24
|
-
'win32': {
|
25
|
-
'x64': { file: 'WinKeyServer.exe', archive: 'keyspy-win32-x64.tar.gz' }
|
26
|
-
}
|
27
27
|
};
|
28
28
|
|
29
29
|
function log(message) {
|
@@ -39,56 +39,58 @@ function getPlatformInfo() {
|
|
39
39
|
if (!platformInfo) {
|
40
40
|
throw new Error(`Unsupported platform: ${platform}`);
|
41
41
|
}
|
42
|
-
|
42
|
+
|
43
43
|
const archInfo = platformInfo[arch];
|
44
44
|
if (!archInfo) {
|
45
45
|
throw new Error(`Unsupported architecture: ${arch} on ${platform}`);
|
46
46
|
}
|
47
|
-
|
47
|
+
|
48
48
|
return archInfo;
|
49
49
|
}
|
50
50
|
|
51
51
|
function downloadFile(url, dest) {
|
52
52
|
return new Promise((resolve, reject) => {
|
53
53
|
log(`Downloading ${url}`);
|
54
|
-
|
54
|
+
|
55
55
|
const file = fs.createWriteStream(dest);
|
56
|
-
|
57
|
-
https
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
file.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
56
|
+
|
57
|
+
https
|
58
|
+
.get(url, (response) => {
|
59
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
60
|
+
// Handle redirect
|
61
|
+
return downloadFile(response.headers.location, dest).then(resolve).catch(reject);
|
62
|
+
}
|
63
|
+
|
64
|
+
if (response.statusCode !== 200) {
|
65
|
+
reject(new Error(`Download failed with status ${response.statusCode}`));
|
66
|
+
return;
|
67
|
+
}
|
68
|
+
|
69
|
+
response.pipe(file);
|
70
|
+
|
71
|
+
file.on("finish", () => {
|
72
|
+
file.close();
|
73
|
+
resolve();
|
74
|
+
});
|
75
|
+
|
76
|
+
file.on("error", (err) => {
|
77
|
+
fs.unlink(dest, () => {
|
78
|
+
// Ignore unlink errors - file cleanup is best effort
|
79
|
+
}); // Delete partial file
|
80
|
+
reject(err);
|
81
|
+
});
|
82
|
+
})
|
83
|
+
.on("error", reject);
|
82
84
|
});
|
83
85
|
}
|
84
86
|
|
85
87
|
function extractTarGz(archivePath, extractDir) {
|
86
88
|
try {
|
87
89
|
// Try using tar command
|
88
|
-
execSync(`tar -xzf "${archivePath}" -C "${extractDir}"`, { stdio:
|
90
|
+
execSync(`tar -xzf "${archivePath}" -C "${extractDir}"`, { stdio: "inherit" });
|
89
91
|
return true;
|
90
92
|
} catch (_err) {
|
91
|
-
log(
|
93
|
+
log("tar command failed, trying alternative extraction...");
|
92
94
|
return false;
|
93
95
|
}
|
94
96
|
}
|
@@ -96,39 +98,39 @@ function extractTarGz(archivePath, extractDir) {
|
|
96
98
|
async function downloadAndExtract() {
|
97
99
|
try {
|
98
100
|
const { file: binaryFile, archive } = getPlatformInfo();
|
99
|
-
|
101
|
+
|
100
102
|
// Create bin directory
|
101
|
-
const binDir = path.join(__dirname,
|
103
|
+
const binDir = path.join(__dirname, "..", "bin");
|
102
104
|
if (!fs.existsSync(binDir)) {
|
103
105
|
fs.mkdirSync(binDir, { recursive: true });
|
104
106
|
}
|
105
|
-
|
107
|
+
|
106
108
|
const binaryPath = path.join(binDir, binaryFile);
|
107
|
-
|
109
|
+
|
108
110
|
// Check if binary already exists
|
109
111
|
if (fs.existsSync(binaryPath)) {
|
110
112
|
log(`Binary already exists: ${binaryPath}`);
|
111
113
|
return;
|
112
114
|
}
|
113
|
-
|
115
|
+
|
114
116
|
// Download URL
|
115
117
|
const downloadUrl = `https://github.com/teomyth/keyspy/releases/download/v${version}/${archive}`;
|
116
118
|
const archivePath = path.join(binDir, archive);
|
117
|
-
|
119
|
+
|
118
120
|
log(`Platform: ${platform}-${arch}`);
|
119
121
|
log(`Binary: ${binaryFile}`);
|
120
|
-
|
122
|
+
|
121
123
|
try {
|
122
124
|
// Download archive
|
123
125
|
await downloadFile(downloadUrl, archivePath);
|
124
126
|
log(`Downloaded: ${archive}`);
|
125
|
-
|
127
|
+
|
126
128
|
// Extract archive
|
127
129
|
if (extractTarGz(archivePath, binDir)) {
|
128
130
|
log(`Extracted: ${archive}`);
|
129
|
-
|
131
|
+
|
130
132
|
// Make binary executable (Unix systems)
|
131
|
-
if (platform !==
|
133
|
+
if (platform !== "win32") {
|
132
134
|
try {
|
133
135
|
fs.chmodSync(binaryPath, 0o755);
|
134
136
|
log(`Made executable: ${binaryFile}`);
|
@@ -136,43 +138,41 @@ async function downloadAndExtract() {
|
|
136
138
|
log(`Warning: Could not make binary executable: ${err.message}`);
|
137
139
|
}
|
138
140
|
}
|
139
|
-
|
141
|
+
|
140
142
|
// Clean up archive
|
141
143
|
fs.unlinkSync(archivePath);
|
142
144
|
log(`Cleaned up: ${archive}`);
|
143
|
-
|
145
|
+
|
144
146
|
log(`✅ Successfully installed binary: ${binaryFile}`);
|
145
147
|
} else {
|
146
|
-
throw new Error(
|
148
|
+
throw new Error("Failed to extract archive");
|
147
149
|
}
|
148
|
-
|
149
150
|
} catch (downloadErr) {
|
150
151
|
error(`Failed to download binary: ${downloadErr.message}`);
|
151
|
-
log(
|
152
|
-
log(
|
153
|
-
log(
|
154
|
-
log(
|
155
|
-
log(
|
156
|
-
log(
|
157
|
-
log(
|
158
|
-
log(
|
159
|
-
log(
|
160
|
-
|
152
|
+
log("");
|
153
|
+
log("📝 Manual installation options:");
|
154
|
+
log("1. Download from: https://github.com/teomyth/keyspy/releases");
|
155
|
+
log("2. Build from source:");
|
156
|
+
log(" - macOS: npm run build:swift");
|
157
|
+
log(" - Linux: npm run build:x11");
|
158
|
+
log(" - Windows: npm run build:win");
|
159
|
+
log("");
|
160
|
+
log("⚠️ keyspy will not work without the platform-specific binary.");
|
161
|
+
|
161
162
|
// Don't fail the installation, just warn
|
162
163
|
process.exit(0);
|
163
164
|
}
|
164
|
-
|
165
165
|
} catch (err) {
|
166
166
|
error(err.message);
|
167
|
-
log(
|
168
|
-
log(
|
169
|
-
log(
|
170
|
-
log(
|
171
|
-
log(
|
172
|
-
log(
|
173
|
-
log(
|
174
|
-
log(
|
175
|
-
|
167
|
+
log("");
|
168
|
+
log("📋 Supported platforms:");
|
169
|
+
log("- macOS (ARM64, x64)");
|
170
|
+
log("- Linux (x64)");
|
171
|
+
log("- Windows (x64)");
|
172
|
+
log("");
|
173
|
+
log("If your platform should be supported, please report this issue:");
|
174
|
+
log("https://github.com/teomyth/keyspy/issues");
|
175
|
+
|
176
176
|
// Don't fail the installation for unsupported platforms
|
177
177
|
process.exit(0);
|
178
178
|
}
|
@@ -180,7 +180,7 @@ async function downloadAndExtract() {
|
|
180
180
|
|
181
181
|
// Skip download in CI environments or if explicitly disabled
|
182
182
|
if (process.env.CI || process.env.KEYSPY_SKIP_DOWNLOAD) {
|
183
|
-
log(
|
183
|
+
log("Skipping binary download (CI environment or explicitly disabled)");
|
184
184
|
process.exit(0);
|
185
185
|
}
|
186
186
|
|