UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

88 lines • 4.49 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 { DirListing, FileStat, FileType } from "../../types.js"; import { globPrefix, globStemPrefix } from "../../utils/glob_walk.js"; import { compareCodePoints } from "../../utils/sort.js"; import { PATH_SAFE } from "../hierarchy/codec.js"; import { filtersOf, tableOf } from "../vector/scope.js"; import { tableExists } from "./query.js"; import { cellText, renderCard } from "./render.js"; function rowFiles(rows, config) { // The widened select carries every rendered column, so each card's exact // size is free here; blob values are deliberately not fetched at listing // time, so blob entries stay size-unknown and stat renders them itself. const listed = []; for (const row of rows) { const id = cellText(row[config.idColumn]); listed.push(new FileStat({ name: `${id}.md`, type: FileType.FILE, size: renderCard(row, config).byteLength, })); if (config.blobColumn !== null) { listed.push(new FileStat({ name: `${id}.${config.blobExt}`, type: FileType.FILE })); } } return listed; } /** Keep values whose rendered name starts with a glob's literal head. */ function renderedPrefixTest(prefix) { return (value) => PATH_SAFE.encode(value).startsWith(prefix); } /** * The row-id prefix a leaf glob narrows the row query to. * * A leaf is named `<rowId>` plus whichever suffix the renderer gave it, and * only the id half is a prefix the query can test. */ function rowPrefix(pattern, config) { const suffixes = ['.md']; if (config.blobColumn !== null && config.blobColumn !== '') suffixes.push(`.${config.blobExt}`); return globStemPrefix(pattern, suffixes); } /** The entries under a table or a group. */ export async function children(accessor, match) { const config = accessor.config; const table = tableOf(config.table, match); const filters = filtersOf(config.groupBy, match); const pattern = match.pattern; if (!(await tableExists(accessor, table))) return null; const depth = Object.keys(filters).length; if (depth < config.groupBy.length) { const displayPrefix = globPrefix(pattern); // Values render path-safe, so a glob's head is spelled in rendered names: // the query takes the value prefix the head stands for, which loses // nothing, and the cap counts the renderings that really start with the // head, so a head no value prefix spells (the escape lead alone) still // reaches past the rows at the head of the table. const values = await accessor.driver.distinct(table, config.groupBy[depth] ?? '', filters, config.maxRows, PATH_SAFE.prefixValue(displayPrefix), displayPrefix === '' ? undefined : renderedPrefixTest(displayPrefix)); const names = values.map((value) => PATH_SAFE.encode(value)).sort(compareCodePoints); return new DirListing({ entries: names.map((name) => new FileStat({ name, type: FileType.DIRECTORY })), partial: displayPrefix !== '', window: true, }); } // Select every column except the vector and blob ones (schema order, so // the projected rows render byte-identically to the full rows read() // fetches). Still one data query; the schema lookup is local metadata on // the already-opened table. const columns = (await accessor.driver.tableColumns(table)).filter((c) => c !== config.vectorColumn && c !== config.blobColumn); const prefix = rowPrefix(pattern, config); const rows = await accessor.driver.rowsMatching(table, filters, columns, config.maxRows, config.idColumn, prefix); return new DirListing({ entries: rowFiles(rows, config), partial: prefix !== '', window: true }); } //# sourceMappingURL=readdir.js.map