@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
119 lines • 6.55 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 { 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