dsh-ssh-tunnel 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_en.md ADDED
@@ -0,0 +1,171 @@
1
+ <p align="center"><a href="README.md">简体中文</a> | <strong>English</strong></p>
2
+
3
+ <div align="center">
4
+ <h1>dsh-ssh-tunnel</h1>
5
+ <p>A multi-host SSH workbench for DeepSeek Harness: host inventory, per-project grants, and a terminal plus dual-pane SFTP in the sidebar.</p>
6
+ <p>The model drives the <strong>SSHManager</strong> tool to run commands and move files; you manage hosts and grants in the sidebar. <strong>Secrets never enter model context</strong>.</p>
7
+
8
+ <p>
9
+ <a href="https://github.com/OMSociety/dsh-ssh-tunnel/releases"><img src="https://img.shields.io/badge/version-1.0.0-4f6ef7" alt="Version"></a>
10
+ <a href="https://github.com/deepseek-ai/dsh"><img src="https://img.shields.io/badge/DSH-%3E%3D0.1.7--rc.2_%3C0.3.0--0-4f6ef7" alt="DSH"></a>
11
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/OMSociety/dsh-ssh-tunnel?color=4f6ef7" alt="License"></a>
12
+ <a href="https://github.com/OMSociety/dsh-ssh-tunnel/stargazers"><img src="https://img.shields.io/github/stars/OMSociety/dsh-ssh-tunnel?color=4f6ef7" alt="Stars"></a>
13
+ <a href="https://github.com/OMSociety/dsh-ssh-tunnel/issues"><img src="https://img.shields.io/github/issues/OMSociety/dsh-ssh-tunnel?color=4f6ef7" alt="Issues"></a>
14
+ </p>
15
+ </div>
16
+
17
+ > **Note:** This is the maintained line of `dsh-ssh-tunnel`, continued independently at the [OMSociety repository](https://github.com/OMSociety/dsh-ssh-tunnel) (standalone since 2026-09-28). The upstream project and the author of this code is [thirsty5034/dsh-ssh-tunnel](https://github.com/thirsty5034/dsh-ssh-tunnel) (MIT, see [LICENSE](LICENSE)). Fixes and issue reports are handled in this repository.
18
+
19
+ ## What this is
20
+
21
+ **dsh-ssh-tunnel** is a community plugin for [DeepSeek Harness](https://github.com/deepseek-ai/dsh), mounted in the sidebar host [dsh-better-sidebar](https://github.com/omdsh-dev/DSH-better-sidebar). It collects your SSH hosts into one **host inventory**, authorizes them per project, and then opens an **interactive terminal** (xterm) or **dual-pane SFTP** in the center panel.
22
+
23
+ It does **not** replace the global `fs` / `subprocess` with a remote disk: remote operations happen only in the `SSHManager` tool you call explicitly and inside the panel, and local and remote files remain two clearly separated sides.
24
+
25
+ Its companion plugin is [dsh-git-forge](https://github.com/OMSociety/dsh-git-forge) (Git credentials and push policy).
26
+
27
+ ## Prior art
28
+
29
+ **The product shape and several UX patterns are informed by the open-source [LiveAgent](https://github.com/thirsty5034/LiveAgent)** (multi-host SSH inventory, project-scoped access, sidebar tunnel management, center terminal / SFTP surfaces).
30
+
31
+ This package is a **DSH-native implementation** (Cordis host/client plugin, `dsh-better-sidebar` tab, `SSHManager` tool, DSH-local secret layout). It is **not** a git fork of LiveAgent and does **not** vendor LiveAgent sources. Consult LiveAgent under its own license when comparing designs.
32
+
33
+ ## Features
34
+
35
+ | Feature | Description |
36
+ |---|---|
37
+ | **Host inventory** | Create, edit and delete hosts; import from your OpenSSH config; password or private key (with passphrase). Keys stay host-side |
38
+ | **Per-project grants** | The grant key is the **DSH session workspace** (`projectPathKey`). **Grant before connect** — Connect never auto-authorizes |
39
+ | **`SSHManager` tool** | Remote exec, SFTP list/read/write/mkdir/rename/delete, upload and download, interactive session I/O; session strategies `reuse_or_create` / `new` / `require_existing` |
40
+ | **Center panel** | Interactive terminal (xterm) and dual-pane SFTP: the project workspace on the left, the remote side on the right, with direct upload and download |
41
+ | **Survives drops** | A dropped session stays as a tombstone you can **Reconnect** (same id) or close; unexpected drops auto-reconnect up to 3 times, ssh2 keepalive 30s × 3 |
42
+ | **Host key fingerprints** | Stored as SHA256 hex in `known_hosts.json`; first connect or a changed fingerprint is confirmed in the sidebar with the fingerprint shown |
43
+ | **Local path guard** | Local upload / download / list / delete paths are constrained to the **project workspace root**, with both lexical and realpath checks |
44
+ | **Bilingual UI** | Sidebar and panel follow the DSH interface language between Chinese and English live |
45
+
46
+ ## Quick start
47
+
48
+ **Option 1: install from the CLI (recommended)**
49
+
50
+ ```powershell
51
+ # 1) stop dsh web first (a running server holds the dependency lock; start it again afterwards)
52
+ dsh plugin --profile web add "github:OMSociety/dsh-ssh-tunnel"
53
+ # 2) restart dsh web
54
+ ```
55
+
56
+ To reproduce a specific install, pin a ref by appending `#<tag or commit sha>` to the repository URL.
57
+
58
+ **Option 2: one-line installer**
59
+
60
+ ```sh
61
+ curl -fsSL https://raw.githubusercontent.com/OMSociety/dsh-ssh-tunnel/main/scripts/install.sh | bash
62
+ ```
63
+
64
+ ```powershell
65
+ irm https://raw.githubusercontent.com/OMSociety/dsh-ssh-tunnel/main/scripts/install.ps1 | iex
66
+ ```
67
+
68
+ Besides installing, the script adds this plugin to the profile's `minimumReleaseAgeExclude`, verifies that `dsh.profile.bundles` really received the entry, and removes the mount older versions wrote by hand into the profile's `cordis.patch.yml`. Add `--dry-run` to print the plan without touching anything.
69
+
70
+ > **Note:** After installing, **refresh the browser page** for the "SSH Tunnel" entry to appear in the sidebar — restarting the host alone is not enough, because the client artifact is fetched when the page loads.
71
+
72
+ **First run**
73
+
74
+ 1. Open the "SSH Tunnel" tab in the sidebar and add a host on the **Hosts** page (password or private key)
75
+ 2. Switch to **Project access** and grant that host to the current project, then save (without a grant you cannot connect — that is intentional)
76
+ 3. Back on **Sessions**, press Connect; the first connection asks you to confirm the host key fingerprint
77
+ 4. Click **Terminal** for an interactive shell, or **SFTP** for the dual-pane panel
78
+ 5. Have the model run `SSHManager action=exec`, list a directory with `sftp_list`, and move a file with `sftp_upload` / `sftp_download` to verify the whole chain
79
+
80
+ ## Sidebar
81
+
82
+ One sidebar tab with three pages:
83
+
84
+ | Page | Purpose |
85
+ |---|---|
86
+ | **Project access** | Hosts the current project may use |
87
+ | **Hosts** | Host CRUD and OpenSSH config scan import |
88
+ | **Sessions** | Connect / disconnect, open the terminal or SFTP; dropped sessions stay as tombstones you can reconnect or close |
89
+
90
+ ## Model tool
91
+
92
+ `SSHManager` actions, grouped by purpose:
93
+
94
+ | Action | Purpose |
95
+ |---|---|
96
+ | `list_hosts` / `list_sessions` | List the host inventory and the current sessions |
97
+ | `create_session` / `close_session` | Open or close a session (together with `session_strategy`) |
98
+ | `exec` | Run a remote command (`command`, `cwd`, `timeout_ms`) |
99
+ | `sftp_list` / `sftp_stat` / `sftp_read_text` / `sftp_write_text` | Remote listing, metadata and text I/O |
100
+ | `sftp_mkdir` / `sftp_rename` / `sftp_delete` | Remote directory creation, rename and delete |
101
+ | `sftp_upload` / `sftp_download` | Transfer files between the project workspace and the remote side |
102
+ | `read_session` / `send_input` / `resize_session` | Read, feed and resize an interactive session |
103
+
104
+ - Session strategies: `reuse_or_create` (default; revives a disconnected session for that host), `new`, `require_existing`, or an explicit `session_id`
105
+ - `timeout_ms` ranges from 1000 to 300000 and applies to exec / SFTP / shell; defaults are 30s for exec and SFTP metadata, 120s for SFTP transfers
106
+ - Authentication is **password** or **private key** only; keyboard-interactive (including bastion web MFA) is not supported
107
+
108
+ ## Security
109
+
110
+ - Tool results and list APIs never return password / PEM / passphrase
111
+ - Local upload, download, list and delete paths are constrained to the **project workspace root** (the host resolves it from the current session workspace rather than assuming a fixed mount point): both lexical and realpath checks apply, and out-of-bounds paths or symlinks pointing outside the workspace are rejected
112
+ - Host keys are stored as **SHA256 hex** in `known_hosts.json`; the first connect or a fingerprint change is confirmed in the sidebar with the fingerprint shown
113
+ - The HTTP API is fenced to loopback / trusted hosts; the browser `Origin` must match; session APIs require `projectPathKey`
114
+ - Prefer key-based auth; rotate credentials immediately if `secrets.json` may have leaked
115
+ - keyboard-interactive is retired: edit such hosts to password or private key
116
+
117
+ ## Where data lives
118
+
119
+ Under `$DSH_HOME/ssh-tunnel/` (directory mode `0700`):
120
+
121
+ | File | Contents |
122
+ |---|---|
123
+ | `hosts.json` | Host metadata (no secret material) |
124
+ | `secrets.json` | Passwords / PEM / passphrases (`0600`) |
125
+ | `grants.json` | `projectPathKey → hostIds[]` |
126
+ | `known_hosts.json` | Trusted host key fingerprints |
127
+
128
+ ## UI internationalization
129
+
130
+ - Namespace: `sshTunnel`; dictionaries `zh` / `en` registered on `ctx.locale`
131
+ - Tab title and panel follow the DSH interface language live
132
+ - Host-side `SSHManager` strings stay English (model-facing)
133
+
134
+ ## Development
135
+
136
+ ```powershell
137
+ npm test # node --test: full regression of the smoke scripts
138
+ npm run check # syntax + smoke tests
139
+ bash scripts/sync-to-dsh.sh # register this checkout into the web profile as link: (dev)
140
+ bash scripts/install.sh --dry-run # print the install plan without touching the profile
141
+ node scripts/portal-probe.mjs # client tab render probe (runs when react resolves, otherwise skips)
142
+ ```
143
+
144
+ Layout and where to change what:
145
+
146
+ ```text
147
+ lib/index.js Host entry: tool registration, /dsh-ssh-tunnel/api routes, grants and path guard, xterm asset serving
148
+ lib/client.js Client bundle (committed; dsh plugin add does not build)
149
+ lib/session.js Session lifecycle: connect, keepalive, drop tombstones and auto-reconnect
150
+ lib/shared/ Pure functions shared by host and client: path / host-key / host-summary / http-trust / persist /
151
+ session-auth / session-policy / shell-buffer / vendor
152
+ scripts/ install.sh · install.ps1 · sync-to-dsh.sh · smoke-test.mjs · portal-probe.mjs
153
+ cordis.patch.yml In-package bundle patch the CLI turns into dsh.profile.bundles
154
+ ```
155
+
156
+ ### xterm loading
157
+
158
+ `@xterm/xterm@5.5.0` and `@xterm/addon-fit@0.11.0` are pinned runtime dependencies. The host serves their UMD and CSS from an allowlisted same-origin route (`/dsh-ssh-tunnel/vendor/xterm.js|addon-fit.js|xterm.css`), and the client loads them with plain `<script>` / `<link>` tags. There is no CDN fallback and no module-table requirement.
159
+
160
+ ## Support and credits
161
+
162
+ - If this plugin helps you, a Star is welcome; questions and suggestions go to [Issues](https://github.com/OMSociety/dsh-ssh-tunnel/issues) or [Pull Requests](https://github.com/OMSociety/dsh-ssh-tunnel/pulls).
163
+ - Changes are recorded in the [CHANGELOG](CHANGELOG.md).
164
+ - [LiveAgent](https://github.com/thirsty5034/LiveAgent): prior art for the product shape and several UX patterns (see "Prior art" above)
165
+ - [dsh-better-sidebar](https://github.com/omdsh-dev/DSH-better-sidebar): the sidebar host and tab contract
166
+ - [dsh-git-forge](https://github.com/OMSociety/dsh-git-forge): sibling plugin for Git credentials and push policy
167
+ - [DeepSeek Harness](https://github.com/deepseek-ai/dsh): the host for plugins, tools and agent shells
168
+
169
+ ## License and author
170
+
171
+ [MIT](LICENSE). Upstream project and code author [@thirsty5034](https://github.com/thirsty5034); maintenance and additions in this repository © 2026 [@OMSociety](https://github.com/OMSociety).
@@ -0,0 +1,4 @@
1
+ # dsh-ssh-tunnel bundle mount
2
+ - insert:
3
+ - id: ssh-tunnel
4
+ name: dsh-ssh-tunnel