@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
69 lines • 3.91 kB
JavaScript
// ========= 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