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.
Files changed (79) hide show
  1. package/CHANGELOG.md +278 -0
  2. package/CONTRIBUTING.md +129 -39
  3. package/README.md +20 -20
  4. package/docs/ARCHITECTURE.md +6 -3
  5. package/docs/LIMITATIONS.md +13 -0
  6. package/docs/README.zh.md +20 -20
  7. package/lib/agent-confined.d.ts +42 -0
  8. package/lib/agent-confined.js +25 -41
  9. package/lib/agent-errors.d.ts +31 -0
  10. package/lib/agent-errors.js +19 -16
  11. package/lib/agent-exec.d.ts +159 -0
  12. package/lib/agent-exec.js +151 -165
  13. package/lib/agent-protocol.d.ts +192 -0
  14. package/lib/agent-protocol.js +76 -100
  15. package/lib/agent-shared.d.ts +27 -0
  16. package/lib/agent-shared.js +12 -12
  17. package/lib/agent.d.ts +353 -0
  18. package/lib/agent.js +536 -552
  19. package/lib/auto-preset.d.ts +110 -0
  20. package/lib/auto-preset.js +157 -141
  21. package/lib/bwrap.d.ts +90 -0
  22. package/lib/bwrap.js +18 -18
  23. package/lib/file-reference-wsl.d.ts +160 -0
  24. package/lib/file-reference-wsl.js +192 -173
  25. package/lib/fs-decisions.d.ts +107 -0
  26. package/lib/fs-decisions.js +64 -60
  27. package/lib/fs-routing.d.ts +182 -0
  28. package/lib/fs-routing.js +173 -116
  29. package/lib/fs-substrate.d.ts +258 -0
  30. package/lib/fs-substrate.js +248 -248
  31. package/lib/fs.d.ts +10 -0
  32. package/lib/fs.js +5 -0
  33. package/lib/fsio-agent.d.ts +307 -0
  34. package/lib/fsio-agent.js +414 -410
  35. package/lib/fsio-text.d.ts +115 -0
  36. package/lib/fsio-text.js +104 -84
  37. package/lib/git-route.d.ts +100 -0
  38. package/lib/git-route.js +46 -47
  39. package/lib/index.d.ts +1003 -0
  40. package/lib/index.js +1101 -1003
  41. package/lib/listing.d.ts +114 -0
  42. package/lib/listing.js +68 -55
  43. package/lib/paths.d.ts +182 -0
  44. package/lib/paths.js +134 -109
  45. package/lib/picker.d.ts +266 -0
  46. package/lib/picker.js +371 -351
  47. package/lib/ports.d.ts +44 -0
  48. package/lib/ports.js +39 -29
  49. package/lib/preset-choice.d.ts +33 -0
  50. package/lib/preset-choice.js +15 -7
  51. package/lib/probe-cache.d.ts +40 -0
  52. package/lib/probe-cache.js +35 -29
  53. package/lib/sandbox-core.d.ts +79 -0
  54. package/lib/sandbox-core.js +71 -88
  55. package/lib/sandbox.d.ts +48 -0
  56. package/lib/sandbox.js +4 -4
  57. package/lib/search-exec.d.ts +96 -0
  58. package/lib/search-exec.js +52 -79
  59. package/lib/search-route.d.ts +75 -0
  60. package/lib/search-route.js +30 -31
  61. package/lib/shell-env.d.ts +88 -0
  62. package/lib/shell-env.js +78 -74
  63. package/lib/shell.d.ts +10 -0
  64. package/lib/shell.js +5 -0
  65. package/lib/subprocess.d.ts +313 -0
  66. package/lib/subprocess.js +267 -262
  67. package/lib/terminal-activity.d.ts +98 -0
  68. package/lib/terminal-activity.js +29 -39
  69. package/lib/terminal-route.d.ts +27 -0
  70. package/lib/terminal-route.js +16 -8
  71. package/lib/watcher.d.ts +77 -0
  72. package/lib/watcher.js +120 -126
  73. package/lib/workspace-files-route.d.ts +132 -0
  74. package/lib/workspace-files-route.js +73 -81
  75. package/lib/workspace-files-wsl.d.ts +257 -0
  76. package/lib/workspace-files-wsl.js +311 -251
  77. package/lib/wsl.d.ts +266 -0
  78. package/lib/wsl.js +144 -155
  79. 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
