UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

105 lines • 4.21 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 { commandFiles, dirAwareStream, resolveOrEmpty } from "../files.js"; import { specOf } from "../../../spec/builtins.js"; import { FlagView } from "../../../spec/flag_view.js"; import { IOResult, materialize } from "../../../../io/types.js"; import { ByteSpool } from "../../../../io/spool.js"; import { StreamRefusal } from "../../../../rs/errors.js"; import { closeStream, openStream, serveRequests, } from "../../../../rs/stream.js"; import { byteView, utf8Locale } from "../../../../shell/bytes.js"; import { concat } from "../../../../utils/bytes.js"; import { resolveSource, stdinStream } from "../../utils/stream.js"; import { reportedStream } from "../../utils/operands.js"; const ENC = new TextEncoder(); /** Each input reversed in turn: held whole, which the engine reads back a * block at a time and has written out a record at a time. Running out of * memory ends the run, exit 1. Mirrors Python's _reversed. */ async function* reversed(engine, sources, io, signal) { const errors = new ByteSpool(); let spool = new ByteSpool(); const host = { errors, async serve(request) { const [offset, size] = [Number(request.offset), Number(request.size)]; if (request.op === 'emit') return { reply: {}, output: spool.stream(offset, size) }; return { reply: {}, data: await spool.read(offset, size) }; }, }; try { for (const source of sources) { spool = new ByteSpool(); try { await spool.fill(source); engine.begin({ size: spool.size }); yield* serveRequests(engine, host, signal); } finally { await spool.close(); } if (engine.status() !== 0) break; } } finally { if (engine.status() !== 0) { io.exitCode = 1; io.stderr = concat([await materialize(io.stderr), await materialize(await errors.output())]); } await errors.close(); await closeStream(engine); } } const tac = async (_accessor, paths, _texts, ctx) => { const fl = new FlagView(ctx.flags, specOf('tac')); const separator = fl.asStr('separator'); let engine; try { engine = await openStream('tac', { separator: separator === undefined ? null : byteView(separator), before: fl.asBool('before'), regex: fl.asBool('regex'), utf8: utf8Locale(ctx.env), }); } catch (err) { if (!(err instanceof StreamRefusal)) throw err; return [null, new IOResult({ exitCode: 1, stderr: ENC.encode(`${err.message}\n`) })]; } // The separator is refused before any operand is touched; the engine is // closed if resolving them fails before the output takes it over. const files = commandFiles(ctx, paths); let resolved; try { resolved = await resolveOrEmpty(files, paths); } catch (err) { await closeStream(engine); throw err; } const stream = stdinStream(dirAwareStream(files, ctx), ctx.stdin); const io = new IOResult(); const sources = resolved.length > 0 ? resolved.map((path) => reportedStream(stream(path), io, path, 'tac')) : [resolveSource(ctx.stdin)]; return [reversed(engine, sources, io, ctx.signal), io]; }; export const BUILDER = { name: 'tac', read: true, fn: tac, }; //# sourceMappingURL=tac.js.map