UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

119 lines • 6.55 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 { OPERAND_CONCURRENCY } from "../../constants.js"; import { DISPATCH_BUILDERS } from "./constants.js"; import { mountStarts, reached } from "./scopes.js"; import { du, leavesOf, parseFlags } from "../du.js"; import { runDispatch } from "../../generic_bind/dispatch.js"; import { specOf } from "../../../spec/builtins.js"; import { FlagView } from "../../../spec/flag_view.js"; import { boundedMap } from "../../../../concurrency/limiter.js"; import { IOResult, materialize } from "../../../../io/types.js"; import { PathSpec } from "../../../../types.js"; import { stripSlash } from "../../../../utils/slash.js"; import { virtualKey } from "../../utils/paths.js"; import { mountView } from "../../utils/links.js"; // The flags that shape only the rendering: every mount measures without them, // and the line renders once. export const RENDERING = new Set(['s', 'max_depth']); /** * Render du over operands spanning mounts from each mount's own du. * * Every start point is measured by the du its mount registered, a few at a * time, and the measurements (`IOResult.records`) render as one tree: a * directory's row counts the mounts inside it, and `-c` totals the line. No * mount's output text is read back. A mount whose du fails adds its * diagnostic and status, and the mounts below it count only where the walk * could still reach them (`reached`); one that succeeds without a measurement * (a du not built on `duGeneric`) leaves the line to the one dispatcher walk. * With `nested`, `runSingle` answers only its own mount's part, so the mounts * below each operand are measured here unless `-x` keeps the walk on one * filesystem; otherwise each operand's run composes its own. */ export async function runDu(paths, texts, bag, dispatch, runSingle, cwd, vfs, stdin = null, signal, nested = false, // The line's operand resolution, which the one walk's globs take. follow) { const rendering = parseFlags({ stdin: null, flags: bag, cwd: PathSpec.fromStrPath(cwd) }); if (rendering instanceof IOResult) return [null, rendering]; const bounded = new FlagView(bag, specOf('du')).asBool('one_file_system'); const measuring = Object.fromEntries(Object.entries(bag).filter(([k]) => !RENDERING.has(k))); // Each start is then one mount's own part, and keeps only what that mount // owns: a part walked through the dispatcher reaches the mounts below it // too, which measure themselves. const mounts = nested && !bounded ? mountView(vfs) : undefined; const plan = paths.flatMap((path, index) => (mounts !== undefined ? mountStarts(path, vfs) : [path]).map((start) => [ index, start, ])); const ios = await boundedMap(plan, async ([, start]) => { const [out, io] = await runSingle('du', [start], [...texts], measuring, signal === undefined ? {} : { signal }); await materialize(out); return io; }, OPERAND_CONCURRENCY); // A run that failed measured nothing and says why; one that succeeded // without a measurement is a du this line cannot compose. if (ios.some((io) => io.records === null && io.exitCode === 0)) { const builder = DISPATCH_BUILDERS.get('du'); if (builder === undefined) throw new Error('No dispatch builder for du'); return runDispatch(builder, paths, texts, bag, dispatch, cwd, vfs, stdin, signal, [], follow); } const kept = await reached(paths, plan, ios.map((io) => io.exitCode !== 0), dispatch); const done = plan.flatMap((step, i) => { const io = ios[i]; return kept[i] === true && io !== undefined ? [{ step, io }] : []; }); const found = paths.map(() => []); const present = paths.map(() => false); let merged = new IOResult(); for (const { step, io } of done) { const [index, start] = step; const owner = mounts?.rootOf(start.virtual); const owned = (io.records ?? []).filter((r) => mounts === undefined || mounts.rootOf(r.path.virtual) === owner); if (start === paths[index]) { present[index] = (io.records ?? []).length > 0; } else if (leavesOf(owned).every(([leaf]) => stripSlash(leaf) !== stripSlash(start.virtual))) { // A mount root holding nothing still gets its row, unless the mount // is one file (/.bash_history). found[index]?.push({ path: start, run: index }); } // A run's record of its own start is left out: the line renders the // operand's row from the operand, and a mount root's as above. found[index]?.push(...owned .filter((r) => r.size !== undefined || stripSlash(r.path.virtual) !== stripSlash(start.virtual)) .map((r) => ({ ...r, run: index }))); merged = await merged.merge(io); } const measured = new Map(); const records = []; paths.forEach((path, index) => { if (!present[index]) return; const target = virtualKey(path); measured.set(target, found[index] ?? []); records.push({ path: target, run: index }, ...(found[index] ?? [])); }); const entries = (path) => { const counted = leavesOf(measured.get(path) ?? []); return Promise.resolve([counted, counted.reduce((acc, [, size]) => acc + size, 0)]); }; const out = await du([...measured.keys()], rendering, async (path) => (await entries(path))[1], entries, [], undefined, null, undefined, () => [...measured.values()].flatMap((rows) => rows.flatMap((r) => (r.size === undefined ? [r.path.virtual] : [])))); merged.stderr = new Uint8Array([...out.stderr, ...(await materialize(merged.stderr))]); merged.exitCode = Math.max(out.exitCode, ...done.map(({ io }) => io.exitCode)); merged.records = records; return [out.stdout, merged]; } //# sourceMappingURL=du.js.map