@tangle-network/browser-agent-driver 0.12.1 → 0.14.0

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 (90) hide show
  1. package/README.md +81 -0
  2. package/dist/brain/index.d.ts.map +1 -1
  3. package/dist/brain/index.js +88 -6
  4. package/dist/brain/index.js.map +1 -1
  5. package/dist/cli-design-audit.d.ts +2 -0
  6. package/dist/cli-design-audit.d.ts.map +1 -1
  7. package/dist/cli-design-audit.js +111 -303
  8. package/dist/cli-design-audit.js.map +1 -1
  9. package/dist/cli-view.d.ts +83 -0
  10. package/dist/cli-view.d.ts.map +1 -0
  11. package/dist/cli-view.js +397 -0
  12. package/dist/cli-view.js.map +1 -0
  13. package/dist/cli.js +32 -1
  14. package/dist/cli.js.map +1 -1
  15. package/dist/design/audit/classify.d.ts +20 -0
  16. package/dist/design/audit/classify.d.ts.map +1 -0
  17. package/dist/design/audit/classify.js +148 -0
  18. package/dist/design/audit/classify.js.map +1 -0
  19. package/dist/design/audit/evaluate.d.ts +49 -0
  20. package/dist/design/audit/evaluate.d.ts.map +1 -0
  21. package/dist/design/audit/evaluate.js +355 -0
  22. package/dist/design/audit/evaluate.js.map +1 -0
  23. package/dist/design/audit/measure/a11y.d.ts +25 -0
  24. package/dist/design/audit/measure/a11y.d.ts.map +1 -0
  25. package/dist/design/audit/measure/a11y.js +144 -0
  26. package/dist/design/audit/measure/a11y.js.map +1 -0
  27. package/dist/design/audit/measure/contrast.d.ts +18 -0
  28. package/dist/design/audit/measure/contrast.d.ts.map +1 -0
  29. package/dist/design/audit/measure/contrast.js +201 -0
  30. package/dist/design/audit/measure/contrast.js.map +1 -0
  31. package/dist/design/audit/measure/index.d.ts +14 -0
  32. package/dist/design/audit/measure/index.d.ts.map +1 -0
  33. package/dist/design/audit/measure/index.js +38 -0
  34. package/dist/design/audit/measure/index.js.map +1 -0
  35. package/dist/design/audit/pipeline.d.ts +33 -0
  36. package/dist/design/audit/pipeline.d.ts.map +1 -0
  37. package/dist/design/audit/pipeline.js +109 -0
  38. package/dist/design/audit/pipeline.js.map +1 -0
  39. package/dist/design/audit/roi.d.ts +49 -0
  40. package/dist/design/audit/roi.d.ts.map +1 -0
  41. package/dist/design/audit/roi.js +157 -0
  42. package/dist/design/audit/roi.js.map +1 -0
  43. package/dist/design/audit/rubric/fragments/domain-ai.md +19 -0
  44. package/dist/design/audit/rubric/fragments/domain-crypto.md +24 -0
  45. package/dist/design/audit/rubric/fragments/domain-devtools.md +21 -0
  46. package/dist/design/audit/rubric/fragments/domain-fintech.md +19 -0
  47. package/dist/design/audit/rubric/fragments/maturity-prototype.md +36 -0
  48. package/dist/design/audit/rubric/fragments/type-blog.md +22 -0
  49. package/dist/design/audit/rubric/fragments/type-docs.md +23 -0
  50. package/dist/design/audit/rubric/fragments/type-ecommerce.md +23 -0
  51. package/dist/design/audit/rubric/fragments/type-marketing.md +22 -0
  52. package/dist/design/audit/rubric/fragments/type-saas-app.md +20 -0
  53. package/dist/design/audit/rubric/fragments/universal-calibration.md +16 -0
  54. package/dist/design/audit/rubric/fragments/universal-effort-anchor.md +46 -0
  55. package/dist/design/audit/rubric/fragments/universal-foundation.md +49 -0
  56. package/dist/design/audit/rubric/loader.d.ts +49 -0
  57. package/dist/design/audit/rubric/loader.d.ts.map +1 -0
  58. package/dist/design/audit/rubric/loader.js +216 -0
  59. package/dist/design/audit/rubric/loader.js.map +1 -0
  60. package/dist/design/audit/types.d.ts +166 -0
  61. package/dist/design/audit/types.d.ts.map +1 -0
  62. package/dist/design/audit/types.js +8 -0
  63. package/dist/design/audit/types.js.map +1 -0
  64. package/dist/drivers/cursor-overlay.d.ts +26 -0
  65. package/dist/drivers/cursor-overlay.d.ts.map +1 -0
  66. package/dist/drivers/cursor-overlay.js +235 -0
  67. package/dist/drivers/cursor-overlay.js.map +1 -0
  68. package/dist/drivers/playwright.d.ts +32 -0
  69. package/dist/drivers/playwright.d.ts.map +1 -1
  70. package/dist/drivers/playwright.js +79 -0
  71. package/dist/drivers/playwright.js.map +1 -1
  72. package/dist/drivers/steel.d.ts +135 -0
  73. package/dist/drivers/steel.d.ts.map +1 -0
  74. package/dist/drivers/steel.js +236 -0
  75. package/dist/drivers/steel.js.map +1 -0
  76. package/dist/index.d.ts +2 -0
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +1 -0
  79. package/dist/index.js.map +1 -1
  80. package/dist/provider-defaults.d.ts +19 -1
  81. package/dist/provider-defaults.d.ts.map +1 -1
  82. package/dist/provider-defaults.js +34 -0
  83. package/dist/provider-defaults.js.map +1 -1
  84. package/dist/test-runner.d.ts.map +1 -1
  85. package/dist/test-runner.js +51 -14
  86. package/dist/test-runner.js.map +1 -1
  87. package/dist/types.d.ts +10 -0
  88. package/dist/types.d.ts.map +1 -1
  89. package/dist/viewer/viewer.html +940 -0
  90. package/package.json +3 -2
