viberun 0.0.1 → 0.3.5

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.
Files changed (49) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +379 -2
  3. package/bin/viberun.js +176 -0
  4. package/package.json +15 -88
  5. package/vendor/aarch64-apple-darwin/viberun/viberun +0 -0
  6. package/vendor/aarch64-pc-windows-msvc/viberun/viberun.exe +0 -0
  7. package/vendor/aarch64-unknown-linux-musl/viberun/viberun +0 -0
  8. package/vendor/x86_64-apple-darwin/viberun/viberun +0 -0
  9. package/vendor/x86_64-pc-windows-msvc/viberun/viberun.exe +0 -0
  10. package/vendor/x86_64-unknown-linux-musl/viberun/viberun +0 -0
  11. package/CHANGELOG.md +0 -5
  12. package/LICENSE.md +0 -21
  13. package/dist/cli/bin.d.ts +0 -0
  14. package/dist/cli/bin.js +0 -9
  15. package/dist/cli/bin.js.map +0 -1
  16. package/dist/cli/builder.d.ts +0 -18
  17. package/dist/cli/builder.js +0 -44
  18. package/dist/cli/builder.js.map +0 -1
  19. package/dist/cli/commands.d.ts +0 -10
  20. package/dist/cli/commands.js +0 -35
  21. package/dist/cli/commands.js.map +0 -1
  22. package/dist/cli/run.d.ts +0 -4
  23. package/dist/cli/run.js +0 -37
  24. package/dist/cli/run.js.map +0 -1
  25. package/dist/config/babelrc.d.ts +0 -27
  26. package/dist/config/babelrc.js +0 -47
  27. package/dist/config/babelrc.js.map +0 -1
  28. package/dist/config/webpack.common.d.ts +0 -13
  29. package/dist/config/webpack.common.js +0 -137
  30. package/dist/config/webpack.common.js.map +0 -1
  31. package/dist/config/webpack.dev.d.ts +0 -9
  32. package/dist/config/webpack.dev.js +0 -39
  33. package/dist/config/webpack.dev.js.map +0 -1
  34. package/dist/config/webpack.prod.d.ts +0 -5
  35. package/dist/config/webpack.prod.js +0 -63
  36. package/dist/config/webpack.prod.js.map +0 -1
  37. package/dist/config/webpack.profile.d.ts +0 -5
  38. package/dist/config/webpack.profile.js +0 -29
  39. package/dist/config/webpack.profile.js.map +0 -1
  40. package/dist/index.d.ts +0 -4
  41. package/dist/index.js +0 -11
  42. package/dist/index.js.map +0 -1
  43. package/dist/utils.d.ts +0 -3
  44. package/dist/utils.js +0 -27
  45. package/dist/utils.js.map +0 -1
  46. package/typings/global.d.ts +0 -2
  47. package/typings/script-ext-html-webpack-plugin.d.ts +0 -17
  48. package/typings/webpack-bundle-analyzer.d.ts +0 -45
  49. package/yarn.lock +0 -4937
package/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, AUTHORS
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -1,3 +1,380 @@
1
- # TypeScript Starter
1
+ <p align="center">
2
+ <img src="assets/viberun-logo.png" alt="viberun logo" width="320">
3
+ </p>
2
4
 
