dsh-wsl-workspace 0.4.3 → 0.7.2
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/README.md +131 -3
- package/README.zh.md +101 -2
- package/TESTING.md +32 -6
- package/lib/client.js +44 -6
- package/lib/client.js.map +1 -1
- package/lib/fs.js +135 -4
- package/lib/fs.js.map +1 -1
- package/lib/index.js +508 -83
- package/lib/index.js.map +1 -1
- package/lib/links-BQxdJOMy.js +66 -0
- package/lib/links-BQxdJOMy.js.map +1 -0
- package/lib/shell.js +2 -2
- package/lib/{wsl-6VcgOvF9.js → wsl-CECXiGZH.js} +15 -2
- package/lib/{wsl-6VcgOvF9.js.map → wsl-CECXiGZH.js.map} +1 -1
- package/lib/{wsl-credentials-B6wIXsKt.js → wsl-credentials-BJXc9tfi.js} +2 -2
- package/lib/{wsl-credentials-B6wIXsKt.js.map → wsl-credentials-BJXc9tfi.js.map} +1 -1
- package/lib/wsl-jobs.js +139 -0
- package/lib/wsl-jobs.js.map +1 -0
- package/lib/wsl-relay.js +64 -0
- package/lib/wsl-relay.js.map +1 -0
- package/lib/wsl-sandbox.js +27 -0
- package/lib/wsl-sandbox.js.map +1 -0
- package/lib/wsl-search.js +957 -0
- package/lib/wsl-search.js.map +1 -0
- package/package.json +24 -4
- package/src/client/help.tsx +11 -0
- package/src/client/locales.ts +14 -6
- package/src/client/styles.ts +9 -0
- package/src/fs.ts +210 -6
- package/src/host/variants.ts +211 -24
- package/src/host/wsl-jobs.ts +229 -0
- package/src/host/wsl-relay.ts +89 -0
- package/src/host/wsl-sandbox.ts +47 -0
- package/src/host/wsl-search.ts +1166 -0
- package/src/host/wsl-skills.ts +353 -66
- package/src/index.ts +120 -6
- package/src/shared/links.ts +90 -0
package/lib/fs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.js","names":[],"sources":["../src/fs.ts"],"sourcesContent":["/**\n * WSL Service Provider for the `ctx.fs` capability seam. Backed by the host\n * filesystem over the `\\\\wsl.localhost\\<distro>\\…` 9P share — zero install\n * inside the distribution — while every model/UI-facing path is the Linux\n * path a WSL process would open (`processPath`, `displayPath`, `fileUrl`).\n * Reuses `LocalFileSystem`'s mechanics (realpath identity, atomic writes,\n * per-target locks, version guards) unchanged, because those operate on the\n * UNC path Node can open directly.\n *\n * Both UNC paths and Linux absolute paths resolve; Windows drive paths\n * resolve through their `/mnt/<drive>` form, so a WSL-composed session can\n * still touch the Windows filesystem coherently.\n * @module dsh-wsl-workspace/fs\n */\n\nimport { Context } from '@deepseek-ai/cordis'\nimport z from '@deepseek-ai/schemastery'\nimport { AsyncLocalStorage } from 'node:async_hooks'\nimport { link, lstat, rename } from 'node:fs/promises'\nimport { FsError } from '@deepseek-ai/dsh-fs'\nimport type { FsPathInfo, FsTarget } from '@deepseek-ai/dsh-fs'\nimport { LocalFileSystem } from '@deepseek-ai/dsh-fs-local'\nimport {\n isAbsoluteLinuxPath,\n joinUnc,\n mntToWindowsPath,\n parseWslUnc,\n windowsToMntPath,\n} from './shared/paths.ts'\nimport { defaultDistroSync } from './shared/wsl.ts'\n\n/** Plugin config. `cwd`/`distro` are optional because UNC workdirs carry both. */\nexport interface Config {\n /** Base directory for relative paths without a per-call cwd (UNC or Linux). */\n cwd?: string\n /** Default distribution for Linux-absolute paths without a UNC cwd. */\n distro?: string\n /** Exclusive UTF-8 byte limit on each overwrite-diff side (see fs-local). */\n diffBasisMaxBytes?: number\n}\n\n/** One translated coordinate: the input the local backend opens plus its cwd. */\ninterface Translated {\n /** Absolute path to hand to the local backend (UNC or Windows drive). */\n input: string\n /** Absolute Windows-side base for relative inputs (UNC or Windows drive). */\n cwd: string\n}\n\ninterface ToolExecution {\n agent?: { session: { header: { cwd?: string } } }\n}\n\n/**\n * The WSL filesystem backend. Identity keys are canonical UNC paths; the\n * Linux form is derived on demand, so both worlds stay in sync across\n * aliases and symlinks.\n */\nexport class WslFileSystem extends LocalFileSystem {\n static override Config: z<Config> = z.object({\n cwd: z.string(),\n distro: z.string(),\n diffBasisMaxBytes: z.number().default(10 * 1024 * 1024),\n })\n\n private readonly distro: string | undefined\n private readonly executionCwd = new AsyncLocalStorage<string | undefined>()\n\n constructor(ctx: Context, config: Config) {\n // schemastery fills the defaults before construction; the parent validates\n // `diffBasisMaxBytes` and stores the resolved shape.\n super(ctx, config)\n this.distro = config.distro\n ctx.on('tools/execute', (exec: ToolExecution, next: () => unknown) => (\n this.executionCwd.run(exec.agent?.session.header.cwd, next)\n ))\n // The 9P/drvfs substrate has no hard links and no Win32 security semantics:\n // replace the atomic-publication boundaries the parent's fsio defaults to.\n this.internals = {\n linkFile: WslFileSystem.publishNoReplace,\n replaceFile: WslFileSystem.replaceOverWrite,\n copyFileDacl: WslFileSystem.skipDaclCopy,\n }\n }\n\n /**\n * No-replace publication for filesystems without hard links. A real\n * collision (a concurrent external creator won) must still surface as the\n * original EEXIST so the guarded-create failure path classifies it; an\n * absent target falls back to rename, which on Windows publishes without\n * replacing anything. Safe against this backend's own writers because the\n * per-target lock serializes them.\n * @param tempPath - the staged file.\n * @param destPath - the destination to create.\n */\n private static async publishNoReplace(tempPath: string, destPath: string): Promise<void> {\n try {\n await link(tempPath, destPath)\n return\n } catch (error) {\n let exists = false\n try {\n await lstat(destPath)\n exists = true\n } catch {\n // Absent destination: rename publishes the staged file.\n }\n if (exists) throw error\n await rename(tempPath, destPath)\n }\n }\n\n /**\n * Security-preserving replacement boundary: Windows rename replaces an\n * existing destination atomically; no DACL preservation is needed over 9P.\n * @param destPath - the file being replaced.\n * @param tempPath - the staged replacement.\n */\n private static async replaceOverWrite(destPath: string, tempPath: string): Promise<void> {\n await rename(tempPath, destPath)\n }\n\n /** 9P files inherit their directory's DACL; nothing to preserve. */\n private static async skipDaclCopy(): Promise<void> {}\n\n /** Translate a model/plugin path into Windows-side coordinates. */\n private translate(path: string, cwd?: string): Translated {\n const unc = parseWslUnc(path)\n if (unc !== null) {\n return { input: joinUnc(unc.distro, unc.linuxPath), cwd: this.cwdOr(cwd) }\n }\n if (isAbsoluteLinuxPath(path)) {\n // /mnt/<drive>/… names the Windows filesystem inside the Linux world\n // (the dual-access path for migration): open the drive path directly so\n // both worlds stay coherent — the display stays the /mnt form.\n const win = mntToWindowsPath(path)\n if (win !== null) return { input: win, cwd: this.cwdOr(cwd) }\n return { input: joinUnc(this.distroFor(cwd), path), cwd: this.cwdOr(cwd) }\n }\n if (windowsToMntPath(path) !== null) {\n // Windows drive paths open directly; the Linux world reaches them via /mnt.\n return { input: path, cwd: this.cwdOr(cwd) }\n }\n // Relative: resolve against the caller cwd (or the configured base).\n const base = this.uncCwd(cwd)\n return { input: path, cwd: base }\n }\n\n /** A base for absolute inputs (unused by resolution, but the parent needs one). */\n private cwdOr(cwd?: string): string {\n return cwd ?? this.executionCwd.getStore() ?? this.config.cwd ?? process.cwd()\n }\n\n private uncCwd(cwd?: string): string {\n const base = cwd ?? this.executionCwd.getStore() ?? this.config.cwd\n if (base === undefined || base === '') {\n throw new FsError('wsl-fs: no cwd and no configured base for relative resolution', 'FS_IO_ERROR')\n }\n const unc = parseWslUnc(base)\n if (unc !== null) return joinUnc(unc.distro, unc.linuxPath)\n if (isAbsoluteLinuxPath(base)) return joinUnc(this.distroFor(base), base)\n if (windowsToMntPath(base) !== null) return base\n throw new FsError(`wsl-fs: cwd \"${base}\" is not in the WSL execution world`, 'FS_IO_ERROR')\n }\n\n /**\n * Resolve the distribution an absolute Linux path opens inside. The chain:\n * the caller cwd when it is a WSL UNC path, then the current tool\n * execution's session cwd, then the configured `distro`,\n * then the host's default distribution from the Lxss registry. The registry\n * fallback is reserved for calls that genuinely have no session.\n */\n private distroFor(cwd?: string): string {\n const fromCwd = parseWslUnc(cwd ?? '')\n if (fromCwd !== null) return fromCwd.distro\n const fromExecution = parseWslUnc(this.executionCwd.getStore() ?? '')\n if (fromExecution !== null) return fromExecution.distro\n const distro = this.distro\n if (distro !== undefined && distro !== '') return distro\n const fallback = defaultDistroSync()\n if (fallback !== undefined) return fallback\n throw new FsError('wsl-fs: Linux path carries no distribution and none is configured', 'FS_IO_ERROR')\n }\n\n /** The Linux display path for a resolved Windows-side path. */\n private linuxDisplay(raw: string): string {\n const unc = parseWslUnc(raw)\n if (unc !== null) return unc.linuxPath\n const mnt = windowsToMntPath(raw)\n if (mnt !== null) return mnt\n throw new FsError(`wsl-fs: resolved path \"${raw}\" is outside the WSL execution world`, 'FS_IO_ERROR')\n }\n\n override async resolve(path: string, opts?: { cwd?: string; signal?: AbortSignal }): Promise<FsTarget> {\n if (opts?.signal?.aborted) throw new FsError('resolve aborted', 'FS_ABORTED')\n const { input, cwd } = this.translate(path, opts?.cwd)\n const local = await super.resolve(input, {\n cwd,\n ...opts?.signal !== undefined ? { signal: opts.signal } : {},\n })\n return { targetKey: local.targetKey, displayPath: this.linuxDisplay(String(local.displayPath)) }\n }\n\n override processPath(target: FsTarget): string {\n const key = String(target.targetKey)\n const unc = parseWslUnc(key)\n if (unc !== null) return unc.linuxPath\n const mnt = windowsToMntPath(key)\n if (mnt !== null) return mnt\n throw new FsError(`wsl-fs: target \"${target.displayPath}\" is outside the WSL execution world`, 'FS_IO_ERROR')\n }\n\n override fileUrl(target: FsTarget): string {\n const linux = this.processPath(target)\n const encoded = linux.split('/').map(encodeURIComponent).join('/')\n return `file://${encoded}`\n }\n\n override contains(parent: FsTarget, child: FsTarget): boolean {\n const parentWorld = this.worldPath(parent)\n const childWorld = this.worldPath(child)\n if (parentWorld.distro !== childWorld.distro) return false\n const parentPath = parentWorld.linuxPath\n const childPath = childWorld.linuxPath\n if (childPath === parentPath) return true\n return parentPath === '/' ? true : childPath.startsWith(`${parentPath}/`)\n }\n\n /** One target's (distro, linuxPath) pair for containment; `undefined` distro = Windows world. */\n private worldPath(target: FsTarget): { distro: string | undefined; linuxPath: string } {\n const key = String(target.targetKey)\n const unc = parseWslUnc(key)\n if (unc !== null) return { distro: unc.distro, linuxPath: unc.linuxPath }\n const mnt = windowsToMntPath(key)\n if (mnt !== null) return { distro: undefined, linuxPath: mnt }\n throw new FsError(`wsl-fs: target \"${target.displayPath}\" is outside the WSL execution world`, 'FS_IO_ERROR')\n }\n\n override async lstat(path: string, opts?: { cwd?: string }, signal?: AbortSignal): Promise<FsPathInfo | undefined> {\n if (signal?.aborted) throw new FsError('lstat aborted', 'FS_ABORTED')\n if (path.trim().length === 0) throw new FsError('file_path must be a non-empty string', 'FS_NOT_FOUND')\n const { input, cwd } = this.translate(path, opts?.cwd)\n return super.lstat(input, { cwd }, signal)\n }\n}\n\nexport default WslFileSystem\n"],"mappings":";;;;;;;;;;;;;AA0DA,IAAa,gBAAb,MAAa,sBAAsB,gBAAgB;CACjD,OAAgB,SAAoB,EAAE,OAAO;EAC3C,KAAK,EAAE;EACP,QAAQ,EAAE;EACV,mBAAmB,EAAE,SAAS,QAAQ,KAAK,OAAO;;CAGpD,AAAiB;CACjB,AAAiB,eAAe,IAAI;CAEpC,YAAY,KAAc,QAAgB;AAGxC,QAAM,KAAK;AACX,OAAK,SAAS,OAAO;AACrB,MAAI,GAAG,kBAAkB,MAAqB,SAC5C,KAAK,aAAa,IAAI,KAAK,OAAO,QAAQ,OAAO,KAAK;AAIxD,OAAK,YAAY;GACf,UAAU,cAAc;GACxB,aAAa,cAAc;GAC3B,cAAc,cAAc;;;;;;;;;;;;;CAchC,aAAqB,iBAAiB,UAAkB,UAAiC;AACvF,MAAI;AACF,SAAM,KAAK,UAAU;AACrB;WACO,OAAO;GACd,IAAI,SAAS;AACb,OAAI;AACF,UAAM,MAAM;AACZ,aAAS;WACH;AAGR,OAAI,OAAQ,OAAM;AAClB,SAAM,OAAO,UAAU;;;;;;;;;CAU3B,aAAqB,iBAAiB,UAAkB,UAAiC;AACvF,QAAM,OAAO,UAAU;;;CAIzB,aAAqB,eAA8B;;CAGnD,AAAQ,UAAU,MAAc,KAA0B;EACxD,MAAM,MAAM,YAAY;AACxB,MAAI,QAAQ,KACV,QAAO;GAAE,OAAO,QAAQ,IAAI,QAAQ,IAAI;GAAY,KAAK,KAAK,MAAM;;AAEtE,MAAI,oBAAoB,OAAO;GAI7B,MAAM,MAAM,iBAAiB;AAC7B,OAAI,QAAQ,KAAM,QAAO;IAAE,OAAO;IAAK,KAAK,KAAK,MAAM;;AACvD,UAAO;IAAE,OAAO,QAAQ,KAAK,UAAU,MAAM;IAAO,KAAK,KAAK,MAAM;;;AAEtE,MAAI,iBAAiB,UAAU,KAE7B,QAAO;GAAE,OAAO;GAAM,KAAK,KAAK,MAAM;;EAGxC,MAAM,OAAO,KAAK,OAAO;AACzB,SAAO;GAAE,OAAO;GAAM,KAAK;;;;CAI7B,AAAQ,MAAM,KAAsB;AAClC,SAAO,OAAO,KAAK,aAAa,cAAc,KAAK,OAAO,OAAO,QAAQ;;CAG3E,AAAQ,OAAO,KAAsB;EACnC,MAAM,OAAO,OAAO,KAAK,aAAa,cAAc,KAAK,OAAO;AAChE,MAAI,SAAS,UAAa,SAAS,GACjC,OAAM,IAAI,QAAQ,iEAAiE;EAErF,MAAM,MAAM,YAAY;AACxB,MAAI,QAAQ,KAAM,QAAO,QAAQ,IAAI,QAAQ,IAAI;AACjD,MAAI,oBAAoB,MAAO,QAAO,QAAQ,KAAK,UAAU,OAAO;AACpE,MAAI,iBAAiB,UAAU,KAAM,QAAO;AAC5C,QAAM,IAAI,QAAQ,gBAAgB,KAAK,sCAAsC;;;;;;;;;CAU/E,AAAQ,UAAU,KAAsB;EACtC,MAAM,UAAU,YAAY,OAAO;AACnC,MAAI,YAAY,KAAM,QAAO,QAAQ;EACrC,MAAM,gBAAgB,YAAY,KAAK,aAAa,cAAc;AAClE,MAAI,kBAAkB,KAAM,QAAO,cAAc;EACjD,MAAM,SAAS,KAAK;AACpB,MAAI,WAAW,UAAa,WAAW,GAAI,QAAO;EAClD,MAAM,WAAW;AACjB,MAAI,aAAa,OAAW,QAAO;AACnC,QAAM,IAAI,QAAQ,qEAAqE;;;CAIzF,AAAQ,aAAa,KAAqB;EACxC,MAAM,MAAM,YAAY;AACxB,MAAI,QAAQ,KAAM,QAAO,IAAI;EAC7B,MAAM,MAAM,iBAAiB;AAC7B,MAAI,QAAQ,KAAM,QAAO;AACzB,QAAM,IAAI,QAAQ,0BAA0B,IAAI,uCAAuC;;CAGzF,MAAe,QAAQ,MAAc,MAAkE;AACrG,MAAI,MAAM,QAAQ,QAAS,OAAM,IAAI,QAAQ,mBAAmB;EAChE,MAAM,EAAE,OAAO,QAAQ,KAAK,UAAU,MAAM,MAAM;EAClD,MAAM,QAAQ,MAAM,MAAM,QAAQ,OAAO;GACvC;GACA,GAAG,MAAM,WAAW,SAAY,EAAE,QAAQ,KAAK,WAAW;;AAE5D,SAAO;GAAE,WAAW,MAAM;GAAW,aAAa,KAAK,aAAa,OAAO,MAAM;;;CAGnF,AAAS,YAAY,QAA0B;EAC7C,MAAM,MAAM,OAAO,OAAO;EAC1B,MAAM,MAAM,YAAY;AACxB,MAAI,QAAQ,KAAM,QAAO,IAAI;EAC7B,MAAM,MAAM,iBAAiB;AAC7B,MAAI,QAAQ,KAAM,QAAO;AACzB,QAAM,IAAI,QAAQ,mBAAmB,OAAO,YAAY,uCAAuC;;CAGjG,AAAS,QAAQ,QAA0B;EACzC,MAAM,QAAQ,KAAK,YAAY;EAC/B,MAAM,UAAU,MAAM,MAAM,KAAK,IAAI,oBAAoB,KAAK;AAC9D,SAAO,UAAU;;CAGnB,AAAS,SAAS,QAAkB,OAA0B;EAC5D,MAAM,cAAc,KAAK,UAAU;EACnC,MAAM,aAAa,KAAK,UAAU;AAClC,MAAI,YAAY,WAAW,WAAW,OAAQ,QAAO;EACrD,MAAM,aAAa,YAAY;EAC/B,MAAM,YAAY,WAAW;AAC7B,MAAI,cAAc,WAAY,QAAO;AACrC,SAAO,eAAe,MAAM,OAAO,UAAU,WAAW,GAAG,WAAW;;;CAIxE,AAAQ,UAAU,QAAqE;EACrF,MAAM,MAAM,OAAO,OAAO;EAC1B,MAAM,MAAM,YAAY;AACxB,MAAI,QAAQ,KAAM,QAAO;GAAE,QAAQ,IAAI;GAAQ,WAAW,IAAI;;EAC9D,MAAM,MAAM,iBAAiB;AAC7B,MAAI,QAAQ,KAAM,QAAO;GAAE,QAAQ;GAAW,WAAW;;AACzD,QAAM,IAAI,QAAQ,mBAAmB,OAAO,YAAY,uCAAuC;;CAGjG,MAAe,MAAM,MAAc,MAAyB,QAAuD;AACjH,MAAI,QAAQ,QAAS,OAAM,IAAI,QAAQ,iBAAiB;AACxD,MAAI,KAAK,OAAO,WAAW,EAAG,OAAM,IAAI,QAAQ,wCAAwC;EACxF,MAAM,EAAE,OAAO,QAAQ,KAAK,UAAU,MAAM,MAAM;AAClD,SAAO,MAAM,MAAM,OAAO,EAAE,OAAO;;;AAIvC,iBAAe"}
|
|
1
|
+
{"version":3,"file":"fs.js","names":["local: FsTarget","real"],"sources":["../src/fs.ts"],"sourcesContent":["/**\n * WSL Service Provider for the `ctx.fs` capability seam. Backed by the host\n * filesystem over the `\\\\wsl.localhost\\<distro>\\…` 9P share — zero install\n * inside the distribution — while every model/UI-facing path is the Linux\n * path a WSL process would open (`processPath`, `displayPath`, `fileUrl`).\n * Reuses `LocalFileSystem`'s mechanics (realpath identity, atomic writes,\n * per-target locks, version guards) unchanged, because those operate on the\n * UNC path Node can open directly.\n *\n * Both UNC paths and Linux absolute paths resolve; Windows drive paths\n * resolve through their `/mnt/<drive>` form, so a WSL-composed session can\n * still touch the Windows filesystem coherently.\n *\n * Two seams the host's own provider supplies are re-established here, because\n * a WSL world mounts this backend in a preset realm where the host's\n * `fs-sandbox` wrapper (and therefore both behaviours) is not in the call\n * path:\n *\n * - **Linux symlinks**: the share lists a link but cannot resolve it, so a link\n * path used to fail as missing. `resolve`/`lstat` now retry through the\n * distribution (`wsl.exe … readlink -f`, see `shared/links.ts`) and continue\n * at the real path — never silently replacing the link, since the fallback\n * only runs when the direct resolution failed.\n * - **The file policy**: writes are fenced by `ctx.sandboxPolicy` exactly like\n * `@deepseek-ai/dsh-fs-sandbox` fences the host backend — the same\n * `writableRoots` allow-list, the same `FS_SANDBOX_DENIED` error the tool\n * layer turns into its model-facing denial and escalation hint, and the same\n * `sandboxMode` capability fact it reads to advertise escalation.\n *\n * @module dsh-wsl-workspace/fs\n */\n\nimport { Context } from '@deepseek-ai/cordis'\nimport z from '@deepseek-ai/schemastery'\nimport { AsyncLocalStorage } from 'node:async_hooks'\nimport { link, lstat, rename } from 'node:fs/promises'\nimport { FsError } from '@deepseek-ai/dsh-fs'\nimport type { FsEditOutcome, FsEditRequest, FsPathInfo, FsTarget, FsVersion, FsWriteIntent, FsWriteOutcome } from '@deepseek-ai/dsh-fs'\nimport { LocalFileSystem } from '@deepseek-ai/dsh-fs-local'\nimport { canonicalPath, writableRoots } from '@deepseek-ai/dsh-sandbox'\nimport { resolveLinuxSymlink } from './shared/links.ts'\nimport {\n isAbsoluteLinuxPath,\n joinUnc,\n mntToWindowsPath,\n parseWslUnc,\n windowsToMntPath,\n} from './shared/paths.ts'\nimport { defaultDistroSync } from './shared/wsl.ts'\n\n/** Plugin config. `cwd`/`distro` are optional because UNC workdirs carry both. */\nexport interface Config {\n /** Base directory for relative paths without a per-call cwd (UNC or Linux). */\n cwd?: string\n /** Default distribution for Linux-absolute paths without a UNC cwd. */\n distro?: string\n /** Exclusive UTF-8 byte limit on each overwrite-diff side (see fs-local). */\n diffBasisMaxBytes?: number\n}\n\n/** The host file-effect policy for one call, as `ctx.sandboxPolicy` resolves it. */\nexport interface SandboxPolicyLike {\n mode: string\n workspaceRoot?: string\n}\n\n/** The `ctx.sandboxPolicy` face this backend fences its writes with (optional service). */\nexport interface SandboxPolicyFace {\n /** Deployment default mode, mirrored as this backend's `sandboxMode`. */\n defaultMode?: string\n /** Per-call (or session-resolved) policy. */\n resolve(): SandboxPolicyLike\n}\n\n\n/** One translated coordinate: the input the local backend opens plus its cwd. */\ninterface Translated {\n /** Absolute path to hand to the local backend (UNC or Windows drive). */\n input: string\n /** Absolute Windows-side base for relative inputs (UNC or Windows drive). */\n cwd: string\n}\n\ninterface ToolExecution {\n agent?: { session: { header: { cwd?: string } } }\n}\n\n/**\n * The WSL filesystem backend. Identity keys are canonical UNC paths; the\n * Linux form is derived on demand, so both worlds stay in sync across\n * aliases and symlinks.\n */\nexport class WslFileSystem extends LocalFileSystem {\n static override Config: z<Config> = z.object({\n cwd: z.string(),\n distro: z.string(),\n diffBasisMaxBytes: z.number().default(10 * 1024 * 1024),\n })\n\n private readonly distro: string | undefined\n private readonly executionCwd = new AsyncLocalStorage<string | undefined>()\n\n constructor(ctx: Context, config: Config) {\n // schemastery fills the defaults before construction; the parent validates\n // `diffBasisMaxBytes` and stores the resolved shape.\n super(ctx, config)\n this.distro = config.distro\n ctx.on('tools/execute', (exec: ToolExecution, next: () => unknown) => (\n this.executionCwd.run(exec.agent?.session.header.cwd, next)\n ))\n // The 9P/drvfs substrate has no hard links and no Win32 security semantics:\n // replace the atomic-publication boundaries the parent's fsio defaults to.\n this.internals = {\n linkFile: WslFileSystem.publishNoReplace,\n replaceFile: WslFileSystem.replaceOverWrite,\n copyFileDacl: WslFileSystem.skipDaclCopy,\n }\n }\n\n /**\n * No-replace publication for filesystems without hard links. A real\n * collision (a concurrent external creator won) must still surface as the\n * original EEXIST so the guarded-create failure path classifies it; an\n * absent target falls back to rename, which on Windows publishes without\n * replacing anything. Safe against this backend's own writers because the\n * per-target lock serializes them.\n * @param tempPath - the staged file.\n * @param destPath - the destination to create.\n */\n private static async publishNoReplace(tempPath: string, destPath: string): Promise<void> {\n try {\n await link(tempPath, destPath)\n return\n } catch (error) {\n let exists = false\n try {\n await lstat(destPath)\n exists = true\n } catch {\n // Absent destination: rename publishes the staged file.\n }\n if (exists) throw error\n await rename(tempPath, destPath)\n }\n }\n\n /**\n * Security-preserving replacement boundary: Windows rename replaces an\n * existing destination atomically; no DACL preservation is needed over 9P.\n * @param destPath - the file being replaced.\n * @param tempPath - the staged replacement.\n */\n private static async replaceOverWrite(destPath: string, tempPath: string): Promise<void> {\n await rename(tempPath, destPath)\n }\n\n /** 9P files inherit their directory's DACL; nothing to preserve. */\n private static async skipDaclCopy(): Promise<void> {}\n\n /** Translate a model/plugin path into Windows-side coordinates. */\n private translate(path: string, cwd?: string): Translated {\n const unc = parseWslUnc(path)\n if (unc !== null) {\n return { input: joinUnc(unc.distro, unc.linuxPath), cwd: this.cwdOr(cwd) }\n }\n if (isAbsoluteLinuxPath(path)) {\n // /mnt/<drive>/… names the Windows filesystem inside the Linux world\n // (the dual-access path for migration): open the drive path directly so\n // both worlds stay coherent — the display stays the /mnt form.\n const win = mntToWindowsPath(path)\n if (win !== null) return { input: win, cwd: this.cwdOr(cwd) }\n return { input: joinUnc(this.distroFor(cwd), path), cwd: this.cwdOr(cwd) }\n }\n if (windowsToMntPath(path) !== null) {\n // Windows drive paths open directly; the Linux world reaches them via /mnt.\n return { input: path, cwd: this.cwdOr(cwd) }\n }\n // Relative: resolve against the caller cwd (or the configured base).\n const base = this.uncCwd(cwd)\n return { input: path, cwd: base }\n }\n\n /** A base for absolute inputs (unused by resolution, but the parent needs one). */\n private cwdOr(cwd?: string): string {\n return cwd ?? this.executionCwd.getStore() ?? this.config.cwd ?? process.cwd()\n }\n\n private uncCwd(cwd?: string): string {\n const base = cwd ?? this.executionCwd.getStore() ?? this.config.cwd\n if (base === undefined || base === '') {\n throw new FsError('wsl-fs: no cwd and no configured base for relative resolution', 'FS_IO_ERROR')\n }\n const unc = parseWslUnc(base)\n if (unc !== null) return joinUnc(unc.distro, unc.linuxPath)\n if (isAbsoluteLinuxPath(base)) return joinUnc(this.distroFor(base), base)\n if (windowsToMntPath(base) !== null) return base\n throw new FsError(`wsl-fs: cwd \"${base}\" is not in the WSL execution world`, 'FS_IO_ERROR')\n }\n\n /**\n * Resolve the distribution an absolute Linux path opens inside. The chain:\n * the caller cwd when it is a WSL UNC path, then the current tool\n * execution's session cwd, then the configured `distro`,\n * then the host's default distribution from the Lxss registry. The registry\n * fallback is reserved for calls that genuinely have no session.\n */\n private distroFor(cwd?: string): string {\n const fromCwd = parseWslUnc(cwd ?? '')\n if (fromCwd !== null) return fromCwd.distro\n const fromExecution = parseWslUnc(this.executionCwd.getStore() ?? '')\n if (fromExecution !== null) return fromExecution.distro\n const distro = this.distro\n if (distro !== undefined && distro !== '') return distro\n const fallback = defaultDistroSync()\n if (fallback !== undefined) return fallback\n throw new FsError('wsl-fs: Linux path carries no distribution and none is configured', 'FS_IO_ERROR')\n }\n\n /** The Linux display path for a resolved Windows-side path. */\n private linuxDisplay(raw: string): string {\n const unc = parseWslUnc(raw)\n if (unc !== null) return unc.linuxPath\n const mnt = windowsToMntPath(raw)\n if (mnt !== null) return mnt\n throw new FsError(`wsl-fs: resolved path \"${raw}\" is outside the WSL execution world`, 'FS_IO_ERROR')\n }\n\n override async resolve(path: string, opts?: { cwd?: string; signal?: AbortSignal }): Promise<FsTarget> {\n if (opts?.signal?.aborted) throw new FsError('resolve aborted', 'FS_ABORTED')\n const { input, cwd } = this.translate(path, opts?.cwd)\n const resolved = { cwd, ...opts?.signal !== undefined ? { signal: opts.signal } : {} }\n let local: FsTarget\n try {\n local = await super.resolve(input, resolved)\n } catch (error) {\n const real = await this.linkAwarePath(input, input)\n if (real === undefined) throw error\n return this.wslTarget(await super.resolve(real, resolved))\n }\n // The share resolves a link path to a *lexical* identity: `lstat` on a\n // Linux symlink fails, so the local resolver hands back the deepest\n // existing ancestor plus the remaining segments. Ask the distribution\n // before accepting that identity, or a link would be treated as a plain\n // missing file (and a write through it would escape the policy).\n const real = await this.linkAwarePath(input, String(local.targetKey))\n if (real === undefined) return this.wslTarget(local)\n return this.wslTarget(await super.resolve(real, resolved))\n }\n\n /** Wrap a locally resolved target in this world's Linux-facing identity. */\n private wslTarget(local: FsTarget): FsTarget {\n return { targetKey: local.targetKey, displayPath: this.linuxDisplay(String(local.displayPath)) }\n }\n\n /**\n * The real path a link-aware lookup must use, or `undefined` when the input\n * needs no help. Only a path this share cannot already describe pays for a\n * `wsl.exe` lookup: an existing file or directory resolves directly, while a\n * symlink (in the final segment or anywhere above it), a dangling target and\n * a not-yet-created file all ask the distribution, which answers with the\n * same path when nothing was linked.\n * @param input - the translated input or resolved identity to inspect.\n * @param targetKey - the identity the local resolver produced.\n * @returns the distribution's real path when it differs, else `undefined`.\n */\n private async linkAwarePath(input: string, targetKey: string): Promise<string | undefined> {\n const unc = parseWslUnc(targetKey) ?? parseWslUnc(input)\n if (unc === null) return undefined\n const asSpelled = joinUnc(unc.distro, unc.linuxPath)\n if (await this.describable(targetKey)) return undefined\n const real = await resolveLinuxSymlink(asSpelled)\n if (real === undefined) return undefined\n return real.toLowerCase() === asSpelled.toLowerCase() ? undefined : real\n }\n\n /** Whether this share can describe a Windows-side identity at all. */\n private async describable(winPath: string): Promise<boolean> {\n return await super.lstat(winPath, {}).catch(() => undefined) !== undefined\n }\n\n /**\n * The host file-effect policy for this call: the tool layer's per-call value\n * when it passes one, else the service's own resolution. `undefined` means\n * the deployment mounts no policy at all — the same state as a host\n * filesystem without `fs-sandbox`, so nothing is fenced.\n */\n protected sandboxPolicy(perCall?: SandboxPolicyLike): SandboxPolicyLike | undefined {\n if (isSandboxPolicy(perCall)) return perCall\n const service = this.sandboxPolicyService()\n if (service === undefined) return undefined\n try {\n const policy = service.resolve()\n return isSandboxPolicy(policy) ? policy : undefined\n } catch {\n // A policy that cannot resolve (no session in scope) fences nothing.\n return undefined\n }\n }\n\n /** The policy service this backend reads, when the deployment mounts one. */\n private sandboxPolicyService(): SandboxPolicyFace | undefined {\n const service = this.ctx.get('sandboxPolicy') as SandboxPolicyFace | undefined\n return service !== undefined && typeof service.resolve === 'function' ? service : undefined\n }\n\n /**\n * The deployment's default sandbox mode — the capability fact the file tool\n * reads to advertise escalation, mirrored from `SandboxedFileSystem`.\n */\n get sandboxMode(): string | undefined {\n const mode = this.sandboxPolicyService()?.defaultMode\n return typeof mode === 'string' ? mode : undefined\n }\n\n /**\n * Fence a mutation by the policy, then hand back the EXACT target to mutate\n * (no check-here-write-there): `read-only` denies, `workspace-write`\n * re-resolves and requires containment under a writable root, and\n * `danger-full-access` passes through. Mirrors\n * `@deepseek-ai/dsh-fs-sandbox`'s `checkedTarget`, including the\n * `FS_SANDBOX_DENIED` code the tool layer renders as a denial.\n * @param target - the resolved target about to be written.\n * @param perCall - the tool layer's per-call policy, when it passes one.\n * @returns the target the mutation must use.\n */\n private async checkedTarget(target: FsTarget, perCall?: SandboxPolicyLike): Promise<FsTarget> {\n const policy = this.sandboxPolicy(perCall)\n if (policy === undefined || policy.mode === 'danger-full-access') return target\n if (policy.mode === 'read-only') {\n throw new FsError(\n `cannot write \"${target.displayPath}\": file access denied under read-only mode`,\n 'FS_SANDBOX_DENIED',\n )\n }\n if (policy.mode !== 'workspace-write') return target\n const fresh = await this.resolve(target.displayPath)\n for (const root of this.writableRoots(policy)) {\n if (this.underRoot(String(fresh.targetKey), root)) return fresh\n }\n throw new FsError(\n `cannot write \"${target.displayPath}\": file access denied under workspace-write mode`,\n 'FS_SANDBOX_DENIED',\n )\n }\n\n /**\n * The roots a write may land under: the host's rule verbatim\n * (`writableRoots`: the workspace root plus the platform temp areas) plus,\n * in a WSL session, the distribution's own `/tmp` — the temp area of the\n * world this session actually runs in, which the host-side rule cannot name.\n * @param policy - the resolved policy.\n */\n private writableRoots(policy: SandboxPolicyLike): string[] {\n const roots = writableRoots(policy as Parameters<typeof writableRoots>[0]) as string[]\n const workspace = policy.workspaceRoot\n const unc = workspace === undefined ? null : parseWslUnc(workspace)\n if (unc !== null) roots.push(joinUnc(unc.distro, '/tmp'))\n return roots\n }\n\n /** Whether a canonical target key is a writable root or sits below one. */\n private underRoot(targetKey: string, root: string): boolean {\n const key = trimTrailing(canonicalPath(targetKey)).toLowerCase()\n const base = trimTrailing(canonicalPath(root)).toLowerCase()\n if (base === '' || base === '/' || key === base) return key === base\n return key.startsWith(base.endsWith('/') || base.endsWith('\\\\') ? base : `${base}\\\\`)\n || key.startsWith(`${base}/`)\n }\n\n /** Fence a full-content write by the policy, then delegate to the parent. */\n override async writeText(\n target: FsTarget,\n content: string,\n expected?: FsWriteIntent,\n signal?: AbortSignal,\n sandboxPolicy?: SandboxPolicyLike,\n ): Promise<FsWriteOutcome> {\n return super.writeText(await this.checkedTarget(target, sandboxPolicy), content, expected, signal)\n }\n\n /** Fence an edit by the policy, then delegate to the parent. */\n override async editText(\n target: FsTarget,\n edit: FsEditRequest,\n expected?: { version: FsVersion },\n signal?: AbortSignal,\n sandboxPolicy?: SandboxPolicyLike,\n ): Promise<FsEditOutcome> {\n return super.editText(await this.checkedTarget(target, sandboxPolicy), edit, expected, signal)\n }\n\n override processPath(target: FsTarget): string {\n const key = String(target.targetKey)\n const unc = parseWslUnc(key)\n if (unc !== null) return unc.linuxPath\n const mnt = windowsToMntPath(key)\n if (mnt !== null) return mnt\n throw new FsError(`wsl-fs: target \"${target.displayPath}\" is outside the WSL execution world`, 'FS_IO_ERROR')\n }\n\n override fileUrl(target: FsTarget): string {\n const linux = this.processPath(target)\n const encoded = linux.split('/').map(encodeURIComponent).join('/')\n return `file://${encoded}`\n }\n\n override contains(parent: FsTarget, child: FsTarget): boolean {\n const parentWorld = this.worldPath(parent)\n const childWorld = this.worldPath(child)\n if (parentWorld.distro !== childWorld.distro) return false\n const parentPath = parentWorld.linuxPath\n const childPath = childWorld.linuxPath\n if (childPath === parentPath) return true\n return parentPath === '/' ? true : childPath.startsWith(`${parentPath}/`)\n }\n\n /** One target's (distro, linuxPath) pair for containment; `undefined` distro = Windows world. */\n private worldPath(target: FsTarget): { distro: string | undefined; linuxPath: string } {\n const key = String(target.targetKey)\n const unc = parseWslUnc(key)\n if (unc !== null) return { distro: unc.distro, linuxPath: unc.linuxPath }\n const mnt = windowsToMntPath(key)\n if (mnt !== null) return { distro: undefined, linuxPath: mnt }\n throw new FsError(`wsl-fs: target \"${target.displayPath}\" is outside the WSL execution world`, 'FS_IO_ERROR')\n }\n\n override async lstat(path: string, opts?: { cwd?: string }, signal?: AbortSignal): Promise<FsPathInfo | undefined> {\n if (signal?.aborted) throw new FsError('lstat aborted', 'FS_ABORTED')\n if (path.trim().length === 0) throw new FsError('file_path must be a non-empty string', 'FS_NOT_FOUND')\n const { input, cwd } = this.translate(path, opts?.cwd)\n const info = await super.lstat(input, { cwd }, signal).catch(() => undefined)\n if (info !== undefined) return info\n // Same substrate limit as `resolve`: a link path must describe its target,\n // because the share cannot describe the link itself.\n const real = await this.linkAwarePath(input, input)\n if (real === undefined) return info\n return super.lstat(real, { cwd }, signal)\n }\n}\n\n/** Whether a value is a usable file-effect policy. */\nfunction isSandboxPolicy(value: SandboxPolicyLike | undefined): value is SandboxPolicyLike {\n return value !== undefined && typeof value.mode === 'string' && value.mode !== ''\n}\n\n/** Strip a trailing separator (keeping the root separator itself). */\nfunction trimTrailing(path: string): string {\n return path.length > 1 ? path.replace(/[\\\\/]+$/, '') : path\n}\n\nexport default WslFileSystem\n"],"mappings":"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"}
|