swarmhack-cli 0.1.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/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # @prancer/swarmhack
2
+
3
+ Neural swarm-based penetration testing framework.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @prancer/swarmhack
9
+ ```
10
+
11
+ Or use npx:
12
+
13
+ ```bash
14
+ npx @prancer/swarmhack --help
15
+ ```
16
+
17
+ ## CLI Usage
18
+
19
+ ```bash
20
+ # Run SQL injection scan
21
+ swarmhack spawn --agents sqli \
22
+ --target "http://example.com" \
23
+ --customer "your-customer" \
24
+ --token "your-token"
25
+
26
+ # Run multiple agents
27
+ swarmhack spawn --agents sqli,xss,csrf \
28
+ --target "http://example.com" \
29
+ --customer "your-customer" \
30
+ --token "your-token"
31
+
32
+ # List available agents
33
+ swarmhack agents list
34
+
35
+ # Check system health
36
+ swarmhack doctor
37
+ ```
38
+
39
+ ## Node.js API
40
+
41
+ ```javascript
42
+ const swarmhack = require('@prancer/swarmhack');
43
+
44
+ // Run a scan
45
+ const results = await swarmhack.scan({
46
+ target: 'http://example.com',
47
+ agents: ['sqli', 'xss'],
48
+ customer: 'your-customer',
49
+ token: 'your-token',
50
+ });
51
+
52
+ console.log(results);
53
+
54
+ // Check version
55
+ const version = await swarmhack.version();
56
+ console.log(version);
57
+
58
+ // Run any command
59
+ const result = await swarmhack.run(['spawn', '--help']);
60
+ console.log(result.stdout);
61
+ ```
62
+
63
+ ## Supported Platforms
64
+
65
+ | Platform | Architecture |
66
+ |----------|--------------|
67
+ | Linux | x64, arm64 |
68
+ | macOS | x64, arm64 |
69
+ | Windows | x64 |
70
+
71
+ ## Docker Alternative
72
+
73
+ If npm installation fails, use Docker:
74
+
75
+ ```bash
76
+ docker run --rm \
77
+ -v /var/run/docker.sock:/var/run/docker.sock \
78
+ -v $(pwd)/reports:/app/reports \
79
+ prancer/swarmhack:0.1.0 \
80
+ spawn --agents sqli --target "http://example.com" \
81
+ --customer "your-customer" --token "your-token"
82
+ ```
83
+
84
+ ## Available Agents
85
+
86
+ | Agent | Description |
87
+ |-------|-------------|
88
+ | `crawler` | Web crawling and discovery |
89
+ | `sqli` | SQL injection detection |
90
+ | `xss` | Cross-site scripting |
91
+ | `csrf` | CSRF vulnerabilities |
92
+ | `idor` | Insecure direct object reference |
93
+ | `auth_bypass` | Authentication bypass |
94
+ | `cmdi` | Command injection |
95
+
96
+ ## Requirements
97
+
98
+ - Node.js 16+
99
+ - Prancer Portal account (for `--token` and `--customer`)
100
+
101
+ ## License
102
+
103
+ MIT
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SwarmHack CLI Wrapper
5
+ * Executes the native binary with all arguments passed through
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const path = require('path');
10
+ const fs = require('fs');
11
+ const os = require('os');
12
+
13
+ // Determine binary path based on platform
14
+ function getBinaryPath() {
15
+ const platform = os.platform();
16
+ const arch = os.arch();
17
+
18
+ let binaryName = 'swarmhack';
19
+ if (platform === 'win32') {
20
+ binaryName = 'swarmhack.exe';
21
+ }
22
+
23
+ // Check multiple locations
24
+ const locations = [
25
+ // Installed in package
26
+ path.join(__dirname, '..', 'native', `${platform}-${arch}`, binaryName),
27
+ // Fallback to generic
28
+ path.join(__dirname, '..', 'native', binaryName),
29
+ // Development: in release folder
30
+ path.join(__dirname, '..', '..', binaryName),
31
+ ];
32
+
33
+ for (const loc of locations) {
34
+ if (fs.existsSync(loc)) {
35
+ return loc;
36
+ }
37
+ }
38
+
39
+ // Not found - show helpful error
40
+ console.error(`
41
+ SwarmHack binary not found for ${platform}-${arch}
42
+
43
+ This could mean:
44
+ 1. The postinstall script failed to download the binary
45
+ 2. Your platform is not supported yet
46
+
47
+ Supported platforms:
48
+ - linux-x64
49
+ - linux-arm64
50
+ - darwin-x64 (macOS Intel)
51
+ - darwin-arm64 (macOS Apple Silicon)
52
+ - win32-x64 (Windows)
53
+
54
+ To manually install:
55
+ 1. Download binary from: https://github.com/prancer-io/swarmhack/releases
56
+ 2. Place in: ${path.join(__dirname, '..', 'native', `${platform}-${arch}`)}
57
+ 3. Make executable: chmod +x swarmhack
58
+
59
+ Or use Docker instead:
60
+ docker run --rm prancer/swarmhack:0.1.0 --help
61
+ `);
62
+ process.exit(1);
63
+ }
64
+
65
+ // Get binary path
66
+ const binaryPath = getBinaryPath();
67
+
68
+ // Spawn the binary with all arguments
69
+ const args = process.argv.slice(2);
70
+ const child = spawn(binaryPath, args, {
71
+ stdio: 'inherit',
72
+ env: {
73
+ ...process.env,
74
+ // Ensure proper terminal handling
75
+ TERM: process.env.TERM || 'xterm-256color',
76
+ },
77
+ });
78
+
79
+ // Forward exit code
80
+ child.on('close', (code) => {
81
+ process.exit(code || 0);
82
+ });
83
+
84
+ child.on('error', (err) => {
85
+ if (err.code === 'ENOENT') {
86
+ console.error(`Error: Binary not found at ${binaryPath}`);
87
+ } else if (err.code === 'EACCES') {
88
+ console.error(`Error: Binary not executable. Run: chmod +x ${binaryPath}`);
89
+ } else {
90
+ console.error(`Error executing SwarmHack: ${err.message}`);
91
+ }
92
+ process.exit(1);
93
+ });
package/index.js ADDED
@@ -0,0 +1,137 @@
1
+ /**
2
+ * SwarmHack Node.js API
3
+ * Programmatic interface for running SwarmHack scans
4
+ */
5
+
6
+ const { spawn } = require('child_process');
7
+ const path = require('path');
8
+ const fs = require('fs');
9
+ const os = require('os');
10
+
11
+ /**
12
+ * Get path to SwarmHack binary
13
+ */
14
+ function getBinaryPath() {
15
+ const platform = os.platform();
16
+ const arch = os.arch();
17
+ const binaryName = platform === 'win32' ? 'swarmhack.exe' : 'swarmhack';
18
+
19
+ const locations = [
20
+ path.join(__dirname, 'native', `${platform}-${arch}`, binaryName),
21
+ path.join(__dirname, 'native', binaryName),
22
+ path.join(__dirname, '..', binaryName),
23
+ ];
24
+
25
+ for (const loc of locations) {
26
+ if (fs.existsSync(loc)) {
27
+ return loc;
28
+ }
29
+ }
30
+
31
+ throw new Error(`SwarmHack binary not found for ${platform}-${arch}`);
32
+ }
33
+
34
+ /**
35
+ * Run SwarmHack with arguments
36
+ * @param {string[]} args - Command line arguments
37
+ * @param {object} options - Spawn options
38
+ * @returns {Promise<{code: number, stdout: string, stderr: string}>}
39
+ */
40
+ function run(args = [], options = {}) {
41
+ return new Promise((resolve, reject) => {
42
+ const binaryPath = getBinaryPath();
43
+ const stdout = [];
44
+ const stderr = [];
45
+
46
+ const child = spawn(binaryPath, args, {
47
+ ...options,
48
+ env: { ...process.env, ...options.env },
49
+ });
50
+
51
+ child.stdout?.on('data', (data) => stdout.push(data));
52
+ child.stderr?.on('data', (data) => stderr.push(data));
53
+
54
+ child.on('close', (code) => {
55
+ resolve({
56
+ code: code || 0,
57
+ stdout: Buffer.concat(stdout).toString(),
58
+ stderr: Buffer.concat(stderr).toString(),
59
+ });
60
+ });
61
+
62
+ child.on('error', reject);
63
+ });
64
+ }
65
+
66
+ /**
67
+ * Run a security scan
68
+ * @param {object} config - Scan configuration
69
+ * @param {string} config.target - Target URL
70
+ * @param {string[]} config.agents - Agents to run (sqli, xss, etc.)
71
+ * @param {string} config.customer - Prancer customer ID
72
+ * @param {string} config.token - Prancer API token
73
+ * @param {string} config.output - Output file path
74
+ * @returns {Promise<object>} - Scan results
75
+ */
76
+ async function scan(config) {
77
+ const args = ['spawn'];
78
+
79
+ if (config.target) args.push('--target', config.target);
80
+ if (config.agents) args.push('--agents', config.agents.join(','));
81
+ if (config.customer) args.push('--customer', config.customer);
82
+ if (config.token) args.push('--token', config.token);
83
+ if (config.output) args.push('--output', config.output);
84
+ if (config.timeout) args.push('--timeout', String(config.timeout));
85
+
86
+ args.push('--format', 'json');
87
+
88
+ const result = await run(args);
89
+
90
+ if (result.code !== 0) {
91
+ throw new Error(`Scan failed: ${result.stderr || result.stdout}`);
92
+ }
93
+
94
+ // Try to parse JSON output
95
+ try {
96
+ return JSON.parse(result.stdout);
97
+ } catch {
98
+ return { raw: result.stdout };
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Get SwarmHack version
104
+ */
105
+ async function version() {
106
+ const result = await run(['--version']);
107
+ return result.stdout.trim();
108
+ }
109
+
110
+ /**
111
+ * Check if SwarmHack is installed and working
112
+ */
113
+ async function doctor() {
114
+ try {
115
+ const binaryPath = getBinaryPath();
116
+ const result = await run(['doctor']);
117
+ return {
118
+ installed: true,
119
+ binaryPath,
120
+ healthy: result.code === 0,
121
+ output: result.stdout,
122
+ };
123
+ } catch (err) {
124
+ return {
125
+ installed: false,
126
+ error: err.message,
127
+ };
128
+ }
129
+ }
130
+
131
+ module.exports = {
132
+ run,
133
+ scan,
134
+ version,
135
+ doctor,
136
+ getBinaryPath,
137
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "swarmhack-cli",
3
+ "version": "0.1.0",
4
+ "description": "SwarmHack - Neural swarm-based penetration testing framework",
5
+ "author": "Prancer <support@prancer.io>",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/prancer-io/swarmhack"
10
+ },
11
+ "homepage": "https://prancer.io",
12
+ "keywords": [
13
+ "security",
14
+ "pentesting",
15
+ "vulnerability-scanner",
16
+ "sql-injection",
17
+ "xss",
18
+ "web-security",
19
+ "ocsf"
20
+ ],
21
+ "bin": {
22
+ "swarmhack": "./bin/swarmhack.js"
23
+ },
24
+ "main": "index.js",
25
+ "files": [
26
+ "bin/",
27
+ "scripts/",
28
+ "index.js",
29
+ "README.md"
30
+ ],
31
+ "scripts": {
32
+ "postinstall": "node scripts/postinstall.js",
33
+ "test": "node bin/swarmhack.js --version"
34
+ },
35
+ "engines": {
36
+ "node": ">=16.0.0"
37
+ },
38
+ "os": [
39
+ "linux",
40
+ "darwin",
41
+ "win32"
42
+ ],
43
+ "cpu": [
44
+ "x64",
45
+ "arm64"
46
+ ],
47
+ "dependencies": {},
48
+ "devDependencies": {}
49
+ }
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SwarmHack npm Package Build Script
5
+ * Builds binaries for all platforms and packages for npm
6
+ */
7
+
8
+ const { execSync } = require('child_process');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ const VERSION = require('../package.json').version;
13
+ const ROOT = path.join(__dirname, '..');
14
+ const PROJECT_ROOT = path.join(ROOT, '..', '..');
15
+
16
+ // Build targets
17
+ const TARGETS = [
18
+ { platform: 'linux', arch: 'x64', rust_target: 'x86_64-unknown-linux-gnu' },
19
+ { platform: 'linux', arch: 'arm64', rust_target: 'aarch64-unknown-linux-gnu' },
20
+ { platform: 'darwin', arch: 'x64', rust_target: 'x86_64-apple-darwin' },
21
+ { platform: 'darwin', arch: 'arm64', rust_target: 'aarch64-apple-darwin' },
22
+ { platform: 'win32', arch: 'x64', rust_target: 'x86_64-pc-windows-msvc' },
23
+ ];
24
+
25
+ function exec(cmd, options = {}) {
26
+ console.log(`$ ${cmd}`);
27
+ try {
28
+ return execSync(cmd, { stdio: 'inherit', cwd: PROJECT_ROOT, ...options });
29
+ } catch (err) {
30
+ console.error(`Command failed: ${cmd}`);
31
+ throw err;
32
+ }
33
+ }
34
+
35
+ function buildTarget(target) {
36
+ console.log(`\n=== Building ${target.platform}-${target.arch} ===\n`);
37
+
38
+ const nativeDir = path.join(ROOT, 'native', `${target.platform}-${target.arch}`);
39
+ fs.mkdirSync(nativeDir, { recursive: true });
40
+
41
+ const binaryName = target.platform === 'win32' ? 'swarmhack.exe' : 'swarmhack';
42
+ const binaryPath = path.join(nativeDir, binaryName);
43
+
44
+ // Build with cross-compilation
45
+ try {
46
+ exec(`cross build --release --target ${target.rust_target}`);
47
+
48
+ const srcBinary = path.join(
49
+ PROJECT_ROOT,
50
+ 'target',
51
+ target.rust_target,
52
+ 'release',
53
+ binaryName
54
+ );
55
+
56
+ fs.copyFileSync(srcBinary, binaryPath);
57
+ fs.chmodSync(binaryPath, 0o755);
58
+ console.log(`✓ Built: ${binaryPath}`);
59
+
60
+ } catch (err) {
61
+ console.warn(`⚠ Skipping ${target.rust_target}: ${err.message}`);
62
+ }
63
+ }
64
+
65
+ function buildLocal() {
66
+ console.log('\n=== Building for current platform ===\n');
67
+
68
+ const platform = process.platform;
69
+ const arch = process.arch;
70
+
71
+ const nativeDir = path.join(ROOT, 'native', `${platform}-${arch}`);
72
+ fs.mkdirSync(nativeDir, { recursive: true });
73
+
74
+ const binaryName = platform === 'win32' ? 'swarmhack.exe' : 'swarmhack';
75
+
76
+ exec('cargo build --release');
77
+
78
+ const srcBinary = path.join(PROJECT_ROOT, 'target', 'release', binaryName);
79
+ const destBinary = path.join(nativeDir, binaryName);
80
+
81
+ fs.copyFileSync(srcBinary, destBinary);
82
+ fs.chmodSync(destBinary, 0o755);
83
+
84
+ console.log(`✓ Built: ${destBinary}`);
85
+ }
86
+
87
+ function main() {
88
+ const args = process.argv.slice(2);
89
+
90
+ if (args.includes('--all')) {
91
+ // Build all platforms (requires cross)
92
+ console.log('Building all platforms...');
93
+ for (const target of TARGETS) {
94
+ try {
95
+ buildTarget(target);
96
+ } catch (err) {
97
+ console.error(`Failed to build ${target.platform}-${target.arch}`);
98
+ }
99
+ }
100
+ } else {
101
+ // Build for current platform only
102
+ buildLocal();
103
+ }
104
+
105
+ console.log(`\n✓ Build complete! Version: ${VERSION}\n`);
106
+ console.log('To publish:');
107
+ console.log(' cd npm && npm publish --access public\n');
108
+ }
109
+
110
+ main();
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Pack local binary for npm
5
+ * Use this when you already have a built binary
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const os = require('os');
11
+
12
+ const ROOT = path.join(__dirname, '..');
13
+ const RELEASE_DIR = path.join(ROOT, '..');
14
+
15
+ function main() {
16
+ const platform = os.platform();
17
+ const arch = os.arch();
18
+ const binaryName = platform === 'win32' ? 'swarmhack.exe' : 'swarmhack';
19
+
20
+ // Source: release/swarmhack
21
+ const srcBinary = path.join(RELEASE_DIR, 'swarmhack');
22
+
23
+ if (!fs.existsSync(srcBinary)) {
24
+ console.error(`Binary not found: ${srcBinary}`);
25
+ console.error('Build first with: cargo build --release && cp target/release/swarmhack release/');
26
+ process.exit(1);
27
+ }
28
+
29
+ // Destination: npm/native/<platform>-<arch>/swarmhack
30
+ const nativeDir = path.join(ROOT, 'native', `${platform}-${arch}`);
31
+ fs.mkdirSync(nativeDir, { recursive: true });
32
+
33
+ const destBinary = path.join(nativeDir, binaryName);
34
+ fs.copyFileSync(srcBinary, destBinary);
35
+ fs.chmodSync(destBinary, 0o755);
36
+
37
+ console.log(`✓ Packed binary for ${platform}-${arch}`);
38
+ console.log(` Source: ${srcBinary}`);
39
+ console.log(` Dest: ${destBinary}`);
40
+ console.log();
41
+ console.log('Package structure:');
42
+ console.log(' npm/');
43
+ console.log(' ├── package.json');
44
+ console.log(' ├── bin/swarmhack.js');
45
+ console.log(' ├── index.js');
46
+ console.log(` └── native/${platform}-${arch}/${binaryName}`);
47
+ console.log();
48
+ console.log('To test locally:');
49
+ console.log(' cd npm && npm link');
50
+ console.log(' swarmhack --version');
51
+ console.log();
52
+ console.log('To publish:');
53
+ console.log(' cd npm && npm publish --access public');
54
+ }
55
+
56
+ main();
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SwarmHack Postinstall Script
5
+ * Downloads the appropriate binary for the current platform
6
+ */
7
+
8
+ const https = require('https');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const os = require('os');
12
+ const { execSync } = require('child_process');
13
+
14
+ const VERSION = '0.1.0';
15
+ const GITHUB_REPO = 'prancer-io/swarmhack';
16
+ const BASE_URL = `https://github.com/${GITHUB_REPO}/releases/download/v${VERSION}`;
17
+
18
+ // Platform mapping
19
+ const PLATFORM_MAP = {
20
+ 'linux-x64': 'swarmhack-linux-x64',
21
+ 'linux-arm64': 'swarmhack-linux-arm64',
22
+ 'darwin-x64': 'swarmhack-darwin-x64',
23
+ 'darwin-arm64': 'swarmhack-darwin-arm64',
24
+ 'win32-x64': 'swarmhack-windows-x64.exe',
25
+ };
26
+
27
+ function getPlatformKey() {
28
+ const platform = os.platform();
29
+ const arch = os.arch();
30
+ return `${platform}-${arch}`;
31
+ }
32
+
33
+ function getBinaryName() {
34
+ const platform = os.platform();
35
+ return platform === 'win32' ? 'swarmhack.exe' : 'swarmhack';
36
+ }
37
+
38
+ function downloadFile(url, dest) {
39
+ return new Promise((resolve, reject) => {
40
+ const file = fs.createWriteStream(dest);
41
+
42
+ const request = https.get(url, (response) => {
43
+ // Handle redirects (GitHub releases use redirects)
44
+ if (response.statusCode === 302 || response.statusCode === 301) {
45
+ file.close();
46
+ fs.unlinkSync(dest);
47
+ return downloadFile(response.headers.location, dest).then(resolve).catch(reject);
48
+ }
49
+
50
+ if (response.statusCode !== 200) {
51
+ file.close();
52
+ fs.unlinkSync(dest);
53
+ reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
54
+ return;
55
+ }
56
+
57
+ response.pipe(file);
58
+ file.on('finish', () => {
59
+ file.close();
60
+ resolve();
61
+ });
62
+ });
63
+
64
+ request.on('error', (err) => {
65
+ file.close();
66
+ fs.unlinkSync(dest);
67
+ reject(err);
68
+ });
69
+
70
+ request.setTimeout(60000, () => {
71
+ request.destroy();
72
+ reject(new Error('Download timeout'));
73
+ });
74
+ });
75
+ }
76
+
77
+ async function main() {
78
+ const platformKey = getPlatformKey();
79
+ const remoteBinary = PLATFORM_MAP[platformKey];
80
+
81
+ if (!remoteBinary) {
82
+ console.log(`
83
+ ╔════════════════════════════════════════════════════════════╗
84
+ ║ SwarmHack: Platform not supported ║
85
+ ╠════════════════════════════════════════════════════════════╣
86
+ ║ Your platform: ${platformKey.padEnd(40)}║
87
+ ║ ║
88
+ ║ Supported platforms: ║
89
+ ║ - linux-x64, linux-arm64 ║
90
+ ║ - darwin-x64, darwin-arm64 ║
91
+ ║ - win32-x64 ║
92
+ ║ ║
93
+ ║ Alternative: Use Docker ║
94
+ ║ docker run prancer/swarmhack:${VERSION} --help ║
95
+ ╚════════════════════════════════════════════════════════════╝
96
+ `);
97
+ // Don't fail install - just warn
98
+ return;
99
+ }
100
+
101
+ const nativeDir = path.join(__dirname, '..', 'native', platformKey);
102
+ const binaryPath = path.join(nativeDir, getBinaryName());
103
+
104
+ // Skip if already exists
105
+ if (fs.existsSync(binaryPath)) {
106
+ console.log(`SwarmHack binary already exists: ${binaryPath}`);
107
+ return;
108
+ }
109
+
110
+ // Create directory
111
+ fs.mkdirSync(nativeDir, { recursive: true });
112
+
113
+ const url = `${BASE_URL}/${remoteBinary}`;
114
+
115
+ console.log(`
116
+ ╔════════════════════════════════════════════════════════════╗
117
+ ║ SwarmHack: Downloading binary... ║
118
+ ╠════════════════════════════════════════════════════════════╣
119
+ ║ Version: ${VERSION.padEnd(48)}║
120
+ ║ Platform: ${platformKey.padEnd(47)}║
121
+ ╚════════════════════════════════════════════════════════════╝
122
+ `);
123
+
124
+ try {
125
+ await downloadFile(url, binaryPath);
126
+
127
+ // Make executable on Unix
128
+ if (os.platform() !== 'win32') {
129
+ fs.chmodSync(binaryPath, 0o755);
130
+ }
131
+
132
+ console.log(`✓ SwarmHack installed successfully!`);
133
+ console.log(` Binary: ${binaryPath}`);
134
+ console.log(`\n Run: npx swarmhack --help\n`);
135
+
136
+ } catch (err) {
137
+ console.error(`
138
+ ╔════════════════════════════════════════════════════════════╗
139
+ ║ SwarmHack: Download failed ║
140
+ ╠════════════════════════════════════════════════════════════╣
141
+ ║ ${err.message.substring(0, 56).padEnd(56)}║
142
+ ║ ║
143
+ ║ Manual installation: ║
144
+ ║ 1. Download from GitHub releases ║
145
+ ║ 2. Place binary in: native/${platformKey}/ ║
146
+ ║ 3. Make executable: chmod +x swarmhack ║
147
+ ║ ║
148
+ ║ Or use Docker: ║
149
+ ║ docker run prancer/swarmhack:${VERSION} --help ║
150
+ ╚════════════════════════════════════════════════════════════╝
151
+ `);
152
+ // Don't fail the install
153
+ }
154
+ }
155
+
156
+ main().catch(console.error);