vulcn 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/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/index.js +291 -0
- package/dist/index.js.map +1 -0
- package/package.json +75 -0
- package/vulcn.mjs +15 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-02-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release of Vulcn - Security testing recorder & runner
|
|
13
|
+
- **Session Recording** - Record browser interactions (clicks, form fills, navigation)
|
|
14
|
+
- **Session Replay** - Replay sessions with security payloads injected
|
|
15
|
+
- **Smart Browser Detection** - Uses system Chrome/Edge first, Playwright fallback
|
|
16
|
+
- **Built-in Payloads** - XSS and SQL injection payload sets
|
|
17
|
+
- **YAML Sessions** - Human-readable session format with Zod validation
|
|
18
|
+
- **Cross-Platform** - macOS, Linux, and Windows support
|
|
19
|
+
|
|
20
|
+
### CLI Commands
|
|
21
|
+
|
|
22
|
+
- `vulcn record` - Record browser interactions
|
|
23
|
+
- `vulcn run` - Replay session with payloads
|
|
24
|
+
- `vulcn payloads` - List available payloads
|
|
25
|
+
- `vulcn doctor` - Check browser availability
|
|
26
|
+
- `vulcn install` - Install Playwright browsers
|
|
27
|
+
|
|
28
|
+
[0.1.0]: https://github.com/rawlab-dev/vulcn/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 rawlab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# 🔐 Vulcn
|
|
2
|
+
|
|
3
|
+
**Security testing made simple.** Record once, test with payloads, find vulnerabilities.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/rawlab-dev/vulcn/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/vulcn)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## ⚡ Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Install globally
|
|
15
|
+
npm install -g vulcn
|
|
16
|
+
|
|
17
|
+
# Record a session
|
|
18
|
+
vulcn record --url https://example.com/login
|
|
19
|
+
|
|
20
|
+
# Run with XSS payloads
|
|
21
|
+
vulcn run session.vulcn.yml --payload xss-basic
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Zero-config browser support** — Vulcn uses your existing Chrome or Edge. No browser downloads needed.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 🎯 What is Vulcn?
|
|
29
|
+
|
|
30
|
+
Vulcn is a security testing tool that:
|
|
31
|
+
|
|
32
|
+
1. **Records** your browser interactions (clicks, form inputs, navigation)
|
|
33
|
+
2. **Replays** them with security payloads injected into input fields
|
|
34
|
+
3. **Detects** vulnerabilities like XSS and SQL injection
|
|
35
|
+
|
|
36
|
+
Think of it as **Playwright + Burp Suite**, but simpler and focused on automated payload testing.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 🚀 Features
|
|
41
|
+
|
|
42
|
+
| Feature | Description |
|
|
43
|
+
| --------------------- | --------------------------------------------------- |
|
|
44
|
+
| 🎬 **Record** | Capture browser sessions as replayable YAML files |
|
|
45
|
+
| 🔍 **Test** | Inject XSS, SQLi, and custom payloads automatically |
|
|
46
|
+
| 🌐 **Cross-platform** | Works on macOS, Linux, and Windows |
|
|
47
|
+
| 🚫 **Zero-config** | Uses system Chrome/Edge by default |
|
|
48
|
+
| 📊 **CI/CD Ready** | Exit codes for pipeline integration |
|
|
49
|
+
| 🔧 **Extensible** | Add custom payloads and detection patterns |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 📦 Installation
|
|
54
|
+
|
|
55
|
+
### CLI
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm install -g vulcn
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Programmatic API
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm install @vulcn/engine
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { Recorder, Runner, parseSession } from "@vulcn/engine";
|
|
69
|
+
|
|
70
|
+
// Record programmatically
|
|
71
|
+
const session = await Recorder.start("https://example.com");
|
|
72
|
+
// ... user interacts ...
|
|
73
|
+
const recorded = await session.stop();
|
|
74
|
+
|
|
75
|
+
// Run with payloads
|
|
76
|
+
const result = await Runner.execute(recorded, ["xss-basic"]);
|
|
77
|
+
console.log(result.findings);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 🎬 Recording
|
|
83
|
+
|
|
84
|
+
Start recording a session:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
vulcn record --url https://target.com/login
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Options:
|
|
91
|
+
|
|
92
|
+
- `--url, -u` — Start URL (required)
|
|
93
|
+
- `--output, -o` — Output file (default: `session.vulcn.yml`)
|
|
94
|
+
- `--browser, -b` — Browser (`chromium`, `firefox`, `webkit`)
|
|
95
|
+
- `--headless` — Run headless
|
|
96
|
+
|
|
97
|
+
When recording:
|
|
98
|
+
|
|
99
|
+
1. Browser opens to your start URL
|
|
100
|
+
2. Interact normally (fill forms, click buttons)
|
|
101
|
+
3. Press `Ctrl+C` to stop and save
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 🔍 Running Tests
|
|
106
|
+
|
|
107
|
+
Run a recorded session with payloads:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
vulcn run session.vulcn.yml --payload xss-basic --payload sqli-basic
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Options:
|
|
114
|
+
|
|
115
|
+
- `--payload, -p` — Payload to use (can specify multiple)
|
|
116
|
+
- `--headless` — Run headless (default: true)
|
|
117
|
+
- `--browser, -b` — Browser to use
|
|
118
|
+
|
|
119
|
+
### Built-in Payloads
|
|
120
|
+
|
|
121
|
+
| Payload | Category | Description |
|
|
122
|
+
| ------------ | -------- | ------------------------------ |
|
|
123
|
+
| `xss-basic` | XSS | Script tags and event handlers |
|
|
124
|
+
| `xss-event` | XSS | Event handler injection |
|
|
125
|
+
| `xss-svg` | XSS | SVG-based XSS |
|
|
126
|
+
| `sqli-basic` | SQLi | Basic SQL injection |
|
|
127
|
+
| `sqli-error` | SQLi | Error-based SQLi detection |
|
|
128
|
+
| `sqli-blind` | SQLi | Blind SQLi payloads |
|
|
129
|
+
|
|
130
|
+
List all payloads:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
vulcn payloads
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 📄 Session Format
|
|
139
|
+
|
|
140
|
+
Sessions are stored as YAML:
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
version: "1"
|
|
144
|
+
name: Login Test
|
|
145
|
+
recordedAt: "2026-02-05T12:00:00Z"
|
|
146
|
+
browser: chromium
|
|
147
|
+
viewport:
|
|
148
|
+
width: 1280
|
|
149
|
+
height: 720
|
|
150
|
+
startUrl: https://example.com/login
|
|
151
|
+
steps:
|
|
152
|
+
- id: step_001
|
|
153
|
+
type: navigate
|
|
154
|
+
url: https://example.com/login
|
|
155
|
+
timestamp: 0
|
|
156
|
+
- id: step_002
|
|
157
|
+
type: input
|
|
158
|
+
selector: input[name="username"]
|
|
159
|
+
value: testuser
|
|
160
|
+
injectable: true
|
|
161
|
+
timestamp: 1500
|
|
162
|
+
- id: step_003
|
|
163
|
+
type: click
|
|
164
|
+
selector: button[type="submit"]
|
|
165
|
+
timestamp: 3000
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 🩺 Browser Management
|
|
171
|
+
|
|
172
|
+
Check available browsers:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
vulcn doctor
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Install Playwright browsers (if needed):
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
vulcn install chromium
|
|
182
|
+
vulcn install --all # Install all browsers
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 🔧 CI/CD Integration
|
|
188
|
+
|
|
189
|
+
Vulcn returns exit code `1` when vulnerabilities are found:
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
# GitHub Actions example
|
|
193
|
+
- name: Security Test
|
|
194
|
+
run: |
|
|
195
|
+
npm install -g vulcn
|
|
196
|
+
vulcn run tests/login.vulcn.yml --payload xss-basic --headless
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 📚 Documentation
|
|
202
|
+
|
|
203
|
+
- [Contributing Guide](./CONTRIBUTING.md)
|
|
204
|
+
- [Security Policy](./SECURITY.md)
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 🛣️ Roadmap
|
|
209
|
+
|
|
210
|
+
- [ ] HTML/JSON reports
|
|
211
|
+
- [ ] Custom payload definitions
|
|
212
|
+
- [ ] SSRF and path traversal payloads
|
|
213
|
+
- [ ] Authenticated session support
|
|
214
|
+
- [ ] API endpoint testing
|
|
215
|
+
- [ ] Vulnerability severity scoring
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 📝 License
|
|
220
|
+
|
|
221
|
+
[MIT](./LICENSE) © [rawlab](https://rawlab.dev)
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
<p align="center">
|
|
226
|
+
Made with ❤️ by <a href="https://rawlab.dev">rawlab</a>
|
|
227
|
+
</p>
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/record.ts
|
|
7
|
+
import { writeFile } from "fs/promises";
|
|
8
|
+
import { Recorder, serializeSession } from "@vulcn/engine";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import ora from "ora";
|
|
11
|
+
async function recordCommand(options) {
|
|
12
|
+
const spinner = ora("Starting browser...").start();
|
|
13
|
+
try {
|
|
14
|
+
const session = await Recorder.start(options.url, {
|
|
15
|
+
browser: options.browser,
|
|
16
|
+
headless: options.headless
|
|
17
|
+
});
|
|
18
|
+
spinner.succeed("Browser started");
|
|
19
|
+
console.log();
|
|
20
|
+
console.log(chalk.cyan("\u{1F3AC} Recording started"));
|
|
21
|
+
console.log(chalk.gray(` URL: ${options.url}`));
|
|
22
|
+
console.log(chalk.gray(` Browser: ${options.browser}`));
|
|
23
|
+
console.log();
|
|
24
|
+
console.log(
|
|
25
|
+
chalk.yellow(" Interact with the browser to record actions.")
|
|
26
|
+
);
|
|
27
|
+
console.log(chalk.yellow(" Press Ctrl+C to stop recording."));
|
|
28
|
+
console.log();
|
|
29
|
+
if (process.stdin.isTTY) {
|
|
30
|
+
process.stdin.setRawMode(true);
|
|
31
|
+
}
|
|
32
|
+
process.stdin.resume();
|
|
33
|
+
process.stdin.setEncoding("utf8");
|
|
34
|
+
let stopped = false;
|
|
35
|
+
const stopRecording = async () => {
|
|
36
|
+
if (stopped) return;
|
|
37
|
+
stopped = true;
|
|
38
|
+
console.log();
|
|
39
|
+
const saveSpinner = ora("Stopping recording...").start();
|
|
40
|
+
try {
|
|
41
|
+
const result = await session.stop();
|
|
42
|
+
const yaml = serializeSession(result);
|
|
43
|
+
await writeFile(options.output, yaml, "utf-8");
|
|
44
|
+
saveSpinner.succeed(`Session saved to ${chalk.green(options.output)}`);
|
|
45
|
+
console.log();
|
|
46
|
+
console.log(chalk.cyan(`\u{1F4DD} Recorded ${result.steps.length} steps`));
|
|
47
|
+
console.log();
|
|
48
|
+
console.log(chalk.gray("To run with payloads:"));
|
|
49
|
+
console.log(
|
|
50
|
+
chalk.white(` vulcn run ${options.output} --payload xss-basic`)
|
|
51
|
+
);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
saveSpinner.fail("Failed to save session");
|
|
54
|
+
console.error(chalk.red(String(err)));
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
await new Promise((resolve) => {
|
|
59
|
+
const handleStop = () => {
|
|
60
|
+
process.stdin.removeAllListeners("data");
|
|
61
|
+
process.off("SIGINT", handleStop);
|
|
62
|
+
process.off("SIGTERM", handleStop);
|
|
63
|
+
stopRecording().then(() => {
|
|
64
|
+
resolve();
|
|
65
|
+
}).catch((err) => {
|
|
66
|
+
console.error(chalk.red(String(err)));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
process.stdin.on("data", (key) => {
|
|
71
|
+
if (key === "") {
|
|
72
|
+
handleStop();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
process.on("SIGINT", handleStop);
|
|
76
|
+
process.on("SIGTERM", handleStop);
|
|
77
|
+
});
|
|
78
|
+
} catch (err) {
|
|
79
|
+
spinner.fail("Failed to start recording");
|
|
80
|
+
console.error(chalk.red(String(err)));
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/run.ts
|
|
86
|
+
import { readFile } from "fs/promises";
|
|
87
|
+
import {
|
|
88
|
+
Runner,
|
|
89
|
+
parseSession
|
|
90
|
+
} from "@vulcn/engine";
|
|
91
|
+
import chalk2 from "chalk";
|
|
92
|
+
import ora2 from "ora";
|
|
93
|
+
async function runCommand(sessionFile, options) {
|
|
94
|
+
const loadSpinner = ora2("Loading session...").start();
|
|
95
|
+
let sessionYaml;
|
|
96
|
+
try {
|
|
97
|
+
sessionYaml = await readFile(sessionFile, "utf-8");
|
|
98
|
+
} catch {
|
|
99
|
+
loadSpinner.fail(`Cannot read file: ${sessionFile}`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
let session;
|
|
103
|
+
try {
|
|
104
|
+
session = parseSession(sessionYaml);
|
|
105
|
+
loadSpinner.succeed(`Loaded session: ${chalk2.cyan(session.name)}`);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
loadSpinner.fail("Invalid session file");
|
|
108
|
+
console.error(chalk2.red(String(err)));
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
const payloads = options.payload ?? ["xss-basic"];
|
|
112
|
+
console.log();
|
|
113
|
+
console.log(chalk2.cyan("\u{1F50D} Running security tests"));
|
|
114
|
+
console.log(chalk2.gray(` Session: ${session.name}`));
|
|
115
|
+
console.log(chalk2.gray(` Payloads: ${payloads.join(", ")}`));
|
|
116
|
+
console.log(chalk2.gray(` Browser: ${options.browser}`));
|
|
117
|
+
console.log(chalk2.gray(` Headless: ${options.headless}`));
|
|
118
|
+
console.log();
|
|
119
|
+
const runSpinner = ora2("Executing tests...").start();
|
|
120
|
+
try {
|
|
121
|
+
const result = await Runner.execute(session, payloads, {
|
|
122
|
+
browser: options.browser,
|
|
123
|
+
headless: options.headless,
|
|
124
|
+
onFinding: (finding) => {
|
|
125
|
+
runSpinner.stop();
|
|
126
|
+
console.log(chalk2.red(`\u26A0\uFE0F FINDING: ${finding.title}`));
|
|
127
|
+
console.log(chalk2.gray(` Step: ${finding.stepId}`));
|
|
128
|
+
console.log(
|
|
129
|
+
chalk2.gray(` Payload: ${finding.payload.slice(0, 50)}...`)
|
|
130
|
+
);
|
|
131
|
+
console.log(chalk2.gray(` URL: ${finding.url}`));
|
|
132
|
+
console.log();
|
|
133
|
+
runSpinner.start("Continuing tests...");
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
runSpinner.succeed("Tests completed");
|
|
137
|
+
console.log();
|
|
138
|
+
console.log(chalk2.cyan("\u{1F4CA} Results"));
|
|
139
|
+
console.log(chalk2.gray(` Steps executed: ${result.stepsExecuted}`));
|
|
140
|
+
console.log(chalk2.gray(` Payloads tested: ${result.payloadsTested}`));
|
|
141
|
+
console.log(
|
|
142
|
+
chalk2.gray(` Duration: ${(result.duration / 1e3).toFixed(1)}s`)
|
|
143
|
+
);
|
|
144
|
+
console.log();
|
|
145
|
+
if (result.findings.length > 0) {
|
|
146
|
+
console.log(chalk2.red(`\u{1F6A8} ${result.findings.length} findings detected!`));
|
|
147
|
+
console.log();
|
|
148
|
+
for (const finding of result.findings) {
|
|
149
|
+
const severityColor = finding.severity === "critical" || finding.severity === "high" ? chalk2.red : finding.severity === "medium" ? chalk2.yellow : chalk2.gray;
|
|
150
|
+
console.log(
|
|
151
|
+
severityColor(`[${finding.severity.toUpperCase()}] ${finding.title}`)
|
|
152
|
+
);
|
|
153
|
+
console.log(chalk2.gray(` Type: ${finding.type}`));
|
|
154
|
+
console.log(chalk2.gray(` Step: ${finding.stepId}`));
|
|
155
|
+
console.log(chalk2.gray(` URL: ${finding.url}`));
|
|
156
|
+
console.log(chalk2.gray(` Payload: ${finding.payload}`));
|
|
157
|
+
console.log();
|
|
158
|
+
}
|
|
159
|
+
process.exit(1);
|
|
160
|
+
} else {
|
|
161
|
+
console.log(chalk2.green("\u2705 No vulnerabilities detected"));
|
|
162
|
+
}
|
|
163
|
+
if (result.errors.length > 0) {
|
|
164
|
+
console.log();
|
|
165
|
+
console.log(
|
|
166
|
+
chalk2.yellow(`\u26A0\uFE0F ${result.errors.length} errors during execution:`)
|
|
167
|
+
);
|
|
168
|
+
for (const err of result.errors.slice(0, 5)) {
|
|
169
|
+
console.log(chalk2.gray(` - ${err}`));
|
|
170
|
+
}
|
|
171
|
+
if (result.errors.length > 5) {
|
|
172
|
+
console.log(chalk2.gray(` ... and ${result.errors.length - 5} more`));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
} catch (err) {
|
|
176
|
+
runSpinner.fail("Test execution failed");
|
|
177
|
+
console.error(chalk2.red(String(err)));
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/payloads.ts
|
|
183
|
+
import { BUILTIN_PAYLOADS } from "@vulcn/engine";
|
|
184
|
+
import chalk3 from "chalk";
|
|
185
|
+
async function payloadsCommand() {
|
|
186
|
+
console.log();
|
|
187
|
+
console.log(chalk3.cyan("\u{1F4E6} Available Payloads"));
|
|
188
|
+
console.log();
|
|
189
|
+
const payloads = Object.values(BUILTIN_PAYLOADS);
|
|
190
|
+
for (const payload of payloads) {
|
|
191
|
+
console.log(chalk3.white(` ${payload.name}`));
|
|
192
|
+
console.log(chalk3.gray(` Category: ${payload.category}`));
|
|
193
|
+
console.log(chalk3.gray(` ${payload.description}`));
|
|
194
|
+
console.log(chalk3.gray(` Payloads: ${payload.payloads.length}`));
|
|
195
|
+
console.log();
|
|
196
|
+
}
|
|
197
|
+
console.log(chalk3.gray("Usage:"));
|
|
198
|
+
console.log(chalk3.white(" vulcn run session.vulcn.yml --payload xss-basic"));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/install.ts
|
|
202
|
+
import { installBrowsers, checkBrowsers } from "@vulcn/engine";
|
|
203
|
+
import chalk4 from "chalk";
|
|
204
|
+
import ora3 from "ora";
|
|
205
|
+
async function installCommand(browsers, options) {
|
|
206
|
+
let browsersToInstall;
|
|
207
|
+
if (options?.all) {
|
|
208
|
+
browsersToInstall = ["chromium", "firefox", "webkit"];
|
|
209
|
+
} else if (browsers && browsers.length > 0) {
|
|
210
|
+
browsersToInstall = browsers;
|
|
211
|
+
} else {
|
|
212
|
+
browsersToInstall = ["chromium"];
|
|
213
|
+
}
|
|
214
|
+
console.log();
|
|
215
|
+
console.log(chalk4.cyan("\u{1F527} Installing browsers for Vulcn"));
|
|
216
|
+
console.log();
|
|
217
|
+
try {
|
|
218
|
+
await installBrowsers(browsersToInstall);
|
|
219
|
+
console.log();
|
|
220
|
+
console.log(chalk4.green("\u2705 Browsers installed successfully"));
|
|
221
|
+
} catch (err) {
|
|
222
|
+
console.error(chalk4.red("Failed to install browsers:"), err);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async function doctorCommand() {
|
|
227
|
+
console.log();
|
|
228
|
+
console.log(chalk4.cyan("\u{1FA7A} Vulcn Browser Check"));
|
|
229
|
+
console.log();
|
|
230
|
+
const spinner = ora3("Checking available browsers...").start();
|
|
231
|
+
try {
|
|
232
|
+
const status = await checkBrowsers();
|
|
233
|
+
spinner.stop();
|
|
234
|
+
console.log(chalk4.white("System Browsers:"));
|
|
235
|
+
console.log(
|
|
236
|
+
` Chrome: ${status.systemChrome ? chalk4.green("\u2713 Available") : chalk4.gray("\u2717 Not found")}`
|
|
237
|
+
);
|
|
238
|
+
console.log(
|
|
239
|
+
` Edge: ${status.systemEdge ? chalk4.green("\u2713 Available") : chalk4.gray("\u2717 Not found")}`
|
|
240
|
+
);
|
|
241
|
+
console.log();
|
|
242
|
+
console.log(chalk4.white("Playwright Browsers:"));
|
|
243
|
+
console.log(
|
|
244
|
+
` Chromium: ${status.playwrightChromium ? chalk4.green("\u2713 Installed") : chalk4.gray("\u2717 Not installed")}`
|
|
245
|
+
);
|
|
246
|
+
console.log(
|
|
247
|
+
` Firefox: ${status.playwrightFirefox ? chalk4.green("\u2713 Installed") : chalk4.gray("\u2717 Not installed")}`
|
|
248
|
+
);
|
|
249
|
+
console.log(
|
|
250
|
+
` WebKit: ${status.playwrightWebkit ? chalk4.green("\u2713 Installed") : chalk4.gray("\u2717 Not installed")}`
|
|
251
|
+
);
|
|
252
|
+
console.log();
|
|
253
|
+
if (status.systemChrome || status.systemEdge) {
|
|
254
|
+
console.log(
|
|
255
|
+
chalk4.green("\u2705 Ready to use! Vulcn will use your system browser.")
|
|
256
|
+
);
|
|
257
|
+
} else if (status.playwrightChromium) {
|
|
258
|
+
console.log(
|
|
259
|
+
chalk4.green("\u2705 Ready to use! Vulcn will use Playwright Chromium.")
|
|
260
|
+
);
|
|
261
|
+
} else {
|
|
262
|
+
console.log(chalk4.yellow("\u26A0\uFE0F No browsers found."));
|
|
263
|
+
console.log();
|
|
264
|
+
console.log(chalk4.white("Options:"));
|
|
265
|
+
console.log(chalk4.gray(" 1. Install Google Chrome (recommended)"));
|
|
266
|
+
console.log(chalk4.gray(" 2. Run: vulcn install"));
|
|
267
|
+
}
|
|
268
|
+
} catch (err) {
|
|
269
|
+
spinner.fail("Failed to check browsers");
|
|
270
|
+
console.error(chalk4.red(String(err)));
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/index.ts
|
|
276
|
+
var program = new Command();
|
|
277
|
+
program.name("vulcn").description("Security testing recorder & runner").version("0.1.0");
|
|
278
|
+
program.command("record").description("Record browser interactions").requiredOption("-u, --url <url>", "Starting URL to record from").option("-o, --output <file>", "Output file path", "session.vulcn.yml").option(
|
|
279
|
+
"-b, --browser <browser>",
|
|
280
|
+
"Browser to use (chromium, firefox, webkit)",
|
|
281
|
+
"chromium"
|
|
282
|
+
).option("--headless", "Run in headless mode", false).action(recordCommand);
|
|
283
|
+
program.command("run").description("Run a recorded session with payloads").argument("<session>", "Session file to run (.vulcn.yml)").option(
|
|
284
|
+
"-p, --payload <names...>",
|
|
285
|
+
"Payloads to use (e.g., xss-basic, sqli-basic)"
|
|
286
|
+
).option("-b, --browser <browser>", "Browser to use", "chromium").option("--headless", "Run in headless mode", true).option("--no-headless", "Run with visible browser").action(runCommand);
|
|
287
|
+
program.command("payloads").description("List available payloads").action(payloadsCommand);
|
|
288
|
+
program.command("install").description("Install Playwright browsers").argument("[browsers...]", "Browsers to install (chromium, firefox, webkit)").option("--all", "Install all browsers").action(installCommand);
|
|
289
|
+
program.command("doctor").description("Check available browsers").action(doctorCommand);
|
|
290
|
+
program.parse();
|
|
291
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/record.ts","../src/run.ts","../src/payloads.ts","../src/install.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { recordCommand } from \"./record\";\nimport { runCommand } from \"./run\";\nimport { payloadsCommand } from \"./payloads\";\nimport { installCommand, doctorCommand } from \"./install\";\n\nconst program = new Command();\n\nprogram\n .name(\"vulcn\")\n .description(\"Security testing recorder & runner\")\n .version(\"0.1.0\");\n\n// vulcn record\nprogram\n .command(\"record\")\n .description(\"Record browser interactions\")\n .requiredOption(\"-u, --url <url>\", \"Starting URL to record from\")\n .option(\"-o, --output <file>\", \"Output file path\", \"session.vulcn.yml\")\n .option(\n \"-b, --browser <browser>\",\n \"Browser to use (chromium, firefox, webkit)\",\n \"chromium\",\n )\n .option(\"--headless\", \"Run in headless mode\", false)\n .action(recordCommand);\n\n// vulcn run\nprogram\n .command(\"run\")\n .description(\"Run a recorded session with payloads\")\n .argument(\"<session>\", \"Session file to run (.vulcn.yml)\")\n .option(\n \"-p, --payload <names...>\",\n \"Payloads to use (e.g., xss-basic, sqli-basic)\",\n )\n .option(\"-b, --browser <browser>\", \"Browser to use\", \"chromium\")\n .option(\"--headless\", \"Run in headless mode\", true)\n .option(\"--no-headless\", \"Run with visible browser\")\n .action(runCommand);\n\n// vulcn payloads\nprogram\n .command(\"payloads\")\n .description(\"List available payloads\")\n .action(payloadsCommand);\n\n// vulcn install\nprogram\n .command(\"install\")\n .description(\"Install Playwright browsers\")\n .argument(\"[browsers...]\", \"Browsers to install (chromium, firefox, webkit)\")\n .option(\"--all\", \"Install all browsers\")\n .action(installCommand);\n\n// vulcn doctor\nprogram\n .command(\"doctor\")\n .description(\"Check available browsers\")\n .action(doctorCommand);\n\nprogram.parse();\n","import { writeFile } from \"node:fs/promises\";\nimport { Recorder, serializeSession, type BrowserType } from \"@vulcn/engine\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\n\ninterface RecordOptions {\n url: string;\n output: string;\n browser: string;\n headless: boolean;\n}\n\nexport async function recordCommand(options: RecordOptions) {\n const spinner = ora(\"Starting browser...\").start();\n\n try {\n const session = await Recorder.start(options.url, {\n browser: options.browser as BrowserType,\n headless: options.headless,\n });\n\n spinner.succeed(\"Browser started\");\n console.log();\n console.log(chalk.cyan(\"🎬 Recording started\"));\n console.log(chalk.gray(` URL: ${options.url}`));\n console.log(chalk.gray(` Browser: ${options.browser}`));\n console.log();\n console.log(\n chalk.yellow(\" Interact with the browser to record actions.\"),\n );\n console.log(chalk.yellow(\" Press Ctrl+C to stop recording.\"));\n console.log();\n\n // Enable raw mode to intercept Ctrl+C before it becomes SIGINT\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n process.stdin.resume();\n process.stdin.setEncoding(\"utf8\");\n\n // Handle Ctrl+C gracefully\n let stopped = false;\n const stopRecording = async (): Promise<void> => {\n if (stopped) return;\n stopped = true;\n\n console.log();\n const saveSpinner = ora(\"Stopping recording...\").start();\n\n try {\n const result = await session.stop();\n const yaml = serializeSession(result);\n await writeFile(options.output, yaml, \"utf-8\");\n\n saveSpinner.succeed(`Session saved to ${chalk.green(options.output)}`);\n console.log();\n console.log(chalk.cyan(`📝 Recorded ${result.steps.length} steps`));\n console.log();\n console.log(chalk.gray(\"To run with payloads:\"));\n console.log(\n chalk.white(` vulcn run ${options.output} --payload xss-basic`),\n );\n } catch (err) {\n saveSpinner.fail(\"Failed to save session\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n };\n\n // Use a promise-based approach to handle signals properly\n await new Promise<void>((resolve) => {\n const handleStop = () => {\n // Remove all handlers to prevent double-handling\n process.stdin.removeAllListeners(\"data\");\n process.off(\"SIGINT\", handleStop);\n process.off(\"SIGTERM\", handleStop);\n\n stopRecording()\n .then(() => {\n resolve();\n })\n .catch((err) => {\n console.error(chalk.red(String(err)));\n process.exit(1);\n });\n };\n\n // Listen for Ctrl+C keypress (char code 0x03) in raw mode\n process.stdin.on(\"data\", (key: string) => {\n if (key === \"\\u0003\") {\n handleStop();\n }\n });\n\n // Also handle SIGINT/SIGTERM for non-TTY or external signals\n process.on(\"SIGINT\", handleStop);\n process.on(\"SIGTERM\", handleStop);\n });\n } catch (err) {\n spinner.fail(\"Failed to start recording\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport {\n Runner,\n parseSession,\n type BrowserType,\n type PayloadName,\n} from \"@vulcn/engine\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\n\ninterface RunOptions {\n payload?: string[];\n browser: string;\n headless: boolean;\n}\n\nexport async function runCommand(sessionFile: string, options: RunOptions) {\n // Load session\n const loadSpinner = ora(\"Loading session...\").start();\n\n let sessionYaml: string;\n try {\n sessionYaml = await readFile(sessionFile, \"utf-8\");\n } catch {\n loadSpinner.fail(`Cannot read file: ${sessionFile}`);\n process.exit(1);\n }\n\n let session;\n try {\n session = parseSession(sessionYaml);\n loadSpinner.succeed(`Loaded session: ${chalk.cyan(session.name)}`);\n } catch (err) {\n loadSpinner.fail(\"Invalid session file\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n\n // Validate payloads\n const payloads = (options.payload ?? [\"xss-basic\"]) as PayloadName[];\n console.log();\n console.log(chalk.cyan(\"🔍 Running security tests\"));\n console.log(chalk.gray(` Session: ${session.name}`));\n console.log(chalk.gray(` Payloads: ${payloads.join(\", \")}`));\n console.log(chalk.gray(` Browser: ${options.browser}`));\n console.log(chalk.gray(` Headless: ${options.headless}`));\n console.log();\n\n const runSpinner = ora(\"Executing tests...\").start();\n\n try {\n const result = await Runner.execute(session, payloads, {\n browser: options.browser as BrowserType,\n headless: options.headless,\n onFinding: (finding) => {\n runSpinner.stop();\n console.log(chalk.red(`⚠️ FINDING: ${finding.title}`));\n console.log(chalk.gray(` Step: ${finding.stepId}`));\n console.log(\n chalk.gray(` Payload: ${finding.payload.slice(0, 50)}...`),\n );\n console.log(chalk.gray(` URL: ${finding.url}`));\n console.log();\n runSpinner.start(\"Continuing tests...\");\n },\n });\n\n runSpinner.succeed(\"Tests completed\");\n console.log();\n\n // Summary\n console.log(chalk.cyan(\"📊 Results\"));\n console.log(chalk.gray(` Steps executed: ${result.stepsExecuted}`));\n console.log(chalk.gray(` Payloads tested: ${result.payloadsTested}`));\n console.log(\n chalk.gray(` Duration: ${(result.duration / 1000).toFixed(1)}s`),\n );\n console.log();\n\n if (result.findings.length > 0) {\n console.log(chalk.red(`🚨 ${result.findings.length} findings detected!`));\n console.log();\n for (const finding of result.findings) {\n const severityColor =\n finding.severity === \"critical\" || finding.severity === \"high\"\n ? chalk.red\n : finding.severity === \"medium\"\n ? chalk.yellow\n : chalk.gray;\n\n console.log(\n severityColor(`[${finding.severity.toUpperCase()}] ${finding.title}`),\n );\n console.log(chalk.gray(` Type: ${finding.type}`));\n console.log(chalk.gray(` Step: ${finding.stepId}`));\n console.log(chalk.gray(` URL: ${finding.url}`));\n console.log(chalk.gray(` Payload: ${finding.payload}`));\n console.log();\n }\n process.exit(1); // Non-zero exit for CI/CD\n } else {\n console.log(chalk.green(\"✅ No vulnerabilities detected\"));\n }\n\n if (result.errors.length > 0) {\n console.log();\n console.log(\n chalk.yellow(`⚠️ ${result.errors.length} errors during execution:`),\n );\n for (const err of result.errors.slice(0, 5)) {\n console.log(chalk.gray(` - ${err}`));\n }\n if (result.errors.length > 5) {\n console.log(chalk.gray(` ... and ${result.errors.length - 5} more`));\n }\n }\n } catch (err) {\n runSpinner.fail(\"Test execution failed\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","import { BUILTIN_PAYLOADS } from \"@vulcn/engine\";\nimport chalk from \"chalk\";\n\nexport async function payloadsCommand() {\n console.log();\n console.log(chalk.cyan(\"📦 Available Payloads\"));\n console.log();\n\n const payloads = Object.values(BUILTIN_PAYLOADS);\n\n for (const payload of payloads) {\n console.log(chalk.white(` ${payload.name}`));\n console.log(chalk.gray(` Category: ${payload.category}`));\n console.log(chalk.gray(` ${payload.description}`));\n console.log(chalk.gray(` Payloads: ${payload.payloads.length}`));\n console.log();\n }\n\n console.log(chalk.gray(\"Usage:\"));\n console.log(chalk.white(\" vulcn run session.vulcn.yml --payload xss-basic\"));\n}\n","import { installBrowsers, checkBrowsers, type BrowserType } from \"@vulcn/engine\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\n\nexport async function installCommand(\n browsers?: string[],\n options?: { all?: boolean },\n) {\n // Determine which browsers to install\n let browsersToInstall: BrowserType[];\n\n if (options?.all) {\n browsersToInstall = [\"chromium\", \"firefox\", \"webkit\"];\n } else if (browsers && browsers.length > 0) {\n browsersToInstall = browsers as BrowserType[];\n } else {\n browsersToInstall = [\"chromium\"];\n }\n\n console.log();\n console.log(chalk.cyan(\"🔧 Installing browsers for Vulcn\"));\n console.log();\n\n try {\n await installBrowsers(browsersToInstall);\n console.log();\n console.log(chalk.green(\"✅ Browsers installed successfully\"));\n } catch (err) {\n console.error(chalk.red(\"Failed to install browsers:\"), err);\n process.exit(1);\n }\n}\n\nexport async function doctorCommand() {\n console.log();\n console.log(chalk.cyan(\"🩺 Vulcn Browser Check\"));\n console.log();\n\n const spinner = ora(\"Checking available browsers...\").start();\n\n try {\n const status = await checkBrowsers();\n spinner.stop();\n\n console.log(chalk.white(\"System Browsers:\"));\n console.log(\n ` Chrome: ${status.systemChrome ? chalk.green(\"✓ Available\") : chalk.gray(\"✗ Not found\")}`,\n );\n console.log(\n ` Edge: ${status.systemEdge ? chalk.green(\"✓ Available\") : chalk.gray(\"✗ Not found\")}`,\n );\n console.log();\n\n console.log(chalk.white(\"Playwright Browsers:\"));\n console.log(\n ` Chromium: ${status.playwrightChromium ? chalk.green(\"✓ Installed\") : chalk.gray(\"✗ Not installed\")}`,\n );\n console.log(\n ` Firefox: ${status.playwrightFirefox ? chalk.green(\"✓ Installed\") : chalk.gray(\"✗ Not installed\")}`,\n );\n console.log(\n ` WebKit: ${status.playwrightWebkit ? chalk.green(\"✓ Installed\") : chalk.gray(\"✗ Not installed\")}`,\n );\n console.log();\n\n // Recommendation\n if (status.systemChrome || status.systemEdge) {\n console.log(\n chalk.green(\"✅ Ready to use! Vulcn will use your system browser.\"),\n );\n } else if (status.playwrightChromium) {\n console.log(\n chalk.green(\"✅ Ready to use! Vulcn will use Playwright Chromium.\"),\n );\n } else {\n console.log(chalk.yellow(\"⚠️ No browsers found.\"));\n console.log();\n console.log(chalk.white(\"Options:\"));\n console.log(chalk.gray(\" 1. Install Google Chrome (recommended)\"));\n console.log(chalk.gray(\" 2. Run: vulcn install\"));\n }\n } catch (err) {\n spinner.fail(\"Failed to check browsers\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["chalk","ora","chalk","chalk","ora"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vulcn",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Security testing CLI - Record once, test with payloads, find vulnerabilities",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"vulcn": "./vulcn.mjs"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"vulcn.mjs",
|
|
13
|
+
"CHANGELOG.md",
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"dev": "tsup --watch",
|
|
20
|
+
"clean": "rm -rf dist vulcn.mjs LICENSE README.md CHANGELOG.md",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"prepack": "cp ../vulcn.mjs ../LICENSE ../README.md ../CHANGELOG.md .",
|
|
23
|
+
"postpack": "rm -f vulcn.mjs LICENSE README.md CHANGELOG.md",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"vulcn",
|
|
28
|
+
"security",
|
|
29
|
+
"testing",
|
|
30
|
+
"cli",
|
|
31
|
+
"recorder",
|
|
32
|
+
"xss",
|
|
33
|
+
"sql-injection",
|
|
34
|
+
"penetration-testing",
|
|
35
|
+
"pentest",
|
|
36
|
+
"vulnerability",
|
|
37
|
+
"scanner",
|
|
38
|
+
"playwright",
|
|
39
|
+
"browser",
|
|
40
|
+
"automation"
|
|
41
|
+
],
|
|
42
|
+
"author": "rawlab",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/rawlab-dev/vulcn.git",
|
|
47
|
+
"directory": "cli"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://rawlab.dev/vulcn",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/rawlab-dev/vulcn/issues"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18.0.0"
|
|
55
|
+
},
|
|
56
|
+
"os": [
|
|
57
|
+
"darwin",
|
|
58
|
+
"linux",
|
|
59
|
+
"win32"
|
|
60
|
+
],
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@vulcn/engine": "workspace:*",
|
|
66
|
+
"commander": "^13.1.0",
|
|
67
|
+
"chalk": "^5.4.0",
|
|
68
|
+
"ora": "^8.2.0"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"typescript": "^5.7.0",
|
|
72
|
+
"tsup": "^8.4.0",
|
|
73
|
+
"@types/node": "^22.0.0"
|
|
74
|
+
}
|
|
75
|
+
}
|
package/vulcn.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import module from "node:module";
|
|
4
|
+
|
|
5
|
+
// Enable Node.js module compile cache for faster startup
|
|
6
|
+
// https://nodejs.org/api/module.html#module-compile-cache
|
|
7
|
+
if (module.enableCompileCache && !process.env.NODE_DISABLE_COMPILE_CACHE) {
|
|
8
|
+
try {
|
|
9
|
+
module.enableCompileCache();
|
|
10
|
+
} catch {
|
|
11
|
+
// Ignore errors (older Node versions)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
await import("./cli/dist/index.js");
|