@hahahhh/sshx 0.0.2-rc.1 → 0.0.3-rc.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.
Files changed (2) hide show
  1. package/README.md +47 -28
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -2,11 +2,12 @@
2
2
 
3
3
  > Transparent SSH enhancement — add remote-to-local commands, auto port forwarding, and local domains to your SSH workflow. Zero side effects when you don't need them.
4
4
 
5
- **sshx** is a drop-in wrapper around OpenSSH. Wrap it as `alias ssh=sshx` and your existing SSH workflow works exactly as before — every flag, config, and connection passes through verbatim. But when you connect to a host with sshx-aware features enabled, you unlock a persistent, shared remote server that gives you:
5
+ **sshx** is a drop-in wrapper around OpenSSH. Wrap it as `alias ssh=sshx` and your existing SSH workflow works exactly as before — every flag, config, and connection passes through verbatim. But when you connect to a host (or Docker container) with sshx-aware features enabled, you unlock a persistent, shared remote server that gives you:
6
6
 
7
7
  - 🔄 **Reverse command bridge** — run `sshx local <cmd>` *on the remote* to execute commands on your local machine, with stdout, stderr, exit code, and stdin all propagated.
8
8
  - 🔌 **Automatic port forwarding** — remote loopback listeners (e.g., a dev server on `localhost:8080`) are automatically detected and forwarded to your local machine.
9
9
  - 🌐 **Local domain binding** — access forwarded ports as `<host>.<your-user>.sshx:<port>` in your local browser, no manual `-L` flags needed.
10
+ - 🐳 **Docker container support** — target running containers by name or ID: `sshx my-container`. Command bridge support works inside containers via `docker exec`.
10
11
 
11
12
  ## Why sshx?
12
13
 
@@ -31,6 +32,16 @@ sshx is designed to be **safe to alias**. Hosts without sshx configuration are u
31
32
  - `~/.ssh/config` resolution is handled by OpenSSH — no reimplementation.
32
33
  - Bypass with `sshx --no-wrap` or `SSHX_DISABLE=1` at any time.
33
34
 
35
+ ### 🐳 Docker Container Target
36
+
37
+ When the target doesn't match any SSH host, sshx falls back to resolving it as a running Docker container:
38
+
39
+ - `sshx <container-name>` — opens a shell in the container via `docker exec`.
40
+ - `sshx <container-id-prefix>` — matches by container ID prefix.
41
+ - Explicit SSH targets (`user@host`, IP addresses, hostnames with dots/colons) are never treated as Docker containers.
42
+ - Command bridge support works inside containers.
43
+ - Requires `docker` CLI available on the local machine — gracefully falls back to SSH if Docker isn't found or the container isn't running.
44
+
34
45
  ### 🔄 Remote-to-Local Command Bridge
35
46
 
36
47
  Run commands on your **local machine** from inside an SSH session:
@@ -51,15 +62,15 @@ sshx local pbcopy < /tmp/some-data
51
62
  When a process on the remote starts listening on `127.0.0.1` (e.g., `npm run dev` on port 3000), sshx detects it and:
52
63
 
53
64
  1. Broadcasts the port to the local daemon.
54
- 2. Creates a shared TCP forward over SSH.
55
- 3. Binds the SSH target domain, e.g. `debian.<your-user>.sshx`.
65
+ 2. Assigns the SSH target its own loopback IP.
66
+ 3. Exposes a TCP proxy at the target domain, e.g. `debian.<your-user>.sshx:3000`.
56
67
 
57
- sshx first tries to use the same local port as the remote listener. If that local port is already occupied, it automatically tries the next port (`+1`) until it finds a free one. Run `sshx forward` to see the active mapping.
68
+ The URL port is the remote port. sshx does not bind `127.0.0.1:<port>`; it binds the target's private loopback IP instead, so `debian.<your-user>.sshx:8080` and `ubuntu.<your-user>.sshx:8080` can point at different hosts at the same time. Run `sshx forward` to see the active mappings.
58
69
 
59
70
  ### 🌐 Local Domains (macOS, Linux)
60
71
 
61
- - A local DNS responder on `127.0.0.1:53` resolves `*.sshx` names dynamically.
62
- - The domain resolves to localhost; the URL port selects the forwarded local listener.
72
+ - A local DNS responder on `127.0.0.1:53` resolves active target names dynamically.
73
+ - Each target domain resolves to a private loopback IP; the URL port selects the remote listener.
63
74
  - On macOS, `/etc/resolver/<suffix>` is configured once (with `sudo` when needed).
64
75
  - All terminals on the same host share one DNS resolver and forwarding daemon.
65
76
 
@@ -128,6 +139,21 @@ sshx -p 2222 user@my-server hostname
128
139
 
129
140
  All existing SSH options work — `-F`, `-o`, `-J`, `ProxyJump`, etc. are handled by OpenSSH.
130
141
 
142
+ ### 1a. Connect to a Docker container
143
+
144
+ ```sh
145
+ # By container name
146
+ sshx my-dev-container
147
+
148
+ # By container ID prefix
149
+ sshx 4fa8bc
150
+
151
+ # Run a command directly
152
+ sshx my-container cat /etc/os-release
153
+ ```
154
+
155
+ sshx detects that the target isn't an SSH host and automatically uses `docker exec`. The command bridge and other features work exactly the same inside containers.
156
+
131
157
  ### 2. Try the command bridge
