UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

69 lines • 3.91 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 { chunks } from "../../../io/cooperative.js"; import { NOOPAccessor } from "../../../accessor/base.js"; import { materialize, IOResult } from "../../../io/types.js"; import { FileType, PathSpec } from "../../../types.js"; import { eisdir } from "../../../errors/fs.js"; import { currentCaller, runWithCaller } from "../../../context/session_context.js"; import { Files } from "../../../workspace/files.js"; import { dispatchStat, virtualFlags, virtualKey } from "../utils/paths.js"; /** A streamed read that opens as the command that asked for it: at the first * pull, which can come after that command ended, so under the command's * caller, as a `fresh` mount trusts only the listings that command made. A * directory fails with EISDIR, as a POSIX read does, before a keyed store * reads it as nothing. `ahead` is what the read awaits first (`readAhead`). * Mirrors Python's caller_stream. */ export async function* callerStream(dispatch, caller, path, ahead) { const data = await runWithCaller(caller, async () => { if ((await dispatchStat(dispatch)(path)).type === FileType.DIRECTORY) throw eisdir(path); await ahead?.(path); return (await dispatch('read', path, [], { stream: true }))[0]; }); yield* chunks(data); } /** Run the existing builder once over the full virtual namespace. Mirrors * Python's run_dispatch. The builder runs as a run across mounts: no mount's * command scope is bound around it (`crossesMounts`), so every call it makes * through its files reaches whichever mount serves the path. The dispatcher * lists the mounts below a directory itself, so no descendant is left to * avoid; where each mount begins stays for `--one-file-system`, and each * mount's du budget for a walk. `follow` is the line's operand resolution, * which its globs' matches take too. The output is read before this returns, * inside the running command: a `fresh` mount trusts only the listings that * command made, so a lazy stream read after it ends would be served the * previous command's. A builder that `streams` only reads, and each read opens * as this command (`callerStream`), so its output is handed on live. */ export async function runDispatch(builder, paths, texts, bag, dispatch, cwd, vfs, stdin = null, signal, argv = [], follow, diff, ids, find) { return runWithCaller({ ...currentCaller(), mount: null }, async () => { const result = await builder.fn(new NOOPAccessor(), paths.map(virtualKey), [...texts], { stdin, flags: virtualFlags(bag), cwd: PathSpec.fromStrPath(cwd), vfs: (vfs ?? new Files(dispatch, null, null, { follow: follow ?? null, ledger: false })).servedBy(null), argv, ...(diff === undefined ? {} : { diff }), ...(ids === undefined ? {} : { ids }), ...(find === undefined ? {} : { find }), ...(signal === undefined ? {} : { signal }), }); if (result === null) return [null, new IOResult()]; if (builder.streams === true) return result; return [await materialize(result[0]), result[1]]; }); } //# sourceMappingURL=dispatch.js.map