@sema-agent/core
Version:
Stateless, task-oriented AI agent core
70 lines (69 loc) • 4.26 kB
TypeScript
/**
* Directory ENTRIES for the model, and the one per-entry read-deny judge every traversal shares.
*
* The judge ({@link createEntryDenyJudge}) is the walk's (search.ts `walk`, the throat Glob, the Grep
* fallback and the repo map traverse through): an entry path is judged as spelled and at its home view
* (read-deny-home.ts), so a traversal that enters the home through an alias of it meets the
* home-anchored rows where the home is. It answers; it does not count — each caller counts what its own
* result has to disclose.
*
* The enumerator ({@link enumerateDirectory}) lists ONE level of a directory the way the upstream
* at-mention lists one (a single readdir, at most {@link DIRECTORY_LISTING_MAX_ENTRIES} names, then
* "… and N more entries"), with three differences that are this engine's facts:
* · entries are files, directories AND symbolic links (kinds from the environment's listing, which does
* not follow links); a link is listed by its own name and judged at its own path — its target is never
* resolved or read here;
* · every entry passes the per-entry read-deny judge; a withheld entry is neither named nor counted in
* the remainder, and the withheld count is EXACT (one level, so every entry is judged);
* · no ignore rules apply: the user named this directory, and ignore files are a search-noise filter, not
* a read boundary.
* Entries sort by code unit (a stable listing; the environment's own order is not one). Three counts stay
* apart: `omitted` (withheld by the deny judge), `more` (kept entries past the cap), `incomplete` (the
* judging was cut short by an abort — the listing is a prefix, not the directory).
*/
import type { ExecutionEnv } from "../../internal/harness-types.js";
import type { FileError, FileKind, Result } from "../../internal/harness.js";
import { type HomeViewEnv, type HomeViewsCarrier } from "./read-deny-home.js";
/** The upstream at-mention's cap on listed entries. */
export declare const DIRECTORY_LISTING_MAX_ENTRIES = 1000;
/** The read-deny table as the traversals hold it. */
export type EntryDenyTable = {
matchPath(path: string): {
pattern: string;
} | null;
} & HomeViewsCarrier;
/** Judge one entry path: the row that withholds it, or null. `leaf: "file"` asks the home view for a file
* leaf (a directory entry is judged as a directory). */
export type EntryDenyJudge = (path: string, leaf?: "file") => Promise<{
pattern: string;
} | null>;
/** The per-entry judge over `deny` (literal spelling, then the home view). */
export declare function createEntryDenyJudge(env: HomeViewEnv, deny: EntryDenyTable, signal?: AbortSignal): EntryDenyJudge;
export interface DirectoryEntry {
name: string;
kind: FileKind;
}
export interface DirectoryListing {
/** At most {@link DIRECTORY_LISTING_MAX_ENTRIES}, sorted. */
entries: DirectoryEntry[];
/** Kept entries past the cap. */
more: number;
/** Entries withheld by the read-deny judge (exact). */
omitted: number;
/** The rows that withheld something, first-seen order. */
omittedPatterns: string[];
/** An abort cut the judging short: `entries` / `more` / `omitted` describe a prefix of the directory. */
incomplete: boolean;
}
/** List one level of `dir` (a canonical directory path). A listing the environment refuses is the error. */
export declare function enumerateDirectory(env: ExecutionEnv, dir: string, judge: EntryDenyJudge | undefined, signal?: AbortSignal): Promise<Result<DirectoryListing, FileError>>;
/**
* A data label (a path, a file name) as a JSON string literal with every C0/C1 control, format character
* and line / paragraph separator written as `\uXXXX` — lossless (JSON.parse gives the original back), and
* one line whatever the name holds. JSON's own escaping alone leaves U+2028 / U+2029 / U+0085 and the
* format characters raw.
*/
export declare function quoteDataLabel(label: string): string;
/** The listing as text: one entry per line (a directory with a trailing "/"; a name that could break or
* hide in its line is written as {@link quoteDataLabel}), then "… and N more entries" when capped. */
export declare function renderDirectoryListing(l: DirectoryListing): string;