@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
98 lines • 4.21 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 { checkItem } from "../msgraph/paths.js";
import { enotdir, isEexist, isEnoent } from "../../errors/fs.js";
import { rstripSlash } from "../../utils/slash.js";
import { baseName, createChildFolder, parentPath } from "../msgraph/drive.js";
import { itemUrl } from "./client.js";
import { driveLoc, resolveItem } from "./resolve.js";
async function createDir(accessor, driveId, path, virtual, existOk) {
const config = accessor.config;
const parent = parentPath(path);
await createChildFolder(config, itemUrl(config, driveId, parent, '/children'), baseName(path), {
item: itemUrl(config, driveId, path),
parent: itemUrl(config, driveId, parent),
virtual,
}, existOk);
}
/**
* Create every level of a drive path, from the drive root down.
*
* Args:
* accessor: the mount's accessor.
* driveId: the drive the path lives in.
* itemPath: the drive-relative path, keyPrefix included.
* path: the operand.
* parents: `-p`: a folder at the operand passes, and a file in the way is
* named rather than the operand.
*/
async function createChain(accessor, driveId, itemPath, path, parents) {
const parts = itemPath.split('/');
const shown = rstripSlash(path.virtual).split('/');
const depth = path.vfsPath.split('/').filter((part) => part !== '').length;
for (let index = 1; index <= parts.length; index++) {
try {
await createDir(accessor, driveId, parts.slice(0, index).join('/'), path.virtual, parents || index < parts.length);
}
catch (error) {
const above = parts.length - index;
if (!isEexist(error) || above === 0)
throw error;
// `mkdir -p` names the file it stops at, as GNU does, and a file in the
// hidden keyPrefix as the mount root it blocks; mkdir(2) blames the
// operand.
const level = shown.slice(0, -Math.min(above, depth)).join('/') || '/';
throw enotdir(parents ? level : path);
}
}
}
/**
* The keyPrefix a scoped mount's root folder chain lives at.
*
* Only a mount scoped to one site and drive places its paths under the
* prefix, so only there is the mount root a folder chain that a folder
* create can find missing. With parents the chain is already walked;
* without, a create right under the root has to make it first.
*
* Args:
* accessor: the mount's accessor.
*/
function scopedPrefix(accessor) {
const { site, drive, keyPrefix } = accessor.config;
return site !== null && drive !== null ? keyPrefix : '';
}
export async function mkdir(accessor, path, parents = false) {
if (path.vfsPath === '')
return;
const resolved = await resolveItem(accessor, path);
await checkItem(accessor.config, driveLoc(accessor.config, resolved, path.vfsPath), path.virtual);
const driveId = resolved.driveId ?? '';
const itemPath = resolved.itemPath ?? '';
if (parents) {
await createChain(accessor, driveId, itemPath, path, true);
}
else {
try {
await createDir(accessor, driveId, itemPath, path.virtual, false);
}
catch (error) {
const prefix = scopedPrefix(accessor);
const missingRoot = isEnoent(error) && prefix !== '' && parentPath(itemPath) === prefix;
if (!missingRoot)
throw error;
await createChain(accessor, driveId, itemPath, path, false);
}
}
}
//# sourceMappingURL=mkdir.js.map