dsh-plugin-wsl-env 0.7.5 → 0.8.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 +278 -0
- package/CONTRIBUTING.md +129 -39
- package/README.md +20 -20
- package/docs/ARCHITECTURE.md +6 -3
- package/docs/LIMITATIONS.md +13 -0
- package/docs/README.zh.md +20 -20
- package/lib/agent-confined.d.ts +42 -0
- package/lib/agent-confined.js +25 -41
- package/lib/agent-errors.d.ts +31 -0
- package/lib/agent-errors.js +19 -16
- package/lib/agent-exec.d.ts +159 -0
- package/lib/agent-exec.js +151 -165
- package/lib/agent-protocol.d.ts +192 -0
- package/lib/agent-protocol.js +76 -100
- package/lib/agent-shared.d.ts +27 -0
- package/lib/agent-shared.js +12 -12
- package/lib/agent.d.ts +353 -0
- package/lib/agent.js +536 -552
- package/lib/auto-preset.d.ts +110 -0
- package/lib/auto-preset.js +157 -141
- package/lib/bwrap.d.ts +90 -0
- package/lib/bwrap.js +18 -18
- package/lib/file-reference-wsl.d.ts +160 -0
- package/lib/file-reference-wsl.js +192 -173
- package/lib/fs-decisions.d.ts +107 -0
- package/lib/fs-decisions.js +64 -60
- package/lib/fs-routing.d.ts +182 -0
- package/lib/fs-routing.js +173 -116
- package/lib/fs-substrate.d.ts +258 -0
- package/lib/fs-substrate.js +248 -248
- package/lib/fs.d.ts +10 -0
- package/lib/fs.js +5 -0
- package/lib/fsio-agent.d.ts +307 -0
- package/lib/fsio-agent.js +414 -410
- package/lib/fsio-text.d.ts +115 -0
- package/lib/fsio-text.js +104 -84
- package/lib/git-route.d.ts +100 -0
- package/lib/git-route.js +46 -47
- package/lib/index.d.ts +1003 -0
- package/lib/index.js +1101 -1003
- package/lib/listing.d.ts +114 -0
- package/lib/listing.js +68 -55
- package/lib/paths.d.ts +182 -0
- package/lib/paths.js +134 -109
- package/lib/picker.d.ts +266 -0
- package/lib/picker.js +371 -351
- package/lib/ports.d.ts +44 -0
- package/lib/ports.js +39 -29
- package/lib/preset-choice.d.ts +33 -0
- package/lib/preset-choice.js +15 -7
- package/lib/probe-cache.d.ts +40 -0
- package/lib/probe-cache.js +35 -29
- package/lib/sandbox-core.d.ts +79 -0
- package/lib/sandbox-core.js +71 -88
- package/lib/sandbox.d.ts +48 -0
- package/lib/sandbox.js +4 -4
- package/lib/search-exec.d.ts +96 -0
- package/lib/search-exec.js +52 -79
- package/lib/search-route.d.ts +75 -0
- package/lib/search-route.js +30 -31
- package/lib/shell-env.d.ts +88 -0
- package/lib/shell-env.js +78 -74
- package/lib/shell.d.ts +10 -0
- package/lib/shell.js +5 -0
- package/lib/subprocess.d.ts +313 -0
- package/lib/subprocess.js +267 -262
- package/lib/terminal-activity.d.ts +98 -0
- package/lib/terminal-activity.js +29 -39
- package/lib/terminal-route.d.ts +27 -0
- package/lib/terminal-route.js +16 -8
- package/lib/watcher.d.ts +77 -0
- package/lib/watcher.js +120 -126
- package/lib/workspace-files-route.d.ts +132 -0
- package/lib/workspace-files-route.js +73 -81
- package/lib/workspace-files-wsl.d.ts +257 -0
- package/lib/workspace-files-wsl.js +311 -251
- package/lib/wsl.d.ts +266 -0
- package/lib/wsl.js +144 -155
- package/package.json +68 -20
package/lib/fs-routing.js
CHANGED
|
@@ -24,14 +24,15 @@
|
|
|
24
24
|
* containment — the distro side kernel-enforced). If a root-plane write
|
|
25
25
|
* consumer appears, its fence rides with that consumer.
|
|
26
26
|
*
|
|
27
|
+
* This is a TypeScript source built to `lib/fs-routing.js`; edit THIS file and
|
|
28
|
+
* run `pnpm run build` — the artifact under `lib/` is generated, and `pnpm test`
|
|
29
|
+
* fails when it drifts.
|
|
30
|
+
*
|
|
27
31
|
* @module dsh-plugin-wsl/fs-routing
|
|
28
32
|
*/
|
|
29
|
-
|
|
30
|
-
import { isWslUnc, uncToPosix, windowsToLinuxMount } from "./paths.js";
|
|
33
|
+
import { isWslUnc, uncToPosix } from "./paths.js";
|
|
31
34
|
import { LocalFileSystem } from "@deepseek-ai/dsh-fs-local";
|
|
32
|
-
import { linuxJoin } from "./workspace-files-route.js";
|
|
33
35
|
import { WslFileSystem } from "./index.js";
|
|
34
|
-
|
|
35
36
|
/**
|
|
36
37
|
* Whether a resolved target identity belongs to the distro.
|
|
37
38
|
*
|
|
@@ -39,9 +40,8 @@ import { WslFileSystem } from "./index.js";
|
|
|
39
40
|
* @returns true when the target lives inside a WSL distro.
|
|
40
41
|
*/
|
|
41
42
|
export function targetIsDistro(targetKey) {
|
|
42
|
-
|
|
43
|
+
return isWslUnc(targetKey);
|
|
43
44
|
}
|
|
44
|
-
|
|
45
45
|
/**
|
|
46
46
|
* Whether a raw path-or-cwd input names the distro (used by the operations
|
|
47
47
|
* that take paths before a target exists: resolve, lstat).
|
|
@@ -50,17 +50,8 @@ export function targetIsDistro(targetKey) {
|
|
|
50
50
|
* @returns true when the input names a distro UNC.
|
|
51
51
|
*/
|
|
52
52
|
export function inputIsDistro(value) {
|
|
53
|
-
|
|
53
|
+
return value !== undefined && isWslUnc(value);
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* The Linux working path for one request: UNC absolutes map onto their Linux
|
|
58
|
-
* paths, POSIX absolutes and relative paths join onto the root.
|
|
59
|
-
*
|
|
60
|
-
* @param linuxRoot - the workspace root in Linux form.
|
|
61
|
-
* @param path - the requested path, any coordinate system.
|
|
62
|
-
* @returns the absolute Linux path.
|
|
63
|
-
*/
|
|
64
55
|
/**
|
|
65
56
|
* The root-plane filesystem with coordinate routing.
|
|
66
57
|
*
|
|
@@ -69,108 +60,174 @@ export function inputIsDistro(value) {
|
|
|
69
60
|
* mode the distro side reports through `sandboxMode`).
|
|
70
61
|
*/
|
|
71
62
|
export class WslRoutingFileSystem extends LocalFileSystem {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
63
|
+
static Config = LocalFileSystem.Config;
|
|
64
|
+
/**
|
|
65
|
+
* The lazy distro backend, built on first routed use, typed as the concrete
|
|
66
|
+
* class: these routing calls are that class's own surface, and the
|
|
67
|
+
* `processPathFromHostPath` seam it once could not satisfy (async against the
|
|
68
|
+
* peer interface's synchronous contract) is closed — the backend maps
|
|
69
|
+
* synchronously now, from what it already knows.
|
|
70
|
+
*/
|
|
71
|
+
#distro;
|
|
72
|
+
/** The distro knobs, verbatim from the row config. */
|
|
73
|
+
#distroConfig;
|
|
74
|
+
/**
|
|
75
|
+
* @param ctx - the cordis context.
|
|
76
|
+
* @param config - the row config, host knobs plus distro knobs.
|
|
77
|
+
*/
|
|
78
|
+
constructor(ctx, config) {
|
|
79
|
+
super(ctx, config);
|
|
80
|
+
this.#distroConfig = {
|
|
81
|
+
distro: config.distro ?? "",
|
|
82
|
+
wslPath: config.wslPath ?? "wsl.exe",
|
|
83
|
+
cwd: config.distroCwd ?? "",
|
|
84
|
+
diffBasisMaxBytes: config.diffBasisMaxBytes,
|
|
85
|
+
sandbox: config.sandbox ?? true,
|
|
86
|
+
maskWindowsDrive: config.maskWindowsDrive ?? false,
|
|
87
|
+
restrictToDistro: config.restrictToDistro ?? true,
|
|
88
|
+
watchMaxDepth: config.watchMaxDepth ?? 0,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** The distro backend for routed targets, built on first use. */
|
|
92
|
+
distro() {
|
|
93
|
+
return (this.#distro ??= new WslFileSystem(this.ctx, this.#distroConfig));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* @param path - the requested path.
|
|
97
|
+
* @param opts - the resolve options.
|
|
98
|
+
*/
|
|
99
|
+
async resolve(path, opts) {
|
|
100
|
+
if (inputIsDistro(path) || inputIsDistro(opts?.cwd))
|
|
101
|
+
return (await this.distro()).resolve(path, opts);
|
|
102
|
+
return super.resolve(path, opts);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* @param path - the requested path.
|
|
106
|
+
* @param opts - the lstat options.
|
|
107
|
+
* @param signal - cancels the round trip.
|
|
108
|
+
*/
|
|
109
|
+
async lstat(path, opts, signal) {
|
|
110
|
+
if (inputIsDistro(path) || inputIsDistro(opts?.cwd))
|
|
111
|
+
return (await this.distro()).lstat(path, opts, signal);
|
|
112
|
+
return super.lstat(path, opts, signal);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* @param target - the resolved target.
|
|
116
|
+
* @param signal - cancels the round trip.
|
|
117
|
+
*/
|
|
118
|
+
async stat(target, signal) {
|
|
119
|
+
if (targetIsDistro(target.targetKey))
|
|
120
|
+
return (await this.distro()).stat(target, signal);
|
|
121
|
+
return super.stat(target, signal);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* @param target - the resolved target.
|
|
125
|
+
* @param signal - cancels the round trip.
|
|
126
|
+
*/
|
|
127
|
+
async readText(target, signal) {
|
|
128
|
+
if (targetIsDistro(target.targetKey))
|
|
129
|
+
return (await this.distro()).readText(target, signal);
|
|
130
|
+
return super.readText(target, signal);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* @param target - the resolved target.
|
|
134
|
+
* @param signal - cancels the stream.
|
|
135
|
+
*/
|
|
136
|
+
async streamText(target, signal) {
|
|
137
|
+
if (targetIsDistro(target.targetKey))
|
|
138
|
+
return (await this.distro()).streamText(target, signal);
|
|
139
|
+
return super.streamText(target, signal);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* @param target - the resolved target.
|
|
143
|
+
* @param signal - cancels the read.
|
|
144
|
+
* @param maxBytes - the inclusive byte cap.
|
|
145
|
+
*/
|
|
146
|
+
async readBytes(target, signal, maxBytes) {
|
|
147
|
+
if (targetIsDistro(target.targetKey))
|
|
148
|
+
return (await this.distro()).readBytes(target, signal, maxBytes);
|
|
149
|
+
return super.readBytes(target, signal, maxBytes);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* @param target - the resolved target.
|
|
153
|
+
* @param range - the byte window.
|
|
154
|
+
* @param signal - cancels the read.
|
|
155
|
+
*/
|
|
156
|
+
async readByteRange(target, range, signal) {
|
|
157
|
+
if (targetIsDistro(target.targetKey))
|
|
158
|
+
return (await this.distro()).readByteRange(target, range, signal);
|
|
159
|
+
return super.readByteRange(target, range, signal);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* @param target - the resolved directory.
|
|
163
|
+
* @param signal - cancels the listing.
|
|
164
|
+
*/
|
|
165
|
+
async listDir(target, signal) {
|
|
166
|
+
if (targetIsDistro(target.targetKey))
|
|
167
|
+
return (await this.distro()).listDir(target, signal);
|
|
168
|
+
return super.listDir(target, signal);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* @param target - the resolved target.
|
|
172
|
+
* @param content - the full new content.
|
|
173
|
+
* @param expected - the guarded-write intent.
|
|
174
|
+
* @param signal - cancels the write.
|
|
175
|
+
* @param sandboxPolicy - the confined policy the distro side honors; the
|
|
176
|
+
* host backend takes no such parameter.
|
|
177
|
+
*/
|
|
178
|
+
async writeText(target, content, expected, signal, sandboxPolicy) {
|
|
179
|
+
if (targetIsDistro(target.targetKey)) {
|
|
180
|
+
return (await this.distro()).writeText(target, content, expected, signal, sandboxPolicy);
|
|
181
|
+
}
|
|
182
|
+
return super.writeText(target, content, expected, signal);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* @param target - the resolved target.
|
|
186
|
+
* @param edit - the literal edit.
|
|
187
|
+
* @param expected - the version the edit was based on.
|
|
188
|
+
* @param signal - cancels the edit.
|
|
189
|
+
* @param sandboxPolicy - the confined policy the distro side honors; the
|
|
190
|
+
* host backend takes no such parameter.
|
|
191
|
+
*/
|
|
192
|
+
async editText(target, edit, expected, signal, sandboxPolicy) {
|
|
193
|
+
if (targetIsDistro(target.targetKey)) {
|
|
194
|
+
return (await this.distro()).editText(target, edit, expected, signal, sandboxPolicy);
|
|
195
|
+
}
|
|
196
|
+
return super.editText(target, edit, expected, signal);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* @param target - the resolved target.
|
|
200
|
+
* @param changed - the change callback.
|
|
201
|
+
* @param signal - cancels the watch.
|
|
202
|
+
*/
|
|
203
|
+
async watch(target, changed, signal) {
|
|
204
|
+
if (targetIsDistro(target.targetKey))
|
|
205
|
+
return (await this.distro()).watch(target, changed, signal);
|
|
206
|
+
return super.watch(target, changed, signal);
|
|
141
207
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
208
|
+
/**
|
|
209
|
+
* @param parent - the container.
|
|
210
|
+
* @param child - the contained candidate.
|
|
211
|
+
*/
|
|
212
|
+
contains(parent, child) {
|
|
213
|
+
if (targetIsDistro(parent.targetKey)) {
|
|
214
|
+
// Both targets came from this router's distro resolve, so the plain
|
|
215
|
+
// POSIX containment over their process paths is the same check the
|
|
216
|
+
// distro substrate performs for its own guarded writes.
|
|
217
|
+
const base = this.processPath(parent);
|
|
218
|
+
const full = this.processPath(child);
|
|
219
|
+
return full === base || full.startsWith(base.endsWith("/") ? base : `${base}/`);
|
|
220
|
+
}
|
|
221
|
+
return super.contains(parent, child);
|
|
148
222
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
contains(parent, child) {
|
|
158
|
-
if (targetIsDistro(parent.targetKey)) {
|
|
159
|
-
// Both targets came from this router's distro resolve, so the plain
|
|
160
|
-
// POSIX containment over their process paths is the same check the
|
|
161
|
-
// distro substrate performs for its own guarded writes.
|
|
162
|
-
const base = this.processPath(parent);
|
|
163
|
-
const full = this.processPath(child);
|
|
164
|
-
return full === base || full.startsWith(base.endsWith("/") ? base : `${base}/`);
|
|
223
|
+
/**
|
|
224
|
+
* @param target - the resolved target.
|
|
225
|
+
*/
|
|
226
|
+
processPath(target) {
|
|
227
|
+
const parsed = uncToPosix(target.targetKey);
|
|
228
|
+
if (parsed !== undefined)
|
|
229
|
+
return parsed.linuxPath.length > 0 ? parsed.linuxPath : "/";
|
|
230
|
+
return super.processPath(target);
|
|
165
231
|
}
|
|
166
|
-
return super.contains(parent, child);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
processPath(target) {
|
|
170
|
-
const parsed = uncToPosix(target.targetKey);
|
|
171
|
-
if (parsed !== undefined) return parsed.linuxPath.length > 0 ? parsed.linuxPath : "/";
|
|
172
|
-
return super.processPath(target);
|
|
173
|
-
}
|
|
174
232
|
}
|
|
175
|
-
|
|
176
233
|
export default WslRoutingFileSystem;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent-backed filesystem substrate: the provider-shaped operations the
|
|
3
|
+
* model's file tools call, orchestrated over the distro's FS frames.
|
|
4
|
+
*
|
|
5
|
+
* This is the `ctx.fs` seam's mechanics for `substrate: "agent"` — resolve,
|
|
6
|
+
* stat, reads, and the write/edit orchestration the host backend owns on a
|
|
7
|
+
* share-backed session (probe, guards, diff basis, publication, outcome
|
|
8
|
+
* shape), mirroring `@deepseek-ai/dsh-fs-local`'s `writeText` and `editText`
|
|
9
|
+
* byte-for-byte in message and code. Two deliberate differences from the share
|
|
10
|
+
* backend it replaces:
|
|
11
|
+
*
|
|
12
|
+
* 1. **The mutation guard survives to the write — per intent.** A guarded
|
|
13
|
+
* create publishes with the distro-side no-replace link, a real atomic
|
|
14
|
+
* primitive that refuses to replace. An overwrite or edit carries the
|
|
15
|
+
* version it was based on INTO the write op, and the agent re-verifies it
|
|
16
|
+
* with a fresh stat one syscall before the rename: a concurrent writer
|
|
17
|
+
* (an editor save, `git stash`, another session) wins, and the stale
|
|
18
|
+
* write refuses with `FS_STALE_VERSION` instead of clobbering. That
|
|
19
|
+
* narrows the share backend's check-then-write window from a host round
|
|
20
|
+
* trip to kernel-adjacent — the honest wording; "closed" was true only
|
|
21
|
+
* for the create case.
|
|
22
|
+
* 2. A symlink needs no retry machinery: every identity is resolved where the
|
|
23
|
+
* symlinks live.
|
|
24
|
+
*
|
|
25
|
+
* Peer-free by construction: refusals are `FsCodedError`s from
|
|
26
|
+
* `lib/fsio-text.js`, mapped onto the peer's `FsError` at the provider
|
|
27
|
+
* boundary, so this module is unit-testable in a bare checkout against the
|
|
28
|
+
* real agent script.
|
|
29
|
+
*
|
|
30
|
+
* This is a TypeScript source built to `lib/fs-substrate.js`; edit THIS file
|
|
31
|
+
* and run `pnpm run build` — the artifact under `lib/` is generated, and
|
|
32
|
+
* `pnpm test` fails when it drifts.
|
|
33
|
+
*
|
|
34
|
+
* @module dsh-plugin-wsl/fs-substrate
|
|
35
|
+
*/
|
|
36
|
+
import { DistroFs } from "./fsio-agent.js";
|
|
37
|
+
import type { WslAgent } from "./agent.js";
|
|
38
|
+
/**
|
|
39
|
+
* A resolved target: the Linux spelling the model sees and the UNC identity
|
|
40
|
+
* the harness keys on, as returned by {@linkcode AgentSubstrate#resolve}.
|
|
41
|
+
*/
|
|
42
|
+
export interface ResolvedTarget {
|
|
43
|
+
/** The canonical Linux path spelling. */
|
|
44
|
+
displayPath: string;
|
|
45
|
+
/** The UNC identity this target keys on. */
|
|
46
|
+
targetKey: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* One distro's provider-shaped filesystem face.
|
|
50
|
+
*/
|
|
51
|
+
export declare class AgentSubstrate {
|
|
52
|
+
/** The pinned distro name, for UNC identity. */
|
|
53
|
+
distro: string;
|
|
54
|
+
/** The overwrite-diff bound, mirroring the provider config. */
|
|
55
|
+
diffBasisMaxBytes: number;
|
|
56
|
+
/** The resident in-distro agent reads ride. */
|
|
57
|
+
agent: WslAgent;
|
|
58
|
+
/** Stage-two routing: the agent a mutation must run on for the resolved policy, when wired. */
|
|
59
|
+
agentFor: ((policy: {
|
|
60
|
+
mode: string;
|
|
61
|
+
workspaceRoot: string;
|
|
62
|
+
} | undefined) => Promise<WslAgent>) | undefined;
|
|
63
|
+
/** The distro-side filesystem face. */
|
|
64
|
+
fs: DistroFs;
|
|
65
|
+
/** Per-targetKey tail promise: the host backend's mutation serialization. */
|
|
66
|
+
locks: Map<string, Promise<void>>;
|
|
67
|
+
/**
|
|
68
|
+
* @param deps - the substrate's collaborators.
|
|
69
|
+
*/
|
|
70
|
+
constructor({ agent, agentFor, distro, diffBasisMaxBytes }: {
|
|
71
|
+
/** The resident in-distro agent reads ride. */
|
|
72
|
+
agent: WslAgent;
|
|
73
|
+
/** The pinned distro name, for UNC identity. */
|
|
74
|
+
distro: string;
|
|
75
|
+
/** The overwrite-diff bound, mirroring the provider config. */
|
|
76
|
+
diffBasisMaxBytes?: number;
|
|
77
|
+
/**
|
|
78
|
+
* Stage-two routing: the agent a MUTATION must run on for this resolved
|
|
79
|
+
* policy — the confined resident whose mount table matches the granted
|
|
80
|
+
* rights. Omitted (or resolving to `deps.agent`) keeps every op on the
|
|
81
|
+
* plain resident, which is stage one's posture.
|
|
82
|
+
*/
|
|
83
|
+
agentFor?: (policy: {
|
|
84
|
+
mode: string;
|
|
85
|
+
workspaceRoot: string;
|
|
86
|
+
} | undefined) => Promise<WslAgent>;
|
|
87
|
+
});
|
|
88
|
+
/**
|
|
89
|
+
* The agent a mutation runs on under this resolved policy.
|
|
90
|
+
*
|
|
91
|
+
* @param policy - the resolved file-effect policy, or undefined when the
|
|
92
|
+
* caller pre-checked.
|
|
93
|
+
* @returns the agent to publish through.
|
|
94
|
+
*/
|
|
95
|
+
mutationAgent(policy: {
|
|
96
|
+
mode: string;
|
|
97
|
+
workspaceRoot: string;
|
|
98
|
+
} | undefined): Promise<WslAgent>;
|
|
99
|
+
/**
|
|
100
|
+
* Run `op` with exclusive access to `targetKey` (FIFO per key).
|
|
101
|
+
*
|
|
102
|
+
* @template T
|
|
103
|
+
* @param targetKey - the mutation's serialization key.
|
|
104
|
+
* @param op - the exclusive section.
|
|
105
|
+
* @returns the section's outcome.
|
|
106
|
+
*/
|
|
107
|
+
lock<T>(targetKey: string, op: () => Promise<T>): Promise<T>;
|
|
108
|
+
/**
|
|
109
|
+
* The Linux path a resolved target names, falling back to its display.
|
|
110
|
+
*
|
|
111
|
+
* @param target - the resolved target.
|
|
112
|
+
* @returns the Linux path to operate on.
|
|
113
|
+
*/
|
|
114
|
+
linuxOf(target: ResolvedTarget): string;
|
|
115
|
+
/**
|
|
116
|
+
* Resolve one absolute Linux path to the target shape the provider returns:
|
|
117
|
+
* the canonical Linux spelling the model sees and the UNC identity the
|
|
118
|
+
* harness keys on. Symlinks resolve here, where they live.
|
|
119
|
+
*
|
|
120
|
+
* @param linuxPath - the absolute Linux path to resolve.
|
|
121
|
+
* @param signal - cancels the round trip.
|
|
122
|
+
*/
|
|
123
|
+
resolve(linuxPath: string, signal?: AbortSignal): Promise<{
|
|
124
|
+
displayPath: string;
|
|
125
|
+
targetKey: string;
|
|
126
|
+
}>;
|
|
127
|
+
/**
|
|
128
|
+
* Follow-stat one target; `undefined` when absent.
|
|
129
|
+
*
|
|
130
|
+
* @param target - the resolved target.
|
|
131
|
+
* @param signal - cancels the round trip.
|
|
132
|
+
*/
|
|
133
|
+
stat(target: ResolvedTarget, signal?: AbortSignal): Promise<{
|
|
134
|
+
version: string;
|
|
135
|
+
type: string;
|
|
136
|
+
size: number;
|
|
137
|
+
} | undefined>;
|
|
138
|
+
/**
|
|
139
|
+
* No-follow stat one path; `undefined` when absent, `symlink` for a link.
|
|
140
|
+
*
|
|
141
|
+
* @param linuxPath - the absolute Linux path to inspect.
|
|
142
|
+
* @param signal - cancels the round trip.
|
|
143
|
+
*/
|
|
144
|
+
lstat(linuxPath: string, signal?: AbortSignal): Promise<{
|
|
145
|
+
version: string;
|
|
146
|
+
type: string;
|
|
147
|
+
size: number;
|
|
148
|
+
} | undefined>;
|
|
149
|
+
/**
|
|
150
|
+
* Read a whole regular UTF-8 file.
|
|
151
|
+
*
|
|
152
|
+
* @param target - the resolved target.
|
|
153
|
+
* @param signal - aborts the read.
|
|
154
|
+
* @returns the full decoded text.
|
|
155
|
+
*/
|
|
156
|
+
readText(target: ResolvedTarget, signal?: AbortSignal): Promise<string>;
|
|
157
|
+
/**
|
|
158
|
+
* Stream a whole regular UTF-8 file as decoded chunks.
|
|
159
|
+
*
|
|
160
|
+
* @param target - the resolved target.
|
|
161
|
+
* @param signal - aborts the stream.
|
|
162
|
+
* @returns the chunk stream.
|
|
163
|
+
*/
|
|
164
|
+
streamText(target: ResolvedTarget, signal?: AbortSignal): Promise<AsyncGenerator<string>>;
|
|
165
|
+
/**
|
|
166
|
+
* Read a whole regular file as raw bytes, bounded.
|
|
167
|
+
*
|
|
168
|
+
* @param target - the resolved target.
|
|
169
|
+
* @param signal - aborts the read.
|
|
170
|
+
* @param maxBytes - inclusive byte cap.
|
|
171
|
+
* @returns the bytes.
|
|
172
|
+
*/
|
|
173
|
+
readBytes(target: ResolvedTarget, signal: AbortSignal | undefined, maxBytes: number): Promise<Uint8Array>;
|
|
174
|
+
/**
|
|
175
|
+
* Read one byte window of a regular file.
|
|
176
|
+
*
|
|
177
|
+
* @param target - the resolved target.
|
|
178
|
+
* @param range - the window.
|
|
179
|
+
* @param signal - aborts the read.
|
|
180
|
+
* @returns the window's bytes.
|
|
181
|
+
*/
|
|
182
|
+
readByteRange(target: ResolvedTarget, range: {
|
|
183
|
+
offset: number;
|
|
184
|
+
length: number;
|
|
185
|
+
}, signal?: AbortSignal): Promise<Uint8Array>;
|
|
186
|
+
/**
|
|
187
|
+
* List one directory's direct children.
|
|
188
|
+
*
|
|
189
|
+
* @param target - the resolved directory.
|
|
190
|
+
* @param signal - aborts between children.
|
|
191
|
+
*/
|
|
192
|
+
listDir(target: ResolvedTarget, signal?: AbortSignal): Promise<Array<{
|
|
193
|
+
name: string;
|
|
194
|
+
type: string;
|
|
195
|
+
target: {
|
|
196
|
+
displayPath: string;
|
|
197
|
+
targetKey: string;
|
|
198
|
+
};
|
|
199
|
+
version?: string;
|
|
200
|
+
size?: number;
|
|
201
|
+
}>>;
|
|
202
|
+
/**
|
|
203
|
+
* Write a whole text file with the host backend's orchestration: probe,
|
|
204
|
+
* guard, best-effort diff basis, atomic publication, outcome shape. The
|
|
205
|
+
* guard is FORWARDED — a guarded create publishes with the distro-side
|
|
206
|
+
* no-replace link (atomic), and a `replaceIfVersion` write carries its
|
|
207
|
+
* version into the op, where the agent re-verifies it one syscall before
|
|
208
|
+
* the rename and refuses with `FS_STALE_VERSION` on a mismatch.
|
|
209
|
+
*
|
|
210
|
+
* @param target - the resolved target.
|
|
211
|
+
* @param content - the full new file content.
|
|
212
|
+
* @param expected - the write intent.
|
|
213
|
+
* @param signal - cancels the write.
|
|
214
|
+
* @param policy - the resolved policy this write was fenced with; selects
|
|
215
|
+
* the confined resident when stage-two routing is wired.
|
|
216
|
+
*/
|
|
217
|
+
writeText(target: ResolvedTarget, content: string, expected: {
|
|
218
|
+
kind: string;
|
|
219
|
+
version?: string;
|
|
220
|
+
} | undefined, signal?: AbortSignal, policy?: {
|
|
221
|
+
mode: string;
|
|
222
|
+
workspaceRoot: string;
|
|
223
|
+
} | undefined): Promise<{
|
|
224
|
+
operation: string;
|
|
225
|
+
version: string;
|
|
226
|
+
before: string | null;
|
|
227
|
+
after: string;
|
|
228
|
+
}>;
|
|
229
|
+
/**
|
|
230
|
+
* Edit a text file with the host backend's orchestration: probe, version
|
|
231
|
+
* guard, LF-normalized read, literal replacement, line-ending restore,
|
|
232
|
+
* atomic publication, outcome shape. The version the edit was based on
|
|
233
|
+
* rides the write op and is re-verified distro-side one syscall before the
|
|
234
|
+
* rename, so a concurrent writer wins instead of being clobbered.
|
|
235
|
+
*
|
|
236
|
+
* @param target - the resolved target.
|
|
237
|
+
* @param edit - the literal request.
|
|
238
|
+
* @param expected - the version guard.
|
|
239
|
+
* @param signal - cancels the edit.
|
|
240
|
+
* @param policy - the resolved policy this edit was fenced with; selects
|
|
241
|
+
* the confined resident when stage-two routing is wired.
|
|
242
|
+
*/
|
|
243
|
+
editText(target: ResolvedTarget, edit: {
|
|
244
|
+
oldString: string;
|
|
245
|
+
newString: string;
|
|
246
|
+
replaceAll?: boolean;
|
|
247
|
+
}, expected: {
|
|
248
|
+
version: string;
|
|
249
|
+
} | undefined, signal?: AbortSignal, policy?: {
|
|
250
|
+
mode: string;
|
|
251
|
+
workspaceRoot: string;
|
|
252
|
+
} | undefined): Promise<{
|
|
253
|
+
version: string;
|
|
254
|
+
before: string;
|
|
255
|
+
after: string;
|
|
256
|
+
}>;
|
|
257
|
+
}
|
|
258
|
+
export default AgentSubstrate;
|