- return isWslUnc(targetKey);
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
- return value !== undefined && isWslUnc(value);
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
- static Config = LocalFileSystem.Config;
73
-
74
- /** The lazy distro backend, built on first routed use. */
75
- #distro;
76
- /** The distro knobs, verbatim from the row config. */
77
- #distroConfig;
78
-
79
- constructor(ctx, config) {
80
- super(ctx, config);
81
- this.#distroConfig = {
82
- distro: config.distro ?? "",
83
- wslPath: config.wslPath ?? "wsl.exe",
84
- cwd: config.distroCwd ?? "",
85
- diffBasisMaxBytes: config.diffBasisMaxBytes,
86
- sandbox: config.sandbox ?? true,
87
- maskWindowsDrive: config.maskWindowsDrive ?? false,
88
- restrictToDistro: config.restrictToDistro ?? true,
89
- watchMaxDepth: config.watchMaxDepth ?? 0,
90
- };
91
- }
92
-
93
- /** The distro backend for routed targets, built on first use. */
94
- distro() {
95
- return (this.#distro ??= new WslFileSystem(this.ctx, this.#distroConfig));
96
- }
97
-
98
- async resolve(path, opts) {
99
- if (inputIsDistro(path) || inputIsDistro(opts?.cwd)) return (await this.distro()).resolve(path, opts);
100
- return super.resolve(path, opts);
101
- }
102
-
103
- async lstat(path, opts, signal) {
104
- if (inputIsDistro(path) || inputIsDistro(opts?.cwd)) return (await this.distro()).lstat(path, opts, signal);
105
- return super.lstat(path, opts, signal);
106
- }
107
-
108
- async stat(target, signal) {
109
- if (targetIsDistro(target.targetKey)) return (await this.distro()).stat(target, signal);
110
- return super.stat(target, signal);
111
- }
112
-
113
- async readText(target, signal) {
114
- if (targetIsDistro(target.targetKey)) return (await this.distro()).readText(target, signal);
115
- return super.readText(target, signal);
116
- }
117
-
118
- async streamText(target, signal) {
119
- if (targetIsDistro(target.targetKey)) return (await this.distro()).streamText(target, signal);
120
- return super.streamText(target, signal);
121
- }
122
-
123
- async readBytes(target, signal, maxBytes) {
124
- if (targetIsDistro(target.targetKey)) return (await this.distro()).readBytes(target, signal, maxBytes);
125
- return super.readBytes(target, signal, maxBytes);
126
- }
127
-
128
- async readByteRange(target, range, signal) {
129
- if (targetIsDistro(target.targetKey)) return (await this.distro()).readByteRange(target, range, signal);
130
- return super.readByteRange(target, range, signal);
131
- }
132
-
133
- async listDir(target, signal) {
134
- if (targetIsDistro(target.targetKey)) return (await this.distro()).listDir(target, signal);
135
- return super.listDir(target, signal);
136
- }
137
-
138
- async writeText(target, content, expected, signal, sandboxPolicy) {
139
- if (targetIsDistro(target.targetKey)) {
140
- return (await this.distro()).writeText(target, content, expected, signal, sandboxPolicy);
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
- return super.writeText(target, content, expected, signal, sandboxPolicy);
143
- }
144
-
145
- async editText(target, edit, expected, signal, sandboxPolicy) {
146
- if (targetIsDistro(target.targetKey)) {
147
- return (await this.distro()).editText(target, edit, expected, signal, sandboxPolicy);
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
- return super.editText(target, edit, expected, signal, sandboxPolicy);
150
- }
151
-
152
- async watch(target, changed, signal) {
153
- if (targetIsDistro(target.targetKey)) return (await this.distro()).watch(target, changed, signal);
154
- return super.watch(target, changed, signal);
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;