@sema-agent/core
Version:
Stateless, task-oriented AI agent core
61 lines (60 loc) • 2.2 kB
JavaScript
import { homeViewsOf } from "./read-deny-home.js";
export const DIRECTORY_LISTING_MAX_ENTRIES = 1000;
export function createEntryDenyJudge(env, deny, signal) {
const views = homeViewsOf(env, deny, signal);
return async (path, leaf) => {
const hit = deny.matchPath(path);
if (hit)
return hit;
const view = await views.of(path, leaf !== undefined ? { leaf } : undefined);
return view !== undefined ? deny.matchPath(view) : null;
};
}
export async function enumerateDirectory(env, dir, judge, signal) {
const listing = await env.listDir(dir, signal);
if (!listing.ok)
return listing;
const infos = [...listing.value].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
const kept = [];
let omitted = 0;
const omittedPatterns = [];
let incomplete = false;
for (const info of infos) {
if (signal?.aborted) {
incomplete = true;
break;
}
const hit = judge === undefined ? null : await judge(info.path, info.kind === "directory" ? undefined : "file");
if (hit) {
omitted++;
if (!omittedPatterns.includes(hit.pattern))
omittedPatterns.push(hit.pattern);
continue;
}
kept.push({ name: info.name, kind: info.kind });
}
return {
ok: true,
value: {
entries: kept.slice(0, DIRECTORY_LISTING_MAX_ENTRIES),
more: Math.max(0, kept.length - DIRECTORY_LISTING_MAX_ENTRIES),
omitted,
omittedPatterns,
incomplete,
},
};
}
const LABEL_UNSAFE = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
export function quoteDataLabel(label) {
let out = "";
for (const ch of JSON.stringify(label)) {
out += LABEL_UNSAFE.test(ch) ? `\\u${ch.codePointAt(0).toString(16).padStart(4, "0")}` : ch;
}
return out;
}
export function renderDirectoryListing(l) {
const lines = l.entries.map((e) => `${LABEL_UNSAFE.test(e.name) ? quoteDataLabel(e.name) : e.name}${e.kind === "directory" ? "/" : ""}`);
if (l.more > 0)
lines.push(`… and ${l.more} more entries`);
return lines.join("\n");
}