pinggy 0.4.8 → 0.5.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/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,9 @@ 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
+
20
27
  ## Requirements
21
28
  - Node.js 18+ (recommended). The CLI uses modern ESM and WebSocket features.
22
29
  - A network connection that allows outgoing WebSocket/HTTPS traffic.
@@ -38,7 +45,7 @@ After install, verify:
38
45
 
39
46
  ## Quick start
40
47
  - Start a basic HTTP tunnel to localhost:3000:
41
-
48
+
42
49
  ```bash
43
50
  pinggy -R0:localhost:3000
44
51
  ```
@@ -57,7 +64,164 @@ pinggy -R0:localhost:8000 -L4300:localhost:4300
57
64
  - Use a token and region/domain-like arg:
58
65
  pinggy mytoken@a.example.com -p 3000. For more info read [docs](https://pinggy.io/docs/)
59
66
 
60
- The CLI prints generated public URLs (HTTP/HTTPS or TCP) and keeps running until you press Ctrl+C.
67
+ 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.
68
+
69
+ ## Config management
70
+
71
+ 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)).
72
+
73
+ Configs can be looked up by name (exact match) or by configId prefix (partial match) in every `config` and `start`/`stop`/`restart`/`attach` subcommand.
74
+
75
+ ### Save a tunnel config
76
+ ```bash
77
+ pinggy config save my-tunnel -l 3000 token@pro.pinggy.io
78
+ ```
79
+
80
+ ### Save with auto-start enabled
81
+ ```bash
82
+ pinggy config save my-tunnel --auto -l 3000
83
+ ```
84
+
85
+ ### List all saved configs
86
+ ```bash
87
+ pinggy config list
88
+ pinggy config ls # alias for list
89
+ ```
90
+
91
+ ### View details of a saved config
92
+ ```bash
93
+ pinggy config show my-tunnel
94
+ pinggy config show my-tunnel other-tunnel # View multiple configs
95
+ pinggy config my-tunnel # Shorthand: same as `config show`
96
+ ```
97
+
98
+ ### Update a saved config
99
+ ```bash
100
+ pinggy config update my-tunnel -l 4000
101
+ ```
102
+
103
+ ### Enable or disable auto-start
104
+ ```bash
105
+ pinggy config auto my-tunnel
106
+ pinggy config noauto my-tunnel
107
+ pinggy config auto tunnel1 tunnel2 # Multiple configs at once
108
+ ```
109
+
110
+ ### Delete a saved config
111
+ ```bash
112
+ pinggy config delete my-tunnel
113
+ pinggy config delete tunnel1 tunnel2 # Delete multiple
114
+ ```
115
+
116
+
117
+ ## Running tunnels
118
+
119
+ Every tunnel runs inside the daemon. The CLI either holds a live TUI subscription to it (foreground) or starts it and exits (detached).
120
+
121
+ ### Foreground vs detached
122
+
123
+ - **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.
124
+ - **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`.
125
+
126
+ ### Start a saved tunnel
127
+ ```bash
128
+ pinggy start my-tunnel # foreground, TUI attached
129
+ pinggy start -b my-tunnel # detached, CLI exits immediately
130
+ ```
131
+
132
+ ### Start with runtime overrides
133
+ ```bash
134
+ pinggy start my-tunnel -l 4000
135
+ ```
136
+
137
+ ### Start multiple tunnels
138
+ ```bash
139
+ pinggy start tunnel1 tunnel2
140
+ ```
141
+
142
+ > Runtime overrides (`-l`, `--type`, `--token`, ...) only apply when starting a single tunnel. For multiple tunnels, update the saved config first with `pinggy config update`.
143
+
144
+ ### Start all auto-start tunnels
145
+ ```bash
146
+ pinggy start --all
147
+ ```
148
+ Runs through the daemon as detached tunnels. Useful for scripting and service startup.
149
+
150
+ ### Start with remote management
151
+ ```bash
152
+ pinggy start --all --remote-management <API_KEY>
153
+ pinggy start tunnel1 tunnel2 --remote-management <API_KEY>
154
+ ```
155
+
156
+ ### Start with logging enabled
157
+ ```bash
158
+ pinggy start my-tunnel --vvv
159
+ pinggy start --all --logfile /tmp/pinggy.log --loglevel DEBUG
160
+ ```
161
+
162
+ ### List running tunnels
163
+ ```bash
164
+ pinggy ps
165
+ ```
166
+ Prints a table of ID, name, status, local endpoint, and public URL.
167
+
168
+ ### Stop tunnels
169
+ ```bash
170
+ pinggy stop my-tunnel
171
+ pinggy stop my-tunnel other-tunnel # multiple
172
+ pinggy stop abc12345 # by configId prefix
173
+ ```
174
+
175
+ ### Restart a tunnel
176
+ ```bash
177
+ pinggy restart my-tunnel
178
+ ```
179
+ Preserves the existing mode (foreground stays foreground, detached stays detached).
180
+
181
+ ### Re-attach the TUI to a running tunnel
182
+ ```bash
183
+ pinggy attach my-tunnel
184
+ ```
185
+ Opens a fresh TUI session against a tunnel that is already running. Useful to inspect a detached tunnel live.
186
+
187
+
188
+ ## Daemon
189
+
190
+ 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.
191
+
192
+ Both `pinggy daemon` and the alias `pinggy d` work.
193
+
194
+ ### Start the daemon
195
+ ```bash
196
+ pinggy daemon start
197
+ ```
198
+ Lists which configs will auto-start (any tagged with `config auto`).
199
+
200
+ ### Stop the daemon
201
+ ```bash
202
+ pinggy daemon stop
203
+ ```
204
+ Stops every running tunnel and shuts the daemon down cleanly.
205
+
206
+ ### Show daemon status
207
+ ```bash
208
+ pinggy daemon status
209
+ ```
210
+ Prints PID, port, start time, and uptime.
211
+
212
+
213
+ ## Remote management
214
+ You can control tunnels remotely using a secure WebSocket connection.
215
+
216
+ - Start remote management with a token:
217
+ ```bash
218
+ pinggy --remote-management <API KEY>
219
+ ```
220
+
221
+ - Specify a management server (default is wss://dashboard.pinggy.io):
222
+ ```bash
223
+ pinggy --remote-management <API KEY> --manage wss://custom.example.com
224
+ ```
61
225
 
62
226
 
63
227
  ## Usage
@@ -99,6 +263,8 @@ The CLI supports both SSH-style flags and more descriptive long flags. Below is
99
263
  | `--vv` | Detailed logs (Node.js SDK + Libpinggy) |
100
264
  | `--vvv` | Enable logs from CLI, SDK, and Libpinggy |
101
265
 
266
+ These flags apply to the CLI invocation. For daemon-wide log level and per-tunnel log files, see [Logging](#logging).
267
+
102
268
  ---
103
269
 
104
270
  ### **Config (File-based)**
@@ -132,6 +298,15 @@ The CLI supports both SSH-style flags and more descriptive long flags. Below is
132
298
 
133
299
  ---
134
300
 
301
+ ### **Tunnel lifecycle**
302
+ | Flag | Description |
303
+ |------|-------------|
304
+ | `-b` | Start the tunnel detached (daemon keeps it alive after the CLI exits). Pairs with `pinggy start`. |
305
+ | `--all` | Start every config marked auto-start. Pairs with `pinggy start`. |
306
+ | `--auto` | Mark a saved config as auto-start. Pairs with `pinggy config save`. |
307
+
308
+ ---
309
+
135
310
  ### **Misc**
136
311
  | Flag | Description |
137
312
  |------|-------------|
@@ -164,35 +339,9 @@ Examples:
164
339
  To generate advanced CLI arguments, use [Configure from Pinggy.io](https://pinggy.io/)
165
340
 
166
341
 
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
342
  ## Saving and loading configuration
194
343
  - Save current options to a file:
195
- ```bash
344
+ ```bash
196
345
  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
346
  ```
198
347
  - Use a config as base and override with flags:
@@ -201,93 +350,59 @@ pinggy --conf ./myconfig.json -p 8080
201
350
  ```
202
351
 
203
352
 
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
- ```
353
+ ## Logging
222
354
 
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
- ```
355
+ 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
356
 
229
- ### Update a saved config
230
- ```bash
231
- pinggy config update my-tunnel -l 4000
232
- ```
357
+ ### Per-invocation flags
358
+ Pass these on any command that starts or interacts with a tunnel.
233
359
 
234
- ### Enable or disable auto-start
235
360
  ```bash
236
- pinggy config auto my-tunnel
237
- pinggy config noauto my-tunnel
238
- pinggy config auto tunnel1 tunnel2 # Multiple configs at once
361
+ pinggy -p 3000 --logfile ~/.pinggy/pinggy.log --loglevel INFO --v
239
362
  ```
363
+ 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
364
 
241
- ### Delete a saved config
242
- ```bash
243
- pinggy config delete my-tunnel
244
- pinggy config delete tunnel1 tunnel2 # Delete multiple
245
- ```
365
+ ### Daemon and per-tunnel log files
366
+ 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
367
 
247
- ### Shorthand: view config details
368
+ #### Tail the daemon log
248
369
  ```bash
249
- pinggy config my-tunnel # Same as: pinggy config show my-tunnel
370
+ pinggy logs # last 100 lines of the daemon log
371
+ pinggy logs -f # follow new daemon log lines
250
372
  ```
251
373
 
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
374
+ #### Tail a tunnel log
258
375
  ```bash
259
- pinggy start my-tunnel
376
+ pinggy logs my-tunnel # last 100 lines of that tunnel's log
377
+ pinggy logs my-tunnel -f # follow new lines (survives log rotation)
260
378
  ```
261
379
 
262
- ### Start with runtime overrides
380
+ #### Print the log file path
263
381
  ```bash
264
- pinggy start my-tunnel -l 4000
382
+ pinggy log path # daemon log path
383
+ pinggy log path my-tunnel # path to a specific tunnel's log
265
384
  ```
266
385
 
267
- ### Start multiple tunnels
386
+ #### Get or set the daemon log level
268
387
  ```bash
269
- pinggy start tunnel1 tunnel2
388
+ pinggy log level # print current level
389
+ pinggy log level debug # set to debug, info, or error
270
390
  ```
391
+ 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
392
 
272
- ### Start all auto-start tunnels
273
- ```bash
274
- pinggy start --all
275
- ```
276
393
 
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
- ```
394
+ ## State and file locations
282
395
 
283
- ### Start with logging enabled
284
- ```bash
285
- pinggy start my-tunnel --vvv
286
- pinggy start --all --logfile /tmp/pinggy.log --loglevel DEBUG
287
- ```
396
+ Config dir varies by OS:
397
+ - Linux/macOS: `~/.config/pinggy/`
398
+ - Windows: `%APPDATA%\pinggy\`
288
399
 
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`.
400
+ Log dir varies by OS:
401
+ - Linux: `~/.local/state/pinggy-cli/logs/` (honors `$XDG_STATE_HOME`)
402
+ - macOS: `~/Library/Logs/Pinggy-CLI/`
403
+ - Windows: `%LOCALAPPDATA%\Pinggy-CLI\Logs\`
290
404
 
405
+ Use `pinggy log path` to print the exact resolved paths on your system.
291
406
 
292
407
  ## File server mode
293
408
  Serve a local directory quickly over a tunnel:
@@ -296,8 +411,10 @@ Optionally combine with other flags (auth, IP whitelist) as needed.
296
411
 
297
412
 
298
413
  ## Signals and shutdown
299
- Press Ctrl+C to stop. The CLI traps SIGINT and gracefully stops active tunnels before exiting.
300
414
 
415
+ - **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.
416
+ - **Detached tunnel** (`-b`): the CLI already exited. Stop it with `pinggy stop <name|id>`.
417
+ - **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
418
 
302
419
 
303
420
  ## 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
+ };