import { type StateEntry, type StateFact, type StateNeed } from "./hook-state.js"; /** The closed set of built-in facts a gate may declare via `needs`, with value types. */ export interface ProviderResults { /** The current git branch, or "" outside a git repo / on an unborn HEAD. */ readonly "git.branch": string; /** True iff the working tree has uncommitted changes (false if not a repo). */ readonly "git.isDirty": boolean; /** The repo's top-level directory, or "" outside a git repo. */ readonly "git.root": string; /** The directory the hook runs in. */ readonly cwd: string; /** The OS platform (`process.platform`: "darwin" | "linux" | "win32" | …). */ readonly "os.platform": NodeJS.Platform; /** True iff running on a CI server (detected via the `ci-info` library). */ readonly "env.isCI": boolean; } /** A declarable built-in provider name. */ export type ProviderName = keyof ProviderResults; /** * An INLINE one-off provider: a command declared right in `needs` (no registered * file), run by the trusted runtime, its stdout becoming `e.ctx[name]` (a string). * `dangerous` marks the loud escape — a command not provably read-only. Built via * {@link provide} (read-only) or {@link dangerously} (acknowledged). */ export interface InlineProvider { readonly kind: "inline"; readonly name: Name; readonly run: string; readonly dangerous: boolean; } /** * A `needs` entry — a built-in name, an inline `provide`/`dangerously`, a * `provider()` ref, or a `state()` read of a fact some hook recorded. * * `state()` rides this union rather than getting its own accessor so that ALL of * a hook's external inputs stay in one declared list: the dependency is auditable * from outside the hook, and reading an undeclared one is a `tsc` error. See the * design note in `hook-state.ts`. */ export type NeedSpec = ProviderName | InlineProvider | RegisteredRef | StateNeed; /** * Declare an INLINE read-only fact: `provide("k8sCtx", "kubectl config current-context")`. * The command MUST be provably read-only (compile rejects it otherwise — use * {@link dangerously} to acknowledge a side-effecting/undecidable one). Its stdout * is `e.ctx[name]`. */ export declare const provide: (name: Name, run: string) => InlineProvider; /** * Declare an INLINE fact whose command ISN'T provably read-only — the loud, * greppable escape hatch (the `dangerouslySetInnerHTML` / `unsafe` / `http.send` * convention; sibling of `purity:'dangerously-unrestricted'`). A security review * searches for this one word. */ export declare const dangerously: (name: Name, run: string) => InlineProvider; /** * A REGISTERED provider — a reusable, named fact authored once in * `.vigiles/providers/.provider.{mjs,ts}` (default-exported via {@link defineProvider}) * and referenced from many hooks by {@link provider} name. The reusable sibling of * the one-off inline {@link provide}; same read-only-by-default rule. */ export interface RegisteredProvider { readonly kind: "provider-def"; readonly name: Name; readonly run: string; readonly dangerous: boolean; } /** Author a registered provider: `export default defineProvider({ name, run })`. */ export declare const defineProvider: (p: { readonly name: Name; readonly run: string; /** Acknowledge a command that isn't provably read-only (the loud escape). */ readonly dangerous?: boolean; }) => RegisteredProvider; /** A reference to a registered provider, used in a hook's `needs`: `provider("myFact")`. */ export interface RegisteredRef { readonly kind: "provider-ref"; readonly name: Name; } /** Reference a registered provider (from `.vigiles/providers/`) by name in `needs`. */ export declare const provider: (name: Name) => RegisteredRef; /** name → its registered provider; the runtime resolves a `provider(name)` ref against this. */ export type ProviderRegistry = Record; type NeedName = E extends ProviderName ? E : E extends InlineProvider ? Nm : E extends RegisteredRef ? Rn : E extends StateNeed ? Sn : never; type NeedValue = E extends ProviderName ? ProviderResults[E] : E extends StateNeed ? StateFact : string; /** * The typed `e.ctx` for a hook that declared `needs: N` — ONLY the declared facts * are present (built-in name → its typed value, inline → string), so reading an * undeclared one is a `tsc` error (the typed-purity trick). With `N = readonly []` * the ctx is empty. The default `readonly ProviderName[]` is the erased runtime * shape (built-ins only — an inline `string` name would force an index signature * that clashes with `git.isDirty: boolean`; concrete authored inline names are * literals, so they never clash). */ export type HookCtx = { readonly [E in N[number] as NeedName]: NeedValue; }; /** The read-only capabilities a provider may use to gather its fact. */ export interface ProviderIO { /** Run a read-only command, return stdout (throws on non-zero exit). */ readonly exec: (command: string) => string; /** The hook's working directory. */ readonly cwd: string; /** The OS platform (`process.platform`). */ readonly platform: NodeJS.Platform; /** Whether the process is on a CI server (the CLI injects `ci-info`'s verdict). */ readonly isCI: boolean; /** * Read one recorded fact from THIS hook's state namespace, or `null` if it was * never recorded. The namespace is resolved by the caller, so a key can never * address another owner's store — see `hook-state.ts`. */ readonly readState: (key: string) => StateEntry | null; /** Epoch milliseconds, injected so fact ages are pinnable in a test. */ readonly now: number; } interface ProviderDef { /** * The read-only command the provider runs (for audit + the read-only * soundness test). Absent for an ambient fact gathered without a subprocess. */ readonly run?: string; /** Produce the fact; TOTAL — returns a sensible default on failure, never throws. */ readonly gather: (io: ProviderIO) => ProviderResults[K]; } /** The closed built-in registry. Each `run` is provably read-only (see the test). */ export declare const BUILTIN_PROVIDERS: { readonly [K in ProviderName]: ProviderDef; }; /** * `needs` entries that don't resolve: a built-in NAME that isn't a built-in (a * typo), or a `provider()` ref whose name isn't in `registeredNames` (a dangling * ref). Inline `provide`/`dangerously` are always self-defined, so never flagged. */ export declare function unknownProviders(needs: readonly NeedSpec[], registeredNames?: readonly string[]): string[]; /** * Inline `provide()` entries whose command ISN'T provably read-only — these must * switch to `dangerously()` (the acknowledged escape) or compile is rejected. A * `dangerously()` entry is never flagged (it already acknowledged the risk). */ export declare function unsafeInlineProviders(needs: readonly NeedSpec[]): InlineProvider[]; /** * Is a REGISTERED provider's command unsafe (not read-only and not acknowledged * `dangerous`)? Reused when compiling a `.vigiles/providers/` file. */ export declare function unsafeProvider(def: RegisteredProvider): boolean; /** * Gather the DECLARED facts into a context object (the trusted-host step). Only * the names in `needs` are gathered, each at most once; a built-in, inline, or * registered provider that can't resolve yields its default ("" / false), never * throws. Pure over the injected `io` (CLI passes a real execSync; tests a fake) * and the `registry` (the loaded `.vigiles/providers/`, for `provider()` refs). */ export declare function gatherContext(needs: readonly NeedSpec[], io: ProviderIO, registry?: ProviderRegistry): Record; export {}; //# sourceMappingURL=hook-providers.d.ts.map