# rdsh — dsh の Rust 高速ランチャー(安全な移植)
[English](README.md)
<img src="assets/icon.svg" width="96" alt="rdsh icon">
フル移植ではなく**ホットパスだけ Rust 化+残りは本家 dsh に委譲**する設計です。
起動約98倍・メモリ約1/23を、本家の動作を変えずに実現します。
- 起動中央値 **約0.90ミリ秒**(本家約88ミリ秒)
- 常駐メモリ **約2.9MB**(本家約66MB)・単一バイナリ約806KB(依存ツリー不要)
- `dsh`名で置換しても引数を一字も変えず委譲するため、既存の使い方・スクリプトはそのまま動きます
## 目次
- [実測](#実測)
- [インストール](#インストール)
- [使い方](#使い方)
- [置換モード(dsh として使う)](#置換モードdsh-として使う)
- [Smart-DSH との併用](#smart-dsh-との併用)
- [Web UI(ダッシュボード)](#web-uiダッシュボード)
- [安全設計](#安全設計)
- [高速化の仕組み](#高速化の仕組み)
- [構成](#構成)
- [よくある質問](#よくある質問)
- [ライセンス](#ライセンス)
## 実測
手元環境(Linux x86_64)での測定値です。条件をそろえた前後比較も含みます。
| `--version` 起動(中央値、n=5) | 約0.90ms | 本家dsh 約88ms | 約98倍 |
| `--version` メモリ(最大RSS) | 約2.9MB | 本家 約66MB | 約1/23 |
| フック相当処理のメモリ | 約2.7MB | node同等 約45MB | 約1/16 |
| search(300ファイル・60万行) | 約17ms | 改修前 約41ms | 約2.4倍 |
| tokens(9.6MBテキスト) | 約12ms | 改修前 約35ms | 約2.9倍 |
| sessions --tokens(20件展開) | 約0.41秒 | 改修前 約1.65秒 | 約4.0倍 |
| 配布サイズ | 単一バイナリ約806KB | Nodeツリー約508MB | — |
測定コマンドは `rdsh bench --n 5` と `/usr/bin/time -v` です。再現手順は[高速化の仕組み](#高速化の仕組み)にあります。
## インストール
```sh
git clone https://github.com/sahenjp/rustdsh.git
cd rustdsh
./install.sh # ビルド+ ~/.local/bin/rdsh に導入
./install.sh --as-dsh # rdsh を `dsh` 名でも使えるよう置換(元は dsh-orig に退避)
./install.sh --restore # 置換を元に戻す
./install.sh --prefix=DIR # 導入先を変更(既定 ~/.local/bin)
```
ソースから直接建てる場合は `cargo build --release` で `target/release/rdsh` ができます。
## 使い方
### dsh 互換(委譲)
```sh
rdsh tui # = dsh --profile tui(slim env 付きで委譲)
rdsh --profile web --patch x.yml # オーバーレイ付き起動
rdsh --passthrough tui # slim 無しの完全委譲(非常口)
rdsh --dry-run tui -- --resume abc # 実行内容だけ表示
```
### 高速ネイティブコマンド(Nodeを起動しない)
```sh
rdsh tokens ./AGENTS.md # 入力トークン見積(約4文字=1トークン、CJKは1字1トークン)
rdsh compact ./s.jsonl --max-tokens 8000 # セッションJSONLの圧縮(元ファイル不変)
rdsh sessions --limit 20 --tokens # セッション一覧+展開後トークン見積
rdsh logs --tail 50 --grep ERROR # 起動ログの参照
rdsh profiles / rdsh skills # プロファイル・スキル一覧
rdsh doctor # 本家dsh・DSH_HOME・slim設定の確認
rdsh bench --n 5 # rdsh/dsh の起動比較
rdsh serve # Webダッシュボード(:3080)
```
### hooks.json での使い方(`rdsh guard`)
標準入力(フックJSONまたは生テキスト)を走査し、拒否パターンに一致したらexit 2+理由出力でブロック、それ以外はexit 0で通過します。`--json` で `{"decision":"block"/"approve"}` を返します。パターンの `*` は任意文字列に一致します。
```sh
`dsh`名で呼ばれた場合の振る舞いです。
- rdsh固有の先頭サブコマンド(`tokens`/`guard`/`serve`/`sessions`等)以外は、**引数を一字も変えず本家へexec委譲**します(`dsh --version`・`dsh --profile tui`・`dsh --help`は完全互換)
- 本家の探索順: `RDSH_ORIG_BIN`(旧 `DSH_ORIG_BIN` も有効)→ `~/.config/rdsh/origin` → 退避ファイル(dsh-orig等)→ PATH(自分を除外)→ 既知npmパス
- 命名は本家に準拠:コマンド・フラグはケバブケース(`dump-config`等)、`DSH_`環境変数名前空間は本家の所有とし、rdsh固有キーは `RDSH_` 配下に置きます
- 一時退避: `RDSH_PASSTHROUGH=1 dsh ...`(slim無し)、`RDSH_DRY_RUN=1 dsh ...`(実行内容のみ表示)
- 注意: `dsh tokens` のようにプロファイル名が予約語と衝突する場合は `dsh --profile tokens` で起動してください
## Smart-DSH との併用
[Smart-DSH](https://github.com/hikarioyama/Smart-DSH)はDSHのwebプロファイル用プラグイン集
(モバイルUI・Web Push通知・Esc停止)で、競合バイナリではありません。rdshと共存できます。
```sh
rdsh doctor # dsh版+Smart-DSHバンドルも表示
rdsh --profile web # slim env付きで起動(プラグインに影響なし)
```
併用の注意点です。
- ポート:dsh web GUIと`rdsh serve`は既定3080です。dsh webを3080のまま使い、
`rdsh serve --port 38080` に分けます
- 置換時:`install.sh --as-dsh`後はSmart-DSHの補助スクリプトがPATH上の`dsh`を
Rust製と誤認します。`dsh-orig`を使うか`DSH_PACKAGE_DIR`を指定します
- 版数:Smart-DSHはDSH `0.1.2-rc.1`基準です。`rdsh doctor`の版表示で差異を確認します
## Web UI(ダッシュボード)
```sh
rdsh serve
# → http://127.0.0.1:3080/ を開く(localhost のみ、読取専用API)
# ※ dsh web GUIと同ポートのため競合時は `rdsh serve --port 38080` 等を使ってください
```
| `GET /api/version` | バージョン |
| `GET /api/doctor` | 状態確認 |
| `POST /api/tokens` | トークン推定(`{"text"}`) |
| `POST /api/prune` | 切り詰め(`{"text","max_tokens"}`) |
| `GET /api/bench?n=3` | 起動計測 |
| `GET /api/sessions?limit=20` | セッション一覧 |
| `GET /api/skills` / `/api/profiles` | 一覧 |
依存なし(std のみ+埋め込み単一HTML、CDN不要・オフライン可)です。
## 安全設計
1. agent loop・profile bootの再実装はしません。`exec`委譲のみです
2. slimは**環境変数の追加だけ**です。本家が知らないキーは無視されます
3. `desktop`プロファイル拒否・dump排他など本家のエラー条件をRust側でも再現します
4. 読取系(tokens/search/compact/dump --native/serve API/inspect)は元ファイルを書き換えません
5. `--passthrough`・`RDSH_PASSTHROUGH=1`・`./install.sh --restore`で即時退避できます
### 検証(すべて実行済み)
- `cargo test`:14件通過(トークン計算・ワイルドカード・引数分割)
- `tests/regress.sh`:19件通過(全サブコマンド・異常系・dsh名委譲の隔離検証)
- 高速化の前後で出力をdiff比較し、完全一致を確認(300件search・上限打ち切りsearch)
- 実置換後に `dsh --version`(委譲)と `dsh guard`(新機能)を実機確認
## 高速化の仕組み
- トークン推定のASCII高速路:純ASCIIは `len/4` 一発計算(非ASCIIのみ従来走査、結果は同一)
- searchの二段階化:逐次walkで順序固定→ファイル単位で並列grep→walk順に結合。32ファイル未満は従来の逐次路のままです
- sessions --tokensの展開並列化:zstd展開をスレッド分散(数値は逐次と同一、順序保持)
- ビルドは `opt-level=z`+LTO+strip+`panic=abort` で小型維持(約806KB)
- 再現: `python3` で9.6MBテキスト・300ファイル合成木を作り、新旧バイナリを `time` 比較(旧版はgit worktreeでHEADビルド)
## 構成
- `src/main.rs` — CLI定義・振り分け・`dsh`名検出
- `src/dsh_args.rs` — 本家 `lib/bin.js` 互換の引数分割(読取専用)
- `src/passthrough.rs` — 本家探索+`exec`委譲
- `src/slim.rs` — slim env定義
- `src/tokens.rs` — トークン推定・prune
- `src/search.rs` — 順序保持の並列grep
- `src/compact.rs` — JSONLセッション圧縮
- `src/inspect.rs` — sessions/logs/skills/profiles参照
- `src/guard.rs` — hooks.json用ガード
- `src/serve.rs`+`src/ui.html` — ローカルWeb UI
- `install.sh` — 導入(`--as-dsh`置換/`--restore`復元)
- `tests/regress.sh` — CLI回帰試験(19件)
## よくある質問
- **3080が使用中と言われる**:dsh web GUIと同ポートです。`rdsh serve --port 38080` を使ってください
- **プロファイル名がサブコマンドと被る**:`dsh --profile <name>` 形式で起動してください
- **元に戻したい**:`./install.sh --restore`(退避した本家を復元)
- **`--tokens` の `?` 付き表示**:zstd CLIが無い環境では圧縮サイズからの概算である印です
## ライセンス
MIT([LICENSE](LICENSE))です。