UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

112 lines • 4.98 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { FileStat, FileType, PathSpec } from "../../../types.js"; import { isMissError } from "../../../errors/fs.js"; import { operandName } from "./operands.js"; import { rstripSlash, stripSlash } from "../../../utils/slash.js"; /** `path` as a PathSpec keyed by its whole virtual path. Mirrors Python's * to_pathspec. */ export function toPathspec(path) { if (path instanceof PathSpec) return path; return new PathSpec({ virtual: path, directory: path, vfsPath: stripSlash(path) }); } /** * Wrap a walker's readdir so a mount parent lists as empty, not absent. * * A directory that exists only because mounts sit under it has no backend * to list it, so the readdir throws and a recursive command reports the * operand missing even as the fan-out searches the mounts below it and * prints hits. Empty is the honest answer for the primary backend: the * directory is there, and it owns nothing in it. * * Empty rather than the mount names, because the fan-out already runs the * command once per descendant mount and concatenates. Listing them here * would search each one twice. * * The visible descendants, not every descendant. Answering at all tells * the session the directory is there, and a directory that exists only * because of a mount it may not be told about is a directory it may not be * told about either: a hidden mount under an otherwise absent parent has * to keep reading as absence, the same way the mount itself does. * * Only for an absence, which is why the catch is `isMissError` and not the * walk's own wider set: a directory the backend refused with EACCES or * ENOTSUP is there and holds data this run cannot read, and calling it * empty would let `grep -r` print the descendant mount's hits and exit 0 * while silently omitting it. A refusal that is not absence keeps * propagating and gets reported. * * A directory a mount below this one serves lists as empty too, whatever * the backend holds there: the mount shadows those keys, as a kernel mount * does, and the fan-out walks it in a run of its own. `home` is the prefix * of the mount the readdir is bound to. */ export function mountParentReaddir(readdir, mounts, home) { if (mounts === undefined || mounts === null) return readdir; return async (p) => { const below = mounts.descendants(home === '' ? '/' : home); if (below.some((root) => p === root || p.startsWith(rstripSlash(root) + '/'))) return []; try { return await readdir(p); } catch (e) { if (!isMissError(e)) throw e; if (mounts.visibleDescendants(p).length === 0) throw e; return []; } }; } /** * Wrap a walker's stat so a mount parent reports as a directory. * * The twin of `mountParentReaddir`, and the reason a recursive search over * `/repos` reported it missing while still printing hits from * `/repos/alpha`: the operand was statted before it was walked, the * primary backend has no such path, and the miss was reported as absence. * * The mount table decides, not the dispatcher. A dispatched stat would * answer for paths inside the descendant mounts too, which is exactly what * the primary run must not see: the fan-out searches each of them * separately, so claiming their entries here would search them twice. * * Visible descendants only, because a row is a disclosure: the parent of a * mount this session may not be told about stays absent, which is what * every other verb already answers there. * * An absence only, the same as its readdir twin: a backend that refused the * path rather than not having it is reporting something the run must not * paper over with a synthesized row. */ export function mountParentStat(stat, mounts) { if (mounts === undefined || mounts === null) return stat; return async (p) => { try { return await stat(p); } catch (e) { if (!isMissError(e)) throw e; if (mounts.visibleDescendants(p).length === 0) throw e; return new FileStat({ name: operandName(p), type: FileType.DIRECTORY }); } }; } //# sourceMappingURL=wrap.js.map