132
158
 
133
159
  Inside your SSH session on the remote:
@@ -151,13 +177,12 @@ On your **local** machine, open:
151
177
  http://my-server.<your-user>.sshx:8080
152
178
  ```
153
179
 
154
- No `-L` flags, no manual forwarding.
155
-
156
- If local port `8080` is already occupied, sshx will try `8081`, then `8082`, and so on. Check the chosen port with:
180
+ No `-L` flags, no manual forwarding. Since each target gets its own loopback IP, another target can expose its own `8080` at the same time:
157
181
 
158
182
  ```sh
159
183
  sshx forward
160
- # 8080 -> my-server:8080
184
+ # http://my-server.<your-user>.sshx:8080 -> my-server:8080
185
+ # http://other-server.<your-user>.sshx:8080 -> other-server:8080
161
186
  ```
162
187
 
163
188
  ---
@@ -175,17 +200,9 @@ features:
175
200
  # Remote-to-local command bridge (`sshx local <cmd>` on the remote)
176
201
  commandBridge: true
177
202
 
178
- ports:
179
- # Auto-detect loopback TCP listeners on the remote and forward them.
180
- auto: true
181
- # Future: also detect 0.0.0.0 listeners.
182
- # bindAll: false
183
-
184
- domains:
185
- # Enable local domain binding (<host>.<user>.sshx:<port>).
186
- enabled: true
187
- # Custom domain suffix. Default: <local-user>.sshx
188
- suffix: user.sshx
203
+ # Auto-detect remote loopback TCP listeners and expose them via
204
+ # <host>.<user>.sshx:<remote-port>.
205
+ autoForward: true
189
206
 
190
207
  commands:
191
208
  # Commands blocked from bridge execution.
@@ -216,7 +233,7 @@ commands:
216
233
  4. **Forwarding**: Detected ports are forwarded through a single shared local daemon using `ssh -W`.
217
234
  5. **Domains**: The local DNS responder maps `<target>.<suffix>` → localhost. The browser's URL port selects the local forwarded port.
218
235
 
219
- When `sshx` is invoked for a **non-matching host** (no sshx config, or host not in scope), it `exec`s the real `ssh` directly — no daemon, no installation, no overhead.
236
+ When `sshx` is invoked for a **non-matching host** (no sshx config, or host not in scope), it first checks if the target resolves to a running Docker container. If neither SSH nor Docker matches, it `exec`s the real `ssh` directly — no daemon, no installation, no overhead.
220
237
 
221
238
  ---
222
239
 
@@ -225,20 +242,22 @@ When `sshx` is invoked for a **non-matching host** (no sshx config, or host not
225
242
  - `sshx --no-wrap ...` — skip all sshx behavior and call raw `ssh`.
226
243
  - `SSHX_DISABLE=1 sshx ...` — same as `--no-wrap`, useful in scripts.
227
244
  - `sshx local ...` on a **client** (not inside a remote session) — errors immediately with a clear message. `local` is globally reserved.
245
+ - Docker containers that aren't running or can't be reached are pure passthrough — sshx falls back to raw `ssh` with no side effects.
228
246
  - Unmatched hosts are pure passthrough — no files created, no processes started.
229
247
 
230
248
  ---
231
249
 
232
250
  ## Platform Support
233
251
 
234
- | Platform | Client | Server |
235
- |---|---|---|
236
- | macOS | ✅ | — |
237
- | Linux | ✅ | ✅ |
238
- | Windows | 🔜 | — |
252
+ | Platform | Client | Server | Docker Client |
253
+ |---|---|---|---|
254
+ | macOS | ✅ | — | ✅ |
255
+ | Linux | ✅ | ✅ | ✅ |
256
+ | Windows | 🔜 | — | 🔜 |
239
257
 
240
258
  - **Client**: macOS and Linux are fully supported.
241
259
  - **Server**: Linux is required for the remote sshx server (uses `/proc/net/tcp*` for port detection).
260
+ - **Docker Client**: macOS and Linux — targets any running Docker container via `docker exec`.
242
261
 
243
262
  ---
244
263
 
@@ -248,7 +267,7 @@ When `sshx` is invoked for a **non-matching host** (no sshx config, or host not
248
267
  sshx/
249
268
  ├── cmd/sshx/ # Main entry point
250
269
  ├── internal/
251
- │ ├── cli/ # CLI parsing, host detection
270
+ │ ├── cli/ # CLI parsing, host detection, Docker container resolution
252
271
  │ ├── sshcompat/ # SSH argument compatibility
253
272
  │ ├── config/ # YAML configuration
254
273
  │ ├── protocol/ # Client-server wire protocol
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hahahhh/sshx",
3
- "version": "0.0.2-rc.1",
3
+ "version": "0.0.3-rc.0",
4
4
  "type": "module",
5
5
  "description": "Transparent SSH enhancement wrapper for OpenSSH",
6
6
  "repository": {