dsh-plugin-wsl-env 0.8.0 → 0.10.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/CHANGELOG.md +488 -12
- package/CONTRIBUTING.md +125 -62
- package/README.md +99 -68
- package/SECURITY.md +18 -2
- package/SUPPORT.md +26 -10
- package/agent/native/linux-aarch64/dsh-wsl-agent +0 -0
- package/agent/native/linux-x86_64/dsh-wsl-agent +0 -0
- package/agent/wsl-agent.sh +83 -16
- package/cordis.patch.yml +50 -35
- package/docs/ARCHITECTURE.md +203 -55
- package/docs/CONFIGURATION.md +185 -18
- package/docs/LIMITATIONS.md +125 -45
- package/docs/PARITY.md +68 -38
- package/docs/PEER-PARITY.md +103 -33
- package/docs/README.zh.md +105 -64
- package/docs/UPSTREAM-FSIO-EXPORT.md +159 -50
- package/docs/UPSTREAM-TERMINAL-TITLE.md +56 -14
- package/examples/preset-wsl-session-sandbox.cordis.patch.yml +178 -0
- package/lib/agent-protocol.d.ts +10 -4
- package/lib/agent-protocol.js +10 -3
- package/lib/agent.d.ts +84 -0
- package/lib/agent.js +167 -15
- package/lib/bwrap.d.ts +8 -0
- package/lib/bwrap.js +4 -1
- package/lib/fs-routing.d.ts +40 -4
- package/lib/fs-routing.js +80 -12
- package/lib/fsio-agent.js +1 -1
- package/lib/index.d.ts +134 -0
- package/lib/index.js +202 -9
- package/lib/native-agent.d.ts +124 -0
- package/lib/native-agent.js +198 -0
- package/lib/ports.d.ts +13 -2
- package/lib/ports.js +18 -5
- package/lib/preflight.d.ts +91 -0
- package/lib/preflight.js +117 -0
- package/lib/probe-cache.d.ts +12 -1
- package/lib/probe-cache.js +11 -3
- package/lib/sandbox-core.d.ts +70 -0
- package/lib/sandbox-core.js +187 -18
- package/lib/session-runtime.d.ts +161 -0
- package/lib/session-runtime.js +220 -0
- package/lib/session-scope.d.ts +124 -0
- package/lib/session-scope.js +191 -0
- package/lib/shell-env.js +10 -3
- package/lib/watcher.d.ts +25 -12
- package/lib/watcher.js +120 -32
- package/lib/workspace-files-route.d.ts +8 -4
- package/lib/workspace-files-route.js +42 -14
- package/lib/workspace-files-wsl.js +25 -8
- package/lib/wsl.js +10 -4
- package/locale/preflight/en.json +6 -0
- package/locale/preflight/zh.json +6 -0
- package/package.json +44 -27
- package/scripts/diagnose.sh +92 -0
|
@@ -162,11 +162,13 @@ export async function distroStat({ runner, distro, linuxRoot, path, distroWorksp
|
|
|
162
162
|
const linuxFile = linuxJoin(linuxRoot, path);
|
|
163
163
|
const result = await runner.exec({
|
|
164
164
|
cwd: "/",
|
|
165
|
-
argv: statRecordArgv(linuxFile),
|
|
165
|
+
argv: statRecordArgv(linuxFile, linuxRoot),
|
|
166
166
|
maxOutputBytes: 4096,
|
|
167
167
|
timeoutMs: 30_000,
|
|
168
168
|
signal,
|
|
169
169
|
});
|
|
170
|
+
if (result.exitCode === 3)
|
|
171
|
+
throw outsideWorkspace(path);
|
|
170
172
|
if (result.exitCode !== 0)
|
|
171
173
|
throw notFound(path);
|
|
172
174
|
const record = parseStatRecord(result.stdout);
|
|
@@ -186,11 +188,13 @@ export async function distroRead({ runner, distro, linuxRoot, path, offset, limi
|
|
|
186
188
|
const linuxFile = linuxJoin(linuxRoot, path);
|
|
187
189
|
const result = await runner.exec({
|
|
188
190
|
cwd: "/",
|
|
189
|
-
argv: pageArgv(linuxFile, offset, limit),
|
|
191
|
+
argv: pageArgv(linuxFile, offset, limit, linuxRoot),
|
|
190
192
|
maxOutputBytes: (maxBytes + 1) * 4,
|
|
191
193
|
timeoutMs: 60_000,
|
|
192
194
|
signal,
|
|
193
195
|
});
|
|
196
|
+
if (result.exitCode === 3)
|
|
197
|
+
throw outsideWorkspace(path);
|
|
194
198
|
if (result.exitCode === 2)
|
|
195
199
|
throw notFound(path);
|
|
196
200
|
if (result.exitCode !== 0 && result.exitCode !== 1) {
|
|
@@ -213,16 +217,27 @@ export async function distroRead({ runner, distro, linuxRoot, path, offset, limi
|
|
|
213
217
|
catch {
|
|
214
218
|
throw notText(path);
|
|
215
219
|
}
|
|
216
|
-
|
|
217
|
-
|
|
220
|
+
// `pageArgv` reads one line past the page so EOF is decidable from the
|
|
221
|
+
// yield; that line is a probe, not part of the answer. Split it off before
|
|
222
|
+
// counting, and count bytes on the page the caller actually receives (a
|
|
223
|
+
// CRLF file's line count is not a byte budget).
|
|
224
|
+
const parts = text.length === 0 ? [] : text.split("\n");
|
|
225
|
+
if (text.endsWith("\n"))
|
|
226
|
+
parts.pop();
|
|
227
|
+
const count = parts.length;
|
|
228
|
+
const truncated = count > limit;
|
|
229
|
+
const kept = truncated ? parts.slice(0, limit) : parts;
|
|
230
|
+
const pageText = truncated ? `${kept.join("\n")}\n` : text;
|
|
231
|
+
const lines = kept.length;
|
|
232
|
+
const bytes = Buffer.byteLength(pageText, "utf8");
|
|
218
233
|
if (bytes > maxBytes) {
|
|
219
234
|
throw new RemoteError("workspace-file/too-large", `lines ${offset}-${offset + limit - 1} of "${path}" exceed the ${maxBytes} byte cap`, { path, limit: maxBytes });
|
|
220
235
|
}
|
|
221
|
-
if (
|
|
236
|
+
if (pageText.includes(String.fromCharCode(0)))
|
|
222
237
|
throw notText(path);
|
|
223
|
-
const eof =
|
|
238
|
+
const eof = !truncated;
|
|
224
239
|
const stat = { absolutePath: posixToUnc(distro, linuxFile), version: record.version };
|
|
225
|
-
return { ...stat, offset, text, lines, eof };
|
|
240
|
+
return { ...stat, offset, text: pageText, lines, eof };
|
|
226
241
|
}
|
|
227
242
|
/**
|
|
228
243
|
* Read one byte window (or the capped whole file) through the runner.
|
|
@@ -248,11 +263,13 @@ export async function distroReadBytes({ runner, distro, linuxRoot, path, offset,
|
|
|
248
263
|
throw windowTooLarge(path, window.length, maxBytes);
|
|
249
264
|
const result = await runner.exec({
|
|
250
265
|
cwd: "/",
|
|
251
|
-
argv: bytesArgv(linuxFile, window.offset, window.length),
|
|
266
|
+
argv: bytesArgv(linuxFile, window.offset, window.length, linuxRoot),
|
|
252
267
|
maxOutputBytes: window.length + 1024,
|
|
253
268
|
timeoutMs: 60_000,
|
|
254
269
|
signal,
|
|
255
270
|
});
|
|
271
|
+
if (result.exitCode === 3)
|
|
272
|
+
throw outsideWorkspace(path);
|
|
256
273
|
const record = parseStatRecordFromStderr(result.stderr);
|
|
257
274
|
if (record === undefined)
|
|
258
275
|
throw notFound(path);
|
package/lib/wsl.js
CHANGED
|
@@ -104,8 +104,11 @@ export function parseDistroList(stdout) {
|
|
|
104
104
|
*/
|
|
105
105
|
export async function defaultDistro(options = {}) {
|
|
106
106
|
const [first] = await listDistros(options);
|
|
107
|
-
if (first === undefined)
|
|
108
|
-
throw new Error("dsh-plugin-wsl: no WSL distro is installed (`wsl.exe -l -q` returned nothing)"
|
|
107
|
+
if (first === undefined) {
|
|
108
|
+
throw new Error("dsh-plugin-wsl: no WSL distro is installed (`wsl.exe -l -q` returned nothing). " +
|
|
109
|
+
"Install one: `wsl.exe --list --online` lists the available names, then `wsl --install -d <name>`, " +
|
|
110
|
+
"or point this row's `distro` at an existing one.");
|
|
111
|
+
}
|
|
109
112
|
return first;
|
|
110
113
|
}
|
|
111
114
|
/**
|
|
@@ -134,7 +137,8 @@ export async function linuxHomePath(distro, options = {}) {
|
|
|
134
137
|
export function parseHomePath(distro, stdout) {
|
|
135
138
|
const home = String(stdout).trim();
|
|
136
139
|
if (home.length === 0 || !home.startsWith("/")) {
|
|
137
|
-
throw new Error(`dsh-plugin-wsl: distro "${distro}" reported no usable $HOME (got "${home}")`
|
|
140
|
+
throw new Error(`dsh-plugin-wsl: distro "${distro}" reported no usable $HOME (got "${home}"). ` +
|
|
141
|
+
`Check the distro's default user in /etc/wsl.conf, and that the user's /etc/passwd entry carries a home directory.`);
|
|
138
142
|
}
|
|
139
143
|
return home;
|
|
140
144
|
}
|
|
@@ -337,7 +341,9 @@ export async function defaultShell(distro, options = {}) {
|
|
|
337
341
|
export async function runInDistro(distro, command, options = {}) {
|
|
338
342
|
const shell = options.shell ?? (await defaultShell(distro, options));
|
|
339
343
|
if (shell === undefined) {
|
|
340
|
-
throw new Error(`dsh-plugin-wsl: distro "${distro}" named no usable shell (passwd probe and $SHELL both failed)`
|
|
344
|
+
throw new Error(`dsh-plugin-wsl: distro "${distro}" named no usable shell (passwd probe and $SHELL both failed). ` +
|
|
345
|
+
`Check the user's login shell in /etc/passwd (\`getent passwd "$(id -u)"\` inside the distro), ` +
|
|
346
|
+
`or point this row's \`shell\` at an existing absolute path.`);
|
|
341
347
|
}
|
|
342
348
|
return runCapture([options.wslPath ?? DEFAULT_WSL_PATH, "-d", distro, "--exec", shell, ...shellArgs(shell, options.loginShell !== false), command], options.signal);
|
|
343
349
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "WSL sandbox preflight",
|
|
4
|
+
"description": "Probes bubblewrap when a distro session opens and surfaces a missing or unusable bwrap as a warning with the exact remedy — instead of the first command's fail-closed error being the discovery moment. Advisory only; never installs anything."
|
|
5
|
+
}
|
|
6
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-wsl-env",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "\u8ba9 DeepSeek Harness \u4ee5 WSL \u5b50\u7cfb\u7edf\u4f5c\u4e3a\u4f1a\u8bdd\u7684\u6267\u884c\u73af\u5883\uff1ashell\u3001\u6587\u4ef6\u8bfb\u5199\u4e0e\u547d\u4ee4\u6267\u884c\u5747\u5728\u5b50\u7cfb\u7edf\u5185\u5b8c\u6210\uff0c\u76ee\u5f55\u9009\u62e9\u5668\u4e0e GUI \u7ec8\u7aef\u540c\u6837\u5b9a\u4f4d\u5230\u5b50\u7cfb\u7edf\u8def\u5f84\uff0c\u5e76\u901a\u8fc7\u5b50\u7cfb\u7edf\u5185\u7684 bubblewrap \u5bf9\u547d\u4ee4\u8fdb\u884c\u6c99\u7bb1\u9694\u79bb",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
7
7
|
"dsh",
|
|
@@ -47,12 +47,18 @@
|
|
|
47
47
|
"types": "./lib/paths.d.ts",
|
|
48
48
|
"default": "./lib/paths.js"
|
|
49
49
|
},
|
|
50
|
+
"./preflight": {
|
|
51
|
+
"types": "./lib/preflight.d.ts",
|
|
52
|
+
"default": "./lib/preflight.js"
|
|
53
|
+
},
|
|
50
54
|
"./picker": {
|
|
51
55
|
"types": "./lib/picker.d.ts",
|
|
52
56
|
"default": "./lib/picker.js"
|
|
53
57
|
},
|
|
54
58
|
"./picker/locale/en.json": "./locale/picker/en.json",
|
|
55
59
|
"./picker/locale/zh.json": "./locale/picker/zh.json",
|
|
60
|
+
"./preflight/locale/en.json": "./locale/preflight/en.json",
|
|
61
|
+
"./preflight/locale/zh.json": "./locale/preflight/zh.json",
|
|
56
62
|
"./shell": {
|
|
57
63
|
"types": "./lib/shell.d.ts",
|
|
58
64
|
"default": "./lib/shell.js"
|
|
@@ -87,6 +93,7 @@
|
|
|
87
93
|
"lib/**/*.js",
|
|
88
94
|
"lib/**/*.d.ts",
|
|
89
95
|
"agent/*.sh",
|
|
96
|
+
"agent/native/linux-*/dsh-wsl-agent",
|
|
90
97
|
"locale/**/*.json",
|
|
91
98
|
"cordis.patch.yml",
|
|
92
99
|
"examples/**/*.yml",
|
|
@@ -104,16 +111,17 @@
|
|
|
104
111
|
"SECURITY.md",
|
|
105
112
|
"SUPPORT.md",
|
|
106
113
|
"LICENSE",
|
|
107
|
-
"scripts/bootstrap.sh"
|
|
114
|
+
"scripts/bootstrap.sh",
|
|
115
|
+
"scripts/diagnose.sh"
|
|
108
116
|
],
|
|
109
117
|
"scripts": {
|
|
110
118
|
"test": "pnpm run lint:style && pnpm run test:syntax && pnpm run lint:build && pnpm run lint:types && pnpm run test:unit",
|
|
111
119
|
"lint:types": "tsc --noEmit",
|
|
112
120
|
"build": "node scripts/build.mjs",
|
|
113
121
|
"lint:build": "node test/build-freshness.mjs",
|
|
114
|
-
"test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=85 --test-coverage-branches=84 --test-coverage-functions=70 test/agent-exec.test.mjs test/agent-fs-script.test.mjs test/agent-protocol.test.mjs test/agent.test.mjs test/fs-substrate.test.mjs test/fs.boot.test.mjs test/workspace-files-wsl.test.mjs test/composition.test.mjs test/provider.test.mjs test/file-reference-wsl.test.mjs test/fsio-agent.test.mjs test/fsio-text.test.mjs test/git-route.test.mjs test/listing.test.mjs test/paths.test.mjs test/ports.test.mjs test/preset-choice.test.mjs test/probe-cache.test.mjs test/
|
|
122
|
+
"test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=85 --test-coverage-branches=84 --test-coverage-functions=70 test/agent-exec.test.mjs test/agent-fs-script.test.mjs test/agent-protocol.test.mjs test/agent.test.mjs test/fs-substrate.test.mjs test/fs.boot.test.mjs test/workspace-files-wsl.test.mjs test/composition.test.mjs test/provider.test.mjs test/file-reference-wsl.test.mjs test/fsio-agent.test.mjs test/fsio-text.test.mjs test/git-route.test.mjs test/listing.test.mjs test/paths.test.mjs test/ports.test.mjs test/preset-choice.test.mjs test/probe-cache.test.mjs test/preflight.test.mjs test/sandbox.test.mjs test/search-exec.test.mjs test/search-route.test.mjs test/shell.test.mjs test/terminal-activity.test.mjs test/terminal.test.mjs test/watcher.test.mjs test/wsl.test.mjs test/fs-decisions.test.mjs test/session-scope.test.mjs test/session-runtime.test.mjs test/native-agent.test.mjs test/peers.test.mjs",
|
|
115
123
|
"test:syntax": "node test/syntax.mjs",
|
|
116
|
-
"test:unit": "node --test test/fs.boot.test.mjs test/fsio-text.test.mjs test/workspace-files-wsl.test.mjs test/composition.test.mjs test/provider.test.mjs test/file-reference-wsl.test.mjs test/paths.test.mjs test/listing.test.mjs test/shell.test.mjs test/terminal.test.mjs test/probe-cache.test.mjs test/preset-choice.test.mjs test/sandbox.test.mjs test/agent-protocol.test.mjs test/agent.test.mjs test/agent-fs-script.test.mjs test/fsio-agent.test.mjs test/fs-substrate.test.mjs test/agent-exec.test.mjs test/ports.test.mjs test/watcher.test.mjs test/wsl.test.mjs test/fs-decisions.test.mjs test/git-route.test.mjs test/fsio-text.test.mjs test/search-route.test.mjs test/search-exec.test.mjs test/terminal-activity.test.mjs",
|
|
124
|
+
"test:unit": "node --test test/fs.boot.test.mjs test/fsio-text.test.mjs test/workspace-files-wsl.test.mjs test/composition.test.mjs test/provider.test.mjs test/file-reference-wsl.test.mjs test/paths.test.mjs test/listing.test.mjs test/shell.test.mjs test/terminal.test.mjs test/probe-cache.test.mjs test/preflight.test.mjs test/preset-choice.test.mjs test/sandbox.test.mjs test/agent-protocol.test.mjs test/agent.test.mjs test/agent-fs-script.test.mjs test/fsio-agent.test.mjs test/fs-substrate.test.mjs test/agent-exec.test.mjs test/ports.test.mjs test/watcher.test.mjs test/wsl.test.mjs test/fs-decisions.test.mjs test/git-route.test.mjs test/fsio-text.test.mjs test/search-route.test.mjs test/search-exec.test.mjs test/terminal-activity.test.mjs test/session-scope.test.mjs test/session-runtime.test.mjs test/native-agent.test.mjs test/peers.test.mjs",
|
|
117
125
|
"lint:style": "node test/style.mjs",
|
|
118
126
|
"prepublishOnly": "pnpm test",
|
|
119
127
|
"probe": "bash test/probe/run.sh",
|
|
@@ -129,7 +137,8 @@
|
|
|
129
137
|
"probe:agent": "bash test/probe/agent.sh",
|
|
130
138
|
"probe:substrate": "bash test/probe/substrate.sh",
|
|
131
139
|
"probe:exec": "bash test/probe/exec.sh",
|
|
132
|
-
"bootstrap": "bash scripts/bootstrap.sh"
|
|
140
|
+
"bootstrap": "bash scripts/bootstrap.sh",
|
|
141
|
+
"diagnose": "bash scripts/diagnose.sh"
|
|
133
142
|
},
|
|
134
143
|
"packageManager": "pnpm@11.7.0",
|
|
135
144
|
"engines": {
|
|
@@ -153,40 +162,45 @@
|
|
|
153
162
|
"url": "https://github.com/Big-Dao/dsh-plugin-wsl-env/issues"
|
|
154
163
|
},
|
|
155
164
|
"devDependencies": {
|
|
156
|
-
"@deepseek-ai/cordis": "4.0.
|
|
165
|
+
"@deepseek-ai/cordis": "4.0.5",
|
|
157
166
|
"@deepseek-ai/cordis-plugin-include": "*",
|
|
158
167
|
"@deepseek-ai/cordis-plugin-loader": "*",
|
|
159
|
-
"@deepseek-ai/dsh-api-workspace-files": "0.2.
|
|
160
|
-
"@deepseek-ai/dsh-bash-local": "0.2.
|
|
161
|
-
"@deepseek-ai/dsh-fs": "0.2.
|
|
162
|
-
"@deepseek-ai/dsh-fs-local": "0.2.
|
|
163
|
-
"@deepseek-ai/dsh-fs-sandbox": "0.2.
|
|
164
|
-
"@deepseek-ai/dsh-host-directory-picker": "0.2.
|
|
165
|
-
"@deepseek-ai/dsh-sandbox": "0.2.
|
|
166
|
-
"@deepseek-ai/dsh-sandbox-policy": "0.2.
|
|
167
|
-
"@deepseek-ai/dsh-subprocess": "0.2.
|
|
168
|
-
"@deepseek-ai/dsh-subprocess-local": "0.2.
|
|
169
|
-
"@deepseek-ai/dsh-typert-protocol": "0.2.
|
|
168
|
+
"@deepseek-ai/dsh-api-workspace-files": "0.2.1-rc.2",
|
|
169
|
+
"@deepseek-ai/dsh-bash-local": "0.2.1-rc.2",
|
|
170
|
+
"@deepseek-ai/dsh-fs": "0.2.1-rc.2",
|
|
171
|
+
"@deepseek-ai/dsh-fs-local": "0.2.1-rc.2",
|
|
172
|
+
"@deepseek-ai/dsh-fs-sandbox": "0.2.1-rc.2",
|
|
173
|
+
"@deepseek-ai/dsh-host-directory-picker": "0.2.1-rc.2",
|
|
174
|
+
"@deepseek-ai/dsh-sandbox": "0.2.1-rc.2",
|
|
175
|
+
"@deepseek-ai/dsh-sandbox-policy": "0.2.1-rc.2",
|
|
176
|
+
"@deepseek-ai/dsh-subprocess": "0.2.1-rc.2",
|
|
177
|
+
"@deepseek-ai/dsh-subprocess-local": "0.2.1-rc.2",
|
|
178
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-rc.2",
|
|
170
179
|
"@types/js-yaml": "^4.0.9",
|
|
171
180
|
"@types/node": "~22.20.5",
|
|
172
181
|
"js-yaml": "4.3.2",
|
|
173
182
|
"typescript": "~6.0.3"
|
|
174
183
|
},
|
|
175
184
|
"peerDependencies": {
|
|
176
|
-
"@deepseek-ai/cordis": "~4.0.
|
|
177
|
-
"@deepseek-ai/dsh-
|
|
178
|
-
"@deepseek-ai/dsh-
|
|
179
|
-
"@deepseek-ai/dsh-fs
|
|
180
|
-
"@deepseek-ai/dsh-
|
|
181
|
-
"@deepseek-ai/dsh-
|
|
182
|
-
"@deepseek-ai/dsh-
|
|
183
|
-
"@deepseek-ai/dsh-subprocess
|
|
184
|
-
"@deepseek-ai/
|
|
185
|
+
"@deepseek-ai/cordis": "~4.0.5",
|
|
186
|
+
"@deepseek-ai/dsh-api-workspace-files": "0.2.1-rc.2",
|
|
187
|
+
"@deepseek-ai/dsh-bash-local": "0.2.1-rc.2",
|
|
188
|
+
"@deepseek-ai/dsh-fs": "0.2.1-rc.2",
|
|
189
|
+
"@deepseek-ai/dsh-fs-local": "0.2.1-rc.2",
|
|
190
|
+
"@deepseek-ai/dsh-host-directory-picker": "0.2.1-rc.2",
|
|
191
|
+
"@deepseek-ai/dsh-sandbox": "0.2.1-rc.2",
|
|
192
|
+
"@deepseek-ai/dsh-subprocess": "0.2.1-rc.2",
|
|
193
|
+
"@deepseek-ai/dsh-subprocess-local": "0.2.1-rc.2",
|
|
194
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-rc.2",
|
|
195
|
+
"@deepseek-ai/schemastery": "~3.18.5"
|
|
185
196
|
},
|
|
186
197
|
"peerDependenciesMeta": {
|
|
187
198
|
"@deepseek-ai/cordis": {
|
|
188
199
|
"optional": true
|
|
189
200
|
},
|
|
201
|
+
"@deepseek-ai/dsh-api-workspace-files": {
|
|
202
|
+
"optional": true
|
|
203
|
+
},
|
|
190
204
|
"@deepseek-ai/dsh-bash-local": {
|
|
191
205
|
"optional": true
|
|
192
206
|
},
|
|
@@ -208,6 +222,9 @@
|
|
|
208
222
|
"@deepseek-ai/dsh-subprocess-local": {
|
|
209
223
|
"optional": true
|
|
210
224
|
},
|
|
225
|
+
"@deepseek-ai/dsh-typert-protocol": {
|
|
226
|
+
"optional": true
|
|
227
|
+
},
|
|
211
228
|
"@deepseek-ai/schemastery": {
|
|
212
229
|
"optional": true
|
|
213
230
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Collect a read-only diagnostic report for a bug report, in one command:
|
|
3
|
+
#
|
|
4
|
+
# pnpm run diagnose -- [distro] # distro optional; default distro otherwise
|
|
5
|
+
#
|
|
6
|
+
# Prints versions and probe verdicts as plain text that can be pasted into an
|
|
7
|
+
# issue as-is. It runs NO installation, changes nothing in the distro, and reads
|
|
8
|
+
# nothing secret: the report is tool versions, a kernel release and probe
|
|
9
|
+
# verdicts. Exit code is always 0 — the report is informational; the verdict
|
|
10
|
+
# lines carry the failures.
|
|
11
|
+
#
|
|
12
|
+
# Deeper sandbox probing lives in `npm run probe:sandbox` (run inside the
|
|
13
|
+
# distro); this script answers "what is installed and does bwrap run at all".
|
|
14
|
+
|
|
15
|
+
set -u
|
|
16
|
+
export WSL_UTF8=1 # wsl.exe writes UTF-16LE without it; read as UTF-8 that is mojibake
|
|
17
|
+
|
|
18
|
+
DISTRO="${1:-}"
|
|
19
|
+
|
|
20
|
+
ok() { printf 'ok %s\n' "$1"; }
|
|
21
|
+
miss() { printf 'MISSING %s\n' "$1"; }
|
|
22
|
+
info() { printf 'info %s\n' "$1"; }
|
|
23
|
+
header(){ printf '\n== %s ==\n' "$1"; }
|
|
24
|
+
|
|
25
|
+
echo "# dsh-plugin-wsl-env diagnose report"
|
|
26
|
+
|
|
27
|
+
header "host"
|
|
28
|
+
winver="$(cmd.exe /c ver 2>/dev/null | tr -d '\r' | grep -o '[0-9][0-9.]*' | head -1)"
|
|
29
|
+
if [ -n "$winver" ]; then ok "windows build $winver"; else info "windows build unknown (cmd.exe not reachable through interop)"; fi
|
|
30
|
+
wsl_ver="$(wsl.exe --version 2>/dev/null | tr -d '\0\r' | head -2 | tr '\n' ' ')"
|
|
31
|
+
if [ -n "$wsl_ver" ]; then ok "wsl: $wsl_ver"; else info "wsl --version unsupported on this WSL build"; fi
|
|
32
|
+
wsl_status="$(wsl.exe --status 2>/dev/null | tr -d '\0\r' | tr '\n' ' ')"
|
|
33
|
+
[ -n "$wsl_status" ] && info "wsl status: $wsl_status"
|
|
34
|
+
wsl.exe -l -v 2>/dev/null | tr -d '\0\r' | grep -v '^$' | sed 's/^/ /'
|
|
35
|
+
|
|
36
|
+
header "plugin"
|
|
37
|
+
echo " plugin version: $(node -p "require('./package.json').version" 2>/dev/null || echo unknown)"
|
|
38
|
+
echo " dsh version: $(dsh --version 2>/dev/null || echo unknown)"
|
|
39
|
+
|
|
40
|
+
if [ -z "$DISTRO" ]; then
|
|
41
|
+
DISTRO="$(wsl.exe -l -q 2>/dev/null | tr -d '\0\r' | grep -v '^$' | head -1)"
|
|
42
|
+
fi
|
|
43
|
+
if [ -z "$DISTRO" ]; then
|
|
44
|
+
header "distro"
|
|
45
|
+
miss "no distro installed — 'wsl.exe --list --online' lists names, 'wsl --install -d <name>' installs one"
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
header "distro: $DISTRO"
|
|
50
|
+
in_distro() { wsl.exe -d "$DISTRO" --exec sh -c "$1" 2>/dev/null; }
|
|
51
|
+
|
|
52
|
+
info "kernel: $(in_distro 'uname -r')"
|
|
53
|
+
family="$(in_distro 'for m in apt-get dnf pacman zypper; do command -v $m && break; done' | tr -d '\r')"
|
|
54
|
+
case "$family" in
|
|
55
|
+
*apt-get) info "package family: apt" ;;
|
|
56
|
+
*dnf) info "package family: dnf" ;;
|
|
57
|
+
*pacman) info "package family: pacman" ;;
|
|
58
|
+
*zypper) info "package family: zypper" ;;
|
|
59
|
+
*) info "package family: unknown" ;;
|
|
60
|
+
esac
|
|
61
|
+
|
|
62
|
+
for tool in bwrap rg git inotifywait; do
|
|
63
|
+
if in_distro "command -v $tool" | grep -q .; then
|
|
64
|
+
case "$tool" in
|
|
65
|
+
bwrap) ver="$(in_distro 'bwrap --version' | tr -d '\r' | head -1)" ;;
|
|
66
|
+
rg) ver="$(in_distro 'rg --version' | tr -d '\r' | head -1)" ;;
|
|
67
|
+
git) ver="$(in_distro 'git --version' | tr -d '\r' | head -1)" ;;
|
|
68
|
+
inotifywait) ver="inotifywait (no version flag)" ;;
|
|
69
|
+
esac
|
|
70
|
+
ok "$ver"
|
|
71
|
+
else
|
|
72
|
+
case "$tool" in
|
|
73
|
+
bwrap) miss "bwrap — REQUIRED; every confined command fails closed without it. Install: wsl.exe -d $DISTRO -u root -- apt-get install -y bubblewrap (or: pnpm run bootstrap -- $DISTRO --install)" ;;
|
|
74
|
+
rg) miss "ripgrep — the search tool falls back to slower matching without it" ;;
|
|
75
|
+
git) miss "git — snapshot and diff baselines degrade without it" ;;
|
|
76
|
+
inotifywait) miss "inotify-tools — file watching falls back to polling without it" ;;
|
|
77
|
+
esac
|
|
78
|
+
fi
|
|
79
|
+
done
|
|
80
|
+
|
|
81
|
+
if in_distro 'command -v bwrap' | grep -q .; then
|
|
82
|
+
if in_distro 'bwrap --ro-bind / / -- true'; then
|
|
83
|
+
ok "bwrap runs a read-only profile (the usability probe passes)"
|
|
84
|
+
else
|
|
85
|
+
miss "bwrap is installed but FAILED the read-only profile probe — likely the kernel (unprivileged user namespaces disabled) or an unusable build; reinstalling will not help"
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
header "notes"
|
|
90
|
+
info "trace file: set DSH_WSL_TRACE=<path> to record the auto-preset decisions, then re-run the scenario"
|
|
91
|
+
info "paste this report into the issue's Output section; redact anything you would rather not publish"
|
|
92
|
+
exit 0
|