UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

74 lines (73 loc) • 5.37 kB
/** * WRITE TARGETS — which words of a shell segment a program writes, under which names, and at which seat, read off the * plan's text alone (no filesystem): the `>`-family redirections and a `sed` script's `w` files, the operands of the * write commands ({@link SHELL_WRITE_COMMANDS}), a copy's or a move's destination children (GNU's argument grammar), an * in-place `sed`'s backups, and the seat each is written at ({@link WriteSeat}: the directory entry, or where the path * lands). The establisher (`shell-read-establish.ts`) places what this module names; the judge reads the result on the * deny table's write face; the station's `writesPlaced` fact reads the option readers exported here. */ import type { ReadCandidate, ShellReadSegment } from "./shell-read-plan.js"; /** * The commands whose operands are WRITE targets — the reference implementation's path-checked commands whose operation * is a write or a create (`mkdir` / `touch` create; `rm` / `rmdir` / `mv` / `cp` / `tee` write; `sed` writes when it * edits in place). Every operand counts (a `cp` source is judged as a write too, as the reference judges it): the write * face only ever REFUSES, so a word read as a target it is not costs a refusal of a command that names a denied path. */ export declare const SHELL_WRITE_COMMANDS: readonly ["mkdir", "touch", "rm", "rmdir", "mv", "cp", "tee", "sed"]; /** * Does an option WORD spell this option — the long name or any abbreviation of it GNU getopt accepts (`--in-p`, `--fi`, * `--par`: an unambiguous prefix, `=value` allowed), or the short letter alone or inside a bundle (`-i`, `-ni`, `-i.bak`)? * Read in the tightening direction: a prefix that another long option shares still counts (the program would refuse it). */ export declare function spellsOption(word: string, long: string, short: string): boolean; /** A word of a program's argv: its raw spelling (the plan's candidates are keyed by it) and its folded spelling. */ export interface ArgWord { readonly raw: string; readonly spelled: string; } /** The words a segment hands its program — the argv after the program word (a launcher's own words are not the program's). */ export declare function programArgs(segment: ShellReadSegment): ArgWord[]; /** What a `sed` invocation's option words say about writing, under either grammar ({@link SED_GRAMMARS}): whether it edits * in place (`-i` / `-I` / `--in-place`), the backup suffixes it is given (their values; an empty value keeps no backup), * and whether GNU `--follow-symlinks` is on. */ export interface SedOptions { readonly inPlace: boolean; readonly suffixes: readonly string[]; readonly followsLinks: boolean; } export declare function sedOptionsOf(segment: ShellReadSegment): SedOptions; /** * The BACKUP names an in-place `sed` gives the file it knows as `name` — both readings a suffix has: GNU sed replaces every * `*` in the suffix with the name (`bak/*` on `d/f` is `bak/d/f`, `/elsewhere/*` is `/elsewhere/d/f`) and appends a suffix * without one (`d/f.bak`); the BSD and BusyBox seds append the suffix literally (`d/f` + `bak/*`). A name resolves against * the working directory like the operand itself, so a suffix carrying a separator places the backup wherever it points. */ export declare function sedBackupNames(name: string, suffix: string): string[]; /** * WHERE a write reaches a path it names. `landing` — the path followed through every link to where it lands: the program * opens the path and writes through it. `entry` — the directory entry itself, the canonical parent joined with the last * name: the program renames over the entry, unlinks it or replaces it, and a link there is not followed (a name ending in * a separator, `.` or `..` resolves itself, so it lands). */ export type WriteSeat = "landing" | "entry"; /** One candidate handed to the judge. `seats`: where a write target is established ({@link WriteSeat}; absent ⇒ it lands — * every read does). `written`: the seats among `seats` the program itself WRITES the target at (absent ⇒ all of them; * `[]` ⇒ none — a copy's source, judged on the write face as a write path and read by the program); the write guards are * asked about these alone. `child`: a copy's or a move's destination child, written only where the destination is a * directory when the program runs. `followed`: a GNU sed `--follow-symlinks` backup — its names are {@link sedBackupNames} * of the operand's FOLLOWED name, which only the filesystem answers (the candidate's own spelling is the operand's as * written, the identity the pre-spawn re-check compares). */ export interface JudgedCandidate { readonly candidate: ReadCandidate; readonly seats?: readonly WriteSeat[]; readonly written?: readonly WriteSeat[]; readonly child?: true; readonly followed?: { readonly operand: ReadCandidate; readonly suffix: string; }; } /** Every candidate a segment hands the judge: its reads minus the write targets, plus its `cd` target (the plan already * lists it among the reads), plus its WRITE targets for the write face ({@link writeTargetsOf}), plus the deny-floor * shadow of every unplaced home word ({@link denyFloorShadowsOf}) on both faces. */ export declare function judgedCandidatesOf(segment: ShellReadSegment): readonly JudgedCandidate[];