UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

157 lines • 6.11 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 { RAMAccessor } from "../../accessor/ram.js"; import { VFSName } from "../../types.js"; import { BaseVFS } from "../base.js"; import { storageUsage } from "../capacity.js"; import { LOCAL_WALK_LIMIT } from "../constants.js"; import { RAMFiles, RAMStore } from "./store.js"; import { readdir as ramReaddir } from "../../core/ram/readdir.js"; import { read as devAwareRead, readRange as devAwareReadRange } from "../../core/dev/read.js"; import { stat as devAwareStat } from "../../core/dev/stat.js"; import { exists as ramExists } from "../../core/ram/exists.js"; import { write as ramWrite } from "../../core/ram/write.js"; import { pwrite as ramPwrite } from "../../core/ram/pwrite.js"; import { create as ramCreate } from "../../core/ram/create.js"; import { mkdir as ramMkdir } from "../../core/ram/mkdir.js"; import { unlink as ramUnlink } from "../../core/ram/unlink.js"; import { rmdir as ramRmdir } from "../../core/ram/rmdir.js"; import { rmR as ramRmR } from "../../core/ram/rm.js"; import { rename as ramRename } from "../../core/ram/rename.js"; import { copy as ramCopy } from "../../core/ram/copy.js"; import { truncate as ramTruncate } from "../../core/ram/truncate.js"; import { setAttrs as ramSetAttrs } from "../../core/ram/set_attrs.js"; import { tree as ramTree } from "../../core/ram/readdir.js"; export class RAMVFS extends BaseVFS { name = VFSName.RAM; cachesReads = false; // byte store: stat() sizes every file from metadata sizesAlwaysKnown = true; indexTtl = 0; usage; store; accessor; readsRanges = true; local = true; walkLimit = LOCAL_WALK_LIMIT; /** @throws VFSConfigError when `capacity` is not a size. */ constructor(options = {}) { super(); this.usage = storageUsage(this.name, options.capacity, 0); this.store = new RAMStore(this.usage); this.accessor = new RAMAccessor(this.store); } /** * The bytes the store's files hold, which count against the `max_memory` * of each workspace the store is mounted in; 0 for a table that keeps none, * as `/dev`'s devices and pipes. Mirrors Python's `held`. */ get held() { const files = this.accessor.store.files; return files instanceof RAMFiles ? files.held : 0; } readTree(path) { return ramTree(this.accessor, path); } readdir(path) { return ramReaddir(this.accessor, path); } read(path, _handed, offset = 0, size = null, signal) { if (offset === 0 && size === null) return devAwareRead(this.accessor, path, signal); return devAwareReadRange(this.accessor, path, offset, size, signal); } stat(path) { return devAwareStat(this.accessor, path); } exists(path) { return ramExists(this.accessor, path); } write(path, data, signal, _handed, atomic = false) { return ramWrite(this.accessor, path, data, false, signal, atomic); } append(path, data, _handed, signal) { return ramWrite(this.accessor, path, data, true, signal); } pwrite(path, data, offset, _handed, signal) { return ramPwrite(this.accessor, path, data, offset, signal); } create(path) { return ramCreate(this.accessor, path); } mkdir(path, parents = false) { return ramMkdir(this.accessor, path, parents); } unlink(path) { return ramUnlink(this.accessor, path); } rmdir(path) { return ramRmdir(this.accessor, path); } rmR(path) { return ramRmR(this.accessor, path); } rename(src, dst) { return ramRename(this.accessor, src, dst); } copy(src, dst, signal) { return ramCopy(this.accessor, src, dst, signal); } truncate(path, length, noCreate = false) { return ramTruncate(this.accessor, path, length, noCreate); } setattr(path, fields) { return ramSetAttrs(this.accessor, path, fields); } getState() { const files = {}; for (const [k, v] of this.store.files) files[k] = v; const modified = {}; for (const [k, v] of this.store.modified) modified[k] = v; const attrs = {}; for (const [k, v] of this.store.attrs) attrs[k] = { ...v }; return { type: this.name, ...(this.usage !== null ? { config: { capacity: this.usage.limit } } : {}), files, dirs: [...this.store.dirs], modified, attrs, }; } loadState(state) { this.store.files.clear(); for (const [k, v] of Object.entries(state.files ?? {})) this.store.files.set(k, v); this.store.dirs.clear(); const dirs = state.dirs ?? []; for (const d of dirs.length > 0 ? dirs : ['/']) this.store.dirs.add(d); this.store.modified.clear(); for (const [k, v] of Object.entries(state.modified ?? {})) this.store.modified.set(k, v); this.store.attrs.clear(); for (const [k, v] of Object.entries(state.attrs ?? {})) this.store.attrs.set(k, { ...v }); } /** df's QUOTA row for a capped store; the base UNKNOWN otherwise. Mirrors * Python's. */ capacity() { return this.usage !== null ? Promise.resolve(this.usage.report()) : super.capacity(); } } //# sourceMappingURL=ram.js.map