/** * skillsFromDirRoutes — the `routes:` half of the on-disk runbook grammar. * * ## What a file may say about routing, and why it is this little * * `skillsFromDir` reads prose, `tools:` and `steps:` — everything about ONE * skill — and stopped exactly where the value was supposed to start: the * routing. A directory of runbooks still had to be hand-wired into a graph in * code, which is the work the graph exists to remove. * * This module adds the missing key under the SAME security law the tools list * follows: **the file PICKS, it never DEFINES.** * * --- * name: billing * tools: lookup_order, issue_refund * routes: * - escalation: on issue_refund status=denied * - receipts: on issue_refund * - audit * --- * * A route names a SKILL ID and, optionally, a guard. Both halves are picks: * * • the id is resolved against the skills THIS DIRECTORY declares — an id * nothing here declares is refused at load, by name, listing what is * available. Never a half-graph: one bad id fails the whole load, because * a graph missing one edge routes silently wrong, which is worse than a * graph that refuses to exist; * • the guard is one of the two DATA conditions a route already has * (`onToolReturn`, `onToolStatus`), and the tool it names must be one of * this file's own `tools:` — the same law `steps:` follows, for the same * reason (an edge out of this skill fires on this skill's work). * * Nothing is evaluated, imported or resolved as a path. The strings can only * MATCH — against ids the loader already read off disk and against a closed * status vocabulary. * * ## What a file CANNOT express, said plainly * * A `when:` predicate is CODE. There is no honest way for a markdown file to * carry it: reading one would mean evaluating a string, which is the one thing * this loader exists never to do. So the grammar has no `when` and no * expression language of any kind — a conditional a file cannot express is a * conditional that stays in code: * * skillGraph({ skills, steps: [{ from: 'billing', to: 'escalation', * when: r => JSON.parse(r.result).tier > 2 }] }); * * Anything that is not one of the three forms is refused with the whole grammar * quoted, rather than half-understood by a parser inventing a mini-language. * * Zone: HOST (it belongs to the file loader). Pure over strings all the same — * it reads no filesystem; `skillsFromDir.ts` hands it the parsed lines. */ import type { SkillGraphStep } from './skillGraph.js'; import { type ToolResultStatus } from './toolOutcome.js'; /** * One frontmatter list item, structurally — `skillsFromDir`'s module-private * `ListItem` satisfies it unchanged, so the two never import each other. */ export interface RouteItem { /** Text before the first `:` — the target skill id. */ readonly key: string; /** Text after the first `:` — the guard. Undefined when the item has none. */ readonly value?: string; /** 1-based line number in the file. Every refusal quotes it. */ readonly line: number; } /** One route as the FILE declared it: a target id and a parsed guard. The id is * still unresolved here — a file cannot know what the rest of the directory * carries, so that refusal waits for {@link toGraphSteps}. */ export interface DeclaredRoute { readonly to: string; readonly onToolReturn?: string; readonly onToolStatus?: readonly ToolResultStatus[]; readonly line: number; } /** * Read one file's `routes:` items into declared routes, refusing every shape * the grammar does not carry. Pure; every message names the file and the line, * because "malformed routes" over a directory of forty runbooks has told the * author nothing. * * @param items the `routes:` block-list items, in file order. * @param file the path, quoted by every refusal. * @param toolNames this file's own `tools:` — a guard may only name one of * them (undefined when the file declared no tools at all). */ export declare function readDeclaredRoutes(items: readonly RouteItem[], file: string, toolNames: readonly string[] | undefined): readonly DeclaredRoute[]; /** * Resolve one file's declared routes into graph steps, refusing an id no * SKILL.md in the directory declares. * * The refusal lists what IS available and fails the whole load. A route to a * name nothing declares is the one mistake that cannot be reported later: the * loader would return a skill set the graph then wires with a missing edge, and * a graph that silently does not route is exactly the failure the check-up * exists to prevent. Half a graph is not a smaller version of the graph. * * @param from the id of the skill whose file declared these routes. * @param file that skill's path, quoted by the refusal. * @param known every skill id the directory declared. */ export declare function toGraphSteps(from: string, routes: readonly DeclaredRoute[], file: string, known: ReadonlySet): readonly SkillGraphStep[]; //# sourceMappingURL=skillsFromDirRoutes.d.ts.map