/** * * `peaks best-practice-scan --intent --project [--lang ] [--commit]` * * Pipeline: * 1. detect language via language-detector (or use --lang override) * 2. scan via scan-orchestrator (Context7 → WebSearch → empty) * 3. render 8-row table via output-formatter * 4. write artifact into /best-practice/-.md * (gitignored directory by convention; --commit flag reserved for * a future slice that opts the artifact into git tracking) * 5. print artifact path + the 8-row table to stdout * * `--intent` is REQUIRED: it is the business goal the scan is for (Step 2.5 * fires from a non-empty business goal), and it is what the artifact slug is * derived from. The project path is NOT an intent — falling back to it was * the defect this command was fixed for (a `.`-titled "best-practice scan"). * Omitting `--intent` fails with `BEST_PRACTICE_SCAN_INTENT_REQUIRED`. * * Honesty gate: the built-in Context7 / WebSearch lookups are stubs, so an * uninjected scan comes back `synthetic: true` (see scan-orchestrator). A * synthetic result is NOT a scan result — the command then prints a refusal (no * table, no recommendation, no ⚠️ catch gate), records the skip, and exits * non-zero with `BEST_PRACTICE_SCAN_SYNTHETIC_LOOKUP` so no automated caller can * treat Step 2.5 as satisfied. Two further outcomes also refuse non-zero, both * without rendering: a `--lookup-results` document that breaks the injection * contract (`BEST_PRACTICE_SCAN_INVALID_RESULTS`) and a scan that resolved * against caller-supplied lookups and found nothing * (`BEST_PRACTICE_SCAN_NO_FRAGMENTS` — see `emitNoFragmentsRefusal`, which is * the guard against a `★` recommendation built from zero fragments). * * Collision refusal: the artifact path keys on `(date, slug)` with the slug * capped at 32 characters, so two intents that agree in their first 32 slug * characters land on one file. The second scan refuses * (`BEST_PRACTICE_SCAN_SLUG_COLLISION`) rather than overwrite the first. * * Catch-gate (spec §7): the command emits a 3-line prompt asking the * user to ack / pick alt / reject + reason. The gate is read from * stdin via `PEAKS_BEST_PRACTICE_STDIN` (test seam) or the real stdin * (production). The result is written to stdout as a JSON envelope * suffix so the orchestrator can react programmatically. */ import type { Command } from 'commander'; import { type ProgramIO } from '../cli-helpers.js'; import { type RecommendationChoice } from '../../services/best-practice/output-formatter.js'; export type CatchGateOutcome = { kind: 'accept'; choice: RecommendationChoice; } | { kind: 'alternative'; choice: RecommendationChoice; reason?: string; } | { kind: 'reject'; reason: string; }; export declare function parseCatchGateReply(raw: string, recommended: RecommendationChoice): CatchGateOutcome; export declare function registerBestPracticeScanCommand(program: Command, io: ProgramIO): void;