pinggy 0.4.9 → 0.5.1

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/CLAUDE.md ADDED
@@ -0,0 +1,112 @@
1
+ ## Project Overview
2
+
3
+ Pinggy CLI (`@pinggy/cli`) is a Node.js CLI tool for creating and managing Pinggy tunnels. It runs as **two processes**: a short-lived foreground CLI that the user invokes, and a long-running daemon that owns every tunnel. The CLI talks to the daemon over HTTP + WebSocket on `127.0.0.1`. Built with TypeScript, wraps the `@pinggy/pinggy` SDK in the daemon, and ships a blessed-based TUI plus remote control via WebSocket.
4
+
5
+ ## Common Commands
6
+
7
+ ```bash
8
+ # Build (produces CJS + ESM in dist/)
9
+ npm run build
10
+
11
+ # TypeScript type-check only (output to dist_tsc/)
12
+ npm run build:tsc
13
+
14
+ # Dev workflow (link SDK, build, link locally)
15
+ npm run dev
16
+
17
+ # Build platform binaries (via pkg)
18
+ npm run pack:all
19
+
20
+ # E2E suite against a packaged binary (see test/e2e/README.md)
21
+ node test/e2e/run.cjs out/pinggy-<platform>
22
+ ```
23
+
24
+ ## Architecture
25
+
26
+ ### Two-process model
27
+
28
+ The CLI binary has 3 entry modes, dispatched in `src/main.ts`:
29
+
30
+ 1. **Daemon child** (`--_daemon-child` flag). Calls `runDaemonChild()` in `src/daemon/daemonChild.ts`. The CLI re-execs itself with this flag when it needs to spawn a daemon; users never invoke it directly.
31
+ 2. **Subcommand** (`config`, `start`, `stop`, `ps`, `attach`, `daemon`, `d`). Routes to `handleSubcommand()` in `src/cli/subcommands.ts`.
32
+ 3. **Legacy single-tunnel** (no subcommand). Routes to `buildAndStartTunnel()` for flags like `-l 3000` or `-R0:localhost:3000`.
33
+
34
+ The daemon owns the `TunnelManager` singleton, the `@pinggy/pinggy` SDK, the web debugger server, and any `--serve` file servers. The CLI owns argument parsing, the TUI, the remote-management WebSocket client, and the IPC client to the daemon.
35
+
36
+ ### IPC: HTTP + WebSocket on localhost
37
+
38
+ The daemon listens on `127.0.0.1` with an OS-assigned port (recorded in `daemon.json`):
39
+
40
+ - **HTTP** for request/response (`src/daemon/ipcServer.ts`): `GET /ping`, `GET /tunnels`, `POST /tunnels/start`, `POST /tunnels/start-config`, `POST /tunnels/stop`, `POST /tunnels/restart`, `POST /shutdown`, plus v1 compatibility routes used by remote management.
41
+ - **WebSocket** for streaming tunnel events (schema in `src/daemon/wsProtocol.ts`). Client subscribes by `tunnelId`; daemon emits `tunnel_event` frames keyed by event name.
42
+
43
+ CLI code calls `TunnelClient` (`src/daemon/tunnelClient.ts`), the public facade that combines HTTP RPC with WebSocket event dispatch. `IPCClient` (`src/daemon/ipcClient.ts`) is the raw HTTP wrapper underneath; nothing outside `tunnelClient.ts` should touch it.
44
+
45
+ ### Daemon discovery and lifecycle
46
+
47
+ `getDaemonInfo()` in `src/daemon/daemonManager.ts` reads `daemon.json`, validates the PID with `process.kill(pid, 0)`, deletes the file if stale, and returns `null` if no live daemon is found. `startDaemon()` spawns a detached daemon child and polls `daemon.json` for up to 8s.
48
+
49
+ Single daemon per user. State lives under `~/.config/pinggy/` on Linux/macOS or `%APPDATA%/pinggy/` on Windows (helper: `src/utils/configDir.ts`):
50
+
51
+ - `daemon.json`: `{pid, port, startedAt}`.
52
+ - `daemon-state.json`: detached tunnel configs for crash recovery (`src/daemon/stateStore.ts`). Deleted on clean shutdown; replayed on next start.
53
+ - `daemon.log`: SDK + daemon logs. CLI logs stay separate.
54
+ - `tunnels/<name>_<configId>.json`: saved tunnel configs from `pinggy config save`.
55
+
56
+ ### Foreground vs detached tunnels
57
+
58
+ `SessionTracker` (`src/daemon/sessionTracker.ts`) maps each `tunnelId` to a `sessionId` plus a mode:
59
+
60
+ - **Foreground**: CLI holds an open WebSocket subscription. If the subscription closes, a 5-second grace period starts; if no other CLI re-attaches, the daemon stops the tunnel.
61
+ - **Detached** (`-b` flag, or remote-management tunnels): tunnel persists in the daemon regardless of CLI presence and is recorded in `daemon-state.json`.
62
+
63
+ `pinggy attach <name|id>` reopens a foreground subscription and renders the TUI.
64
+
65
+ **Core types** are in `src/types.ts`: `TunnelStatus`, `Status`, `TunnelStateType` enum (`idle/starting/running/live/closed/exited`), `FinalConfig` (extends SDK's `TunnelConfigurationV1`). Browse `src/daemon/` and `src/cli/` for the rest of the module layout.
66
+
67
+ ## Subcommands (user-facing)
68
+
69
+ | Command | Purpose |
70
+ |---|---|
71
+ | `pinggy config list \| show \| save \| update \| delete \| auto \| noauto` | CRUD on saved tunnel configs |
72
+ | `pinggy start <name...> [-b] [--all]` | Start saved tunnel(s). `-b` detaches; `--all` starts every auto-start config |
73
+ | `pinggy stop <name\|id>` | Stop running tunnel(s) by name or ID prefix |
74
+ | `pinggy ps` | Table of running tunnels (ID, name, status, local, URL) |
75
+ | `pinggy attach <name\|id>` | Re-attach TUI to a running tunnel |
76
+ | `pinggy daemon start \| stop \| status \| install-service \| uninstall-service` (alias `d`) | Daemon lifecycle and system-service installation |
77
+
78
+ ## Build System
79
+
80
+ tsup bundles to `dist/` (CJS + ESM). tsc type-checks only (`npm run build:tsc`). pkg builds standalone platform binaries (`out/pinggy-<platform>`). ts-jest with the ESM preset for unit tests (`jest.config.cjs`).
81
+
82
+ ## Testing
83
+
84
+ **Unit tests** live in `src/_tests_/`. Use `@jest/globals` imports (no global `jest`). `TunnelManager` is a singleton, so reset it between tests with `TunnelManager.instance = undefined`, and call `jest.clearAllMocks()` in `beforeEach`.
85
+
86
+ **End-to-end tests** live in `test/e2e/`. They run against a packaged `pkg` binary, spawn real Pinggy free-tier tunnels, and assert HTTP/TCP/UDP behavior over the live edge. See `test/e2e/README.md` for layout, framework helpers, and how to add a case. CI runs them across 6 platform binaries via `.github/workflows/e2e-test.yml`.
87
+
88
+ ## Key Patterns
89
+
90
+ - **Singletons** inside the daemon: `TunnelManager`, Winston `logger`, `CLIPrinter`. Access via `getInstance()` or static methods.
91
+ - **Listener/observer maps** for SDK callbacks: `Map<tunnelId, Map<listenerId, fn>>`. Register/unregister by `listenerId` to avoid leaks.
92
+ - **Zod validation** on remote-management payloads (`src/remote_management/remote_schema.ts`), V1 and V2.
93
+ - **Worker threads** for file serving (`src/workers/file_serve_worker.ts`).
94
+ - **DaemonTunnelHandler**. Remote management lives in the CLI, but every tunnel operation it receives is forwarded to the daemon via this adapter in `src/daemon/tunnelClient.ts`. Same code path as user-typed subcommands.
95
+
96
+ ## English Style
97
+
98
+ - **No em-dashes.** Use a period, colon, or restructure the sentence. No obvious characters or constructions used by LLMs and AI.
99
+ - **Short phrases.** Enough to convey technical meaning. Nothing more.
100
+ - **No filler words.** Cut: "in order to", "it is important to note", "please note that", "essentially", "basically", "simply".
101
+ - **No passive voice** unless the subject is unknown or irrelevant.
102
+ - **No nominalizations.** Prefer "detect" over "perform detection"; "configure" over "apply configuration".
103
+ - **One idea per sentence.** Split compound sentences.
104
+ - **No throat-clearing openers.** Never start with "This document describes...", "The purpose of this is...", "As mentioned above...".
105
+ - **Prefer concrete over abstract.** Name the thing: `navigator.webdriver`, not "the relevant browser property".
106
+ - **Present tense.** "The system routes requests." Not "The system will route requests."
107
+ - **No redundant qualifiers.** "Persistent storage" not "persistent, durable, long-lived storage".
108
+ - **Numbers.** Use digits for all quantities: "3 retries", "50 sessions", "300ms".
109
+
110
+ ## Code Style
111
+ - **No dead code.** Remove unused imports, functions, and variables immediately. `ruff` enforces this.
112
+ - **Small functions.** If a function needs a comment to explain its sections, split it.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Pinggy CLI
1
+ # Pinggy CLI
2
2
 
3
- Create secure, shareable tunnels to your localhost and manage them from the command line.
3
+ Create secure, shareable tunnels to your localhost and manage them from the command line.
4
4
 
5
5
 
6
6
  ## Key features
@@ -8,8 +8,12 @@ Create secure, shareable tunnels to your localhost and manage them from the comm
8
8
  - SSH-style and user-friendly flags
9
9
  - Web debugger for HTTP tunnels
10
10
  - Extended options for auth, header manipulation, IP allowlists, CORS handling, etc.
11
+ - Persistent background daemon owns every tunnel; CLI invocations are short-lived
12
+ - Foreground (live TUI) and detached (`-b`) tunnel modes
13
+ - Lifecycle commands: `ps`, `start`, `stop`, `restart`, `attach`
14
+ - Per-tunnel and per-daemon log files with `pinggy logs` (tail, follow, rotation-safe)
15
+ - System-service install for auto-start at boot (systemd, launchd, Task Scheduler)
11
16
  - Remote management via secure WebSocket connection (works with Pinggy Dashboard)
12
- - Configurable logging to file and/or stdout
13
17
  - Save and load configuration files
14
18
  - Config store for saving, listing, updating, and starting named tunnel configs
15
19
  - Auto-start support for launching saved tunnels automatically
@@ -17,6 +21,11 @@ Create secure, shareable tunnels to your localhost and manage them from the comm
17
21
  - Built-in TUI (Text User Interface) for viewing tunnel statistics, requests, and responses in real time
18
22
 
19
23
 
24
+ ## Architecture at a glance
25
+ The CLI runs as two processes. A short-lived foreground process is what you invoke. A long-running daemon owns every tunnel and the `@pinggy/pinggy` SDK. They talk over HTTP and WebSocket on `127.0.0.1`.
26
+
27
+ See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full breakdown of the two-process model, IPC routes, daemon discovery, session ownership, and filesystem layout.
28
+
20
29
  ## Requirements
21
30
  - Node.js 18+ (recommended). The CLI uses modern ESM and WebSocket features.
22
31
  - A network connection that allows outgoing WebSocket/HTTPS traffic.
@@ -38,7 +47,7 @@ After install, verify:
38
47
 
39
48
  ## Quick start
40
49
  - Start a basic HTTP tunnel to localhost:3000:
41
-
50
+
42
51
  ```bash
43
52
  pinggy -R0:localhost:3000
44
53
  ```
@@ -57,7 +66,164 @@ pinggy -R0:localhost:8000 -L4300:localhost:4300
57
66
  - Use a token and region/domain-like arg:
58
67
  pinggy mytoken@a.example.com -p 3000. For more info read [docs](https://pinggy.io/docs/)
59
68
 
60
- The CLI prints generated public URLs (HTTP/HTTPS or TCP) and keeps running until you press Ctrl+C.
69
+ The CLI prints generated public URLs (HTTP/HTTPS or TCP) and keeps the TUI attached until you press Ctrl+C. Tunnels run inside a background daemon. See [Daemon](#daemon) and [Running tunnels](#running-tunnels) for `ps`, `stop`, and detached (`-b`) mode.
70
+
71
+ ## Config management
72
+
73
+ The CLI includes a built-in config store for saving, listing, and starting tunnel configurations. Configs are persisted as JSON files under the platform config directory (see [State and file locations](#state-and-file-locations)).
74
+
75
+ Configs can be looked up by name (exact match) or by configId prefix (partial match) in every `config` and `start`/`stop`/`restart`/`attach` subcommand.
76
+
77
+ ### Save a tunnel config
78
+ ```bash
79
+ pinggy config save my-tunnel -l 3000 token@pro.pinggy.io
80
+ ```
81
+
82
+ ### Save with auto-start enabled
83
+ ```bash
84
+ pinggy config save my-tunnel --auto -l 3000
85
+ ```
86
+
87
+ ### List all saved configs
88
+ ```bash
89
+ pinggy config list
90
+ pinggy config ls # alias for list
91
+ ```
92
+
93
+ ### View details of a saved config
94
+ ```bash
95
+ pinggy config show my-tunnel
96
+ pinggy config show my-tunnel other-tunnel # View multiple configs
97
+ pinggy config my-tunnel # Shorthand: same as `config show`
98
+ ```
99
+
100
+ ### Update a saved config
101
+ ```bash
102
+ pinggy config update my-tunnel -l 4000
103
+ ```
104
+
105
+ ### Enable or disable auto-start
106
+ ```bash
107
+ pinggy config auto my-tunnel
108
+ pinggy config noauto my-tunnel
109
+ pinggy config auto tunnel1 tunnel2 # Multiple configs at once
110
+ ```
111
+
112
+ ### Delete a saved config
113
+ ```bash
114
+ pinggy config delete my-tunnel
115
+ pinggy config delete tunnel1 tunnel2 # Delete multiple
116
+ ```
117
+
118
+
119
+ ## Running tunnels
120
+
121
+ Every tunnel runs inside the daemon. The CLI either holds a live TUI subscription to it (foreground) or starts it and exits (detached).
122
+
123
+ ### Foreground vs detached
124
+
125
+ - **Foreground** (default): `pinggy start <name>`. The CLI keeps a WebSocket open to the tunnel and renders the TUI. Use ctrl+C to close the TUI and stop the tunnel.
126
+ - **Detached** (`-b`): `pinggy start -b <name>`. The CLI prints the public URL, then exits. The tunnel persists in the daemon until you stop it explicitly with `pinggy stop`.
127
+
128
+ ### Start a saved tunnel
129
+ ```bash
130
+ pinggy start my-tunnel # foreground, TUI attached
131
+ pinggy start -b my-tunnel # detached, CLI exits immediately
132
+ ```
133
+
134
+ ### Start with runtime overrides
135
+ ```bash
136
+ pinggy start my-tunnel -l 4000
137
+ ```
138
+
139
+ ### Start multiple tunnels
140
+ ```bash
141
+ pinggy start tunnel1 tunnel2
142
+ ```
143
+
144
+ > Runtime overrides (`-l`, `--type`, `--token`, ...) only apply when starting a single tunnel. For multiple tunnels, update the saved config first with `pinggy config update`.
145
+
146
+ ### Start all auto-start tunnels
147
+ ```bash
148
+ pinggy start --all
149
+ ```
150
+ Runs through the daemon as detached tunnels. Useful for scripting and service startup.
151
+
152
+ ### Start with remote management
153
+ ```bash
154
+ pinggy start --all --remote-management <API_KEY>
155
+ pinggy start tunnel1 tunnel2 --remote-management <API_KEY>
156
+ ```
157
+
158
+ ### Start with logging enabled
159
+ ```bash
160
+ pinggy start my-tunnel --vvv
161
+ pinggy start --all --logfile /tmp/pinggy.log --loglevel DEBUG
162
+ ```
163
+
164
+ ### List running tunnels
165
+ ```bash
166
+ pinggy ps
167
+ ```
168
+ Prints a table of ID, name, status, local endpoint, and public URL.
169
+
170
+ ### Stop tunnels
171
+ ```bash
172
+ pinggy stop my-tunnel
173
+ pinggy stop my-tunnel other-tunnel # multiple
174
+ pinggy stop abc12345 # by configId prefix
175
+ ```
176
+
177
+ ### Restart a tunnel
178
+ ```bash
179
+ pinggy restart my-tunnel
180
+ ```
181
+ Preserves the existing mode (foreground stays foreground, detached stays detached).
182
+
183
+ ### Re-attach the TUI to a running tunnel
184
+ ```bash
185
+ pinggy attach my-tunnel
186
+ ```
187
+ Opens a fresh TUI session against a tunnel that is already running. Useful to inspect a detached tunnel live.
188
+
189
+
190
+ ## Daemon
191
+
192
+ The daemon is the long-running process that owns every tunnel. The CLI starts it automatically when needed, so most users never call these commands directly. They exist for explicit control, scripting, and boot-time service install.
193
+
194
+ Both `pinggy daemon` and the alias `pinggy d` work.
195
+
196
+ ### Start the daemon
197
+ ```bash
198
+ pinggy daemon start
199
+ ```
200
+ Lists which configs will auto-start (any tagged with `config auto`).
201
+
202
+ ### Stop the daemon
203
+ ```bash
204
+ pinggy daemon stop
205
+ ```
206
+ Stops every running tunnel and shuts the daemon down cleanly.
207
+
208
+ ### Show daemon status
209
+ ```bash
210
+ pinggy daemon status
211
+ ```
212
+ Prints PID, port, start time, and uptime.
213
+
214
+
215
+ ## Remote management
216
+ You can control tunnels remotely using a secure WebSocket connection.
217
+
218
+ - Start remote management with a token:
219
+ ```bash
220
+ pinggy --remote-management <API KEY>
221
+ ```
222
+
223
+ - Specify a management server (default is wss://dashboard.pinggy.io):
224
+ ```bash
225
+ pinggy --remote-management <API KEY> --manage wss://custom.example.com
226
+ ```
61
227
 
62
228
 
63
229
  ## Usage
@@ -99,6 +265,8 @@ The CLI supports both SSH-style flags and more descriptive long flags. Below is
99
265
  | `--vv` | Detailed logs (Node.js SDK + Libpinggy) |
100
266
  | `--vvv` | Enable logs from CLI, SDK, and Libpinggy |
101
267
 
268
+ These flags apply to the CLI invocation. For daemon-wide log level and per-tunnel log files, see [Logging](#logging).
269
+
102
270
  ---
103
271
 
104
272
  ### **Config (File-based)**
@@ -132,6 +300,15 @@ The CLI supports both SSH-style flags and more descriptive long flags. Below is
132
300
 
133
301
  ---
134
302
 
303
+ ### **Tunnel lifecycle**
304
+ | Flag | Description |
305
+ |------|-------------|
306
+ | `-b` | Start the tunnel detached (daemon keeps it alive after the CLI exits). Pairs with `pinggy start`. |
307
+ | `--all` | Start every config marked auto-start. Pairs with `pinggy start`. |
308
+ | `--auto` | Mark a saved config as auto-start. Pairs with `pinggy config save`. |
309
+
310
+ ---
311
+
135
312
  ### **Misc**
136
313
  | Flag | Description |
137
314
  |------|-------------|
@@ -164,35 +341,9 @@ Examples:
164
341
  To generate advanced CLI arguments, use [Configure from Pinggy.io](https://pinggy.io/)
165
342
 
166
343
 
167
- ## Remote management
168
- You can control tunnels remotely using a secure WebSocket connection.
169
-
170
- - Start remote management with a token:
171
- ```bash
172
- pinggy --remote-management <API KEY>
173
- ```
174
-
175
- - Specify a management server (default is wss://dashboard.pinggy.io):
176
- ```bash
177
- pinggy --remote-management <API KEY> --manage wss://custom.example.com
178
- ```
179
-
180
-
181
-
182
- ## Logging
183
- You can control logs via CLI flags (which override environment variables). If logfile is provided, the log directory will be created if it does not exist.
184
-
185
- - To log to file and stdout at INFO level:
186
- ```bash
187
- pinggy -p 3000 --logfile ~/.pinggy/pinggy.log --loglevel INFO --v
188
- ```
189
- If you provide `--v`, `--vv`, or `--vvv` without specifying a log level, the default log level is INFO.
190
-
191
-
192
-
193
344
  ## Saving and loading configuration
194
345
  - Save current options to a file:
195
- ```bash
346
+ ```bash
196
347
  pinggy -p 443 -L4300:localhost:4300 -t -R0:127.0.0.1:8000 qr+force@free.pinggy.io x:noreverseproxy x:passpreflight x:xff --saveconf myconfig.json
197
348
  ```
198
349
  - Use a config as base and override with flags:
@@ -201,93 +352,59 @@ pinggy --conf ./myconfig.json -p 8080
201
352
  ```
202
353
 
203
354
 
204
- ## Config management
205
-
206
- The CLI includes a built-in config store for saving, listing, and starting tunnel configurations. Configs are persisted as JSON files in your platform's config directory (`~/.config/pinggy/tunnels/` on Linux/macOS, `%APPDATA%/pinggy/tunnels/` on Windows).
207
-
208
- ### Save a tunnel config
209
- ```bash
210
- pinggy config save my-tunnel -l 3000 token@pro.pinggy.io
211
- ```
212
-
213
- ### Save with auto-start enabled
214
- ```bash
215
- pinggy config save my-tunnel --auto -l 3000
216
- ```
217
-
218
- ### List all saved configs
219
- ```bash
220
- pinggy config list
221
- ```
355
+ ## Logging
222
356
 
223
- ### View details of a saved config
224
- ```bash
225
- pinggy config show my-tunnel
226
- pinggy config show my-tunnel other-tunnel # View multiple configs
227
- ```
357
+ The CLI has two layers of logging: per-invocation flags that affect what the current command prints, and daemon-wide log commands that read the persistent log files the daemon writes.
228
358
 
229
- ### Update a saved config
230
- ```bash
231
- pinggy config update my-tunnel -l 4000
232
- ```
359
+ ### Per-invocation flags
360
+ Pass these on any command that starts or interacts with a tunnel.
233
361
 
234
- ### Enable or disable auto-start
235
362
  ```bash
236
- pinggy config auto my-tunnel
237
- pinggy config noauto my-tunnel
238
- pinggy config auto tunnel1 tunnel2 # Multiple configs at once
363
+ pinggy -p 3000 --logfile ~/.pinggy/pinggy.log --loglevel INFO --v
239
364
  ```
365
+ If you pass `--v`, `--vv`, or `--vvv` without a log level, the default is INFO. If a logfile path is provided, the log directory is created if it does not exist.
240
366
 
241
- ### Delete a saved config
242
- ```bash
243
- pinggy config delete my-tunnel
244
- pinggy config delete tunnel1 tunnel2 # Delete multiple
245
- ```
367
+ ### Daemon and per-tunnel log files
368
+ The daemon writes its own log file and a separate log per tunnel under the platform log directory (see [State and file locations](#state-and-file-locations)).
246
369
 
247
- ### Shorthand: view config details
370
+ #### Tail the daemon log
248
371
  ```bash
249
- pinggy config my-tunnel # Same as: pinggy config show my-tunnel
372
+ pinggy logs # last 100 lines of the daemon log
373
+ pinggy logs -f # follow new daemon log lines
250
374
  ```
251
375
 
252
- Configs can be looked up by name (exact match) or by configId prefix (partial match).
253
-
254
-
255
- ## Starting saved tunnels
256
-
257
- ### Start a saved tunnel
376
+ #### Tail a tunnel log
258
377
  ```bash
259
- pinggy start my-tunnel
378
+ pinggy logs my-tunnel # last 100 lines of that tunnel's log
379
+ pinggy logs my-tunnel -f # follow new lines (survives log rotation)
260
380
  ```
261
381
 
262
- ### Start with runtime overrides
382
+ #### Print the log file path
263
383
  ```bash
264
- pinggy start my-tunnel -l 4000
384
+ pinggy log path # daemon log path
385
+ pinggy log path my-tunnel # path to a specific tunnel's log
265
386
  ```
266
387
 
267
- ### Start multiple tunnels
388
+ #### Get or set the daemon log level
268
389
  ```bash
269
- pinggy start tunnel1 tunnel2
390
+ pinggy log level # print current level
391
+ pinggy log level debug # set to debug, info, or error
270
392
  ```
393
+ Setting the level persists in `daemon-config.json` and applies to the daemon and any new tunnels. To pick up the new level on a tunnel that is already running, restart it with `pinggy restart <name>`.
271
394
 
272
- ### Start all auto-start tunnels
273
- ```bash
274
- pinggy start --all
275
- ```
276
395
 
277
- ### Start with remote management
278
- ```bash
279
- pinggy start --all --remote-management <API_KEY>
280
- pinggy start tunnel1 tunnel2 --remote-management <API_KEY>
281
- ```
396
+ ## State and file locations
282
397
 
283
- ### Start with logging enabled
284
- ```bash
285
- pinggy start my-tunnel --vvv
286
- pinggy start --all --logfile /tmp/pinggy.log --loglevel DEBUG
287
- ```
398
+ Config dir varies by OS:
399
+ - Linux/macOS: `~/.config/pinggy/`
400
+ - Windows: `%APPDATA%\pinggy\`
288
401
 
289
- > **Note:** Runtime overrides (`-l`, `--type`, `--token`, etc.) can only be used when starting a single tunnel. For multiple tunnels, update the saved config first with `pinggy config update`.
402
+ Log dir varies by OS:
403
+ - Linux: `~/.local/state/pinggy-cli/logs/` (honors `$XDG_STATE_HOME`)
404
+ - macOS: `~/Library/Logs/Pinggy-CLI/`
405
+ - Windows: `%LOCALAPPDATA%\Pinggy-CLI\Logs\`
290
406
 
407
+ Use `pinggy log path` to print the exact resolved paths on your system.
291
408
 
292
409
  ## File server mode
293
410
  Serve a local directory quickly over a tunnel:
@@ -296,8 +413,10 @@ Optionally combine with other flags (auth, IP whitelist) as needed.
296
413
 
297
414
 
298
415
  ## Signals and shutdown
299
- Press Ctrl+C to stop. The CLI traps SIGINT and gracefully stops active tunnels before exiting.
300
416
 
417
+ - **Foreground tunnel**: Ctrl+C closes the TUI. The daemon arms a 5-second grace timer and stops the tunnel if no other CLI re-attaches.
418
+ - **Detached tunnel** (`-b`): the CLI already exited. Stop it with `pinggy stop <name|id>`.
419
+ - **Everything at once**: `pinggy daemon stop` stops every tunnel and shuts the daemon down cleanly. `daemon-state.json` is cleared, so nothing replays on next start.
301
420
 
302
421
 
303
422
  ## Versioning
@@ -0,0 +1,11 @@
1
+ import {
2
+ TunnelAlreadyRunningError,
3
+ TunnelManager
4
+ } from "./chunk-DLNUDW6G.js";
5
+ import "./chunk-UB26QJ4T.js";
6
+ import "./chunk-7G6SJEEA.js";
7
+ import "./chunk-GBYF2H4H.js";
8
+ export {
9
+ TunnelAlreadyRunningError,
10
+ TunnelManager
11
+ };