diff --git a/.serena/.gitignore b/.serena/.gitignore deleted file mode 100644 index 14d86ad6..00000000 --- a/.serena/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/cache diff --git a/.serena/memories/architecture.md b/.serena/memories/architecture.md deleted file mode 100644 index 756a0fde..00000000 --- a/.serena/memories/architecture.md +++ /dev/null @@ -1,119 +0,0 @@ -# Rafters Architecture - -## System Overview - -``` -Registry (API + D1) ← Source of truth - ↓ - ┌────┴────┬─────────┬──────────┐ - ↓ ↓ ↓ ↓ - CLI Studio MCP llms.txt - ↓ ↓ ↓ ↓ -Project Browser AI Agents Discovery -``` - -## Key Principle -**Registry is source of truth.** CLI always queries registry. Local `.rafters/` is cache/storage only. - -## Apps - -### API (apps/api) -- **Hono** + `@hono/zod-openapi` for OpenAPI-first routes -- **Scalar** for API reference at `/reference` -- **D1** for color cache (exact OKLCH lookups) -- **Vectorize** for semantic search -- **Workers AI** for color intelligence generation - -Routes structure: -``` -src/routes/{feature}/ -├── {feature}.index.ts # Router -├── {feature}.routes.ts # OpenAPI route definitions -└── {feature}.handlers.ts # Handler implementations -``` - -### CLI (packages/cli) -Like shadcn CLI but multi-framework with intelligence: -```bash -npx rafters init # Setup, detect framework -npx rafters add button # Fetch from registry, copy to project -npx rafters tokens # Export tokens -npx rafters studio # Launch customization UI -npx rafters mcp # Start MCP server for AI agents -``` - -**Auto-dependency installation**: CLI detects package manager from lockfiles (@antfu/ni) and auto-installs npm dependencies when adding components. - -### Website (apps/website) -- **Astro** for static site generation -- **MDX** for documentation -- **Custom Shadow DOM preview system** - Replaces Storybook (~500 lines) - -## Packages - -### @rafters/shared -Consolidated types shared across all packages. - -### @rafters/color-utils -OKLCH color intelligence: -- `generateOKLCHScale()` - 50-950 scales with contrast-based lightness -- `generateAccessibilityMetadata()` - Pre-computed WCAG pairs -- `generateHarmony()` - 11 harmonic relationships -- `calculateAtmosphericWeight()` - Depth perception -- `calculatePerceptualWeight()` - Visual heaviness (0-1) - -### @rafters/math-utils -Mathematical foundations: -- `generateProgression()` - Musical ratios (minor-third, major-third, perfect-fourth) -- `generateModularScale()` - Typography scales -- `generateFibonacciLike()` - Custom ratio sequences -- Unit-aware CSS operations - -### @rafters/design-tokens -Token engine with dependency graph: -- **TokenRegistry** - O(1) storage with dependency tracking -- **5 Rule Types:** calc(), state:hover, scale:600, contrast:auto, invert -- **Dependency Engine** - Topological sort, cycle detection -- **Event System** - Real-time change notifications - -### @rafters/ui -React components with cognitive metadata: -- **Primitives** (17 total, vanilla TS, SSR-safe): slot, modal, keyboard, escape-handler, aria, sr-manager, focus, float, classy, etc. -- **Components**: 55 total (52 shadcn-compatible) - Badge, Button, Card, Dialog, Input, Label, Select, Slider, Toast, etc. -- **shadcn drop-in compatibility**: All overlay components (Dialog, Sheet, Drawer, Select, Tooltip, etc.) include Portal/Overlay internally - users can copy shadcn examples verbatim -- Each component includes cognitive load ratings and accessibility requirements - -## Token Format (Rafters Native JSON) -```typescript -{ - "primary": { - "value": "oklch(0.65 0.28 250)", - "scale": [/* 11 steps: 50-950 */], - "perceptualWeight": { "weight": 0.65, "density": "medium" }, - "atmosphericWeight": { "distanceWeight": 0.7, "temperature": "cool" }, - "harmonies": { "complementary": [...], "triadic": [...] }, - "accessibility": { "wcagAA": [...], "wcagAAA": [...] }, - "states": { "hover": "...", "focus": "...", "active": "...", "disabled": "..." }, - "userOverride": { - "previousValue": "oklch(0.60 0.22 240)", - "reason": "Brand requires higher saturation", - "context": "Q1 2026 rebrand initiative" - } - } -} -``` - -## Cross-Worker Communication -Use **Service Bindings** for worker-to-worker calls: -```jsonc -// wrangler.jsonc -{ "services": [{ "binding": "UNCERTAINTY_API", "service": "api-realhandy" }] } -``` - -## Export Formats (Lossy) -```bash -rafters export --format dtcg # W3C Design Tokens -rafters export --format css # CSS custom properties -rafters export --format tailwind # theme.extend config -``` -These strip intelligence for tool interop - Rafters format has 10x more data. diff --git a/.serena/memories/cli-0.0.5-changes.md b/.serena/memories/cli-0.0.5-changes.md deleted file mode 100644 index e8cdedfc..00000000 --- a/.serena/memories/cli-0.0.5-changes.md +++ /dev/null @@ -1,44 +0,0 @@ -# CLI Changes (v0.0.3 - v0.0.5) - -## Pretty Output (v0.0.3) -- Created `packages/cli/src/utils/ui.ts` with ora spinners -- `--agent` flag switches to JSON output for machine consumption -- Human-friendly output shows spinners, success/failure messages -- Events logged through `log()` function that branches on agent mode - -## React Router v7 Support (v0.0.5) -- Added `'react-router'` to Framework type in `detect.ts` -- Detection checks for `react-router` package before Remix (RR7 uses different package name) -- CSS locations: `['app/app.css', 'app/root.css', 'app/styles.css', 'app/globals.css']` -- Component paths: `{ components: 'app/components/ui', primitives: 'app/lib/primitives' }` - -## Config File System (v0.0.5) -- `rafters init` now creates `.rafters/config.rafters.json` -- Config stores: framework, componentsPath, primitivesPath, cssPath -- `rafters add` loads config and uses it for path transformations - -## Path Transformation -```typescript -// In add.ts -function transformPath(registryPath: string, config: RaftersConfig | null): string { - if (!config) return registryPath; - if (registryPath.startsWith('components/ui/')) { - return registryPath.replace('components/ui/', `${config.componentsPath}/`); - } - if (registryPath.startsWith('lib/primitives/')) { - return registryPath.replace('lib/primitives/', `${config.primitivesPath}/`); - } - return registryPath; -} -``` - -## Import Transformation -- `transformFileContent()` now takes config parameter -- Transforms relative imports to use configured paths -- Handles primitives, components, lib, and hooks imports -- Derives lib path as parent of primitivesPath -- Derives hooks path from components path structure - -## Testing -- Tests in `test/utils/detect.test.ts` cover RR7 detection -- Tests pass `null` as config parameter for backward compatibility diff --git a/.serena/memories/cli-architecture.md b/.serena/memories/cli-architecture.md deleted file mode 100644 index 10045fa9..00000000 --- a/.serena/memories/cli-architecture.md +++ /dev/null @@ -1,144 +0,0 @@ -# @rafters/cli Architecture - -## Package Purpose -AI-first design intelligence CLI. Provides MCP server for AI agents and CLI commands for developers. - -## Directory Structure -``` -src/ -├── index.ts # CLI entry point (commander) -├── commands/ -│ ├── init.ts # Initialize Rafters in a project -│ ├── add.ts # Add components -│ ├── mcp.ts # Start MCP server -│ └── studio.ts # Launch Studio -├── mcp/ -│ ├── server.ts # MCP server (stdio transport) -│ └── tools.ts # Tool definitions and handler -├── registry/ -│ ├── client.ts # Fetch from website registry API -│ └── types.ts # Registry response types -└── utils/ - ├── detect.ts # Framework detection - ├── paths.ts # Path resolution - ├── exports.ts # Package export generation - ├── get-package-manager.ts - ├── update-dependencies.ts - └── ui.ts # Console output helpers -``` - -## MCP Server Architecture - -### Server Setup (server.ts) -```typescript -import { Server } from '@modelcontextprotocol/sdk/server/index.js'; -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; - -const server = new Server( - { name: 'rafters', version: '0.0.1' }, - { capabilities: { tools: {} } } -); - -const transport = new StdioServerTransport(); -await server.connect(transport); -``` - -### Tool Handler (tools.ts) -```typescript -class RaftersToolHandler { - constructor(projectRoot: string) { - this.projectRoot = projectRoot; - this.adapter = new NodePersistenceAdapter(projectRoot); - } - - async handleToolCall(name: string, args: Record) { - switch (name) { - case 'rafters_vocabulary': return this.getVocabulary(); - case 'rafters_pattern': return this.getPattern(args.pattern); - case 'rafters_component': return this.getComponent(args.name); - case 'rafters_token': return this.getToken(args.name); - } - } -} -``` - -## Four MCP Tools - -| Tool | Purpose | Input | -|------|---------|-------| -| `rafters_vocabulary` | List available colors, spacing, components, patterns | none | -| `rafters_pattern` | Get guidance for scenario (destructive-action, etc) | `pattern: string` | -| `rafters_component` | Get full component intelligence | `name: string` | -| `rafters_token` | Get token with dependencies and override context | `name: string` | - -## Tool Response Format - -All tools return: -```typescript -{ - isError: boolean; - content: [{ type: 'text', text: string }]; // JSON string -} -``` - -## CLI Commands - -```bash -# Initialize Rafters in a project -rafters init - -# Add a component -rafters add button - -# Start MCP server (for AI agents) -rafters mcp - -# Launch Studio -rafters studio -``` - -## Framework Detection - -Detects and supports: -- Next.js (app router, pages router) -- Vite -- Remix -- Create React App - -Detection order: package.json dependencies → config files → directory structure - -## Registry Client - -Fetches component definitions from website: -```typescript -const client = new RegistryClient('https://rafters.studio'); -const component = await client.getComponent('button'); -const primitive = await client.getPrimitive('focus-trap'); -``` - -## Key Files - -- `src/mcp/tools.ts` - Tool definitions with TOOL_DEFINITIONS array -- `src/mcp/server.ts` - MCP server setup with stdio transport -- `src/commands/init.ts` - Project initialization flow -- `src/registry/client.ts` - Registry API client - -## Running MCP Server - -Via CLI: -```bash -rafters mcp -``` - -Or for Claude Desktop config: -```json -{ - "mcpServers": { - "rafters": { - "command": "npx", - "args": ["rafters", "mcp"], - "cwd": "/path/to/project" - } - } -} -``` diff --git a/.serena/memories/code_style.md b/.serena/memories/code_style.md deleted file mode 100644 index a0b01f49..00000000 --- a/.serena/memories/code_style.md +++ /dev/null @@ -1,74 +0,0 @@ -# Code Style and Conventions - -## TypeScript Configuration -- **Strict mode** - All strict checks enabled -- **ES2024 target** - Modern JavaScript features -- **No `any` types** - `noExplicitAny: error` -- **No implicit any in let** - `noImplicitAnyLet: error` -- **Unused variables/imports are errors** -- **Exhaustive switch cases required** -- **Explicit return types** - `noImplicitReturns: true` - -## Biome Formatting -- **Indent:** 2 spaces -- **Line width:** 100 characters -- **Quotes:** Single quotes -- **Semicolons:** Always -- **Trailing commas:** All (except JSON) -- **Imports:** Auto-organized - -## Biome Linting Rules -- `noExplicitAny: error` -- `noVar: error` - Use const/let -- `useConst: error` - Prefer const -- `noForEach: error` - Use for...of instead -- `noUnusedVariables: error` -- `noUnusedImports: error` -- `noNonNullAssertion: warn` -- `useExhaustiveDependencies: warn` - React hooks - -## Naming Conventions -- **Files:** kebab-case (e.g., `color-utils.ts`, `token-registry.ts`) -- **Components:** PascalCase (e.g., `Button.tsx`, `TokenPreview.tsx`) -- **Functions/variables:** camelCase -- **Types/Interfaces:** PascalCase -- **Constants:** UPPER_SNAKE_CASE for true constants - -## Component Standards -- Must include **cognitive load metadata** -- Must define **dependencies explicitly** -- Must include **accessibility requirements** -- Shadow DOM for component isolation - -## No Emojis -Professional codebase - no emojis in code, comments, or commit messages. - -## Testing Standards -- Minimum 80% coverage target -- Unit tests in `*.test.ts` files -- Component tests use Playwright -- E2E tests use Playwright - -## Project-Specific Patterns - -### Token Definitions -Tokens contain full intelligence with embedded decisions: -- Perceptual weight, atmospheric weight -- Harmonies, accessibility metadata -- States (hover, focus, active, disabled) -- Override reasons when designer changes values - -### 5 Dependency Rule Types -```typescript -'state:hover(primary)' // State transformations -'scale:600(spacing)' // Scale extractions -'contrast:auto(primary)' // Automatic contrast -'invert(primary)' // Dark mode inversion -'calc(spacing.md * 1.5)' // Mathematical calculations -``` - -### React Components -- Use primitives from `packages/ui/src/primitives` (17 primitives including float, classy, slot, modal, etc.) -- Vanilla TypeScript base, framework-agnostic -- SSR-safe implementations -- **shadcn drop-in compatibility**: Overlay components (Dialog, Sheet, Drawer, Select, Tooltip, etc.) include Portal/Overlay internally so users can copy shadcn examples verbatim diff --git a/.serena/memories/color-families-11.md b/.serena/memories/color-families-11.md deleted file mode 100644 index e9848d7e..00000000 --- a/.serena/memories/color-families-11.md +++ /dev/null @@ -1,60 +0,0 @@ -# 11 Rafters Color Families - -From a single primary OKLCH, generate all 11 color families. - -## Sources - -```typescript -import { generateRaftersHarmony, buildColorValue } from '@rafters/color-utils'; - -const harmony = generateRaftersHarmony(primaryOklch); -const colorValue = buildColorValue(primaryOklch); -``` - -## The 11 Families - -### From generateRaftersHarmony() (7) -| Family | Source | Choices | -|--------|--------|---------| -| primary | user's choice | 1 | -| secondary | splitComplementary1/2 | 2 | -| tertiary | triadic1/2 | 2 | -| accent | complementary | 1 | -| highlight | analogous1/2 | 2 | -| surface | desaturated base | 1 | -| neutral | calculated optimal gray | 1 | - -### From colorValue.semanticSuggestions (4) -| Family | Source | Choices | -|--------|--------|---------| -| destructive | danger[0,1,2] | 3 | -| success | success[0,1,2] | 3 | -| warning | warning[0,1,2] | 3 | -| info | info[0,1,2] | 3 | - -## Combined Map - -```typescript -const allFamilies = { - // From harmony - primary: harmony.primary, - secondary: harmony.secondary, // or splitComplementary2 - tertiary: harmony.tertiary, // or triadic2 - accent: harmony.accent, - highlight: harmony.highlight, // or analogous2 - surface: harmony.surface, - neutral: harmony.neutral, - - // From semanticSuggestions - destructive: colorValue.semanticSuggestions.danger[0], // or [1], [2] - success: colorValue.semanticSuggestions.success[0], - warning: colorValue.semanticSuggestions.warning[0], - info: colorValue.semanticSuggestions.info[0], -}; -``` - -## Each Family Becomes a Scale - -Each OKLCH base → `generateOKLCHScale()` → 11-position scale (50-950) - -**11 families × 11 positions = 121 color tokens** diff --git a/.serena/memories/color-intelligence-purpose.md b/.serena/memories/color-intelligence-purpose.md deleted file mode 100644 index c87e03c8..00000000 --- a/.serena/memories/color-intelligence-purpose.md +++ /dev/null @@ -1,54 +0,0 @@ -# Color Intelligence: Two Audiences - -The same color data serves two different purposes. - -## For Humans: Education - -The prose helps designers understand: -- "This color evokes creativity and luxury" -- "Warm tones create urgency" -- "Cultural associations in Western markets" - -Helps them make informed decisions and learn color theory. - -## For AI Agents: Decision Data - -AI doesn't care about poetry. It reads structured properties: - -```typescript -{ - role: 'secondary', - temperature: 'warm', // from atmosphericWeight - atmosphericRole: 'background', // advancing/receding - perceptualWeight: 'light', // visual density - relationship: 'split-complementary', - - // Actionable accessibility - onWhite: { wcagAA: false }, - onBlack: { wcagAA: true }, - minFontSize: 24 -} -``` - -## What AI Uses - -| Property | Use | -|----------|-----| -| `role` | Which family this belongs to | -| `temperature` | Warm/cool for visual balance | -| `atmosphericRole` | Background vs foreground decisions | -| `perceptualWeight` | Balance heavy/light elements | -| `accessibility.onWhite/onBlack` | Contrast pairing decisions | -| `harmonicRelationship` | Understand why colors work together | - -## The Core Philosophy - -**AI doesn't have taste.** It doesn't guess at colors. - -It reads: -1. Designer's recorded decisions (which option they picked) -2. Structured properties (temperature, weight, role) -3. Mathematical relationships (complementary, triadic, etc.) - -The intelligence prose educates designers. -The structured data informs agents. diff --git a/.serena/memories/color-selection-flow.md b/.serena/memories/color-selection-flow.md deleted file mode 100644 index 4dbd09c1..00000000 --- a/.serena/memories/color-selection-flow.md +++ /dev/null @@ -1,74 +0,0 @@ -# Color Selection Flow - -## Two-Phase Pattern - -### Phase 1: Instant Math (local) -```typescript -const colorValue = buildColorValue(oklch); // @rafters/color-utils -const harmony = generateRaftersHarmony(oklch); -``` - -Returns immediately: -- 11-position scale -- Harmonies with choices -- Semantic suggestions (danger/success/warning/info) -- Accessibility data (WCAG, APCA) -- Perceptual/atmospheric weights - -### Phase 2: Async Intelligence (API) -```typescript -// Fire and forget - don't block UI -fetch(`https://api.rafters.studio/color/${l}-${c}-${h}?sync=true`) - .then(res => res.json()) - .then(data => { - // Update token with intelligence when it arrives - token.value.intelligence = data.color.intelligence; - }); -``` - -Adds (when available): -- AI reasoning -- Emotional impact -- Cultural context -- Usage guidance - -## WhyGate Rules - -**NO explanation needed:** -- Picking from computed options (tertiary[0] vs tertiary[1]) -- Math justifies the choice - -**Explanation required:** -- Primary color (the seed - user's arbitrary choice) -- Custom override (deviating from ALL computed options) - -```typescript -// No userOverride - picked from options -{ name: 'tertiary', value: harmony.triadic2 } - -// userOverride required - custom value -{ - name: 'tertiary', - value: customOklch, - userOverride: { - reason: "Client brand guidelines", - overriddenAt: "2025-01-30T..." - } -} -``` - -## Intelligence Fetch on Every Selection - -When user picks ANY option (even from computed choices), fetch intelligence: - -```typescript -// User picks tertiary[0] -const selected = harmony.triadic1; - -// Fetch intelligence async (no WhyGate needed) -fetchColorIntelligence(selected).then(enriched => { - token.value.intelligence = enriched.intelligence; -}); -``` - -Every color token gets enriched with AI context. diff --git a/.serena/memories/color-utils-architecture.md b/.serena/memories/color-utils-architecture.md deleted file mode 100644 index 8d2c855a..00000000 --- a/.serena/memories/color-utils-architecture.md +++ /dev/null @@ -1,153 +0,0 @@ -# @rafters/color-utils Architecture - -## Package Purpose -OKLCH color manipulation and intelligence. Pure functions, no state. Used by design-tokens for color generation and by MCP tools for color analysis. - -## Directory Structure -``` -src/ -├── index.ts # All exports -├── builder.ts # buildColorValue() - creates ColorValue objects -├── harmony.ts # Color theory harmonies and semantic suggestions -├── accessibility.ts # WCAG/APCA contrast calculations -├── analysis.ts # Temperature, lightness detection -├── conversion.ts # OKLCH ↔ hex ↔ CSS -├── manipulation.ts # Adjustments, blending, surface/neutral generation -├── validation-alerts.ts # Semantic mapping validation -└── naming/ # Deterministic color naming system - ├── hue-hubs.ts # 18 hue hubs × temperature variants - ├── word-banks.ts # Material, intensity, luminosity words - ├── quantize.ts # L/C/H bucketing - └── generator.ts # Name generation algorithm -``` - -## Core Functions - -### buildColorValue(oklch, options?) → ColorValue -The main entry point. Creates a complete ColorValue with: -- `name` - Deterministic human-readable name -- `scale` - 11-position lightness scale (50-950) -- `harmonies` - complementary, triadic, analogous, tetradic, monochromatic -- `accessibility` - WCAG AA/AAA, APCA, contrast ratios -- `analysis` - temperature (warm/cool/neutral), isLight -- `atmosphericWeight` - spatial/depth perception -- `perceptualWeight` - visual density -- `semanticSuggestions` - danger[], success[], warning[], info[] - -### generateRaftersHarmony(oklch) → 7 colors -Color theory harmonies mapped to semantic roles: -| Role | Source | Theory | -|------|--------|--------| -| primary | base | User's choice | -| secondary | splitComplementary1 | Sophisticated contrast | -| tertiary | triadic1 | Visual interest | -| accent | complementary | Maximum attention | -| highlight | analogous1 | Subtle emphasis | -| surface | desaturated base | Backgrounds | -| neutral | calculated gray | Text, borders | - -### generateSemanticColorSuggestions(oklch) → 4×3 colors -Status colors derived from base, maintaining harmony: -| Semantic | Hue Range | Choices | -|----------|-----------|---------| -| danger | Red 0-30° | 3 variants | -| success | Green 120-150° | 3 variants | -| warning | Orange/Yellow 30-70° | 3 variants | -| info | Blue 200-240° | 3 variants | - -Each suggestion adapts lightness/chroma relative to the base color. - -## 11 Families Algorithm - -From a single primary OKLCH: -1. `generateRaftersHarmony()` → 7 families (primary, secondary, tertiary, accent, highlight, surface, neutral) -2. `buildColorValue().semanticSuggestions` → 4 families (destructive, success, warning, info) -3. Each family → `generateOKLCHScale()` → 11 positions (50-950) - -**11 families × 11 positions = 121 color tokens** - -## Color Naming System - -Deterministic names from OKLCH coordinates using hub/spoke architecture: - -### Structure -- **18 hue hubs** (20° each, covering 360°) -- **5 lightness bands** (veryDark, dark, mid, light, veryLight) -- **4 chroma bands** (muted, moderate, saturated, vivid) -- **3 temperature variants** (warm, cool, neutral) - -### Algorithm -``` -OKLCH → bucketize(L,C,H) → hueHub[temperature][lightnessBand][chromaBand] → word[] -``` -Sub-index selection uses fractional position within bucket for deterministic synonym choice. - -### Name Format -``` -{prefix}-{material}-{hue} -``` -Examples: "silver-bold-fire-truck", "dark-deep-glacier", "bright-soft-honey" - -## Accessibility Functions - -```typescript -// WCAG 2.1 contrast ratio -calculateWCAGContrast(fg: OKLCH, bg: OKLCH): number - -// APCA (Advanced Perceptual Contrast Algorithm) -calculateAPCAContrast(fg: OKLCH, bg: OKLCH): number - -// Find accessible color by adjusting lightness -findAccessibleColor(color: OKLCH, background: OKLCH, targetContrast: number): OKLCH -``` - -## Key Types - -```typescript -interface OKLCH { - l: number; // Lightness 0-1 - c: number; // Chroma 0-0.4 - h: number; // Hue 0-360 - alpha?: number; -} - -interface ColorValue { - name: string; - scale: OKLCH[]; - harmonies: { complementary, triadic[], analogous[], tetradic[], monochromatic[] }; - accessibility: { wcagAA, wcagAAA, onWhite, onBlack, apca }; - analysis: { temperature, isLight, name }; - atmosphericWeight: { atmosphericRole, distanceWeight, temperature }; - perceptualWeight: { weight, density, balancingRecommendation }; - semanticSuggestions: { danger[], success[], warning[], info[] }; -} -``` - -## Usage Patterns - -```typescript -import { - buildColorValue, - generateRaftersHarmony, - generateOKLCHScale, - hexToOKLCH, - oklchToCSS, - generateColorName, -} from '@rafters/color-utils'; - -// From hex to full ColorValue -const oklch = hexToOKLCH('#3B82F6'); -const colorValue = buildColorValue(oklch); - -// Get harmonies for design system -const harmony = generateRaftersHarmony(oklch); - -// Generate scale for a family -const scale = generateOKLCHScale(harmony.primary); - -// Get deterministic name -const name = generateColorName(oklch); // e.g., "silver-true-sky" - -// Convert to CSS -const css = oklchToCSS(oklch); // "oklch(0.623 0.214 255)" -``` diff --git a/.serena/memories/design-tokens-architecture.md b/.serena/memories/design-tokens-architecture.md deleted file mode 100644 index 16a83b97..00000000 --- a/.serena/memories/design-tokens-architecture.md +++ /dev/null @@ -1,321 +0,0 @@ -# @rafters/design-tokens Architecture - -## Package Purpose -Dependency-aware design token system. **100% source-only workspace import - never published to npm.** - -Source of truth for all token operations. Used directly by CLI and Studio via workspace imports (no API wrapper needed). - -## Directory Structure -``` -src/ -├── index.ts # Main exports -├── registry.ts # TokenRegistry - runtime engine -├── dependencies.ts # TokenDependencyGraph - DAG -├── generation-rules.ts # Rule parser/executor -├── registry-factory.ts # Factory (simplified) -├── generators/ # Token generators by namespace -│ ├── color.ts # OKLCH 11-position scales -│ ├── spacing.ts # minor-third (1.2) progression -│ ├── typography.ts # Font scales -│ ├── semantic.ts # primary, destructive, success, etc. -│ ├── defaults.ts # All default values (240+ tokens) -│ └── [radius|shadow|depth|motion|breakpoint|elevation|focus].ts -├── exporters/ -│ ├── tailwind.ts # Tailwind v4 CSS (@theme, :root, dark mode) -│ ├── typescript.ts # Type-safe constants -│ ├── dtcg.ts # W3C Design Tokens format -│ └── style-dictionary.ts -├── persistence/ -│ ├── node-adapter.ts # .rafters/tokens/*.rafters.json -│ └── types.ts -└── plugins/ # Rule type implementations - ├── calc.ts # calc({base} * 2) - ├── state.ts # state:hover|focus|active|disabled - ├── scale.ts # scale:600 - ├── contrast.ts # contrast:auto|high|medium|low - └── invert.ts # invert (dark mode) -``` - -## Core Classes - -### TokenRegistry (registry.ts) -```typescript -class TokenRegistry { - private tokens: Map; - public dependencyGraph: TokenDependencyGraph; - - // Core operations - get(name: string): Token | undefined - add(token: Token): void - has(name: string): boolean - list(filter?: { category?, namespace? }): Token[] - size(): number - - // Update with events - updateToken(name: string, value: string): void // fires token-changed - updateMultipleTokens(updates: Array<{name, value}>): void // fires tokens-batch-changed - async set(name: string, value: string): Promise // updateToken + regenerateDependents - - // Event system (for Studio live CSS) - setChangeCallback(callback: RegistryChangeCallback): void - - // Dependency graph - addDependency(tokenName, dependsOn[], rule): void - addDependencies(deps[]): void // bulk - getDependents(tokenName): string[] - getDependencies(tokenName): string[] - getDependencyInfo(tokenName): { dependsOn, rule } | null - getTopologicalOrder(): string[] - - // Validation - validate(): { isValid, errors[] } - validateComplete(): { isValid, errors[], ruleErrors[] } -} -``` - -### TokenDependencyGraph (dependencies.ts) -- Bidirectional: `dependsOn[]` (parents) and `dependents[]` (children) -- `generationRule` stored per token -- Topological sort with caching (`_sortCache`) -- Cycle detection on add -- Bulk operations for performance - -### Generation Rules (5 types) -1. `calc({token} * 2)` - math with token substitution -2. `state:hover|focus|active|disabled` - interaction variants -3. `scale:600` - extract scale position -4. `contrast:auto|high|medium|low` - WCAG contrast -5. `invert` - lightness inversion for dark mode - -## Key Behaviors - -### regenerateDependents() respects userOverride -```typescript -// In regenerateToken(): -if (existingToken.userOverride) { - // Update computedValue but preserve value (human's choice) - this.tokens.set(tokenName, { - ...existingToken, - computedValue: newComputedValue, // what rule would produce - // value stays as-is - }); -} else { - // No override - update actual value - this.tokens.set(tokenName, { - ...existingToken, - value: newComputedValue, - computedValue: newComputedValue, - }); -} -``` - -### COMPUTED Symbol - Override Clearing and Self-Repair - -The `COMPUTED` symbol (from @rafters/shared) enables clearing overrides and triggering DAG self-repair: - -```typescript -import { COMPUTED } from '@rafters/shared'; - -// Clear override and restore to computed/previous value -await registry.set('spacing-4', COMPUTED); -``` - -**Behavior depends on token type:** -- **Derived tokens** (have `generationRule`): Override removed, value regenerated from rule -- **Root tokens** (no rule): Override removed, value restored to `previousValue` - -**Why a symbol?** Prevents accidental `null` clearing. `Symbol.for('rafters.computed')` is globally unique across packages. - -**Self-repair cascade:** After clearing an override, all dependents automatically regenerate via `regenerateDependents()`. - -```typescript -// Example: Clear override triggers cascade -registry.set('spacing-base', COMPUTED); -// -> spacing-base regenerates -// -> spacing-2, spacing-4, spacing-8, etc. all regenerate -``` - -### Event Types -```typescript -type TokenChangeEvent = - | { type: 'token-changed', tokenName, oldValue?, newValue?, timestamp } - | { type: 'tokens-batch-changed', changes[], timestamp } - | { type: 'registry-initialized', tokenCount, timestamp } -``` - -## Main Entry Points - -```typescript -// Generate full system with exports -const { system, registry, exports } = buildColorSystem({ - config: { colorPaletteBases: customColors }, - exports: { tailwind: true, dtcg: true, typescript: true } -}); - -// Create registry from tokens -const registry = new TokenRegistry(tokens); - -// Export to Tailwind CSS -const css = registryToTailwind(registry, { includeImport: true }); - -// Node persistence (simple 2-method interface) -const adapter = new NodePersistenceAdapter(cwd); -const tokens = await adapter.load(); // All tokens from all namespace files -await adapter.save(tokens); // Groups by namespace internally -``` - -## Persistence Architecture - -The `PersistenceAdapter` interface is intentionally minimal: - -```typescript -interface PersistenceAdapter { - load(): Promise; - save(tokens: Token[]): Promise; -} -``` - -**Why so simple?** This contract enables any storage backend: -- `NodePersistenceAdapter` - .rafters/tokens/*.rafters.json (groups by namespace internally) -- Future: `CloudflareKVAdapter`, `D1Adapter`, `IndexedDBAdapter` - -The adapter hides storage details. Callers don't know if tokens are in files, KV, or a database. - -### Registry Integration - -The registry owns persistence through dirty tracking: - -```typescript -// Registry manages its own persistence -registry.setAdapter(adapter); - -// set() marks namespace dirty and auto-persists -await registry.set('spacing-4', '2rem'); // Saves only affected namespaces -``` - -**Dirty tracking** ensures only changed namespaces are written, not the entire token set. - -## Tailwind Exporters - -Four functions for different use cases: - -```typescript -// Production - combined @theme + values (apps import rafters.css) -registryToTailwind(registry): string - -// Studio static - @theme inline with var() refs (processed once at startup) -registryToTailwindStatic(registry): string - -// Studio dynamic - pure CSS variables (instant HMR, no Tailwind rebuild) -registryToVars(registry): string - -// Standalone - fully compiled CSS via Tailwind CLI (no build step needed) -registryToCompiled(registry, options?): Promise -``` - -The `registryToCompiled` function: -- Generates theme CSS with `registryToTailwind()` -- Runs it through `@tailwindcss/cli` (bundled dependency) -- Returns fully resolved CSS with all utilities -- Options: `{ minify?: boolean, includeImport?: boolean }` - -## Tailwind Export Structure (rafters.css) -```css -@import "tailwindcss"; - -@theme { - --color-neutral-50: oklch(...); - --color-neutral-100: oklch(...); - /* ... all color scales */ - --spacing-1: 0.25rem; - /* ... all tokens by namespace */ -} - -@theme inline { - --color-primary: var(--primary); - --color-destructive: var(--destructive); - /* semantic bridges */ -} - -:root { - --rafters-primary: var(--color-neutral-900); - --rafters-dark-primary: var(--color-neutral-50); - --primary: var(--rafters-primary); - /* ... */ -} - -@media (prefers-color-scheme: dark) { - :root { --primary: var(--rafters-dark-primary); } -} - -.dark { --primary: var(--rafters-dark-primary); } -``` - -## Token Schema (key fields) -```typescript -interface Token { - name: string; - value: string | ColorValue | ColorReference; - category: string; - namespace: string; - - // Dependencies - dependsOn?: string[]; - generationRule?: string; // "calc({base}*2)", "state:hover", etc. - computedValue?: string; // what rule would produce - - // Human override (CRITICAL for agent intelligence) - userOverride?: { - previousValue: string | ColorValue | ColorReference; // enables undo/self-repair - reason: string; // WHY overridden (required) - context?: string; // optional additional context - }; - - // Designer intent - usagePatterns?: { do: string[], never: string[] }; - semanticMeaning?: string; - usageContext?: string[]; -} -``` - -## Studio Integration Pattern - -Studio imports directly from @rafters/design-tokens (workspace dependency). -Uses split CSS for instant HMR (no Tailwind rebuild needed). - -```typescript -import { - TokenRegistry, - NodePersistenceAdapter, - registryToTailwind, - registryToTailwindStatic, - registryToVars, - registryToTypeScript, - toDTCG -} from '@rafters/design-tokens'; - -// Load all tokens and create registry -const adapter = new NodePersistenceAdapter(cwd); -const allTokens = await adapter.load(); -const registry = new TokenRegistry(allTokens); - -// Connect adapter for auto-persistence -registry.setAdapter(adapter); - -// Studio startup - write static Tailwind config (processed once) -await writeFile('.rafters/output/rafters.tailwind.css', registryToTailwindStatic(registry)); - -// Live CSS updates - only vars file (instant HMR, no Tailwind rebuild) -registry.setChangeCallback(async () => { - await writeFile('.rafters/output/rafters.vars.css', registryToVars(registry)); -}); - -// Edit (auto-cascades, respects overrides, auto-persists dirty namespaces) -await registry.set('primary', 'oklch(0.5 0.2 250)'); -// No manual save needed - registry.set() persists automatically - -// Explicit save - generate production files -await writeFile('.rafters/output/rafters.css', registryToTailwind(registry)); -await writeFile('.rafters/output/rafters.ts', registryToTypeScript(registry)); -await writeFile('.rafters/output/rafters.json', JSON.stringify(toDTCG(registry.list()), null, 2)); -``` diff --git a/.serena/memories/dev-server-running.md b/.serena/memories/dev-server-running.md deleted file mode 100644 index ad9009dc..00000000 --- a/.serena/memories/dev-server-running.md +++ /dev/null @@ -1,12 +0,0 @@ -# Development Environment - -## Dev Servers Already Running - -The demo app dev server is **always running** during development sessions. - -**DO NOT** start dev servers. They are already running: -- Demo app: http://localhost:4321 - -If you need to verify something in the browser, just navigate to the URL - don't try to start servers. - -If a hard reset is needed, wait for user to explicitly request it. diff --git a/.serena/memories/docs-rs-architecture.md b/.serena/memories/docs-rs-architecture.md deleted file mode 100644 index 396f9060..00000000 --- a/.serena/memories/docs-rs-architecture.md +++ /dev/null @@ -1,112 +0,0 @@ -# packages/docs-rs - Rust Documentation Generator - -## Overview -`rafters-docs` is a Rust-powered component documentation generator that transforms MDX files into a static site with interactive Web Component previews. The key insight: documentation previews don't need React/Solid runtimes - they just need to look right. JSX is transformed into static Web Components with Shadow DOM. - -## Workspace Structure (Cargo workspace, edition 2021) -``` -packages/docs-rs/ -├── Cargo.toml # Workspace manifest -├── rust-toolchain.toml # stable channel -├── .cargo/config.toml # parallel builds, clippy alias -├── crates/ -│ ├── rafters-mdx/ # MDX parsing (pulldown-cmark, serde_yaml) -│ ├── rafters-adapters/ # JSX -> Web Component transformation (oxc_parser, regex) -│ ├── rafters-static/ # Static site generation (minijinja, lightningcss, rayon) -│ ├── rafters-server/ # Dev server + HMR (axum, notify, tokio) -│ └── rafters-docs/ # CLI binary (clap) -├── docs/ # Project documentation -│ ├── ARCHITECTURE.md -│ ├── DEVELOPER.md -│ └── USER_GUIDE.md -└── dist/ # Built output -``` - -## Dependency Graph -``` -rafters-docs (CLI) - ├── rafters-server - │ ├── rafters-mdx - │ └── rafters-adapters - └── rafters-static - ├── rafters-mdx - └── rafters-adapters -``` - -## Crate Details - -### rafters-mdx -- **Purpose**: Parse MDX files, extract YAML frontmatter, code blocks, headings/TOC -- **Key types**: `ParsedDoc`, `Frontmatter`, `CodeBlock`, `BlockMode` (Live/Editable/Source/Preview), `Language`, `TocEntry` -- **Pipeline**: frontmatter extraction -> markdown parsing (pulldown-cmark) -> code block extraction -> heading extraction -- **Code block modes**: `live` (Web Component preview), `editable` (future), `preview` (iframe), `source` (default, syntax highlight only) -- **`is_live()`**: true when mode=Live AND language is transformable (TSX/JSX) -- **Files**: lib.rs, frontmatter.rs, parser.rs, codeblock.rs - -### rafters-adapters -- **Purpose**: Transform JSX source code into Web Component definitions -- **Key types**: `FrameworkAdapter` trait, `ReactAdapter`, `ComponentStructure`, `TransformedBlock`, `ComponentRegistry`, `InlineJsx` -- **React adapter extraction**: Uses regex patterns (LazyLock) to extract variantClasses, sizeClasses, baseClasses, disabledClasses, component name, observed attributes -- **variantClasses is REQUIRED** - transform fails with `MissingVariants` if absent -- **ComponentRegistry**: Scans directories for .tsx/.jsx files, skips test/stories/index files, caches parsed structures -- **InlineJsx parser**: Parses `` from doc code blocks, handles self-closing, children, nested same-name components, props (string/boolean/expression) -- **`to_custom_element()`**: Converts InlineJsx to `Click` with HTML escaping -- **Generator**: Produces ES6 class extending HTMLElement with Shadow DOM, adoptedStyleSheets for Tailwind CSS, slot-based content, observed attributes -- **Files**: lib.rs, traits.rs, react.rs, inline.rs, generator.rs, registry.rs - -### rafters-static -- **Purpose**: Build complete static documentation site -- **Key types**: `StaticBuilder`, `BuildConfig`, `BuildResult`, `TemplateEngine`, `AssetPipeline` -- **Build pipeline**: discover MDX files -> parse -> sort by frontmatter order -> build navigation -> parallel render pages (Rayon) -> generate assets -> generate search index JSON -> generate sitemap.xml + robots.txt -- **Page rendering**: For each live code block, tries inline JSX parsing first (looks up component in registry), falls back to full component transform. Replaces live blocks with `
` + Web Component HTML + source code below -- **Template engine**: minijinja with base.html (layout), doc.html (content + TOC), nav.html (sidebar) -- **Asset pipeline**: Default CSS using Rafters design tokens (CSS variables), responsive layout, lightningcss minification. JS for mobile menu, active nav, copy code buttons -- **Rafters CSS integration**: Optional `rafters_css` config to include design token stylesheet -- **Files**: lib.rs, builder.rs, templates.rs, assets.rs - -### rafters-server -- **Purpose**: Development server with hot module replacement -- **Key types**: `DevServer`, `DevServerConfig`, `FileWatcher`, `WatchEvent`, `HmrHub`, `HmrMessage` -- **Default port**: 7777 -- **Routes**: `GET /` (index), `GET /__hmr` (WebSocket), `GET /__hmr.js` (client script), `/docs/*` (static files) -- **HMR flow**: File system (notify/inotify) -> FileWatcher thread (100ms debounce) -> classify event (MDX/Component/Other) -> WatchEvent -> broadcast via HmrHub (tokio broadcast channel) -> WebSocket -> browser -- **HMR messages**: Connected, Reload, UpdateComponent (tag_name + web_component JS), UpdateContent (path + html) -- **Component hot update**: Re-transforms changed component, sends new Web Component JS to browser, forces re-render of existing instances via connectedCallback() -- **Files**: lib.rs, server.rs, watcher.rs, websocket.rs - -### rafters-docs (CLI) -- **Purpose**: CLI orchestration with clap -- **Commands**: `init` (scaffolds docs.toml + docs/), `dev` (starts dev server), `build` (static site gen), `serve` (preview built site on port 4000) -- **Config**: `docs.toml` with [docs] (dir, output, title, base_url, rafters_css), [components] (dir), [build] (minify) -- **Flags**: `--config` (path to docs.toml), `--verbose`, per-command flags -- **Files**: main.rs, commands/{mod,init,dev,build,serve}.rs - -## Key Design Decisions -1. **Zero-runtime previews**: Web Components are native, no React/Solid runtime in docs -2. **Shadow DOM + adoptedStyleSheets**: Copies page-level Tailwind CSS into shadow roots -3. **Regex-based extraction (not AST)**: ReactAdapter uses regex to find variantClasses/sizeClasses patterns - simpler, works for convention-based components -4. **Inline JSX parsing**: Separate parser for doc code blocks (` - * - * // Destructive action - requires confirmation UX - * - * - * // Loading state - prevents double submission - * - * ``` - */ -``` - -## Example from Dialog.tsx - -```tsx -/** - * Modal dialog component with focus management and escape patterns - * - * @registry-name dialog - * @registry-version 0.1.0 - * @registry-status published - * @registry-path components/ui/Dialog.tsx - * @registry-type registry:component - * - * @cognitive-load 6/10 - Interrupts user flow, requires decision making - * @attention-economics Attention capture: modal=full attention, drawer=partial attention, popover=contextual attention - * @trust-building Clear close mechanisms, confirmation for destructive actions, non-blocking for informational content - * @accessibility Focus trapping, escape key handling, backdrop dismissal, screen reader announcements - * @semantic-meaning Usage patterns: modal=blocking workflow, drawer=supplementary, alert=urgent information - * - * @usage-patterns - * DO: Low trust - Quick confirmations, save draft (size=sm, minimal friction) - * DO: Medium trust - Publish content, moderate consequences (clear context) - * DO: High trust - Payments, significant impact (detailed explanation) - * DO: Critical trust - Account deletion, permanent loss (progressive confirmation) - * NEVER: Routine actions, non-essential interruptions - * - * @design-guides - * - Trust Building: https://rafters.studio/docs/llm/trust-building - * - Cognitive Load: https://rafters.studio/docs/llm/cognitive-load - * - Progressive Enhancement: https://rafters.studio/docs/llm/progressive-enhancement - * - * @dependencies @radix-ui/react-dialog, @rafters/design-tokens/motion - * - * @example - * ```tsx - * // Critical trust dialog with confirmation - * - * - * - * - * - * Delete Account - * This action cannot be undone. - * - * - * ``` - */ -``` - -## Example from Card.tsx - -```tsx -/** - * Flexible container component for grouping related content with semantic structure - * - * @registry-name card - * @registry-version 0.1.0 - * @registry-status published - * @registry-path components/ui/Card.tsx - * @registry-type registry:component - * - * @cognitive-load 2/10 - Simple container with clear boundaries and minimal cognitive overhead - * @attention-economics Neutral container: Content drives attention, elevation hierarchy for interactive states - * @trust-building Consistent spacing, predictable interaction patterns, clear content boundaries - * @accessibility Proper heading structure, landmark roles, keyboard navigation for interactive cards - * @semantic-meaning Structural roles: article=standalone content, section=grouped content, aside=supplementary information - * - * @usage-patterns - * DO: Group related information with clear visual boundaries - * DO: Create interactive cards with hover states and focus management - * DO: Establish information hierarchy with header, content, actions - * DO: Implement responsive scaling with consistent proportions - * NEVER: Use decorative containers without semantic purpose - * - * @design-guides - * - Content Grouping: https://rafters.studio/docs/llm/content-grouping - * - Attention Economics: https://rafters.studio/docs/llm/attention-economics - * - Spatial Relationships: https://rafters.studio/docs/llm/spatial-relationships - * - * @dependencies @rafters/design-tokens/motion - * - * @example - * ```tsx - * // Basic card with content structure - * - * - * Card Title - * Supporting description - * - * - * Main card content - * - * - * - * - * - * ``` - */ -``` diff --git a/.serena/memories/project_overview.md b/.serena/memories/project_overview.md deleted file mode 100644 index f78b2bed..00000000 --- a/.serena/memories/project_overview.md +++ /dev/null @@ -1,83 +0,0 @@ -# Rafters Project Overview - -**READ `what_rafters_is` MEMORY FIRST.** That explains what Rafters actually is and why it exists. This file is just technical reference. - -## Purpose -Rafters is a **Design Intelligence Protocol for AI Agents**. - -## Design Philosophy -See `docs/DESIGN_PHILOSOPHY.md` for the complete philosophy document that balances: -- **Craft (Jobs/Ive/Rams)** - Deep simplicity, every detail intentional, design as soul -- **Experimentation (Joshua Davis)** - Structured chaos, room for delight within constraints -- **Usability (Jakob Nielsen)** - Empirical validation via 10 heuristics - -The system exists to encode design judgment - built from decades of work at Frog, IDEO, physical devices, brand systems - into a format machines can learn from. AI agents don't have taste; Rafters provides data that simulates taste. - -Key tension: Craft without experimentation is sterile. Experimentation without usability is chaos. Usability without craft looks like ass. All three, together. It converts subjective design decisions into objective, queryable data structures that AI agents can use to build interfaces without guessing at colors, spacing, hierarchy, and balance. - -**Core concept:** AI agents don't have taste. They need data. Rafters provides data that simulates taste through three interconnected registries: - -1. **Token Registry** - What design values exist and why (OKLCH scales, musical progressions, perceptual weights) -2. **Component Registry** - What UI patterns exist and when to use them (cognitive load, semantic meaning) - - 55 components (52 shadcn-compatible), 17 primitives, 72 total registry items - - Schema uses `primitives` (not `registryDependencies`) with per-file versioned dependencies -3. **Designer Decisions Archive** - Why choices were made (embedded in tokens) - -## Tech Stack - -### Core -- **TypeScript** - Strict mode, ES2024 target -- **Node.js** >= 24.12.0 -- **pnpm** >= 10.25.0 (required package manager) -- **Monorepo** - pnpm workspaces - -### Frontend -- **Astro** - Website/docs (apps/website) -- **React** - UI components (packages/ui) -- **MDX** - Documentation - -### Backend -- **Hono** - API framework with `@hono/zod-openapi` -- **Cloudflare Workers** - Runtime -- **D1** - Color cache database -- **Vectorize** - Semantic search -- **Workers AI** - Color intelligence generation - -### Testing -- **Vitest** - Unit testing -- **Playwright** - E2E and component testing -- **Testing Library** - React component testing -- **Axe-core** - Accessibility testing - -### Code Quality -- **Biome** - Linting and formatting -- **Lefthook** - Git hooks -- **TypeScript** - Strict type checking - -## Monorepo Structure - -``` -rafters/ -├── apps/ -│ ├── api/ # Hono backend on Cloudflare Workers -│ ├── cli/ # AI-first CLI with embedded MCP server -│ └── website/ # Astro docs and Studio interface -├── packages/ -│ ├── cli/ # CLI implementation -│ ├── color-utils/ # OKLCH color intelligence -│ ├── design-tokens/# Token engine with dependency graph -│ ├── math-utils/ # Mathematical progressions -│ ├── shared/ # Consolidated types and utilities -│ └── ui/ # React components with cognitive metadata -├── test/ # Shared test utilities -└── docs/ # Additional documentation -``` - -## Key Package Aliases -- `@rafters/shared` → `packages/shared/src/index.ts` -- `@rafters/color-utils` → `packages/color-utils/src/index.ts` -- `@rafters/math-utils` → `packages/math-utils/src/index.ts` -- `@rafters/design-tokens` → `packages/design-tokens/src/index.ts` - -## Production Domain -`rafters.studio` diff --git a/.serena/memories/rafters-component-patterns.md b/.serena/memories/rafters-component-patterns.md deleted file mode 100644 index d19f80d1..00000000 --- a/.serena/memories/rafters-component-patterns.md +++ /dev/null @@ -1,108 +0,0 @@ -# Rafters Component Patterns - -## Compound Components - -Many components use the compound pattern with namespaced exports: - -```tsx -// Provider wraps app/section - - {/* Root wraps each instance */} - - {/* Trigger + Content are siblings */} - - - - - Help text - - - -``` - -Components using this pattern: -- Tooltip (Provider, Trigger, Content) -- Dialog (Root, Trigger, Portal, Overlay, Content, Header, Footer, Title, Description, Close) -- Sidebar (Provider, Trigger, Rail, Inset, Header, Footer, Content, Group, Menu, MenuItem, etc.) -- Grid (Root, Item) - -## asChild Pattern - -Pass styling/behavior to a child element instead of creating a wrapper: - -```tsx -// Without asChild - creates a button wrapper - - Click me - - -// With asChild - applies to the Button directly - - - -``` - -The asChild pattern uses `React.cloneElement` to merge props onto the child. - -## Button Variants - -Semantic variants map to token classes: -- `default`/`primary` - main actions (bg-primary) -- `secondary` - supporting actions (bg-secondary) -- `destructive` - irreversible actions (bg-destructive) -- `success`, `warning`, `info` - status feedback -- `ghost` - minimal, transparent -- `outline` - bordered, transparent background - -Size variants: -- `sm` - tertiary actions -- `default` - secondary interactions -- `lg` - primary CTAs -- `icon` - square icon buttons - -## Separator - -Simple divider using token colors: - -```tsx -// Horizontal (default) - - -// Vertical (for toolbars) - -``` - -Uses `bg-border` token for color. - -## Container Props Recap - -```tsx - -``` - -## Typography Selection - -Choose by semantic meaning, not visual appearance: -- H1 = page title -- H2 = section heading -- H3 = subsection -- Small = fine print, captions -- Muted = secondary info -- Lead = introductory paragraphs - -## Token Classes in Components - -All components use semantic token classes: -- `bg-primary`, `text-primary-foreground` -- `bg-muted`, `text-muted-foreground` -- `border-border` -- `hover:bg-primary-hover` -- `focus-visible:ring-primary-ring` - -Never raw colors like `bg-blue-500` or arbitrary values. diff --git a/.serena/memories/rafters-compound-components.md b/.serena/memories/rafters-compound-components.md deleted file mode 100644 index a504b9d7..00000000 --- a/.serena/memories/rafters-compound-components.md +++ /dev/null @@ -1,86 +0,0 @@ -# Rafters Compound Component Patterns - -## Pattern Structure - -Rafters uses namespaced compound components with React Context for state sharing. - -### Root + Subcomponents -```tsx -// Root creates context, subcomponents consume it - - - Tokens - Preview - - ... - ... - -``` - -### Implementation Pattern -```tsx -// Context for sharing state -const TabsContext = React.createContext(null); - -// Root component provides context -function Tabs({ children, defaultValue, ...props }) { - const [value, setValue] = useState(defaultValue); - return ( - -
{children}
-
- ); -} - -// Subcomponents consume context -function TabsTrigger({ value, children }) { - const { value: selected, setValue } = useContext(TabsContext); - return ; -} - -// Namespace attachment -Tabs.List = TabsList; -Tabs.Trigger = TabsTrigger; -Tabs.Content = TabsContent; -``` - -## Components Using This Pattern - -| Component | Root | Subcomponents | -|-----------|------|---------------| -| Tooltip | Tooltip.Provider | Tooltip, Tooltip.Trigger, Tooltip.Content | -| Tabs | Tabs | Tabs.List, Tabs.Trigger, Tabs.Content | -| Card | Card | Card.Header, Card.Title, Card.Description, Card.Content, Card.Footer | -| Dialog | Dialog | Dialog.Trigger, Dialog.Content, Dialog.Header, Dialog.Footer | - -## Key Principles - -1. **Root provides context** - State lives in root, flows down via context -2. **Subcomponents are pure** - They read context, render accordingly -3. **Value-based matching** - Tabs/Trigger/Content match by `value` prop -4. **Controlled or uncontrolled** - Support both `value` (controlled) and `defaultValue` (uncontrolled) -5. **asChild pattern** - Tooltip.Trigger can pass behavior to child via `asChild` - -## asChild Pattern - -The `asChild` prop uses slot primitive to merge props with the child element: - -```tsx -// Without asChild - renders a button -Click me - -// With asChild - passes tooltip behavior to Button - - - -``` - -This allows any element to become a trigger without wrapper divs. - -## Semantic Props - -Components often have `as` prop for semantic HTML: -- Card: `as="article" | "section" | "aside" | "div"` -- Container: `as="main" | "nav" | "aside" | "section" | "div"` - -This separates semantic meaning from visual appearance. diff --git a/.serena/memories/rafters-form-patterns.md b/.serena/memories/rafters-form-patterns.md deleted file mode 100644 index 98ae478f..00000000 --- a/.serena/memories/rafters-form-patterns.md +++ /dev/null @@ -1,89 +0,0 @@ -# Rafters Form Patterns - -## Field + Input Composition - -Field is a wrapper that auto-wires accessibility between label, input, and messages. - -```tsx -import { Field } from '@rafters/ui/components/ui/field'; -import { Input } from '@rafters/ui/components/ui/input'; - -// Basic field - - - - -// Required field - - - - -// Error state - - - -``` - -## How Field Works - -Field uses `React.cloneElement` to inject accessibility props into children: - -```tsx -// Field automatically adds to child Input: -// - id (generated or custom) -// - aria-describedby (links to description/error) -// - aria-invalid (when error present) -// - aria-required (when required) -// - disabled (inherited from Field) -``` - -## Input Variants - -Input supports semantic variants for validation states: - -| Variant | Use Case | -|---------|----------| -| default | Normal input state | -| destructive | Validation error | -| success | Validation passed | -| warning | Caution/attention | -| info | Informational | - -```tsx - // Red border - // Green border -``` - -## Input Sizes - -```tsx - // h-8, text-xs - // h-10, text-sm - // h-12, text-base -``` - -## Card + Field Composition - -For token editors, combine Card structure with Field: - -```tsx - - - token-name - Token description - - - - - - - -``` - -## Key Principles - -1. **Field handles accessibility** - Never manually wire htmlFor/aria-describedby -2. **Input is pure** - Just renders, Field adds context -3. **Variants are semantic** - destructive = error, success = valid -4. **Placeholder shows format** - Use for examples, not labels -5. **Description before error** - Error replaces description when present diff --git a/.serena/memories/rafters-overlay-patterns.md b/.serena/memories/rafters-overlay-patterns.md deleted file mode 100644 index 461c5ff9..00000000 --- a/.serena/memories/rafters-overlay-patterns.md +++ /dev/null @@ -1,89 +0,0 @@ -# Rafters Overlay Component Patterns - -## Dialog Usage - -Dialog auto-includes Portal and Overlay when used shadcn-style: - -```tsx -import { Dialog } from '@rafters/ui/components/ui/dialog'; - - - - - - - - - Title - Description - - - {/* Form content */} - - - - - - - - - -``` - -## Built-in Behaviors - -Dialog primitives provide: -- **Focus trap** - Tab cycles within dialog -- **Body scroll lock** - Background doesn't scroll -- **Escape key** - Closes dialog -- **Outside click** - Closes dialog (when modal) -- **ARIA** - Proper dialog role, labelledby, describedby - -## Interactive Card + Dialog Pattern - -Use Card's `interactive` prop for clickable cards that open dialogs: - -```tsx - - - - - Token Name - Description - - - Current value - - - - - - {/* Edit form */} - - -``` - -## Overlay Components in Rafters - -| Component | Use Case | -|-----------|----------| -| Dialog | Full blocking modal, requires decision | -| Sheet | Slide-in panel, supplementary content | -| Drawer | Bottom slide-up, mobile-friendly actions | -| Popover | Contextual, anchored to trigger | -| Tooltip | Hover info, non-interactive | -| DropdownMenu | Action menu, anchored to trigger | - -## Key Principles - -1. **asChild everywhere** - Trigger passes behavior to child element -2. **Auto-portal** - Content auto-portals to document.body -3. **Close mechanisms** - Dialog.Close, Escape, outside click all work -4. **Controlled or uncontrolled** - `open` vs `defaultOpen` -5. **showCloseButton** - Defaults true for shadcn-style usage - -## Z-Index Tokens - -Dialogs use z-index tokens: -- `z-depth-overlay` - Background overlay -- `z-depth-modal` - Dialog content diff --git a/.serena/memories/rafters-self-consumption.md b/.serena/memories/rafters-self-consumption.md deleted file mode 100644 index 19aed6ec..00000000 --- a/.serena/memories/rafters-self-consumption.md +++ /dev/null @@ -1,36 +0,0 @@ -# Rafters Self-Consumption Pattern - -## Core Insight -Every layer of Rafters uses the layers below it. This is not accidental - it's the architecture. - -## The Chain -1. **Design tokens** - Mathematical relationships, dependency graph, OKLCH color science -2. **Tailwind integration** - Tokens become Tailwind utilities via `@theme` block in CSS -3. **Studio** - Edits tokens, styled BY those tokens via Tailwind classes. Designer changes primary color, Studio UI reflects it instantly. -4. **rafters-docs** - Documentation generated FROM the tokens and component intelligence metadata. Not a side project - same self-consumption pattern. -5. **MCP tools** - AI agents query the same token/component/pattern data that everything else uses. - -## How Tokens Become Tailwind -- `@theme { --color-primary: var(--rafters-color-primary); }` - Tailwind processes this ONCE, generates utility classes -- `:root { --rafters-color-primary: oklch(0.65 0.2 250); }` - Actual values in CSS custom properties -- `bg-primary` in any component resolves through: utility class -> @theme var ref -> :root value -- Change the :root value, everything using `bg-primary` updates. No rebuild. - -## Studio Split-CSS for HMR -- `rafters.tailwind.css` (static) - @theme block with var() refs, processed once at startup -- `rafters.vars.css` (dynamic) - Pure :root CSS variables, Vite HMR target -- Production uses `rafters.css` - combined, no indirection needed - -## Why This Matters -- Studio dogfoods automatically - not a feature to build, a constraint on how we build -- Every Studio component MUST use Tailwind token classes, never hardcoded values -- The designer experiences their own changes in real time through the tool itself -- Same mechanism in dev (Studio) and prod (apps) - just different CSS file splits -- rafters-docs uses the same tokens/intelligence - another consumer of the same system - -## Key File -`packages/design-tokens/src/exporters/tailwind.ts` -- `registryToTailwind()` - production combined -- `registryToTailwindStatic()` - Studio static (@theme with var refs) -- `registryToVars()` - Studio dynamic (pure CSS vars for HMR) -- `generateThemeBlockWithVarRefs()` - the indirection layer that makes it all work diff --git a/.serena/memories/rafters-ui-components-for-agents.md b/.serena/memories/rafters-ui-components-for-agents.md deleted file mode 100644 index 67f8c591..00000000 --- a/.serena/memories/rafters-ui-components-for-agents.md +++ /dev/null @@ -1,113 +0,0 @@ -# Rafters UI Components - Agent Guidelines - -## Core Principle: Agents Don't Make Design Choices - -The designer's decisions are encoded in: -1. **Tokens** - colors, spacing, typography values -2. **Components** - semantic structure with embedded intelligence - -Agents compose these. They never pick values. - -## Container Component - -**Purpose**: Semantic structure, not layout - -**Props**: -- `as`: 'div' | 'main' | 'section' | 'article' | 'aside' - semantic HTML element -- `size`: 'sm' | 'md' | 'lg' | ... | '7xl' | 'full' - max-width constraint -- `padding`: '0' | '1' | '2' | ... | '24' - internal spacing -- `query`: boolean - enable container queries (default true) -- `background`: 'none' | 'muted' | 'accent' | 'card' - -**Behavior**: -- Renders semantic HTML element -- No layout imposed - children flow in normal document flow -- `article` gets automatic typography styling -- Container queries enabled by default - -**Usage**: -```tsx - - - - - -``` - -## Grid Component - -**Purpose**: Content layouts with semantic presets - -**Presets**: -- `linear` - Equal-priority content (catalogs, galleries) -- `golden` - Hierarchical flow (2:1 ratio) -- `bento` - Complex attention patterns (dashboards) - -**Bento Patterns**: -- `editorial` - Hero + supporting articles -- `dashboard` - Primary metric + supporting data -- `feature` - Main feature + benefits -- `portfolio` - Featured work + gallery - -**NOT for app shell layout** - use for content within regions. - -## Typography Components - -**Use semantic meaning, not visual styling**: -- `H1` - Page title (one per page) -- `H2` - Section headings -- `H3` - Subsections -- `P` - Body paragraphs -- `Lead` - Introductory text -- `Muted` - Secondary/supplementary info -- `Code` - Technical terms -- `Small` - Fine print - -All styling is pre-encoded. Agent picks semantic meaning, component applies the designer's style. - -## App Shell Layout - -Two approaches: - -**1. Grid classes on Container**: -```tsx - - - - - -``` - -**2. Grid component with Containers inside**: -```tsx - - ... - ... - -``` - -## classy() Primitive - -Blocks arbitrary Tailwind values: -- `grid-cols-[auto_1fr]` - BLOCKED, warns in console -- `grid-cols-12` - OK, standard Tailwind - -## Rules - -1. **NO arbitrary values** - no `-[400px]`, `-[#ff0000]`, etc. -2. **NO design choices** - don't pick font sizes, spacing values, colors -3. **Use semantic tokens** - `bg-primary`, `text-muted-foreground`, `border-border` -4. **Use component props** - Container `padding`, `size`, `background` -5. **Structural layout is OK** - grid columns/rows for composition, not design - -## Package Imports - -Components are copied into projects via CLI (like shadcn). Within monorepo: - -```tsx -import { Container } from '@rafters/ui/components/ui/container'; -import { Muted } from '@rafters/ui/components/ui/typography'; -import { Grid } from '@rafters/ui/components/ui/grid'; -``` - -NOT: `import { Container } from '@rafters/ui'` (no "." export) diff --git a/.serena/memories/registry-add-vs-set.md b/.serena/memories/registry-add-vs-set.md deleted file mode 100644 index 4a1811ed..00000000 --- a/.serena/memories/registry-add-vs-set.md +++ /dev/null @@ -1,70 +0,0 @@ -# TokenRegistry: add() vs set() - -## The Rule - -- **`add(token)`** - Initialization only (loading from disk) -- **`set(name, value)`** - All runtime operations (user edits) - -## Why This Matters - -Studio loads the default design system at startup. The registry is NEVER empty when the user interacts with it. Even "first run" (picking a primary color) is an UPDATE to existing tokens, not creating new ones. - -### add() Behavior -```typescript -add(token: Token): void { - this.tokens.set(token.name, token); // silent overwrite, no cascade -} -``` -- Stores token directly in Map -- No events fired -- No cascade through dependency graph -- Fast for bulk operations - -### set() Behavior -```typescript -async set(tokenName: string, value: Token['value'] | ComputedSymbol): Promise { - if (value === COMPUTED) { - await this.clearOverride(tokenName); // restore computed/previous value - } else { - this.updateToken(tokenName, value); // update + fire changeCallback - } - await this.regenerateDependents(tokenName); // cascade through graph -} -``` -- Fires `changeCallback` (triggers CSS HMR) -- Regenerates all dependent tokens -- Respects `userOverride` on dependents -- Required for live editing -- Accepts `COMPUTED` symbol to clear overrides and trigger self-repair - -## When to Use Each - -| Scenario | Method | Why | -|----------|--------|-----| -| `initRegistry()` loading from disk | `add()` | Bulk population, no cascade needed | -| POST /api/tokens (user action) | `set()` | Must cascade to dependents | -| PATCH /api/token/:ns/:name | `set()` | Must cascade to dependents | -| Loading default system | `add()` | Initial population | -| User picks primary color | `set()` | Updates existing, needs cascade | -| User adjusts semantic | `set()` | May have dependents | - -## The Bug That Was Fixed - -The POST handler was using `add()` for user-initiated token updates. This silently overwrote tokens without cascading changes through the dependency graph. Semantic tokens that depended on primary wouldn't regenerate. - -Fixed in `packages/studio/src/api/vite-plugin.ts`: -```typescript -// Wrong - no cascade -for (const token of tokens) { - reg.add(token); -} - -// Correct - cascades dependents -for (const token of tokens) { - await reg.set(token.name, value); -} -``` - -## Key Insight - -The default design system means the registry is always populated. "First run" UI is about capturing designer intent, not bootstrapping an empty system. Every token operation after initialization is an update, not a creation. diff --git a/.serena/memories/registry-deployment.md b/.serena/memories/registry-deployment.md deleted file mode 100644 index 455da905..00000000 --- a/.serena/memories/registry-deployment.md +++ /dev/null @@ -1,33 +0,0 @@ -# Registry Deployment Notes - -## @rafters/* Dependency Exclusion -JSDoc examples in UI components reference `@rafters/ui` imports. The registry was incorrectly detecting these as npm dependencies. - -### Fix in `apps/website/src/lib/registry/componentService.ts`: -```typescript -const EXCLUDED_PREFIXES = ['@rafters/']; - -function versionDeps(deps: string[]): string[] { - return deps - .filter((dep) => !EXCLUDED_DEPS.has(dep)) - .filter((dep) => !EXCLUDED_PREFIXES.some((prefix) => dep.startsWith(prefix))) - .map((dep) => { /* version mapping */ }); -} -``` - -## Cloudflare Custom Domain Route -Custom domains in wrangler.jsonc cannot have `/*` pattern. - -### Wrong: -```json -"routes": [{ "pattern": "rafters.studio/*", ... }] -``` - -### Correct: -```json -"routes": [{ "pattern": "rafters.studio", ... }] -``` - -## Registry URL -- Production: https://rafters.studio/registry/components/{name}.json -- Components served from Cloudflare Workers diff --git a/.serena/memories/studio-ai-limitations.md b/.serena/memories/studio-ai-limitations.md deleted file mode 100644 index c3ec3c86..00000000 --- a/.serena/memories/studio-ai-limitations.md +++ /dev/null @@ -1,27 +0,0 @@ -# Studio UI - AI Limitations (Critical) - -## The Problem -AI (Claude) defaults to control-panel UIs. Every time Studio UI has been built, it converges on: -- Tabs, cards, form inputs, grids -- Labels, token names, numbers visible -- Settings pages and CRUD interfaces -- Range sliders for color picking - -The Studio UI has been tossed multiple times because of this pattern. - -## What Studio Actually Is -Read `studio-vision` memory. Key points: -- Snowstorm first-run (blank page anxiety made literal) -- 6 circles connected by negative space, not a labeled sidebar -- No labels, no token names, no numbers visible to designer -- "Why" gates that require reasoning before proceeding -- Designer sees colors and blocks, not forms -- More art installation than settings panel - -## The Rule -When building Studio UI, every judgment call about "how should this feel" will be wrong if left to AI instinct. The vision docs contain explicit constraints that must be followed literally. When constraints don't cover something, ASK rather than defaulting to utilitarian patterns. - -## Current State (2026-02-09) -- Backend (vite-plugin API + WebSocket HMR) is solid, 149 tests -- Frontend App.tsx is a control-panel scaffold -- proves components work but is NOT the real UI -- The real UI has never been successfully built by AI alone diff --git a/.serena/memories/studio-architecture.md b/.serena/memories/studio-architecture.md deleted file mode 100644 index fee3b1dd..00000000 --- a/.serena/memories/studio-architecture.md +++ /dev/null @@ -1,74 +0,0 @@ -# Studio Architecture - CRITICAL - -## What Studio IS -Studio is a **THIN UI** on top of the TokenRegistry. Nothing more. - -## What Studio is NOT -Studio does NOT generate tokens, build color values, or do any design system logic on the server. - -## The Pattern -1. **All intelligence lives in packages**: `@rafters/design-tokens`, `@rafters/color-utils`, `@rafters/math-utils`, `@rafters/shared` -2. **Client-side builds tokens**: The React app imports from these packages and builds Token objects -3. **Server just persists**: The API endpoint validates against `TokenSchema` and saves to registry - -## API Endpoints -- `GET /api/tokens` - Read tokens from registry -- `POST /api/tokens` - Accept Token objects (validated against TokenSchema), save to registry -- `PATCH /api/token/:ns/:name` - Update a single token value -- `GET /api/registry/log` - Activity log - -## Flow for Primary Color Selection -1. User picks color in Snowstorm component -2. **CLIENT** calls `buildColorValue()` from `@rafters/color-utils` -3. **CLIENT** calls `generateColorTokens()` from `@rafters/design-tokens` -4. **CLIENT** POSTs the Token[] to `/api/tokens` -5. **SERVER** validates against TokenSchema, adds to registry, persists - -## DO NOT -- Add `buildColorValue`, `generateOKLCHScale`, `generateColorTokens` to the server -- Create custom request schemas for specific flows -- Put any design system logic in vite-plugin.ts -- Use `registry.add()` for runtime operations - only use during `initRegistry()` - -## add() vs set() -- `add(token)` - Initialization only (loading from disk into empty registry) -- `set(name, value)` - All runtime operations (fires changeCallback, cascades dependents) -- `set(name, COMPUTED)` - Clear override and trigger self-repair (regenerate from rule or restore previousValue) - -The default design system is always loaded at startup. Even "first run" is an UPDATE to existing tokens, not creating new ones. See `registry-add-vs-set` memory for details. - -## The server is DUMB -It only knows how to: -- Validate tokens against TokenSchema -- Add tokens to TokenRegistry (via `set()` for updates) -- Persist via NodePersistenceAdapter -- Return tokens grouped by namespace -- Proxy to Rafters API for color intelligence (`GET /api/tokens/color`) - -## Two-Phase Color Selection Pattern - -**Phase 1 - Instant (local math):** -```typescript -const colorValue = buildColorValue(oklch); // @rafters/color-utils -const tokens = generateColorTokens(config, [{ name: 'primary', scale }]); -await fetch('/api/tokens', { method: 'POST', body: tokens }); -``` - -**Phase 2 - Async (API intelligence):** -```typescript -// Fire and forget - don't block UI -fetchColorIntelligence(oklch).then(enriched => { - if (enriched.intelligence) { - // Update registry with AI reasoning, emotional impact, etc. - await fetch('/api/tokens', { method: 'POST', body: [enrichedToken] }); - } -}); -``` - -This gives instant feedback (math is local) while the AI intelligence arrives in the background. - -## Semantic Color Flow -1. User picks primary → `buildColorValue()` returns `semanticSuggestions` -2. `semanticSuggestions.danger[0]` → destructive scale -3. `semanticSuggestions.success[0]` → success scale -4. Semantic tokens reference these families via `DEFAULT_SEMANTIC_COLOR_MAPPINGS` diff --git a/.serena/memories/studio-build-plan-v2.md b/.serena/memories/studio-build-plan-v2.md deleted file mode 100644 index f9460e75..00000000 --- a/.serena/memories/studio-build-plan-v2.md +++ /dev/null @@ -1,118 +0,0 @@ -# Studio Build Plan v2 (Post-Reset) - -**Created**: 2025-01-28 -**Status**: Architecture finalized - -## Architecture - -Single-designer local tool. Vite middleware (~50 lines) + React UI. - -``` -Browser (React) - │ - ▼ -Vite Middleware (~50 lines) - │ - ├── TokenRegistry (singleton) - ├── NodePersistenceAdapter - └── setChangeCallback → write rafters.vars.css - │ - ▼ -Vite HMR (CSS hot reload) -``` - -## Non-Negotiable Rules - -1. **Import, don't reimplement** - Use existing packages -2. **Zod-first types** - `import type { Token } from '@rafters/shared'` -3. **Singleton registry** - One instance with `setChangeCallback` -4. **~50 lines middleware** - Just HTTP glue, no logic - -## Vite Plugin (~50 lines) - -```typescript -import { TokenRegistry, NodePersistenceAdapter, registryToVars, registryToTailwindStatic } from '@rafters/design-tokens'; -import type { Token } from '@rafters/shared'; - -let registry: TokenRegistry | null = null; -let adapter: NodePersistenceAdapter | null = null; - -export function studioApiPlugin(): Plugin { - return { - name: 'studio-api', - async configureServer(server) { - const projectPath = process.env.RAFTERS_PROJECT_PATH; - if (!projectPath) return; - - // Singleton registry - adapter = new NodePersistenceAdapter(projectPath); - const namespaces = await adapter.listNamespaces(); - const allTokens: Token[] = []; - for (const ns of namespaces) { - allTokens.push(...await adapter.loadNamespace(ns)); - } - registry = new TokenRegistry(allTokens); - - // Event-driven CSS - registry.setChangeCallback(async () => { - await writeFile(`${projectPath}/.rafters/output/rafters.vars.css`, registryToVars(registry!)); - }); - await writeFile(`${projectPath}/.rafters/output/rafters.tailwind.css`, registryToTailwindStatic(registry)); - - // GET /api/tokens - server.middlewares.use('/api/tokens', (req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify(registry!.list())); - }); - - // PATCH /api/token/:ns/:name - server.middlewares.use('/api/token/', async (req, res) => { - if (req.method !== 'PATCH') return; - const [ns, name] = req.url!.slice(1).split('/'); - const { value, reason } = await parseBody(req); - await registry!.set(name, value); - await adapter!.saveNamespace(ns, registry!.list({ namespace: ns })); - res.end(JSON.stringify({ ok: true })); - }); - } - }; -} -``` - -## UI Components (the actual work) - -All UI code imports from existing packages: - -```typescript -// Types -import type { Token, OKLCH } from '@rafters/shared'; - -// Color operations -import { hexToOKLCH, oklchToHex, generateOKLCHScale, generateSemanticColorSuggestions } from '@rafters/color-utils'; - -// No manual color functions. No manual types. -``` - -### Sprint 1: First Run -- Snowstorm (color picker) - uses `hexToOKLCH`, `generateColorName` -- ScalePaint (scale display) - uses `generateOKLCHScale` -- SemanticChoices - uses `generateSemanticColorSuggestions` - -### Sprint 2: Workspaces -- Sidebar - namespace list from `/api/tokens` -- ColorWorkspace - displays tokens with `oklchToHex` -- Context menus - L/C/H sliders, WhyGate - -### Sprint 3: Polish -- Cascade preview - uses `registry.getDependents()` -- Override conflicts - shows `userOverride` data -- Save all - regenerate production files - -## What Went Wrong in v1 - -| Wrong | Right | -|-------|-------| -| `utils/color-conversion.ts` | `import { hexToOKLCH } from '@rafters/color-utils'` | -| `interface Token {}` | `import type { Token } from '@rafters/shared'` | -| New registry per request | Singleton with `setChangeCallback` | -| 300+ lines middleware | ~50 lines HTTP glue | \ No newline at end of file diff --git a/.serena/memories/studio-registry-prototype-findings.md b/.serena/memories/studio-registry-prototype-findings.md deleted file mode 100644 index 84855914..00000000 --- a/.serena/memories/studio-registry-prototype-findings.md +++ /dev/null @@ -1,108 +0,0 @@ -# Studio Registry Prototype Findings - -## Core Pattern: Two-Phase Color Loading - -### Phase 1: Instant (Local Math) -- `generateRaftersHarmony(baseOKLCH)` returns 7 semantic positions -- `generateOKLCHScale(baseOKLCH)` creates 11-position scale -- User sees immediate feedback while API loads - -### Phase 2: Background (API Intelligence) -- Fetch `api.rafters.studio/color/{l}-{c}-{h}?adhoc=true` -- Returns complete `ColorValue` with: - - `name`: Fancy color name (e.g., "balanced-bold-dynamic-ocean") - - `scale`: 11 OKLCH positions - - `harmonies`: complementary, triadic, analogous, tetradic, monochromatic - - `semanticSuggestions`: danger[3], success[3], warning[3], info[3] options - - `accessibility`: WCAG AA/AAA pairs, onWhite/onBlack positions - -## 11 Color Families - -### From Harmony (7) -1. **primary** - User's chosen color -2. **secondary** - From complementary -3. **tertiary** - From analogous[0] -4. **accent** - From triadic[0] -5. **highlight** - Bright version of primary (higher L, higher C) -6. **surface** - Desaturated (very low C) -7. **neutral** - True gray (C=0) - -### From Semantic Suggestions (4) -8. **danger** - Red range (h~15) -9. **success** - Green range (h~135) -10. **warning** - Yellow/amber range (h~45) -11. **info** - Usually matches primary hue - -## Registry Token Structure - -### Family Token -```typescript -registry.add({ - name: 'color-family-primary', - value: colorValue, // Full ColorValue object - category: 'color', - namespace: 'color', -}); -``` - -### Scale Token -```typescript -registry.add({ - name: 'primary-500', - value: oklchToCSS(colorValue.scale[5]), - category: 'color', - namespace: 'color', - dependsOn: ['color-family-primary'], - generationRule: 'scale:500', -}); -registry.addDependency('primary-500', ['color-family-primary'], 'scale:500'); -``` - -## Auto-Regeneration - -When `registry.set('color-family-primary', newColorValue)` is called: -1. Registry updates family token -2. `regenerateDependents()` finds all tokens with `dependsOn: ['color-family-primary']` -3. For each dependent, executes `generationRule` (e.g., `scale:500`) -4. Scale plugin extracts position from token name (`primary-500` -> 500) -5. Executor resolves to CSS: `oklchToCSS(newColorValue.scale[5])` -6. `changeCallback` fires for each updated token - -## CSS Export - -- `registryToTailwind(registry)` exports to CSS variables -- ~97KB for full 11-family system -- ~800 color variables - -## Studio UI Requirements - -1. **Color Picker** - Let user pick OKLCH, show instant local preview -2. **API Loader** - Fetch full intelligence in background -3. **Harmony Choices** - Present options from `harmonies` for secondary/tertiary/accent -4. **Semantic Choices** - Present 3 options each for danger/success/warning/info -5. **Why Gate** - Capture user's reason for color choice -6. **Live CSS Preview** - Subscribe to `changeCallback`, update preview - -## Key APIs - -```typescript -// Load base system -const { allTokens } = generateBaseSystem(); -const registry = new TokenRegistry(allTokens); - -// Fetch color intelligence -const color = await fetch(`${API}/color/${l}-${c}-${h}?adhoc=true`).then(r => r.json()); - -// Add family and scales -registry.add({ name: 'color-family-X', value: colorValue, ... }); -registry.addDependency('X-500', ['color-family-X'], 'scale:500'); - -// Update triggers regeneration -await registry.set('color-family-X', newColorValue); - -// Subscribe to changes -registry.setChangeCallback((event) => { - const css = registryToTailwind(registry); - updatePreview(css); -}); -``` diff --git a/.serena/memories/studio-ui-rules.md b/.serena/memories/studio-ui-rules.md deleted file mode 100644 index 18702911..00000000 --- a/.serena/memories/studio-ui-rules.md +++ /dev/null @@ -1,27 +0,0 @@ -# Studio UI Rules - -## Core Principle -Studio is styled BY its own tokens. When the designer changes a token, Studio's UI updates instantly via HMR. This is the architecture, not a feature. - -## Never Do -- Never use arbitrary Tailwind values (-[400px], -[#color]) -- Never hardcode colors, spacing, sizes -- Never use raw HTML with manual classes when a Rafters component exists -- Never make design choices - the tokens encode the designer's decisions - -## Always Do -- Use @rafters/ui components (Container, Typography, Button, etc.) -- Use classy() from @rafters/ui/primitives/classy for class management -- Use semantic token classes (bg-primary, text-foreground, etc.) -- Query rafters_* MCP tools before writing UI code -- Let Container handle spacing, Typography handle text sizes - -## Component Hierarchy -1. Container - sections, layout with designer's padding/size -2. Typography - text with designer's type scale -3. Grid - layouts with designer's gap/columns -4. Button, Badge, etc. - interactions with designer's styles - -## The Test -If you're picking a value (text-sm, gap-4, h-12), you're wrong. -The component or token should provide the value. You just use it. diff --git a/.serena/memories/studio-vision.md b/.serena/memories/studio-vision.md deleted file mode 100644 index 0b5132d2..00000000 --- a/.serena/memories/studio-vision.md +++ /dev/null @@ -1,74 +0,0 @@ -# Studio Vision - -Read `docs/STUDIO_VISION.md` for the full narrative. This is a quick reference. - -## Core Concept - -Studio is a visual decision recorder, not a token editor. Designers see colors/blocks/samples, pick, say why. System handles naming/rules/exports. - -## First Run Flow - -1. White page, snowstorm (blank page anxiety literal) -2. Bouncing box: "choose primary color..." -3. Click → color picker → pick → "why this color?" (placeholder cycles with color intelligence) -4. If no why → system explains DIS philosophy, gates progress -5. Commit → snowstorm fades forever → system paints from defaults - -## After Primary - -- System exists: IBM Plex, 4ths spacing, default radius/depth/motion -- Semantics appear with 3 computed choices each -- Pick or custom → why → fades to "done" with scale - -## Sidebar - -- 6 circles: Color, Spacing, Typography, Radius, Depth, Motion -- 44px default, 64px hover -- Icons only, connected by negative space -- No chrome, no background, no divider -- Retreat to -33% left margin when workspace has focus - -## Namespace UIs - -- Click circle → full workspace redraw -- Top: educational (dismissible) - explains math, shows choices, real examples -- After dismiss: just visual output + control -- No labels, no token names, no numbers -- Change from default → "why" gate - -## Key Principles - -- No giant sheet of knobs and sliders -- Defaults are beautiful (math-derived) -- Designer only speaks when they have something to say -- Every deviation captured with reasoning -- Technical details invisible (for machines) - -## Power Features: Right-Click - -Not "all the knobs" - "the right knobs for this thing." - -### Color swatch right-click: -- L, C, H sliders (names may change based on user feedback) -- Target block updates live -- Value box shows current values -- Neighbor warning when leaving harmonic relationships -- Cascade: non-overridden values regenerate, "why" values preserved - -### Other contexts (to design): -- Spacing: ratio, base unit -- Semantic: reference selector, override -- Typography: font picker, scale ratio - -Default: visual + control + why -Right-click: scoped power, thoughtfully designed per context - -## Files - -- `docs/STUDIO_VISION.md` - Full narrative -- `docs/STUDIO_ARCHITECTURE.md` - Technical implementation (needs updating) - -## Self-Consumption (Dogfooding) -Studio uses Tailwind token classes for ALL styling. When the designer changes a token, -the entire Studio UI reflects the change instantly via CSS HMR. This is not a feature - -it's the architecture. The tokens ARE Tailwind. See `rafters-self-consumption` memory. \ No newline at end of file diff --git a/.serena/memories/suggested_commands.md b/.serena/memories/suggested_commands.md deleted file mode 100644 index c1b23b95..00000000 --- a/.serena/memories/suggested_commands.md +++ /dev/null @@ -1,62 +0,0 @@ -# Suggested Commands - -## Package Manager -**MUST use pnpm** - npm/yarn will not work with this monorepo. - -## Development -```bash -pnpm dev # Start all apps in parallel dev mode -pnpm build # Build all packages -``` - -## Testing -```bash -pnpm test # Run all tests in all packages -pnpm test:unit # Unit tests only -pnpm test:component # Component tests only -pnpm test:e2e # End-to-end tests -pnpm test:a11y # Accessibility tests (playwright with @a11y tag) -pnpm test:quick # Unit + component tests (fast feedback) -pnpm test:all # preflight + e2e (full CI) -pnpm test:watch # Unit tests in watch mode -``` - -## Code Quality -```bash -pnpm typecheck # TypeScript type checking across all packages -pnpm lint # Biome linting -pnpm lint:fix # Biome linting with auto-fix -pnpm format # Biome formatting with auto-fix -``` - -## Pre-Commit/Pre-Push (Automated) -```bash -pnpm preflight # Full validation: typecheck + lint + test:unit + test:a11y + build -pnpm ci # CI command: preflight + test:e2e -``` - -## Cleanup -```bash -pnpm clean # Remove node_modules and dist from all packages -``` - -## Git Hooks (Lefthook) -Pre-commit hooks run automatically: -- Biome lint (with auto-fix) -- TypeScript typecheck -- Unit tests for changed packages - -Pre-push hooks run automatically: -- Full `pnpm preflight` - -## System Utilities -- `git` - Version control -- `ls`, `cd`, `grep`, `find` - Standard Linux commands -- The project runs on Linux - -## Package-Specific Commands -Run commands in specific packages: -```bash -pnpm --filter @rafters/ui test:unit # Test specific package -pnpm --filter @rafters/cli build # Build specific package -``` diff --git a/.serena/memories/task_completion.md b/.serena/memories/task_completion.md deleted file mode 100644 index b1d6c8e5..00000000 --- a/.serena/memories/task_completion.md +++ /dev/null @@ -1,61 +0,0 @@ -# Task Completion Checklist - -When a coding task is completed, run these checks: - -## 1. Type Checking -```bash -pnpm typecheck -``` -Ensure no TypeScript errors across all packages. - -## 2. Linting -```bash -pnpm lint:fix -``` -Fix any linting issues. Review and address any that can't be auto-fixed. - -## 3. Unit Tests -```bash -pnpm test:unit -``` -Ensure all unit tests pass. If you added new functionality, add tests. - -## 4. Quick Validation (Recommended) -```bash -pnpm test:quick -``` -Runs unit + component tests for faster feedback. - -## 5. Full Preflight (Before Commit) -```bash -pnpm preflight -``` -This runs: typecheck → lint → test:unit → test:a11y → build - -## 6. For Component Changes -If you modified UI components: -```bash -pnpm test:component -pnpm test:a11y -``` - -## 7. For Major Changes -```bash -pnpm test:all -``` -Runs full preflight + e2e tests. - -## Git Hooks -The repository has automated hooks via Lefthook: -- **Pre-commit:** Auto-runs lint, typecheck, and unit tests for changed packages -- **Pre-push:** Auto-runs full `pnpm preflight` - -These hooks will catch issues automatically, but running checks manually helps catch problems earlier. - -## Minimum Requirements -- [ ] `pnpm typecheck` passes -- [ ] `pnpm lint` passes (or `lint:fix` applied) -- [ ] `pnpm test:unit` passes -- [ ] New code has test coverage (target: 80%+) -- [ ] Components include cognitive load metadata -- [ ] No emojis in code/comments diff --git a/.serena/memories/testing_strategy.md b/.serena/memories/testing_strategy.md deleted file mode 100644 index c60c132b..00000000 --- a/.serena/memories/testing_strategy.md +++ /dev/null @@ -1,61 +0,0 @@ -# Testing Strategy - -Full details in `docs/TEST_STRATEGY.md` and `docs/TEST_STRATEGY_SUMMARY.md`. - -## Testing Principles -- **Property-based testing** with zocker for schema-driven validation -- **Real fixtures** over brittle hardcoded mocks -- Test **behavior**, not implementation details -- **MANDATORY accessibility tests** for UI components -- Critical path coverage before edge cases - -## Test File Structure -``` -packages/[package]/ -├── src/ -│ └── [module].ts -└── test/ - ├── [module].test.ts # Unit tests - ├── [module].a11y.tsx # Accessibility (MANDATORY for UI) - ├── [module].spec.ts # Integration tests - └── fixtures.ts # Zocker-generated test data -``` - -## Package Coverage Targets -| Package | Target | Priority Areas | -|---------------------|--------|-----------------------------------| -| @rafters/shared | 95% | Schemas (100%), Components (100%) | -| @rafters/math-utils | 100% | Pure functions | -| @rafters/color-utils| 95% | WCAG (100%), Conversion (100%) | -| @rafters/design-tokens| 90% | Registry (100%), Dependencies | - -## Property-Based Testing with Zocker -```typescript -import { zocker } from 'zocker'; - -// Generate 100 random valid tokens, test property holds for ALL -const tokens = zocker(z.array(TokenSchema).length(100)).generate(); -for (const token of tokens) { - expect(TokenSchema.parse(token)).toBeDefined(); -} -``` - -## Accessibility Tests (MANDATORY for UI) -Every UI component needs `.a11y.tsx`: -```typescript -import { axe } from 'vitest-axe'; - -it('has no accessibility violations', async () => { - const { container } = render(); - const results = await axe(container); - expect(results).toHaveNoViolations(); -}); -``` - -## Key Commands -```bash -pnpm test # All tests -pnpm --filter=@rafters/shared test # Specific package -pnpm test:a11y # Accessibility only -pnpm test:coverage # Coverage report -``` diff --git a/.serena/memories/what_rafters_is.md b/.serena/memories/what_rafters_is.md deleted file mode 100644 index 0a56fbc6..00000000 --- a/.serena/memories/what_rafters_is.md +++ /dev/null @@ -1,116 +0,0 @@ -# What Rafters Actually Is - -Read this first. Every time. - -## The Problem - -AI agents don't have taste. When they build UI, they guess at colors, spacing, hierarchy, and balance. The results look like AI made them - generic, inconsistent, wrong. - -## The Solution - -Rafters encodes design judgment into data structures AI can query. A designer's decades of experience - what works, what doesn't, when to break rules, why - becomes machine-readable. - -## The Three Layers - -| Layer | What | Where | -|-------|------|-------| -| **What** | Components | `packages/ui` - 55 components with JSDoc intelligence | -| **Where** | Design tokens | `packages/design-tokens` - TokenRegistry with dependency graph | -| **Why** | Designer's notes | JSDoc tags, MCP tools, do/never patterns | - -## The Token System - -Tokens aren't just values. Each token knows: -- What it is (`value`) -- Where it comes from (`dependsOn`, `generationRule`) -- Why it exists (`semanticMeaning`, `usagePatterns`) -- When to use it (`usageContext`, `appliesWhen`) -- When a human overrode the system and why (`userOverride` with reason, context, who, when) - -Five generation rule types derive tokens automatically: -- `calc()` - Mathematical calculations -- `state:hover` - Color state transformations -- `scale:600` - Scale position extraction -- `contrast:auto` - Automatic contrast generation -- `invert` - Lightness inversion for dark mode - -When a human overrides a computed value, the system preserves both: -- `computedValue` - What the rule would produce -- `value` - What the human chose -- `userOverride.reason` - Why they chose it - -The AI can see: "system says X, human chose Y because Z." - -## The MCP Tools - -Four tools, progressive disclosure: - -1. **rafters_vocabulary** - "What do I have?" - - Color palettes, spacing scale, type scale - - Component list with cognitive loads - - Pattern names - -2. **rafters_pattern** - "How do I implement this scenario?" - - 10 patterns: destructive-action, form-validation, empty-state, etc. - - Components to use, tokens to apply - - Cognitive load, accessibility, trust patterns - - Do/never guidance with examples - -3. **rafters_component** - "Tell me everything about this component" - - Cognitive load score - - Attention economics - - Accessibility requirements - - Trust building patterns - - Do/never guidance - - Variants, sizes, dependencies - -4. **rafters_token** - "Tell me everything about this token" - - Current value and computed value - - Derivation rule (calc, state, scale, contrast, invert) - - Dependencies (what it depends on) - - Dependents (cascade impact if changed) - - Human override context (what, why, previousValue for undo) - -The AI never guesses. It queries the designer's decisions. - -## The Philosophy - -See `docs/DESIGN_PHILOSOPHY.md` for the full document. Three balanced perspectives: - -- **Craft (Jobs/Ive/Rams)** - Deep simplicity, every detail intentional -- **Experimentation (Joshua Davis)** - Structured chaos, room for delight -- **Usability (Jakob Nielsen)** - Empirical validation via 10 heuristics - -The founder worked with Joshua Davis on Praystation and Dreamless, at Frog and IDEO. Physical devices in the 90s. Rebrands of Sun and SGI. This isn't academic - it's encoded experience. - -## What Rafters Is NOT - -- Not a component library with nice docs -- Not shadcn with extra features -- Not a design system you configure - -It's a protocol for transferring design judgment to machines. - -## The Docs - -Docs are secondary. They exist for the 20% of humans who want them. The real value: -- MCP tools for AI agents (primary interface) -- llms.txt generated from docs (AI training data) - -The docs should follow Storybook conventions (sidebar, preview, props, examples) because that's what users expect. The differentiation is the content, not the structure. - -## Key Files - -- `packages/shared/src/types.ts` - Token schema with full intelligence fields -- `packages/shared/src/component-intelligence.ts` - JSDoc parsing -- `packages/design-tokens/src/registry.ts` - TokenRegistry with dependency tracking -- `packages/design-tokens/src/dependencies.ts` - Dependency graph -- `packages/design-tokens/src/generation-rules.ts` - Rule parser and executor -- `packages/cli/src/mcp/tools.ts` - The three MCP tools -- `docs/DESIGN_PHILOSOPHY.md` - Jobs/Ive, Davis, Nielsen balance - -## Remember - -The AI learns **what** to do, **because of how** it works, **and why** it matters. - -Not how to make decisions. What to do because the decisions are already made. diff --git a/.serena/memories/why-the-registry-exists.md b/.serena/memories/why-the-registry-exists.md deleted file mode 100644 index 3ed0e44f..00000000 --- a/.serena/memories/why-the-registry-exists.md +++ /dev/null @@ -1,82 +0,0 @@ -# Why the Registry Exists - -## The Core Problem -AI doesn't have taste. When AI builds UI, it guesses at colors, spacing, hierarchy. The results look like AI made them. - -## The Solution -Encode a designer's choices into data AI can query. Not values - **choices**. - -## What Makes This Different - -A typical design token system stores values: -```json -{ "spacing-4": "1rem" } -``` - -Rafters stores choices: -```json -{ - "name": "spacing-4", - "value": "2rem", - "computedValue": "1rem", - "dependsOn": ["spacing-base"], - "generationRule": "calc({spacing-base}*4)", - "userOverride": { - "previousValue": "1rem", - "reason": "Design review found original too tight for touch targets" - } -} -``` - -The AI sees: -- Math says 1rem -- Human chose 2rem -- Because touch targets - -**That's not data. That's wisdom.** - -## Why the Dependency Graph - -Design choices have consequences. Change `spacing-base` and 50 derived tokens respond. The graph exists to: - -1. **Cascade changes** - One edit propagates correctly -2. **Protect human judgment** - Overrides aren't silently erased -3. **Show impact** - Before you change something, see what depends on it - -## Why Track Both Values - -```typescript -{ - value: "2rem", // What human chose - computedValue: "1rem" // What system would produce -} -``` - -The system keeps computing. The human decision persists. AI can see both: -- "The system thinks X" -- "But the designer chose Y because Z" - -## The Most Important Field - -`userOverride.reason` is the most important field in the schema. It's the designer's voice persisting through every regeneration. - -Without it, we have values. With it, we have intent. - -## Self-Repair, Not Self-Override - -When you clear an override with `COMPUTED`: -- Derived tokens regenerate from their rules -- Root tokens restore `previousValue` -- The cascade propagates - -The system heals itself. But it never overwrites human judgment without explicit action. - -## The Registry is Memory - -Not memory like RAM. Memory like human memory - the accumulation of decisions that form judgment. - -A designer spends years learning what works. Rafters captures that into queryable data. AI reads it and produces work that reflects those years of learning, not random guesses. - -## One Sentence - -**The registry exists to make design choices queryable, so AI reads decisions instead of guessing.** diff --git a/.serena/project.yml b/.serena/project.yml deleted file mode 100644 index 1ae226b4..00000000 --- a/.serena/project.yml +++ /dev/null @@ -1,109 +0,0 @@ -# list of languages for which language servers are started; choose from: -# al bash clojure cpp csharp csharp_omnisharp -# dart elixir elm erlang fortran go -# haskell java julia kotlin lua markdown -# nix perl php python python_jedi r -# rego ruby ruby_solargraph rust scala swift -# terraform typescript typescript_vts yaml zig -# Note: -# - For C, use cpp -# - For JavaScript, use typescript -# Special requirements: -# - csharp: Requires the presence of a .sln file in the project folder. -# When using multiple languages, the first language server that supports a given file will be used for that file. -# The first language is the default language and the respective language server will be used as a fallback. -# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. -languages: -- typescript - -# the encoding used by text files in the project -# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings -encoding: "utf-8" - -# whether to use the project's gitignore file to ignore files -# Added on 2025-04-07 -ignore_all_files_in_gitignore: true - -# list of additional paths to ignore -# same syntax as gitignore, so you can use * and ** -# Was previously called `ignored_dirs`, please update your config if you are using that. -# Added (renamed) on 2025-04-07 -ignored_paths: [] - -# whether the project is in read-only mode -# If set to true, all editing tools will be disabled and attempts to use them will result in an error -# Added on 2025-04-18 -read_only: false - -# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details. -# Below is the complete list of tools for convenience. -# To make sure you have the latest list of tools, and to view their descriptions, -# execute `uv run scripts/print_tool_overview.py`. -# -# * `activate_project`: Activates a project by name. -# * `check_onboarding_performed`: Checks whether project onboarding was already performed. -# * `create_text_file`: Creates/overwrites a file in the project directory. -# * `delete_lines`: Deletes a range of lines within a file. -# * `delete_memory`: Deletes a memory from Serena's project-specific memory store. -# * `execute_shell_command`: Executes a shell command. -# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced. -# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type). -# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type). -# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes. -# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file. -# * `initial_instructions`: Gets the initial instructions for the current project. -# Should only be used in settings where the system prompt cannot be set, -# e.g. in clients you have no control over, like Claude Desktop. -# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol. -# * `insert_at_line`: Inserts content at a given line in a file. -# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol. -# * `list_dir`: Lists files and directories in the given directory (optionally with recursion). -# * `list_memories`: Lists memories in Serena's project-specific memory store. -# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building). -# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context). -# * `read_file`: Reads a file within the project directory. -# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store. -# * `remove_project`: Removes a project from the Serena configuration. -# * `replace_lines`: Replaces a range of lines within a file with new content. -# * `replace_symbol_body`: Replaces the full definition of a symbol. -# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen. -# * `search_for_pattern`: Performs a search for a pattern in the project. -# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase. -# * `switch_modes`: Activates modes by providing a list of their names -# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information. -# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task. -# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed. -# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store. -excluded_tools: [] - -# initial prompt for the project. It will always be given to the LLM upon activating the project -# (contrary to the memories, which are loaded on demand). -initial_prompt: "" -# the name by which the project can be referenced within Serena -project_name: "rafters" - -# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default) -included_optional_tools: [] - -# list of mode names to that are always to be included in the set of active modes -# The full set of modes to be activated is base_modes + default_modes. -# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply. -# Otherwise, this setting overrides the global configuration. -# Set this to [] to disable base modes for this project. -# Set this to a list of mode names to always include the respective modes for this project. -base_modes: - -# list of mode names that are to be activated by default. -# The full set of modes to be activated is base_modes + default_modes. -# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply. -# Otherwise, this overrides the setting from the global configuration (serena_config.yml). -# This setting can, in turn, be overridden by CLI parameters (--mode). -default_modes: - -# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. -# This cannot be combined with non-empty excluded_tools or included_optional_tools. -fixed_tools: [] - -# override of the corresponding setting in serena_config.yml, see the documentation there. -# If null or missing, the value from the global config is used. -symbol_info_budget: