@chronosun/dsh-wsl 0.0.0-stage → 1.5.1
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 +21 -0
- package/README.md +233 -2
- package/client.js +645 -0
- package/cordis.patch.yml +79 -0
- package/fs-service.mjs +57 -0
- package/host.js +262 -0
- package/icon.svg +11 -0
- package/index.js +5 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +86 -4
- package/prompt.mjs +25 -0
- package/search-tools.mjs +91 -0
- package/src/broker.mjs +373 -0
- package/src/changes-paths.mjs +92 -0
- package/src/collector.mjs +47 -0
- package/src/doctor.mjs +237 -0
- package/src/file-references.mjs +214 -0
- package/src/fs.mjs +312 -0
- package/src/helper.mjs +455 -0
- package/src/launch.mjs +54 -0
- package/src/path-user.mjs +13 -0
- package/src/preset-default.mjs +277 -0
- package/src/registry.mjs +56 -0
- package/src/settings.mjs +51 -0
- package/src/subprocess.mjs +180 -0
- package/src/wsl-diff-v2.mjs +315 -0
- package/terminal-launcher.mjs +59 -0
- package/worktree-tool-v2.mjs +102 -0
- package/world.js +112 -0
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
|
-
#
|
|
1
|
+
# @chronosun/dsh-wsl
|
|
2
2
|
|
|
3
|
-
|
|
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.
|