@chronosun/dsh-wsl 0.0.0-stage → 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yunson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,234 @@
1
- # Temporary Holding Version
1
+ # @chronosun/dsh-wsl
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Run a DeepSeek Harness session inside a local WSL distribution: `bash`,
4
+ background jobs, the sidebar terminal, `read`/`write`/`edit`, `grep` and `glob`
5
+ all operate on the Linux filesystem — not on a `\\wsl.localhost` share.
6
+
7
+ ## What it gives you
8
+
9
+ - **A WSL workspace picker.** The sidebar gains a `WSL` panel: pick a
10
+ distribution, browse its directories, and adopt one as a workspace. The
11
+ workspace is registered through the official API, so history, diffs and the
12
+ session list keep working; its title is prefixed with `🐧`.
13
+ - **WSL by default inside a WSL workspace.** Opening a `🐧` workspace or
14
+ pressing **New Session** there creates the session under the `WSL` preset
15
+ without asking. The Host rewrites the preset only when the Client names none,
16
+ and only for `\\wsl.localhost\...` / `\\wsl$\...` paths, so Windows
17
+ workspaces and explicit preset choices keep their behavior. An existing
18
+ session keeps the preset recorded when it was created; resuming it never
19
+ switches modes. This works for existing workspaces too — no re-creation is
20
+ needed.
21
+ - **A `WSL` agent preset.** Sessions created in that workspace run their tools
22
+ in Linux. A broker keeps one persistent connection per (distribution, user)
23
+ and disconnects it after **5 idle days** by default (configurable in the
24
+ panel, `0` = never).
25
+ - **A clean environment.** `wsl.exe` normally hands Linux a PATH polluted with
26
+ `/mnt/c`, `/mnt/d` entries, so `node`, `npm`, `git` and `rg` can silently
27
+ resolve to Windows binaries. Every command here runs with the distribution's
28
+ **login PATH minus every `/mnt/*` entry**, so the user's own toolchain
29
+ (`~/.local/bin`, cargo, nvm, `/usr/local/bin`, …) stays reachable and an
30
+ interop binary is never used.
31
+ - **WSL-native `@` discovery.** For a WSL-preset Agent, `@file` candidates are
32
+ indexed inside the distribution (bounded tree, `.gitignore`-aware) and
33
+ returned relative to the Linux cwd, not scanned through the UNC share. The
34
+ Host provider remains for every other preset.
35
+ - **Linux diff summaries and comparisons.** For a WSL-preset Session the plugin
36
+ snapshots the work tree inside the distribution at turn start/end (private
37
+ `GIT_INDEX_FILE`, `write-tree`/`diff-tree`) and serves the changed-files card
38
+ from Linux git. The Host recorder remains the event source and fallback; the
39
+ card's open action still uses the Host's UNC coordinates. Absolute UNC display
40
+ paths are translated to Linux; relative paths are already neutral.
41
+ - **Linux-native worktree creation.** `create_wsl_worktree` creates a retained
42
+ Git worktree with Linux git and returns its path, branch and base commit.
43
+ The Session working directory is unchanged, so pass the returned path (or
44
+ `workdir`) to later tools; the shipped Host `create_worktree` tool is not
45
+ mounted in the WSL preset.
46
+
47
+ ## Why this instead of opening the UNC path
48
+
49
+ Opening `\\wsl.localhost\...` as a Workspace only changes the folder: on Windows
50
+ the standard preset still runs `pwsh`, reads and writes through the 9P share,
51
+ and spawns the Windows `rg`. This bundle changes the **execution world**:
52
+
53
+ | | UNC workspace | WSL preset |
54
+ |---|---|---|
55
+ | shell | Windows `pwsh` | Linux `bash`, clean login PATH |
56
+ | file I/O | 9P share | persistent broker → ext4 |
57
+ | search | Windows ripgrep over 9P | Linux walk / `git ls-files` |
58
+ | model cwd | UNC (`\\wsl.localhost\...`) | `/home/...` |
59
+ | toolchain | Windows node/npm/git | the distribution's own |
60
+
61
+ Measured on a local machine (1000 `stat`, 20 `readdir`): 9P 1.31 ms vs broker
62
+ 0.29 ms per stat (4.5×), 4.48 ms vs 0.49 ms per readdir (9.1×). A cold
63
+ `wsl.exe` is about 120 ms, which is why file and search work go through the
64
+ persistent broker while `bash` keeps DSH's one-shot contract (`workdir`, not a
65
+ persistent `cd`).
66
+
67
+ It is deliberately not a host-preset rewrite and not a `wsl_*` tool set: the
68
+ world is declared as its own preset, so the model never chooses between Windows
69
+ and Linux tools, and upgrades do not depend on the text of a shipped preset.
70
+
71
+ ## Install
72
+
73
+ Published package:
74
+
75
+ ```powershell
76
+ dsh plugin --profile desktop add @chronosun/dsh-wsl
77
+ ```
78
+
79
+ From a source checkout:
80
+
81
+ ```powershell
82
+ npm pack --pack-destination dist
83
+ dsh plugin --profile desktop add dist\chronosun-dsh-wsl-<version>.tgz
84
+ ```
85
+
86
+ Then **quit DSH from the tray and reopen it** — client plugins and preset rows
87
+ load at boot; a page refresh is not enough.
88
+
89
+ Requires: Windows, WSL 2, and a Linux `node` (v18+) inside the distribution,
90
+ used only to run a small helper. Nothing is installed into the distribution.
91
+
92
+ ## Use
93
+
94
+ 1. Sidebar → `WSL` → `+ 添加 WSL 工作区`.
95
+ 2. Choose a distribution, browse to a directory, press `使用此目录`.
96
+ 3. The workspace opens with the `WSL` preset; every later **New Session**
97
+ inside that workspace also defaults to `WSL`. In a WSL session the Agent's
98
+ `Current working directory` is the Linux path (the Host still keeps the UNC
99
+ path for its own diff/`@` features). Ask the agent to run
100
+ `pwd; uname -s; echo $PATH` and it should answer `/home/..., Linux` and a
101
+ five-entry PATH.
102
+ 4. `标记已有` renames existing `\\wsl.localhost\...` workspaces with the `🐧`
103
+ prefix; workspaces that already carry it are skipped and the panel reports
104
+ how many changed. Renaming is only cosmetic — the preset default keys off
105
+ the path, so an unmarked WSL workspace still gets `WSL` sessions.
106
+
107
+ ## Limits (deliberate, documented)
108
+
109
+ - `watch` is not implemented by the WSL filesystem, so the skill catalog is
110
+ collected once (`watch: false`) instead of being invalidated live.
111
+ - The Host keeps the durable session cwd as the UNC path, because host
112
+ features (diff view, `@` references, open-in-app) resolve it through the
113
+ Windows filesystem. WSL-preset sessions present the **Linux** equivalent as
114
+ `Current working directory` to the Agent, so every model-visible path is
115
+ Linux; every tool still accepts either form.
116
+ - A WSL snapshot companion serves the changed-files summary/comparison for WSL
117
+ Sessions; the Host recorder still runs as the `workspace/changes` event
118
+ source and fallback. When the WSL snapshot misses the event race, the card
119
+ falls back to the Host summary. Open coordinates (`path`/`cwd`) stay UNC.
120
+ - A filesystem target carries its own distribution, so workspaces from several
121
+ distributions coexist; a call with a Linux-only path falls back to the
122
+ distribution the world was configured with.
123
+ - `grep` uses a JavaScript regular expression and skips files over 2 MiB;
124
+ `glob`/`grep` require an explicit `path`. Inside a Git worktree both respect
125
+ `.gitignore` (they list files with `git ls-files --exclude-standard`), so
126
+ `build/`, `dist/` and ignored dependency trees are not searched; outside a
127
+ worktree the walk prunes `.git`/`node_modules`.
128
+
129
+ ## SSH and web
130
+
131
+ - `ssh`, `scp`, `rsync` and `curl` are the distribution's own binaries; keys
132
+ and `~/.ssh/config` belong to the distribution user, not to Windows. The
133
+ Agent has no TTY, so use key-based auth (`ssh -o BatchMode=yes host 'cmd'`)
134
+ or `ControlMaster` for reuse; interactive password logins belong in the
135
+ sidebar terminal. A `Host *` block with `ControlMaster auto`,
136
+ `ControlPath ~/.ssh/cm-%r@%h:%p` and `ControlPersist 10m` makes one-shot
137
+ Agent commands reuse a single connection.
138
+ - `web_fetch` / `web_search` run on the Host but share the network. A service
139
+ started inside the distribution is reachable from Windows at
140
+ `http://localhost:<port>` (WSL2 localhost forwarding), so both the web tools
141
+ and `curl` work; use `curl` in `bash` when the service is reachable only
142
+ through an SSH tunnel.
143
+
144
+ ## Doctor and settings
145
+
146
+ The `WSL` panel has **运行诊断**: it checks the WSL version, each distribution's
147
+ user/home, Linux `node`, `git`, `ssh`, SSH keys, `~/.ssh/config`, the login PATH
148
+ and how many `/mnt` entries the plugin has to remove, plus `.wslconfig`
149
+ networking mode and localhost forwarding. Missing pieces offer guided actions:
150
+
151
+ - **安装 Node** — `apt-get install nodejs` as the distro user (uses `sudo -n`;
152
+ refuses without passwordless sudo and prints the command instead);
153
+ - **生成 SSH key** — `ssh-keygen -t ed25519` with no passphrase, then shows the
154
+ public key to add to devices;
155
+ - **写 SSH 配置** — appends a `ControlMaster`/`ControlPersist` block once;
156
+ - **创建普通用户** — when a distro's default user is `root` and it has no normal
157
+ user, creates `chronos` (locked password, home, bash).
158
+
159
+ Settings store a **default distribution** and a **per-distribution login user**
160
+ in `~/.dsh/remote-wsl-settings.json`. The user field is a dropdown of users
161
+ reported by the doctor; a root distro is automatically moved to its first normal
162
+ user when settings are empty. The terminal, WSL preset and `@` index all use
163
+ that user, so a Session and its terminal run as the same non-root identity.
164
+ Leave it empty only when the distro default is already the intended user.
165
+
166
+ The panel and plugin icon are a penguin outline (white body, current-color
167
+ outline, no blue tile); the display title is `WSL` and the package id is
168
+ `@chronosun/dsh-wsl`.
169
+
170
+ ## Compatibility
171
+
172
+ | DSH | Status |
173
+ |---|---|
174
+ | `0.2.2-rc.1` | tested (unit + real WSL + Agent A/B eval) |
175
+ | other `0.2.x` | capability-probed, untested |
176
+
177
+ The Host seam is narrow: `sessionController.create`, `workingDirectory.contextText`,
178
+ `fileReferences.list`, `workspaceChanges.summary/diff`, plus the web server.
179
+ Each patch checks the service/method and degrades independently; `/dsh-wsl/state`
180
+ reports `capabilities` so a missing seam is visible instead of taking the whole
181
+ plugin down. The WSL preset itself uses only published Cordis services.
182
+
183
+ ## Verifying a live install
184
+
185
+ From the source checkout, after restarting DSH to load the current profile:
186
+
187
+ ```sh
188
+ node tools/verify-live.mjs
189
+ ```
190
+
191
+ It checks the installed Host version, the `wslDiff` install flag, all
192
+ capabilities, the doctor's Node/PATH result for every distro, and the settings
193
+ endpoint. Worktree creation and the panel render are manual: open a new WSL
194
+ session and call `create_wsl_worktree`, then open the WSL panel's Doctor /
195
+ Settings section.
196
+
197
+ ## Troubleshooting
198
+
199
+ - **`WSL 发行版里没有 node`** — the distribution has no Linux Node.js (the
200
+ Windows `node.exe` on `/mnt/...` does not count and is rejected). Install it
201
+ inside the distribution, then press `断开` → `连接` in the panel:
202
+ `sudo apt-get update && sudo apt-get install -y nodejs` (Ubuntu/Debian), or
203
+ put a v18+ `node` on the login-shell `PATH` (`bash -lc 'command -v node'`).
204
+ The broker caches the resolved path in `~/.dsh/wsl-broker-cache.json` and
205
+ self-heals once when that path goes stale.
206
+ - **New Session still opens in Standard/PTC instead of WSL** — the profile was
207
+ started before this version: the preset default is installed by the Host row
208
+ at boot. Restart DSH (tray → quit), or check the `WSL` panel: it says when
209
+ the default injection is not installed.
210
+ - **Agent still sees a `\\wsl.localhost\...` working directory** — `/dsh-wsl/state`
211
+ should report `modelCwd.installed: true`. If it is missing, this build
212
+ predates 1.0.6 or the Host row was not reloaded: restart DSH. The durable
213
+ session cwd is intentionally still UNC for the Host's diff/`@` features.
214
+ - **`npm` / `cargo` / compiler not found in a WSL session** — commands inherit
215
+ the distribution login PATH with `/mnt/*` removed. If a tool lives in a
216
+ directory your login shell does not export, add it to `~/.profile` (or
217
+ `~/.bash_profile`), then reconnect. The pre-broker fallback also includes
218
+ `~/.local/bin`, `~/.cargo/bin` and `~/.hermes/node/bin`.
219
+ - **No `WSL` entry in the sidebar** — the bundle is installed but the client
220
+ half was not scanned; reinstall from a tarball (`remove_bundle` →
221
+ `install_bundle`) and restart.
222
+ - **`agent-preset/invalid: <row> (<package>): ...`** — one preset row failed to
223
+ activate; the message names the exact service, usually a missing `isolate`
224
+ entry on the `wsl-world` group.
225
+ - **`Receiver must be an instance of class ...`** — a provider used `#private`
226
+ members; Cordis' service proxy calls methods with a different `this`.
227
+ - **`wsl-exec: line 1: exec: : not found`** — `wsl.exe` drops trailing
228
+ arguments; commands must travel inside a single `-c` script.
229
+ - **`syntax error near unexpected token '('`** — `wsl.exe` pre-expands `$VAR`
230
+ in its command line against the dirty target environment; commands are
231
+ base64-encoded to avoid it. Quote variables in commands you write yourself.
232
+
233
+ Set `DSH_WSL_DEBUG=1` to append provider traces to
234
+ `wsl-world.log` beside this package's source.