taste-lint 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +141 -0
  3. package/data/config.schema.json +123 -0
  4. package/data/corpus/blode-co-review.jsonl +80 -0
  5. package/data/corpus/copywriting.jsonl +139 -0
  6. package/data/corpus/typography.jsonl +53 -0
  7. package/data/rule-drafts/README.md +9 -0
  8. package/data/rule-drafts/interaction/interaction-layout-shift.yaml +54 -0
  9. package/data/rule-drafts/typography/typography-long-content-safety.yaml +60 -0
  10. package/data/rules/authoring/authoring-approval-every-step.yaml +44 -0
  11. package/data/rules/authoring/authoring-fixed-agent-quota.yaml +44 -0
  12. package/data/rules/authoring/authoring-generic-coding-advice.yaml +44 -0
  13. package/data/rules/authoring/authoring-generic-verification.yaml +45 -0
  14. package/data/rules/authoring/authoring-plan-vague-acceptance.yaml +43 -0
  15. package/data/rules/copywriting/copywriting-announced-honesty.yaml +43 -0
  16. package/data/rules/copywriting/copywriting-anthropomorphism.yaml +29 -0
  17. package/data/rules/copywriting/copywriting-artificial-balance.yaml +35 -0
  18. package/data/rules/copywriting/copywriting-bare-confirm-label.yaml +23 -0
  19. package/data/rules/copywriting/copywriting-boilerplate-offer.yaml +38 -0
  20. package/data/rules/copywriting/copywriting-canned-phrasing.yaml +53 -0
  21. package/data/rules/copywriting/copywriting-changed-supplied-facts.yaml +31 -0
  22. package/data/rules/copywriting/copywriting-claim-without-evidence.yaml +59 -0
  23. package/data/rules/copywriting/copywriting-click-here-links.yaml +22 -0
  24. package/data/rules/copywriting/copywriting-conditions-first.yaml +50 -0
  25. package/data/rules/copywriting/copywriting-confirmshaming.yaml +43 -0
  26. package/data/rules/copywriting/copywriting-cta-names-outcome.yaml +54 -0
  27. package/data/rules/copywriting/copywriting-dead-weight-hedges.yaml +58 -0
  28. package/data/rules/copywriting/copywriting-drafting-instruction-echo.yaml +31 -0
  29. package/data/rules/copywriting/copywriting-emoji-in-ui.yaml +20 -0
  30. package/data/rules/copywriting/copywriting-empty-state-no-action.yaml +51 -0
  31. package/data/rules/copywriting/copywriting-error-descriptions.yaml +53 -0
  32. package/data/rules/copywriting/copywriting-excessive-hedging.yaml +48 -0
  33. package/data/rules/copywriting/copywriting-fabricated-specificity.yaml +35 -0
  34. package/data/rules/copywriting/copywriting-filler-words.yaml +55 -0
  35. package/data/rules/copywriting/copywriting-flat-description.yaml +37 -0
  36. package/data/rules/copywriting/copywriting-friction-cta.yaml +53 -0
  37. package/data/rules/copywriting/copywriting-generic-audience.yaml +55 -0
  38. package/data/rules/copywriting/copywriting-generic-framing.yaml +35 -0
  39. package/data/rules/copywriting/copywriting-generic-language.yaml +35 -0
  40. package/data/rules/copywriting/copywriting-generic-validation.yaml +46 -0
  41. package/data/rules/copywriting/copywriting-idea-repetition.yaml +34 -0
  42. package/data/rules/copywriting/copywriting-latinisms.yaml +25 -0
  43. package/data/rules/copywriting/copywriting-leaked-error-message.yaml +23 -0
  44. package/data/rules/copywriting/copywriting-live-region-feedback.yaml +24 -0
  45. package/data/rules/copywriting/copywriting-machine-prose.yaml +73 -0
  46. package/data/rules/copywriting/copywriting-mechanism-over-outcome.yaml +33 -0
  47. package/data/rules/copywriting/copywriting-meta-commentary.yaml +48 -0
  48. package/data/rules/copywriting/copywriting-missing-reasoning-link.yaml +33 -0
  49. package/data/rules/copywriting/copywriting-nominalisations.yaml +45 -0
  50. package/data/rules/copywriting/copywriting-over-explanation.yaml +34 -0
  51. package/data/rules/copywriting/copywriting-passive-voice.yaml +53 -0
  52. package/data/rules/copywriting/copywriting-permission-benefit.yaml +43 -0
  53. package/data/rules/copywriting/copywriting-profile-register-mismatch.yaml +31 -0
  54. package/data/rules/copywriting/copywriting-promotional-docs-voice.yaml +58 -0
  55. package/data/rules/copywriting/copywriting-prompt-restatement.yaml +35 -0
  56. package/data/rules/copywriting/copywriting-punctuation-tics.yaml +35 -0
  57. package/data/rules/copywriting/copywriting-reader-first.yaml +59 -0
  58. package/data/rules/copywriting/copywriting-register-shift.yaml +58 -0
  59. package/data/rules/copywriting/copywriting-repetitive-transitions.yaml +48 -0
  60. package/data/rules/copywriting/copywriting-requirements-language.yaml +50 -0
  61. package/data/rules/copywriting/copywriting-searchable-headings.yaml +52 -0
  62. package/data/rules/copywriting/copywriting-semantic-links.yaml +23 -0
  63. package/data/rules/copywriting/copywriting-structural-symmetry.yaml +35 -0
  64. package/data/rules/copywriting/copywriting-success-state-specific.yaml +43 -0
  65. package/data/rules/copywriting/copywriting-temporal-words.yaml +55 -0
  66. package/data/rules/copywriting/copywriting-toast-successfully.yaml +22 -0
  67. package/data/rules/copywriting/copywriting-unexplained-action.yaml +33 -0
  68. package/data/rules/copywriting/copywriting-unnatural-polish.yaml +48 -0
  69. package/data/rules/copywriting/copywriting-unraised-objection.yaml +43 -0
  70. package/data/rules/copywriting/copywriting-unverifiable-proof.yaml +23 -0
  71. package/data/rules/copywriting/copywriting-vague-error.yaml +58 -0
  72. package/data/rules/copywriting/copywriting-vague-personal-request.yaml +43 -0
  73. package/data/rules/copywriting/copywriting-visual-direction-instruction.yaml +43 -0
  74. package/data/rules/craft/craft-affordance-mismatch.yaml +23 -0
  75. package/data/rules/craft/craft-decoration-no-role.yaml +27 -0
  76. package/data/rules/craft/craft-faux-product-chrome.yaml +22 -0
  77. package/data/rules/craft/craft-hover-only-affordance.yaml +23 -0
  78. package/data/rules/craft/craft-i18n-rtl-untested.yaml +23 -0
  79. package/data/rules/craft/craft-i18n-untested.yaml +28 -0
  80. package/data/rules/craft/craft-image-dimensions-and-priority.yaml +23 -0
  81. package/data/rules/craft/craft-inline-styles.yaml +24 -0
  82. package/data/rules/craft/craft-lazy-load-offscreen.yaml +28 -0
  83. package/data/rules/craft/craft-near-duplicate-scale.yaml +29 -0
  84. package/data/rules/craft/craft-token-drift.yaml +22 -0
  85. package/data/rules/craft/craft-viewport-scaling.yaml +25 -0
  86. package/data/rules/craft/craft-virtualize-large-lists.yaml +24 -0
  87. package/data/rules/interaction/interaction-a11y-color-only-meaning.yaml +23 -0
  88. package/data/rules/interaction/interaction-a11y-data-table-semantics.yaml +24 -0
  89. package/data/rules/interaction/interaction-a11y-disabled-control-tooltip.yaml +23 -0
  90. package/data/rules/interaction/interaction-a11y-document-language.yaml +24 -0
  91. package/data/rules/interaction/interaction-a11y-icon-controls-labeled.yaml +23 -0
  92. package/data/rules/interaction/interaction-a11y-image-alt-text.yaml +24 -0
  93. package/data/rules/interaction/interaction-a11y-media-captions.yaml +24 -0
  94. package/data/rules/interaction/interaction-a11y-semantic-html-first.yaml +23 -0
  95. package/data/rules/interaction/interaction-a11y-skip-link-heading-order.yaml +24 -0
  96. package/data/rules/interaction/interaction-a11y-tooltip-no-interactive.yaml +23 -0
  97. package/data/rules/interaction/interaction-broken-focus-trap.yaml +25 -0
  98. package/data/rules/interaction/interaction-dont-block-paste-ime.yaml +23 -0
  99. package/data/rules/interaction/interaction-error-association.yaml +24 -0
  100. package/data/rules/interaction/interaction-focus-visible.yaml +25 -0
  101. package/data/rules/interaction/interaction-inline-errors-first-focus.yaml +24 -0
  102. package/data/rules/interaction/interaction-input-affix-hit-target.yaml +23 -0
  103. package/data/rules/interaction/interaction-keyboard-operable.yaml +23 -0
  104. package/data/rules/interaction/interaction-labels-and-autocomplete.yaml +23 -0
  105. package/data/rules/interaction/interaction-lost-data-on-error.yaml +23 -0
  106. package/data/rules/interaction/interaction-mobile-input-font-size.yaml +24 -0
  107. package/data/rules/interaction/interaction-no-disable-while-submitting.yaml +23 -0
  108. package/data/rules/interaction/interaction-no-empty-state.yaml +26 -0
  109. package/data/rules/interaction/interaction-no-error-boundary.yaml +27 -0
  110. package/data/rules/interaction/interaction-no-error-state.yaml +26 -0
  111. package/data/rules/interaction/interaction-no-suspense-boundary.yaml +23 -0
  112. package/data/rules/interaction/interaction-not-restored.yaml +25 -0
  113. package/data/rules/interaction/interaction-on-dynamic-content.yaml +25 -0
  114. package/data/rules/interaction/interaction-optimistic-without-rollback.yaml +23 -0
  115. package/data/rules/interaction/interaction-out-of-order-responses.yaml +27 -0
  116. package/data/rules/interaction/interaction-target-size.yaml +26 -0
  117. package/data/rules/interaction/interaction-use-form-status-misuse.yaml +23 -0
  118. package/data/rules/product/product-nested-modals.yaml +26 -0
  119. package/data/rules/product/product-select-for-few-options.yaml +24 -0
  120. package/data/rules/schema/rule.schema.json +262 -0
  121. package/data/rules/tuning.json +1 -0
  122. package/data/rules/typography/typography-dashes.yaml +28 -0
  123. package/data/rules/typography/typography-ellipsis.yaml +27 -0
  124. package/data/rules/typography/typography-hover-weight-shift.yaml +24 -0
  125. package/data/rules/typography/typography-midpoint-separators.yaml +21 -0
  126. package/data/rules/typography/typography-multiplication-sign.yaml +27 -0
  127. package/data/rules/typography/typography-nbsp-value-unit.yaml +27 -0
  128. package/data/rules/typography/typography-readable-scale.yaml +23 -0
  129. package/data/rules/typography/typography-straight-quotes.yaml +37 -0
  130. package/data/rules/typography/typography-title-case-heading.yaml +49 -0
  131. package/dist/cli.d.ts +2 -0
  132. package/dist/cli.js +6317 -0
  133. package/dist/cli.js.map +1 -0
  134. package/dist/index.d.ts +736 -0
  135. package/dist/index.d.ts.map +1 -0
  136. package/dist/index.js +5330 -0
  137. package/dist/index.js.map +1 -0
  138. package/package.json +87 -0
