@carlos-burelo/wyrm 1.0.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 +242 -0
- package/bin/cli.js +28 -0
- package/package.json +38 -0
- package/scripts/install.js +123 -0
package/README.md
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Wyrm 🐉
|
|
2
|
+
|
|
3
|
+
**Wyrm** es un gestor de procesos de ultra alto rendimiento escrito en **Rust**, enfocado en **Windows Server**. Mantiene aplicaciones Node.js, Next.js, Astro y Express corriendo como Servicio de Windows nativo con Zero-Config.
|
|
4
|
+
|
|
5
|
+
- Supervisor real con `JobObjects` (`KILL_ON_JOB_CLOSE`), auto-restart con backoff y restore al arrancar.
|
|
6
|
+
- IPC por Named Pipe con protocolo tipado `Request/Response` NDJSON.
|
|
7
|
+
- CLI completa: `start/stop/restart/delete/list/status/logs/daemon/top/service`.
|
|
8
|
+
- TUI de primer nivel con Ratatui: lista, métricas CPU/MEM, logs en vivo, filtro y acciones.
|
|
9
|
+
- Logs por app en `%ProgramData%\wyrm\logs\<name>.log`.
|
|
10
|
+
- DB SQLite en `%ProgramData%\wyrm\wyrm.db`.
|
|
11
|
+
|
|
12
|
+
## Instalación
|
|
13
|
+
|
|
14
|
+
```powershell
|
|
15
|
+
npm install -g @carlos-burelo/wyrm
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
O desde fuente:
|
|
19
|
+
|
|
20
|
+
```powershell
|
|
21
|
+
cargo build --release
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quickstart
|
|
25
|
+
|
|
26
|
+
```powershell
|
|
27
|
+
# En tu proyecto Node (auto-detecta package.json, .next/standalone, Astro, pnpm/yarn/bun)
|
|
28
|
+
wyrm start
|
|
29
|
+
|
|
30
|
+
# Ver estado (funciona con o sin demonio)
|
|
31
|
+
wyrm list
|
|
32
|
+
|
|
33
|
+
# Demonio en foreground (dev)
|
|
34
|
+
wyrm daemon
|
|
35
|
+
|
|
36
|
+
# TUI interactiva
|
|
37
|
+
wyrm top
|
|
38
|
+
# o simplemente:
|
|
39
|
+
wyrm
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Con demonio corriendo:
|
|
43
|
+
|
|
44
|
+
```powershell
|
|
45
|
+
wyrm stop mi-app
|
|
46
|
+
wyrm restart mi-app
|
|
47
|
+
wyrm status mi-app
|
|
48
|
+
wyrm logs mi-app --lines 100
|
|
49
|
+
wyrm logs mi-app --follow
|
|
50
|
+
wyrm delete mi-app --yes
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Multi-app con ecosystem file:
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
wyrm init # genera wyrm.json del proyecto actual
|
|
57
|
+
wyrm start --all # levanta todas las apps (wyrm.json o ecosystem.json)
|
|
58
|
+
wyrm start --all --file ./prod.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`wyrm.json`:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{ "apps": [{ "name": "web", "cwd": ".", "env": { "PORT": "3000" } }] }
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`executable`/`args` opcionales: si faltan se auto-detectan. `cwd` relativo
|
|
68
|
+
al archivo. El `env` del archivo gana sobre `.env`.
|
|
69
|
+
|
|
70
|
+
Políticas por app (`policy: {...}` en `wyrm.json` o payload `START`):
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"policy": {
|
|
75
|
+
"max_restarts": 10,
|
|
76
|
+
"min_uptime_secs": 5,
|
|
77
|
+
"stop_timeout_secs": 5,
|
|
78
|
+
"max_memory_mb": 512,
|
|
79
|
+
"healthcheck_url": "http://127.0.0.1:3000/health",
|
|
80
|
+
"healthcheck_secs": 30
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- Salir antes de `min_uptime_secs` suma crash-loop; al llegar a
|
|
86
|
+
`max_restarts` la app queda `ERRORED` (requiere `wyrm restart` manual).
|
|
87
|
+
- `max_memory_mb` reinicia al superar la RSS; `healthcheck_url` con 3 fallos
|
|
88
|
+
seguidos mata el proceso para que el supervisor lo reinicie.
|
|
89
|
+
- Logs rotan a 10 MiB conservando 5 históricos (`app.log.1…5`).
|
|
90
|
+
- No se persisten en SQLite (solo vive en ecosystem/`START`; el restore usa
|
|
91
|
+
defaults). En Windows el stop es terminate (CTRL+BREAK elegante: futuro).
|
|
92
|
+
|
|
93
|
+
Diagnóstico:
|
|
94
|
+
|
|
95
|
+
```powershell
|
|
96
|
+
wyrm doctor # node, demonio, servicio, DB, disco, logs + hints
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Deploy (git + hooks)
|
|
100
|
+
|
|
101
|
+
```powershell
|
|
102
|
+
wyrm deploy <app> [--ref main] # pre hook → git sync → post hook → restart
|
|
103
|
+
wyrm releases <app> [--limit 10]
|
|
104
|
+
wyrm rollback <app> # git reset al último deploy ok + restart
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Hooks en `wyrm.json` por app: `pre_deploy` / `post_deploy` (shell `cmd /C`).
|
|
108
|
+
Historial en SQLite (`deploys`).
|
|
109
|
+
|
|
110
|
+
## API local + métricas (plano de control)
|
|
111
|
+
|
|
112
|
+
El demonio sirve `http://127.0.0.1:8379` (`WYRM_API_ADDR`, off con
|
|
113
|
+
`WYRM_NO_API=1`). Auth Bearer con token en `%ProgramData%\wyrm\token`:
|
|
114
|
+
|
|
115
|
+
```powershell
|
|
116
|
+
wyrm token # muestra el token
|
|
117
|
+
wyrm token --rotate
|
|
118
|
+
curl -H "Authorization: Bearer $t" http://127.0.0.1:8379/apps
|
|
119
|
+
curl -H "Authorization: Bearer $t" http://127.0.0.1:8379/metrics # Prometheus
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Endpoints: `GET /health` (público), `GET /apps`, `GET /apps/:name`,
|
|
123
|
+
`POST /apps/:name/{start,stop,restart}`, `GET /metrics`
|
|
124
|
+
(`wyrm_app_up/uptime/restarts/cpu/memory`).
|
|
125
|
+
|
|
126
|
+
## Edge + TLS (mini-PAAS)
|
|
127
|
+
|
|
128
|
+
```powershell
|
|
129
|
+
wyrm route add <host> <http://127.0.0.1:3000>
|
|
130
|
+
wyrm route list / wyrm route rm <host>
|
|
131
|
+
wyrm edge # :80 (WYRM_EDGE_PORT) + :443 SNI (WYRM_EDGE_TLS_PORT, 0=off)
|
|
132
|
+
wyrm cert issue <host> [--staging|--prod] [--email x@y] # requiere edge en :80
|
|
133
|
+
wyrm cert selfsigned <host> # solo dev
|
|
134
|
+
wyrm cert list / wyrm cert renew [--force]
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`wyrm.json` acepta `routes: [{host, target}]` (se aplican con `start --all`).
|
|
138
|
+
TLS con SNI + wildcard, recarga de certs cada 60s. Proxy HTTP bufferizado
|
|
139
|
+
(16 MB, sin websockets todavía).
|
|
140
|
+
|
|
141
|
+
Servicio Windows (producción):
|
|
142
|
+
|
|
143
|
+
```powershell
|
|
144
|
+
wyrm service install
|
|
145
|
+
wyrm service uninstall
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## TUI (`wyrm top`) — mejor que `pm2 monit`
|
|
149
|
+
|
|
150
|
+
Dashboard dos paneles: lista + detalle + sparklines CPU/MEM + preview logs.
|
|
151
|
+
Tabs `1/2/3` o `tab` para Dashboard / Logs / Help.
|
|
152
|
+
|
|
153
|
+
| Tecla | Acción |
|
|
154
|
+
|---|---|
|
|
155
|
+
| `1/2/3`, `tab` | cambiar tab |
|
|
156
|
+
| `j/k` o `↑/↓` | navegar apps o scroll logs |
|
|
157
|
+
| `enter` / `l` | ver logs full de la app |
|
|
158
|
+
| `r` | restart |
|
|
159
|
+
| `s` / `S` | stop / start (revive STOPPED desde DB, sin cwd) |
|
|
160
|
+
| `o` | ciclo orden: nombre → cpu → mem → uptime → restarts |
|
|
161
|
+
| `d` luego `y` | delete con confirmación |
|
|
162
|
+
| `/` | filtrar apps o buscar en logs |
|
|
163
|
+
| `f` / `G` | follow on/off / ir al final en logs |
|
|
164
|
+
| `F` luego `y` | vaciar log actual |
|
|
165
|
+
| `?` | ayuda |
|
|
166
|
+
| `q` / `esc` | salir o volver |
|
|
167
|
+
|
|
168
|
+
Logs con colores por nivel (error rojo, warn amarillo, ok/ready verde) y
|
|
169
|
+
resaltado de búsqueda. Header con demonio, CPU global, MEM y conteo running.
|
|
170
|
+
Detalle con pid, executable, cwd, log path y gauge de MEM del sistema.
|
|
171
|
+
|
|
172
|
+
## Arquitectura
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
CLI (clap) ──Named Pipe NDJSON──> Daemon
|
|
176
|
+
│ ├─ HashMap<String, ManagedApp>
|
|
177
|
+
│ ├─ JobObject por proceso
|
|
178
|
+
│ ├─ logs a archivo (append)
|
|
179
|
+
│ └─ supervise loop cada 2s + backoff
|
|
180
|
+
└─ fallback DB (SQLite) si demonio off
|
|
181
|
+
|
|
182
|
+
crates/wyrm/src:
|
|
183
|
+
main.rs bootstrap (16 líneas)
|
|
184
|
+
api/ HTTP 127.0.0.1:8379 + token + /metrics Prometheus
|
|
185
|
+
cli/ args + start/manage/list/status/logs/init/deploy/token/route/cert/doctor
|
|
186
|
+
ecosystem/ wyrm.json multi-app (+routes, hooks, policy)
|
|
187
|
+
deploy/ hooks cmd.exe + git sync/reset
|
|
188
|
+
daemon/ state + supervisor + health loop
|
|
189
|
+
edge/ proxy host→target + acme HTTP-01 + tls SNI
|
|
190
|
+
ipc/ pipe + protocol Request/Response
|
|
191
|
+
store/ SQLite (apps, deploys, routes) + paths
|
|
192
|
+
runtime/ inspector/policy/process/service Windows
|
|
193
|
+
logs/ read/tail/flush/rotate compartido cli+tui
|
|
194
|
+
tui/ state/data/actions/events/theme/views
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Límites conocidos (honestos)
|
|
198
|
+
|
|
199
|
+
- **ACME real sin probar E2E**: `cert issue --prod` requiere DNS público
|
|
200
|
+
apuntando al servidor + `wyrm edge` en :80. Usa `--staging` primero.
|
|
201
|
+
- **Proxy HTTP bufferizado**: sin websockets, cuerpo máximo 16 MB.
|
|
202
|
+
- **Expiración de certs estimada**: `meta.json` asume 90 días (no parse X.509).
|
|
203
|
+
- **Stop en Windows = terminate**: `stop_timeout_secs` es ventana de espera;
|
|
204
|
+
CTRL+BREAK elegante queda futuro.
|
|
205
|
+
- **Policies fuera de SQLite**: viven en `wyrm.json`/payload `START`;
|
|
206
|
+
el restore tras reinicio usa defaults.
|
|
207
|
+
- **API solo loopback** (`127.0.0.1:8379`); el token vive en archivo con los
|
|
208
|
+
permisos del FS del SO.
|
|
209
|
+
- **Single-node**: un demonio por pipe, sin clustering multi-máquina.
|
|
210
|
+
- **Primer release solo x64 Windows** (sin binario ARM64).
|
|
211
|
+
- **Healthcheck TLS** con roots embebidos (sin CAs corporativas custom).
|
|
212
|
+
|
|
213
|
+
## Release (mantenedores)
|
|
214
|
+
|
|
215
|
+
Todo automático al pushear un tag `vX.Y.Z`:
|
|
216
|
+
|
|
217
|
+
```powershell
|
|
218
|
+
git tag v0.1.0
|
|
219
|
+
git push origin v0.1.0
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
CI hace: `cargo test` → build x64 release → GitHub Release con
|
|
223
|
+
`wyrm-x86_64-pc-windows-msvc.exe` + `.sha256` → sync de versión en
|
|
224
|
+
`npm/package.json` → `npm publish`. El `postinstall` descarga el asset de
|
|
225
|
+
tu misma versión y verifica SHA256.
|
|
226
|
+
|
|
227
|
+
Requisitos: secret `NPM_TOKEN` en el repo. Verificación local previa:
|
|
228
|
+
|
|
229
|
+
```powershell
|
|
230
|
+
cargo test -p wyrm
|
|
231
|
+
node --check npm/scripts/install.js
|
|
232
|
+
npm pack --dry-run # en npm/: confirma 4 archivos, sin vendor/
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Desarrollo
|
|
236
|
+
|
|
237
|
+
```powershell
|
|
238
|
+
cargo check -p wyrm
|
|
239
|
+
cargo test -p wyrm
|
|
240
|
+
cargo fmt
|
|
241
|
+
cargo clippy -p wyrm
|
|
242
|
+
```
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { spawn } = require('child_process');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const binPath = path.join(__dirname, '..', 'vendor', 'wyrm.exe');
|
|
8
|
+
|
|
9
|
+
if (!fs.existsSync(binPath)) {
|
|
10
|
+
console.error(
|
|
11
|
+
'[wyrm] Falta vendor/wyrm.exe. Reinstala (npm i -g @carlos-burelo/wyrm) o compila local con `npm run build`.'
|
|
12
|
+
);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const child = spawn(binPath, process.argv.slice(2), {
|
|
17
|
+
stdio: 'inherit',
|
|
18
|
+
windowsHide: true,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
child.on('error', (err) => {
|
|
22
|
+
console.error(`[wyrm] No se pudo lanzar el binario: ${err.message}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
child.on('exit', (code) => {
|
|
27
|
+
process.exit(code || 0);
|
|
28
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@carlos-burelo/wyrm",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "El gestor de procesos definitivo para Windows Server escrito en Rust",
|
|
5
|
+
"main": "bin/cli.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"bin/",
|
|
8
|
+
"scripts/",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"bin": {
|
|
12
|
+
"wyrm": "bin/cli.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"postinstall": "node scripts/install.js"
|
|
16
|
+
},
|
|
17
|
+
"os": [
|
|
18
|
+
"win32"
|
|
19
|
+
],
|
|
20
|
+
"cpu": [
|
|
21
|
+
"x64"
|
|
22
|
+
],
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/carlos-burelo/wyrm.git"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"wyrm",
|
|
29
|
+
"pm2",
|
|
30
|
+
"windows-server",
|
|
31
|
+
"rust",
|
|
32
|
+
"process-manager",
|
|
33
|
+
"nextjs",
|
|
34
|
+
"astro"
|
|
35
|
+
],
|
|
36
|
+
"author": "Carlos Burelo",
|
|
37
|
+
"license": "MIT"
|
|
38
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Postinstall de wyrm: deja vendor/wyrm.exe listo.
|
|
2
|
+
// - Versión desde package.json (la sincroniza el workflow de release).
|
|
3
|
+
// - Salta si ya hay binario local (npm run build) o WYRM_SKIP_DOWNLOAD.
|
|
4
|
+
// - Verifica SHA256 del asset .sha256 cuando existe.
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const https = require('https');
|
|
8
|
+
const crypto = require('crypto');
|
|
9
|
+
|
|
10
|
+
const REPO = 'carlos-burelo/wyrm';
|
|
11
|
+
const BIN_DIR = path.join(__dirname, '..', 'vendor');
|
|
12
|
+
const BIN_NAME = 'wyrm.exe';
|
|
13
|
+
const BIN_PATH = path.join(BIN_DIR, BIN_NAME);
|
|
14
|
+
|
|
15
|
+
const TARGETS = {
|
|
16
|
+
'win32-x64': 'x86_64-pc-windows-msvc',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function pkgVersion() {
|
|
20
|
+
const { version } = require('../package.json');
|
|
21
|
+
if (!version) throw new Error('package.json sin version');
|
|
22
|
+
return String(version).replace(/^v/, '');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function targetTriple(platform = process.platform, arch = process.arch) {
|
|
26
|
+
const triple = TARGETS[`${platform}-${arch}`];
|
|
27
|
+
if (!triple) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Plataforma no soportada: ${platform}-${arch} (wyrm v1 solo publica win32-x64)`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return triple;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function assetName(triple) {
|
|
36
|
+
return `wyrm-${triple}.exe`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function download(url, dest, redirects = 5) {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
https
|
|
42
|
+
.get(url, (res) => {
|
|
43
|
+
const { statusCode, headers } = res;
|
|
44
|
+
if ((statusCode === 301 || statusCode === 302) && headers.location) {
|
|
45
|
+
if (redirects <= 0) return reject(new Error('demasiadas redirecciones'));
|
|
46
|
+
res.resume();
|
|
47
|
+
return resolve(download(headers.location, dest, redirects - 1));
|
|
48
|
+
}
|
|
49
|
+
if (statusCode !== 200) {
|
|
50
|
+
res.resume();
|
|
51
|
+
return reject(new Error(`HTTP ${statusCode} en ${url}`));
|
|
52
|
+
}
|
|
53
|
+
const file = fs.createWriteStream(dest);
|
|
54
|
+
res.pipe(file);
|
|
55
|
+
file.on('finish', () => file.close(resolve));
|
|
56
|
+
file.on('error', reject);
|
|
57
|
+
})
|
|
58
|
+
.on('error', reject);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function sha256File(p) {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
const h = crypto.createHash('sha256');
|
|
65
|
+
fs.createReadStream(p)
|
|
66
|
+
.on('data', (d) => h.update(d))
|
|
67
|
+
.on('end', () => resolve(h.digest('hex')))
|
|
68
|
+
.on('error', reject);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function install() {
|
|
73
|
+
if (process.env.WYRM_SKIP_DOWNLOAD) {
|
|
74
|
+
console.log('[wyrm] WYRM_SKIP_DOWNLOAD=1: salto la descarga.');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (fs.existsSync(BIN_PATH)) {
|
|
78
|
+
console.log('[wyrm] Binario local existente, salto la descarga.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const version = pkgVersion();
|
|
82
|
+
const triple = targetTriple();
|
|
83
|
+
const base = `https://github.com/${REPO}/releases/download/v${version}`;
|
|
84
|
+
const asset = assetName(triple);
|
|
85
|
+
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
86
|
+
|
|
87
|
+
console.log(`[wyrm] Descargando ${asset} v${version}...`);
|
|
88
|
+
try {
|
|
89
|
+
await download(`${base}/${asset}`, BIN_PATH);
|
|
90
|
+
} catch (e) {
|
|
91
|
+
try {
|
|
92
|
+
fs.unlinkSync(BIN_PATH);
|
|
93
|
+
} catch (_) {}
|
|
94
|
+
throw new Error(
|
|
95
|
+
`No se pudo descargar el binario (${e.message}). ¿Existe el release v${version}?`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
await download(`${base}/${asset}.sha256`, `${BIN_PATH}.sha256`);
|
|
101
|
+
const expected = fs.readFileSync(`${BIN_PATH}.sha256`, 'utf8').trim().toLowerCase();
|
|
102
|
+
const actual = await sha256File(BIN_PATH);
|
|
103
|
+
if (expected !== actual) {
|
|
104
|
+
fs.unlinkSync(BIN_PATH);
|
|
105
|
+
throw new Error('SHA256 no coincide: binario corrupto o manipulado.');
|
|
106
|
+
}
|
|
107
|
+
fs.unlinkSync(`${BIN_PATH}.sha256`);
|
|
108
|
+
console.log('[wyrm] SHA256 verificado.');
|
|
109
|
+
} catch (e) {
|
|
110
|
+
if (/corrupto|manipulado/.test(e.message)) throw e;
|
|
111
|
+
console.warn(`[wyrm] Aviso: sin checksum (${e.message}), continúo sin verificar.`);
|
|
112
|
+
}
|
|
113
|
+
console.log('[wyrm] Instalación nativa completada.');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (require.main === module) {
|
|
117
|
+
install().catch((e) => {
|
|
118
|
+
console.error(`[wyrm] ${e.message}`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = { pkgVersion, targetTriple, assetName, REPO, BIN_PATH };
|