@struktoai/mirage-dsh 0.0.1 → 0.0.6
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/cordis.patch.yml +49 -0
- package/dist/{chunk-CATVBGGR.js → chunk-2F2PJ7D7.js} +66 -4
- package/dist/{chunk-CATVBGGR.js.map → chunk-2F2PJ7D7.js.map} +1 -1
- package/dist/chunk-4CZV24HW.js +196 -0
- package/dist/chunk-4CZV24HW.js.map +1 -0
- package/dist/{chunk-C67TSSYB.js → chunk-M4JOF35U.js} +108 -15
- package/dist/chunk-M4JOF35U.js.map +1 -0
- package/dist/chunk-QTBMLMKT.js +698 -0
- package/dist/chunk-QTBMLMKT.js.map +1 -0
- package/dist/fs-B3Zi9oo6.d.ts +104 -0
- package/dist/index.d.ts +137 -5
- package/dist/index.js +14 -6
- package/dist/plugin/fs.d.ts +1 -1
- package/dist/plugin/fs.js +2 -2
- package/dist/plugin/service.d.ts +3 -2
- package/dist/plugin/service.js +1 -1
- package/dist/plugin/shell.d.ts +1 -1
- package/dist/plugin/shell.js +2 -2
- package/dist/{service-CxFYAvoV.d.ts → service-BK6NR_RX.d.ts} +51 -1
- package/dist/shell-BTf2wsDy.d.ts +258 -0
- package/package.json +10 -7
- package/dist/chunk-C67TSSYB.js.map +0 -1
- package/dist/chunk-J6F4OX6Z.js +0 -102
- package/dist/chunk-J6F4OX6Z.js.map +0 -1
- package/dist/chunk-ZSZVHBSL.js +0 -455
- package/dist/chunk-ZSZVHBSL.js.map +0 -1
- package/dist/fs-CuiUEA7A.d.ts +0 -54
- package/dist/shell-B0N_jppN.d.ts +0 -108
|
@@ -4,17 +4,19 @@ import {
|
|
|
4
4
|
detectsCrlf,
|
|
5
5
|
normalizeLineEndings,
|
|
6
6
|
restoreLineEndings
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2F2PJ7D7.js";
|
|
8
8
|
|
|
9
9
|
// src/fs.ts
|
|
10
10
|
import { Buffer } from "buffer";
|
|
11
11
|
import { posix } from "path";
|
|
12
12
|
import { FileSystem, FsError as FsError2, FsTargetKey, FsVersion } from "@deepseek-ai/dsh-fs";
|
|
13
|
-
import {
|
|
13
|
+
import { FileType } from "@struktoai/mirage-core/types";
|
|
14
|
+
import { isMissingPath as isMissingPath2 } from "@struktoai/mirage-core/utils/errors";
|
|
15
|
+
import { compareCodePoints } from "@struktoai/mirage-core/utils/sort";
|
|
14
16
|
|
|
15
17
|
// src/errors.ts
|
|
16
18
|
import { FsError } from "@deepseek-ai/dsh-fs";
|
|
17
|
-
import { isMissingPath } from "@struktoai/mirage-core";
|
|
19
|
+
import { isMissingPath } from "@struktoai/mirage-core/utils/errors";
|
|
18
20
|
function assertNotAborted(signal, operation) {
|
|
19
21
|
if (signal?.aborted === true) {
|
|
20
22
|
throw new FsError(`${operation} aborted`, "FS_ABORTED");
|
|
@@ -27,6 +29,7 @@ function codeOf(err) {
|
|
|
27
29
|
}
|
|
28
30
|
function codeFor(err) {
|
|
29
31
|
if (isMissingPath(err)) return "FS_NOT_FOUND";
|
|
32
|
+
if (err instanceof Error && err.name === "PolicyDenied") return "FS_SANDBOX_DENIED";
|
|
30
33
|
switch (codeOf(err)) {
|
|
31
34
|
case "EISDIR":
|
|
32
35
|
return "FS_NOT_REGULAR_FILE";
|
|
@@ -34,6 +37,7 @@ function codeFor(err) {
|
|
|
34
37
|
return "FS_NOT_DIRECTORY";
|
|
35
38
|
case "EACCES":
|
|
36
39
|
case "EPERM":
|
|
40
|
+
case "EROFS":
|
|
37
41
|
return "FS_PERMISSION_DENIED";
|
|
38
42
|
default:
|
|
39
43
|
return "FS_IO_ERROR";
|
|
@@ -41,7 +45,7 @@ function codeFor(err) {
|
|
|
41
45
|
}
|
|
42
46
|
function mapMirageError(err, operation, displayPath) {
|
|
43
47
|
if (err instanceof FsError) return err;
|
|
44
|
-
if (err instanceof
|
|
48
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
45
49
|
return new FsError(`${operation} aborted`, "FS_ABORTED", { cause: err });
|
|
46
50
|
}
|
|
47
51
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -73,6 +77,13 @@ function typeOf(stat) {
|
|
|
73
77
|
async function* singleChunk(text) {
|
|
74
78
|
yield await Promise.resolve(text);
|
|
75
79
|
}
|
|
80
|
+
function tooLarge(displayPath, maxBytes, size) {
|
|
81
|
+
const found = size === void 0 ? "" : `${String(size)} bytes `;
|
|
82
|
+
return new FsError2(
|
|
83
|
+
`cannot read "${displayPath}": ${found}exceeds the ${String(maxBytes)} byte cap`,
|
|
84
|
+
"FS_TOO_LARGE"
|
|
85
|
+
);
|
|
86
|
+
}
|
|
76
87
|
var MirageFileSystem = class extends FileSystem {
|
|
77
88
|
static inject = ["mirage"];
|
|
78
89
|
fsOps = null;
|
|
@@ -103,8 +114,62 @@ var MirageFileSystem = class extends FileSystem {
|
|
|
103
114
|
}
|
|
104
115
|
return this.fsOps.links;
|
|
105
116
|
}
|
|
106
|
-
|
|
107
|
-
|
|
117
|
+
/**
|
|
118
|
+
* The same confinement claim `MirageShellExecutor` makes, off the same
|
|
119
|
+
* fact and for the same reason: with every runtime reaching only the
|
|
120
|
+
* vfs, a mutation cannot land anywhere but a mount, under its mode.
|
|
121
|
+
*
|
|
122
|
+
* The two seams sit over one world, so answering differently here
|
|
123
|
+
* would let dsh fence a bash write and wave an identical `ctx.fs`
|
|
124
|
+
* write straight through.
|
|
125
|
+
*/
|
|
126
|
+
get sandboxMode() {
|
|
127
|
+
return this.ctx.mirage.vfsOnly ? "workspace-write" : void 0;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Refuse a mutation the call's sandbox policy does not allow.
|
|
131
|
+
*
|
|
132
|
+
* `workspaceRoot` is deliberately not consulted: it is a directory on
|
|
133
|
+
* the harness's own machine, so containment against it says nothing
|
|
134
|
+
* about this world. The mounts and their modes are the boundary, and
|
|
135
|
+
* `read-only` is the one mode that narrows them further. Wording and
|
|
136
|
+
* code mirror `dsh-fs-sandbox`, so the tool layer renders one denial
|
|
137
|
+
* marker whichever backend refused.
|
|
138
|
+
*
|
|
139
|
+
* @param policy the per-call policy, absent for an unguarded mutation.
|
|
140
|
+
* @param displayPath the path to name in the refusal.
|
|
141
|
+
*/
|
|
142
|
+
assertMutable(policy, displayPath) {
|
|
143
|
+
if (policy?.mode !== "read-only") return;
|
|
144
|
+
throw new FsError2(
|
|
145
|
+
`cannot write "${displayPath}": file access denied under read-only mode`,
|
|
146
|
+
"FS_SANDBOX_DENIED"
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The base a relative path resolves against.
|
|
151
|
+
*
|
|
152
|
+
* dsh hands `ctx.fs` either the calling session's cwd or the sandbox
|
|
153
|
+
* policy's workspace root, and both are directories on the harness's
|
|
154
|
+
* own machine that name nothing here. Resolving `notes.txt` against
|
|
155
|
+
* one yields `/Users/.../notes.txt`, which every read then reports as
|
|
156
|
+
* absent. So a base that is not a directory in this world falls back
|
|
157
|
+
* to the configured one, the same rule the shell executor applies to
|
|
158
|
+
* a workdir.
|
|
159
|
+
*
|
|
160
|
+
* An absolute path ignores its base, so it never pays for the probe.
|
|
161
|
+
*
|
|
162
|
+
* @param path the path being resolved.
|
|
163
|
+
* @param cwd the caller's base, if any.
|
|
164
|
+
* @returns the base to resolve against.
|
|
165
|
+
*/
|
|
166
|
+
async resolveBase(path, cwd) {
|
|
167
|
+
if (cwd === void 0 || posix.isAbsolute(path)) return this.cwd;
|
|
168
|
+
const ws = await this.ctx.mirage.ready;
|
|
169
|
+
return await ws.fs.isDir(cwd) ? cwd : this.cwd;
|
|
170
|
+
}
|
|
171
|
+
normalize(path, base) {
|
|
172
|
+
return posix.resolve(base, path);
|
|
108
173
|
}
|
|
109
174
|
follow(path) {
|
|
110
175
|
const links = this.links;
|
|
@@ -132,7 +197,7 @@ var MirageFileSystem = class extends FileSystem {
|
|
|
132
197
|
async resolve(path, opts) {
|
|
133
198
|
assertNotAborted(opts?.signal, "resolve");
|
|
134
199
|
await this.ops(opts?.signal, "resolve");
|
|
135
|
-
const followed = this.follow(this.normalize(path, opts?.cwd));
|
|
200
|
+
const followed = this.follow(this.normalize(path, await this.resolveBase(path, opts?.cwd)));
|
|
136
201
|
return { targetKey: FsTargetKey(followed), displayPath: followed };
|
|
137
202
|
}
|
|
138
203
|
processPath(target) {
|
|
@@ -168,7 +233,7 @@ var MirageFileSystem = class extends FileSystem {
|
|
|
168
233
|
async lstat(path, opts, signal) {
|
|
169
234
|
assertNotAborted(signal, "lstat");
|
|
170
235
|
await this.ops(signal, "lstat");
|
|
171
|
-
const normalized = this.normalize(path, opts?.cwd);
|
|
236
|
+
const normalized = this.normalize(path, await this.resolveBase(path, opts?.cwd));
|
|
172
237
|
const parentFollowed = normalized === "/" ? "/" : posix.join(this.follow(posix.dirname(normalized)), posix.basename(normalized));
|
|
173
238
|
const links = this.links;
|
|
174
239
|
if (links?.isLink(parentFollowed) === true) {
|
|
@@ -207,6 +272,30 @@ var MirageFileSystem = class extends FileSystem {
|
|
|
207
272
|
const text = await this.readText(target, signal);
|
|
208
273
|
return singleChunk(text);
|
|
209
274
|
}
|
|
275
|
+
async readBytes(target, signal, maxBytes) {
|
|
276
|
+
assertNotAborted(signal, "read");
|
|
277
|
+
const info = await this.stat(target, signal);
|
|
278
|
+
if (info !== void 0 && info.type !== "file") {
|
|
279
|
+
throw new FsError2(
|
|
280
|
+
`cannot read "${target.displayPath}": not a regular file`,
|
|
281
|
+
"FS_NOT_REGULAR_FILE"
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
if (info?.size !== void 0 && info.size > maxBytes) {
|
|
285
|
+
throw tooLarge(target.displayPath, maxBytes, info.size);
|
|
286
|
+
}
|
|
287
|
+
const key = String(target.targetKey);
|
|
288
|
+
let bytes;
|
|
289
|
+
try {
|
|
290
|
+
bytes = await (await this.ops(signal, "read")).readFile(key, { size: maxBytes + 1 });
|
|
291
|
+
} catch (err) {
|
|
292
|
+
throw mapMirageError(err, "read", target.displayPath);
|
|
293
|
+
}
|
|
294
|
+
if (bytes.byteLength > maxBytes) {
|
|
295
|
+
throw tooLarge(target.displayPath, maxBytes);
|
|
296
|
+
}
|
|
297
|
+
return bytes;
|
|
298
|
+
}
|
|
210
299
|
async listDir(target, signal) {
|
|
211
300
|
assertNotAborted(signal, "list");
|
|
212
301
|
const key = String(target.targetKey);
|
|
@@ -241,11 +330,12 @@ var MirageFileSystem = class extends FileSystem {
|
|
|
241
330
|
}
|
|
242
331
|
const entries = [];
|
|
243
332
|
for (const name of [...names].sort(compareCodePoints)) {
|
|
244
|
-
|
|
333
|
+
assertNotAborted(signal, "list");
|
|
334
|
+
entries.push(await this.dirEntry(key, name, signal));
|
|
245
335
|
}
|
|
246
336
|
return entries;
|
|
247
337
|
}
|
|
248
|
-
async dirEntry(parentKey, name) {
|
|
338
|
+
async dirEntry(parentKey, name, signal) {
|
|
249
339
|
const childPath = parentKey === "/" ? `/${name}` : `${parentKey}/${name}`;
|
|
250
340
|
let followed;
|
|
251
341
|
try {
|
|
@@ -260,8 +350,9 @@ var MirageFileSystem = class extends FileSystem {
|
|
|
260
350
|
const target = { targetKey: FsTargetKey(followed), displayPath: childPath };
|
|
261
351
|
let stat;
|
|
262
352
|
try {
|
|
263
|
-
stat = await (await this.ops()).stat(followed);
|
|
264
|
-
} catch {
|
|
353
|
+
stat = await (await this.ops(signal, "list")).stat(followed);
|
|
354
|
+
} catch (err) {
|
|
355
|
+
if (err instanceof FsError2 && err.code === "FS_ABORTED") throw err;
|
|
265
356
|
return { name, type: "other", target };
|
|
266
357
|
}
|
|
267
358
|
return {
|
|
@@ -272,9 +363,10 @@ var MirageFileSystem = class extends FileSystem {
|
|
|
272
363
|
...stat.size !== null ? { size: stat.size } : {}
|
|
273
364
|
};
|
|
274
365
|
}
|
|
275
|
-
async writeText(target, content, expected, signal) {
|
|
366
|
+
async writeText(target, content, expected, signal, sandboxPolicy) {
|
|
276
367
|
return this.withLock(target.targetKey, async () => {
|
|
277
368
|
assertNotAborted(signal, "write");
|
|
369
|
+
this.assertMutable(sandboxPolicy, target.displayPath);
|
|
278
370
|
const key = String(target.targetKey);
|
|
279
371
|
const existing = await this.stat(target, signal);
|
|
280
372
|
if (existing !== void 0 && existing.type !== "file") {
|
|
@@ -334,9 +426,10 @@ var MirageFileSystem = class extends FileSystem {
|
|
|
334
426
|
const after = await this.stat(target);
|
|
335
427
|
return after?.version ?? FsVersion(`missing:${String(target.targetKey)}`);
|
|
336
428
|
}
|
|
337
|
-
async editText(target, edit, expected, signal) {
|
|
429
|
+
async editText(target, edit, expected, signal, sandboxPolicy) {
|
|
338
430
|
return this.withLock(target.targetKey, async () => {
|
|
339
431
|
assertNotAborted(signal, "edit");
|
|
432
|
+
this.assertMutable(sandboxPolicy, target.displayPath);
|
|
340
433
|
const key = String(target.targetKey);
|
|
341
434
|
const existing = await this.stat(target, signal);
|
|
342
435
|
if (existing === void 0) {
|
|
@@ -389,4 +482,4 @@ var MirageFileSystem = class extends FileSystem {
|
|
|
389
482
|
export {
|
|
390
483
|
MirageFileSystem
|
|
391
484
|
};
|
|
392
|
-
//# sourceMappingURL=chunk-
|
|
485
|
+
//# sourceMappingURL=chunk-M4JOF35U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fs.ts","../src/errors.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { Buffer } from 'node:buffer'\nimport { posix } from 'node:path'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { FileSystem, FsError, FsTargetKey, FsVersion } from '@deepseek-ai/dsh-fs'\nimport type {\n FsDirEntry,\n FsEditOutcome,\n FsEditRequest,\n FsInfo,\n FsPathInfo,\n FsTarget,\n FsWriteIntent,\n FsWriteOutcome,\n} from '@deepseek-ai/dsh-fs'\nimport type { Ops } from '@struktoai/mirage-core/ops/ops'\nimport { FileType } from '@struktoai/mirage-core/types'\nimport type { FileStat } from '@struktoai/mirage-core/types'\nimport { isMissingPath } from '@struktoai/mirage-core/utils/errors'\nimport { compareCodePoints } from '@struktoai/mirage-core/utils/sort'\nimport { assertNotAborted, mapMirageError } from './errors.ts'\nimport {\n applyLiteralEdit,\n decodeStrictText,\n detectsCrlf,\n normalizeLineEndings,\n restoreLineEndings,\n} from './text.ts'\nimport type {} from './service.ts'\n\ntype LinksSeam = NonNullable<Ops['links']>\n\n// Read off the seam's own signature rather than imported: the policy type\n// lives in `@deepseek-ai/dsh-sandbox`, which reaches this package only as a\n// transitive dependency of dsh-fs, and naming a fourth exact-pinned peer to\n// spell one parameter would couple the adapter to a package it never calls.\ntype SandboxPolicy = Parameters<FileSystem['writeText']>[4]\n\nconst DEFAULT_DIFF_BASIS_MAX_BYTES = 10 * 1024 * 1024\n\n/** Configuration for the mirage filesystem backend. */\nexport interface MirageFsConfig {\n /** Virtual base directory for relative paths. Defaults to `/`. */\n cwd?: string\n /** Exclusive byte limit on each overwrite-diff side. Defaults to 10 MiB. */\n diffBasisMaxBytes?: number\n}\n\n// The freshness token behind FsVersion. Backends that report a fingerprint\n// or revision get a content-derived token; the rest fall back to metadata\n// (modified + size), and a backend reporting neither yields a constant, so\n// stale guards degrade to always-fresh there instead of always-stale.\nfunction versionOf(stat: FileStat): FsVersion {\n if (stat.fingerprint !== null) return FsVersion(`fp:${stat.fingerprint}`)\n if (stat.revision !== null) return FsVersion(`rev:${stat.revision}`)\n if (stat.modified !== null || stat.size !== null) {\n return FsVersion(`meta:${stat.modified ?? ''}:${String(stat.size ?? '')}`)\n }\n return FsVersion('unversioned')\n}\n\nfunction typeOf(stat: FileStat): FsInfo['type'] {\n switch (stat.type) {\n case FileType.DIRECTORY:\n return 'directory'\n case FileType.SYMLINK:\n return 'other'\n default:\n return 'file'\n }\n}\n\nasync function* singleChunk(text: string): AsyncGenerator<string, void, void> {\n yield await Promise.resolve(text)\n}\n\nfunction tooLarge(displayPath: string, maxBytes: number, size?: number): FsError {\n const found = size === undefined ? '' : `${String(size)} bytes `\n return new FsError(\n `cannot read \"${displayPath}\": ${found}exceeds the ${String(maxBytes)} byte cap`,\n 'FS_TOO_LARGE',\n )\n}\n\n/**\n * Mirage-backed implementation of `ctx.fs`. Targets are canonical virtual\n * paths (namespace symlinks followed), every operation walks the workspace\n * op door — session grants, admission policies, cache read-through and\n * post-write invalidation all fire exactly as they do for a shell command —\n * and `processPath` answers in the same virtual path space the mirage shell\n * executes in, so the two providers share one execution world.\n *\n * One limit worth stating: mirage's op facade takes no `AbortSignal`, so\n * cancellation is honored at this adapter's own boundaries (before a\n * dispatch, between listing entries) and not inside a single op. A long\n * read from a remote backend therefore runs to completion after the\n * signal fires, and the caller learns of the abort when it returns.\n */\nexport class MirageFileSystem extends FileSystem {\n static readonly inject = ['mirage']\n\n private fsOps: Ops | null = null\n private readonly cwd: string\n private readonly diffBasisMaxBytes: number\n // Per-targetKey tail promise: serializes mutating ops so the\n // read -> guard -> write window cannot interleave (one concurrent writer\n // wins, the rest observe the new version and reject as stale).\n private readonly locks = new Map<string, Promise<void>>()\n\n constructor(ctx: Context, config: MirageFsConfig = {}) {\n super(ctx)\n this.cwd = config.cwd ?? '/'\n this.diffBasisMaxBytes = config.diffBasisMaxBytes ?? DEFAULT_DIFF_BASIS_MAX_BYTES\n }\n\n // The workspace may still be building (declarative mounts resolve\n // asynchronously), so every entry point awaits the service's `ready`\n // once and caches the op door. The caller's signal can fire during\n // that wait, after its entry assertion passed, so it is asserted\n // again here, before the op it guards dispatches.\n private async ops(signal?: AbortSignal, operation = 'ready'): Promise<Ops> {\n this.fsOps ??= (await this.ctx.mirage.ready).fs\n assertNotAborted(signal, operation)\n return this.fsOps\n }\n\n private get links(): LinksSeam | null {\n if (this.fsOps === null) {\n throw new Error('mirage: filesystem used before the workspace is ready')\n }\n return this.fsOps.links\n }\n\n /**\n * The same confinement claim `MirageShellExecutor` makes, off the same\n * fact and for the same reason: with every runtime reaching only the\n * vfs, a mutation cannot land anywhere but a mount, under its mode.\n *\n * The two seams sit over one world, so answering differently here\n * would let dsh fence a bash write and wave an identical `ctx.fs`\n * write straight through.\n */\n override get sandboxMode(): FileSystem['sandboxMode'] {\n return this.ctx.mirage.vfsOnly ? 'workspace-write' : undefined\n }\n\n /**\n * Refuse a mutation the call's sandbox policy does not allow.\n *\n * `workspaceRoot` is deliberately not consulted: it is a directory on\n * the harness's own machine, so containment against it says nothing\n * about this world. The mounts and their modes are the boundary, and\n * `read-only` is the one mode that narrows them further. Wording and\n * code mirror `dsh-fs-sandbox`, so the tool layer renders one denial\n * marker whichever backend refused.\n *\n * @param policy the per-call policy, absent for an unguarded mutation.\n * @param displayPath the path to name in the refusal.\n */\n private assertMutable(policy: SandboxPolicy, displayPath: string): void {\n if (policy?.mode !== 'read-only') return\n throw new FsError(\n `cannot write \"${displayPath}\": file access denied under read-only mode`,\n 'FS_SANDBOX_DENIED',\n )\n }\n\n /**\n * The base a relative path resolves against.\n *\n * dsh hands `ctx.fs` either the calling session's cwd or the sandbox\n * policy's workspace root, and both are directories on the harness's\n * own machine that name nothing here. Resolving `notes.txt` against\n * one yields `/Users/.../notes.txt`, which every read then reports as\n * absent. So a base that is not a directory in this world falls back\n * to the configured one, the same rule the shell executor applies to\n * a workdir.\n *\n * An absolute path ignores its base, so it never pays for the probe.\n *\n * @param path the path being resolved.\n * @param cwd the caller's base, if any.\n * @returns the base to resolve against.\n */\n private async resolveBase(path: string, cwd: string | undefined): Promise<string> {\n if (cwd === undefined || posix.isAbsolute(path)) return this.cwd\n const ws = await this.ctx.mirage.ready\n return (await ws.fs.isDir(cwd)) ? cwd : this.cwd\n }\n\n private normalize(path: string, base: string): string {\n return posix.resolve(base, path)\n }\n\n private follow(path: string): string {\n const links = this.links\n if (links === null) return path\n try {\n return links.follow(path)\n } catch (err) {\n throw mapMirageError(err, 'resolve', path)\n }\n }\n\n private withLock<T>(key: FsTargetKey, body: () => Promise<T>): Promise<T> {\n const mapKey = String(key)\n const previous = this.locks.get(mapKey) ?? Promise.resolve()\n const next = previous.then(body, body)\n // The stored tail is void (an outcome would pin whole file contents in\n // the map) and drops on settlement unless a newer op queued behind it.\n const tail = next.then(\n () => undefined,\n () => undefined,\n )\n this.locks.set(mapKey, tail)\n void tail.then(() => {\n if (this.locks.get(mapKey) === tail) this.locks.delete(mapKey)\n })\n return next\n }\n\n async resolve(path: string, opts?: { cwd?: string; signal?: AbortSignal }): Promise<FsTarget> {\n assertNotAborted(opts?.signal, 'resolve')\n await this.ops(opts?.signal, 'resolve')\n const followed = this.follow(this.normalize(path, await this.resolveBase(path, opts?.cwd)))\n return { targetKey: FsTargetKey(followed), displayPath: followed }\n }\n\n processPath(target: FsTarget): string {\n return String(target.targetKey)\n }\n\n fileUrl(target: FsTarget): string {\n const encoded = String(target.targetKey).split('/').map(encodeURIComponent).join('/')\n return `file://${encoded}`\n }\n\n contains(parent: FsTarget, child: FsTarget): boolean {\n const parentKey = String(parent.targetKey)\n const childKey = String(child.targetKey)\n if (parentKey === childKey) return true\n const prefix = parentKey === '/' ? '/' : `${parentKey}/`\n return childKey.startsWith(prefix)\n }\n\n async stat(target: FsTarget, signal?: AbortSignal): Promise<FsInfo | undefined> {\n assertNotAborted(signal, 'stat')\n const key = String(target.targetKey)\n let stat: FileStat\n try {\n stat = await (await this.ops(signal, 'stat')).stat(key)\n } catch (err) {\n if (isMissingPath(err)) return undefined\n throw mapMirageError(err, 'stat', target.displayPath)\n }\n return {\n version: versionOf(stat),\n type: typeOf(stat),\n ...(stat.size !== null ? { size: stat.size } : {}),\n }\n }\n\n async lstat(\n path: string,\n opts?: { cwd?: string },\n signal?: AbortSignal,\n ): Promise<FsPathInfo | undefined> {\n assertNotAborted(signal, 'lstat')\n await this.ops(signal, 'lstat')\n const normalized = this.normalize(path, await this.resolveBase(path, opts?.cwd))\n // Follow every component except the last: the probe is about the path\n // entry itself, so a link at the leaf must report as one.\n const parentFollowed =\n normalized === '/'\n ? '/'\n : posix.join(this.follow(posix.dirname(normalized)), posix.basename(normalized))\n const links = this.links\n if (links?.isLink(parentFollowed) === true) {\n const linkTarget = links.readlink(parentFollowed) ?? ''\n return {\n version: FsVersion(`link:${linkTarget}`),\n type: 'symlink',\n size: new TextEncoder().encode(linkTarget).byteLength,\n }\n }\n let stat: FileStat\n try {\n stat = await (await this.ops(signal, 'lstat')).stat(parentFollowed)\n } catch (err) {\n if (isMissingPath(err)) return undefined\n throw mapMirageError(err, 'lstat', normalized)\n }\n return {\n version: versionOf(stat),\n type: typeOf(stat) === 'directory' ? 'directory' : typeOf(stat),\n ...(stat.size !== null ? { size: stat.size } : {}),\n }\n }\n\n async readText(target: FsTarget, signal?: AbortSignal): Promise<string> {\n assertNotAborted(signal, 'read')\n const key = String(target.targetKey)\n let bytes: Uint8Array\n try {\n bytes = await (await this.ops(signal, 'read')).readFile(key)\n } catch (err) {\n throw mapMirageError(err, 'read', target.displayPath)\n }\n return decodeStrictText(bytes, target.displayPath)\n }\n\n async streamText(target: FsTarget, signal?: AbortSignal): Promise<AsyncIterable<string>> {\n // mirage reads land as one rendered buffer, so streaming is a single\n // chunk with readText's exact text semantics.\n const text = await this.readText(target, signal)\n return singleChunk(text)\n }\n\n async readBytes(\n target: FsTarget,\n signal: AbortSignal | undefined,\n maxBytes: number,\n ): Promise<Uint8Array> {\n assertNotAborted(signal, 'read')\n const info = await this.stat(target, signal)\n if (info !== undefined && info.type !== 'file') {\n // A backend read of a directory key surfaces as a missing path, which\n // would report a path that plainly exists as absent.\n throw new FsError(\n `cannot read \"${target.displayPath}\": not a regular file`,\n 'FS_NOT_REGULAR_FILE',\n )\n }\n if (info?.size !== undefined && info.size > maxBytes) {\n throw tooLarge(target.displayPath, maxBytes, info.size)\n }\n // Ask for one byte past the cap rather than the whole object: a backend\n // with a native range fetches only that window, and a full-length answer\n // is itself the proof the file is over the cap, which is what a mount\n // reporting no size (most API mounts) has no other way to establish.\n const key = String(target.targetKey)\n let bytes: Uint8Array\n try {\n bytes = await (await this.ops(signal, 'read')).readFile(key, { size: maxBytes + 1 })\n } catch (err) {\n throw mapMirageError(err, 'read', target.displayPath)\n }\n if (bytes.byteLength > maxBytes) {\n throw tooLarge(target.displayPath, maxBytes)\n }\n return bytes\n }\n\n async listDir(target: FsTarget, signal?: AbortSignal): Promise<FsDirEntry[]> {\n assertNotAborted(signal, 'list')\n const key = String(target.targetKey)\n const info = await this.stat(target, signal)\n if (info === undefined) {\n throw new FsError(\n `cannot list \"${target.displayPath}\": no such file or directory`,\n 'FS_NOT_FOUND',\n )\n }\n if (info.type !== 'directory') {\n throw new FsError(`cannot list \"${target.displayPath}\": not a directory`, 'FS_NOT_DIRECTORY')\n }\n let children: string[]\n try {\n children = await (await this.ops(signal, 'list')).readdir(key)\n } catch (err) {\n throw mapMirageError(err, 'list', target.displayPath)\n }\n const names = new Set<string>()\n for (const childPath of children) {\n names.add(posix.basename(childPath))\n }\n // Namespace symlinks live above every backend, so a listing merges\n // them in here exactly as mirage's own ls does.\n const links = this.links\n if (links !== null) {\n const base = key === '/' ? '/' : `${key}/`\n for (const linkPath of links.symlinkTargets().keys()) {\n if (linkPath.startsWith(base) && !linkPath.slice(base.length).includes('/')) {\n names.add(linkPath.slice(base.length))\n }\n }\n }\n const entries: FsDirEntry[] = []\n for (const name of [...names].sort(compareCodePoints)) {\n // Per entry, not just at the door: a listing is one classification\n // round trip per child on a backend the readdir did not warm, and\n // a caller that gave up should stop paying for them.\n assertNotAborted(signal, 'list')\n entries.push(await this.dirEntry(key, name, signal))\n }\n return entries\n }\n\n private async dirEntry(\n parentKey: string,\n name: string,\n signal?: AbortSignal,\n ): Promise<FsDirEntry> {\n const childPath = parentKey === '/' ? `/${name}` : `${parentKey}/${name}`\n let followed: string\n try {\n followed = this.follow(childPath)\n } catch {\n // A cyclic link must not reject the whole listing; it lists as an\n // entry of unknown kind keyed on its own path.\n return {\n name,\n type: 'other',\n target: { targetKey: FsTargetKey(childPath), displayPath: childPath },\n }\n }\n const target: FsTarget = { targetKey: FsTargetKey(followed), displayPath: childPath }\n let stat: FileStat\n try {\n stat = await (await this.ops(signal, 'list')).stat(followed)\n } catch (err) {\n // An abort is the caller withdrawing, not a child this listing\n // failed to classify, so it ends the walk instead of landing as\n // one more entry of unknown kind.\n if (err instanceof FsError && err.code === 'FS_ABORTED') throw err\n // A child the listing named but stat cannot classify (a broken link,\n // a race with a delete) still lists, as an entry of unknown kind.\n return { name, type: 'other', target }\n }\n return {\n name,\n type: typeOf(stat),\n target,\n version: versionOf(stat),\n ...(stat.size !== null ? { size: stat.size } : {}),\n }\n }\n\n async writeText(\n target: FsTarget,\n content: string,\n expected?: FsWriteIntent,\n signal?: AbortSignal,\n sandboxPolicy?: SandboxPolicy,\n ): Promise<FsWriteOutcome> {\n return this.withLock(target.targetKey, async () => {\n assertNotAborted(signal, 'write')\n this.assertMutable(sandboxPolicy, target.displayPath)\n const key = String(target.targetKey)\n const existing = await this.stat(target, signal)\n if (existing !== undefined && existing.type !== 'file') {\n throw new FsError(\n `cannot write \"${target.displayPath}\": not a regular file`,\n 'FS_NOT_REGULAR_FILE',\n )\n }\n if (expected?.kind === 'createIfAbsent' && existing !== undefined) {\n throw new FsError(\n `cannot write \"${target.displayPath}\": file already exists`,\n 'FS_NOT_OBSERVED',\n )\n }\n if (expected?.kind === 'replaceIfVersion') {\n if (existing?.version !== expected.version) {\n throw new FsError(\n `cannot write \"${target.displayPath}\": file changed since it was read`,\n 'FS_STALE_VERSION',\n )\n }\n }\n const before = existing === undefined ? null : await this.diffBasis(target, content)\n const crlf = before !== null && detectsCrlf(before)\n try {\n await (\n await this.ops(signal, 'write')\n ).writeFile(key, restoreLineEndings(normalizeLineEndings(content), crlf))\n } catch (err) {\n throw mapMirageError(err, 'write', target.displayPath)\n }\n return {\n operation: existing === undefined ? ('create' as const) : ('update' as const),\n version: await this.versionAfterWrite(target),\n before: before === null ? null : normalizeLineEndings(before),\n after: normalizeLineEndings(content),\n }\n })\n }\n\n // The overwrite-diff basis: the prior content when it is text and both\n // sides fit the exclusive limit, else null (dsh renders a whole-file\n // diff then). Never fails the write itself.\n private async diffBasis(target: FsTarget, content: string): Promise<string | null> {\n if (Buffer.byteLength(content, 'utf8') >= this.diffBasisMaxBytes) return null\n let bytes: Uint8Array\n try {\n bytes = await (await this.ops()).readFile(String(target.targetKey))\n } catch {\n return null\n }\n if (bytes.byteLength >= this.diffBasisMaxBytes) return null\n try {\n return decodeStrictText(bytes, target.displayPath)\n } catch {\n return null\n }\n }\n\n private async versionAfterWrite(target: FsTarget): Promise<FsVersion> {\n const after = await this.stat(target)\n return after?.version ?? FsVersion(`missing:${String(target.targetKey)}`)\n }\n\n async editText(\n target: FsTarget,\n edit: FsEditRequest,\n expected?: { version: FsVersion },\n signal?: AbortSignal,\n sandboxPolicy?: SandboxPolicy,\n ): Promise<FsEditOutcome> {\n return this.withLock(target.targetKey, async () => {\n assertNotAborted(signal, 'edit')\n this.assertMutable(sandboxPolicy, target.displayPath)\n const key = String(target.targetKey)\n const existing = await this.stat(target, signal)\n // Stale guard before literal matching: an edit based on an old read\n // reports FS_STALE_VERSION, not a match failure against newer content.\n if (existing === undefined) {\n throw new FsError(\n `cannot edit \"${target.displayPath}\": file changed since it was read`,\n 'FS_STALE_VERSION',\n )\n }\n if (existing.type !== 'file') {\n throw new FsError(\n `cannot edit \"${target.displayPath}\": not a regular file`,\n 'FS_NOT_REGULAR_FILE',\n )\n }\n if (expected !== undefined && existing.version !== expected.version) {\n throw new FsError(\n `cannot edit \"${target.displayPath}\": file changed since it was read`,\n 'FS_STALE_VERSION',\n )\n }\n let bytes: Uint8Array\n try {\n bytes = await (await this.ops(signal, 'edit')).readFile(key)\n } catch (err) {\n throw mapMirageError(err, 'edit', target.displayPath)\n }\n const raw = decodeStrictText(bytes, target.displayPath)\n const original = normalizeLineEndings(raw)\n const edited = applyLiteralEdit(\n original,\n normalizeLineEndings(edit.oldString),\n normalizeLineEndings(edit.newString),\n edit.replaceAll,\n target.displayPath,\n )\n try {\n await (\n await this.ops(signal, 'edit')\n ).writeFile(key, restoreLineEndings(edited, detectsCrlf(raw)))\n } catch (err) {\n throw mapMirageError(err, 'edit', target.displayPath)\n }\n return {\n version: await this.versionAfterWrite(target),\n before: original,\n after: edited,\n }\n })\n }\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { FsError } from '@deepseek-ai/dsh-fs'\nimport type { FsErrorCode } from '@deepseek-ai/dsh-fs'\nimport { isMissingPath } from '@struktoai/mirage-core/utils/errors'\n\nexport function assertNotAborted(signal: AbortSignal | undefined, operation: string): void {\n if (signal?.aborted === true) {\n throw new FsError(`${operation} aborted`, 'FS_ABORTED')\n }\n}\n\nfunction codeOf(err: unknown): string | null {\n if (err === null || typeof err !== 'object') return null\n const stamped = err as { code?: unknown }\n return typeof stamped.code === 'string' ? stamped.code : null\n}\n\n// mirage stamps POSIX codes on its errors (ENOENT, EISDIR, ENOTDIR, EACCES,\n// EROFS, EXDEV; PolicyDenied carries EACCES too), so the dsh taxonomy is\n// derived from the stamp rather than from message sniffing or class checks\n// that would couple this adapter to mirage internals.\nfunction codeFor(err: unknown): FsErrorCode {\n if (isMissingPath(err)) return 'FS_NOT_FOUND'\n // An admission policy refused the op at the door: the session's\n // permission document, or a code policy registered beside it. EACCES is\n // too coarse to say so alone, since a plain mount-mode refusal carries\n // it too, and the two want different answers — a mode refusal is the\n // shape of this world, while a policy refusal is a confinement the call\n // may be entitled to escalate past. So it maps to the sandbox code,\n // which is what makes dsh's tool layer attach the escalation hint\n // (`FsSandboxController.mapError` keys on exactly this code) and render\n // the same denial marker bash gets for a refused command.\n //\n // Matched on `name`, like the AbortError case below and for the same\n // reason: core's PolicyDenied documents that name as the discriminator\n // for \"handlers that special-case mount-mode refusals\", and matching it\n // needs no import of a class this adapter never constructs.\n if (err instanceof Error && err.name === 'PolicyDenied') return 'FS_SANDBOX_DENIED'\n switch (codeOf(err)) {\n case 'EISDIR':\n return 'FS_NOT_REGULAR_FILE'\n case 'ENOTDIR':\n return 'FS_NOT_DIRECTORY'\n case 'EACCES':\n case 'EPERM':\n case 'EROFS':\n return 'FS_PERMISSION_DENIED'\n default:\n return 'FS_IO_ERROR'\n }\n}\n\nexport function mapMirageError(err: unknown, operation: string, displayPath: string): FsError {\n if (err instanceof FsError) return err\n // Matched by name, not by class: mirage's own executor throws a\n // `DOMException`, but an aborted fetch or a backend SDK may throw a\n // plain `Error` named the same, and reporting that as FS_IO_ERROR\n // would tell the caller its own cancellation was a backend failure.\n if (err instanceof Error && err.name === 'AbortError') {\n return new FsError(`${operation} aborted`, 'FS_ABORTED', { cause: err })\n }\n const message = err instanceof Error ? err.message : String(err)\n return new FsError(`cannot ${operation} \"${displayPath}\": ${message}`, codeFor(err), {\n cause: err,\n })\n}\n"],"mappings":"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","names":["FsError","isMissingPath","FsError","isMissingPath"]}
|