sshler 0.3.2__tar.gz → 0.3.3__tar.gz
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.
- {sshler-0.3.2/sshler.egg-info → sshler-0.3.3}/PKG-INFO +123 -49
- {sshler-0.3.2 → sshler-0.3.3}/README.md +125 -52
- {sshler-0.3.2 → sshler-0.3.3}/pyproject.toml +2 -1
- {sshler-0.3.2 → sshler-0.3.3}/sshler/static/base.js +101 -2
- sshler-0.3.3/sshler/static/favicon-terminal-local.svg +8 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/static/style.css +16 -1
- {sshler-0.3.2 → sshler-0.3.3}/sshler/static/term.js +199 -10
- {sshler-0.3.2 → sshler-0.3.3}/sshler/templates/box.html +1 -1
- sshler-0.3.3/sshler/templates/docs.html +20 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/templates/index.html +16 -11
- {sshler-0.3.2 → sshler-0.3.3}/sshler/templates/partials/dir_listing.html +8 -7
- {sshler-0.3.2 → sshler-0.3.3}/sshler/templates/term.html +16 -15
- {sshler-0.3.2 → sshler-0.3.3}/sshler/webapp.py +54 -10
- {sshler-0.3.2 → sshler-0.3.3/sshler.egg-info}/PKG-INFO +123 -49
- {sshler-0.3.2 → sshler-0.3.3}/sshler.egg-info/SOURCES.txt +1 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler.egg-info/requires.txt +1 -0
- {sshler-0.3.2 → sshler-0.3.3}/tests/test_routes.py +40 -0
- sshler-0.3.2/sshler/templates/docs.html +0 -40
- {sshler-0.3.2 → sshler-0.3.3}/MANIFEST.in +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/setup.cfg +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/__init__.py +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/cli.py +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/config.py +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/scripts/install-sshler-task.ps1 +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/scripts/remove-sshler-task.ps1 +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/scripts/run-sshler.ps1 +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/ssh.py +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/ssh_config.py +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/state.py +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/static/favicon-terminal.svg +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/static/favicon.svg +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/static/file-edit.js +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/static/file-view.js +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/templates/base.html +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/templates/file_edit.html +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/templates/file_view.html +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler/templates/new_box.html +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler.egg-info/dependency_links.txt +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler.egg-info/entry_points.txt +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/sshler.egg-info/top_level.txt +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/tests/test_basic.py +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/tests/test_config.py +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/tests/test_ssh.py +0 -0
- {sshler-0.3.2 → sshler-0.3.3}/tests/test_websocket.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sshler
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: A local FastAPI-powered SSH multiplexer for tmux-in-browser — from your laptop only.
|
|
5
5
|
Author: You
|
|
6
6
|
License-Expression: MIT
|
|
@@ -30,6 +30,7 @@ Requires-Dist: asyncssh>=2.14.0
|
|
|
30
30
|
Requires-Dist: platformdirs>=4.2
|
|
31
31
|
Requires-Dist: pydantic>=2.7
|
|
32
32
|
Requires-Dist: python-multipart>=0.0.9
|
|
33
|
+
Requires-Dist: markdown-it-py>=3.0.0
|
|
33
34
|
Requires-Dist: sqler>=1.2025.9.24
|
|
34
35
|
Provides-Extra: dev
|
|
35
36
|
Requires-Dist: anyio>=4.4; extra == "dev"
|
|
@@ -38,60 +39,42 @@ Requires-Dist: pytest>=8.2; extra == "dev"
|
|
|
38
39
|
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
39
40
|
Requires-Dist: ruff>=0.5.6; extra == "dev"
|
|
40
41
|
|
|
42
|
+
# sshler
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
sshler is a lightweight, local-only web UI that lets you browse remote files over SFTP and jump into tmux sessions in your browser — without installing anything on the remote host.
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
files over SFTP and jump into tmux sessions in your browser — without installing
|
|
46
|
-
anything on the remote host.
|
|
46
|
+
## Features
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
- **Cross-platform**: Runs on Windows 11, macOS, and Linux (anywhere with Python 3.12+)
|
|
49
|
+
- **Local workspace**: Browse your own filesystem and launch native tmux sessions alongside remote hosts (uses WSL tmux on Windows, native tmux on Linux/macOS)
|
|
50
|
+
- **SSH integration**: Uses your existing SSH keys and honors OpenSSH aliases
|
|
51
|
+
- **Terminal in browser**: Opens `tmux new -As <session> -c <dir>` on the remote host and bridges it via WebSocket + xterm.js
|
|
52
|
+
- **File management**: HTMX-based file browser with preview, edit, delete, and "Open Terminal Here"
|
|
53
|
+
- **Auto-configuration**: Creates starter config on first run
|
|
54
|
+
- **Alias resolution**: Falls back to `ssh -G` when DNS fails; reset overrides with one click
|
|
55
|
+
- **File operations**: Preview, edit (≤256 KB), and delete files with CodeMirror editor
|
|
56
|
+
- **Bilingual UI**: Full English and Japanese language support
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
- **日本語:** Windows 11 を含む Python が動く環境ならどこでも動作します。
|
|
54
|
-
- Includes a "local" workspace card so you can browse your own filesystem and launch WSL-backed tmux sessions alongside remote hosts
|
|
55
|
-
- **日本語:** ローカルワークスペースカードを備え、ローカル/WSL のファイルや tmux も同じ UI で扱えます。
|
|
56
|
-
- Uses your existing SSH keys
|
|
57
|
-
- **日本語:** 既存の SSH 鍵をそのまま利用します。
|
|
58
|
-
- Opens `tmux new -As <session> -c <dir>` on the remote host and bridges it to the browser via WebSocket + xterm.js
|
|
59
|
-
- **日本語:** リモートで `tmux new -As <session> -c <dir>` を実行し、WebSocket と xterm.js でブラウザに橋渡しします。
|
|
60
|
-
- HTMX-based file browser with “Open Terminal Here”
|
|
61
|
-
- **日本語:** HTMX 製のファイルブラウザから「このディレクトリで端末を開く」がワンクリックで可能です。
|
|
62
|
-
- Auto-creates a starter config at first run
|
|
63
|
-
- **日本語:** 初回起動時に自動で設定ファイルを生成します。
|
|
64
|
-
- Honors your OpenSSH aliases; if DNS fails it resolves them via `ssh -G` and you can reset overrides with a single click
|
|
65
|
-
- **日本語:** OpenSSH のエイリアスを解釈し、DNS 解決に失敗した場合でも `ssh -G` で補完します。ワンクリックで上書きをリセットできます。
|
|
66
|
-
- One-click file previews: view remote files in a new tab without leaving the browser
|
|
67
|
-
- **日本語:** ワンクリックでプレビュー表示。ブラウザを離れずに内容確認できます。
|
|
68
|
-
- Inline edits for lightweight text files (≤256 KB) with a CodeMirror editor and Save button
|
|
69
|
-
- **日本語:** 256 KB 以下のテキストならブラウザ内で編集し、その場で保存できます。
|
|
58
|
+
## Install
|
|
70
59
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
### PyPI (recommended) / PyPI からのインストール
|
|
60
|
+
### PyPI (recommended)
|
|
74
61
|
|
|
75
62
|
```bash
|
|
76
63
|
pip install sshler
|
|
77
64
|
|
|
78
|
-
#
|
|
65
|
+
# Launch once to create the config + systemd/service assets
|
|
79
66
|
sshler serve
|
|
80
67
|
```
|
|
81
68
|
|
|
82
|
-
- **日本語:** `pip install sshler` で最新の安定版を取得し、`sshler serve` を実行すると初期設定ファイルが生成されます。
|
|
83
|
-
|
|
84
69
|
Requires Python **3.12+**.
|
|
85
70
|
|
|
86
|
-
### Development
|
|
71
|
+
### Development
|
|
87
72
|
|
|
88
73
|
```bash
|
|
89
74
|
uv pip install -e .
|
|
90
75
|
# or: pip install -e .
|
|
91
76
|
```
|
|
92
77
|
|
|
93
|
-
- **日本語:** 開発時は editable install (`-e`) を利用してください。
|
|
94
|
-
|
|
95
78
|
After cloning the repository, install the dev extras and run the usual tooling:
|
|
96
79
|
|
|
97
80
|
```bash
|
|
@@ -100,9 +83,7 @@ uv run ruff check .
|
|
|
100
83
|
uv run pytest
|
|
101
84
|
```
|
|
102
85
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
## Run / 実行
|
|
86
|
+
## Run
|
|
106
87
|
|
|
107
88
|
```bash
|
|
108
89
|
sshler serve
|
|
@@ -110,8 +91,6 @@ sshler serve
|
|
|
110
91
|
|
|
111
92
|
The app will open `http://127.0.0.1:8822` in your default browser.
|
|
112
93
|
|
|
113
|
-
- **日本語:** 上記を実行するとデフォルトブラウザで `http://127.0.0.1:8822` が開きます。
|
|
114
|
-
|
|
115
94
|
## Configuration / 設定
|
|
116
95
|
|
|
117
96
|
sshler reads your existing OpenSSH config (`~/.ssh/config`) and shows every concrete `Host` entry automatically. Any favourites, default directories, or custom hosts you add through the UI are stored in a companion YAML file.
|
|
@@ -167,9 +146,9 @@ Hit “Add Box” in the UI to define a host that isn’t in your SSH config (fo
|
|
|
167
146
|
|
|
168
147
|
### CLI options
|
|
169
148
|
|
|
170
|
-
```
|
|
149
|
+
```bash
|
|
171
150
|
sshler serve \
|
|
172
|
-
--
|
|
151
|
+
--host 127.0.0.1 \
|
|
173
152
|
--port 8822 \
|
|
174
153
|
--max-upload-mb 50 \
|
|
175
154
|
--allow-origin http://workstation:8822 \
|
|
@@ -178,17 +157,28 @@ sshler serve \
|
|
|
178
157
|
--log-level info
|
|
179
158
|
```
|
|
180
159
|
|
|
181
|
-
- `--
|
|
182
|
-
- `--
|
|
183
|
-
- `--
|
|
160
|
+
- `--host` (alias `--bind`) sets the bind address (default: `127.0.0.1` for localhost-only). Use `0.0.0.0` to expose on all interfaces, but **only on trusted networks with `--auth` and TLS**.
|
|
161
|
+
- `--port` sets the port number (default: `8822`).
|
|
162
|
+
- `--allow-origin` can be repeated to expand CORS; combine it with `--auth` if you expose the UI beyond localhost.
|
|
163
|
+
- `--auth user:pass` enables HTTP basic authentication (recommended if binding to `0.0.0.0`).
|
|
164
|
+
- `--max-upload-mb` sets the upload size limit (default: 50 MB).
|
|
184
165
|
- `--no-ssh-alias` disables the `ssh -G` fallback when DNS fails.
|
|
185
166
|
- `--token` lets you supply your own `X-SSHLER-TOKEN` (otherwise a secure random value is generated).
|
|
186
|
-
- `--log-level` feeds directly into uvicorn.
|
|
167
|
+
- `--log-level` feeds directly into uvicorn (options: `critical`, `error`, `warning`, `info`, `debug`, `trace`).
|
|
187
168
|
|
|
188
169
|
The server prints the token (and, if enabled, the basic auth username) on startup so you can copy it into API clients or browser extensions.
|
|
189
170
|
|
|
190
171
|
- **日本語:** サーバー起動時にトークン(および Basic 認証を有効にした場合はユーザー名)を表示するので、API クライアントやブラウザ拡張に貼り付けて利用できます。
|
|
191
172
|
|
|
173
|
+
### Terminal notifications
|
|
174
|
+
|
|
175
|
+
- Send a bell (`printf '\a'`) from tmux or your shell to flash the browser title and raise a desktop notification whenever the sshler tab is hidden.
|
|
176
|
+
- For richer messages use OSC 777: `printf '\033]777;notify=Codex%20done|Check%20the%20output\a'`. The text before the `|` becomes the title; the second part is the body.
|
|
177
|
+
- JSON payloads are also supported: `printf '\033]777;notify={"title":"Codex","message":"All tasks finished"}\a'`.
|
|
178
|
+
- The first notification prompts the browser for permission. Denying it still leaves the in-app toast and title badge when you return to the tab.
|
|
179
|
+
|
|
180
|
+
- **日本語:** タブが非表示のときに `printf '\a'` でベルを送ると、ブラウザタイトルが点滅しデスクトップ通知が表示されます。`printf '\033]777;notify=タイトル|本文\a'` で任意メッセージを送信でき、JSON (`notify={"title":"...","message":"..."}`) にも対応しています。初回は通知許可のダイアログが表示されますが、拒否した場合でもタブ復帰時にトーストとタイトルのバッジで気付けます。
|
|
181
|
+
|
|
192
182
|
## Autostart / 自動起動
|
|
193
183
|
|
|
194
184
|
### Windows (Task Scheduler)
|
|
@@ -238,8 +228,92 @@ All assets are used under their respective MIT/BSD-style licenses. sshler itself
|
|
|
238
228
|
|
|
239
229
|
- **日本語:** 依存ライブラリはいずれも寛容なライセンス (MIT/BSD) で提供されています。sshler 本体も MIT ライセンスで配布されます。
|
|
240
230
|
|
|
241
|
-
## Why
|
|
231
|
+
## Why "sshler"?
|
|
232
|
+
|
|
233
|
+
Because sometimes you want less VS Code, more terminal — but still in a nice browser tab.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
# 日本語ドキュメント
|
|
238
|
+
|
|
239
|
+
sshler はローカル専用の軽量 Web UI で、リモートファイルを SFTP で閲覧したり、ブラウザ上で tmux セッションに接続したりできます。リモート側に追加ソフトをインストールする必要はありません。
|
|
240
|
+
|
|
241
|
+
## 特徴
|
|
242
|
+
|
|
243
|
+
- **クロスプラットフォーム**: Windows 11、macOS、Linux で動作(Python 3.12+ が必要)
|
|
244
|
+
- **ローカルワークスペース**: ローカルファイルシステムを閲覧し、リモートホストと並べてネイティブの tmux セッションを起動(Windows では WSL tmux、Linux/macOS ではネイティブ tmux を使用)
|
|
245
|
+
- **SSH 統合**: 既存の SSH 鍵を使用し、OpenSSH エイリアスに対応
|
|
246
|
+
- **ブラウザ内ターミナル**: リモートホストで `tmux new -As <session> -c <dir>` を開き、WebSocket + xterm.js 経由で接続
|
|
247
|
+
- **ファイル管理**: プレビュー、編集、削除、「ここでターミナルを開く」機能を備えた HTMX ベースのファイルブラウザ
|
|
248
|
+
- **自動設定**: 初回起動時にスターター設定を作成
|
|
249
|
+
- **エイリアス解決**: DNS 失敗時は `ssh -G` にフォールバック。ワンクリックで上書きをリセット
|
|
250
|
+
- **ファイル操作**: CodeMirror エディタでファイルのプレビュー、編集(256 KB 以下)、削除が可能
|
|
251
|
+
- **バイリンガル UI**: 英語と日本語の完全サポート
|
|
252
|
+
|
|
253
|
+
## インストール
|
|
254
|
+
|
|
255
|
+
### PyPI(推奨)
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
pip install sshler
|
|
259
|
+
|
|
260
|
+
# 設定ファイルと systemd/サービスアセットを作成するため一度起動
|
|
261
|
+
sshler serve
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Python **3.12+** が必要です。
|
|
265
|
+
|
|
266
|
+
### 開発用
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
uv pip install -e .
|
|
270
|
+
# または: pip install -e .
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
リポジトリをクローンした後、dev extras をインストールして通常のツールを実行:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
uv sync --group dev
|
|
277
|
+
uv run ruff check .
|
|
278
|
+
uv run pytest
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## 実行
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
sshler serve
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
デフォルトブラウザで `http://127.0.0.1:8822` が開きます。
|
|
288
|
+
|
|
289
|
+
## 設定
|
|
290
|
+
|
|
291
|
+
sshler は既存の OpenSSH 設定(`~/.ssh/config`)を読み取り、すべての具体的な `Host` エントリを自動的に表示します。UI を通じて追加したお気に入り、デフォルトディレクトリ、カスタムホストは、付属の YAML ファイルに保存されます。
|
|
292
|
+
|
|
293
|
+
設定ファイルは初回実行時に作成されます:
|
|
294
|
+
|
|
295
|
+
- Windows: `%APPDATA%\sshler\boxes.yaml`
|
|
296
|
+
- macOS/Linux: `~/.config/sshler/boxes.yaml`
|
|
297
|
+
|
|
298
|
+
例:
|
|
299
|
+
|
|
300
|
+
```yaml
|
|
301
|
+
boxes:
|
|
302
|
+
- name: gabu-server
|
|
303
|
+
host: example.tailnet.ts.net
|
|
304
|
+
ssh_alias: gabu-server
|
|
305
|
+
user: gabu
|
|
306
|
+
port: 22
|
|
307
|
+
keyfile: "C:/Users/gabu/.ssh/id_ed25519"
|
|
308
|
+
favorites:
|
|
309
|
+
- /home/gabu
|
|
310
|
+
- /home/gabu/projects
|
|
311
|
+
- /srv/codex
|
|
312
|
+
default_dir: /home/gabu
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
> ヒント: ホームパスが `/home/<user>` でない場合は `default_dir` を設定してください。OpenSSH エイリアスを使用する場合は `ssh_alias:` を追加すると、DNS 失敗時に `ssh -G` で解決します。
|
|
242
316
|
|
|
243
|
-
|
|
317
|
+
## 名前の由来
|
|
244
318
|
|
|
245
|
-
|
|
319
|
+
VS Code だけに頼らず、ブラウザタブの中で軽快にターミナルを扱いたい──そんな願いからこの名前になりました。
|
|
@@ -1,57 +1,39 @@
|
|
|
1
|
+
# sshler
|
|
1
2
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- **日本語:** リモートで `tmux new -As <session> -c <dir>` を実行し、WebSocket と xterm.js でブラウザに橋渡しします。
|
|
20
|
-
- HTMX-based file browser with “Open Terminal Here”
|
|
21
|
-
- **日本語:** HTMX 製のファイルブラウザから「このディレクトリで端末を開く」がワンクリックで可能です。
|
|
22
|
-
- Auto-creates a starter config at first run
|
|
23
|
-
- **日本語:** 初回起動時に自動で設定ファイルを生成します。
|
|
24
|
-
- Honors your OpenSSH aliases; if DNS fails it resolves them via `ssh -G` and you can reset overrides with a single click
|
|
25
|
-
- **日本語:** OpenSSH のエイリアスを解釈し、DNS 解決に失敗した場合でも `ssh -G` で補完します。ワンクリックで上書きをリセットできます。
|
|
26
|
-
- One-click file previews: view remote files in a new tab without leaving the browser
|
|
27
|
-
- **日本語:** ワンクリックでプレビュー表示。ブラウザを離れずに内容確認できます。
|
|
28
|
-
- Inline edits for lightweight text files (≤256 KB) with a CodeMirror editor and Save button
|
|
29
|
-
- **日本語:** 256 KB 以下のテキストならブラウザ内で編集し、その場で保存できます。
|
|
30
|
-
|
|
31
|
-
## Install / インストール
|
|
32
|
-
|
|
33
|
-
### PyPI (recommended) / PyPI からのインストール
|
|
3
|
+
sshler is a lightweight, local-only web UI that lets you browse remote files over SFTP and jump into tmux sessions in your browser — without installing anything on the remote host.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Cross-platform**: Runs on Windows 11, macOS, and Linux (anywhere with Python 3.12+)
|
|
8
|
+
- **Local workspace**: Browse your own filesystem and launch native tmux sessions alongside remote hosts (uses WSL tmux on Windows, native tmux on Linux/macOS)
|
|
9
|
+
- **SSH integration**: Uses your existing SSH keys and honors OpenSSH aliases
|
|
10
|
+
- **Terminal in browser**: Opens `tmux new -As <session> -c <dir>` on the remote host and bridges it via WebSocket + xterm.js
|
|
11
|
+
- **File management**: HTMX-based file browser with preview, edit, delete, and "Open Terminal Here"
|
|
12
|
+
- **Auto-configuration**: Creates starter config on first run
|
|
13
|
+
- **Alias resolution**: Falls back to `ssh -G` when DNS fails; reset overrides with one click
|
|
14
|
+
- **File operations**: Preview, edit (≤256 KB), and delete files with CodeMirror editor
|
|
15
|
+
- **Bilingual UI**: Full English and Japanese language support
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
### PyPI (recommended)
|
|
34
20
|
|
|
35
21
|
```bash
|
|
36
22
|
pip install sshler
|
|
37
23
|
|
|
38
|
-
#
|
|
24
|
+
# Launch once to create the config + systemd/service assets
|
|
39
25
|
sshler serve
|
|
40
26
|
```
|
|
41
27
|
|
|
42
|
-
- **日本語:** `pip install sshler` で最新の安定版を取得し、`sshler serve` を実行すると初期設定ファイルが生成されます。
|
|
43
|
-
|
|
44
28
|
Requires Python **3.12+**.
|
|
45
29
|
|
|
46
|
-
### Development
|
|
30
|
+
### Development
|
|
47
31
|
|
|
48
32
|
```bash
|
|
49
33
|
uv pip install -e .
|
|
50
34
|
# or: pip install -e .
|
|
51
35
|
```
|
|
52
36
|
|
|
53
|
-
- **日本語:** 開発時は editable install (`-e`) を利用してください。
|
|
54
|
-
|
|
55
37
|
After cloning the repository, install the dev extras and run the usual tooling:
|
|
56
38
|
|
|
57
39
|
```bash
|
|
@@ -60,9 +42,7 @@ uv run ruff check .
|
|
|
60
42
|
uv run pytest
|
|
61
43
|
```
|
|
62
44
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
## Run / 実行
|
|
45
|
+
## Run
|
|
66
46
|
|
|
67
47
|
```bash
|
|
68
48
|
sshler serve
|
|
@@ -70,8 +50,6 @@ sshler serve
|
|
|
70
50
|
|
|
71
51
|
The app will open `http://127.0.0.1:8822` in your default browser.
|
|
72
52
|
|
|
73
|
-
- **日本語:** 上記を実行するとデフォルトブラウザで `http://127.0.0.1:8822` が開きます。
|
|
74
|
-
|
|
75
53
|
## Configuration / 設定
|
|
76
54
|
|
|
77
55
|
sshler reads your existing OpenSSH config (`~/.ssh/config`) and shows every concrete `Host` entry automatically. Any favourites, default directories, or custom hosts you add through the UI are stored in a companion YAML file.
|
|
@@ -127,9 +105,9 @@ Hit “Add Box” in the UI to define a host that isn’t in your SSH config (fo
|
|
|
127
105
|
|
|
128
106
|
### CLI options
|
|
129
107
|
|
|
130
|
-
```
|
|
108
|
+
```bash
|
|
131
109
|
sshler serve \
|
|
132
|
-
--
|
|
110
|
+
--host 127.0.0.1 \
|
|
133
111
|
--port 8822 \
|
|
134
112
|
--max-upload-mb 50 \
|
|
135
113
|
--allow-origin http://workstation:8822 \
|
|
@@ -138,17 +116,28 @@ sshler serve \
|
|
|
138
116
|
--log-level info
|
|
139
117
|
```
|
|
140
118
|
|
|
141
|
-
- `--
|
|
142
|
-
- `--
|
|
143
|
-
- `--
|
|
119
|
+
- `--host` (alias `--bind`) sets the bind address (default: `127.0.0.1` for localhost-only). Use `0.0.0.0` to expose on all interfaces, but **only on trusted networks with `--auth` and TLS**.
|
|
120
|
+
- `--port` sets the port number (default: `8822`).
|
|
121
|
+
- `--allow-origin` can be repeated to expand CORS; combine it with `--auth` if you expose the UI beyond localhost.
|
|
122
|
+
- `--auth user:pass` enables HTTP basic authentication (recommended if binding to `0.0.0.0`).
|
|
123
|
+
- `--max-upload-mb` sets the upload size limit (default: 50 MB).
|
|
144
124
|
- `--no-ssh-alias` disables the `ssh -G` fallback when DNS fails.
|
|
145
125
|
- `--token` lets you supply your own `X-SSHLER-TOKEN` (otherwise a secure random value is generated).
|
|
146
|
-
- `--log-level` feeds directly into uvicorn.
|
|
126
|
+
- `--log-level` feeds directly into uvicorn (options: `critical`, `error`, `warning`, `info`, `debug`, `trace`).
|
|
147
127
|
|
|
148
128
|
The server prints the token (and, if enabled, the basic auth username) on startup so you can copy it into API clients or browser extensions.
|
|
149
129
|
|
|
150
130
|
- **日本語:** サーバー起動時にトークン(および Basic 認証を有効にした場合はユーザー名)を表示するので、API クライアントやブラウザ拡張に貼り付けて利用できます。
|
|
151
131
|
|
|
132
|
+
### Terminal notifications
|
|
133
|
+
|
|
134
|
+
- Send a bell (`printf '\a'`) from tmux or your shell to flash the browser title and raise a desktop notification whenever the sshler tab is hidden.
|
|
135
|
+
- For richer messages use OSC 777: `printf '\033]777;notify=Codex%20done|Check%20the%20output\a'`. The text before the `|` becomes the title; the second part is the body.
|
|
136
|
+
- JSON payloads are also supported: `printf '\033]777;notify={"title":"Codex","message":"All tasks finished"}\a'`.
|
|
137
|
+
- The first notification prompts the browser for permission. Denying it still leaves the in-app toast and title badge when you return to the tab.
|
|
138
|
+
|
|
139
|
+
- **日本語:** タブが非表示のときに `printf '\a'` でベルを送ると、ブラウザタイトルが点滅しデスクトップ通知が表示されます。`printf '\033]777;notify=タイトル|本文\a'` で任意メッセージを送信でき、JSON (`notify={"title":"...","message":"..."}`) にも対応しています。初回は通知許可のダイアログが表示されますが、拒否した場合でもタブ復帰時にトーストとタイトルのバッジで気付けます。
|
|
140
|
+
|
|
152
141
|
## Autostart / 自動起動
|
|
153
142
|
|
|
154
143
|
### Windows (Task Scheduler)
|
|
@@ -198,8 +187,92 @@ All assets are used under their respective MIT/BSD-style licenses. sshler itself
|
|
|
198
187
|
|
|
199
188
|
- **日本語:** 依存ライブラリはいずれも寛容なライセンス (MIT/BSD) で提供されています。sshler 本体も MIT ライセンスで配布されます。
|
|
200
189
|
|
|
201
|
-
## Why
|
|
190
|
+
## Why "sshler"?
|
|
191
|
+
|
|
192
|
+
Because sometimes you want less VS Code, more terminal — but still in a nice browser tab.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
# 日本語ドキュメント
|
|
197
|
+
|
|
198
|
+
sshler はローカル専用の軽量 Web UI で、リモートファイルを SFTP で閲覧したり、ブラウザ上で tmux セッションに接続したりできます。リモート側に追加ソフトをインストールする必要はありません。
|
|
199
|
+
|
|
200
|
+
## 特徴
|
|
201
|
+
|
|
202
|
+
- **クロスプラットフォーム**: Windows 11、macOS、Linux で動作(Python 3.12+ が必要)
|
|
203
|
+
- **ローカルワークスペース**: ローカルファイルシステムを閲覧し、リモートホストと並べてネイティブの tmux セッションを起動(Windows では WSL tmux、Linux/macOS ではネイティブ tmux を使用)
|
|
204
|
+
- **SSH 統合**: 既存の SSH 鍵を使用し、OpenSSH エイリアスに対応
|
|
205
|
+
- **ブラウザ内ターミナル**: リモートホストで `tmux new -As <session> -c <dir>` を開き、WebSocket + xterm.js 経由で接続
|
|
206
|
+
- **ファイル管理**: プレビュー、編集、削除、「ここでターミナルを開く」機能を備えた HTMX ベースのファイルブラウザ
|
|
207
|
+
- **自動設定**: 初回起動時にスターター設定を作成
|
|
208
|
+
- **エイリアス解決**: DNS 失敗時は `ssh -G` にフォールバック。ワンクリックで上書きをリセット
|
|
209
|
+
- **ファイル操作**: CodeMirror エディタでファイルのプレビュー、編集(256 KB 以下)、削除が可能
|
|
210
|
+
- **バイリンガル UI**: 英語と日本語の完全サポート
|
|
211
|
+
|
|
212
|
+
## インストール
|
|
213
|
+
|
|
214
|
+
### PyPI(推奨)
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pip install sshler
|
|
218
|
+
|
|
219
|
+
# 設定ファイルと systemd/サービスアセットを作成するため一度起動
|
|
220
|
+
sshler serve
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Python **3.12+** が必要です。
|
|
224
|
+
|
|
225
|
+
### 開発用
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
uv pip install -e .
|
|
229
|
+
# または: pip install -e .
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
リポジトリをクローンした後、dev extras をインストールして通常のツールを実行:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
uv sync --group dev
|
|
236
|
+
uv run ruff check .
|
|
237
|
+
uv run pytest
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## 実行
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
sshler serve
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
デフォルトブラウザで `http://127.0.0.1:8822` が開きます。
|
|
247
|
+
|
|
248
|
+
## 設定
|
|
249
|
+
|
|
250
|
+
sshler は既存の OpenSSH 設定(`~/.ssh/config`)を読み取り、すべての具体的な `Host` エントリを自動的に表示します。UI を通じて追加したお気に入り、デフォルトディレクトリ、カスタムホストは、付属の YAML ファイルに保存されます。
|
|
251
|
+
|
|
252
|
+
設定ファイルは初回実行時に作成されます:
|
|
253
|
+
|
|
254
|
+
- Windows: `%APPDATA%\sshler\boxes.yaml`
|
|
255
|
+
- macOS/Linux: `~/.config/sshler/boxes.yaml`
|
|
256
|
+
|
|
257
|
+
例:
|
|
258
|
+
|
|
259
|
+
```yaml
|
|
260
|
+
boxes:
|
|
261
|
+
- name: gabu-server
|
|
262
|
+
host: example.tailnet.ts.net
|
|
263
|
+
ssh_alias: gabu-server
|
|
264
|
+
user: gabu
|
|
265
|
+
port: 22
|
|
266
|
+
keyfile: "C:/Users/gabu/.ssh/id_ed25519"
|
|
267
|
+
favorites:
|
|
268
|
+
- /home/gabu
|
|
269
|
+
- /home/gabu/projects
|
|
270
|
+
- /srv/codex
|
|
271
|
+
default_dir: /home/gabu
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
> ヒント: ホームパスが `/home/<user>` でない場合は `default_dir` を設定してください。OpenSSH エイリアスを使用する場合は `ssh_alias:` を追加すると、DNS 失敗時に `ssh -G` で解決します。
|
|
202
275
|
|
|
203
|
-
|
|
276
|
+
## 名前の由来
|
|
204
277
|
|
|
205
|
-
|
|
278
|
+
VS Code だけに頼らず、ブラウザタブの中で軽快にターミナルを扱いたい──そんな願いからこの名前になりました。
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "sshler"
|
|
8
|
-
version = "0.3.
|
|
8
|
+
version = "0.3.3"
|
|
9
9
|
description = "A local FastAPI-powered SSH multiplexer for tmux-in-browser — from your laptop only."
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.12"
|
|
@@ -20,6 +20,7 @@ dependencies = [
|
|
|
20
20
|
"platformdirs>=4.2",
|
|
21
21
|
"pydantic>=2.7",
|
|
22
22
|
"python-multipart>=0.0.9",
|
|
23
|
+
"markdown-it-py>=3.0.0",
|
|
23
24
|
"sqler>=1.2025.9.24",
|
|
24
25
|
]
|
|
25
26
|
classifiers = [
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const FAVICONS = {
|
|
3
3
|
default: "/static/favicon.svg",
|
|
4
4
|
terminal: "/static/favicon-terminal.svg",
|
|
5
|
+
"terminal-local": "/static/favicon-terminal-local.svg",
|
|
5
6
|
};
|
|
6
7
|
const LANG_KEY = "sshler-language";
|
|
7
8
|
|
|
@@ -10,11 +11,89 @@
|
|
|
10
11
|
"nav.boxes": "Boxes",
|
|
11
12
|
"nav.addBox": "Add Box",
|
|
12
13
|
"nav.docs": "Docs",
|
|
14
|
+
"boxes.title": "Boxes",
|
|
15
|
+
"boxes.subtitle": "Pick a box to browse and open a terminal. Hosts are imported from your SSH config and any custom boxes you add here.",
|
|
16
|
+
"boxes.localWorkspace": "Local workspace",
|
|
17
|
+
"boxes.fromSSHConfig": "From SSH config",
|
|
18
|
+
"boxes.customBox": "Custom box",
|
|
19
|
+
"boxes.resolvesTo": "resolves to",
|
|
20
|
+
"boxes.favorites": "Favorites",
|
|
21
|
+
"boxes.open": "Open",
|
|
22
|
+
"boxes.terminal": "Terminal",
|
|
23
|
+
"boxes.refresh": "Refresh",
|
|
24
|
+
"boxes.configFile": "Config file:",
|
|
25
|
+
"box.browse": "Browse",
|
|
26
|
+
"box.name": "Name",
|
|
27
|
+
"box.type": "Type",
|
|
28
|
+
"box.size": "Size",
|
|
29
|
+
"box.actions": "Actions",
|
|
30
|
+
"box.preview": "Preview",
|
|
31
|
+
"box.edit": "Edit",
|
|
32
|
+
"box.delete": "Delete",
|
|
33
|
+
"box.createFile": "Create File",
|
|
34
|
+
"box.uploadFile": "Upload File",
|
|
35
|
+
"box.filename": "Filename",
|
|
36
|
+
"box.create": "Create",
|
|
37
|
+
"box.upload": "Upload",
|
|
38
|
+
"term.session": "Session:",
|
|
39
|
+
"term.back": "Back",
|
|
40
|
+
"term.files": "Files",
|
|
41
|
+
"term.scrollMode": "Scroll Mode",
|
|
42
|
+
"term.escape": "Escape",
|
|
43
|
+
"term.ctrlT": "Ctrl+T",
|
|
44
|
+
"term.ctrlC": "Ctrl+C",
|
|
45
|
+
"term.splitH": "Split %",
|
|
46
|
+
"term.splitV": "Split \"",
|
|
47
|
+
"term.newWindow": "New Window",
|
|
48
|
+
"term.renameWindow": "Rename Window",
|
|
49
|
+
"term.killPane": "Kill Pane",
|
|
50
|
+
"term.nextWindow": "Next Window",
|
|
51
|
+
"term.prevWindow": "Prev Window",
|
|
52
|
+
"term.detach": "Detach",
|
|
13
53
|
},
|
|
14
54
|
ja: {
|
|
15
55
|
"nav.boxes": "ボックス",
|
|
16
56
|
"nav.addBox": "ボックスを追加",
|
|
17
57
|
"nav.docs": "ドキュメント",
|
|
58
|
+
"boxes.title": "ボックス",
|
|
59
|
+
"boxes.subtitle": "ボックスを選択してファイルブラウザとターミナルを開きます。SSH 設定からホストが自動的にインポートされ、カスタムボックスも追加できます。",
|
|
60
|
+
"boxes.localWorkspace": "ローカルワークスペース",
|
|
61
|
+
"boxes.fromSSHConfig": "SSH 設定から",
|
|
62
|
+
"boxes.customBox": "カスタムボックス",
|
|
63
|
+
"boxes.resolvesTo": "解決先",
|
|
64
|
+
"boxes.favorites": "お気に入り",
|
|
65
|
+
"boxes.open": "開く",
|
|
66
|
+
"boxes.terminal": "ターミナル",
|
|
67
|
+
"boxes.refresh": "更新",
|
|
68
|
+
"boxes.configFile": "設定ファイル:",
|
|
69
|
+
"box.browse": "ブラウズ",
|
|
70
|
+
"box.name": "名前",
|
|
71
|
+
"box.type": "種類",
|
|
72
|
+
"box.size": "サイズ",
|
|
73
|
+
"box.actions": "操作",
|
|
74
|
+
"box.preview": "プレビュー",
|
|
75
|
+
"box.edit": "編集",
|
|
76
|
+
"box.delete": "削除",
|
|
77
|
+
"box.createFile": "ファイル作成",
|
|
78
|
+
"box.uploadFile": "ファイルアップロード",
|
|
79
|
+
"box.filename": "ファイル名",
|
|
80
|
+
"box.create": "作成",
|
|
81
|
+
"box.upload": "アップロード",
|
|
82
|
+
"term.session": "セッション:",
|
|
83
|
+
"term.back": "戻る",
|
|
84
|
+
"term.files": "ファイル",
|
|
85
|
+
"term.scrollMode": "スクロールモード",
|
|
86
|
+
"term.escape": "Escape",
|
|
87
|
+
"term.ctrlT": "Ctrl+T",
|
|
88
|
+
"term.ctrlC": "Ctrl+C",
|
|
89
|
+
"term.splitH": "横分割 %",
|
|
90
|
+
"term.splitV": "縦分割 \"",
|
|
91
|
+
"term.newWindow": "新規ウィンドウ",
|
|
92
|
+
"term.renameWindow": "ウィンドウ名変更",
|
|
93
|
+
"term.killPane": "ペイン終了",
|
|
94
|
+
"term.nextWindow": "次のウィンドウ",
|
|
95
|
+
"term.prevWindow": "前のウィンドウ",
|
|
96
|
+
"term.detach": "デタッチ",
|
|
18
97
|
},
|
|
19
98
|
};
|
|
20
99
|
|
|
@@ -47,7 +126,7 @@
|
|
|
47
126
|
if (!faviconLink) {
|
|
48
127
|
return;
|
|
49
128
|
}
|
|
50
|
-
const target = mode
|
|
129
|
+
const target = FAVICONS[mode] || FAVICONS.default;
|
|
51
130
|
if (faviconLink.getAttribute("href") !== target) {
|
|
52
131
|
faviconLink.setAttribute("href", target);
|
|
53
132
|
}
|
|
@@ -101,6 +180,16 @@
|
|
|
101
180
|
el.textContent = text;
|
|
102
181
|
}
|
|
103
182
|
});
|
|
183
|
+
|
|
184
|
+
// Also translate placeholders
|
|
185
|
+
const placeholderElements = document.querySelectorAll("[data-i18n-placeholder]");
|
|
186
|
+
placeholderElements.forEach((el) => {
|
|
187
|
+
const key = el.dataset.i18nPlaceholder;
|
|
188
|
+
const text = I18N[lang]?.[key];
|
|
189
|
+
if (text && el.tagName === "INPUT") {
|
|
190
|
+
el.placeholder = text;
|
|
191
|
+
}
|
|
192
|
+
});
|
|
104
193
|
}
|
|
105
194
|
|
|
106
195
|
function updateLangToggle(lang) {
|
|
@@ -192,7 +281,8 @@
|
|
|
192
281
|
// Show modal
|
|
193
282
|
modal.classList.add("visible");
|
|
194
283
|
|
|
195
|
-
// Set initial language
|
|
284
|
+
// Set initial language to match current site language
|
|
285
|
+
const currentLang = getStoredLang();
|
|
196
286
|
switchDocsLanguage(currentLang);
|
|
197
287
|
|
|
198
288
|
// Language switcher in modal
|
|
@@ -255,6 +345,12 @@
|
|
|
255
345
|
showToast(payload.message, status);
|
|
256
346
|
});
|
|
257
347
|
|
|
348
|
+
// Re-translate after HTMX swaps new content
|
|
349
|
+
document.body.addEventListener("htmx:afterSwap", () => {
|
|
350
|
+
const currentLang = getStoredLang();
|
|
351
|
+
translate(currentLang);
|
|
352
|
+
});
|
|
353
|
+
|
|
258
354
|
// Event delegation for delete buttons
|
|
259
355
|
document.body.addEventListener("click", (event) => {
|
|
260
356
|
const deleteBtn = event.target.closest(".delete-file-btn");
|
|
@@ -302,4 +398,7 @@
|
|
|
302
398
|
window.sshlerShowToast = showToast;
|
|
303
399
|
window.sshlerSetFavicon = setFavicon;
|
|
304
400
|
window.sshlerDeleteFile = deleteFile;
|
|
401
|
+
window.sshlerTranslate = function() {
|
|
402
|
+
translate(getStoredLang());
|
|
403
|
+
};
|
|
305
404
|
})();
|