@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
105 lines • 3.37 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 {} from "../../../files.js";
// What a create opens: a file made and never written still lands.
const CREATE = Object.freeze({
readable: false,
writable: true,
truncate: false,
append: false,
create: true,
exclusive: false,
binary: true,
});
export function createJournal() {
const journal = [];
let sealed = false;
const record = (entry) => {
if (!sealed)
journal.push(entry);
};
return {
markCreate(path) {
record({ kind: 'create', path });
},
takeCreate(path) {
const last = journal.at(-1);
if (last?.kind !== 'create' || last.path !== path)
return false;
journal.pop();
return true;
},
markTruncate(path, length) {
record({ kind: 'truncate', path, length });
},
markMkdir(path) {
record({ kind: 'mkdir', path });
},
markUnlink(path) {
record({ kind: 'unlink', path });
},
markRmdir(path) {
record({ kind: 'rmdir', path });
},
markRename(src, dst) {
record({ kind: 'rename', path: src, dst });
},
markSymlink(path, target) {
record({ kind: 'symlink', path, target });
},
markSetattr(path, attrs) {
record({ kind: 'setattr', path, attrs });
},
seal() {
sealed = true;
},
get sealed() {
return sealed;
},
reopen() {
sealed = false;
},
takeMutations() {
return journal.splice(0, journal.length);
},
};
}
/**
* Replay one recorded guest mutation against the mounts.
*
* Args:
* files: the runtime's mount vocabulary to apply through.
* mutation: the journal entry to apply.
*/
export async function applyMutation(files, mutation) {
switch (mutation.kind) {
case 'create':
return files.close(await files.open(mutation.path, CREATE));
case 'truncate':
return files.truncate(mutation.path, mutation.length);
case 'mkdir':
return files.mkdir(mutation.path);
case 'unlink':
return files.unlink(mutation.path);
case 'rmdir':
return files.rmdir(mutation.path);
case 'rename':
return files.rename(mutation.path, mutation.dst);
case 'symlink':
return files.symlink(mutation.path, mutation.target);
case 'setattr':
return files.setattr(mutation.path, mutation.attrs);
}
}
//# sourceMappingURL=journal.js.map