/** * Deterministic weak-model-safety lint for aih's OWN generated markdown (the * Layer-2 canon: RULE_ROUTER, bootloaders, adapters, Kiro steering). * * Regex rules and word lists are ported verbatim from @razroo/isolint v1.4.1 * (MIT — https://github.com/razroo/isolint, `dist/lint/rules/deterministic.js`): * soft-imperative, taste-word, ambiguous-deictic, enum-without-list, * trailing-etc, context-budget, placeholder-leftover. Reference resolution is * adapted to aih's planned-path model: aih KNOWS the set of files a plan will * write, so a forward reference to a not-yet-written canon file resolves on a * fresh repo (strictly better than isolint's repo-walk). `skeleton-unfilled` is * aih-native (isolint's placeholder rule is a deliberate no-op on aih's * `_italic_` skeletons). * * No AST, no mdast dependency, no LLM — pure regex over content aih authored. */ /** A finding's weight. `fail` flips the verify exit code; `info` is report-only. */ export type LintSeverity = "fail" | "info"; export interface LintFinding { ruleId: string; severity: LintSeverity; message: string; } /** Context a rule needs: where it lives + how to resolve a file reference. */ export interface LintRuleCtx { /** Repo-relative (POSIX) path of the doc being linted. */ path: string; /** Canonical POSIX paths this plan will write (forward refs resolve against it). */ plannedPaths: ReadonlySet; /** existsSync(join(root, relPath)) — for refs to pre-existing repo files. */ fileExists: (relPath: string) => boolean; /** * The canon context dir (e.g. `ai-coding`). `canon-ref-resolves` enforces * resolution only for CANON references — bare basenames or paths under this dir. * A slashed ref pointing elsewhere (`apps/x`, `.claude/y`, `src/z`) is the doc * citing repo evidence, not a broken canon link, so it is left alone. */ contextDir: string; } export interface LintRule { id: string; severity: LintSeverity; /** Gate a rule to the docs it makes sense for (by repo-relative path). */ appliesTo: (path: string) => boolean; run: (src: string, ctx: LintRuleCtx) => LintFinding[]; } type Interval = [number, number]; /** * Byte ranges a prose rule must NOT scan: fenced code blocks, inline code spans, * and HTML comments. Mirrors isolint's `computeSkipIntervals` (fenced + inline) * plus HTML comments (aih wraps its managed blocks in ``). */ export declare function skipIntervals(src: string): Interval[]; export declare const RULES: LintRule[]; /** Run every applicable rule over one doc. */ export declare function lintDoc(path: string, source: string, ctx: LintRuleCtx): LintFinding[]; export {};