diff --git a/.ai/conversations/davis-2026-04-15.md b/.ai/conversations/davis-2026-04-15.md index 08df277..3677442 100644 --- a/.ai/conversations/davis-2026-04-15.md +++ b/.ai/conversations/davis-2026-04-15.md @@ -103,3 +103,189 @@ Created `.docs/conversations/2026-04-15.md` with full session documentation. Sav ### Assistant Ran docs skill. No API services in this repo — skipped OpenAPI/Postman. Saved this conversation log to `.ai/conversations/davis-2026-04-15.md`. + +--- + +## Session 2 — 2026-04-16 + +## Summary + +The pipeline was failing on `--prd ./sample-prds/thumbtackAngie.md` because the PRD file was plain text (no markdown headings), causing the parser to return "Untitled PRD (0 sections)" and producing empty Dribbble search queries. Implemented a raw text PRD generation feature: the CLI now auto-detects unstructured input and calls an LLM to generate a proper structured PRD before running the pipeline. Also added a `--prompt` flag for inline text descriptions. + +## Files Modified + +### Created +- `src/agents/prd-generation-agent.mts` — New agent extending `BaseAgent` that sends raw text to an LLM and returns a structured PRD markdown document. Validates output has >= 3 sections. +- `src/prompts/prd-generation.mts` — System prompt instructing the LLM to generate a PRD with 8 required sections (Overview, Features, Data Model, Pages/Views, User Roles, API Endpoints, Non-Functional Requirements). + +### Modified +- `src/input/prd-parser.mts` — Changed `ParsedPrd` from a flat interface to a discriminated union (`StructuredPrd | RawTextPrd`). Files with 0 headings now return `kind: 'raw'`. Added `parseStructuredContent()` helper for re-parsing LLM-generated markdown. +- `src/cli/parse-args.mts` — Added `--prompt ""` flag and `run-prompt` command variant. Updated help text and examples. +- `src/container/di.mts` — Registered `PrdGenerationAgent` in the DI container with `buildChain('planning')` role. +- `src/io/workspace.mts` — Added `saveGeneratedPrd()` method that writes generated PRD to `{workspaceDir}/generated-prd.md`. +- `src/index.mts` — Wired the detection and generation flow: detects raw text from `--prd` files or `--prompt` flag, runs PRD generation agent (logged as "Phase 0a: PRD Generation"), saves output, parses it, and continues the pipeline. + +## Commits + +(Changes not yet committed) + +## Transcript + +### User +> [Pasted pipeline output showing failure: "Untitled PRD (0 sections)" and "Aborting pipeline — Dribbble search failed from all sources"] + +### Assistant +Diagnosed two compounding failures: (1) PRD parser returned empty title/sections because the file had no markdown headings, (2) Dribbble search got 0 results because Playwright was in standalone mode and search queries were derived from the empty scope. Proposed two fixes: improve the PRD parser and add a `--skip-dribbble` flag. + +### User +> the cli should allow raw text and if it receives text it should generate a prd and then use it + +### Assistant +Entered plan mode. Explored the codebase thoroughly: CLI parsing, PRD parser, entry point, LLM agent pattern, DI container, prompt templates, and pipeline flow. Designed a plan with 7 file changes covering content-based detection in the parser, a new `--prompt` flag, a `PrdGenerationAgent`, a system prompt, DI registration, workspace save method, and entry point wiring. + +### User +> how many tokens have i used today + +### Assistant +Explained that token usage isn't accessible from within the session. Suggested `/cost` for session cost and the Anthropic Console for daily totals. + +### User +> [Approved plan] + +### Assistant +Implemented the full feature across 7 files: +1. Updated `prd-parser.mts` with discriminated union (`StructuredPrd | RawTextPrd`) and `parseStructuredContent()` helper +2. Created `src/prompts/prd-generation.mts` with detailed system prompt +3. Created `src/agents/prd-generation-agent.mts` extending `BaseAgent` +4. Added `--prompt` flag to `parse-args.mts` +5. Registered agent in `di.mts` +6. Added `saveGeneratedPrd()` to `workspace.mts` +7. Wired everything in `index.mts` with "Phase 0a: PRD Generation" logging + +TypeScript compiled cleanly. ESLint passed on all changed files (2 pre-existing errors in `pipeline.mts` unrelated to changes). CLI `--help` output verified. + +### User +> document the changes + +### Assistant +Ran docs skill. Appended session 2 to this conversation log. + +--- + +## Session 3 — 2026-04-15 + +## Summary + +Extracted all inline system prompts and rules from TypeScript files into standalone markdown files under `docs/prompts/`. Created a `loadPrompt()` utility that reads prompt text from `.md` files at startup via `Bun.file()`. This makes prompts easy to edit without touching TypeScript source. Affected 8 prompts across `src/prompts/`, `src/agents/`, and `src/orchestrator/`. + +## Files Modified + +### Created +- `docs/prompts/prd-generation.md` — PRD generation system prompt +- `docs/prompts/planning.md` — Angular planning/task decomposition prompt +- `docs/prompts/design-selection.md` — Dribbble design evaluation prompt +- `docs/prompts/codegen.md` — Angular code generation standards and rules +- `docs/prompts/component-library.md` — Component library generation prompt +- `docs/prompts/validation.md` — Code validation severity definitions and rules +- `docs/prompts/visual-fidelity.md` — Visual fidelity scoring and comparison prompt +- `docs/prompts/style-guide-extraction.md` — UI design box model decomposition prompt +- `src/prompts/load-prompt.mts` — Utility to load prompt markdown files via `Bun.file()` + +### Modified +- `src/prompts/codegen.mts` — Replaced inline template literal with `loadPrompt("codegen.md")` +- `src/prompts/component-library.mts` — Replaced inline template literal with `loadPrompt("component-library.md")` +- `src/prompts/design-selection.mts` — Replaced inline template literal with `loadPrompt("design-selection.md")` +- `src/prompts/planning.mts` — Replaced inline template literal with `loadPrompt("planning.md")` +- `src/prompts/prd-generation.mts` — Replaced inline template literal with `loadPrompt("prd-generation.md")` +- `src/agents/validation-agent.mts` — Moved inline `VALIDATION_SYSTEM_PROMPT` to `loadPrompt("validation.md")` +- `src/agents/visual-fidelity-agent.mts` — Moved inline `FIDELITY_SYSTEM_PROMPT` to `loadPrompt("visual-fidelity.md")` +- `src/orchestrator/style-guide-extraction.mts` — Moved inline `SYSTEM_PROMPT` and `ELEMENT_TABLE` to `loadPrompt("style-guide-extraction.md")` + +## Transcript + +### User +> there seems to be a lot of my rules nested into the typescript files. Can we move the rules into md files to make updating easier and then reference the md files + +### Assistant +Initially misunderstood scope as the global `~/.claude/CLAUDE.md`. User clarified they meant the project's TypeScript files. + +### User +> continue, but I am talking about rules and workflow prompts in this project i want those as separate md files + +### Assistant +Explored the codebase and found 8 system prompts embedded as template literals across `src/prompts/`, `src/agents/`, and `src/orchestrator/`. Created `docs/prompts/` with 8 `.md` files, a `loadPrompt()` utility, and updated all source files to load prompts from markdown at startup. TypeScript type check passed cleanly. + +### User +> awesome, document, commit and push + +### Assistant +Ran docs skill, appended session 3 to conversation log, committed and pushed. + +--- + +## Session 4 — 2026-04-16 + +## Summary + +Wired real Playwright browser automation into the standalone CLI runner. Previously, all browser callbacks (navigate, snapshot, screenshot, openTab) were no-ops when running from the command line — only working inside Claude Code with the Playwright MCP plugin. Now the CLI launches a real Chromium instance via the `playwright` package. The snapshot transformer converts Playwright 1.59's `ariaSnapshot()` YAML-like output into the text format all existing parsers expect, with inline URLs for Dribbble link scraping and `[ref=eN]` markers for Stitch fill/click interactions. + +## Files Modified + +### Created +- `src/browser/playwright-browser.mts` — Core browser module: launches Chromium, implements all PlaywrightCallbacks (navigate, snapshot, screenshot, openTab, fill, click, runCommand). Snapshot uses `page.ariaSnapshot()` + transformer that inlines URLs and adds refs for interactive elements. + +### Modified +- `package.json` — Added `playwright` dependency +- `bun.lock` — Updated lockfile +- `src/cli/parse-args.mts` — Added `--headless` flag (default: headed mode so user sees the browser) +- `src/orchestrator/pipeline.mts` — Added optional `fill`/`click` to `PlaywrightCallbacks` interface; Stitch callbacks use them when available instead of no-ops +- `src/index.mts` — Replaced no-op Playwright callbacks with `launchBrowser()` from the new module. Added `try/finally` for browser cleanup. + +## Commits + +(Pending) + +## Transcript + +### User +> [Pasted pipeline output showing LLM_PROVIDER=openai instead of ollama] + +### Assistant +Found `.env` has `LLM_PROVIDER=openai` explicitly set. The default in `env.mts` is `ollama` but the `.env` overrides it. + +### User +> why is there a env.mts when we have a .env file + +### Assistant +Explained the difference: `.env` holds the values, `env.mts` is the Zod schema that validates/types them at startup. This is the pattern from the user's own global CLAUDE.md / docs/bun.md. + +### User +> [Pasted full pipeline output showing Dribbble scraper returning 0 results for all queries] + +### Assistant +Diagnosed the chain: (1) Dribbble API client undefined (no `DRIBBBLE_ACCESS_TOKEN`), (2) Playwright scraper returns empty because standalone mode has no-op callbacks, (3) no design cache. Offered three options: add API token, add skip-design flag, or wire real Playwright. + +### User +> how do i run so all browser calls are not running no-ops + +### Assistant +Explained the two paths: run from Claude Code (Playwright MCP available) or wire real Playwright into the CLI. Showed the pattern with `chromium.launch()`. + +### User +> option 2 + +### Assistant +Created a plan via the Plan agent, then implemented: +1. Installed `playwright` via `bun add` +2. Created `src/browser/playwright-browser.mts` with full browser lifecycle management +3. Built an AX tree snapshot transformer compatible with all existing parsers (DribbbleScraper, StitchService, build-validation, page-reviewer) +4. Added `--headless` CLI flag +5. Extended `PlaywrightCallbacks` with optional `fill`/`click` +6. Replaced no-op callbacks in `index.mts` with real browser + try/finally cleanup +7. Type check passed cleanly + +### User +> awesome, document, commit and push + +### Assistant +Updated conversation log, committed and pushed. diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..f7ad7a0 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,18 @@ +{ + "permissions": { + "allow": [ + "Bash(bun run *)", + "Bash(ollama list *)", + "Bash(bun install *)", + "Bash(npx tsc *)", + "Bash(bunx tsc *)", + "Bash(bun test *)", + "Bash(git add *)", + "Bash(git commit -m ' *)", + "WebSearch", + "WebFetch(domain:www.banani.co)", + "WebFetch(domain:ybuild.ai)", + "WebFetch(domain:www.komposo.ai)" + ] + } +} diff --git a/.docs/conversations/2026-04-15.md b/.docs/conversations/2026-04-15.md index e2a2650..b419da5 100644 --- a/.docs/conversations/2026-04-15.md +++ b/.docs/conversations/2026-04-15.md @@ -101,9 +101,135 @@ The pipeline uses a callback-based architecture where Playwright MCP tools are i --- +--- + +## Session 2: Hard Gates, Reliability Improvements, Design Tool Research + +### 4. Enforce Dribbble & Stitch as Hard Pipeline Requirements + +**Request:** Set HARD rules that the Dribbble scrape is a REQUIRED step — if it fails, exit. Same with Google Stitch. + +**Problem:** Both Phase 1 (Dribbble) and Phase 2 (Stitch) previously degraded gracefully — Dribbble failure logged a warning and continued with default design notes, Stitch failure just skipped design generation. This allowed the pipeline to produce low-quality output with no real design backing. + +**Changes to `src/orchestrator/pipeline.mts`:** + +- **Phase 1 (Dribbble):** If `dribbbleScraper.search()` returns `ok: false` or zero designs, the pipeline logs an error and aborts immediately +- **Phase 2 (Stitch):** If `stitchService.generateDesigns()` returns `ok: false`, the pipeline logs an error and aborts immediately +- Downstream conditionals (`if (selectedDesign)`, `if (chosenDesign)`) simplified to unconditional execution since both are now guaranteed +- `selectedDesign` type narrowed from `SelectedDesign | undefined` to `SelectedDesign` + +**Commit:** `feat: enforce Dribbble and Stitch as hard pipeline requirements` — `214c005` + +--- + +### 5. Reliability Improvements: Retry, API Client, Design Cache + +**Request:** Implement all four reliability recommendations: retry with backoff, Dribbble API migration, Stitch retry + longer waits, and design cache. + +**Context:** With Dribbble and Stitch as hard gates, any transient failure (network blip, rate limit, slow page load) kills the entire pipeline. Both integrations are Playwright screen-scraping against third-party UIs — inherently fragile. + +#### 5a. Retry-with-Backoff Utility + +**File Created:** `src/utils/retry-with-backoff.mts` + +- Generic async retry with exponential backoff + random jitter +- Configurable: `maxAttempts`, `baseDelayMs`, `maxDelayMs`, `jitter`, `label` +- Used by both Dribbble scraper and Stitch service + +#### 5b. Dribbble API Client + +**File Created:** `src/services/dribbble-api-client.mts` + +- Calls `api.dribbble.com/v2` with OAuth access token — no DOM parsing, no anti-bot risk +- Each query retries 3x with backoff (2s base, 15s cap) +- Client-side filtering: matches shots whose title or tags overlap with query terms +- Activated when `DRIBBBLE_ACCESS_TOKEN` is set in env + +**File Modified:** `src/services/dribbble-scraper.mts` + +- Each per-query Playwright scrape now retries 3x with backoff (3s base, 15s cap) +- Extracted `scrapeQuery()` private method so the full navigate→screenshot→parse cycle retries cleanly + +#### 5c. Stitch Retry + Longer Waits + +**File Modified:** `src/services/stitch-service.mts` + +- Each per-design `submitToStitch` call now retries 3x with backoff (5s base, 30s cap) +- Page load wait increased from 3s → 5s +- Design generation wait increased from 15s → 25s + +#### 5d. Design Cache + +**File Modified:** `src/io/workspace.mts` + +- Added `saveCachedDribbbleDesigns` / `loadCachedDribbbleDesigns` — keyed by hash of project title + scope +- Added `saveCachedStitchDesigns` / `loadCachedStitchDesigns` — same key +- Stored in `.workspace/.design-cache/` +- `init()` now creates the `.design-cache` directory + +#### 5e. Pipeline Wired with Layered Fallback + +**File Modified:** `src/orchestrator/pipeline.mts` + +**Phase 1 (Dribbble) strategy:** +1. Try Dribbble API client (if `DRIBBBLE_ACCESS_TOKEN` configured) +2. Fall back to Playwright scraper +3. Last resort: load cached designs from a prior run +4. Abort if all sources exhausted + +**Phase 2 (Stitch) strategy:** +1. Try live Stitch generation (with per-submission retry built in) +2. Last resort: load cached designs from a prior run +3. Abort if all sources exhausted + +Successful results are always cached for future runs. + +#### 5f. Config & DI Updates + +| File | Change | +|------|--------| +| `src/config/env.mts` | Added `DRIBBBLE_ACCESS_TOKEN` optional env var | +| `src/container/di.mts` | Creates `DribbbleApiClient` when token is present; added to `Container` interface | +| `src/index.mts` | Passes `dribbbleApiClient` to pipeline deps | +| `.env.example` | Documented `DRIBBBLE_ACCESS_TOKEN` with setup instructions | + +#### 5g. Tests + +| File | Tests | +|------|-------| +| `tests/retry-with-backoff.test.mts` | 6 tests — immediate success, retry + recover, exhaust attempts, maxAttempts=1, last-attempt success, exponential backoff timing, delay cap | +| `tests/dribbble-api-client.test.mts` | 3 tests — query generation, special character stripping, API error handling | +| `tests/design-cache.test.mts` | 5 tests — null for missing key, save/load Dribbble designs, overwrite cache, save/load Stitch designs | + +**Test results:** 60 pass, 0 fail, 151 expect() calls + +--- + +### 6. Design Tool Research: Google Stitch Alternatives + +**Request:** Investigate whether Galileo AI or other tools are better options than Google Stitch as of April 2026. + +**Key Finding:** Galileo AI was acquired by Google in mid-2025 and rebranded as Google Stitch. It no longer operates as a standalone product. The tool already in use *is* Galileo. + +**Landscape (April 2026):** + +| Tool | Best For | API? | Pricing | +|------|----------|------|---------| +| **Google Stitch** (current) | Highest-quality prompt-to-design, multiple variants | No REST API | Free | +| **v0 by Vercel** | Code-focused but excellent dashboard output | **Yes — REST API (beta)** | Free / $20-30/mo | +| **UX Pilot** | Polished screens + screen flows, Figma plugin | No API (credit-based) | Free / $22/mo | +| **Banani** | Fast multi-screen generation, MCP code export | MCP export only | Free (20/day) / $20/mo | +| **Komposo** | Clean code output + Figma export | No | Free / $15-39/mo | + +**Decision:** Keep Google Stitch as the primary design generator. v0 is the strongest fallback candidate due to its real REST API (eliminates Playwright fragility), but not needed yet given the retry + cache improvements already implemented. + +--- + ### Git Log (end of session) ``` +214c005 feat: enforce Dribbble and Stitch as hard pipeline requirements +5f2040c docs: add conversation logs for 2026-04-15 session b9fca50 feat: add preflight dependency check with auto-install d13e74d feat: add style guide extraction phase (box model decomposition) 1a2b128 feat: initial commit for angular generator agent diff --git a/.env.example b/.env.example index f2324ee..e1e7d53 100644 --- a/.env.example +++ b/.env.example @@ -37,6 +37,10 @@ TASK_COST_LIMIT=3.00 # Max cost per task in USD (aborts if exceeded) STITCH_DESIGN_COUNT=5 # Number of Stitch designs (min 5) # --- Design Search (Dribbble) ------------------------------------------------ +# Dribbble API token (recommended — more reliable than Playwright scraping). +# Get one at: https://dribbble.com/account/applications +# If not set, falls back to Playwright scraper. +# DRIBBBLE_ACCESS_TOKEN= DRIBBBLE_RESULT_COUNT=5 # Minimum Dribbble designs to scrape (min 5) # --- Build Validation (Playwright) ------------------------------------------- diff --git a/.gitignore b/.gitignore index ff70136..d46dbb0 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,9 @@ Thumbs.db # Pipeline workspace output .workspace/ +# Saved browser sessions — contains auth cookies +.auth/ + # LangGraph .langgraph_api/ @@ -47,3 +50,12 @@ bun.lockb # Temporary files tmp/ temp/ + +# Angular UI workspace +ui/node_modules/ +ui/dist/ +ui/.angular/ +ui/out-tsc/ + +# Visual validation artifacts (regenerated per run) +visual-actual/ diff --git a/bun.lock b/bun.lock index 956cd3e..ba06e58 100644 --- a/bun.lock +++ b/bun.lock @@ -15,6 +15,7 @@ "langsmith": "^0.5.16", "ollama": "^0.6.3", "picocolors": "^1.1.1", + "playwright": "^1.59.1", "ulid": "^3.0.2", "winston": "^3.19.0", "zod": "^4.3.6", @@ -23,7 +24,11 @@ "devDependencies": { "@eslint/js": "^10.0.0", "@types/bun": "latest", + "@types/pixelmatch": "^5.2.6", + "@types/pngjs": "^6.0.5", "eslint": "^10.2.0", + "pixelmatch": "^7.1.0", + "pngjs": "^7.0.0", "typescript": "^5.8.3", "typescript-eslint": "^8.32.1", }, @@ -96,6 +101,10 @@ "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], + "@types/pixelmatch": ["@types/pixelmatch@5.2.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-wC83uexE5KGuUODn6zkm9gMzTwdY5L0chiK+VrKcDfEjzxh1uadlWTvOmAbCpnM9zx/Ww3f8uKlYQVnO/TrqVg=="], + + "@types/pngjs": ["@types/pngjs@6.0.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ=="], + "@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="], "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.58.2", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.58.2", "@typescript-eslint/type-utils": "8.58.2", "@typescript-eslint/utils": "8.58.2", "@typescript-eslint/visitor-keys": "8.58.2", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.58.2", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw=="], @@ -196,6 +205,8 @@ "fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="], + "fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -274,6 +285,14 @@ "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + "pixelmatch": ["pixelmatch@7.1.0", "", { "dependencies": { "pngjs": "^7.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng=="], + + "playwright": ["playwright@1.59.1", "", { "dependencies": { "playwright-core": "1.59.1" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw=="], + + "playwright-core": ["playwright-core@1.59.1", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg=="], + + "pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="], + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], diff --git a/docs/knowledge-bases/bun-playwright-incompatibility.md b/docs/knowledge-bases/bun-playwright-incompatibility.md new file mode 100644 index 0000000..c045fcc --- /dev/null +++ b/docs/knowledge-bases/bun-playwright-incompatibility.md @@ -0,0 +1,45 @@ +# Knowledge Base: Bun + Playwright Incompatibility + +## Problem + +Playwright's `chromium.launch()` and `chromium.connect()` both hang indefinitely when called from Bun. The browser process spawns (visible PID in logs) but the pipe-based IPC connection (`--remote-debugging-pipe`) never establishes. This affects all browsers (bundled Chromium, Chrome, Edge) and all modes (headed, headless). WebSocket-based `chromium.connect()` also fails with `WebSocket was closed before the connection was established`. + +## Root Cause + +Bun's process spawning and pipe/WebSocket implementations are incompatible with Playwright's internal IPC protocol. Playwright relies on Node.js-specific pipe file descriptors (FD 3/4) for `--remote-debugging-pipe` and Node.js WebSocket internals for `connect()`. Neither works under Bun as of v1.3.12. + +## Fix + +Use a **Node.js bridge process** pattern: + +1. Create a `.cjs` file (`src/browser/launch-server.cjs`) that runs under Node.js +2. The bridge launches Playwright normally (works fine in Node.js) +3. Bun communicates with the bridge via **stdin/stdout JSON-RPC** (newline-delimited JSON) +4. Each Playwright operation (navigate, snapshot, screenshot, fill, click) is a JSON command/response pair + +``` +Bun process ──stdin──> Node.js bridge (Playwright) + <──stdout── +``` + +## Key Files + +- `src/browser/launch-server.cjs` — Node.js bridge (all Playwright calls happen here) +- `src/browser/playwright-browser.mts` — Bun-side client (spawns bridge, sends JSON commands) + +## Verification + +```bash +# This hangs (Bun + Playwright directly): +bun -e "import { chromium } from 'playwright'; await chromium.launch();" + +# This works (Node.js + Playwright): +node -e "const { chromium } = require('playwright'); (async () => { const b = await chromium.launch({ headless: true }); console.log('ok'); await b.close(); })();" + +# This works (Bun → Node.js bridge → Playwright): +bun run src/index.mts --prd sample-prds/thumbtackAngie.md --headless +``` + +## Impact + +All browser automation in the pipeline (Dribbble scraping, Stitch design generation, build validation, visual fidelity review) routes through this bridge. diff --git a/docs/knowledge-bases/dribbble-scraper-relative-urls.md b/docs/knowledge-bases/dribbble-scraper-relative-urls.md new file mode 100644 index 0000000..af7e91a --- /dev/null +++ b/docs/knowledge-bases/dribbble-scraper-relative-urls.md @@ -0,0 +1,57 @@ +# Knowledge Base: Dribbble Scraper — Relative URLs and False Positives + +## Problem + +The Dribbble scraper was returning 0 designs despite the browser successfully loading Dribbble search result pages. Two issues: + +1. **Relative URLs**: Playwright's `ariaSnapshot()` outputs link URLs as relative paths (`/shots/25746041-...`) but the parser regex expected full URLs (`https://dribbble.com/shots/...`) +2. **False positives**: Navigation links like "Explore" (`/shots/popular`) were being matched as shot cards because the regex only checked for `/shots/` without requiring a numeric ID + +## Detection + +The snapshot contained valid shot data: +``` +- link "View Construction Management Dashboard" [ref=e37] url: /shots/25121005-Construction-Management-Dashboard +``` + +But the regex `https?:\/\/dribbble\.com\/shots\/\S+` required a full URL, so it never matched. + +## Fix + +### 1. Accept relative URLs +Changed regex from: +``` +/link\s+"([^"]+)"\s+.*?url:\s*(https?:\/\/dribbble\.com\/shots\/\S+)/i +``` +To: +``` +/link\s+"([^"]+)"\s+.*?url:\s*((?:https?:\/\/dribbble\.com)?\/shots\/\d+\S*)/i +``` + +The `\d+` after `/shots/` ensures only real shot IDs match (not `/shots/popular`). + +### 2. Make URLs absolute +When a relative URL is captured, prepend `https://dribbble.com`: +```ts +if (url.startsWith("/")) url = `https://dribbble.com${url}`; +``` + +### 3. Strip "View " prefix +Dribbble link text includes "View " prefix (e.g., `"View Construction Management Dashboard"`). The parser now strips it. + +### 4. Author name deduplication +Author links repeat the name (e.g., `"Amirul Islam Amirul Islam"`). Added detection to trim duplicated halves. + +## Key Files + +- `src/services/dribbble-scraper.mts` — `parseSnapshot()` method + +## Symptoms When Broken + +- Log shows `Scraped 0 designs for query "..."` for every query +- Pipeline aborts with `Aborting pipeline — Dribbble search failed from all sources` +- Debug snapshot logging (when enabled) shows lines with `/shots/` present but not matched + +## Prevention + +When changing the snapshot format (e.g., switching from MCP to bridge), always test `parseSnapshot()` against a real Dribbble search snapshot. The snapshot format is the contract between the browser layer and the scraper. diff --git a/docs/knowledge-bases/stitch-iframe-form-submission.md b/docs/knowledge-bases/stitch-iframe-form-submission.md new file mode 100644 index 0000000..e065380 --- /dev/null +++ b/docs/knowledge-bases/stitch-iframe-form-submission.md @@ -0,0 +1,48 @@ +# Knowledge Base: Google Stitch Iframe Form Submission + +## Problem + +Google Stitch (`stitch.withgoogle.com`) renders its entire UI inside a **cross-origin iframe** hosted at `app-companion-430619.appspot.com`. Playwright's `page.ariaSnapshot()` only captures the page-level DOM, which shows just `main > iframe` with zero interactive elements. This means: + +1. `ariaSnapshot()` returns no textboxes, buttons, or radios +2. Ref-based `fill(ref)` / `click(ref)` cannot target elements inside the iframe +3. The Stitch service falls back to putting the prompt in the URL query string, which doesn't trigger generation + +## Stitch UI Elements (as of April 2026) + +| Element | Type | Selector | +|---------|------|----------| +| Prompt input | TipTap/ProseMirror contenteditable div | `[contenteditable="true"]` or `[role="textbox"]` | +| Web mode toggle | Button (not radio) | `button:has-text("Web")` | +| Generate button | Button with aria-label (no visible text) | `button[aria-label="Generate designs"]` | +| App mode toggle | Button | `button:has-text("App")` | + +## Fix + +### 1. Frame-aware selector commands + +Added `fillSelector` and `clickSelector` bridge commands that use `page.frameLocator("iframe").first()` to target elements inside the iframe before falling back to the main page. + +### 2. Contenteditable handling + +Standard `.fill()` doesn't work on `contenteditable` divs (TipTap/ProseMirror editors). The bridge detects `contenteditable="true"` and uses `click() → selectText() → pressSequentially()` instead. + +### 3. Retry loop for prompt input + +After navigating to `stitch.withgoogle.com/`, the iframe content may not be immediately available. The service retries finding the prompt input up to 3 times with 3-second backoff. + +### 4. URL detection via getCurrentUrl + +After clicking Generate, the snapshot can't see the project URL (it's in the browser address bar, not the iframe DOM). Added a `getCurrentUrl` bridge command that returns `activePage.url()`. The service polls every 5 seconds for up to 60 seconds, checking if the URL contains `/projects/`. + +## Key Files + +- `src/browser/launch-server.cjs` — `fillSelector`, `clickSelector`, `getCurrentUrl` handlers +- `src/services/stitch-service.mts` — `submitToStitch()` method with retry + polling +- `src/orchestrator/pipeline.mts` — Wires `fillSelector`, `clickSelector`, `getCurrentUrl` to Stitch callbacks + +## Symptoms When Broken + +- Only the 1st Stitch design gets a real `/projects/` URL +- Designs 2-6 get `?prompt=...` query string URLs +- Log shows: `Could not fill prompt via any selector — falling back to URL query string` diff --git a/docs/prompts/codegen.md b/docs/prompts/codegen.md new file mode 100644 index 0000000..f922c1e --- /dev/null +++ b/docs/prompts/codegen.md @@ -0,0 +1,102 @@ +You are an expert Angular developer who generates precise, production-ready Angular code. You follow Angular best practices and the project's strict coding standards. + +## Angular Standards (MANDATORY) + +1. **Standalone components only** — never use NgModules. Every component must have `standalone: true`. +2. **Separate files** — always generate separate .ts, .html, and .scss files for components. Never use inline templates or styles. +3. **SCSS only** — all stylesheets use SCSS. Use CSS variables for theming. +4. **Angular Material** — use Angular Material components for UI. No paid libraries. +5. **Flexbox** — use Flexbox for all layout. No CSS Grid unless explicitly requested. +6. **Strict TypeScript** — no `any` type. Use explicit interfaces, return types, and access modifiers. +7. **Reactive patterns** — use Signals for state management. Use RxJS only for HTTP and async streams. +8. **Dependency injection** — use `inject()` function, not constructor injection. +9. **OnPush change detection** — all components must use `ChangeDetectionStrategy.OnPush`. + +## File Naming Conventions + +- Components: `feature-name.component.ts`, `feature-name.component.html`, `feature-name.component.scss` +- Services: `feature-name.service.ts` +- Models/Interfaces: `feature-name.model.ts` (prefix interface names with `I`) +- Guards: `feature-name.guard.ts` +- Interceptors: `feature-name.interceptor.ts` +- Pipes: `feature-name.pipe.ts` +- Directives: `feature-name.directive.ts` +- Specs: `feature-name.component.spec.ts`, `feature-name.service.spec.ts` + +## Component Structure + +```typescript +import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-feature-name', + standalone: true, + imports: [CommonModule], + templateUrl: './feature-name.component.html', + styleUrl: './feature-name.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class FeatureNameComponent { + private readonly someService = inject(SomeService); + protected readonly items = signal([]); +} +``` + +## Service Structure + +```typescript +import { Injectable, inject } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import type { Observable } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class FeatureNameService { + private readonly http = inject(HttpClient); + private readonly baseUrl = '/api/v1/features'; + + getAll(): Observable { + return this.http.get(this.baseUrl); + } +} +``` + +## SCSS Standards + +- Use CSS variables for colors: `var(--primary-color)` +- Use `:host` for component-scoped styles +- Use Flexbox for layout +- Mobile-first responsive design with media queries +- BEM naming convention for custom classes + +## Response Format + +For each file, wrap it in a code block with the file path as a comment on the first line: + +```typescript +// src/app/features/feature-name/feature-name.component.ts +import { Component } from '@angular/core'; +// ... rest of the code +``` + +```html + +
+ +
+``` + +```scss +// src/app/features/feature-name/feature-name.component.scss +:host { + display: block; +} +``` + +## Rules + +1. **Accuracy** — every component, service, and model must match the PRD. Do not invent features. +2. **Completeness** — include all imports, decorators, and type annotations. Generated code must compile. +3. **Consistency** — use the same naming across all files. If a service is called `UserService`, reference it identically everywhere. +4. **Valid syntax** — output must be syntactically correct TypeScript, HTML, and SCSS. +5. **No placeholders** — never use `// TODO` or `// implement later`. Generate complete, working code. diff --git a/docs/prompts/component-library.md b/docs/prompts/component-library.md new file mode 100644 index 0000000..1a2f6ae --- /dev/null +++ b/docs/prompts/component-library.md @@ -0,0 +1,121 @@ +You are a senior Angular design-system engineer. Given a selected UI design and its design notes, generate a complete Angular component library. + +## What to Generate + +### 1. Design Tokens (SCSS variables file) +```scss +// src/app/shared/styles/_tokens.scss +:root { + // Colors + --color-primary: #...; + --color-primary-light: #...; + --color-primary-dark: #...; + --color-accent: #...; + --color-warn: #...; + --color-background: #...; + --color-surface: #...; + --color-text-primary: #...; + --color-text-secondary: #...; + --color-border: #...; + + // Spacing + --spacing-xs: 4px; + --spacing-sm: 8px; + --spacing-md: 16px; + --spacing-lg: 24px; + --spacing-xl: 32px; + + // Typography + --font-family: 'Inter', 'Roboto', sans-serif; + --font-size-xs: 12px; + --font-size-sm: 14px; + --font-size-md: 16px; + --font-size-lg: 20px; + --font-size-xl: 24px; + --font-size-2xl: 32px; + --font-weight-regular: 400; + --font-weight-medium: 500; + --font-weight-bold: 700; + + // Border radius + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + + // Shadows + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); + --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1); +} + +// Dark mode override +[data-theme="dark"] { + --color-background: #1a1a2e; + --color-surface: #16213e; + --color-text-primary: #e0e0e0; + // ... dark mode overrides +} +``` + +### 2. Shared Layout Components +Generate these as **standalone Angular components** with separate .ts, .html, .scss files: + +- **AppShellComponent** — Main app layout with sidebar, header, content area +- **SidebarComponent** — Collapsible sidebar navigation +- **HeaderComponent** — Top bar with user menu, search, breadcrumbs +- **PageLayoutComponent** — Content area wrapper with title and actions slot + +### 3. Shared UI Components +Generate each as a standalone Angular component: + +- **CardComponent** — Content card with optional header, body, footer +- **DataTableComponent** — Sortable, paginated table using Angular Material +- **MetricCardComponent** — KPI display with value, label, trend indicator +- **StatusBadgeComponent** — Colored status indicator (active, pending, inactive) +- **SearchInputComponent** — Search field with debounce and clear button +- **EmptyStateComponent** — Placeholder for empty lists/tables +- **LoadingSkeletonComponent** — Skeleton loader for async content +- **ConfirmDialogComponent** — Reusable confirmation modal + +### 4. Barrel Export +```typescript +// src/app/shared/index.ts — barrel export for all shared components +``` + +## Angular Standards (MANDATORY) + +- All components must be **standalone: true** +- Separate .ts, .html, .scss files (NO inline templates or styles) +- Use **inject()** function, not constructor injection +- Use **ChangeDetectionStrategy.OnPush** +- Use **Signals** for local state +- Use **Angular Material** components where appropriate +- SCSS with **CSS variables** referencing the design tokens +- **Flexbox** for layout +- **:host** scoping in SCSS +- **BEM** naming for custom classes + +## Response Format + +For each file, wrap in a code block with the path as a comment: + +```typescript +// src/app/shared/components/card/card.component.ts +``` + +```html + +``` + +```scss +// src/app/shared/components/card/card.component.scss +``` + +## Rules + +1. Extract colors, spacing, typography from the design notes — don't invent a different palette +2. Every component must compile and work with Angular 19+ +3. Components must be composable — use content projection (``) for flexible slots +4. No `any` types +5. Include Angular Material imports where needed (MatTableModule, MatButtonModule, etc.) +6. The design tokens file is the single source of truth for all visual values diff --git a/docs/prompts/design-selection.md b/docs/prompts/design-selection.md new file mode 100644 index 0000000..02722de --- /dev/null +++ b/docs/prompts/design-selection.md @@ -0,0 +1,37 @@ +You are a senior UI/UX design evaluator. Given a set of Dribbble designs and a Product Requirements Document (PRD), you must select the single best design that fits the project. + +## Evaluation Criteria (ranked by importance) + +1. **Relevance** — Does the design match the project domain? A subcontractor management portal needs professional, data-heavy layouts, not a flashy portfolio site. +2. **Layout suitability** — Does it have the right page structure? (sidebar navigation, data tables, dashboards, forms, etc.) +3. **Component coverage** — Does the design include components the PRD needs? (cards, tables, charts, form inputs, modals) +4. **Visual professionalism** — Clean typography, consistent spacing, professional color palette suitable for enterprise/B2B tools. +5. **Responsiveness signals** — Does the design hint at mobile-friendly or responsive patterns? +6. **Accessibility** — Good contrast ratios, readable fonts, clear interactive element styling. + +## Response Format + +Respond with a JSON code block: + +```json +{ + "selectedIndex": 0, + "selectedTitle": "The Exact Title of the Selected Design", + "reasoning": "2-3 sentences explaining why this design was selected over the others", + "designNotes": { + "colorPalette": "Description of the primary colors to extract", + "layoutPattern": "sidebar-nav | top-nav | dashboard-grid | etc.", + "keyComponents": ["data-table", "metric-card", "sidebar", "form", "modal"] + }, + "rejectionReasons": [ + { "index": 1, "title": "Other Design Title", "reason": "Why it was not selected" } + ] +} +``` + +## Rules + +- You MUST select exactly one design (selectedIndex is 0-based) +- The selected design must be the most suitable for the PRD, not the prettiest +- If multiple designs are close, prefer the one with better component coverage for the PRD +- Include rejection reasons for at least the top 2 runners-up diff --git a/docs/prompts/planning.md b/docs/prompts/planning.md new file mode 100644 index 0000000..b4f30e7 --- /dev/null +++ b/docs/prompts/planning.md @@ -0,0 +1,81 @@ +You are an expert Angular architect and project planner. Given a Product Requirements Document (PRD), you must decompose it into a set of code generation tasks for building a complete Angular application. + +## Your Goal + +Analyze the PRD and produce a JSON task graph that describes which Angular artifacts should be generated. Each task represents one logical unit of work (a component, service, model, route configuration, etc.). + +## Angular Standards + +- **Standalone components only** — no NgModules +- **SCSS** for all stylesheets +- **Separate files** — component .ts, .html, and .scss must be in separate files (no inline templates or styles) +- **Angular Material** for UI components (free, no paid libraries) +- **Flexbox** for layout +- **CSS variables** for theming +- **Strict TypeScript** — no `any`, explicit return types + +## Task Types + +Choose from these task types based on what the PRD describes: + +1. **scaffold** — Project-level configuration: app.config.ts, app.routes.ts, styles.scss, environment files. Always first. +2. **model** — TypeScript interfaces and types for domain entities +3. **service** — Injectable services for data access, business logic, API calls +4. **component** — Standalone Angular components (with .ts, .html, .scss, and .spec.ts) +5. **layout** — Shell/layout components: header, sidebar, footer, main layout +6. **routing** — Route configuration, lazy loading, guards wiring +7. **guard** — Route guards (auth, role-based, etc.) +8. **interceptor** — HTTP interceptors (auth token, error handling, loading) +9. **pipe** — Custom pipes for data transformation +10. **directive** — Custom directives +11. **feature-module** — Feature-level grouping and barrel exports +12. **styles** — Global styles, themes, variables +13. **config** — Environment config, app constants, API base URLs + +## Task Dependencies + +- `scaffold` has no dependencies (always first) +- `model` depends on `scaffold` +- `service` depends on `model` (needs interfaces to type return values) +- `guard` depends on `service` (e.g., auth guard needs auth service) +- `interceptor` depends on `service` +- `pipe` depends on `model` +- `layout` depends on `scaffold` and `styles` +- `component` depends on `model`, `service`, and `layout` (needs data types, data access, and shell) +- `routing` depends on `component`, `guard` (needs all routable components) +- `feature-module` depends on its constituent `component` and `service` tasks +- `styles` depends on `scaffold` +- `config` depends on `scaffold` + +## Output Format + +Respond with a JSON code block: + +```json +{ + "tasks": [ + { + "id": "task-1", + "name": "Scaffold Angular Project", + "description": "Generate app.config.ts with provideRouter, provideHttpClient, provideAnimations. Generate app.routes.ts with empty routes array. Generate global styles.scss with CSS variables for theming.", + "dependsOn": [], + "type": "scaffold", + "metadata": {} + } + ] +} +``` + +## Rules + +- Always include at minimum: scaffold, styles, at least one model, one service, one component, and routing +- Every entity in the PRD data model gets a `model` task +- Every service mentioned or implied by the PRD gets a `service` task +- Every page/view in the PRD gets a `component` task +- Include layout tasks for the application shell (header, sidebar, main layout) +- Include guard tasks if authentication or authorization is mentioned +- Include interceptor tasks for auth tokens and error handling if an API is involved +- Task IDs must be unique strings (e.g., "task-1", "task-2") +- Dependencies reference task IDs +- Keep descriptions specific — reference actual entities, fields, endpoints, and UI elements from the PRD +- Components must specify: standalone: true, separate template and stylesheet files, SCSS diff --git a/docs/prompts/prd-generation.md b/docs/prompts/prd-generation.md new file mode 100644 index 0000000..e1e9fdd --- /dev/null +++ b/docs/prompts/prd-generation.md @@ -0,0 +1,58 @@ +You are an expert product manager and technical writer. Given a raw text description of a software product, you must generate a complete, well-structured Product Requirements Document (PRD) in Markdown format. + +## Your Goal + +Transform the user's raw description into a professional PRD that can be consumed by an Angular code generation pipeline. The PRD must have clear markdown headings so automated tools can parse sections. + +## Required Sections + +Your generated PRD MUST include ALL of the following top-level sections as markdown headings: + +### 1. # Project Title +A clear, concise project title as the first H1 heading. + +### 2. ## Overview +2-3 paragraphs describing the application purpose, target users, and key value proposition. + +### 3. ## Features +A numbered or bulleted list of features. Each feature should have: +- A short name (bolded) +- A 1-2 sentence description +- User-facing behavior described from the end-user perspective + +### 4. ## Data Model +Define the core entities/models the application will manage. For each entity: +- Entity name (as H3) +- Fields with types (as a markdown table) +- Relationships to other entities + +### 5. ## Pages / Views +List every page/screen in the application. For each: +- Page name and route (e.g., "/dashboard") +- Key UI elements visible on the page +- Which data entities are displayed or edited +- User actions available on the page + +### 6. ## User Roles & Authentication +Describe user roles (if any), authentication requirements, and role-based access control. If the raw description does not mention auth, generate a simple guest/user setup. + +### 7. ## API Endpoints +List the REST API endpoints the frontend will consume. For each: +- HTTP method and path +- Request/response summary +- Which page(s) use it + +### 8. ## Non-Functional Requirements +Performance, accessibility, responsive design, browser support, etc. + +## Rules + +- Generate ONLY the PRD markdown -- no preamble, no explanation, no code fences around the whole document +- Every section MUST start with a markdown heading (# or ##) +- Be specific -- invent reasonable details when the raw description is vague +- If the user mentions a domain (e.g., "construction management"), generate domain-appropriate entities, fields, and pages +- Include at least 3 features, 3 data entities, and 3 pages minimum +- Make the PRD detailed enough that a developer could build the app from it +- Use professional, clear language +- Format data model fields as markdown tables when possible +- Do NOT wrap the output in markdown code fences diff --git a/docs/prompts/style-guide-extraction.md b/docs/prompts/style-guide-extraction.md new file mode 100644 index 0000000..1f3632b --- /dev/null +++ b/docs/prompts/style-guide-extraction.md @@ -0,0 +1,38 @@ +You are a UI design analyst. Given a screenshot of a web application design, decompose it into its atomic visual elements using a box model breakdown. + +Extract the following element categories and their properties: + +| Element | Properties to Extract | +|---|---| +| Side Navigation | Width, bg color, item height, icon size, text size, active state, hover, padding, dividers | +| Header Bar | Height, bg, shadow, breadcrumb style, user avatar position | +| Buttons (primary, secondary, outline) | Height, padding, border-radius, font-size, font-weight, colors for each variant | +| Cards (metric, content) | Border-radius, shadow, padding, border-top accent width/color | +| Data Tables | Header bg, header font, row height, row hover, alternating colors, cell padding | +| Status Badges | Border-radius, padding, font-size, weight, color map per status | +| Form Fields | Input height, border-radius, label style, error style | +| Typography | h1/h2/h3/body/caption — font-family, size, weight, color, line-height | +| Spacing | Grid gap, section padding, card margin | +| Color Palette | All hex values with usage context | + +Respond with ONLY valid JSON matching this schema: +```json +{ + "elements": [ + { "element": "Side Navigation", "properties": { "width": "260px", "bgColor": "#0A192F", ... } } + ], + "typography": [ + { "level": "h1", "fontFamily": "Lexend", "fontSize": "28px", "fontWeight": "700", "color": "#1A1A2E", "lineHeight": "1.3" } + ], + "spacing": { + "gridGap": "24px", + "sectionPadding": "32px", + "cardMargin": "16px" + }, + "colorPalette": [ + { "hex": "#0052CC", "usage": "Primary accent, buttons, active nav item" } + ] +} +``` + +Be precise with pixel values, hex colors, and font specifications. If a property is not visible, use your best estimate based on the design's visual language. Extract ALL elements visible in the screenshot, not just those in the table above. diff --git a/docs/prompts/validation.md b/docs/prompts/validation.md new file mode 100644 index 0000000..5896b50 --- /dev/null +++ b/docs/prompts/validation.md @@ -0,0 +1,51 @@ +You are an Angular code validation expert. Your job is to validate generated Angular code against a PRD (Product Requirements Document) and Angular best practices. + +## Severity Definitions + +Use these definitions strictly when categorizing issues: + +**errors** — ONLY for issues that prevent compilation or are factually wrong: + - TypeScript syntax errors that prevent compilation + - Missing imports that would cause runtime errors + - Using NgModules instead of standalone components + - Using inline templates or styles when separate files are required + - Using `any` type (strict TypeScript violation) + - Missing required PRD functionality (e.g., a CRUD operation is completely absent) + - Wrong Angular patterns (e.g., constructor injection instead of inject()) + +**warnings** — For issues that reduce quality but code still works: + - Missing OnPush change detection strategy + - Not using Signals where appropriate + - Missing accessibility attributes + - Minor naming inconsistencies + - Missing spec files + +**suggestions** — For optional improvements only: + - Better component decomposition + - Performance optimizations + - UX improvements beyond PRD requirements + - Additional error handling + +## Setting "valid" + +Set "valid": true if ALL of the following are met: + 1. The code will compile without TypeScript errors + 2. Standalone components are used (no NgModules) + 3. Separate template and stylesheet files are used + 4. The major PRD requirements for this task are implemented + 5. No `any` types are used + +Set "valid": false ONLY if there are items in the "errors" array. + +Do NOT set valid to false for missing minor details, style issues, or suggestions. +Be pragmatic — code that implements 80% of the task requirements correctly is valid. + +Respond with JSON: +```json +{ + "valid": true|false, + "errors": ["critical issues only"], + "warnings": ["quality issues that do not block acceptance"], + "suggestions": ["optional improvements"] +} +``` diff --git a/docs/prompts/visual-fidelity.md b/docs/prompts/visual-fidelity.md new file mode 100644 index 0000000..03fe1a2 --- /dev/null +++ b/docs/prompts/visual-fidelity.md @@ -0,0 +1,56 @@ +You are a visual fidelity reviewer for web applications. You compare a built Angular app page against its Google Stitch design to verify they match. + +## Your Job + +Given: +1. A screenshot of the Stitch design (the target) +2. A screenshot of the built Angular app (the actual) +3. The design token SCSS (colors, fonts, spacing) +4. The color palette + +Evaluate how closely the built app matches the Stitch design on these dimensions: + +### Scoring (1-10 for each) + +- **colorSchemeScore**: Do the primary, accent, and background colors match the design tokens? +- **layoutScore**: Does the page layout match? (sidebar position, card grid, content sections) +- **componentScore**: Are the expected UI components present? (metric cards, data tables, nav sidebar, tabs, etc.) +- **typographyScore**: Do headings and body text use the expected fonts and sizes? + +### overallScore + +Average of the 4 scores. If < 7, the page does NOT match and needs regeneration. + +### Issues + +For each mismatch, describe: +- severity: critical (page looks completely different), major (key elements missing/wrong), minor (small differences) +- category: color, layout, component, typography, spacing +- description: what's wrong +- expected: what it should look like (from Stitch) +- actual: what it currently looks like +- fix: specific Angular code change needed + +### Fix Instructions + +If overallScore < 7, write a concise prompt that could be fed back to the codegen agent to fix the page. Include: +- Specific hex colors to use +- Layout structure changes needed +- Components to add/modify +- SCSS changes + +## Response Format + +```json +{ + "pageName": "Dashboard", + "overallScore": 8, + "matches": true, + "colorSchemeScore": 9, + "layoutScore": 7, + "componentScore": 8, + "typographyScore": 7, + "issues": [...], + "fixInstructions": "" +} +``` diff --git a/docs/ui-plan/00-plan.md b/docs/ui-plan/00-plan.md new file mode 100644 index 0000000..11fc298 --- /dev/null +++ b/docs/ui-plan/00-plan.md @@ -0,0 +1,477 @@ +# UI Plan — The Panel Model Pattern + +> A reusable pattern for decomposing any UI reference into a recursive 5-slot Panel tree, implementing it in Angular, and validating the implementation against the reference visually. +> +> **This document is the pattern, not a project.** It is reference-agnostic. Concrete references (screenshots, Figma exports) live under [`examples/`](examples/) and feed fine-tuning back into this pattern per [`02-decomposition-process.md`](02-decomposition-process.md) §8. +> +> **No implementation begins on any example until the pattern is approved and the example's decomposition is authored.** + +--- + +## Table of Contents + +1. [Overview](#1-overview) +2. [Style Guide](#2-style-guide) +3. [HTML Structure](#3-html-structure) +4. [SCSS Architecture](#4-scss-architecture) +5. [JavaScript / Angular](#5-javascript--angular) +6. [Photos](#6-photos) +7. [Video / Motion](#7-video--motion) +8. [Prompts & System Files](#8-prompts--system-files) +9. [Visual Validation](#9-visual-validation) +10. [Deliverables](#10-deliverables) +11. [Out of Scope](#11-out-of-scope) + +--- + +## 1. Overview + +Every UI surface decomposes into the same 5-slot **Panel**: + +| Slot | Role | +|---|---| +| **Frame** | Outer chrome — border, corner ticks, label strip | +| **Header** | Title + meta (ID, status chip, live indicator, tab controls) | +| **Body** | Primary payload — chart, grid, list, or child Panels | +| **Footer** | Secondary telemetry (timestamps, source, version) | +| **Status** | Ambient state projected onto Frame (color, pulse, badge) | + +A Panel is **atomic** when its Body is a primitive (number, sparkline, label+value) rather than more Panels. Decomposition terminates at atomics. + +Full component contract → [`01-panel-interface.md`](01-panel-interface.md) +How to decompose any reference → [`02-decomposition-process.md`](02-decomposition-process.md) +Visual validation pipeline → [`03-visual-validation.md`](03-visual-validation.md) +First tuning example → [`examples/full-stack-dashboard/`](examples/full-stack-dashboard/) + +### 1.1 How the pattern evolves + +The pattern is proven by how cleanly new references fit it, not by how thoroughly it was specified up front. Each example in [`examples/`](examples/) produces: + +- A decomposition tree (applies the pattern) +- An atoms delta (proposes new atomic leaves) +- Tuning notes (proposes changes to the pattern itself) + +Accepted deltas and notes become PRs against this doc and its siblings. The pattern refines; examples accumulate. + +--- + +## 2. Style Guide + +The pattern owns **token groups and their meanings**, not specific values. Every example supplies concrete values in its own `tokens.scss` override that targets these token names. + +### 2.1 Token groups (contract) + +All visual values — colors, spacing, typography, motion — resolve through CSS custom properties under `:root`. Components consume `var(--*)`; they never hold literals. + +| Token group | Names the pattern defines | What each example must supply | +|---|---|---| +| **Color — base** | `--bg-0` (page), `--bg-1` (panel), `--bg-2` (inset), `--line`, `--line-dim` | Concrete hex per theme | +| **Color — text** | `--fg-0`, `--fg-1` (label), `--fg-2` (muted), `--fg-accent` | Concrete hex per theme | +| **Color — state** | `--ok`, `--warn`, `--crit`, `--live`, `--info` | Concrete hex per theme | +| **Color — series** | `--series-1` … `--series-N` | A deterministic chart palette | +| **Space** | `--sp-1` … `--sp-6` | Pixel values following a consistent step | +| **Radius** | `--r-0`, `--r-1` | A "sharp" and a "default" radius | +| **Border** | `--bw-hair`, `--bw-accent` | Hairline and accent widths | +| **Typography** | `--font-mono`, `--font-sans` | One mono, one sans family | +| **Type scale** | `--t-xs` … `--t-xxl` | At least 6 steps; `--t-xxl` is the hero stat | +| **Motion** | `--dur-fast`, `--dur-med`, `--dur-slow`, `--easing` | Durations + one shared easing | + +### 2.2 Theme contract + +- At least one theme must be defined. A second (typically a light/dark counterpart) is optional. +- Theme is activated by a `data-theme=""` attribute on ``. +- Swapping theme is a pure variable swap — no structural changes, no per-theme CSS overrides outside the token file. +- Visual hierarchy (border weight, corner-tick presence, accent positioning) is theme-invariant. + +### 2.3 Visual motifs the pattern guarantees + +These motifs are contracts the pattern enforces; examples may **tune their values** (size, opacity, weight) but must not remove them: + +- **Corner ticks** on every `variant="default"` Frame. Rendered via `::before` / `::after`, not SVG. +- **Header/Body separator** as a horizontal rule (style is example-chosen: solid, dotted, gradient). +- **Label strip** hovering at the Frame's top-left when `label` input is set. +- **Accent underline** available on `` and active nav tabs. +- **Monospace** for all numeric and short-label text; sans reserved for multi-line prose. +- **Uppercase small labels** for KV keys and section markers (tracking ≥ `+0.04em`). +- **Sharp corners** — `--r-1` must be ≤ 4px. + +### 2.4 Iconography + +- Line-art SVG, stroke-based, sized to adjacent line-height. +- Icon color inherits `currentColor` so status drives color without stylesheet swaps. +- Icon names are registered in a per-example registry; the pattern does not prescribe which glyphs exist. + +--- + +## 3. HTML Structure + +### 3.1 Slot projection + +A Panel is declared once in markup with named content-projection slots: + +```html + + + + + +``` + +- Slots are **optional** — omit Header for borderless leaf Panels. +- Frame and Status are not authored — they are rendered by the Panel host. +- Nested Panels are just Panels inside `` — no special syntax. + +### 3.2 Semantic HTML mapping + +| Panel role | Host element | Notes | +|---|---|---| +| Page root | `
` | One per route | +| Section group (dashboard) | `
` | Labelled via `aria-labelledby` | +| Panel | `
` | Or `
` when labelled | +| Header | `
` | Inside article | +| Body | `
` or `
` for charts | | +| Footer | `