@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
147 lines • 6.32 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 { concat } from "../../../../../utils/bytes.js";
import { OutputStream, asyncChain, closeQuietly, drain } from "../../../../../io/stream.js";
import { readFailExitCodeFromLine } from "../../../../spec/usage.js";
import { IOResult, OutputState, materialize } from "../../../../../io/types.js";
import { revoiceFsErrorLine } from "../../../../../errors/render.js";
import { LINE_STREAM_COMMANDS } from "../constants.js";
import { Cmd } from "../types.js";
const ENC = new TextEncoder();
const DEC = new TextDecoder();
function hasActiveFlags(flagKwargs) {
return Object.values(flagKwargs).some((v) => v !== false);
}
// One operand's bytes, its last line ended where the file ends: what a line
// reader sees at a file boundary, so `ab` followed by the next file's `cd` is
// two lines, the way the single-mount commands join their operands. Mirrors
// Python's _line_ended.
async function* lineEnded(source) {
let last = 0x0a;
for await (const chunk of asyncChain([source])) {
if (chunk.byteLength > 0)
last = chunk[chunk.byteLength - 1] ?? 0x0a;
yield chunk;
}
if (last !== 0x0a)
yield Uint8Array.of(0x0a);
}
// The per-operand fetch is a native Cmd.CAT sub-run, so its error lines
// carry the fetch command's voice; each is said again in the real command's
// (its prefix, its quoting, the step it names) so the cross-mount bytes
// match single-mount.
function respellFetchStderr(stderr, cmdName, scope) {
const lines = DEC.decode(stderr).split('\n');
const respelled = lines.map((line) => revoiceFsErrorLine(line, Cmd.CAT, cmdName, scope));
return ENC.encode(respelled.join('\n'));
}
// Run a stream command (`cmd files...` == `cat files... | cmd`). Each
// operand's raw bytes come from a native flagless `cat` on its owning mount
// (which also expands the operand's glob natively); one native run of the
// real command then consumes the merged stream in its stdin mode, so every
// flag keeps its single-invocation semantics (continuous `cat -n`/`nl`
// numbering, one global `sort` order, one `sed` address space). A failed
// operand is skipped and reported on stderr, cat-style; the merged exit code
// is then non-zero.
export async function runStream(cmdName, scopes, textArgs, flagKwargs, runSingle) {
const result = new IOResult();
const state = new OutputState();
result.output = state;
const fetches = [];
let sources = [];
async function finish(final = null) {
let merged = new IOResult();
let failCode = 0;
for (const { scope, io } of fetches) {
if (io.exitCode !== 0) {
let rendered = await materialize(io.stderr);
if (cmdName !== Cmd.CAT)
rendered = respellFetchStderr(rendered, cmdName, scope);
io.stderr = rendered;
failCode = Math.max(failCode, readFailExitCodeFromLine(cmdName, DEC.decode(rendered)), 1);
io.exitCode = 0;
}
merged = await merged.merge(io);
}
if (final !== null)
merged = await merged.merge(final);
result.records = merged.records;
result.refusal = result.refusal ?? merged.refusal;
const stderr = concat([await materialize(merged.stderr), await materialize(result.stderr)]);
result.stderr = stderr.byteLength > 0 ? stderr : null;
result.exitCode = result.exitCode || merged.exitCode || failCode;
state.finish();
}
async function closeFetches() {
await Promise.all(fetches.map(({ out }) => closeQuietly(out)));
}
let out;
let final = null;
try {
for (const scope of scopes) {
const [source, io] = await runSingle(Cmd.CAT, [scope], [], {});
fetches.push({ scope, out: source, io });
result.producer = io.producer;
result.refusal = io.refusal ?? result.refusal;
if (io.exitCode !== 0)
await drain(source);
else if (source !== null)
sources.push(source);
}
if (cmdName === Cmd.SORT && fetches.some(({ io }) => io.exitCode !== 0)) {
await closeFetches();
await finish();
return [null, result];
}
if (LINE_STREAM_COMMANDS.has(cmdName) && sources.length > 0)
sources = [...sources.slice(0, -1).map(lineEnded), ...sources.slice(-1)];
const body = asyncChain(sources);
if (cmdName === Cmd.CAT && !hasActiveFlags(flagKwargs))
out = body;
else
[out, final] = await runSingle(cmdName, [], [...textArgs], flagKwargs, {
stdin: body,
resolveHint: scopes[0] ?? null,
});
if (final !== null) {
result.producer = final.producer;
result.refusal = final.refusal ?? result.refusal;
}
}
catch (error) {
await closeFetches();
throw error;
}
let closing;
async function finalize() {
await Promise.all([closeQuietly(out), closeFetches()]);
await finish(final);
}
function close() {
return (closing ??= finalize());
}
async function* output() {
try {
for await (const data of asyncChain(out === null ? [] : [out])) {
if (cmdName !== Cmd.SORT || !fetches.some(({ io }) => io.exitCode !== 0))
yield data;
}
}
finally {
await close();
}
}
return [new OutputStream(output(), close), result];
}
//# sourceMappingURL=stream.js.map