diff --git a/.agents/hooks/core/serena-primer.ts b/.agents/hooks/core/serena-primer.ts index dc3a7bb..6605ac2 100644 --- a/.agents/hooks/core/serena-primer.ts +++ b/.agents/hooks/core/serena-primer.ts @@ -116,6 +116,7 @@ export function primerContext(): string { "- Code discovery / reading: `get_symbols_overview`, `find_symbol`, `find_referencing_symbols`, `search_for_pattern`.", "- Code edits: `replace_symbol_body`, `insert_after_symbol`, `insert_before_symbol`, `replace_content`.", "- Native grep/glob: only for initial filename/path discovery. Do not fall back to grep + Read for code navigation just because Serena's tools aren't loaded yet — load them.", + "- Exception — MCP timeout: if a Serena MCP call times out or hangs (seen mainly in OpenCode Desktop's long-lived sidecar), stop retrying MCP for this session: use native search/read for code, and access `.serena/memories/` files directly (or `serena memories read|write` when Serena CLI ≥ 1.5 is installed) for memory work. A full app relaunch restores Serena MCP.", ].join("\n"); } diff --git a/.agents/hooks/core/triggers.json b/.agents/hooks/core/triggers.json index 32c9b53..73c6a59 100644 --- a/.agents/hooks/core/triggers.json +++ b/.agents/hooks/core/triggers.json @@ -2067,7 +2067,8 @@ "react", "tailwind", "tsx", - "frontend" + "frontend", + "angular" ], "en": [ "make a react component", @@ -2086,7 +2087,8 @@ "넥스트 페이지", "tailwind로 스타일", "shadcn 붙여줘", - "프론트 구현" + "프론트 구현", + "앵귤러" ], "ja": [ "reactコンポーネント", diff --git a/.agents/skills/_shared/core/evaluator-tuning.md b/.agents/skills/_shared/core/evaluator-tuning.md deleted file mode 100644 index d5f3d1c..0000000 --- a/.agents/skills/_shared/core/evaluator-tuning.md +++ /dev/null @@ -1,82 +0,0 @@ -# Evaluator Tuning Protocol - -QA prompts do not work well out of the box. Reliable evaluation requires -iterative refinement based on observed judgment errors. -(ref: Anthropic harness design, "several rounds of development loop necessary") - -This protocol is **semi-automated**: collection is automatic, analysis and patching -require human review via `oma retro`. - ---- - -## Tuning Loop - -``` -Sessions accumulate EA events in session-metrics.md - ↓ -[1] Trigger: EA >= 30 on rolling 3-session window - ↓ -[2] `oma retro` aggregates EA events and generates tuning report - ↓ -[3] Report categorizes errors by type and suggests specific patches - ↓ -[4] User reviews and approves patches - ↓ -[5] Patches applied to QA checklist.md / execution-protocol.md - ↓ -[6] Validation: Next 3 sessions, check if same error type recurs - ↓ Recurs → re-enter at [2] with stronger fix - ↓ Resolved → mark as confirmed in tuning log -``` - ---- - -## Patch Targets - -| Error Pattern | Patch Target | Example | -|--------------|-------------|---------| -| Missed bug category | QA `checklist.md`: add check item | "Race condition in concurrent writes" | -| Wrong severity | QA `execution-protocol.md`: add calibration rule | "Auth issues are always CRITICAL" | -| Missed stub | QA `checklist.md`: runtime verification section | "Check upload actually processes file" | -| False positive pattern | QA `execution-protocol.md`: add exclusion | "Unused imports in test files are OK" | -| Inconsistent depth | QA `execution-protocol.md`: difficulty link | "Complex tasks require full audit" | - ---- - -## Tuning Log - -Maintained in this file. Record each tuning action: - -```markdown -### {YYYY-MM-DD}: {one-line summary} -- **Error observed**: {what QA got wrong, with EA event type} -- **Root cause**: {why the prompt allowed this} -- **Patch applied**: {file + change description} -- **Validation**: {pending | confirmed in session {id} | failed — re-tuned} -``` - ---- - -## Tuning from Success - -When `good_catch` events accumulate (>= 5 in rolling window): - -1. Identify which QA instruction or checklist item led to the catch -2. Generalize: Can this pattern apply to other domains? -3. If yes: Propose addition to `common-checklist.md` -4. Record in tuning log as positive reinforcement - -This prevents tuning drift toward pure skepticism; QA must also know what it does well. - ---- - -## Integration Points - -| System | Role | -|--------|------| -| `session-metrics.md` | EA event source (automatic collection) | -| `oma retro` | Aggregation + tuning report generation (semi-automated) | -| `lessons-learned.md` | QA Evaluation Lessons for persistent patterns | -| QA `checklist.md` | Primary patch target for missed checks | -| QA `execution-protocol.md` | Patch target for process/severity issues | -| `common-checklist.md` | Propagation target for generalized good patterns | diff --git a/.agents/skills/_shared/core/session-metrics.md b/.agents/skills/_shared/core/session-metrics.md index 03307af..cf52d17 100644 --- a/.agents/skills/_shared/core/session-metrics.md +++ b/.agents/skills/_shared/core/session-metrics.md @@ -191,14 +191,14 @@ Unlike CD (tracked in real-time), Evaluator Accuracy (EA) is a |-------|--------|-----------------| | `false_negative` | +30 | Next session or production: bug that QA missed | | `false_positive` | +15 | During session: impl agent disputes QA finding successfully | -| `severity_mismatch` | +10 | During session or retro: wrong severity assigned | +| `severity_mismatch` | +10 | During session or next-session review: wrong severity assigned | | `missed_stub` | +20 | During session: runtime verification catches display-only feature | | `good_catch` | -10 | During session: QA caught non-obvious bug (reward signal) | ### Recording - `false_positive`, `missed_stub`, `good_catch`: Recorded during session by Orchestrator -- `false_negative`, `severity_mismatch`: Recorded retroactively via `oma retro` or next session discovery +- `false_negative`, `severity_mismatch`: Recorded retroactively on next-session discovery ### Evaluator Accuracy Score (EA) @@ -210,10 +210,10 @@ EA = sum(accuracy_event_points across last 3 sessions) | Threshold | Action | |-----------|--------| -| EA >= 30 | **TUNING SUGGESTED**: `oma retro` flags QA patterns for review | +| EA >= 30 | **TUNING SUGGESTED**: Review accumulated EA events for recurring QA judgment errors | | EA >= 50 | **TUNING REQUIRED**: Review and update QA execution-protocol.md | | `false_negative` >= 3 across window | **CHECKLIST UPDATE**: Add detection pattern to QA checklist.md | -| `good_catch` >= 5 across window | **PROPAGATE**: Document successful pattern in evaluator-tuning.md | +| `good_catch` >= 5 across window | **PROPAGATE**: Generalize the successful pattern into `common-checklist.md` | ### Accuracy Log Format diff --git a/.agents/skills/_shared/runtime/execution-protocols/opencode.md b/.agents/skills/_shared/runtime/execution-protocols/opencode.md index c366b31..fe8f728 100644 --- a/.agents/skills/_shared/runtime/execution-protocols/opencode.md +++ b/.agents/skills/_shared/runtime/execution-protocols/opencode.md @@ -15,6 +15,25 @@ If Serena MCP is available, use `read_memory`/`write_memory`/`edit_memory` (its base path is `.serena/memories`); otherwise write the same files there directly with opencode's file tools. +### Serena MCP Timeout Recovery (OpenCode Desktop) + +OpenCode Desktop runs one long-lived sidecar server; new sessions reuse its MCP clients, +so a stuck Serena MCP stays stuck until the Desktop app is fully relaunched (the TUI is +rarely affected). When a Serena MCP call times out or the MCP queue is clearly stuck, do +not keep retrying MCP — fall back narrowly: + +1. **Memory ops** — read/write the same files directly under `.serena/memories/` (as + above). If a recent Serena CLI is installed (≥ 1.5, check `serena --version`), + `serena memories read|write|list` is an equivalent alternative; older versions + (e.g. 1.3.x) do not have the `memories` command. +2. **Code analysis** — fall back to native search/read tools. The Serena CLI cannot + execute analysis tools (`serena tools` only lists/describes them). +3. **Diagnostics** — `serena project health-check` and `serena project index` work + without MCP. + +Keep the fallback scoped to the blocked call: this is a recovery path, not a license to +abandon Serena-first. A full Desktop relaunch is what actually resets the stale MCP client. + ### Path Resolution (CRITICAL) All result, progress, and state files MUST be written to the **project root** `.serena/memories/` directory, never to a subdirectory's `.serena/memories/`. diff --git a/.agents/skills/_version.json b/.agents/skills/_version.json index aa5e9a9..3995806 100644 --- a/.agents/skills/_version.json +++ b/.agents/skills/_version.json @@ -1,6 +1,6 @@ { - "version": "10.7.1", + "version": "10.10.0", "schemaVersion": 2, "mode": "project", - "installedAt": "2026-06-28T01:08:28.353Z" + "installedAt": "2026-07-06T12:39:22.805Z" } diff --git a/.agents/skills/oma-design/SKILL.md b/.agents/skills/oma-design/SKILL.md index c37f202..c13a73f 100644 --- a/.agents/skills/oma-design/SKILL.md +++ b/.agents/skills/oma-design/SKILL.md @@ -24,6 +24,7 @@ DESIGN.md is the central artifact; all design work revolves around it. - Creating or auditing `DESIGN.md` - Selecting typography, color, layout, motion, or component direction - Reviewing UI work for responsive behavior, accessibility, and visual quality +- Redesigning an existing site or app (preserve vs overhaul modes) - Using optional vendor inspiration from Stitch MCP or getdesign ### When NOT to use @@ -81,6 +82,7 @@ outputs: ### Transitions - If `.design-context.md` is missing, create it before continuing. +- If the target is an existing site/app, load `resources/redesign-protocol.md` and classify Preserve vs Overhaul before proposing. - If CJK support is needed, prioritize CJK-ready fonts. - If vendor seed fetch fails, choose retry, continue without seed, or abort. - If anti-patterns appear, surface alternatives before finalizing. @@ -151,12 +153,16 @@ bunx getdesign@latest list 8. WCAG AA minimum for all designs. Respect `prefers-reduced-motion`. 9. Stitch MCP is optional; all phases work without it. 10. Present 2-3 design directions and get user confirmation before generating. +11. Declare a one-line Design Read before proposing: "Reading this as: \ for \, with a \ language." If genuinely ambiguous, ask exactly ONE clarifying question — never guess, never a question dump. +12. Redesigns follow `resources/redesign-protocol.md`: detect Preserve vs Overhaul, audit before touching, never silently change URLs, nav labels, form field names, or brand marks. +13. Visual assets follow `resources/asset-strategy.md`: image generation (oma-image) first, picsum seed second, labeled placeholder last. Div-based fake screenshots are banned. +14. Consistency locks: one accent color, one corner-radius system, one theme per page. Lock them early, audit against them in Phase 6 (checklist section 6 mechanical checks). ### Anti-Pattern Quick Reference ### Typography - DON'T: Default to custom Google Fonts when system fonts suffice -- DON'T: Use Inter/Geist alone without considering project context +- DON'T: Reach for Inter as the default custom sans (LLM signature); override only on explicit neutral/Linear-style ask or public-sector/a11y-first brief - DON'T: Load 3+ font families without justification - DON'T: Body text below 16px on mobile - DO: System font stack first, custom fonts for brand identity only @@ -190,9 +196,21 @@ bunx getdesign@latest list ### Components - DON'T: Glassmorphism everywhere; use sparingly - DON'T: Hover-only interactions without touch/keyboard alternatives +- DON'T: Default to lucide-react or hand-rolled SVG icons; pick one family deliberately (Phosphor > HugeIcons > Radix > Tabler; lucide on explicit ask or existing dependency) - DO: shadcn/ui for base, Aceternity UI / React Bits for accent effects - DO: All interactive elements must have visible focus states +### Content & Copy +- DON'T: "John Doe" personas, "Acme/Nexus" brand names, Lorem Ipsum, fake-perfect numbers (99.99%) +- DON'T: Filler verbs ("Elevate", "Seamless", "Unleash") or performative labels ("Quietly trusted by") +- DON'T: Em-dash (`—`) anywhere in visible output — zero tolerance, no "sparingly" allowance; en-dash as separator also banned (hyphen only) +- DO: Copy self-audit before handoff — re-read every visible string, rewrite anything broken or AI-cute +- DO: One label per CTA intent per page + +### Assets +- DON'T: Div-based fake screenshots; text wordmark logo walls; hand-rolled SVG icons +- DO: oma-image generation first → picsum seed → labeled placeholder + report + ### Workflow Summary 7 phases: Setup → Extract → Enhance → Propose → Generate → Audit → Handoff. See `resources/execution-protocol.md` for full detail. @@ -235,12 +253,14 @@ injection defenses, and multi-vendor merge policy live in ### Resources - `resources/execution-protocol.md`: 7-phase workflow - `resources/anti-patterns.md`: Full DO/DON'T catalog -- `resources/checklist.md`: Audit checklist (Responsive + WCAG + Nielsen + Slop) +- `resources/checklist.md`: Audit checklist (Responsive + WCAG + Nielsen + Slop + Mechanical counts) - `resources/design-md-spec.md`: DESIGN.md generation guide (9 sections) - `resources/design-tokens.md`: CSS/Tailwind/shadcn export templates - `resources/prompt-enhancement.md`: Vague request to detailed spec - `resources/stitch-integration.md`: Stitch MCP tool mapping (optional) - `resources/getdesign-fetcher.md`: Vendor seed fetch, hash verify, seed rules +- `resources/redesign-protocol.md`: Preserve/Overhaul modes, audit-first, modernization levers +- `resources/asset-strategy.md`: Image sourcing priority, logo walls, fake-screenshot ban - `resources/error-playbook.md`: Design error recovery ## References diff --git a/.agents/skills/oma-design/resources/anti-patterns.md b/.agents/skills/oma-design/resources/anti-patterns.md index af9f78d..5416931 100644 --- a/.agents/skills/oma-design/resources/anti-patterns.md +++ b/.agents/skills/oma-design/resources/anti-patterns.md @@ -5,7 +5,7 @@ ## Typography - DON'T: Default to custom Google Fonts when system fonts suffice -- DON'T: Use Inter or Geist alone without considering project context +- DON'T: Reach for Inter as the default custom sans. When a custom font is justified (brand identity), pick deliberately from alternatives first (Geist, Outfit, Cabinet Grotesk, Satoshi, or a brand-appropriate face). Inter-by-reflex is the LLM signature. OVERRIDE: Inter is acceptable when the user explicitly asks for a neutral / standard / Linear-style feel, or the brief is public-sector / accessibility-first. CJK rules always win (Pretendard Variable / Noto Sans CJK) - DON'T: Load 3+ font families without clear justification - DON'T: Set body text below 16px on mobile - DON'T: Use light font-weight (300) for body on dark backgrounds without testing contrast @@ -63,6 +63,47 @@ - DO: Use Intersection Observer to trigger animations only when visible - DO: Pause off-screen Canvas/WebGL renderers +## Content & Copy +- DON'T: Generic persona names ("John Doe", "Jane Smith") or slop brand names ("Acme", "Nexus", "SmartFlow", "Cloudly") +- DON'T: Fake-perfect numbers (99.99%, 50%, 1234567); use organic data (47.2%) or label mocks explicitly +- DON'T: Fake-precise specs the brand never claimed (invented "5.8mm", "4.1x" for spec aesthetics) +- DON'T: Filler verbs — "Elevate", "Seamless", "Unleash", "Next-Gen", "Revolutionize", "Game-changer" +- DON'T: Lorem Ipsum; write real draft copy +- DON'T: Poetic/performative section labels ("From the field", "Quietly trusted by", "On our desks"); use plain functional labels ("Testimonials", "Latest writing") or none +- DON'T: Section-number eyebrows ("001 · Capabilities", "06 · how it works") or version labels in the hero (BETA, V0.6) unless the brief is a launch +- DON'T: Scroll cues ("Scroll to explore", animated mouse icons) or decorative locale/time/weather strips +- DON'T: Mix copy registers (technical mono + editorial prose + marketing punch) in one page without brand justification +- DON'T: Quotes longer than 3 lines; attribution is name + role, never name only ("- Sarah") +- DON'T: Em-dash (`—`) ANYWHERE in visible output — the #1 LLM stylistic tell. Zero tolerance: banned in headlines, eyebrows, pills, body copy, quotes, attribution, captions, button text, and alt text. No "sparingly" allowance — the model ignores soft limits. Restructure instead: two sentences, a comma, parentheses, or a colon +- DON'T: En-dash (`–`) as a separator; date ranges (2018-2026) and number ranges use a plain hyphen. The only permitted dashes are the hyphen (`-`) and the math minus sign +- DO: Copy self-audit before handoff — re-read every visible string; rewrite anything grammatically broken, unclear-referent, or AI-cute. Plain functional copy beats clever broken copy +- DO: One label per CTA intent across the page +- DO: Apply register rules per content language (CJK copy follows i18n-guide) + +## Consistency Locks +- DON'T: Introduce a second accent color mid-page (a rose-accented site does not get a teal badge in the footer) +- DON'T: Mix corner-radius systems without a documented rule (round buttons in a square layout is broken design) +- DON'T: Invert theme for a single section mid-page (one light warm-paper section inside a dark page reads as a paste accident) +- DO: Pick accent, radius scale, and theme ONCE per page; lock them; audit every component against the locks before handoff +- DO: If a deliberate full theme switch is a composition device, use it at most once per page with a strong transition + +## Assets & Imagery +- DON'T: Div-based fake screenshots (fake dashboards, task lists, terminal windows built from styled divs) — the #1 AI-design tell +- DON'T: Text-only pages passing as "minimalism"; even restrained pages need 2-3 real images +- DON'T: Plain text wordmarks in "Trusted by" logo walls; use real SVG logos or generated monogram marks +- DON'T: Hand-rolled SVG icons or decorative illustrations by default +- DON'T: Pills/labels overlaid on images, photo-credit captions as decoration, guessed Unsplash URLs +- DO: Source priority: image generation (oma-image) → picsum seed → labeled placeholder slot + tell the user +- DO: See `resources/asset-strategy.md` for full rules + +## Iconography +- DON'T: Default to `lucide-react`. It ships with shadcn/ui, so every AI-generated site carries the same icon set. OVERRIDE: acceptable when the user explicitly asks for it, or the project already depends on it (including shadcn base components — never mix families to escape it) +- DON'T: Hand-roll SVG icon paths. If a glyph is missing, install a second allowed library or compose from primitives +- DON'T: Mix icon families in one component tree (no Phosphor + Lucide together) +- DON'T: Inconsistent stroke widths; standardize strokeWidth globally (e.g. 1.5 or 2.0) +- DO: Pick deliberately, priority order: `@phosphor-icons/react` > `hugeicons-react` > `@radix-ui/react-icons` > `@tabler/icons-react` +- DO: One icon family per project, declared in DESIGN.md + ## Components - DON'T: Glassmorphism on every element; reserve for badges, nav pills, accent cards - DON'T: Icon + Title + Description card grid as the only layout pattern diff --git a/.agents/skills/oma-design/resources/asset-strategy.md b/.agents/skills/oma-design/resources/asset-strategy.md new file mode 100644 index 0000000..bb661ea --- /dev/null +++ b/.agents/skills/oma-design/resources/asset-strategy.md @@ -0,0 +1,63 @@ +# Asset Strategy: Images, Logos, and Visual Material + +Landing pages and portfolios are visual products. A text-only page with +fake-screenshot divs is slop, not minimalism. Even a restrained editorial +page needs at least 2-3 real images (hero, one product/lifestyle shot, +one supporting image). + +## Source Priority (in order) + +1. **Image generation first.** If an image-generation path is available, + use it — in the oma ecosystem, route to the `oma-image` skill + (Codex gpt-image-2 / nano-banana / Pollinations). Generate + section-specific assets at the right aspect ratio: hero photography, + product shots, texture backgrounds, mood images. Do not skip this + because hand-rolled CSS feels faster. +2. **Real web images second.** When no generation tool is available: + - `https://picsum.photos/seed/{descriptive-seed}/{w}/{h}` for + placeholder photography. The seed should describe the section + (e.g. `oma-cookware-kitchen`), not be random. + - Actual stock or brand URLs when the brief provides them. + - Open-license sources (Unsplash direct URL, Pexels) if explicitly allowed. + Never emit guessed/unverified Unsplash URLs — they break. +3. **Last resort: tell the user.** Do NOT fill the page with hand-rolled + SVG illustrations or div-based fake screenshots. Leave clearly labeled + placeholder slots (``) and + report at the end: "This page needs real images at: [placements]." + +## Logo Walls ("Trusted by" / "Used by") + +- Use real SVG logos, never plain text wordmarks styled in a row: + - **Simple Icons**: `https://cdn.simpleicons.org/{slug}/{hex}` or the + `simple-icons` npm package (most known brands) + - **devicon** for tech-stack logos +- Invented brand name → invented mark: generate a simple monogram + (one letter in a circle, two-letter ligature, abstract glyph) as inline + `` matching the page style. +- Logos must render in both light and dark mode (single-color theme + variable, or white-on-dark / black-on-light variants). +- **Logo-only rule**: a logo wall is logos and nothing else. No industry + or category labels under each logo. Brand name goes in alt text. +- The logo wall lives in its own section directly BELOW the hero, + never inside the hero. + +## Product Previews + +Div-based fake screenshots are banned: no fake task lists, fake dashboards, +or fake terminal windows built from styled `
` rectangles. If you need +to show a product: + +- Use a real screenshot URL if one exists +- Generate one via the image tool +- Use a real component preview (an actual mini-version of the UI on the page) +- Or skip the preview and use editorial photography + +A hero of "text + gradient blob" is a placeholder, not a hero. + +## Hand-Rolled SVG + +- Icons: always from a library (see component guidance); never draw icon + paths from scratch. One icon family per project, standardized strokeWidth. +- Decorative illustrations: strongly discouraged as default. Acceptable only + when the brief explicitly asks, the mark is a single simple geometric + shape, and quality is assured. diff --git a/.agents/skills/oma-design/resources/checklist.md b/.agents/skills/oma-design/resources/checklist.md index e53f384..25d9ca4 100644 --- a/.agents/skills/oma-design/resources/checklist.md +++ b/.agents/skills/oma-design/resources/checklist.md @@ -58,3 +58,41 @@ - [ ] Dark/light theme tokens defined if applicable - [ ] CSS custom properties used for all design tokens - [ ] Tailwind config extends theme correctly (no arbitrary values in templates) + +## 6. Mechanical Checks (countable — verify by counting/grep, not judgment) + +These checks are deliberately mechanical so an agent can self-verify them +deterministically. A failed count is a failed audit; fix before handoff. + +### Consistency locks +- [ ] Accent lock: ONE accent color, used identically across all sections (no blue CTA appearing on a warm-grey page in section 7) +- [ ] Radius lock: ONE corner-radius system (all-sharp / all-soft / all-pill), or a documented mixed rule applied everywhere +- [ ] Theme lock: ONE theme (light, dark, or auto) for the whole page; no single section inverting mid-scroll + +### Layout counts +- [ ] Eyebrow count: micro-labels (uppercase + letter-spacing above section headlines) <= ceil(sectionCount / 3); hero counts as one +- [ ] Layout-family repetition: no layout family (3-col cards, image+text split, full-width quote, bento...) used for more than one section; a page of 8 sections uses >= 4 distinct families +- [ ] Zigzag cap: max 2 consecutive image+text split sections; the 3rd consecutive one fails +- [ ] Marquee: max 1 horizontal marquee per page +- [ ] Bento cell count: N items → exactly N cells; no empty filler tiles +- [ ] Long lists (> 5 items): grouped chunks / card grid / tabs / carousel — not a default `
    ` with a hairline under every row + +### Hero discipline +- [ ] Hero fits the initial viewport: headline <= 2 lines desktop, subtext <= 20 words, primary CTA visible without scroll +- [ ] Hero stack: max 4 text elements (eyebrow OR brand strip, headline, subtext, CTAs); no trust micro-strip / pricing teaser / tagline-under-CTAs inside the hero +- [ ] Logo wall lives in its own section BELOW the hero, never inside it + +### CTA and copy counts +- [ ] ZERO em-dashes: `grep -rn '—' ` returns nothing in visible strings; en-dash (`–`) not used as a separator either (hyphen only) +- [ ] No CTA label wraps to 2+ lines at desktop (primary CTA <= 3 words) +- [ ] One label per CTA intent: no "Get in touch" + "Let's talk" (same contact intent) coexisting on one page; same for signup and portfolio intents +- [ ] Every CTA/button text passes WCAG AA contrast against its own background (no white-on-white, no ghost button vanishing over photos) + +### Navigation +- [ ] Nav renders on a single line at desktop (condense labels or use hamburger if not) +- [ ] Nav height <= 80px desktop + +### Typography & icons +- [ ] Inter used only with an explicit justification (user asked for neutral/Linear-style, or public-sector/a11y-first brief) — never by reflex +- [ ] ONE icon family per project: grep icon imports; all come from a single library, consistent strokeWidth +- [ ] lucide-react present only if explicitly requested or already a project dependency diff --git a/.agents/skills/oma-design/resources/execution-protocol.md b/.agents/skills/oma-design/resources/execution-protocol.md index cdf3682..a1c70a8 100644 --- a/.agents/skills/oma-design/resources/execution-protocol.md +++ b/.agents/skills/oma-design/resources/execution-protocol.md @@ -21,6 +21,15 @@ If it does not exist: **MUST complete before proceeding. Never skip context gathering.** +### Redesign Mode Detection +If the target is an existing site or app (not greenfield), load +`resources/redesign-protocol.md` FIRST and classify the mode: +Greenfield / Redesign-Preserve / Redesign-Overhaul. If ambiguous, ask +once: "Preserve the existing brand, or start visually from scratch?" +For Preserve mode, run the redesign audit (brand tokens, IA, SEO +baseline, patterns to preserve/retire) and record it in +`.design-context.md` before any proposal. + ### Vendor Inspiration Detection After `.design-context.md` exists (either newly created or already present): 1. Parse the `## Reference Sites` section (if any) and extract bare @@ -106,6 +115,17 @@ If the request is already detailed: skip to Phase 4. ## Phase 4: PROPOSE (Multi-Concept) +### Design Read (declare before proposing) +Open Phase 4 with a one-line Design Read so the direction is inferred +from the brief, not from a default aesthetic: + +> "Reading this as: \ for \, with a \ +> language, leaning toward \." + +If the read genuinely diverges into two directions, ask exactly ONE +clarifying question (e.g. "closer to Linear-clean or Awwwards- +experimental?"). If it can be inferred, declare it and proceed. + ### Default: No vendor seed Present 2-3 distinct design directions. Each direction must include: @@ -115,6 +135,11 @@ Present 2-3 distinct design directions. Each direction must include: 4. **Motion strategy**: scroll-driven / hover-based / entrance-only / minimal 5. **Component recommendations**: which libraries (shadcn base + Aceternity / React Bits accents) 6. **Visual mood**: one-sentence description of the feel +7. **Posture axes**: state each direction's position in plain words on + three axes — layout variance (symmetric ↔ asymmetric), motion + (static ↔ cinematic), density (airy ↔ packed). Trust-first / + public-sector / accessibility-critical briefs pull all three toward + the conservative end and OVERRIDE aesthetic preference. Present as a comparison table with pros/cons for each direction. @@ -164,6 +189,10 @@ Based on the chosen direction: - Tailwind config extensions (`theme.extend.colors`) - shadcn/ui theme variables (if shadcn is in use) 4. Generate component code if requested by the user +5. For any page or component that needs imagery, logos, or product + previews, follow `resources/asset-strategy.md` (generation via + oma-image first → picsum seed → labeled placeholder + report). + Div-based fake screenshots are banned. ### Responsive-First Rule ALL generated designs MUST be responsive by default. Never produce desktop-only layouts. @@ -220,6 +249,15 @@ Load `resources/checklist.md` and run all checks in order: - All spacing from 8px grid scale - Typography uses defined scale +6. **Mechanical Checks** (checklist.md section 6 — countable, not judgment) + - Consistency locks: one accent, one radius system, one theme per page + - Layout counts: eyebrow <= ceil(sections/3), no repeated layout + family, zigzag cap 2, marquee max 1, bento N items → N cells + - Hero discipline: fits viewport, max 4 text elements, logo wall below + - CTA: no label wrap, one label per intent, AA contrast on every button + - Copy self-audit: re-read every visible string (anti-patterns.md + "Content & Copy") + Fix violations automatically where possible, or report to user with recommendations. --- diff --git a/.agents/skills/oma-design/resources/redesign-protocol.md b/.agents/skills/oma-design/resources/redesign-protocol.md new file mode 100644 index 0000000..6cb3842 --- /dev/null +++ b/.agents/skills/oma-design/resources/redesign-protocol.md @@ -0,0 +1,82 @@ +# Redesign Protocol + +Applies whenever the target is an EXISTING site or app, not a greenfield build. +Misclassifying the mode is the biggest source of bad redesign output. + +## 1. Detect the Mode (first action) + +| Mode | Meaning | Treatment | +|------|---------|-----------| +| Greenfield | No existing site, or full overhaul approved | Normal 7-phase flow | +| Redesign - Preserve | Modernize without breaking the brand | Audit first, extract brand tokens, evolve gradually | +| Redesign - Overhaul | New visual language on existing content | Greenfield for visuals; preserve content and IA | + +If ambiguous, ask ONCE: "Should this redesign preserve the existing brand, +or are we starting visually from scratch?" Never a multi-question dump. + +## 2. Audit Before Touching + +Document the current state before proposing any change: + +- **Brand tokens**: primary/accent colors, type stack, logo treatment, radii +- **Information architecture**: page tree, primary nav, key conversion paths +- **Content blocks**: what exists, what's doing work, what's filler +- **Patterns to preserve**: signature interactions, recognizable hero, copy voice +- **Patterns to retire**: AI-slop tells, broken layouts, dead links, generic stock imagery, perf traps +- **SEO baseline**: ranking pages, meta titles, structured data, OG cards. + SEO migration is the #1 redesign risk. + +Record the audit in `.design-context.md` (a `## Redesign Audit` section) +so later phases and subagents can see it. + +## 3. Preservation Rules (Preserve mode) + +1. Do not change information architecture unless asked. Keep page slugs, + anchor IDs, and primary nav labels stable (SEO + muscle memory). +2. Extract brand colors BEFORE applying anti-pattern rules. A brand that is + already purple stays purple — execute it with intent instead of banning it. +3. Preserve copy voice unless asked for a rewrite. Visual modernization + is not a content rewrite. +4. Honor existing accessibility wins. Never regress focus states, alt text, + keyboard nav, or contrast. +5. Respect existing analytics events. Do not rename buttons, form fields, + or section IDs that downstream tracking depends on. + +## 4. Modernization Levers (priority order) + +Apply in order; stop when the brief is satisfied. Earlier levers give the +biggest visual lift per unit of risk: + +1. **Typography refresh** — biggest instant improvement, lowest risk + (CJK rules from SKILL.md still win: Pretendard Variable / Noto Sans CJK) +2. **Spacing & rhythm** — section padding, vertical rhythm, 8px grid +3. **Color recalibration** — desaturate, unify neutrals, keep brand accent +4. **Motion layer** — add restrained micro-interactions to existing components +5. **Hero & key-section recomposition** — restructure top-of-funnel +6. **Full block replacement** — only when the existing block is unsalvageable + +## 5. Decision Tree + +- IA, content, and SEO sound → **targeted evolution** (levers 1-4). + ~70% of the value at ~40% of the risk. +- Visual debt is structural (broken IA, no design system, broken mobile) + → **full redesign** with strict content preservation. +- Brand itself is changing → treat as **greenfield**. + +## 6. What Never Changes Silently + +Never modify without explicit user approval: + +- URL structure / route slugs +- Primary nav labels +- Form field names or order (breaks analytics + autofill) +- Brand logo or wordmark +- Existing legal / consent / cookie copy + +## 7. Implementation Rules + +- Work with the existing tech stack. Do not migrate frameworks or styling + libraries as part of a redesign. +- Before recommending any new library, check the project's dependency file. +- Keep changes reviewable and focused: small targeted improvements over + big rewrites. Frontend implementation itself is delegated to `oma-frontend`. diff --git a/.agents/skills/oma-frontend/SKILL.md b/.agents/skills/oma-frontend/SKILL.md index 6a04764..6250f77 100644 --- a/.agents/skills/oma-frontend/SKILL.md +++ b/.agents/skills/oma-frontend/SKILL.md @@ -1,6 +1,6 @@ --- name: oma-frontend -description: Frontend specialist for React, Next.js, TypeScript with FSD-lite architecture, shadcn/ui, and design system alignment. Use for UI, component, page, layout, CSS, Tailwind, and shadcn work. +description: Frontend specialist for React, Next.js, Angular, TypeScript with FSD-lite architecture, shadcn/ui, and design system alignment. Use for UI, component, page, layout, CSS, Tailwind, shadcn, Angular, and RxJS work. --- # Frontend Agent - UI/UX Specialist @@ -8,11 +8,12 @@ description: Frontend specialist for React, Next.js, TypeScript with FSD-lite ar ## Scheduling ### Goal -Build, modify, and verify React/Next.js/TypeScript user interfaces that follow project architecture, design-system constraints, accessibility expectations, and existing frontend conventions. +Build, modify, and verify React/Next.js or Angular TypeScript user interfaces that follow project architecture, design-system constraints, accessibility expectations, and existing frontend conventions. ### Intent signature - User asks for UI, component, page, layout, CSS, Tailwind, shadcn, form, interaction, client state, or frontend API integration work. -- User needs browser-facing implementation in a React/Next.js TypeScript codebase. +- User needs browser-facing implementation in a React/Next.js or Angular TypeScript codebase. +- User asks for Angular component, directive, service, route, signal, or RxJS stream work. ### When to use - Building user interfaces and components @@ -38,7 +39,7 @@ Build, modify, and verify React/Next.js/TypeScript user interfaces that follow p - Verification results from relevant lint, typecheck, tests, or browser checks ### Dependencies -- React, Next.js, TypeScript, TailwindCSS v4, and `shadcn/ui` +- React, Next.js, TypeScript, TailwindCSS v4, and `shadcn/ui` — or Angular + signals + RxJS in Angular projects (`resources/angular-rules.md`) - Project sources of truth such as `packages/design-tokens`, `packages/i18n`, and shared utilities - `resources/execution-protocol.md`, `resources/checklist.md`, examples, snippets, and Tailwind rules @@ -92,6 +93,7 @@ Build, modify, and verify React/Next.js/TypeScript user interfaces that follow p ### Tools and instruments - React, Next.js, TypeScript, TailwindCSS v4, shadcn/ui - `ahooks`, `es-toolkit`, `nuqs`, TanStack Query, Jotai/Zustand, TanStack React Form, `zod` +- Angular (standalone + signals), RxJS + `rxjs/testing` (`TestScheduler` marble tests) in Angular projects - Lint, typecheck, tests, and browser inspection when applicable ### Canonical workflow path @@ -127,9 +129,12 @@ Then run the project's frontend verification commands, typically lint, typecheck 5. Run the execution checklist before handoff and include relevant verification results. 6. **Self-describing file names**: every new file follows the File Naming convention in `../../rules/frontend.md` §Naming Conventions — domain + role readable from the basename alone (`order-summary-card.tsx`, `use-order-polling.ts`, `cart.atoms.ts`). Grab-bag names (`utils.ts`, `helpers.ts`, `misc.ts`) and version suffixes (`*-v2`, `*-final`) are banned. 7. **Next.js 16 `proxy.ts` is mandatory; `middleware.ts` is BANNED**: this project is Next.js 16+. `middleware.ts` is NOT "deprecated"; it is forbidden, touch it and you die. The canonical request-proxy / auth-gate file is `proxy.ts` (root or `src/`) exporting a `proxy` function. NEVER create, recommend, suggest, or "restore" `middleware.ts`. NEVER flag `proxy.ts` as dead code, unused, or not-wired. Any such finding is a fatal self-error: retract it immediately and write `proxy.ts`. +8. **Angular projects follow `resources/angular-rules.md`**: standalone components + `OnPush` + signals-first, `inject()` DI, lazy routes, new control flow. **Any non-trivial RxJS pipeline MUST ship with a marble test (`TestScheduler` from `rxjs/testing`)** — a stream without a marble test fails review. React/Next.js-specific rules (shadcn workflow, `proxy.ts`, Libraries table below) do not apply in Angular projects. ### Libraries +React/Next.js projects only — Angular projects use the Angular-native equivalents in `resources/angular-rules.md` (signals, typed Reactive Forms, `HttpClient`/`httpResource`, RxJS with mandatory marble tests). + | Category | Library | |----------|---------| | Framework | `next@16+` (App Router) + `react@19+`; `next < 16` is BANNED | @@ -187,6 +192,7 @@ Project stack conventions live in dedicated files. **Read these before coding**; | `resources/tech-stack.md` | Framework versions, Next.js 16 `proxy.ts` conventions, Serena shortcuts | | `resources/tailwind-rules.md` | Design tokens, focus states, Tailwind v4 `@theme` syntax | | `resources/snippets.md` | React 19 hook patterns, TanStack Query/Form, a11y card | +| `resources/angular-rules.md` | Angular standalone/OnPush/signals conventions, RxJS marble-test policy (MANDATORY for streams) | To extend: add `resources/.md` and append a row above. diff --git a/.agents/skills/oma-frontend/resources/angular-rules.md b/.agents/skills/oma-frontend/resources/angular-rules.md new file mode 100644 index 0000000..8b8aba3 --- /dev/null +++ b/.agents/skills/oma-frontend/resources/angular-rules.md @@ -0,0 +1,110 @@ +# Frontend Agent - Angular Rules + +Applies when the target project is Angular (`angular.json` present, or `@angular/core` in +`package.json`). In Angular projects these rules **replace** the React/Next.js-specific +sections of this skill (shadcn workflow, Server/Client component split, Next.js libraries). +Cross-cutting rules still apply: accessibility, design tokens, i18n sources of truth, +self-describing file names, and verification before handoff. + +## Core Conventions + +1. **Standalone components only** — no new `NgModule`s. Existing NgModule code may stay; + migrate opportunistically, never big-bang. +2. **`ChangeDetectionStrategy.OnPush` on every component.** Prefer zoneless + (`provideZonelessChangeDetection`) when the project already opts in. +3. **Signals first**: `signal`, `computed`, `effect`, signal inputs `input()`, `model()`, + and `output()` are the default state primitives. Reach for RxJS only for genuine + event streams (see RxJS policy below). +4. **`inject()` over constructor injection** in new code. +5. **New template control flow** — `@if` / `@for` / `@switch` / `@defer`. Do not write + `*ngIf` / `*ngFor` in new templates. +6. **Lazy routes**: `loadComponent` / `loadChildren`; colocate feature route configs with + the feature. +7. **Typed Reactive Forms** for anything beyond a single input; validation schemas live + next to the form. +8. **Angular CLI for scaffolding** (`ng generate`); respect the project's generator + defaults and file-naming style. For naming, follow the project's existing convention; + new projects follow the current Angular style guide (kebab-case basenames). +9. **UI library**: use the project's detected library (Spartan UI, Angular Material, + PrimeNG, …) before hand-rolling components. Tailwind CSS follows + `resources/tailwind-rules.md` where applicable. +10. **Data access**: `HttpClient` (or `httpResource`) lives in injectable services, never + inline in components. + +## RxJS Policy — Marble Tests Are MANDATORY + +Signals cover most component state. RxJS is the right tool for **streams over time**: +debounced input, cancellation (`switchMap`), merging event sources, websockets, polling. + +Interop happens at boundaries only: `toSignal` / `toObservable` from +`@angular/core/rxjs-interop`. Do not hand-subscribe in components when `toSignal` or the +`async` pipe can own the subscription. + +**Non-negotiable: every non-trivial Observable pipeline ships with a marble test.** +A stream without a marble test fails review. + +"Non-trivial" means the pipeline contains any of: + +- time-based operators: `debounceTime`, `throttleTime`, `auditTime`, `delay`, `timer`-driven logic +- combination operators: `combineLatest`, `withLatestFrom`, `merge`, `zip`, `race` +- higher-order mapping: `switchMap`, `mergeMap`, `concatMap`, `exhaustMap` +- error/retry flow: `retry`, `retryWhen`, `catchError` with re-subscription +- any custom operator + +A single synchronous `map`/`filter` on an `HttpClient` call may use a standard async test +instead — everything else gets marbles. + +### Marble test skeleton (`TestScheduler`, runner-agnostic) + +```ts +import { TestScheduler } from 'rxjs/testing'; +import { debounceTime } from 'rxjs'; + +describe('search query stream', () => { + let scheduler: TestScheduler; + + beforeEach(() => { + scheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); // wire to the runner's deep-equal + }); + }); + + it('emits only the last value inside the debounce window', () => { + scheduler.run(({ cold, expectObservable }) => { + const source$ = cold('a 50ms b 199ms c|', { a: 'n', b: 'ng', c: 'ngx' }); + const result$ = source$.pipe(debounceTime(100)); + expectObservable(result$).toBe('151ms b 100ms (c|)', { b: 'ng', c: 'ngx' }); + }); + }); +}); +``` + +Rules for marble tests: + +1. **Always use `scheduler.run()`** — it virtualizes time, so `debounceTime(300)` needs no + real waiting and no scheduler injection into production code. +2. **Test timing, not just values**: the marble diagram must assert *when* emissions + happen, including completion/error frames. +3. **Cover cancellation** for higher-order mappings (`switchMap` dropping the stale inner + observable is exactly the behavior marbles exist to prove) — use `expectSubscriptions` + for inner-subscription lifetimes when relevant. +4. `TestScheduler` is runner-agnostic — it works under Vitest, Jest, and Jasmine/Karma; + only the `assertDeepEqual` wiring differs. + +## Verification + +Before handoff, run the project's Angular checks (typical set): + +```bash +{pm} run lint # or: ng lint +bunx tsc --noEmit -p tsconfig.app.json +{test_cmd} # e.g. bunx vitest run, ng test --watch=false +``` + +Checklist deltas vs the React checklist: + +- [ ] New components are standalone + OnPush +- [ ] No new `*ngIf` / `*ngFor` / `NgModule` +- [ ] Component state is signal-based unless a stream is genuinely needed +- [ ] Every non-trivial RxJS pipeline has a passing marble test +- [ ] Routes added lazily (`loadComponent` / `loadChildren`) diff --git a/.agents/workflows/stack-set.md b/.agents/workflows/stack-set.md index 34c808d..a7ddc17 100644 --- a/.agents/workflows/stack-set.md +++ b/.agents/workflows/stack-set.md @@ -15,7 +15,7 @@ Analyze project files to detect the tech stack, resolve the target domain skill, ## Step 1: Detect -Scan the project root for package manifests. Evaluate **both** tables independently — do not stop at the first match. +Scan the project root for package manifests. Evaluate **all three** tables independently — do not stop at the first match. ### Backend manifests → domain `backend` @@ -36,6 +36,24 @@ Read manifest contents to detect framework: - Rust: Axum? Actix-web? Rocket? - Java: Spring Boot? Quarkus? +**Frontend exclusion (amendment F):** `package.json` + `tsconfig.json` count as a backend (Node.js/TypeScript) signal only when no frontend signal from the table below claims them. In an Angular-only repo, `package.json` and `tsconfig.json` do NOT create a backend domain. A backend domain still counts when a non-Node backend manifest exists (e.g. `pyproject.toml`) or a separate package carries backend framework dependencies (NestJS, Express, Hono, …) in a monorepo. + +### Frontend manifests → domain `frontend` + +| File | Detection | +|:---|:---| +| `angular.json` | Angular | +| `package.json` with `@angular/core`, `@angular/cli`, or `@angular/build` | Angular | +| `tsconfig.app.json`, `tsconfig.spec.json` | Angular (supporting signal only — never sufficient alone) | + +Read manifest contents to detect the rest of the stack: +- Angular version from `@angular/core` +- Package manager from the lockfile (`bun.lock` → bun, `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `package-lock.json` → npm) +- UI library: `@spartan-ng/*` (Spartan UI)? `@angular/material`? PrimeNG? none +- Styling: Tailwind CSS? SCSS? (`components.json` is a Spartan/shadcn-style marker) +- Test runner: Vitest? Jest? Jasmine/Karma? +- RxJS: is `rxjs` used beyond Angular internals (streams in services/components)? + ### Mobile manifests → domain `mobile` | File | Detection | @@ -50,15 +68,16 @@ For Swift / iOS native, additionally inspect the project to detect the UI framew ### Resolve `target_skill` -After scanning both tables, record every domain that has at least one detected manifest file: +After scanning all tables, record every domain that has at least one detected manifest file: | Detected domain | `target_skill` | |:---|:---| | backend only | `oma-backend` | +| frontend only | `angular-developer` if `.agents/skills/angular-developer/` is installed, otherwise `oma-frontend` | | mobile only | `oma-mobile` | -| both (monorepo) | carry **both** into Step 2 — do NOT first-match | +| two or more (monorepo) | carry **all** into Step 2 — do NOT first-match | -**Multi-domain rule (amendment B):** If manifests from both backend and mobile tables are found, collect both domains as the detected set and proceed to Step 2. Do not silently discard either. +**Multi-domain rule (amendment B):** If manifests from two or more tables are found, collect all detected domains as the detected set and proceed to Step 2. Do not silently discard any. --- @@ -79,6 +98,21 @@ Detected backend stack: Correct? (Y/n) or modify: ``` +### Single-domain: frontend (Angular) + +Present detection results and ask for confirmation: +``` +Detected frontend stack: + Framework: Angular {version} + Package manager: {pm} + UI: {ui_library} (e.g. Spartan UI, Angular Material, none) + Styling: {styling} (e.g. Tailwind CSS v4, SCSS) + Async/State: {async} (signals-only, or signals + rxjs) + Test: {test_runner} (e.g. Vitest, Jest, Jasmine/Karma) + +Correct? (Y/n) or modify: +``` + ### Single-domain: mobile (Swift) Present detection results and ask for confirmation: @@ -102,12 +136,15 @@ When more than one domain was detected in Step 1, **before** showing any per-dom ``` Multiple domains detected in this repo: - [backend] {backend_language} / {backend_framework} - [mobile] {mobile_language} / {mobile_ui} + [backend] {backend_language} / {backend_framework} + [frontend] Angular {angular_version} / {ui_library} + [mobile] {mobile_language} / {mobile_ui} -Generate stack references for: [both / backend / mobile] +Generate stack references for: [all / backend / frontend / mobile] ``` +(List only the domains actually detected.) + After the user selects, show the per-domain confirmation block(s) for the chosen domain(s) and confirm each before generating. --- @@ -117,6 +154,7 @@ After the user selects, show the per-domain confirmation block(s) for the chosen Write generated files into `.agents/skills/{target_skill}/stack/`. - Backend → `.agents/skills/oma-backend/stack/` +- Frontend → `.agents/skills/{frontend_target_skill}/stack/` (`angular-developer` or `oma-frontend`, per Step 1) - Mobile → `.agents/skills/oma-mobile/stack/` - Multi-domain → run the appropriate generation sub-path for each selected domain in turn. @@ -169,6 +207,63 @@ Generate CRUD endpoint boilerplate in the detected language. --- +### Frontend path — Angular + +#### stack.yaml +```yaml +language: typescript +framework: angular +framework_version: "{angular_version}" # e.g. "22.0.0" from @angular/core +package_manager: {pm} # bun | pnpm | yarn | npm, from lockfile +ui: {ui_library} # e.g. spartan-ui, angular-material, none +styling: {styling} # e.g. tailwindcss-v4, scss +state: signals +async: {async} # signals-only | rxjs +test: {test_runner} # e.g. vitest, jest, jasmine-karma +source: detected +detected_from: + - angular.json + - package.json +verify: # consumed by `oma verify frontend` (see _shared/core/stack-verify.schema.json) + detect: angular.json + syntax: + cmd: "{syntax_check_cmd}" # e.g. bunx tsc --noEmit -p tsconfig.app.json + tests: + cmd: "{test_cmd}" # e.g. bunx vitest run, or ng test --watch=false + skip_if_missing: "{optional_binary}" +``` + +#### tech-stack.md +Generate an Angular-specific tech stack reference with these MANDATORY sections: +- Angular version and CLI workflow (`ng generate`, `ng build`, `ng serve`, detected build system) +- Standalone components (no NgModules in new code) +- Change detection: `ChangeDetectionStrategy.OnPush` default; zoneless setup if detected +- Signals as the default state primitive (`signal`, `computed`, `effect`, `input()`, `model()`) +- Lazy routes (`loadComponent` / `loadChildren`) +- UI library + styling integration (detected values) +- Test runner and how to run it +- **RxJS policy: signals first; every non-trivial Observable pipeline MUST ship with a marble test (`TestScheduler` from `rxjs/testing`)** — omit this section only when `async: signals-only` + +#### snippets.md +Generate copy-paste code patterns. MANDATORY patterns (all 8 required): +- [ ] Standalone component with `ChangeDetectionStrategy.OnPush` + signals + new control flow (`@if` / `@for`) +- [ ] `inject()`-based service + provider example +- [ ] Lazy route config (`loadComponent` / `loadChildren`) +- [ ] Typed Reactive Form + validation example +- [ ] HttpClient data-access service (or `httpResource`) example +- [ ] Signal ↔ RxJS interop (`toSignal` / `toObservable`) +- [ ] RxJS stream **with paired marble test** (`TestScheduler.run`) — when `rxjs` is in the detected stack; otherwise a signals-based async pattern +- [ ] Component test in the detected runner + +#### component-template.ts +Generate a standalone CRUD feature (component + data service) in the detected style. The template must: +- Use standalone components with `ChangeDetectionStrategy.OnPush` and signals for state. +- Be lazy-routable (`loadComponent`) and use `inject()` for DI. +- Use the detected UI library and styling conventions. +- If the data service exposes RxJS streams, include a paired `*.spec.ts` marble test using `TestScheduler`. + +--- + ### Mobile path — Swift / iOS native **Adapt, not copy (amendment E):** Seed from `.agents/skills/oma-mobile/variants/swift-ios/` as the baseline, then adapt every value to match the detected project. Specifically: @@ -242,6 +337,14 @@ Confirm generated files meet requirements. - [ ] `api-template` file uses the correct language extension - [ ] Code follows existing project conventions +### Frontend (Angular) checks +- [ ] `stack.yaml` has `language`, `framework`, `framework_version`, `package_manager`, `ui`, `styling`, `test` fields +- [ ] `stack.yaml` has a `verify:` block with runnable `syntax.cmd` and `tests.cmd` +- [ ] `snippets.md` contains all 8 mandatory Angular patterns +- [ ] Generated references mention standalone components, OnPush, signals, lazy routes, and the Angular CLI +- [ ] If `rxjs` is in the detected stack: `snippets.md` includes a runnable marble test (`TestScheduler`) and `tech-stack.md` states that marble tests are mandatory for stream logic +- [ ] An Angular-only repo did NOT also generate `.agents/skills/oma-backend/stack/` + ### Mobile (Swift) checks - [ ] `stack.yaml` has `language`, `api_generator`, `api_spec`, and `structure` fields populated with project-specific values (not variant defaults) - [ ] `stack.yaml` has a `verify:` block with runnable `syntax.cmd` and `tests.cmd` (otherwise `oma verify mobile` cannot dispatch) @@ -258,4 +361,4 @@ Confirm generated files meet requirements. - Do NOT modify `resources/` common files under any skill - Only create or modify files in the resolved skill's `stack/` directory - If `stack/` already exists for the resolved domain skill, ask before overwriting -- `target_skill` is always the resolved domain skill (`oma-backend` or `oma-mobile`); never hardcode a single skill name in generation logic +- `target_skill` is always the resolved domain skill (`oma-backend`, `oma-mobile`, or the resolved frontend skill — `angular-developer` / `oma-frontend`); never hardcode a single skill name in generation logic diff --git a/.claude/hooks/oma-hook.sh b/.claude/hooks/oma-hook.sh index 50bcbff..8c86839 100755 --- a/.claude/hooks/oma-hook.sh +++ b/.claude/hooks/oma-hook.sh @@ -11,8 +11,8 @@ if [ -f "$__oma_dedup_lock" ]; then fi echo "$$" > "$__oma_dedup_lock" __oma_bin="" -if [ -x "/Users/gracefullight/.bun/bin/oma" ]; then - __oma_bin="/Users/gracefullight/.bun/bin/oma" +if [ -x "/home/runner/.bun/bin/oma" ]; then + __oma_bin="/home/runner/.bun/bin/oma" elif command -v oma >/dev/null 2>&1; then __oma_bin="$(command -v oma)" fi diff --git a/.codex/hooks/oma-hook.sh b/.codex/hooks/oma-hook.sh index 50bcbff..8c86839 100755 --- a/.codex/hooks/oma-hook.sh +++ b/.codex/hooks/oma-hook.sh @@ -11,8 +11,8 @@ if [ -f "$__oma_dedup_lock" ]; then fi echo "$$" > "$__oma_dedup_lock" __oma_bin="" -if [ -x "/Users/gracefullight/.bun/bin/oma" ]; then - __oma_bin="/Users/gracefullight/.bun/bin/oma" +if [ -x "/home/runner/.bun/bin/oma" ]; then + __oma_bin="/home/runner/.bun/bin/oma" elif command -v oma >/dev/null 2>&1; then __oma_bin="$(command -v oma)" fi diff --git a/.cursor/hooks/oma-hook.sh b/.cursor/hooks/oma-hook.sh index 50bcbff..8c86839 100755 --- a/.cursor/hooks/oma-hook.sh +++ b/.cursor/hooks/oma-hook.sh @@ -11,8 +11,8 @@ if [ -f "$__oma_dedup_lock" ]; then fi echo "$$" > "$__oma_dedup_lock" __oma_bin="" -if [ -x "/Users/gracefullight/.bun/bin/oma" ]; then - __oma_bin="/Users/gracefullight/.bun/bin/oma" +if [ -x "/home/runner/.bun/bin/oma" ]; then + __oma_bin="/home/runner/.bun/bin/oma" elif command -v oma >/dev/null 2>&1; then __oma_bin="$(command -v oma)" fi diff --git a/.cursor/rules/test-guide.mdc b/.cursor/rules/test-guide.mdc index 68ca01f..c99d52e 100644 --- a/.cursor/rules/test-guide.mdc +++ b/.cursor/rules/test-guide.mdc @@ -49,7 +49,7 @@ cd apps/api && uv run ptw cd apps/web && bun test:coverage # API -cd apps/api && uv run poe test-cov +cd apps/api && uv run poe test:cov # Flutter cd apps/mobile && flutter test --coverage diff --git a/.opencode/plugins/oma/serena-primer.ts b/.opencode/plugins/oma/serena-primer.ts index dc3a7bb..6605ac2 100644 --- a/.opencode/plugins/oma/serena-primer.ts +++ b/.opencode/plugins/oma/serena-primer.ts @@ -116,6 +116,7 @@ export function primerContext(): string { "- Code discovery / reading: `get_symbols_overview`, `find_symbol`, `find_referencing_symbols`, `search_for_pattern`.", "- Code edits: `replace_symbol_body`, `insert_after_symbol`, `insert_before_symbol`, `replace_content`.", "- Native grep/glob: only for initial filename/path discovery. Do not fall back to grep + Read for code navigation just because Serena's tools aren't loaded yet — load them.", + "- Exception — MCP timeout: if a Serena MCP call times out or hangs (seen mainly in OpenCode Desktop's long-lived sidecar), stop retrying MCP for this session: use native search/read for code, and access `.serena/memories/` files directly (or `serena memories read|write` when Serena CLI ≥ 1.5 is installed) for memory work. A full app relaunch restores Serena MCP.", ].join("\n"); } diff --git a/.opencode/plugins/oma/triggers.json b/.opencode/plugins/oma/triggers.json index 32c9b53..73c6a59 100644 --- a/.opencode/plugins/oma/triggers.json +++ b/.opencode/plugins/oma/triggers.json @@ -2067,7 +2067,8 @@ "react", "tailwind", "tsx", - "frontend" + "frontend", + "angular" ], "en": [ "make a react component", @@ -2086,7 +2087,8 @@ "넥스트 페이지", "tailwind로 스타일", "shadcn 붙여줘", - "프론트 구현" + "프론트 구현", + "앵귤러" ], "ja": [ "reactコンポーネント", diff --git a/.qwen/hooks/oma-hook.sh b/.qwen/hooks/oma-hook.sh index 50bcbff..8c86839 100755 --- a/.qwen/hooks/oma-hook.sh +++ b/.qwen/hooks/oma-hook.sh @@ -11,8 +11,8 @@ if [ -f "$__oma_dedup_lock" ]; then fi echo "$$" > "$__oma_dedup_lock" __oma_bin="" -if [ -x "/Users/gracefullight/.bun/bin/oma" ]; then - __oma_bin="/Users/gracefullight/.bun/bin/oma" +if [ -x "/home/runner/.bun/bin/oma" ]; then + __oma_bin="/home/runner/.bun/bin/oma" elif command -v oma >/dev/null 2>&1; then __oma_bin="$(command -v oma)" fi