/** * The known-flag registry, and the rejection of everything else. * * ## The defect this closes * * Every subcommand parsed its own flags by asking `args.includes("--x")` and * ignored the rest. So a typo was accepted in silence: * * ``` * $ npx vigiles audit --this-flag-does-not-exist * Detected harness: claude-code * …a complete, confident audit… * EXIT=0 * ``` * * That is not cosmetic, because audit's flags govern what LEAVES THE MACHINE: * `--no-html`, `--no-json`, `--out=`, `--serve`. `--no-htlm` writes the HTML * report while the author believes they suppressed it. For a tool whose thesis is * that a stated rule is not an enforced one, accepting an argument it did not understand and carrying * on is the same class of error it names elsewhere: the argument is PRESENT, so * the property is assumed enforced. * * The sharper case, observed: `vigiles audit --json /some/path`. `--json` is real * but takes no value, so the PATH fell through to the positional scan directory. * The audit then ran over a directory with no harness in it and reported * "No loadable harness surface — nothing to grade yet", `skills: 0`, grade F, * exit 0 — output indistinguishable from a genuine audit of a repo that scores * badly. A confident measurement OF THE WRONG OBJECT, silently. * * ## Why a table and not a parser library * * The flags are already parsed at their point of use, and moving that would be a * large behavioural change for a validation fix. This adds the ONE thing the * ad-hoc parsing cannot do — say no to what it doesn't recognise. A dogfood test * (src/scan-cli.test.ts, "every flag the help text advertises is accepted") * drives the real `vigiles --help` and asserts the table hasn't drifted from it, * so a flag documented but not registered is a test failure rather than a * rejection in a user's face. */ import type { Verb } from "./cli-commands.js"; /** * A known flag. `--foo` is a bare switch; `--foo=` takes a value with `=` * (`flagValue()` only ever reads the `=` form, so a space-separated value is * genuinely NOT supported and must not be silently accepted). */ export type FlagSpec = string; /** * Flags every verb accepts: the config overrides applied in `main()` before * dispatch (see `applyConfigFlags`) plus the harness override, which the shared * `harnessFlagFrom` reads for lint/compile/audit/generate/init. */ export declare const SHARED_FLAGS: readonly FlagSpec[]; /** * Per-verb flags, derived from what each handler actually READS (not from the * help text — the help text is checked AGAINST this, in src/scan-cli.test.ts). */ export declare const COMMAND_FLAGS: Record; /** Every flag this verb knows, shared ones included. */ export declare function knownFlagsFor(command: string): readonly FlagSpec[]; /** * Args that look like flags but no spec accepts. `--` (the argv terminator) and * anything after it are left alone; a lone `-` is a positional by convention. */ export declare function unknownFlags(command: string, argv: readonly string[]): string[]; /** * The closest known flag to a typo, or undefined when nothing is close enough. * The threshold is deliberately tight — a wrong suggestion is worse than none, * because it invites the reader to "fix" a flag they never meant to type. */ export declare function nearestFlag(unknown: string, known: readonly FlagSpec[]): string | undefined; /** The message printed to stderr for one unrecognised flag. */ export declare function formatUnknownFlag(command: string, flag: string): string; /** * Which of a verb's arguments name a PATH. The CLI runs every command from the * project root it resolves once (`findProjectRoot`), but a path the user types * means "from where I typed it"; these are the arguments re-expressed from the * root before the command runs. One table beside the flag table, so a new * path-valued flag is declared where flags are. */ interface PathArguments { /** * Which directory the verb runs from. `project`: the resolved project root. * `invocation`: where it was typed — `init` makes THAT directory a project * (a workspace member it sets up must not become its monorepo's root), and * `hook-runtime` takes its root from the harness event, not from a directory. */ readonly root: "project" | "invocation"; /** Positionals that are paths: all of them, all after the first (a kind), or none. */ readonly positionals: "all" | "after-first" | "none"; /** `--flag=` specs whose value is a path. */ readonly flags: readonly FlagSpec[]; } export declare const PATH_ARGUMENTS: Readonly>; /** * Whether `command` runs from the resolved project root. A word that is not a * verb (`--version`, a typo) runs nowhere in particular: it is answered where * it was typed. */ export declare function runsFromProjectRoot(command: string): boolean; /** * The verb's arguments (everything after the verb) with each path argument * passed through `rebase`. Flags that do not take a path, words, and `--` * itself are returned unchanged. After `--` every word is an operand: a path * among them is rebased like any other positional, and a dash-led one is never * mistaken for a path-valued flag. */ export declare function rebasePathArgs(command: string, argv: readonly string[], rebase: (path: string) => string): readonly string[]; export {}; //# sourceMappingURL=cli-flag-check.d.ts.map