@@ -0,0 +1,736 @@
1
+ //#region src/analysis/repository.d.ts
2
+ interface DocumentNode {
3
+ type: string;
4
+ value?: string;
5
+ url?: string;
6
+ identifier?: string;
7
+ depth?: number;
8
+ lang?: string | null;
9
+ children?: DocumentNode[];
10
+ position?: {
11
+ start: {
12
+ offset?: number;
13
+ };
14
+ end: {
15
+ offset?: number;
16
+ };
17
+ };
18
+ }
19
+ interface ImportFact {
20
+ name: string;
21
+ offset: number;
22
+ typeOnly: boolean;
23
+ }
24
+ interface SourceFacts {
25
+ document?: DocumentNode;
26
+ imports?: ImportFact[];
27
+ parseError?: string;
28
+ repository: Pick<Repository, "root" | "read" | "resolve" | "exists" | "manifest" | "policy">;
29
+ }
30
+ declare class Repository {
31
+ readonly root: string;
32
+ private readonly contents;
33
+ readonly policy?: ArchitecturePolicy;
34
+ constructor(root: string, policy?: ArchitecturePolicy);
35
+ resolve(file: string, target: string): string | undefined;
36
+ read(file: string): string | undefined;
37
+ exists(file: string): boolean;
38
+ manifest(file: string): {
39
+ file: string;
40
+ value: Record<string, unknown>;
41
+ } | undefined;
42
+ }
43
+ //#endregion
44
+ //#region src/types.d.ts
45
+ declare const DOMAINS: readonly ["typography", "craft", "copywriting", "interaction", "motion", "product", "architecture", "dx", "authoring"];
46
+ type Domain = (typeof DOMAINS)[number];
47
+ declare const UNIT_KINDS: readonly ["paragraph", "heading", "jsx-text", "attr-string", "class-list", "element",
48
+ /** The whole file, for mechanical-only regex rules over raw source. */
49
+ "source",
50
+ /** A file that did not parse; carries the error and nothing else. */
51
+ "file"];
52
+ /** Kinds that are not a piece of copy and never count as units in a report. */
53
+ declare const STRUCTURAL_KINDS: readonly UnitKind[];
54
+ type UnitKind = (typeof UNIT_KINDS)[number];
55
+ declare const TIERS: readonly ["mechanical", "jev", "both"];
56
+ type Tier = (typeof TIERS)[number];
57
+ declare const SEVERITIES: readonly ["major", "minor"];
58
+ type Severity = (typeof SEVERITIES)[number];
59
+ /** Lower is more severe; the single owner of severity ordering. */
60
+ declare const SEVERITY_RANK: Record<Severity, number>;
61
+ declare const RULE_STATUSES: readonly ["active", "draft", "review-only"];
62
+ type RuleStatus = (typeof RULE_STATUSES)[number];
63
+ declare const DOC_TYPES: readonly ["tutorial", "howto", "reference", "explanation", "agent-instructions", "lesson", "marketing", "ui", "readme", "skill", "plan", "personal", "pr", "slides", "unknown"];
64
+ type DocType = (typeof DOC_TYPES)[number];
65
+ declare const ROLES: readonly ["heading", "body", "list-item", "cell", "button", "link", "label", "placeholder", "aria", "literal-copy", "caption", "unknown"];
66
+ type Role = (typeof ROLES)[number];
67
+ declare const CONTEXT_KEYS: readonly ["section", "headingAbove", "docType", "element", "role", "neighbours", "writingFacts", "writingProfile", "writingInstructions"];
68
+ type ContextKey = (typeof CONTEXT_KEYS)[number];
69
+ type Band = "act" | "review" | "silent";
70
+ interface RuleSource {
71
+ repo: string;
72
+ path: string;
73
+ line: number;
74
+ ruleId?: string;
75
+ }
76
+ interface Mechanical {
77
+ /** JavaScript regex source. Compiled with `flags` (default "gu"). */
78
+ regex?: string;
79
+ flags?: string;
80
+ /** Case-insensitive whole-phrase list. Word-boundary checked. */
81
+ phrases?: string[];
82
+ /** Minimum matches before the rule fires (default 1). */
83
+ minMatches?: number;
84
+ /** The rule fires only when this regex matches nowhere in the unit. */
85
+ absent?: string;
86
+ }
87
+ interface CriterionSide {
88
+ what: string;
89
+ examples: string[];
90
+ }
91
+ interface Question {
92
+ instructions: string;
93
+ criteria?: {
94
+ true: CriterionSide;
95
+ false: CriterionSide;
96
+ };
97
+ /** Context keys to include in the state for this question. */
98
+ context?: ContextKey[];
99
+ }
100
+ interface Thresholds {
101
+ review: number;
102
+ act: number;
103
+ }
104
+ interface Fix {
105
+ hint: string;
106
+ /** Named function in src/reduce/fixes.ts; present means `--fix` can apply it. */
107
+ function?: string;
108
+ }
109
+ interface Preconditions {
110
+ notInCode?: boolean;
111
+ docType?: DocType[];
112
+ role?: Role[];
113
+ /** Skip Markdown units when the project curls quotes at build time. */
114
+ smartQuotesAtBuild?: false;
115
+ }
116
+ interface Rule {
117
+ id: string;
118
+ title: string;
119
+ categoryId: string;
120
+ domain: Domain;
121
+ source: RuleSource;
122
+ /** Resolved: include derived from `unit` unless the rule names it. */
123
+ scope: {
124
+ include: string[];
125
+ exclude: string[];
126
+ };
127
+ unit: UnitKind[];
128
+ /** Derived: mechanical only, question only, or both. */
129
+ tier: Tier;
130
+ mechanical?: Mechanical;
131
+ question?: Question;
132
+ thresholds: Thresholds;
133
+ severity: Severity;
134
+ fix: Fix;
135
+ preconditions?: Preconditions;
136
+ status: RuleStatus;
137
+ handWritten: string[];
138
+ /** Absolute path of the YAML file the rule was loaded from, or `code:<module>`. */
139
+ file: string;
140
+ /**
141
+ * A code rule's check, in place of `mechanical`. Counts, compares and
142
+ * measures; throws UnresolvedError to abstain. Data rules never set it.
143
+ */
144
+ check?: (unit: Unit) => MechanicalHit;
145
+ }
146
+ interface TuningEntry {
147
+ act?: number;
148
+ status?: RuleStatus;
149
+ precisionLower?: number;
150
+ n?: number;
151
+ ts?: string;
152
+ }
153
+ type Tuning = Record<string, TuningEntry>;
154
+ interface ResolvedTypography {
155
+ fontSizePx?: number;
156
+ lineHeight?: number;
157
+ lineHeightPx?: number;
158
+ letterSpacingEm?: number;
159
+ fontWeight?: number;
160
+ uppercase?: boolean;
161
+ italic?: boolean;
162
+ family?: "mono" | "sans" | "serif";
163
+ colourClasses: string[];
164
+ unresolved: string[];
165
+ }
166
+ interface NeighbourSummary {
167
+ text: string;
168
+ element?: string;
169
+ typography?: ResolvedTypography;
170
+ }
171
+ interface WritingContext {
172
+ facts?: string;
173
+ profile?: string;
174
+ instructions?: string;
175
+ }
176
+ interface UnitContext {
177
+ section?: string;
178
+ writingFacts?: string;
179
+ writingProfile?: string;
180
+ writingInstructions?: string;
181
+ headingAbove?: string;
182
+ docType: DocType;
183
+ element?: string;
184
+ attr?: string;
185
+ component?: string;
186
+ role: Role;
187
+ /** The className has parts this extractor could not read statically. */
188
+ dynamic?: boolean;
189
+ /** The className is a template literal with `${...}` inside a class. */
190
+ interpolated?: boolean;
191
+ parseError?: string;
192
+ mdxFallback?: boolean;
193
+ }
194
+ interface Unit {
195
+ facts?: SourceFacts;
196
+ /** Stable hash of file, kind and source offset. */
197
+ id: string;
198
+ kind: UnitKind;
199
+ /** Normalised rendered text, whitespace collapsed. */
200
+ text: string;
201
+ /** Relative to the scanned root, forward slashes. */
202
+ file: string;
203
+ line: number;
204
+ column: number;
205
+ endLine: number;
206
+ endColumn: number;
207
+ sourceStart: number;
208
+ sourceEnd: number;
209
+ inCode: boolean;
210
+ /** Ranges inside `text` that are code and must be skipped by regexes. */
211
+ codeSpans: [number, number][];
212
+ /**
213
+ * Source ranges (UTF-16 offsets into the file) holding prose a
214
+ * deterministic fix may rewrite: JSX text pieces, the inside of string
215
+ * literals, Markdown text nodes. Never quotes, braces, inline code or
216
+ * expressions. Absent means the unit cannot be fixed in place.
217
+ */
218
+ fixRanges?: [number, number][];
219
+ context: UnitContext;
220
+ typography?: ResolvedTypography;
221
+ neighbours?: {
222
+ prev?: NeighbourSummary;
223
+ next?: NeighbourSummary;
224
+ };
225
+ /** Class list for class-list and element units. */
226
+ classes?: string[];
227
+ }
228
+ interface MechanicalHit {
229
+ fired: boolean;
230
+ evidence: string;
231
+ /** Offset into `unit.text` of the first match; a source unit's finding line. */
232
+ offset?: number;
233
+ }
234
+ interface Finding {
235
+ ruleId: string;
236
+ categoryId: string;
237
+ domain: Domain;
238
+ severity: Severity;
239
+ band: Band;
240
+ probability: number;
241
+ tier: Tier;
242
+ unitId: string;
243
+ file: string;
244
+ line: number;
245
+ column: number;
246
+ endLine: number;
247
+ endColumn: number;
248
+ message: string;
249
+ evidence: string;
250
+ fixHint: string;
251
+ suppressed: boolean;
252
+ also?: string[];
253
+ }
254
+ interface Unknown {
255
+ ruleId: string;
256
+ unitId: string;
257
+ file: string;
258
+ line: number;
259
+ reason: string;
260
+ }
261
+ interface Scorecard {
262
+ byCategory: Record<string, {
263
+ domain: Domain;
264
+ units: number;
265
+ act: number;
266
+ review: number;
267
+ suppressed: number;
268
+ unknown: number;
269
+ }>;
270
+ byDomain: Record<string, {
271
+ units: number;
272
+ act: number;
273
+ review: number;
274
+ suppressed: number;
275
+ unknown: number;
276
+ }>;
277
+ byRule: Record<string, {
278
+ act: number;
279
+ review: number;
280
+ silent: number;
281
+ unknown: number;
282
+ }>;
283
+ }
284
+ interface Progress {
285
+ phase: "evaluating" | "complete";
286
+ completed: number;
287
+ planned: number;
288
+ cachedAnswers: number;
289
+ failed: number;
290
+ attempts: number;
291
+ elapsedMs: number;
292
+ }
293
+ interface Usage {
294
+ /** HTTP attempts when reported by the evaluator; absent for legacy evaluators. */
295
+ attempts?: number;
296
+ sharedAnswers?: number;
297
+ requests: number;
298
+ cached: number;
299
+ inputTokens: number;
300
+ costUsd: number;
301
+ errors: number;
302
+ }
303
+ type RunStatus = "complete" | "incomplete" | "dry-run";
304
+ interface RunSummary {
305
+ act: number;
306
+ review: number;
307
+ unknown: number;
308
+ failing: number;
309
+ failOn: Severity;
310
+ ruleFindings: number;
311
+ }
312
+ interface Coverage {
313
+ byRule: Record<string, {
314
+ eligible: number;
315
+ skipped: number;
316
+ negative: number;
317
+ pending: number;
318
+ unknown: number;
319
+ answered: number;
320
+ }>;
321
+ byCategory: Record<string, {
322
+ eligibleUnits: number;
323
+ eligiblePairs: number;
324
+ }>;
325
+ }
326
+ interface ScanScope {
327
+ files: number;
328
+ units: number;
329
+ byDocType: Record<string, number>;
330
+ excluded: number;
331
+ diagnostics: string[];
332
+ }
333
+ interface LintResult {
334
+ summary?: RunSummary;
335
+ ruleFindings?: Finding[];
336
+ ruleScorecard?: Scorecard;
337
+ coverage?: Coverage;
338
+ scope?: ScanScope;
339
+ reportPath?: string;
340
+ rerun?: string;
341
+ status: RunStatus;
342
+ findings: Finding[];
343
+ unknowns: Unknown[];
344
+ scorecard: Scorecard;
345
+ usage: Usage;
346
+ units: number;
347
+ rules: string[];
348
+ estimated?: {
349
+ requests: number;
350
+ inputTokens: number;
351
+ costUsd: number;
352
+ };
353
+ exitCode: number;
354
+ }
355
+ type EntryValue = string | number | boolean | null | EntryValue[] | {
356
+ [key: string]: EntryValue;
357
+ };
358
+ interface SystemOneNoul {
359
+ type: "noul";
360
+ instructions: EntryValue;
361
+ criteria?: {
362
+ true?: EntryValue;
363
+ false?: EntryValue;
364
+ } | null;
365
+ }
366
+ interface SystemOneRequest {
367
+ model: string;
368
+ state: EntryValue;
369
+ questions: Record<string, SystemOneNoul>;
370
+ }
371
+ interface SystemOneResponse {
372
+ attempts?: number;
373
+ model: string;
374
+ answers: Record<string, {
375
+ type?: string;
376
+ noul?: number;
377
+ }>;
378
+ usage: {
379
+ input_tokens: number;
380
+ output_tokens: number;
381
+ };
382
+ }
383
+ type Evaluate = (request: SystemOneRequest, onAttempt?: () => void) => Promise<SystemOneResponse>;
384
+ interface RecorderHandle {
385
+ append: (record: Record<string, unknown>) => Record<string, unknown>;
386
+ summary: (obj: Record<string, unknown>) => Record<string, unknown>;
387
+ file: string;
388
+ }
389
+ interface CorpusItem {
390
+ id: string;
391
+ kind: UnitKind;
392
+ text: string;
393
+ context?: Partial<UnitContext>;
394
+ neighbours?: Unit["neighbours"];
395
+ classes?: string[];
396
+ categoryId: string;
397
+ labels: Record<string, boolean>;
398
+ labelSource: "manifest" | "manifest-weak" | "hand" | "sweep" | "ai";
399
+ labelModel?: string;
400
+ labelPromptHash?: string;
401
+ source: {
402
+ repo: string;
403
+ path: string;
404
+ id?: string;
405
+ option?: string;
406
+ };
407
+ split: "dev" | "holdout";
408
+ }
409
+ interface ArchitecturePolicy {
410
+ boundaries?: {
411
+ from: string;
412
+ disallow: string;
413
+ reason: string;
414
+ }[];
415
+ deprecatedImports?: Record<string, string>;
416
+ generated?: string[];
417
+ }
418
+ interface Config {
419
+ architecture?: ArchitecturePolicy;
420
+ root: string;
421
+ docTypes: {
422
+ glob: string;
423
+ type: DocType;
424
+ }[];
425
+ components: {
426
+ unwrap: string[];
427
+ skip: string[];
428
+ };
429
+ tailwind: {
430
+ theme: Record<string, string>;
431
+ };
432
+ smartQuotesAtBuild: boolean;
433
+ exclude: string[];
434
+ }
435
+ //#endregion
436
+ //#region src/lib/config.d.ts
437
+ declare const loadConfig: (root: string, defaults?: Config["docTypes"]) => Config;
438
+ //#endregion
439
+ //#region src/lint.d.ts
440
+ interface LintOptions {
441
+ docTypes?: {
442
+ glob: string;
443
+ type: DocType;
444
+ }[];
445
+ advisoryRules?: string[];
446
+ writingContext?: WritingContext;
447
+ root: string;
448
+ targets: string[];
449
+ rulesDir?: string;
450
+ only?: string[];
451
+ exclude?: string[];
452
+ dryRun?: boolean;
453
+ printRequests?: boolean;
454
+ mechanicalOnly?: boolean;
455
+ noCache?: boolean;
456
+ limitUnits?: number;
457
+ failOn?: Severity;
458
+ fix?: boolean;
459
+ resultsDir?: string;
460
+ model?: string;
461
+ apiKey?: string;
462
+ /** Extra units supplied by the caller (rendered mode). */
463
+ extraUnits?: Unit[];
464
+ }
465
+ interface LintContext {
466
+ evaluate?: Evaluate;
467
+ stdout?: (text: string) => void;
468
+ stderr?: (text: string) => void;
469
+ onProgress?: (progress: Progress) => void;
470
+ onEvidence?: (units: Unit[], answers: Map<string, Record<string, number>>, negatives: Map<string, Set<string>>) => void;
471
+ }
472
+ declare const runLint: (options: LintOptions, ctx?: LintContext) => Promise<LintResult & {
473
+ rulesLoaded: Rule[];
474
+ units: number;
475
+ manifest: Record<string, unknown>;
476
+ }>;
477
+ //#endregion
478
+ //#region src/rules/load.d.ts
479
+ declare const resolveRulesDir: (explicit?: string) => string;
480
+ interface LoadOptions {
481
+ /** Include rules with status draft (default false). */
482
+ allowDraft?: boolean;
483
+ /** Restrict to these rule ids. */
484
+ only?: string[];
485
+ }
486
+ declare const loadRules: (rulesDir: string, options?: LoadOptions) => Rule[];
487
+ //#endregion
488
+ //#region src/rules/validate.d.ts
489
+ declare const validateRule: (raw: unknown, file: string, expectedId: string) => Rule;
490
+ //#endregion
491
+ //#region src/rules/taxonomy.d.ts
492
+ interface Category {
493
+ id: string;
494
+ domain: Domain;
495
+ label: string;
496
+ }
497
+ declare const CATEGORIES: readonly Category[];
498
+ declare const CATEGORY_BY_ID: ReadonlyMap<string, Category>;
499
+ //#endregion
500
+ //#region src/extract/index.d.ts
501
+ declare const extractFile: (config: Config, relativeFile: string) => Unit[];
502
+ //#endregion
503
+ //#region src/extract/tsx.d.ts
504
+ interface TsxExtractOptions {
505
+ config: Config;
506
+ docType: DocType;
507
+ }
508
+ declare const extractTsx: (file: string, source: string, options: TsxExtractOptions) => Unit[];
509
+ //#endregion
510
+ //#region src/extract/capture.d.ts
511
+ interface BoundingBox {
512
+ bottom: number;
513
+ height: number;
514
+ left: number;
515
+ right: number;
516
+ top: number;
517
+ width: number;
518
+ x: number;
519
+ y: number;
520
+ }
521
+ interface ElementSnapshot {
522
+ attributes: Record<string, string>;
523
+ boundingBox: BoundingBox;
524
+ children: string[];
525
+ classList: string[];
526
+ id: string;
527
+ parentId: string | null;
528
+ selector: string;
529
+ styles: Record<string, string>;
530
+ tagName: string;
531
+ text?: string;
532
+ }
533
+ interface CaptureResult {
534
+ elements: Record<string, ElementSnapshot>;
535
+ metadata: {
536
+ url: string;
537
+ title?: string;
538
+ capturedAt?: string;
539
+ };
540
+ order: string[];
541
+ rootElementId: string;
542
+ rootOuterHtml: string;
543
+ settings?: unknown;
544
+ version: 1;
545
+ }
546
+ //#endregion
547
+ //#region src/extract/rendered.d.ts
548
+ declare const extractCapture: (raw: CaptureResult, label: string) => Unit[];
549
+ declare const runStyleCapture: (url: string, selector: string) => Promise<CaptureResult>;
550
+ //#endregion
551
+ //#region src/extract/style-capture-text.d.ts
552
+ declare const parseCaptureInput: (raw: string) => CaptureResult;
553
+ //#endregion
554
+ //#region src/map/jev.d.ts
555
+ type Transport = "typesafe" | "gateway";
556
+ declare class ProviderError extends Error {
557
+ readonly category: "provider_error" | "invalid_response" | "timeout" | "auth";
558
+ readonly status?: number | undefined;
559
+ constructor(category: "provider_error" | "invalid_response" | "timeout" | "auth", status?: number | undefined);
560
+ }
561
+ interface FetchEvaluateOptions {
562
+ apiKey: string;
563
+ transport?: Transport;
564
+ baseUrl?: string;
565
+ fetch?: typeof globalThis.fetch;
566
+ timeoutMs?: number;
567
+ retries?: number;
568
+ /** Sleep hook so tests can run without waiting. */
569
+ sleep?: (ms: number) => Promise<void>;
570
+ }
571
+ declare const makeFetchEvaluate: (options: FetchEvaluateOptions) => Evaluate;
572
+ //#endregion
573
+ //#region src/report/json.d.ts
574
+ declare const renderJson: (result: LintResult, manifest: Record<string, unknown>) => string;
575
+ //#endregion
576
+ //#region src/report/sarif.d.ts
577
+ declare const renderSarif: (result: Pick<LintResult, "findings" | "ruleFindings">, rules: Rule[], version: string) => string;
578
+ //#endregion
579
+ //#region src/report/tty.d.ts
580
+ declare const renderTty: (result: LintResult, options?: {
581
+ verbose?: boolean;
582
+ }) => string;
583
+ //#endregion
584
+ //#region src/lib/stats.d.ts
585
+ interface BinaryMetrics {
586
+ tp: number;
587
+ fp: number;
588
+ fn: number;
589
+ tn: number;
590
+ precision: number;
591
+ recall: number;
592
+ f1: number;
593
+ precisionCI: [number, number];
594
+ recallCI: [number, number];
595
+ }
596
+ declare const calibrationTable: (pairs: {
597
+ label: boolean;
598
+ probability: number;
599
+ }[], buckets?: number) => {
600
+ lo: number;
601
+ hi: number;
602
+ n: number;
603
+ positives: number;
604
+ meanP: number;
605
+ }[];
606
+ //#endregion
607
+ //#region src/eval/coverage.d.ts
608
+ declare const corpusCoverage: (items: CorpusItem[], rules: Rule[]) => {
609
+ items: number;
610
+ labelSources: {
611
+ [k: string]: number;
612
+ };
613
+ overlappingSources: [string, string][];
614
+ overlappingTexts: number;
615
+ rules: {
616
+ negative: number;
617
+ positive: number;
618
+ dev: {
619
+ negative: number;
620
+ positive: number;
621
+ };
622
+ documentTypes: ("agent-instructions" | "explanation" | "howto" | "lesson" | "marketing" | "personal" | "plan" | "pr" | "readme" | "reference" | "skill" | "slides" | "tutorial" | "ui" | "unknown")[];
623
+ holdout: {
624
+ negative: number;
625
+ positive: number;
626
+ };
627
+ repositories: string[];
628
+ ruleId: string;
629
+ }[];
630
+ };
631
+ //#endregion
632
+ //#region src/eval/metrics.d.ts
633
+ interface EvalOptions {
634
+ corpusDir?: string;
635
+ rulesDir?: string;
636
+ only?: string[];
637
+ split?: "dev" | "holdout" | "all";
638
+ includeWeak?: boolean;
639
+ dryRun?: boolean;
640
+ noCache?: boolean;
641
+ resultsDir?: string;
642
+ model?: string;
643
+ apiKey?: string;
644
+ }
645
+ interface EvalContext {
646
+ evaluate?: Evaluate;
647
+ }
648
+ interface RuleEval {
649
+ ruleId: string;
650
+ n: number;
651
+ /** Labelled items the rule could not judge (unresolved value, failed request). */
652
+ unknown: number;
653
+ skipped?: number;
654
+ metrics: BinaryMetrics;
655
+ reviewRate: number;
656
+ calibration: ReturnType<typeof calibrationTable>;
657
+ /** Per item: label, probability. */
658
+ pairs: {
659
+ id: string;
660
+ label: boolean;
661
+ probability: number;
662
+ }[];
663
+ }
664
+ interface EvalResult {
665
+ referenceCoverage?: ReturnType<typeof corpusCoverage>;
666
+ labelSources?: Record<string, number>;
667
+ report: string;
668
+ exitCode: number;
669
+ rules: RuleEval[];
670
+ usage: {
671
+ requests: number;
672
+ cached: number;
673
+ inputTokens: number;
674
+ costUsd: number;
675
+ errors: number;
676
+ };
677
+ }
678
+ declare const runEval: (options: EvalOptions, ctx?: EvalContext) => Promise<EvalResult>;
679
+ //#endregion
680
+ //#region src/eval/corpus.d.ts
681
+ declare const splitFor: (id: string) => "dev" | "holdout";
682
+ //#endregion
683
+ //#region src/eval/promotion.d.ts
684
+ interface PromotionEvidence {
685
+ eligible: boolean;
686
+ n: number;
687
+ precisionLower: number;
688
+ reason: string;
689
+ }
690
+ //#endregion
691
+ //#region src/eval/tune.d.ts
692
+ interface TuneOptions {
693
+ corpusDir?: string;
694
+ rulesDir?: string;
695
+ only?: string[];
696
+ floor?: number;
697
+ write?: boolean;
698
+ resultsDir?: string;
699
+ model?: string;
700
+ apiKey?: string;
701
+ minItems?: number;
702
+ }
703
+ interface TuneContext {
704
+ evaluate?: Evaluate;
705
+ }
706
+ interface TuneDecision {
707
+ ruleId: string;
708
+ validation?: PromotionEvidence;
709
+ n: number;
710
+ current: number;
711
+ chosen: number | null;
712
+ precisionLower: number;
713
+ recall: number;
714
+ action: "keep" | "raise" | "lower" | "demote" | "insufficient";
715
+ }
716
+ declare const runTune: (options: TuneOptions, ctx?: TuneContext) => Promise<{
717
+ report: string;
718
+ exitCode: number;
719
+ decisions: TuneDecision[];
720
+ }>;
721
+ interface TuneAbOptions {
722
+ ruleId: string;
723
+ variantFile: string;
724
+ corpusDir?: string;
725
+ rulesDir?: string;
726
+ resultsDir?: string;
727
+ model?: string;
728
+ apiKey?: string;
729
+ }
730
+ declare const runTuneAb: (options: TuneAbOptions, ctx?: TuneContext) => Promise<{
731
+ report: string;
732
+ exitCode: number;
733
+ }>;
734
+ //#endregion
735
+ export { type ArchitecturePolicy, type Band, CATEGORIES, CATEGORY_BY_ID, type CONTEXT_KEYS, type Config, type ContextKey, type CorpusItem, type Coverage, type CriterionSide, type DOC_TYPES, type DOMAINS, type DocType, type Domain, type EntryValue, type Evaluate, type Finding, type Fix, type LintContext, type LintOptions, type LintResult, type Mechanical, type MechanicalHit, type NeighbourSummary, type Preconditions, type Progress, ProviderError, type Question, type ROLES, type RULE_STATUSES, type RecorderHandle, type ResolvedTypography, type Role, type Rule, type RuleSource, type RuleStatus, type RunStatus, type RunSummary, type SEVERITIES, type SEVERITY_RANK, type STRUCTURAL_KINDS, type ScanScope, type Scorecard, type Severity, type SystemOneNoul, type SystemOneRequest, type SystemOneResponse, type TIERS, type Thresholds, type Tier, type Tuning, type TuningEntry, type UNIT_KINDS, type Unit, type UnitContext, type UnitKind, type Unknown, type Usage, type WritingContext, extractCapture, extractFile, extractTsx, loadConfig, loadRules, makeFetchEvaluate, parseCaptureInput, renderJson, renderSarif, renderTty, resolveRulesDir, runEval, runLint, runStyleCapture, runTune, runTuneAb, splitFor, validateRule };
736
+ //# sourceMappingURL=index.d.ts.map