3
- Slim Boilerplate for TypeScript based projects.
5
+ # viberun
6
+
7
+ `viberun` is a CLI-first, agent-native app host. Run `viberun <app>` locally and get dropped into an agent session inside a persistent Ubuntu container on a remote host. App data is stored under `/home/viberun` and survives container restarts or image updates.
8
+
9
+ ## Quick start (end-to-end)
10
+
11
+ You need a local machine with `ssh` and a reachable Ubuntu host (VM or server) that you can SSH into with sudo access.
12
+
13
+ ### 1) Install the CLI
14
+
15
+ ```bash
16
+ curl -fsSL https://viberun.sh | bash
17
+ ```
18
+
19
+ Verify:
20
+
21
+ ```bash
22
+ viberun --version
23
+ ```
24
+
25
+ Optional overrides (advanced):
26
+
27
+ ```bash
28
+ curl -fsSL https://viberun.sh | bash -s -- --nightly
29
+ curl -fsSL https://viberun.sh | bash -s -- --dir ~/.local/bin --bin viberun
30
+ ```
31
+
32
+ Or with env vars:
33
+
34
+ ```bash
35
+ curl -fsSL https://viberun.sh | VIBERUN_INSTALL_DIR=~/.local/bin VIBERUN_INSTALL_BIN=viberun bash
36
+ ```
37
+
38
+ ### 2) Bootstrap a host (once per VM)
39
+
40
+ Use any SSH host alias (for example, `myhost` in `~/.ssh/config`):
41
+
42
+ ```bash
43
+ viberun bootstrap myhost
44
+ ```
45
+
46
+ Optional: set it as your default host (and agent) so you can omit `@host` later:
47
+
48
+ ```bash
49
+ viberun config --host myhost --agent codex
50
+ ```
51
+
52
+ ### 3) Start your first app
53
+
54
+ ```bash
55
+ viberun hello-world
56
+ ```
57
+
58
+ If this is the first run, the server will prompt to create the container. Press Enter to accept.
59
+
60
+ Detach without stopping the agent: Ctrl-\\ . Reattach later with `viberun hello-world`.
61
+ Paste clipboard images into the session with Ctrl-V; `viberun` uploads the image and inserts a `/tmp/viberun-clip-*.png` path.
62
+
63
+ ### 4) Hello-world prompt (paste inside the session)
64
+
65
+ ```
66
+ Create a beautiful hello-world web app with a simple, tasteful landing page.
67
+ ```
68
+
69
+ ### 5) Open the app
70
+
71
+ While the session is active, `viberun` starts a localhost proxy to the host port. The agent will print a URL like:
72
+
73
+ ```
74
+ http://localhost:8080
75
+ ```
76
+
77
+ Open it in your browser.
78
+ If you've configured app URLs, `viberun <app> url` shows the HTTPS address.
79
+
80
+ ## Common commands
81
+
82
+ ```bash
83
+ viberun myapp
84
+ viberun myapp@hostb
85
+ viberun --forward-agent myapp
86
+ viberun myapp shell
87
+ viberun myapp snapshot
88
+ viberun myapp snapshots
89
+ viberun myapp restore latest
90
+ viberun myapp url
91
+ viberun myapp users
92
+ viberun myapp --delete -y
93
+ viberun myapp update
94
+ viberun bootstrap [<host>]
95
+ viberun proxy setup
96
+ viberun users list
97
+ viberun wipe
98
+ viberun config --host myhost --agent codex
99
+ viberun version
100
+ ```
101
+
102
+ <details>
103
+ <summary>Table of contents</summary>
104
+
105
+ - [Quick start (end-to-end)](#quick-start-end-to-end)
106
+ - [Common commands](#common-commands)
107
+ - [Git setup](#git-setup)
108
+ - [Development](#development)
109
+ - [Architecture](#architecture)
110
+ - [High-level flow](#high-level-flow)
111
+ - [Core components](#core-components)
112
+ - [Session lifecycle](#session-lifecycle)
113
+ - [Bootstrap pipeline](#bootstrap-pipeline)
114
+ - [Networking and ports](#networking-and-ports)
115
+ - [App URLs and proxy](#app-urls-and-proxy)
116
+ - [Snapshots and restore](#snapshots-and-restore)
117
+ - [Host RPC bridge](#host-rpc-bridge)
118
+ - [Configuration and state](#configuration-and-state)
119
+ - [Agents](#agents)
120
+ - [Security model](#security-model)
121
+ - [Wipe (safety)](#wipe-safety)
122
+ - [Repository layout](#repository-layout)
123
+ - [Troubleshooting](#troubleshooting)
124
+
125
+ </details>
126
+
127
+ ## Git setup
128
+
129
+ Git, SSH, and the GitHub CLI are installed in containers. viberun seeds `git config --global user.name` and `user.email` from your local Git config into a host-managed config file that is mounted into each app container and applied on startup. This removes the common "first commit" setup step without auto-authing you.
130
+
131
+ Choose one of these auth paths:
132
+
133
+ - **SSH (agent forwarding)**: Run `viberun --forward-agent <app>`. For existing apps, run `viberun <app> update` once to recreate the container with the agent socket mounted. Then `ssh -T git@github.com` inside the container to verify access.
134
+ - **HTTPS (GitHub CLI)**: Run `gh auth login` and choose HTTPS, then `gh auth setup-git`. Verify with `gh auth status`.
135
+
136
+ If you update your local Git identity later, restart the app container (or run `viberun <app> update`) to re-apply the new values on startup.
137
+
138
+ ## Development
139
+
140
+ This repo is Go-first and uses `mise` for tool and task orchestration.
141
+
142
+ ### Setup
143
+
144
+ ```bash
145
+ mise install
146
+ ```
147
+
148
+ ### Build
149
+
150
+ ```bash
151
+ mise exec -- go build ./cmd/viberun
152
+ mise exec -- go build ./cmd/viberun-server
153
+ ```
154
+
155
+ ### Run locally
156
+
157
+ ```bash
158
+ mise exec -- go run ./cmd/viberun -- --help
159
+ mise exec -- go run ./cmd/viberun-server -- --help
160
+ ```
161
+
162
+ ### Test and vet
163
+
164
+ ```bash
165
+ mise exec -- go test ./...
166
+ mise exec -- go vet ./...
167
+ ```
168
+
169
+ ### Container image
170
+
171
+ ```bash
172
+ mise run build:image
173
+ # fallback: docker build -t viberun .
174
+ # proxy image (Caddy + auth):
175
+ docker build -f Dockerfile.proxy -t viberun-proxy .
176
+ ```
177
+
178
+ ### E2E and integration
179
+
180
+ ```bash
181
+ bin/viberun-e2e-local
182
+ bin/viberun-integration
183
+ ```
184
+
185
+ ### Bootstrap in development
186
+
187
+ When you run `viberun` via `go run` (or a dev build), bootstrap defaults to staging the local server binary and building the container image locally. This is equivalent to:
188
+
189
+ ```bash
190
+ viberun bootstrap --local --local-image myhost
191
+ ```
192
+
193
+ Under the hood, it builds a `viberun:dev` image for the host architecture, streams it over `ssh` with `docker save | docker load`, and tags it as `viberun:latest` on the host.
194
+
195
+ If you want to explicitly pass a local server binary:
196
+
197
+ ```bash
198
+ mise exec -- go build -o /tmp/viberun-server ./cmd/viberun-server
199
+ viberun bootstrap --local-path /tmp/viberun-server myhost
200
+ ```
201
+
202
+ For the full build/test/E2E flow, see `DEVELOPMENT.md`.
203
+
204
+ ## Architecture
205
+
206
+ ### High-level flow
207
+
208
+ ```
209
+ viberun <app>
210
+ -> ssh <host>
211
+ -> viberun-server <app>
212
+ -> docker container viberun-<app>
213
+ -> agent session (tmux)
214
+
215
+ container port 8080
216
+ -> host port (assigned per app)
217
+ -> ssh -L localhost:<port>
218
+ -> http://localhost:<port>
219
+ -> (optional) host proxy (Caddy)
220
+ -> https://<app>.<domain>
221
+ ```
222
+
223
+ ### Core components
224
+
225
+ - Client: `viberun` CLI on your machine.
226
+ - Server: `viberun-server` executed on the host via SSH (no long-running daemon required).
227
+ - Container: `viberun-<app>` Docker container built from the `viberun:latest` image.
228
+ - Agent: runs inside the container in a tmux session (default provider: `codex`).
229
+ - Host RPC: local Unix socket used by the container to request snapshot/restore operations.
230
+ - Proxy (optional): `viberun-proxy` (Caddy + `viberun-auth`) for app URLs and login.
231
+
232
+ ### Session lifecycle
233
+
234
+ 1. `viberun <app>` resolves the host (from `@host` or your default config) and runs `viberun-server` over SSH.
235
+ 2. The server creates the container if needed, or starts it if it already exists.
236
+ 3. The agent process is attached via `docker exec` inside a tmux session so it persists across disconnects.
237
+ 4. `viberun` sets up a local port forward so you can open the app on `http://localhost:<port>`.
238
+
239
+ ### Bootstrap pipeline
240
+
241
+ The bootstrap script (run on the host) does the following:
242
+
243
+ - Verifies the host is Ubuntu.
244
+ - Installs Docker (if missing) and enables it.
245
+ - Installs Btrfs tools (`btrfs-progs`) for volume snapshots.
246
+ - Pulls the `viberun` container image from GHCR (unless using local image mode).
247
+ - Downloads and installs the `viberun-server` binary.
248
+
249
+ If bootstrap is run from a TTY, it will offer to set up a public domain name (same as `viberun proxy setup`).
250
+
251
+ Useful bootstrap overrides:
252
+
253
+ - `VIBERUN_SERVER_REPO`: GitHub repo for releases (default `shayne/viberun`).
254
+ - `VIBERUN_SERVER_VERSION`: release tag or `latest`.
255
+ - `VIBERUN_IMAGE`: container image override.
256
+ - `VIBERUN_PROXY_IMAGE`: proxy container image override (for app URLs).
257
+ - `VIBERUN_SERVER_INSTALL_DIR`: install directory on the host.
258
+ - `VIBERUN_SERVER_BIN`: server binary name on the host.
259
+ - `VIBERUN_SERVER_LOCAL_PATH`: use a local server binary staged over SSH.
260
+ - `VIBERUN_SKIP_IMAGE_PULL`: skip pulling from GHCR (used for local builds).
261
+
262
+ ### Networking and ports
263
+
264
+ - Each app container exposes port `8080` internally.
265
+ - The host port is assigned per app (starting at `8080`) and stored in the host server state.
266
+ - `viberun` opens an SSH local forward so `http://localhost:<port>` connects to the host port.
267
+ - If the proxy is configured, apps can also be served over HTTPS at `https://<app>.<domain>` (or a custom domain). Access requires login by default and can be made public per app.
268
+
269
+ ### App URLs and proxy
270
+
271
+ `viberun` can optionally expose apps via a host-side proxy (Caddy + `viberun-auth`).
272
+ Set it up once per host:
273
+
274
+ ```bash
275
+ viberun proxy setup [<host>]
276
+ ```
277
+
278
+ You'll be prompted for a base domain and public IP (for DNS), plus a primary username/password.
279
+ Create an A record (or wildcard) pointing to the host's public IP.
280
+
281
+ After setup:
282
+
283
+ - `viberun <app> url` shows the current URL and access status.
284
+ - `viberun <app> url --make-public` or `--require-login` toggles access (default requires login).
285
+ - `viberun <app> url --set-domain <domain>` or `--reset-domain` manages custom domains.
286
+ - `viberun <app> url --disable` or `--enable` turns the URL off/on.
287
+ - `viberun <app> url --open` opens the URL in your browser.
288
+ - `viberun users ...` manages login accounts; `viberun <app> users` controls who can access the app.
289
+
290
+ If URL settings change, run `viberun <app> update` to refresh `VIBERUN_PUBLIC_URL` and `VIBERUN_PUBLIC_DOMAIN` inside the container.
291
+
292
+ ### Snapshots and restore
293
+
294
+ Snapshots are Btrfs subvolume snapshots of the app's `/home/viberun` volume (auto-incremented versions).
295
+ On the host, each app uses a loop-backed Btrfs file under `/var/lib/viberun/apps/<app>/home.btrfs`.
296
+
297
+ - `viberun <app> snapshot` creates the next `vN` snapshot.
298
+ - `viberun <app> snapshots` lists versions with timestamps.
299
+ - `viberun <app> restore <vN|latest>` restores from a snapshot (`latest` picks the highest `vN`).
300
+ - `viberun <app> --delete -y` removes the container, the app volume + snapshots, and the host RPC directory.
301
+
302
+ Restore details:
303
+ - The host stops the container (if running) to safely unmount the volume.
304
+ - The current `@home` subvolume is replaced by a new writable snapshot of `@snapshots/vN`.
305
+ - The container is started again, and s6 reloads services from `/home/viberun/.local/services`.
306
+
307
+ ### Host RPC bridge
308
+
309
+ When you open a session, the server creates a Unix socket on the host and mounts it into the container at `/var/run/viberun-hostrpc`. The container uses it to request snapshot and restore operations. Access is protected by a per-session token file mounted alongside the socket.
310
+
311
+ ### Configuration and state
312
+
313
+ Local config lives at `~/.config/viberun/config.toml` (or `$XDG_CONFIG_HOME/viberun/config.toml`) and stores:
314
+
315
+ - `default_host`
316
+ - `agent_provider`
317
+ - `hosts` (alias mapping)
318
+
319
+ Host server state lives at `~/.config/viberun/server-state.json` (or `$XDG_CONFIG_HOME/viberun/server-state.json`) and stores the port mapping for each app.
320
+
321
+ Proxy config (when enabled) lives at `/var/lib/viberun/proxy.toml` (or `$VIBERUN_PROXY_CONFIG_PATH`) and stores the base domain, access rules, and users.
322
+ When enabled, the server injects `VIBERUN_PUBLIC_URL` and `VIBERUN_PUBLIC_DOMAIN` into containers.
323
+
324
+ ### Agents
325
+
326
+ Supported agent providers:
327
+
328
+ - `codex` (default)
329
+ - `claude`
330
+ - `gemini`
331
+ - `ampcode` (alias: `amp`)
332
+ - `opencode`
333
+
334
+ Custom agents can be run via `npx:<pkg>` or `uvx:<pkg>` (for example, `viberun --agent npx:@sourcegraph/amp@latest <app>`).
335
+
336
+ Set globally with `viberun config --agent <provider>` or per-run with `viberun --agent <provider> <app>`.
337
+ To forward your local SSH agent into the container, use `viberun --forward-agent <app>`. For existing apps, run `viberun <app> update` once to recreate the container with the agent socket mounted.
338
+
339
+ Base skills are shipped in `/opt/viberun/skills` and symlinked into each agent's skills directory. User skills can be added directly to the agent-specific skills directory under `/home/viberun`.
340
+
341
+ ### Security model
342
+
343
+ - All control traffic goes over SSH; the server is invoked on demand and does not expose a network port.
344
+ - The host RPC socket is local-only and protected by filesystem permissions and a per-session token.
345
+ - Containers are isolated by Docker and only the app port is exposed.
346
+ - App URLs are optional: the proxy requires login by default and can be made public per app with `viberun <app> url --make-public`.
347
+
348
+ ### Wipe (safety)
349
+
350
+ `viberun wipe [<host>]` deletes local config and wipes all viberun data on the host.
351
+ It requires a TTY and asks you to type `WIPE`.
352
+
353
+ On the host, wipe removes:
354
+
355
+ - All containers named `viberun-*`, any containers using `viberun` images, and the proxy container (default `viberun-proxy`).
356
+ - All `viberun` images (including the proxy image).
357
+ - App data and snapshots under `/var/lib/viberun` (including per-app Btrfs volumes).
358
+ - Host RPC sockets in `/tmp/viberun-hostrpc` and `/var/run/viberun-hostrpc`.
359
+ - `/etc/viberun`, `/etc/sudoers.d/viberun-server`, and `/usr/local/bin/viberun-server`.
360
+
361
+ Locally, it removes `~/.config/viberun/config.toml` (and legacy config if present).
362
+
363
+ ### Repository layout
364
+
365
+ - `cmd/`: Go entrypoints (`viberun`, `viberun-server`, `viberun-auth`).
366
+ - `internal/`: Core packages (config, server state, SSH args, target parsing, TUI helpers).
367
+ - `bin/`: Helper scripts for installs, integration/E2E flows, and container utilities.
368
+ - `skills/`: Codex skill definitions used inside containers.
369
+ - `config/`: Shell/TMUX/Starship config, auth assets, and runtime configs.
370
+ - `Dockerfile`: Base container image definition.
371
+ - `Dockerfile.proxy`: Proxy image definition (Caddy + auth).
372
+
373
+ ### Troubleshooting
374
+
375
+ - `unsupported OS: ... expected ubuntu`: bootstrap currently supports Ubuntu only.
376
+ - `docker is required but was not found in PATH`: install Docker on the host or re-run bootstrap.
377
+ - `missing btrfs on host`: rerun bootstrap to install `btrfs-progs` and ensure sudo access.
378
+ - `no host provided and no default host configured`: run `viberun config --host myhost` or use `myapp@host`.
379
+ - `container image architecture mismatch`: delete and recreate the app (`viberun <app> --delete -y`).
380
+ - `proxy is not configured`: run `viberun proxy setup` (then retry `viberun <app> url`).
package/bin/viberun.js ADDED
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env node
2
+ // Unified entry point for the viberun CLI.
3
+
4
+ import { spawn } from "node:child_process";
5
+ import { existsSync } from "fs";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
8
+
9
+ // __dirname equivalent in ESM
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ const { platform, arch } = process;
14
+
15
+ let targetTriple = null;
16
+ switch (platform) {
17
+ case "linux":
18
+ case "android":
19
+ switch (arch) {
20
+ case "x64":
21
+ targetTriple = "x86_64-unknown-linux-musl";
22
+ break;
23
+ case "arm64":
24
+ targetTriple = "aarch64-unknown-linux-musl";
25
+ break;
26
+ default:
27
+ break;
28
+ }
29
+ break;
30
+ case "darwin":
31
+ switch (arch) {
32
+ case "x64":
33
+ targetTriple = "x86_64-apple-darwin";
34
+ break;
35
+ case "arm64":
36
+ targetTriple = "aarch64-apple-darwin";
37
+ break;
38
+ default:
39
+ break;
40
+ }
41
+ break;
42
+ case "win32":
43
+ switch (arch) {
44
+ case "x64":
45
+ targetTriple = "x86_64-pc-windows-msvc";
46
+ break;
47
+ case "arm64":
48
+ targetTriple = "aarch64-pc-windows-msvc";
49
+ break;
50
+ default:
51
+ break;
52
+ }
53
+ break;
54
+ default:
55
+ break;
56
+ }
57
+
58
+ if (!targetTriple) {
59
+ throw new Error(`Unsupported platform: ${platform} (${arch})`);
60
+ }
61
+
62
+ const vendorRoot = path.join(__dirname, "..", "vendor");
63
+ const archRoot = path.join(vendorRoot, targetTriple);
64
+ const viberunBinaryName = process.platform === "win32" ? "viberun.exe" : "viberun";
65
+ const binaryPath = path.join(archRoot, "viberun", viberunBinaryName);
66
+
67
+ // Use an asynchronous spawn instead of spawnSync so that Node is able to
68
+ // respond to signals (e.g. Ctrl-C / SIGINT) while the native binary is
69
+ // executing. This allows us to forward those signals to the child process
70
+ // and guarantees that when either the child terminates or the parent
71
+ // receives a fatal signal, both processes exit in a predictable manner.
72
+
73
+ function getUpdatedPath(newDirs) {
74
+ const pathSep = process.platform === "win32" ? ";" : ":";
75
+ const existingPath = process.env.PATH || "";
76
+ const updatedPath = [
77
+ ...newDirs,
78
+ ...existingPath.split(pathSep).filter(Boolean),
79
+ ].join(pathSep);
80
+ return updatedPath;
81
+ }
82
+
83
+ /**
84
+ * Use heuristics to detect the package manager that was used to install viberun
85
+ * in order to give the user a hint about how to update it.
86
+ */
87
+ function detectPackageManager() {
88
+ const userAgent = process.env.npm_config_user_agent || "";
89
+ if (/\bbun\//.test(userAgent)) {
90
+ return "bun";
91
+ }
92
+
93
+ const execPath = process.env.npm_execpath || "";
94
+ if (execPath.includes("bun")) {
95
+ return "bun";
96
+ }
97
+
98
+ if (
99
+ __dirname.includes(".bun/install/global") ||
100
+ __dirname.includes(".bun\\install\\global")
101
+ ) {
102
+ return "bun";
103
+ }
104
+
105
+ return userAgent ? "npm" : null;
106
+ }
107
+
108
+ const additionalDirs = [];
109
+ const pathDir = path.join(archRoot, "path");
110
+ if (existsSync(pathDir)) {
111
+ additionalDirs.push(pathDir);
112
+ }
113
+ const updatedPath = getUpdatedPath(additionalDirs);
114
+
115
+ const env = { ...process.env, PATH: updatedPath };
116
+ const packageManagerEnvVar =
117
+ detectPackageManager() === "bun"
118
+ ? "VIBERUN_MANAGED_BY_BUN"
119
+ : "VIBERUN_MANAGED_BY_NPM";
120
+ env[packageManagerEnvVar] = "1";
121
+
122
+ const child = spawn(binaryPath, process.argv.slice(2), {
123
+ stdio: "inherit",
124
+ env,
125
+ });
126
+
127
+ child.on("error", (err) => {
128
+ // Typically triggered when the binary is missing or not executable.
129
+ // Re-throwing here will terminate the parent with a non-zero exit code
130
+ // while still printing a helpful stack trace.
131
+ // eslint-disable-next-line no-console
132
+ console.error(err);
133
+ process.exit(1);
134
+ });
135
+
136
+ // Forward common termination signals to the child so that it shuts down
137
+ // gracefully. In the handler we temporarily disable the default behavior of
138
+ // exiting immediately; once the child has been signaled we simply wait for
139
+ // its exit event which will in turn terminate the parent (see below).
140
+ const forwardSignal = (signal) => {
141
+ if (child.killed) {
142
+ return;
143
+ }
144
+ try {
145
+ child.kill(signal);
146
+ } catch {
147
+ /* ignore */
148
+ }
149
+ };
150
+
151
+ ["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => {
152
+ process.on(sig, () => forwardSignal(sig));
153
+ });
154
+
155
+ // When the child exits, mirror its termination reason in the parent so that
156
+ // shell scripts and other tooling observe the correct exit status.
157
+ // Wrap the lifetime of the child process in a Promise so that we can await
158
+ // its termination in a structured way. The Promise resolves with an object
159
+ // describing how the child exited: either via exit code or due to a signal.
160
+ const childResult = await new Promise((resolve) => {
161
+ child.on("exit", (code, signal) => {
162
+ if (signal) {
163
+ resolve({ type: "signal", signal });
164
+ } else {
165
+ resolve({ type: "code", exitCode: code ?? 1 });
166
+ }
167
+ });
168
+ });
169
+
170
+ if (childResult.type === "signal") {
171
+ // Re-emit the same signal so that the parent terminates with the expected
172
+ // semantics (this also sets the correct exit code of 128 + n).
173
+ process.kill(process.pid, childResult.signal);
174
+ } else {
175
+ process.exit(childResult.exitCode);
176
+ }
package/package.json CHANGED
@@ -1,95 +1,22 @@
1
1
  {
2
2
  "name": "viberun",
3
- "version": "0.0.1",
4
- "description": "CLI for quick app development",
5
- "main": "dist/index.js",
6
- "author": "Marvin Hagemeister <marvin@marvinhagemeister.de>",
7
- "license": "MIT",
3
+ "version": "0.3.5",
4
+ "license": "BSD-3-Clause",
8
5
  "bin": {
9
- "viberun": "dist/cli/bin.js"
6
+ "viberun": "bin/viberun.js"
10
7
  },
11
- "scripts": {
12
- "cleanup": "rimraf dist/",
13
- "lint": "tslint 'src/**/*.ts'",
14
- "watch": "tsc -w",
15
- "build": "npm run cleanup && tsc",
16
- "test": "mocha --compilers ts:ts-node/register 'src/**/__tests__/*.spec.ts'",
17
- "test-watch": "npm t -- -w -R min",
18
- "coverage": "nyc npm t",
19
- "prepublish": "npm run lint && npm t && npm run build"
8
+ "type": "module",
9
+ "engines": {
10
+ "node": ">=16"
20
11
  },
21
- "dependencies": {
22
- "@types/autoprefixer": "^6.7.1",
23
- "@types/html-webpack-plugin": "^2.28.0",
24
- "@types/rimraf": "^0.0.28",
25
- "@types/webpack": "^2.2.15",
26
- "@types/webpack-dev-server": "^2.4.0",
27
- "@types/webpack-merge": "^0.0.4",
28
- "@types/yargs": "^6.6.0",
29
- "autoprefixer": "^7.1.1",
30
- "awesome-typescript-loader": "^3.1.3",
31
- "babel-core": "^6.24.1",
32
- "babel-loader": "^7.0.0",
33
- "babel-plugin-syntax-dynamic-import": "^6.18.0",
34
- "babel-plugin-transform-react-jsx-self": "^6.22.0",
35
- "babel-plugin-transform-react-jsx-source": "^6.22.0",
36
- "babel-preset-env": "^1.5.1",
37
- "css-loader": "^0.28.2",
38
- "extract-text-webpack-plugin": "^2.1.0",
39
- "file-loader": "^0.11.1",
40
- "html-webpack-plugin": "^2.28.0",
41
- "nicer-fs": "^1.0.0",
42
- "node-sass": "^4.5.3",
43
- "raw-loader": "^0.5.1",
44
- "sass-loader": "^6.0.5",
45
- "script-ext-html-webpack-plugin": "^1.8.0",
46
- "style-loader": "^0.18.0",
47
- "url-loader": "^0.5.8",
48
- "webpack": "^2.6.0",
49
- "webpack-bundle-analyzer": "^2.8.2",
50
- "webpack-dev-server": "^2.4.5",
51
- "webpack-merge": "^4.1.0",
52
- "yargs": "^8.0.1"
53
- },
54
- "devDependencies": {
55
- "@types/chai": "^3.5.1",
56
- "@types/extract-text-webpack-plugin": "^2.1.0",
57
- "@types/mocha": "^2.2.41",
58
- "@types/node": "^7.0.22",
59
- "chai": "^4.0.0",
60
- "mocha": "^3.3.0",
61
- "nyc": "^10.2.0",
62
- "rimraf": "^2.6.1",
63
- "ts-node": "^3.0.2",
64
- "tslint": "^5.1.0",
65
- "tslint-config-sevenval": "^0.6.0",
66
- "typescript": "^2.3.1"
67
- },
68
- "nyc": {
69
- "include": [
70
- "src/*.ts",
71
- "src/**/*.ts"
72
- ],
73
- "exclude": [
74
- "typings",
75
- "node_modules/",
76
- "**/__tests__/**",
77
- "__tests__/**",
78
- "**/*.d.ts"
79
- ],
80
- "extension": [
81
- ".ts"
82
- ],
83
- "require": [
84
- "ts-node/register"
85
- ],
86
- "reporter": [
87
- "json",
88
- "html",
89
- "text",
90
- "text-summary",
91
- "lcovonly"
92
- ],
93
- "all": true
12
+ "files": [
13
+ "bin",
14
+ "vendor",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/shayne/viberun.git"
94
21
  }
95
22
  }