import { type AppGraph } from "./app-graph.js"; import { type UxAuditReport } from "../ux/tenets-traps.js"; import { type ComplianceReport } from "../ux/skill-compliance.js"; import { type ResolvedPolicy } from "./policy.js"; export type AppQualitySeverity = "critical" | "high" | "medium" | "low"; export type AppQualityCategory = "visual-system" | "typography" | "spacing" | "color" | "components" | "accessibility" | "responsive" | "maintainability"; export interface AppQualityIssue { id: string; category: AppQualityCategory; severity: AppQualitySeverity; title: string; detail: string; evidence: string[]; recommendation: string; evidenceLocations?: Array<{ file: string; line?: number; excerpt?: string; }>; affectedFiles?: string[]; confidence?: number; estimatedEffort?: "small" | "medium" | "large"; fixCategory?: "tokens" | "components" | "accessibility" | "responsive" | "code-health"; } export interface AppQualityDirection { id: string; name: string; fit: string; tokenMoves: string[]; componentMoves: string[]; patchScope: string[]; } export interface AppQualityFileSignal { path: string; kind: "component" | "route" | "style" | "config" | "markup"; classCount: number; shadcnImports: string[]; hexColors: string[]; cssVariables: string[]; } export interface AppQualityDiagnosis { version: 1; target: string; generatedAt: string; summary: { score: number; verdict: string; scannedFiles: number; routes: number; components: number; styleFiles: number; tailwindClasses: number; shadcnImports: number; cssVariables: number; hexColors: number; scannedBytes?: number; scanMs?: number; analysisMs?: number; }; scores: Record; files: AppQualityFileSignal[]; issues: AppQualityIssue[]; ux: UxAuditReport; directions: AppQualityDirection[]; nextActions: string[]; appGraph?: { routes: number; components: number; imports: number; shadcnComponents: string[]; package: AppGraph["package"]; graphMs?: number; }; /** Post-hoc verification of real source files against skills/ATOMIC_DESIGN.md and skills/MOTION_VIDEO_DESIGN.md's checkable rules. */ compliance?: ComplianceReport; /** The policy this diagnosis was produced under — scores are only comparable across identical policy hashes. */ policy?: { hash: string; source: "default" | "file"; preset: string; }; /** * Present when the scan was PR-scoped. Scores remain whole-tree (labeled * scan-scoped for trend purposes); `issues` contains only scoped findings. */ scope?: { base?: string; requestedFiles: number; effectiveFiles: number; expandedWithDependents: boolean; emittedIssues: number; filteredOutIssues: number; }; } interface ScanOptions { target?: string; projectRoot: string; maxFiles?: number; write?: boolean; /** Resolved policy (thresholds, rule overrides). Defaults to the built-in memi-recommended policy. */ policy?: ResolvedPolicy; /** * PR scope: whole-tree stats/scores are STILL computed (thresholds stay * meaningful), but emitted issues are filtered to those touching these * repo-relative files. Aggregate issues with no file anchor are dropped * from the scoped issue list — they gate via score budgets, not per-file * blame. expandImports adds one hop of dependents via the app graph. */ scope?: { files: string[]; base?: string; expandImports?: boolean; }; } export declare function diagnoseAppQuality(options: ScanOptions): Promise; export declare function hasDiagnosis(projectRoot: string): Promise; export {};