@@ -0,0 +1,19 @@
1
+ ---
2
+ id: domain-ai
3
+ title: AI / ML Products
4
+ weight: high
5
+ applies-when:
6
+ domain: [ai, ml, llm, agents]
7
+ ---
8
+
9
+ AI / ML PRODUCT CRITERIA:
10
+
11
+ - Demo prominence: working live demo > screenshots
12
+ - Model differentiation: clear what makes this AI different (latency, quality, cost)
13
+ - Streaming UI quality (for chat/agent products): smooth, no layout shifts, cancelable
14
+ - Tool/function call visualization: when the agent uses tools, can the user see it?
15
+ - Error recovery: model timeouts, content filters, rate limits — all handled gracefully
16
+ - Conversation history: persistent, searchable, exportable
17
+ - Token/cost transparency for paid usage
18
+ - Safety messaging: where appropriate, present without being alarmist
19
+ - Avoid excessive AI cliches (matrix rain, robot illustrations, generic gradients)
@@ -0,0 +1,24 @@
1
+ ---
2
+ id: domain-crypto
3
+ title: Crypto / DeFi
4
+ weight: high
5
+ dimension: trust-signals
6
+ applies-when:
7
+ domain: [crypto, defi, web3]
8
+ type: [marketing, saas-app, tool]
9
+ ---
10
+
11
+ DeFi / CRYPTO CRITERIA — evaluate as a trader managing real money:
12
+
13
+ - Trust signals: does the UI feel safe to connect a wallet to? Professional or sketchy?
14
+ - Token displays: balances formatted correctly, right decimals, USD equivalents
15
+ - Transaction clarity: clear what you're signing — amount, fees, slippage shown
16
+ - Loading states: RPC calls are slow — proper indicators for balances, quotes, gas
17
+ - Mobile responsiveness: most DeFi usage is mobile
18
+ - Dark mode: most crypto apps use dark mode — sufficient contrast, visible borders
19
+ - Error handling: RPC fails, wallet rejects, insufficient balance — all handled
20
+ - Swap UX: token selection intuitive, address paste, price impact shown
21
+ - Wallet connection: smooth flow, supported wallets clearly shown
22
+ - Gas/fee transparency: estimates shown before confirmation
23
+
24
+ CALIBRATION: Uniswap v4 / Aave v3 = 8. Average DEX = 5. Rug-pull-looking sites = 2.
@@ -0,0 +1,21 @@
1
+ ---
2
+ id: domain-devtools
3
+ title: Developer Tools
4
+ weight: high
5
+ applies-when:
6
+ domain: [devtools, dev, infrastructure, api, sdk]
7
+ ---
8
+
9
+ DEVELOPER TOOLS CRITERIA:
10
+
11
+ - Code-first messaging: hero shows code, not abstract illustrations
12
+ - Quickstart prominent: "get started in N minutes" with copyable command
13
+ - API docs link visible
14
+ - SDK support transparency: which languages, badges/logos
15
+ - Pricing transparency: free tier clear, no "contact us"
16
+ - GitHub stars, npm downloads, or similar credibility markers
17
+ - Dark mode: developers prefer dark, must be excellent
18
+ - Terminal aesthetics done well, not gimmicky
19
+ - Real customer logos (other dev companies preferred)
20
+
21
+ CALIBRATION: Vercel / Linear / Cursor / Stripe = 9. Average dev tool landing = 6. "Enterprise blockchain" sites = 3.
@@ -0,0 +1,19 @@
1
+ ---
2
+ id: domain-fintech
3
+ title: Fintech / Financial Services
4
+ weight: high
5
+ dimension: trust-signals
6
+ applies-when:
7
+ domain: [fintech, finance, banking, payments]
8
+ ---
9
+
10
+ FINTECH-SPECIFIC CRITERIA:
11
+
12
+ - Trust signals: security badges, compliance mentions (SOC2, PCI), institutional logos
13
+ - Numerical precision: amounts with correct decimals, currency symbols, no truncation
14
+ - Risk disclosure: fees, terms, warnings prominently shown
15
+ - Conservative aesthetic: financial sites should feel substantial, not playful
16
+ - Data tables: aligned columns, easy scanning, totals visible
17
+ - Form validation: especially strict for money inputs (max digits, format)
18
+ - Color use: green/red for money should follow market conventions (gain/loss)
19
+ - Audit trail visibility: transaction history, statements, exports
@@ -0,0 +1,36 @@
1
+ ---
2
+ id: maturity-prototype
3
+ title: Prototype / Template Detection
4
+ weight: high
5
+ applies-when:
6
+ maturity: [prototype, mvp]
7
+ designSystem: [shadcn, mui, ant, chakra]
8
+ ---
9
+
10
+ TEMPLATE-DETECTION CRITERIA — apply when this looks like an unmodified component-library app:
11
+
12
+ The #1 sin of vibecoded / AI-generated apps is shipping unmodified component library defaults:
13
+ - Default border-radius (6-8px shadcn, 4px MUI)
14
+ - Default color palette (zinc/slate grays, blue-600 primary)
15
+ - Default component spacing with no customization
16
+ - Standard card shadows, stock empty states
17
+ - "Looks like every other AI-generated app" = automatic 3-4 score
18
+
19
+ HIERARCHY & INFORMATION ARCHITECTURE:
20
+ - Is everything the same visual weight? (Common AI pattern: all cards same size)
21
+ - Clear primary/secondary/tertiary action distinction?
22
+ - Layout has purpose, or is it "centered column of cards"?
23
+
24
+ DESIGN SYSTEM COHERENCE:
25
+ - More than 3 distinct border-radius values = incoherent
26
+ - Color palette: intentional limited (4-6) vs random accumulation
27
+ - Spacing: 8px grid rhythm vs arbitrary per-component
28
+ - Typography: deliberate scale with 3-4 sizes vs every component picking its own
29
+
30
+ CRAFT SIGNALS (separates 7 from 9):
31
+ - Custom icons or generic Lucide/Heroicons dump?
32
+ - Micro-interactions: button feedback, page transitions, loading skeletons
33
+ - Empty states: designed illustrations or "No data found" text?
34
+ - Error states: helpful with recovery actions or raw error strings?
35
+
36
+ CEILING: Unmodified template apps cap at 4 regardless of functionality. State this in the score reasoning.
@@ -0,0 +1,22 @@
1
+ ---
2
+ id: type-blog
3
+ title: Blog / Article
4
+ weight: medium
5
+ applies-when:
6
+ type: [blog]
7
+ ---
8
+
9
+ BLOG / ARTICLE CRITERIA — evaluate as a reader scanning then committing:
10
+
11
+ - Reading line length: 65-75ch optimal
12
+ - Type pairing: serif body or excellent sans, clear heading distinction
13
+ - Line height: 1.5-1.7 for body text
14
+ - Image usage: meaningful, not stock filler
15
+ - Code blocks (if technical): syntax highlighting, copyable
16
+ - Author byline + date prominent
17
+ - Reading time estimate (helpful)
18
+ - TOC or section nav for long articles
19
+ - Related/next-article surface at the end
20
+ - No autoplay video, no aggressive CTAs interrupting reading
21
+
22
+ CALIBRATION: Stripe blog / Vercel blog / Substack flagships = 9. Medium = 6. WordPress defaults = 4.
@@ -0,0 +1,23 @@
1
+ ---
2
+ id: type-docs
3
+ title: Technical Documentation
4
+ weight: high
5
+ dimension: readability
6
+ applies-when:
7
+ type: [docs]
8
+ ---
9
+
10
+ TECHNICAL DOCUMENTATION CRITERIA — evaluate as a developer trying to learn:
11
+
12
+ - Reading line length: prose 65-75ch, never wider
13
+ - Code blocks: syntax highlighting, copyable, language labels
14
+ - Information architecture: clear section navigation, breadcrumbs, in-page TOC
15
+ - Search affordance: prominent, fast, results relevant
16
+ - Type hierarchy: H1/H2/H3 visually distinct, scannable
17
+ - Inline code styling distinguishable from prose
18
+ - Anchor links on headings for sharing
19
+ - Dark mode toggle present and well-implemented
20
+ - Performance: doc pages should load instantly (no JS-heavy frameworks for static content)
21
+ - Cross-linking between related concepts
22
+
23
+ CALIBRATION: Stripe Docs / Tailwind Docs / Vercel Docs = 9. Average dev docs = 5. Wall-of-text wikis = 3.
@@ -0,0 +1,23 @@
1
+ ---
2
+ id: type-ecommerce
3
+ title: E-commerce / Storefront
4
+ weight: high
5
+ dimension: conversion
6
+ applies-when:
7
+ type: [ecommerce]
8
+ ---
9
+
10
+ E-COMMERCE CRITERIA — evaluate as a shopper deciding to spend money:
11
+
12
+ - Product imagery: high-resolution, multiple angles, zoom support
13
+ - Price prominence and clarity (no hidden fees, currency obvious)
14
+ - Add-to-cart affordance: obvious, immediate feedback
15
+ - Trust signals: reviews, ratings, return policy, security badges
16
+ - Filters/sort: discoverable, fast, persistent state
17
+ - Cart accessibility: visible at all times, count badge
18
+ - Checkout flow: single-page or stepped, progress visible, guest checkout option
19
+ - Mobile-first: most ecommerce traffic is mobile
20
+ - Performance: every second of load = ~2% conversion lost
21
+ - Inventory state: clear "in stock" / "out of stock" / "limited"
22
+
23
+ CALIBRATION: Apple / Allbirds / Glossier = 9. Generic Shopify themes = 5. Broken cart flows = 2.
@@ -0,0 +1,22 @@
1
+ ---
2
+ id: type-marketing
3
+ title: Marketing / Landing Page
4
+ weight: high
5
+ applies-when:
6
+ type: [marketing]
7
+ ---
8
+
9
+ MARKETING / LANDING PAGE CRITERIA — evaluate as a potential customer deciding in 10 seconds:
10
+
11
+ - Hero clarity: in 5 seconds, can I tell what this product does and who it's for?
12
+ - Visual hierarchy: does the eye flow naturally from headline → subtext → CTA?
13
+ - CTA prominence: is the primary call-to-action obvious and compelling?
14
+ - Social proof: testimonials, logos, or metrics shown convincingly?
15
+ - Headline typography impactful? Body text readable?
16
+ - Imagery high quality and relevant, or stock-photo generic?
17
+ - Whitespace — does the page breathe or feel cramped?
18
+ - Mobile: hero and CTA work without scrolling on small viewports?
19
+ - Performance perception: feels fast? Images optimized? No layout shift?
20
+ - Footer: navigation complete, legal links present?
21
+
22
+ CALIBRATION: Stripe / Linear / Vercel = 9. Average startup landing = 5. Template sites = 3.
@@ -0,0 +1,20 @@
1
+ ---
2
+ id: type-saas-app
3
+ title: SaaS Application
4
+ weight: high
5
+ applies-when:
6
+ type: [saas-app, dashboard]
7
+ ---
8
+
9
+ SaaS APPLICATION CRITERIA — evaluate as a paying customer would:
10
+
11
+ - Information density: data presented efficiently without clutter?
12
+ - Navigation: features findable in <3 clicks? Sidebar/nav intuitive?
13
+ - Empty states: helpful onboarding prompts when there's no data?
14
+ - Loading states: skeleton screens or spinners, or does content pop in?
15
+ - Form design: inline validation, clear labels, logical tab order?
16
+ - Dashboard layout: most important data prominent, card hierarchy clear?
17
+ - Error states: actionable with clear recovery paths?
18
+ - Pattern consistency: do buttons, inputs, modals follow the same patterns throughout?
19
+
20
+ CALIBRATION: Linear / Notion / Figma = 9. Generic admin templates = 5. Broken CRUD = 3.
@@ -0,0 +1,16 @@
1
+ ---
2
+ id: universal-calibration
3
+ title: Universal Calibration Anchor
4
+ weight: critical
5
+ applies-when:
6
+ universal: true
7
+ ---
8
+
9
+ CALIBRATION — be ruthlessly honest:
10
+ - 9-10: Only world-class design (Linear, Stripe, Vercel, Apple). Exceptional typography, spacing, micro-interactions. Coherent system, intentional decisions visible everywhere.
11
+ - 7-8: Professional and polished. Clear design system. Minor inconsistencies tolerated if the whole feels coherent.
12
+ - 5-6: Functional but generic. Default component libraries with light customization. Production-ready but uninspired.
13
+ - 3-4: Noticeably broken or amateurish. Inconsistent spacing, clashing colors, poor hierarchy. Default templates with no investment.
14
+ - 1-2: Unusable. Overlapping elements, unreadable text, broken layouts.
15
+
16
+ Most production apps score 5-7. Very few deserve 8+. Do NOT grade on a curve.
@@ -0,0 +1,46 @@
1
+ ---
2
+ id: universal-effort-anchor
3
+ title: Effort & ROI Calibration
4
+ weight: critical
5
+ applies-when:
6
+ universal: true
7
+ ---
8
+
9
+ EFFORT SCALE — when scoring `effort` on a finding, use these anchors:
10
+
11
+ | Effort | Definition | Examples |
12
+ |---|---|---|
13
+ | 1 | Single CSS value change in a token or shared style | `--color-text: #4b5563`, `padding-bottom: 48px` |
14
+ | 2 | Single component file edit | Update `Button.tsx` to add focus ring |
15
+ | 3 | A few related component edits | Standardize 3 card components to one radius |
16
+ | 4 | New design token + propagation | Add `--space-section`, replace 12 hardcoded values |
17
+ | 5 | New shared component | Build a reusable `Stack` to fix layout drift |
18
+ | 6 | Significant component refactor | Restructure `Sidebar` to support responsive collapse |
19
+ | 7 | Section redesign | Hero rewrite with new copy hierarchy |
20
+ | 8 | Multi-page layout change | Apply new grid container across routes |
21
+ | 9 | Design system overhaul | New type scale + recolor + spacing rebuild |
22
+ | 10 | Full app redesign | Greenfield rebuild |
23
+
24
+ IMPACT SCALE — when scoring `impact` on a finding:
25
+
26
+ | Impact | Definition |
27
+ |---|---|
28
+ | 1-2 | Pure nitpick. Most users wouldn't notice. |
29
+ | 3-4 | Visible if you're looking. Polish detail. |
30
+ | 5-6 | Noticeable on first scan. Affects perceived quality. |
31
+ | 7-8 | Hurts trust or usability. Affects task success. |
32
+ | 9-10 | Breaks the experience. WCAG failures, broken layouts, unreadable text. |
33
+
34
+ BLAST SCALE — when assigning `blast`:
35
+
36
+ | Blast | When |
37
+ |---|---|
38
+ | `page` | Only this page benefits from the fix |
39
+ | `section` | A region of this page (hero, footer, sidebar) |
40
+ | `component` | A shared component (`Card`, `Button`) — multiple pages benefit |
41
+ | `system` | A design token, global style, or universal pattern — every page benefits |
42
+
43
+ RANKING DISCIPLINE — assign these honestly:
44
+ - A 5-second token change with system blast (e.g. fix the body text gray) should DOMINATE a 2-day visual polish refactor.
45
+ - Don't inflate impact to make minor findings sound important. The user fixes the top-5; everything below 5 may never get touched.
46
+ - A "small but everywhere" fix beats a "big but isolated" fix in ROI ranking — that's correct.
@@ -0,0 +1,49 @@
1
+ ---
2
+ id: universal-foundation
3
+ title: Universal Design Foundation
4
+ weight: critical
5
+ applies-when:
6
+ universal: true
7
+ ---
8
+
9
+ EVALUATION FRAMEWORK — score each area 1-10:
10
+
11
+ 1. LAYOUT & GRID
12
+ - Consistent grid system? What unit? (4px, 8px, etc.)
13
+ - Column alignment: do content blocks align to consistent edges?
14
+ - Container widths appropriate (prose 65-75ch, app fluid)?
15
+ - Z-index layering — any stacking issues, overlapping elements?
16
+ - Orphaned elements floating outside the grid?
17
+
18
+ 2. TYPOGRAPHY SYSTEM
19
+ - Type scale: count distinct font-size values. >5-6 suggests no scale.
20
+ - Line height: body 1.4-1.6, headings 1.1-1.3. Flag violations.
21
+ - Letter spacing: headings often need negative tracking (-0.01 to -0.03em).
22
+ - Font pairing: max 2 families. Flag 3+.
23
+ - Long-form text wider than 75ch harms readability.
24
+
25
+ 3. SPACING & RHYTHM
26
+ - Grid adherence: % of spacing values that are multiples of the base unit
27
+ - Vertical rhythm: are section gaps consistent?
28
+ - Component internal spacing: consistent padding within similar components?
29
+ - Whitespace ratio: enough breathing room or cramped?
30
+
31
+ 4. COMPONENT CONSISTENCY
32
+ - Button variants: how many distinct button styles? Intentional or accidental?
33
+ - Input styling: consistent border, focus ring, label position?
34
+ - Card patterns: same border-radius, shadow, padding?
35
+ - Border radius count: >3 distinct values = incoherent
36
+ - Shadow system: consistent elevation scale or random drops?
37
+
38
+ 5. INTERACTION DESIGN
39
+ - Hover states present and meaningful?
40
+ - Visible focus indicators for keyboard nav?
41
+ - Active/pressed feedback?
42
+ - Transition timing 150-300ms with appropriate easing?
43
+ - Loading states: skeleton, spinner, or content pop-in?
44
+
45
+ 6. VISUAL POLISH
46
+ - Pixel precision — anything off by 1px?
47
+ - Image quality on retina displays?
48
+ - Icon set consistency — all from one family or mixed?
49
+ - Empty/error states: designed or browser-default?
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Rubric loader — reads markdown fragments with YAML frontmatter, composes
3
+ * a rubric from the set whose `applies-when` predicates match a classification.
4
+ *
5
+ * Adding a new rubric: drop a markdown file in `fragments/` (or in
6
+ * `~/.bad/rubrics/` for user fragments). No code changes required.
7
+ */
8
+ import type { PageClassification, RubricFragment, ComposedRubric } from '../types.js';
9
+ /**
10
+ * Parse a markdown fragment file into a RubricFragment.
11
+ * Frontmatter format:
12
+ * ---
13
+ * id: foo
14
+ * title: Foo
15
+ * weight: high
16
+ * applies-when:
17
+ * type: [marketing]
18
+ * domain: [fintech]
19
+ * ---
20
+ * body markdown...
21
+ */
22
+ export declare function parseFragment(filePath: string): RubricFragment;
23
+ /**
24
+ * Load all fragments from a directory. Recursive subdirs ignored — fragments are flat.
25
+ */
26
+ export declare function loadFragments(dir?: string): RubricFragment[];
27
+ /**
28
+ * Predicate evaluator. Returns true if the fragment applies to the classification.
29
+ *
30
+ * Universal fragments always apply.
31
+ * Type/domain/maturity/designSystem predicates are AND-combined: all listed
32
+ * fields must match. Within a field, the classification value must be in the
33
+ * fragment's allowed set.
34
+ */
35
+ export declare function fragmentApplies(fragment: RubricFragment, classification: PageClassification): boolean;
36
+ /**
37
+ * Compose a rubric from a classification.
38
+ *
39
+ * @param classification - the page classification
40
+ * @param fragments - all loaded fragments (defaults to builtin)
41
+ * @param userFragmentsDir - optional path to user-supplied fragments
42
+ */
43
+ export declare function composeRubric(classification: PageClassification, fragments?: RubricFragment[], userFragmentsDir?: string): ComposedRubric;
44
+ /**
45
+ * Compose a rubric from an explicit profile name (for `--profile` override).
46
+ * Loads only the matching type fragment + universal fragments.
47
+ */
48
+ export declare function composeRubricFromProfile(profile: string, fragmentsOverride?: RubricFragment[]): ComposedRubric;
49
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../src/design/audit/rubric/loader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,cAAc,EAEf,MAAM,aAAa,CAAA;AAYpB;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAiB9D;AAkED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAA8B,GAAG,cAAc,EAAE,CAMnF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,cAAc,EACxB,cAAc,EAAE,kBAAkB,GACjC,OAAO,CA4BT;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,kBAAkB,EAClC,SAAS,CAAC,EAAE,cAAc,EAAE,EAC5B,gBAAgB,CAAC,EAAE,MAAM,GACxB,cAAc,CAgChB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,iBAAiB,CAAC,EAAE,cAAc,EAAE,GACnC,cAAc,CAsBhB"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Rubric loader — reads markdown fragments with YAML frontmatter, composes
3
+ * a rubric from the set whose `applies-when` predicates match a classification.
4
+ *
5
+ * Adding a new rubric: drop a markdown file in `fragments/` (or in
6
+ * `~/.bad/rubrics/` for user fragments). No code changes required.
7
+ */
8
+ import * as fs from 'node:fs';
9
+ import * as path from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ const BUILTIN_FRAGMENTS_DIR = path.join(__dirname, 'fragments');
13
+ const WEIGHT_ORDER = {
14
+ critical: 0,
15
+ high: 1,
16
+ medium: 2,
17
+ low: 3,
18
+ };
19
+ /**
20
+ * Parse a markdown fragment file into a RubricFragment.
21
+ * Frontmatter format:
22
+ * ---
23
+ * id: foo
24
+ * title: Foo
25
+ * weight: high
26
+ * applies-when:
27
+ * type: [marketing]
28
+ * domain: [fintech]
29
+ * ---
30
+ * body markdown...
31
+ */
32
+ export function parseFragment(filePath) {
33
+ const raw = fs.readFileSync(filePath, 'utf-8');
34
+ const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
35
+ if (!match) {
36
+ throw new Error(`fragment ${filePath} missing YAML frontmatter`);
37
+ }
38
+ const [, frontmatter, body] = match;
39
+ const meta = parseMinimalYaml(frontmatter);
40
+ return {
41
+ id: String(meta.id ?? path.basename(filePath, '.md')),
42
+ title: String(meta.title ?? meta.id ?? 'Untitled'),
43
+ weight: meta.weight ?? 'medium',
44
+ appliesWhen: meta['applies-when'] ?? {},
45
+ body: body.trim(),
46
+ ...(meta.dimension ? { dimension: String(meta.dimension) } : {}),
47
+ };
48
+ }
49
+ /**
50
+ * Minimal YAML parser — supports the subset our frontmatter uses:
51
+ * key: value
52
+ * key: [a, b, c]
53
+ * key:
54
+ * subkey: [a, b]
55
+ *
56
+ * Avoids pulling in a full YAML dep for ~50 lines of config.
57
+ */
58
+ function parseMinimalYaml(text) {
59
+ const lines = text.split('\n');
60
+ const result = {};
61
+ let i = 0;
62
+ while (i < lines.length) {
63
+ const line = lines[i];
64
+ if (!line.trim() || line.trim().startsWith('#')) {
65
+ i++;
66
+ continue;
67
+ }
68
+ const topMatch = line.match(/^([a-zA-Z][\w-]*):\s*(.*)$/);
69
+ if (!topMatch) {
70
+ i++;
71
+ continue;
72
+ }
73
+ const [, key, valueRaw] = topMatch;
74
+ const value = valueRaw.trim();
75
+ if (value === '') {
76
+ // Nested object — collect indented lines
77
+ const nested = {};
78
+ i++;
79
+ while (i < lines.length && (lines[i].startsWith(' ') || lines[i].trim() === '')) {
80
+ if (!lines[i].trim()) {
81
+ i++;
82
+ continue;
83
+ }
84
+ const nm = lines[i].match(/^\s+([a-zA-Z][\w-]*):\s*(.*)$/);
85
+ if (nm) {
86
+ nested[nm[1]] = parseScalarOrList(nm[2].trim());
87
+ }
88
+ i++;
89
+ }
90
+ result[key] = nested;
91
+ }
92
+ else {
93
+ result[key] = parseScalarOrList(value);
94
+ i++;
95
+ }
96
+ }
97
+ return result;
98
+ }
99
+ function parseScalarOrList(value) {
100
+ if (value.startsWith('[') && value.endsWith(']')) {
101
+ return value
102
+ .slice(1, -1)
103
+ .split(',')
104
+ .map(s => s.trim())
105
+ .filter(Boolean);
106
+ }
107
+ if (value === 'true')
108
+ return true;
109
+ if (value === 'false')
110
+ return false;
111
+ if (/^-?\d+(\.\d+)?$/.test(value))
112
+ return Number(value);
113
+ return value;
114
+ }
115
+ /**
116
+ * Load all fragments from a directory. Recursive subdirs ignored — fragments are flat.
117
+ */
118
+ export function loadFragments(dir = BUILTIN_FRAGMENTS_DIR) {
119
+ if (!fs.existsSync(dir))
120
+ return [];
121
+ return fs
122
+ .readdirSync(dir)
123
+ .filter(f => f.endsWith('.md'))
124
+ .map(f => parseFragment(path.join(dir, f)));
125
+ }
126
+ /**
127
+ * Predicate evaluator. Returns true if the fragment applies to the classification.
128
+ *
129
+ * Universal fragments always apply.
130
+ * Type/domain/maturity/designSystem predicates are AND-combined: all listed
131
+ * fields must match. Within a field, the classification value must be in the
132
+ * fragment's allowed set.
133
+ */
134
+ export function fragmentApplies(fragment, classification) {
135
+ const w = fragment.appliesWhen;
136
+ if (w.universal)
137
+ return true;
138
+ if (w.type && w.type.length > 0) {
139
+ if (!w.type.includes(classification.type))
140
+ return false;
141
+ }
142
+ if (w.domain && w.domain.length > 0) {
143
+ const domainMatch = w.domain.some(d => classification.domain.toLowerCase().includes(d.toLowerCase()));
144
+ if (!domainMatch)
145
+ return false;
146
+ }
147
+ if (w.maturity && w.maturity.length > 0) {
148
+ if (!w.maturity.includes(classification.maturity))
149
+ return false;
150
+ }
151
+ if (w.designSystem && w.designSystem.length > 0) {
152
+ if (!w.designSystem.includes(classification.designSystem))
153
+ return false;
154
+ }
155
+ // If at least one predicate field was set and all matched, apply.
156
+ // If NO predicates were set and not universal, don't apply (be conservative).
157
+ const hasPredicate = !!w.type?.length ||
158
+ !!w.domain?.length ||
159
+ !!w.maturity?.length ||
160
+ !!w.designSystem?.length;
161
+ return hasPredicate;
162
+ }
163
+ /**
164
+ * Compose a rubric from a classification.
165
+ *
166
+ * @param classification - the page classification
167
+ * @param fragments - all loaded fragments (defaults to builtin)
168
+ * @param userFragmentsDir - optional path to user-supplied fragments
169
+ */
170
+ export function composeRubric(classification, fragments, userFragmentsDir) {
171
+ const all = [
172
+ ...(fragments ?? loadFragments(BUILTIN_FRAGMENTS_DIR)),
173
+ ...(userFragmentsDir ? loadFragments(userFragmentsDir) : []),
174
+ ];
175
+ const matched = all
176
+ .filter(f => fragmentApplies(f, classification))
177
+ .sort((a, b) => WEIGHT_ORDER[a.weight] - WEIGHT_ORDER[b.weight]);
178
+ const body = matched
179
+ .map(f => `## ${f.title}\n\n${f.body}`)
180
+ .join('\n\n---\n\n');
181
+ // Calibration is the universal-calibration fragment if loaded; otherwise
182
+ // a sensible default.
183
+ const calFragment = matched.find(f => f.id === 'universal-calibration');
184
+ const calibration = calFragment?.body ??
185
+ 'Score 1-10. Most production apps score 5-7. Only world-class deserves 8+. Be honest.';
186
+ // Custom dimensions contributed by fragments (deduped, preserves order)
187
+ const dimensions = Array.from(new Set(matched.map(f => f.dimension).filter((d) => Boolean(d))));
188
+ return {
189
+ fragments: matched,
190
+ body,
191
+ calibration,
192
+ dimensions,
193
+ };
194
+ }
195
+ /**
196
+ * Compose a rubric from an explicit profile name (for `--profile` override).
197
+ * Loads only the matching type fragment + universal fragments.
198
+ */
199
+ export function composeRubricFromProfile(profile, fragmentsOverride) {
200
+ const all = fragmentsOverride ?? loadFragments(BUILTIN_FRAGMENTS_DIR);
201
+ const wanted = new Set([
202
+ `type-${profile}`,
203
+ 'universal-foundation',
204
+ 'universal-calibration',
205
+ ]);
206
+ const matched = all
207
+ .filter(f => wanted.has(f.id))
208
+ .sort((a, b) => WEIGHT_ORDER[a.weight] - WEIGHT_ORDER[b.weight]);
209
+ const body = matched.map(f => `## ${f.title}\n\n${f.body}`).join('\n\n---\n\n');
210
+ const calFragment = matched.find(f => f.id === 'universal-calibration');
211
+ const calibration = calFragment?.body ??
212
+ 'Score 1-10. Most production apps score 5-7. Only world-class deserves 8+. Be honest.';
213
+ const dimensions = Array.from(new Set(matched.map(f => f.dimension).filter((d) => Boolean(d))));
214
+ return { fragments: matched, body, calibration, dimensions };
215
+ }
216
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../../src/design/audit/rubric/loader.ts"],"names":[],"mappings":"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"}