dsh-plugin-wsl-env 0.11.0 → 0.12.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 +27 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +117 -138
- package/cordis.patch.yml +8 -17
- package/docs/ARCHITECTURE.md +23 -24
- package/docs/CONFIGURATION.md +6 -5
- package/docs/LIMITATIONS.md +25 -0
- package/docs/README.zh.md +115 -137
- package/lib/index.js +3 -1
- package/lib/paths.d.ts +15 -0
- package/lib/paths.js +28 -0
- package/package.json +3 -12
- package/lib/workspace-files-route.d.ts +0 -136
- package/lib/workspace-files-route.js +0 -225
- package/lib/workspace-files-wsl.d.ts +0 -257
- package/lib/workspace-files-wsl.js +0 -418
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The distro-routed `workspace-files` service: the GUI file tree and previews
|
|
3
|
-
* for a `\\wsl.localhost\<distro>` workspace are served from inside the distro
|
|
4
|
-
* through the resident agent, instead of Windows-side 9P walks.
|
|
5
|
-
*
|
|
6
|
-
* ## Route predicate
|
|
7
|
-
*
|
|
8
|
-
* Every override checks `scope.workspaceRoot` — a distro UNC routes
|
|
9
|
-
* distro-side, a drive path calls `super` (host native, unchanged).
|
|
10
|
-
* `changes` (the watch stream) always delegates to `super`: its feed rides
|
|
11
|
-
* `ctx.fs.watch`, whose behaviour is today's on both workspace kinds.
|
|
12
|
-
*
|
|
13
|
-
* ## What the distro side reproduces
|
|
14
|
-
*
|
|
15
|
-
* The wire shapes of `dsh-api-workspace-files`: listings capped with a
|
|
16
|
-
* `truncated` flag, stats of `{absolutePath, version, bytes?}`, line-paged
|
|
17
|
-
* text with NUL and UTF-8 refusal and the byte-cap error, and byte windows
|
|
18
|
-
* with EOF markers. Versions are synthesized from `stat` fields — opaque to
|
|
19
|
-
* the client, which only compares them. `absolutePath` is synthesized in the
|
|
20
|
-
* UNC form so the GUI's path display stays what it was on the host fs. Read
|
|
21
|
-
* refuses a final-component symlink exactly like the upstream `locateFile`
|
|
22
|
-
* lstat gate does; `list` follows one (matching its own symlink-through
|
|
23
|
-
* rule).
|
|
24
|
-
*
|
|
25
|
-
* The distro operations are standalone functions over an injected runner, so
|
|
26
|
-
* they are unit-testable with a fake agent; the class methods are thin
|
|
27
|
-
* coordinate guards around them.
|
|
28
|
-
*
|
|
29
|
-
* This is a TypeScript source built to `lib/workspace-files-wsl.js`; edit THIS
|
|
30
|
-
* file and run `pnpm run build` — the artifact under `lib/` is generated, and
|
|
31
|
-
* `pnpm test` fails when it drifts.
|
|
32
|
-
*
|
|
33
|
-
* @module dsh-plugin-wsl/workspace-files-wsl
|
|
34
|
-
*/
|
|
35
|
-
import { RemoteError } from "@deepseek-ai/dsh-typert-protocol";
|
|
36
|
-
import { WorkspaceFiles } from "@deepseek-ai/dsh-api-workspace-files";
|
|
37
|
-
import { isDistroWorkspace, linuxJoin, listDistroArgv, parseDirListing, parseStatRecord, parseStatRecordFromStderr, pageArgv, statRecordArgv, bytesArgv } from "./workspace-files-route.js";
|
|
38
|
-
import { posixToUnc, uncToPosix } from "./paths.js";
|
|
39
|
-
import { sharedAgent } from "./agent-shared.js";
|
|
40
|
-
/**
|
|
41
|
-
* Read this row's validated config through the one documented cast.
|
|
42
|
-
*
|
|
43
|
-
* @param self - the service instance.
|
|
44
|
-
* @returns its own config.
|
|
45
|
-
*/
|
|
46
|
-
function ownConfig(self) {
|
|
47
|
-
return self.config;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Throw the wire's not-found refusal.
|
|
51
|
-
*
|
|
52
|
-
* @param path - the requested path.
|
|
53
|
-
* @returns the refusal.
|
|
54
|
-
*/
|
|
55
|
-
function notFound(path) {
|
|
56
|
-
return new RemoteError("workspace-file/not-found", `no entry at "${path}"`, { path });
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Throw the wire's outside-workspace refusal.
|
|
60
|
-
*
|
|
61
|
-
* @param path - the requested path.
|
|
62
|
-
* @returns the refusal.
|
|
63
|
-
*/
|
|
64
|
-
function outsideWorkspace(path) {
|
|
65
|
-
return new RemoteError("workspace-file/outside-workspace", `"${path}" is outside the workspace`, { path });
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Throw the wire's not-directory refusal.
|
|
69
|
-
*
|
|
70
|
-
* @param path - the requested path.
|
|
71
|
-
* @param kind - what the entry is.
|
|
72
|
-
* @returns the refusal.
|
|
73
|
-
*/
|
|
74
|
-
function notDirectory(path, kind) {
|
|
75
|
-
return new RemoteError("workspace-file/not-directory", `"${path}" is a ${kind}`, { path, kind });
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Throw the wire's not-regular-file refusal.
|
|
79
|
-
*
|
|
80
|
-
* @param path - the requested path.
|
|
81
|
-
* @param kind - what the entry is.
|
|
82
|
-
* @returns the refusal.
|
|
83
|
-
*/
|
|
84
|
-
function notRegularFile(path, kind) {
|
|
85
|
-
return new RemoteError("workspace-file/not-regular-file", `"${path}" is a ${kind}`, { path, kind });
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Throw the wire's too-large refusal.
|
|
89
|
-
*
|
|
90
|
-
* @param path - the requested path.
|
|
91
|
-
* @param limit - the full-file cap.
|
|
92
|
-
* @returns the refusal.
|
|
93
|
-
*/
|
|
94
|
-
function tooLarge(path, limit) {
|
|
95
|
-
return new RemoteError("workspace-file/too-large", `"${path}" exceeds the ${limit} byte full-file cap`, { path, limit });
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Throw the wire's too-large refusal for a byte window that asked past the cap
|
|
99
|
-
* — upstream's byte-read wording, distinct from the full-file cap's.
|
|
100
|
-
*
|
|
101
|
-
* @param path - the requested path.
|
|
102
|
-
* @param length - the requested window length.
|
|
103
|
-
* @param limit - the window cap.
|
|
104
|
-
* @returns the refusal.
|
|
105
|
-
*/
|
|
106
|
-
function windowTooLarge(path, length, limit) {
|
|
107
|
-
return new RemoteError("workspace-file/too-large", `${length} bytes of "${path}" exceed the ${limit} byte cap`, { path, limit });
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Throw the wire's not-text refusal.
|
|
111
|
-
*
|
|
112
|
-
* @param path - the requested path.
|
|
113
|
-
* @returns the refusal.
|
|
114
|
-
*/
|
|
115
|
-
function notText(path) {
|
|
116
|
-
return new RemoteError("workspace-file/not-text", `"${path}" is not UTF-8 text`, { path });
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* List one distro directory through the runner.
|
|
120
|
-
*
|
|
121
|
-
* The agent argv confines the directory under the workspace root, refuses
|
|
122
|
-
* non-directories, and emits one line per child — a trailing `/` marks a
|
|
123
|
-
* directory (symlinks resolve through, broken links drop out, matching the
|
|
124
|
-
* upstream child semantics).
|
|
125
|
-
*
|
|
126
|
-
* @param object - the listing's inputs.
|
|
127
|
-
* @returns the listing, with `path` relative to the workspace root (empty for it).
|
|
128
|
-
*/
|
|
129
|
-
export async function distroList({ runner, distro, linuxRoot, path, maxEntries, signal }) {
|
|
130
|
-
const linuxDir = linuxJoin(linuxRoot, path);
|
|
131
|
-
const result = await runner.exec({
|
|
132
|
-
cwd: "/",
|
|
133
|
-
argv: listDistroArgv(linuxRoot, linuxDir, maxEntries),
|
|
134
|
-
maxOutputBytes: 4_000_000,
|
|
135
|
-
timeoutMs: 30_000,
|
|
136
|
-
signal,
|
|
137
|
-
});
|
|
138
|
-
if (result.exitCode === 3)
|
|
139
|
-
throw outsideWorkspace(path);
|
|
140
|
-
// The exit-4 relay carries no kind, and the refusal's message reads back
|
|
141
|
-
// `"x" is a directory` inside a not-directory refusal — the passed kind is
|
|
142
|
-
// wrong. Fixing it honestly needs the relay to report what the entry IS; a
|
|
143
|
-
// protocol decision, deliberately left visible.
|
|
144
|
-
// @ts-expect-error — the wire's kind is unknown on exit 4; see above.
|
|
145
|
-
if (result.exitCode === 4)
|
|
146
|
-
throw notDirectory(path, "directory");
|
|
147
|
-
if (result.exitCode === 2)
|
|
148
|
-
throw notFound(path);
|
|
149
|
-
if (result.exitCode !== 0)
|
|
150
|
-
throw new Error(`listing "${linuxDir}" failed: ${String(result.stderr).trim() || `exit ${result.exitCode}`}`);
|
|
151
|
-
const { entries, truncated } = parseDirListing(result.stdout, maxEntries);
|
|
152
|
-
const relative = linuxDir === linuxRoot ? "" : linuxDir.slice(linuxRoot.length + 1);
|
|
153
|
-
return { path: relative, entries, truncated };
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Stat one distro path through the runner.
|
|
157
|
-
*
|
|
158
|
-
* @param object - the stat's inputs.
|
|
159
|
-
* @returns the wire stat row.
|
|
160
|
-
*/
|
|
161
|
-
export async function distroStat({ runner, distro, linuxRoot, path, distroWorkspaceRoot, signal }) {
|
|
162
|
-
const linuxFile = linuxJoin(linuxRoot, path);
|
|
163
|
-
const result = await runner.exec({
|
|
164
|
-
cwd: "/",
|
|
165
|
-
argv: statRecordArgv(linuxFile, linuxRoot),
|
|
166
|
-
maxOutputBytes: 4096,
|
|
167
|
-
timeoutMs: 30_000,
|
|
168
|
-
signal,
|
|
169
|
-
});
|
|
170
|
-
if (result.exitCode === 3)
|
|
171
|
-
throw outsideWorkspace(path);
|
|
172
|
-
if (result.exitCode !== 0)
|
|
173
|
-
throw notFound(path);
|
|
174
|
-
const record = parseStatRecord(result.stdout);
|
|
175
|
-
const stat = { absolutePath: posixToUnc(distro, linuxFile), version: record.version };
|
|
176
|
-
return record.size === undefined || Number.isNaN(record.size) ? stat : { ...stat, bytes: record.size };
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Read one line-paged UTF-8 window through the runner, mirroring the
|
|
180
|
-
* upstream `cutPage` semantics: a NUL byte marks the page binary, a page
|
|
181
|
-
* above the byte cap is refused (never shortened), and `eof` is false exactly
|
|
182
|
-
* when a character exists past the page.
|
|
183
|
-
*
|
|
184
|
-
* @param object - the read's inputs.
|
|
185
|
-
* @returns the wire text page.
|
|
186
|
-
*/
|
|
187
|
-
export async function distroRead({ runner, distro, linuxRoot, path, offset, limit, maxBytes, distroWorkspaceRoot, signal }) {
|
|
188
|
-
const linuxFile = linuxJoin(linuxRoot, path);
|
|
189
|
-
const result = await runner.exec({
|
|
190
|
-
cwd: "/",
|
|
191
|
-
argv: pageArgv(linuxFile, offset, limit, linuxRoot),
|
|
192
|
-
maxOutputBytes: (maxBytes + 1) * 4,
|
|
193
|
-
timeoutMs: 60_000,
|
|
194
|
-
signal,
|
|
195
|
-
});
|
|
196
|
-
if (result.exitCode === 3)
|
|
197
|
-
throw outsideWorkspace(path);
|
|
198
|
-
if (result.exitCode === 2)
|
|
199
|
-
throw notFound(path);
|
|
200
|
-
if (result.exitCode !== 0 && result.exitCode !== 1) {
|
|
201
|
-
throw new Error(`reading "${linuxFile}" failed: ${String(result.stderr).trim() || `exit ${result.exitCode}`}`);
|
|
202
|
-
}
|
|
203
|
-
const record = parseStatRecordFromStderr(result.stderr);
|
|
204
|
-
if (record === undefined)
|
|
205
|
-
throw notFound(path);
|
|
206
|
-
// The stat record's kind is whatever the distro named — a socket or a fifo
|
|
207
|
-
// reaches this line too — and the refusal embeds it verbatim; the narrowed
|
|
208
|
-
// parameter is the upstream wire's three-kind vocabulary.
|
|
209
|
-
if (record.type !== "file")
|
|
210
|
-
throw notRegularFile(path, record.type);
|
|
211
|
-
const raw = Buffer.from(result.stdout);
|
|
212
|
-
const strict = new TextDecoder("utf-8", { fatal: true });
|
|
213
|
-
let text;
|
|
214
|
-
try {
|
|
215
|
-
text = strict.decode(raw);
|
|
216
|
-
}
|
|
217
|
-
catch {
|
|
218
|
-
throw notText(path);
|
|
219
|
-
}
|
|
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");
|
|
233
|
-
if (bytes > maxBytes) {
|
|
234
|
-
throw new RemoteError("workspace-file/too-large", `lines ${offset}-${offset + limit - 1} of "${path}" exceed the ${maxBytes} byte cap`, { path, limit: maxBytes });
|
|
235
|
-
}
|
|
236
|
-
if (pageText.includes(String.fromCharCode(0)))
|
|
237
|
-
throw notText(path);
|
|
238
|
-
const eof = !truncated;
|
|
239
|
-
const stat = { absolutePath: posixToUnc(distro, linuxFile), version: record.version };
|
|
240
|
-
return { ...stat, offset, text: pageText, lines, eof };
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Read one byte window (or the capped whole file) through the runner.
|
|
244
|
-
*
|
|
245
|
-
* @param object - the read's inputs.
|
|
246
|
-
* @returns the wire byte read.
|
|
247
|
-
*/
|
|
248
|
-
export async function distroReadBytes({ runner, distro, linuxRoot, path, offset, length, maxBytes, maxFileBytes, distroWorkspaceRoot, signal }) {
|
|
249
|
-
const linuxFile = linuxJoin(linuxRoot, path);
|
|
250
|
-
// One exec carries both halves: the stat record on stderr (for the version,
|
|
251
|
-
// the size, and the whole-file refusal), the window on stdout.
|
|
252
|
-
const whole = offset === undefined && length === undefined;
|
|
253
|
-
// Upstream's `resolveWindow` defaulting: an absent length means the WINDOW
|
|
254
|
-
// cap (not the whole-file cap), so a ranged read never silently grows past it.
|
|
255
|
-
const window = whole
|
|
256
|
-
? { offset: 0, length: maxFileBytes }
|
|
257
|
-
: { offset: offset ?? 0, length: length ?? maxBytes ?? maxFileBytes };
|
|
258
|
-
// The window form mirrors the upstream refusal the same way the whole-file
|
|
259
|
-
// form does: a window asking for more than the page cap is refused, never
|
|
260
|
-
// shortened. `readByteRange` passes the request as its own cap, so only the
|
|
261
|
-
// ranged `readBytes` form can trip this.
|
|
262
|
-
if (!whole && maxBytes !== undefined && window.length > maxBytes)
|
|
263
|
-
throw windowTooLarge(path, window.length, maxBytes);
|
|
264
|
-
const result = await runner.exec({
|
|
265
|
-
cwd: "/",
|
|
266
|
-
argv: bytesArgv(linuxFile, window.offset, window.length, linuxRoot),
|
|
267
|
-
maxOutputBytes: window.length + 1024,
|
|
268
|
-
timeoutMs: 60_000,
|
|
269
|
-
signal,
|
|
270
|
-
});
|
|
271
|
-
if (result.exitCode === 3)
|
|
272
|
-
throw outsideWorkspace(path);
|
|
273
|
-
const record = parseStatRecordFromStderr(result.stderr);
|
|
274
|
-
if (record === undefined)
|
|
275
|
-
throw notFound(path);
|
|
276
|
-
// Same wire reality as the text read above: the kind is the distro's own
|
|
277
|
-
// naming, embedded verbatim.
|
|
278
|
-
if (record.type !== "file")
|
|
279
|
-
throw notRegularFile(path, record.type);
|
|
280
|
-
const data = new Uint8Array(Buffer.from(result.stdout).subarray(0, window.length));
|
|
281
|
-
// The whole-file form mirrors the upstream refusal: a file bigger than the
|
|
282
|
-
// cap is refused, never silently truncated (the stderr record names the
|
|
283
|
-
// real size even though head capped the stdout).
|
|
284
|
-
if (offset === undefined && length === undefined && record.size > maxFileBytes) {
|
|
285
|
-
throw tooLarge(path, maxFileBytes);
|
|
286
|
-
}
|
|
287
|
-
return {
|
|
288
|
-
absolutePath: posixToUnc(distro, linuxFile),
|
|
289
|
-
version: record.version,
|
|
290
|
-
offset: window.offset,
|
|
291
|
-
data,
|
|
292
|
-
eof: window.offset + data.length >= record.size,
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* The distro-routed `workspace-files` service.
|
|
297
|
-
*/
|
|
298
|
-
export class WorkspaceFilesWsl extends WorkspaceFiles {
|
|
299
|
-
static Config = WorkspaceFiles.Config;
|
|
300
|
-
/**
|
|
301
|
-
* The agent runner for one distro; a hook tests substitute.
|
|
302
|
-
*
|
|
303
|
-
* @param distro - the distro name.
|
|
304
|
-
* @returns the agent runner.
|
|
305
|
-
*/
|
|
306
|
-
runnerFor(distro) {
|
|
307
|
-
return sharedAgent(distro);
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* The distro coordinates of one workspace scope.
|
|
311
|
-
*
|
|
312
|
-
* @param workspaceRoot - the scope's workspace root.
|
|
313
|
-
* @returns the distro and its workspace root in Linux form.
|
|
314
|
-
*/
|
|
315
|
-
coords(workspaceRoot) {
|
|
316
|
-
const parsed = uncToPosix(workspaceRoot);
|
|
317
|
-
if (parsed === undefined)
|
|
318
|
-
throw new Error(`"${workspaceRoot}" is not a distro workspace root`);
|
|
319
|
-
return { distro: parsed.distro, linuxRoot: parsed.linuxPath.length > 0 ? parsed.linuxPath : "/" };
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* List one workspace directory; distro UNC roots list inside the distro.
|
|
323
|
-
*
|
|
324
|
-
* @param workspaceFileScope - the Session's file scope.
|
|
325
|
-
* @param path - the directory to list.
|
|
326
|
-
* @param signal - caller cancellation.
|
|
327
|
-
*/
|
|
328
|
-
async list(workspaceFileScope, path, signal) {
|
|
329
|
-
if (!isDistroWorkspace(workspaceFileScope.workspaceRoot))
|
|
330
|
-
return super.list(workspaceFileScope, path, signal);
|
|
331
|
-
const { distro, linuxRoot } = this.coords(workspaceFileScope.workspaceRoot);
|
|
332
|
-
const { path: relative, entries, truncated } = await distroList({
|
|
333
|
-
runner: this.runnerFor(distro),
|
|
334
|
-
distro,
|
|
335
|
-
linuxRoot,
|
|
336
|
-
path,
|
|
337
|
-
maxEntries: ownConfig(this).maxEntries,
|
|
338
|
-
signal,
|
|
339
|
-
});
|
|
340
|
-
return {
|
|
341
|
-
path: relative,
|
|
342
|
-
entries: entries.map((entry) => entry.size === undefined ? entry : { ...entry, size: entry.size }),
|
|
343
|
-
truncated,
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Stat one workspace file; distro UNC roots stat inside the distro.
|
|
348
|
-
*
|
|
349
|
-
* @param workspaceFileScope - the Session's file scope.
|
|
350
|
-
* @param path - the file to stat.
|
|
351
|
-
* @param signal - caller cancellation.
|
|
352
|
-
*/
|
|
353
|
-
async stat(workspaceFileScope, path, signal) {
|
|
354
|
-
if (!isDistroWorkspace(workspaceFileScope.workspaceRoot))
|
|
355
|
-
return super.stat(workspaceFileScope, path, signal);
|
|
356
|
-
const { distro, linuxRoot } = this.coords(workspaceFileScope.workspaceRoot);
|
|
357
|
-
return distroStat({ runner: this.runnerFor(distro), distro, linuxRoot, path, distroWorkspaceRoot: workspaceFileScope.workspaceRoot, signal });
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Read one line page; distro UNC roots read inside the distro.
|
|
361
|
-
*
|
|
362
|
-
* @param workspaceFileScope - the Session's file scope.
|
|
363
|
-
* @param path - the file to read.
|
|
364
|
-
* @param range - the line window.
|
|
365
|
-
* @param signal - caller cancellation.
|
|
366
|
-
*/
|
|
367
|
-
async read(workspaceFileScope, path, range, signal) {
|
|
368
|
-
if (!isDistroWorkspace(workspaceFileScope.workspaceRoot))
|
|
369
|
-
return super.read(workspaceFileScope, path, range, signal);
|
|
370
|
-
const { distro, linuxRoot } = this.coords(workspaceFileScope.workspaceRoot);
|
|
371
|
-
const offset = range.offset === undefined ? 1 : range.offset;
|
|
372
|
-
const limit = range.limit === undefined ? ownConfig(this).maxLines : range.limit;
|
|
373
|
-
if (!Number.isSafeInteger(offset) || offset < 1) {
|
|
374
|
-
throw new RemoteError("gateway/bad-request", "offset must be a safe integer of at least 1", {});
|
|
375
|
-
}
|
|
376
|
-
if (limit > ownConfig(this).maxLines) {
|
|
377
|
-
throw new RemoteError("gateway/bad-request", `limit must be at most ${ownConfig(this).maxLines}`, {});
|
|
378
|
-
}
|
|
379
|
-
return distroRead({
|
|
380
|
-
runner: this.runnerFor(distro),
|
|
381
|
-
distro,
|
|
382
|
-
linuxRoot,
|
|
383
|
-
path,
|
|
384
|
-
offset,
|
|
385
|
-
limit,
|
|
386
|
-
maxBytes: ownConfig(this).maxBytes,
|
|
387
|
-
distroWorkspaceRoot: workspaceFileScope.workspaceRoot,
|
|
388
|
-
signal,
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Read one byte window or the complete file; distro UNC roots read inside
|
|
393
|
-
* the distro.
|
|
394
|
-
*
|
|
395
|
-
* @param workspaceFileScope - the Session's file scope.
|
|
396
|
-
* @param path - the file to read.
|
|
397
|
-
* @param options - the byte window.
|
|
398
|
-
* @param signal - caller cancellation.
|
|
399
|
-
*/
|
|
400
|
-
async readBytes(workspaceFileScope, path, options, signal) {
|
|
401
|
-
if (!isDistroWorkspace(workspaceFileScope.workspaceRoot))
|
|
402
|
-
return super.readBytes(workspaceFileScope, path, options, signal);
|
|
403
|
-
const { distro, linuxRoot } = this.coords(workspaceFileScope.workspaceRoot);
|
|
404
|
-
return distroReadBytes({
|
|
405
|
-
runner: this.runnerFor(distro),
|
|
406
|
-
distro,
|
|
407
|
-
linuxRoot,
|
|
408
|
-
path,
|
|
409
|
-
offset: options.range?.offset,
|
|
410
|
-
length: options.range?.length,
|
|
411
|
-
maxBytes: ownConfig(this).maxBytes,
|
|
412
|
-
maxFileBytes: ownConfig(this).maxFileBytes,
|
|
413
|
-
distroWorkspaceRoot: workspaceFileScope.workspaceRoot,
|
|
414
|
-
signal,
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
export default WorkspaceFilesWsl;
|