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