opencode-agent-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +796 -0
- package/bin/commands/init.mjs +221 -0
- package/bin/init.mjs +21 -0
- package/package.json +22 -0
- package/template/.opencode/agent-docs/backend/README.md +0 -0
- package/template/.opencode/agent-docs/backend/node/BACKEND_PATTERNS.md +82 -0
- package/template/.opencode/agent-docs/backend/node/BACKEND_QUICK_START.md +49 -0
- package/template/.opencode/agent-docs/frontend/next/README.md +0 -0
- package/template/.opencode/agent-docs/frontend/nuxt/API_PATTERNS.md +807 -0
- package/template/.opencode/agent-docs/frontend/nuxt/CHEATSHEET.md +676 -0
- package/template/.opencode/agent-docs/frontend/nuxt/COMPLETION_REPORT.md +613 -0
- package/template/.opencode/agent-docs/frontend/nuxt/EXAMPLES.md +956 -0
- package/template/.opencode/agent-docs/frontend/nuxt/INDEX.md +596 -0
- package/template/.opencode/agent-docs/frontend/nuxt/MCP_GUIDE.md +881 -0
- package/template/.opencode/agent-docs/frontend/nuxt/MENTOR_CURRICULUM_30_DAYS.md +256 -0
- package/template/.opencode/agent-docs/frontend/nuxt/MENTOR_CURRICULUM_CHECKLIST.md +156 -0
- package/template/.opencode/agent-docs/frontend/nuxt/MENTOR_WEEKLY_ASSIGNMENTS.md +191 -0
- package/template/.opencode/agent-docs/frontend/nuxt/QUICK_START.md +509 -0
- package/template/.opencode/agent-docs/frontend/nuxt/README.md +506 -0
- package/template/.opencode/agent-docs/frontend/nuxt/README_AGENTS.md +140 -0
- package/template/.opencode/agent-docs/frontend/nuxt/README_DOCS.md +65 -0
- package/template/.opencode/agent-docs/frontend/nuxt/SUMMARY.md +474 -0
- package/template/.opencode/agent-docs/frontend/nuxt/TEAM_OPERATING_GUIDE.md +54 -0
- package/template/.opencode/agent-docs/frontend/nuxt/TESTING_GUIDE.md +904 -0
- package/template/.opencode/agent-docs/frontend/nuxt/WORKFLOWS.md +758 -0
- package/template/.opencode/agent-docs/frontend/react/API_PATTERNS.md +187 -0
- package/template/.opencode/agent-docs/frontend/react/CHEATSHEET.md +87 -0
- package/template/.opencode/agent-docs/frontend/react/INDEX.md +45 -0
- package/template/.opencode/agent-docs/frontend/react/QUICK_START.md +43 -0
- package/template/.opencode/agent-docs/frontend/react/README.md +159 -0
- package/template/.opencode/agent-docs/frontend/vue/README.md +0 -0
- package/template/.opencode/agent-docs/mobile/android/README.md +45 -0
- package/template/.opencode/agent-docs/mobile/flutter/README.md +44 -0
- package/template/.opencode/agents/android-developer.md +418 -0
- package/template/.opencode/agents/code-igniter-3-fullstack.md +345 -0
- package/template/.opencode/agents/code-reviewer.md +517 -0
- package/template/.opencode/agents/database-specialist.md +455 -0
- package/template/.opencode/agents/devops-specialist.md +562 -0
- package/template/.opencode/agents/flutter-developer.md +556 -0
- package/template/.opencode/agents/it-leader.md +911 -0
- package/template/.opencode/agents/laravel-advanced.md +691 -0
- package/template/.opencode/agents/node-backend-developer.md +343 -0
- package/template/.opencode/agents/nuxt-frontend-developer-mentor.md +402 -0
- package/template/.opencode/agents/nuxt-frontend-developer.md +1573 -0
- package/template/.opencode/agents/react-frontend-developer.md +1017 -0
- package/template/.opencode/agents/seo-specialist.md +681 -0
- package/template/.opencode/agents/ui-ux-designer.md +783 -0
- package/template/.opencode/commands/android-build/command.md +25 -0
- package/template/.opencode/commands/android-test/command.md +23 -0
- package/template/.opencode/commands/build-fix.md +29 -0
- package/template/.opencode/commands/checkpoint.md +74 -0
- package/template/.opencode/commands/code-review.md +40 -0
- package/template/.opencode/commands/e2e.md +363 -0
- package/template/.opencode/commands/eval.md +120 -0
- package/template/.opencode/commands/evolve.md +193 -0
- package/template/.opencode/commands/flutter-build/command.md +25 -0
- package/template/.opencode/commands/flutter-test/command.md +24 -0
- package/template/.opencode/commands/go-build.md +183 -0
- package/template/.opencode/commands/go-review.md +148 -0
- package/template/.opencode/commands/go-test.md +268 -0
- package/template/.opencode/commands/gpc-release/command.md +30 -0
- package/template/.opencode/commands/instinct-export.md +91 -0
- package/template/.opencode/commands/instinct-import.md +142 -0
- package/template/.opencode/commands/instinct-status.md +86 -0
- package/template/.opencode/commands/learn.md +70 -0
- package/template/.opencode/commands/multi-backend.md +158 -0
- package/template/.opencode/commands/multi-execute.md +310 -0
- package/template/.opencode/commands/multi-frontend.md +158 -0
- package/template/.opencode/commands/multi-plan.md +261 -0
- package/template/.opencode/commands/multi-workflow.md +183 -0
- package/template/.opencode/commands/orchestrate.md +172 -0
- package/template/.opencode/commands/plan.md +113 -0
- package/template/.opencode/commands/pm2.md +271 -0
- package/template/.opencode/commands/python-review.md +297 -0
- package/template/.opencode/commands/refactor-clean.md +28 -0
- package/template/.opencode/commands/sessions.md +305 -0
- package/template/.opencode/commands/setup-pm.md +80 -0
- package/template/.opencode/commands/skill-create.md +174 -0
- package/template/.opencode/commands/tdd.md +326 -0
- package/template/.opencode/commands/test-coverage.md +27 -0
- package/template/.opencode/commands/update-codemaps.md +17 -0
- package/template/.opencode/commands/update-docs.md +31 -0
- package/template/.opencode/commands/verify.md +59 -0
- package/template/.opencode/config.example.json +309 -0
- package/template/.opencode/config.json +341 -0
- package/template/.opencode/contexts/dev.md +20 -0
- package/template/.opencode/contexts/research.md +26 -0
- package/template/.opencode/contexts/review.md +22 -0
- package/template/.opencode/hooks/hooks.json +169 -0
- package/template/.opencode/instructions/INSTRUCTIONS.md +388 -0
- package/template/.opencode/package.json +5 -0
- package/template/.opencode/rules/README.md +82 -0
- package/template/.opencode/rules/android/gradle.md +62 -0
- package/template/.opencode/rules/android/testing.md +27 -0
- package/template/.opencode/rules/common/agents.md +49 -0
- package/template/.opencode/rules/common/coding-style.md +48 -0
- package/template/.opencode/rules/common/git-workflow.md +45 -0
- package/template/.opencode/rules/common/hooks.md +30 -0
- package/template/.opencode/rules/common/patterns.md +31 -0
- package/template/.opencode/rules/common/performance.md +55 -0
- package/template/.opencode/rules/common/security.md +29 -0
- package/template/.opencode/rules/common/testing.md +29 -0
- package/template/.opencode/rules/flutter/state-management.md +57 -0
- package/template/.opencode/rules/flutter/testing.md +42 -0
- package/template/.opencode/rules/golang/coding-style.md +26 -0
- package/template/.opencode/rules/golang/hooks.md +11 -0
- package/template/.opencode/rules/golang/patterns.md +39 -0
- package/template/.opencode/rules/golang/security.md +28 -0
- package/template/.opencode/rules/golang/testing.md +25 -0
- package/template/.opencode/rules/mobile/performance.md +36 -0
- package/template/.opencode/rules/python/coding-style.md +37 -0
- package/template/.opencode/rules/python/hooks.md +14 -0
- package/template/.opencode/rules/python/patterns.md +34 -0
- package/template/.opencode/rules/python/security.md +25 -0
- package/template/.opencode/rules/python/testing.md +33 -0
- package/template/.opencode/rules/typescript/coding-style.md +58 -0
- package/template/.opencode/rules/typescript/hooks.md +15 -0
- package/template/.opencode/rules/typescript/patterns.md +45 -0
- package/template/.opencode/rules/typescript/security.md +21 -0
- package/template/.opencode/rules/typescript/testing.md +11 -0
- package/template/.opencode/skills/api-documentation/SKILL.md +188 -0
- package/template/.opencode/skills/backend-patterns/SKILL.md +587 -0
- package/template/.opencode/skills/building-components/SKILL.md +37 -0
- package/template/.opencode/skills/building-components/references/accessibility.mdx +819 -0
- package/template/.opencode/skills/building-components/references/as-child.mdx +324 -0
- package/template/.opencode/skills/building-components/references/composition.mdx +239 -0
- package/template/.opencode/skills/building-components/references/data-attributes.mdx +413 -0
- package/template/.opencode/skills/building-components/references/definitions.mdx +258 -0
- package/template/.opencode/skills/building-components/references/design-tokens.mdx +57 -0
- package/template/.opencode/skills/building-components/references/docs.mdx +155 -0
- package/template/.opencode/skills/building-components/references/marketplaces.mdx +144 -0
- package/template/.opencode/skills/building-components/references/npm.mdx +166 -0
- package/template/.opencode/skills/building-components/references/polymorphism.mdx +583 -0
- package/template/.opencode/skills/building-components/references/principles.mdx +61 -0
- package/template/.opencode/skills/building-components/references/registry.mdx +169 -0
- package/template/.opencode/skills/building-components/references/state.mdx +99 -0
- package/template/.opencode/skills/building-components/references/styling.mdx +286 -0
- package/template/.opencode/skills/building-components/references/types.mdx +191 -0
- package/template/.opencode/skills/clickhouse-io/SKILL.md +429 -0
- package/template/.opencode/skills/coding-standards/SKILL.md +520 -0
- package/template/.opencode/skills/configure-ecc/SKILL.md +298 -0
- package/template/.opencode/skills/continuous-learning/SKILL.md +110 -0
- package/template/.opencode/skills/continuous-learning/config.json +18 -0
- package/template/.opencode/skills/continuous-learning/evaluate-session.sh +60 -0
- package/template/.opencode/skills/continuous-learning-v2/SKILL.md +284 -0
- package/template/.opencode/skills/continuous-learning-v2/agents/observer.md +137 -0
- package/template/.opencode/skills/continuous-learning-v2/agents/start-observer.sh +134 -0
- package/template/.opencode/skills/continuous-learning-v2/config.json +41 -0
- package/template/.opencode/skills/continuous-learning-v2/hooks/observe.sh +153 -0
- package/template/.opencode/skills/continuous-learning-v2/scripts/instinct-cli.py +489 -0
- package/template/.opencode/skills/continuous-learning-v2/scripts/test_parse_instinct.py +82 -0
- package/template/.opencode/skills/dart-add-unit-test/SKILL.md +122 -0
- package/template/.opencode/skills/dart-build-cli-app/SKILL.md +185 -0
- package/template/.opencode/skills/dart-collect-coverage/SKILL.md +141 -0
- package/template/.opencode/skills/dart-fix-runtime-errors/SKILL.md +166 -0
- package/template/.opencode/skills/dart-generate-test-mocks/SKILL.md +155 -0
- package/template/.opencode/skills/dart-migrate-to-checks-package/SKILL.md +126 -0
- package/template/.opencode/skills/dart-resolve-package-conflicts/SKILL.md +116 -0
- package/template/.opencode/skills/dart-run-static-analysis/SKILL.md +104 -0
- package/template/.opencode/skills/dart-use-pattern-matching/SKILL.md +146 -0
- package/template/.opencode/skills/django-patterns/SKILL.md +733 -0
- package/template/.opencode/skills/django-security/SKILL.md +592 -0
- package/template/.opencode/skills/django-tdd/SKILL.md +728 -0
- package/template/.opencode/skills/django-verification/SKILL.md +460 -0
- package/template/.opencode/skills/eval-harness/SKILL.md +227 -0
- package/template/.opencode/skills/firebase-basics/SKILL.md +103 -0
- package/template/.opencode/skills/firebase-basics/references/additional-skills.md +113 -0
- package/template/.opencode/skills/firebase-basics/references/cli-usage.md +31 -0
- package/template/.opencode/skills/firebase-basics/references/client-library-usage.md +45 -0
- package/template/.opencode/skills/firebase-basics/references/core-concepts.md +61 -0
- package/template/.opencode/skills/firebase-basics/references/iac-usage.md +40 -0
- package/template/.opencode/skills/firebase-basics/references/iam-security.md +74 -0
- package/template/.opencode/skills/firebase-basics/references/mcp-usage.md +63 -0
- package/template/.opencode/skills/flutter/SKILL.md +292 -0
- package/template/.opencode/skills/flutter-add-integration-test/SKILL.md +163 -0
- package/template/.opencode/skills/flutter-add-widget-preview/SKILL.md +145 -0
- package/template/.opencode/skills/flutter-add-widget-test/SKILL.md +154 -0
- package/template/.opencode/skills/flutter-apply-architecture-best-practices/SKILL.md +162 -0
- package/template/.opencode/skills/flutter-build-responsive-layout/SKILL.md +139 -0
- package/template/.opencode/skills/flutter-fix-layout-issues/SKILL.md +130 -0
- package/template/.opencode/skills/flutter-implement-json-serialization/SKILL.md +153 -0
- package/template/.opencode/skills/flutter-setup-declarative-routing/SKILL.md +255 -0
- package/template/.opencode/skills/flutter-setup-localization/SKILL.md +210 -0
- package/template/.opencode/skills/flutter-use-http-package/SKILL.md +174 -0
- package/template/.opencode/skills/frontend-design/SKILL.md +89 -0
- package/template/.opencode/skills/frontend-patterns/SKILL.md +631 -0
- package/template/.opencode/skills/golang-patterns/SKILL.md +673 -0
- package/template/.opencode/skills/golang-testing/SKILL.md +719 -0
- package/template/.opencode/skills/impeccable/SKILL.md +165 -0
- package/template/.opencode/skills/impeccable/agents/impeccable-asset-producer.md +101 -0
- package/template/.opencode/skills/impeccable/reference/adapt.md +190 -0
- package/template/.opencode/skills/impeccable/reference/animate.md +175 -0
- package/template/.opencode/skills/impeccable/reference/audit.md +133 -0
- package/template/.opencode/skills/impeccable/reference/bolder.md +113 -0
- package/template/.opencode/skills/impeccable/reference/brand.md +118 -0
- package/template/.opencode/skills/impeccable/reference/clarify.md +174 -0
- package/template/.opencode/skills/impeccable/reference/codex.md +105 -0
- package/template/.opencode/skills/impeccable/reference/cognitive-load.md +106 -0
- package/template/.opencode/skills/impeccable/reference/color-and-contrast.md +105 -0
- package/template/.opencode/skills/impeccable/reference/colorize.md +154 -0
- package/template/.opencode/skills/impeccable/reference/craft.md +123 -0
- package/template/.opencode/skills/impeccable/reference/critique.md +273 -0
- package/template/.opencode/skills/impeccable/reference/delight.md +302 -0
- package/template/.opencode/skills/impeccable/reference/distill.md +111 -0
- package/template/.opencode/skills/impeccable/reference/document.md +427 -0
- package/template/.opencode/skills/impeccable/reference/extract.md +69 -0
- package/template/.opencode/skills/impeccable/reference/harden.md +347 -0
- package/template/.opencode/skills/impeccable/reference/heuristics-scoring.md +234 -0
- package/template/.opencode/skills/impeccable/reference/interaction-design.md +195 -0
- package/template/.opencode/skills/impeccable/reference/layout.md +141 -0
- package/template/.opencode/skills/impeccable/reference/live.md +622 -0
- package/template/.opencode/skills/impeccable/reference/motion-design.md +109 -0
- package/template/.opencode/skills/impeccable/reference/onboard.md +234 -0
- package/template/.opencode/skills/impeccable/reference/optimize.md +258 -0
- package/template/.opencode/skills/impeccable/reference/overdrive.md +130 -0
- package/template/.opencode/skills/impeccable/reference/personas.md +179 -0
- package/template/.opencode/skills/impeccable/reference/polish.md +242 -0
- package/template/.opencode/skills/impeccable/reference/product.md +62 -0
- package/template/.opencode/skills/impeccable/reference/quieter.md +99 -0
- package/template/.opencode/skills/impeccable/reference/responsive-design.md +114 -0
- package/template/.opencode/skills/impeccable/reference/shape.md +165 -0
- package/template/.opencode/skills/impeccable/reference/spatial-design.md +100 -0
- package/template/.opencode/skills/impeccable/reference/teach.md +156 -0
- package/template/.opencode/skills/impeccable/reference/typeset.md +124 -0
- package/template/.opencode/skills/impeccable/reference/typography.md +159 -0
- package/template/.opencode/skills/impeccable/reference/ux-writing.md +107 -0
- package/template/.opencode/skills/impeccable/scripts/cleanup-deprecated.mjs +284 -0
- package/template/.opencode/skills/impeccable/scripts/command-metadata.json +94 -0
- package/template/.opencode/skills/impeccable/scripts/critique-storage.mjs +242 -0
- package/template/.opencode/skills/impeccable/scripts/design-parser.mjs +820 -0
- package/template/.opencode/skills/impeccable/scripts/detect-csp.mjs +198 -0
- package/template/.opencode/skills/impeccable/scripts/detect.mjs +21 -0
- package/template/.opencode/skills/impeccable/scripts/impeccable-paths.mjs +110 -0
- package/template/.opencode/skills/impeccable/scripts/is-generated.mjs +69 -0
- package/template/.opencode/skills/impeccable/scripts/live-accept.mjs +595 -0
- package/template/.opencode/skills/impeccable/scripts/live-browser-session.js +123 -0
- package/template/.opencode/skills/impeccable/scripts/live-browser.js +4860 -0
- package/template/.opencode/skills/impeccable/scripts/live-complete.mjs +75 -0
- package/template/.opencode/skills/impeccable/scripts/live-completion.mjs +18 -0
- package/template/.opencode/skills/impeccable/scripts/live-inject.mjs +446 -0
- package/template/.opencode/skills/impeccable/scripts/live-poll.mjs +200 -0
- package/template/.opencode/skills/impeccable/scripts/live-resume.mjs +48 -0
- package/template/.opencode/skills/impeccable/scripts/live-server.mjs +838 -0
- package/template/.opencode/skills/impeccable/scripts/live-session-store.mjs +254 -0
- package/template/.opencode/skills/impeccable/scripts/live-status.mjs +47 -0
- package/template/.opencode/skills/impeccable/scripts/live-wrap.mjs +632 -0
- package/template/.opencode/skills/impeccable/scripts/live.mjs +247 -0
- package/template/.opencode/skills/impeccable/scripts/load-context.mjs +141 -0
- package/template/.opencode/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
- package/template/.opencode/skills/impeccable/scripts/pin.mjs +214 -0
- package/template/.opencode/skills/iterative-retrieval/SKILL.md +202 -0
- package/template/.opencode/skills/java-coding-standards/SKILL.md +138 -0
- package/template/.opencode/skills/jetpack-compose/.skillfish.json +10 -0
- package/template/.opencode/skills/jetpack-compose/SKILL.md +420 -0
- package/template/.opencode/skills/jpa-patterns/SKILL.md +141 -0
- package/template/.opencode/skills/nutrient-document-processing/SKILL.md +165 -0
- package/template/.opencode/skills/nuxt-ui/SKILL.md +334 -0
- package/template/.opencode/skills/nuxt-ui/references/components.md +377 -0
- package/template/.opencode/skills/nuxt-ui/references/composables.md +127 -0
- package/template/.opencode/skills/nuxt-ui/references/layouts/chat.md +266 -0
- package/template/.opencode/skills/nuxt-ui/references/layouts/dashboard.md +220 -0
- package/template/.opencode/skills/nuxt-ui/references/layouts/docs.md +141 -0
- package/template/.opencode/skills/nuxt-ui/references/layouts/editor.md +168 -0
- package/template/.opencode/skills/nuxt-ui/references/layouts/page.md +260 -0
- package/template/.opencode/skills/nuxt-ui/references/theming.md +427 -0
- package/template/.opencode/skills/postgres-patterns/SKILL.md +146 -0
- package/template/.opencode/skills/project-guidelines-example/SKILL.md +345 -0
- package/template/.opencode/skills/python-patterns/SKILL.md +749 -0
- package/template/.opencode/skills/python-testing/SKILL.md +815 -0
- package/template/.opencode/skills/security-review/SKILL.md +494 -0
- package/template/.opencode/skills/security-review/cloud-infrastructure-security.md +361 -0
- package/template/.opencode/skills/shadcn-ui/README.md +248 -0
- package/template/.opencode/skills/shadcn-ui/SKILL.md +326 -0
- package/template/.opencode/skills/shadcn-ui/examples/auth-layout.tsx +177 -0
- package/template/.opencode/skills/shadcn-ui/examples/data-table.tsx +313 -0
- package/template/.opencode/skills/shadcn-ui/examples/form-pattern.tsx +177 -0
- package/template/.opencode/skills/shadcn-ui/resources/component-catalog.md +481 -0
- package/template/.opencode/skills/shadcn-ui/resources/customization-guide.md +516 -0
- package/template/.opencode/skills/shadcn-ui/resources/migration-guide.md +463 -0
- package/template/.opencode/skills/shadcn-ui/resources/setup-guide.md +412 -0
- package/template/.opencode/skills/shadcn-ui/scripts/verify-setup.sh +134 -0
- package/template/.opencode/skills/springboot-patterns/SKILL.md +304 -0
- package/template/.opencode/skills/springboot-security/SKILL.md +119 -0
- package/template/.opencode/skills/springboot-tdd/SKILL.md +157 -0
- package/template/.opencode/skills/springboot-verification/SKILL.md +100 -0
- package/template/.opencode/skills/strategic-compact/SKILL.md +63 -0
- package/template/.opencode/skills/strategic-compact/suggest-compact.sh +52 -0
- package/template/.opencode/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.opencode/skills/vercel-composition-patterns/AGENTS.md +946 -0
- package/template/.opencode/skills/vercel-composition-patterns/SKILL.md +89 -0
- package/template/.opencode/skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/template/.opencode/skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
- package/template/.opencode/skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/template/.opencode/skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/template/.opencode/skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/template/.opencode/skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
- package/template/.opencode/skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/template/.opencode/skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
- package/template/.opencode/skills/vercel-react-best-practices/AGENTS.md +2934 -0
- package/template/.opencode/skills/vercel-react-best-practices/SKILL.md +136 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/template/.opencode/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/template/.opencode/skills/verification-loop/SKILL.md +120 -0
- package/template/.opencode/skills/web-design-guidelines/SKILL.md +39 -0
- package/template/AGENTS.md +32 -0
- package/template/opencode.json +354 -0
|
@@ -0,0 +1,956 @@
|
|
|
1
|
+
# Frontend Developer Agent - Contoh Praktis
|
|
2
|
+
|
|
3
|
+
Dokumen ini berisi contoh-contoh praktis penggunaan Frontend Developer Agent untuk berbagai skenario development.
|
|
4
|
+
|
|
5
|
+
## Daftar Isi
|
|
6
|
+
|
|
7
|
+
1. [Component Development](#1-component-development)
|
|
8
|
+
2. [Nuxt UI Integration](#2-nuxt-ui-integration)
|
|
9
|
+
3. [API Integration](#3-api-integration)
|
|
10
|
+
4. [Form Handling](#4-form-handling)
|
|
11
|
+
5. [State Management](#5-state-management)
|
|
12
|
+
6. [Performance Optimization](#6-performance-optimization)
|
|
13
|
+
7. [Accessibility Review](#7-accessibility-review)
|
|
14
|
+
8. [Bug Fixing](#8-bug-fixing)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Component Development
|
|
19
|
+
|
|
20
|
+
### Skenario: Membuat Product Card Component
|
|
21
|
+
|
|
22
|
+
**Prompt:**
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
@frontend Saya butuh ProductCard component untuk e-commerce dengan fitur:
|
|
26
|
+
- Gambar produk dengan lazy loading
|
|
27
|
+
- Badge untuk discount
|
|
28
|
+
- Rating stars
|
|
29
|
+
- Add to cart button
|
|
30
|
+
- Wishlist toggle
|
|
31
|
+
- Support dark mode
|
|
32
|
+
- Accessible (WCAG 2.1)
|
|
33
|
+
|
|
34
|
+
Gunakan Nuxt UI components sebisa mungkin.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Output yang Diharapkan:**
|
|
38
|
+
|
|
39
|
+
- `app/components/product/ProductCard.vue` menggunakan `<UCard>`, `<UBadge>`, `<UButton>`
|
|
40
|
+
- TypeScript interfaces untuk Product type
|
|
41
|
+
- Composable `useProduct` untuk business logic
|
|
42
|
+
- Accessible markup dengan ARIA labels
|
|
43
|
+
- Responsive design dengan Tailwind
|
|
44
|
+
- Unit tests dengan Vitest
|
|
45
|
+
|
|
46
|
+
**Agent akan:**
|
|
47
|
+
|
|
48
|
+
1. ✅ Check MCP Nuxt UI untuk available components
|
|
49
|
+
2. ✅ Load skill `nuxt-ui` untuk component patterns
|
|
50
|
+
3. ✅ Load skill `building-components` untuk best practices
|
|
51
|
+
4. ✅ Load skill `web-design-guidelines` untuk accessibility
|
|
52
|
+
5. ✅ Create component dengan TypeScript strict mode
|
|
53
|
+
6. ✅ Add comprehensive tests
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 2. Nuxt UI Integration
|
|
58
|
+
|
|
59
|
+
### Skenario: Dashboard Layout dengan Sidebar
|
|
60
|
+
|
|
61
|
+
**Prompt:**
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
@frontend Build dashboard layout dengan:
|
|
65
|
+
- Collapsible sidebar navigation
|
|
66
|
+
- Top header dengan user menu
|
|
67
|
+
- Breadcrumb navigation
|
|
68
|
+
- Main content area
|
|
69
|
+
- Toast notifications
|
|
70
|
+
- Command palette (Cmd+K)
|
|
71
|
+
|
|
72
|
+
Gunakan Nuxt UI App components.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Output yang Diharapkan:**
|
|
76
|
+
|
|
77
|
+
- Layout menggunakan `<UDashboard>` components
|
|
78
|
+
- `<UVerticalNavigation>` untuk sidebar
|
|
79
|
+
- `<UCommandPalette>` untuk search
|
|
80
|
+
- `<UToast>` untuk notifications
|
|
81
|
+
- Dark mode toggle
|
|
82
|
+
- Responsive mobile menu
|
|
83
|
+
|
|
84
|
+
**Agent akan:**
|
|
85
|
+
|
|
86
|
+
1. ✅ Query Nuxt UI MCP untuk Dashboard components
|
|
87
|
+
2. ✅ Check documentation untuk `<UDashboard>` API
|
|
88
|
+
3. ✅ Implement dengan Nuxt 4 app/ directory structure
|
|
89
|
+
4. ✅ Add keyboard shortcuts
|
|
90
|
+
5. ✅ Test responsive behavior
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 3. API Integration
|
|
95
|
+
|
|
96
|
+
### Skenario: Data Fetching dengan Error Handling
|
|
97
|
+
|
|
98
|
+
**Prompt:**
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
@frontend Implement user list page dengan:
|
|
102
|
+
- Fetch dari /api/users
|
|
103
|
+
- Loading skeleton
|
|
104
|
+
- Error state dengan retry
|
|
105
|
+
- Pagination
|
|
106
|
+
- Search dan filter
|
|
107
|
+
- Optimistic updates untuk delete
|
|
108
|
+
|
|
109
|
+
Gunakan useApi composable (app/composables/useApi.ts)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Output yang Diharapkan:**
|
|
113
|
+
|
|
114
|
+
- `app/pages/users/index.vue` dengan `useApi`
|
|
115
|
+
- Error handling dengan `<UAlert>`
|
|
116
|
+
- Loading states dengan `<USkeleton>`
|
|
117
|
+
- Pagination dengan `<UPagination>`
|
|
118
|
+
- Search dengan debounce
|
|
119
|
+
|
|
120
|
+
**Agent akan:**
|
|
121
|
+
|
|
122
|
+
1. ✅ Load skill `frontend-patterns` untuk data fetching
|
|
123
|
+
2. ✅ Use custom `useApi` composable (recommended pattern)
|
|
124
|
+
3. ✅ Implement error boundaries
|
|
125
|
+
4. ✅ Add loading states
|
|
126
|
+
5. ✅ Handle authentication automatically
|
|
127
|
+
|
|
128
|
+
**Code Example (Recommended - Using useApi):**
|
|
129
|
+
|
|
130
|
+
```vue
|
|
131
|
+
<script setup lang="ts">
|
|
132
|
+
interface User {
|
|
133
|
+
id: string
|
|
134
|
+
name: string
|
|
135
|
+
email: string
|
|
136
|
+
role: 'admin' | 'user'
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const page = ref(1)
|
|
140
|
+
const search = ref('')
|
|
141
|
+
|
|
142
|
+
// ✅ BEST: Use useApi for automatic auth + error handling
|
|
143
|
+
const {
|
|
144
|
+
data: response,
|
|
145
|
+
pending,
|
|
146
|
+
error,
|
|
147
|
+
refresh,
|
|
148
|
+
} = await useApi<User[]>('/users', {
|
|
149
|
+
query: { page, search },
|
|
150
|
+
watch: [page, search],
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
// Access users from response.data
|
|
154
|
+
const users = computed(() => response.value?.data || [])
|
|
155
|
+
|
|
156
|
+
const handleDelete = async (id: string) => {
|
|
157
|
+
// Optimistic update
|
|
158
|
+
const originalUsers = users.value
|
|
159
|
+
users.value = users.value.filter((u) => u.id !== id)
|
|
160
|
+
|
|
161
|
+
// Use useApi for delete
|
|
162
|
+
const { error: deleteError } = await useApi(`/users/${id}`, {
|
|
163
|
+
method: 'DELETE',
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
if (deleteError.value) {
|
|
167
|
+
// Rollback on error
|
|
168
|
+
users.value = originalUsers
|
|
169
|
+
useToast().add({
|
|
170
|
+
title: 'Error',
|
|
171
|
+
description: deleteError.value.message,
|
|
172
|
+
color: 'red',
|
|
173
|
+
})
|
|
174
|
+
} else {
|
|
175
|
+
useToast().add({
|
|
176
|
+
title: 'Success',
|
|
177
|
+
description: 'User deleted successfully',
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
</script>
|
|
182
|
+
|
|
183
|
+
<template>
|
|
184
|
+
<UContainer>
|
|
185
|
+
<div class="space-y-4">
|
|
186
|
+
<UInput v-model="search" placeholder="Search users..." />
|
|
187
|
+
|
|
188
|
+
<div v-if="pending">
|
|
189
|
+
<USkeleton v-for="i in 5" :key="i" class="h-20" />
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<UAlert v-else-if="error" color="red" :description="error.message">
|
|
193
|
+
<template #actions>
|
|
194
|
+
<UButton @click="refresh">Retry</UButton>
|
|
195
|
+
</template>
|
|
196
|
+
</UAlert>
|
|
197
|
+
|
|
198
|
+
<div v-else>
|
|
199
|
+
<UCard v-for="user in users" :key="user.id">
|
|
200
|
+
<template #header>
|
|
201
|
+
<div class="flex items-center justify-between">
|
|
202
|
+
<div>
|
|
203
|
+
<h3 class="font-semibold">{{ user.name }}</h3>
|
|
204
|
+
<p class="text-sm text-gray-500">{{ user.email }}</p>
|
|
205
|
+
</div>
|
|
206
|
+
<UBadge :color="user.role === 'admin' ? 'blue' : 'gray'">
|
|
207
|
+
{{ user.role }}
|
|
208
|
+
</UBadge>
|
|
209
|
+
</div>
|
|
210
|
+
</template>
|
|
211
|
+
|
|
212
|
+
<template #footer>
|
|
213
|
+
<UButton color="red" variant="ghost" @click="handleDelete(user.id)"> Delete </UButton>
|
|
214
|
+
</template>
|
|
215
|
+
</UCard>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<UPagination v-model="page" :total="100" />
|
|
219
|
+
</div>
|
|
220
|
+
</UContainer>
|
|
221
|
+
</template>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Alternative (Using native useFetch):**
|
|
225
|
+
|
|
226
|
+
```vue
|
|
227
|
+
<script setup lang="ts">
|
|
228
|
+
// ⚠️ Only use this if you need custom caching or external API
|
|
229
|
+
const {
|
|
230
|
+
data: users,
|
|
231
|
+
pending,
|
|
232
|
+
error,
|
|
233
|
+
refresh,
|
|
234
|
+
} = await useFetch<User[]>('/api/users', {
|
|
235
|
+
query: { page, search },
|
|
236
|
+
watch: [page, search],
|
|
237
|
+
})
|
|
238
|
+
</script>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Key Differences - useApi vs useFetch:**
|
|
242
|
+
|
|
243
|
+
| Feature | useApi | useFetch |
|
|
244
|
+
| --------------- | ------------------------ | -------------------- |
|
|
245
|
+
| Authentication | ✅ Automatic | ⚠️ Manual |
|
|
246
|
+
| Error message | ✅ `error.value.message` | ❌ Need to extract |
|
|
247
|
+
| 401 Redirect | ✅ Automatic | ❌ Manual |
|
|
248
|
+
| SSR/CSR Smart | ✅ Yes | ✅ Yes |
|
|
249
|
+
| Type Safety | ✅ Generic `<T>` | ✅ Generic `<T>` |
|
|
250
|
+
| POST/PUT/DELETE | ✅ Auto-$fetch | ⚠️ Need useAsyncData |
|
|
251
|
+
|
|
252
|
+
**IMPORTANT: Always prefer `useApi` for this project's API calls.**
|
|
253
|
+
@frontend Implement user list page dengan:
|
|
254
|
+
|
|
255
|
+
- Fetch dari /api/users
|
|
256
|
+
- Loading skeleton
|
|
257
|
+
- Error state dengan retry
|
|
258
|
+
- Pagination
|
|
259
|
+
- Search dan filter
|
|
260
|
+
- Optimistic updates untuk delete
|
|
261
|
+
|
|
262
|
+
````
|
|
263
|
+
|
|
264
|
+
**Output yang Diharapkan:**
|
|
265
|
+
|
|
266
|
+
- `app/pages/users/index.vue` dengan `useFetch`
|
|
267
|
+
- Error handling dengan `<UAlert>`
|
|
268
|
+
- Loading states dengan `<USkeleton>`
|
|
269
|
+
- Pagination dengan `<UPagination>`
|
|
270
|
+
- Search dengan debounce
|
|
271
|
+
|
|
272
|
+
**Agent akan:**
|
|
273
|
+
|
|
274
|
+
1. ✅ Load skill `frontend-patterns` untuk data fetching
|
|
275
|
+
2. ✅ Use Nuxt 4 `useFetch` dengan proper typing
|
|
276
|
+
3. ✅ Implement error boundaries
|
|
277
|
+
4. ✅ Add loading states
|
|
278
|
+
5. ✅ Create reusable composable
|
|
279
|
+
|
|
280
|
+
**Code Example:**
|
|
281
|
+
|
|
282
|
+
```vue
|
|
283
|
+
<script setup lang="ts">
|
|
284
|
+
interface User {
|
|
285
|
+
id: string
|
|
286
|
+
name: string
|
|
287
|
+
email: string
|
|
288
|
+
role: 'admin' | 'user'
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const page = ref(1)
|
|
292
|
+
const search = ref('')
|
|
293
|
+
|
|
294
|
+
const {
|
|
295
|
+
data: users,
|
|
296
|
+
pending,
|
|
297
|
+
error,
|
|
298
|
+
refresh,
|
|
299
|
+
} = await useFetch<User[]>('/api/users', {
|
|
300
|
+
query: { page, search },
|
|
301
|
+
watch: [page, search],
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
const handleDelete = async (id: string) => {
|
|
305
|
+
// Optimistic update
|
|
306
|
+
users.value = users.value?.filter((u) => u.id !== id)
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
await $fetch(`/api/users/${id}`, { method: 'DELETE' })
|
|
310
|
+
} catch (err) {
|
|
311
|
+
// Rollback on error
|
|
312
|
+
await refresh()
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
</script>
|
|
316
|
+
|
|
317
|
+
<template>
|
|
318
|
+
<UContainer>
|
|
319
|
+
<div class="space-y-4">
|
|
320
|
+
<UInput v-model="search" placeholder="Search users..." />
|
|
321
|
+
|
|
322
|
+
<div v-if="pending">
|
|
323
|
+
<USkeleton v-for="i in 5" :key="i" class="h-20" />
|
|
324
|
+
</div>
|
|
325
|
+
|
|
326
|
+
<UAlert v-else-if="error" color="red" :description="error.message">
|
|
327
|
+
<template #actions>
|
|
328
|
+
<UButton @click="refresh">Retry</UButton>
|
|
329
|
+
</template>
|
|
330
|
+
</UAlert>
|
|
331
|
+
|
|
332
|
+
<div v-else>
|
|
333
|
+
<UCard v-for="user in users" :key="user.id">
|
|
334
|
+
<!-- User content -->
|
|
335
|
+
</UCard>
|
|
336
|
+
</div>
|
|
337
|
+
|
|
338
|
+
<UPagination v-model="page" :total="100" />
|
|
339
|
+
</div>
|
|
340
|
+
</UContainer>
|
|
341
|
+
</template>
|
|
342
|
+
````
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## 4. Form Handling
|
|
347
|
+
|
|
348
|
+
### Skenario: Complex Form dengan Validation
|
|
349
|
+
|
|
350
|
+
**Prompt:**
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
@frontend Create user profile form dengan:
|
|
354
|
+
- Multiple steps (Personal, Contact, Preferences)
|
|
355
|
+
- Real-time validation
|
|
356
|
+
- File upload untuk avatar
|
|
357
|
+
- Auto-save draft
|
|
358
|
+
- Success/error toast
|
|
359
|
+
- Accessible form labels
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Output yang Diharapkan:**
|
|
363
|
+
|
|
364
|
+
- Multi-step form dengan `<UForm>`
|
|
365
|
+
- Validation dengan Zod schema
|
|
366
|
+
- `<UFormGroup>` untuk field groups
|
|
367
|
+
- File upload dengan preview
|
|
368
|
+
- Auto-save dengan debounce
|
|
369
|
+
|
|
370
|
+
**Agent akan:**
|
|
371
|
+
|
|
372
|
+
1. ✅ Check Nuxt UI Form components via MCP
|
|
373
|
+
2. ✅ Load skill `frontend-patterns` untuk form handling
|
|
374
|
+
3. ✅ Implement validation dengan Zod
|
|
375
|
+
4. ✅ Add accessibility features
|
|
376
|
+
5. ✅ Create composable untuk form state
|
|
377
|
+
|
|
378
|
+
**Code Example:**
|
|
379
|
+
|
|
380
|
+
```vue
|
|
381
|
+
<script setup lang="ts">
|
|
382
|
+
import { z } from 'zod'
|
|
383
|
+
|
|
384
|
+
const schema = z.object({
|
|
385
|
+
name: z.string().min(2, 'Name must be at least 2 characters'),
|
|
386
|
+
email: z.string().email('Invalid email address'),
|
|
387
|
+
avatar: z.instanceof(File).optional(),
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
type FormData = z.infer<typeof schema>
|
|
391
|
+
|
|
392
|
+
const state = reactive<FormData>({
|
|
393
|
+
name: '',
|
|
394
|
+
email: '',
|
|
395
|
+
avatar: undefined,
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
const { pending, error, execute } = useFetch('/api/profile', {
|
|
399
|
+
method: 'POST',
|
|
400
|
+
body: state,
|
|
401
|
+
immediate: false,
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
const onSubmit = async () => {
|
|
405
|
+
await execute()
|
|
406
|
+
if (!error.value) {
|
|
407
|
+
useToast().add({ title: 'Profile updated!' })
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Auto-save draft
|
|
412
|
+
watchDebounced(
|
|
413
|
+
state,
|
|
414
|
+
() => {
|
|
415
|
+
localStorage.setItem('profile-draft', JSON.stringify(state))
|
|
416
|
+
},
|
|
417
|
+
{ debounce: 1000 }
|
|
418
|
+
)
|
|
419
|
+
</script>
|
|
420
|
+
|
|
421
|
+
<template>
|
|
422
|
+
<UForm :schema="schema" :state="state" @submit="onSubmit">
|
|
423
|
+
<UFormGroup label="Name" name="name" required>
|
|
424
|
+
<UInput v-model="state.name" />
|
|
425
|
+
</UFormGroup>
|
|
426
|
+
|
|
427
|
+
<UFormGroup label="Email" name="email" required>
|
|
428
|
+
<UInput v-model="state.email" type="email" />
|
|
429
|
+
</UFormGroup>
|
|
430
|
+
|
|
431
|
+
<UFormGroup label="Avatar" name="avatar">
|
|
432
|
+
<UInput type="file" accept="image/*" />
|
|
433
|
+
</UFormGroup>
|
|
434
|
+
|
|
435
|
+
<UButton type="submit" :loading="pending"> Save Profile </UButton>
|
|
436
|
+
</UForm>
|
|
437
|
+
</template>
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## 5. State Management
|
|
443
|
+
|
|
444
|
+
### Skenario: Shopping Cart dengan Pinia
|
|
445
|
+
|
|
446
|
+
**Prompt:**
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
@frontend Implement shopping cart dengan:
|
|
450
|
+
- Add/remove items
|
|
451
|
+
- Update quantity
|
|
452
|
+
- Calculate total
|
|
453
|
+
- Persist to localStorage
|
|
454
|
+
- Sync across tabs
|
|
455
|
+
- Optimistic updates
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Output yang Diharapkan:**
|
|
459
|
+
|
|
460
|
+
- `app/stores/cart.ts` Pinia store
|
|
461
|
+
- Composable `useCart` untuk easy access
|
|
462
|
+
- LocalStorage persistence
|
|
463
|
+
- BroadcastChannel untuk sync
|
|
464
|
+
- Type-safe actions
|
|
465
|
+
|
|
466
|
+
**Agent akan:**
|
|
467
|
+
|
|
468
|
+
1. ✅ Load skill `frontend-patterns` untuk state management
|
|
469
|
+
2. ✅ Create Pinia store dengan TypeScript
|
|
470
|
+
3. ✅ Implement persistence plugin
|
|
471
|
+
4. ✅ Add optimistic updates
|
|
472
|
+
5. ✅ Create comprehensive tests
|
|
473
|
+
|
|
474
|
+
**Code Example:**
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
// app/stores/cart.ts
|
|
478
|
+
import { defineStore } from 'pinia'
|
|
479
|
+
|
|
480
|
+
interface CartItem {
|
|
481
|
+
id: string
|
|
482
|
+
name: string
|
|
483
|
+
price: number
|
|
484
|
+
quantity: number
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export const useCartStore = defineStore('cart', () => {
|
|
488
|
+
const items = ref<CartItem[]>([])
|
|
489
|
+
|
|
490
|
+
const total = computed(() =>
|
|
491
|
+
items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
const addItem = (product: Omit<CartItem, 'quantity'>) => {
|
|
495
|
+
const existing = items.value.find((i) => i.id === product.id)
|
|
496
|
+
if (existing) {
|
|
497
|
+
existing.quantity++
|
|
498
|
+
} else {
|
|
499
|
+
items.value.push({ ...product, quantity: 1 })
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const removeItem = (id: string) => {
|
|
504
|
+
items.value = items.value.filter((i) => i.id !== id)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const updateQuantity = (id: string, quantity: number) => {
|
|
508
|
+
const item = items.value.find((i) => i.id === id)
|
|
509
|
+
if (item) {
|
|
510
|
+
item.quantity = Math.max(0, quantity)
|
|
511
|
+
if (item.quantity === 0) {
|
|
512
|
+
removeItem(id)
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Persist to localStorage
|
|
518
|
+
watch(
|
|
519
|
+
items,
|
|
520
|
+
(newItems) => {
|
|
521
|
+
localStorage.setItem('cart', JSON.stringify(newItems))
|
|
522
|
+
},
|
|
523
|
+
{ deep: true }
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
// Sync across tabs
|
|
527
|
+
if (process.client) {
|
|
528
|
+
const channel = new BroadcastChannel('cart-sync')
|
|
529
|
+
channel.onmessage = (event) => {
|
|
530
|
+
items.value = event.data
|
|
531
|
+
}
|
|
532
|
+
watch(items, (newItems) => {
|
|
533
|
+
channel.postMessage(newItems)
|
|
534
|
+
})
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
items,
|
|
539
|
+
total,
|
|
540
|
+
addItem,
|
|
541
|
+
removeItem,
|
|
542
|
+
updateQuantity,
|
|
543
|
+
}
|
|
544
|
+
})
|
|
545
|
+
|
|
546
|
+
// app/composables/useCart.ts
|
|
547
|
+
export const useCart = () => useCartStore()
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## 6. Performance Optimization
|
|
553
|
+
|
|
554
|
+
### Skenario: Optimize Slow Page
|
|
555
|
+
|
|
556
|
+
**Prompt:**
|
|
557
|
+
|
|
558
|
+
```
|
|
559
|
+
@frontend Page /products sangat lambat. Tolong optimize:
|
|
560
|
+
- Initial load time
|
|
561
|
+
- Image loading
|
|
562
|
+
- Component rendering
|
|
563
|
+
- Bundle size
|
|
564
|
+
- Lighthouse score target: 90+
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Agent akan:**
|
|
568
|
+
|
|
569
|
+
1. ✅ Load skill `frontend-patterns`
|
|
570
|
+
2. ✅ Analyze bundle dengan `nuxi analyze`
|
|
571
|
+
3. ✅ Implement lazy loading
|
|
572
|
+
4. ✅ Add image optimization
|
|
573
|
+
5. ✅ Use virtual scrolling untuk long lists
|
|
574
|
+
6. ✅ Run Lighthouse audit
|
|
575
|
+
|
|
576
|
+
**Optimizations Applied:**
|
|
577
|
+
|
|
578
|
+
```vue
|
|
579
|
+
<!-- Before -->
|
|
580
|
+
<script setup lang="ts">
|
|
581
|
+
import ProductCard from '~/components/ProductCard.vue'
|
|
582
|
+
import HeavyChart from '~/components/HeavyChart.vue'
|
|
583
|
+
|
|
584
|
+
const { data: products } = await useFetch('/api/products')
|
|
585
|
+
</script>
|
|
586
|
+
|
|
587
|
+
<template>
|
|
588
|
+
<div v-for="product in products" :key="product.id">
|
|
589
|
+
<img :src="product.image" />
|
|
590
|
+
<ProductCard :product="product" />
|
|
591
|
+
</div>
|
|
592
|
+
<HeavyChart :data="chartData" />
|
|
593
|
+
</template>
|
|
594
|
+
|
|
595
|
+
<!-- After -->
|
|
596
|
+
<script setup lang="ts">
|
|
597
|
+
// Lazy load heavy component
|
|
598
|
+
const HeavyChart = defineAsyncComponent(() => import('~/components/HeavyChart.vue'))
|
|
599
|
+
|
|
600
|
+
// Fetch with caching
|
|
601
|
+
const { data: products } = await useFetch('/api/products', {
|
|
602
|
+
key: 'products-list',
|
|
603
|
+
getCachedData: (key) => useNuxtData(key).data,
|
|
604
|
+
})
|
|
605
|
+
</script>
|
|
606
|
+
|
|
607
|
+
<template>
|
|
608
|
+
<!-- Virtual scrolling untuk list panjang -->
|
|
609
|
+
<UVirtualScroll :items="products" :item-height="200">
|
|
610
|
+
<template #default="{ item: product }">
|
|
611
|
+
<!-- Optimized image dengan Nuxt Image -->
|
|
612
|
+
<NuxtImg :src="product.image" width="400" height="300" loading="lazy" format="webp" />
|
|
613
|
+
<ProductCard :product="product" />
|
|
614
|
+
</template>
|
|
615
|
+
</UVirtualScroll>
|
|
616
|
+
|
|
617
|
+
<!-- Lazy load chart -->
|
|
618
|
+
<ClientOnly>
|
|
619
|
+
<HeavyChart v-if="showChart" :data="chartData" />
|
|
620
|
+
</ClientOnly>
|
|
621
|
+
</template>
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
**Results:**
|
|
625
|
+
|
|
626
|
+
- ✅ Bundle size reduced: 500KB → 200KB
|
|
627
|
+
- ✅ First Contentful Paint: 3.5s → 1.2s
|
|
628
|
+
- ✅ Lighthouse Performance: 65 → 94
|
|
629
|
+
- ✅ Images optimized with WebP format
|
|
630
|
+
- ✅ Code splitting implemented
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## 7. Accessibility Review
|
|
635
|
+
|
|
636
|
+
### Skenario: Audit Existing Component
|
|
637
|
+
|
|
638
|
+
**Prompt:**
|
|
639
|
+
|
|
640
|
+
```
|
|
641
|
+
@frontend Review accessibility untuk component app/components/Modal.vue
|
|
642
|
+
Target: WCAG 2.1 Level AA compliance
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
**Agent akan:**
|
|
646
|
+
|
|
647
|
+
1. ✅ Load skill `web-design-guidelines`
|
|
648
|
+
2. ✅ Check semantic HTML
|
|
649
|
+
3. ✅ Verify ARIA attributes
|
|
650
|
+
4. ✅ Test keyboard navigation
|
|
651
|
+
5. ✅ Check color contrast
|
|
652
|
+
6. ✅ Provide detailed report
|
|
653
|
+
|
|
654
|
+
**Audit Report Example:**
|
|
655
|
+
|
|
656
|
+
````markdown
|
|
657
|
+
# Accessibility Audit: Modal.vue
|
|
658
|
+
|
|
659
|
+
## Issues Found (6)
|
|
660
|
+
|
|
661
|
+
### Critical
|
|
662
|
+
|
|
663
|
+
1. ❌ Missing `role="dialog"` on modal container
|
|
664
|
+
2. ❌ No focus trap - keyboard navigation escapes modal
|
|
665
|
+
3. ❌ Missing `aria-labelledby` and `aria-describedby`
|
|
666
|
+
|
|
667
|
+
### Warning
|
|
668
|
+
|
|
669
|
+
4. ⚠️ Close button lacks accessible label
|
|
670
|
+
5. ⚠️ Background color contrast 3.2:1 (needs 4.5:1)
|
|
671
|
+
|
|
672
|
+
### Info
|
|
673
|
+
|
|
674
|
+
6. ℹ️ Consider adding focus restoration on close
|
|
675
|
+
|
|
676
|
+
## Recommended Fixes
|
|
677
|
+
|
|
678
|
+
### 1. Add proper ARIA attributes
|
|
679
|
+
|
|
680
|
+
```vue
|
|
681
|
+
<template>
|
|
682
|
+
<div role="dialog" aria-modal="true" aria-labelledby="modal-title" aria-describedby="modal-desc">
|
|
683
|
+
<h2 id="modal-title">{{ title }}</h2>
|
|
684
|
+
<p id="modal-desc">{{ description }}</p>
|
|
685
|
+
</div>
|
|
686
|
+
</template>
|
|
687
|
+
```
|
|
688
|
+
````
|
|
689
|
+
|
|
690
|
+
### 2. Implement focus trap
|
|
691
|
+
|
|
692
|
+
```typescript
|
|
693
|
+
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
|
|
694
|
+
|
|
695
|
+
const modalRef = ref<HTMLElement>()
|
|
696
|
+
const { activate, deactivate } = useFocusTrap(modalRef)
|
|
697
|
+
|
|
698
|
+
watch(isOpen, (open) => {
|
|
699
|
+
if (open) activate()
|
|
700
|
+
else deactivate()
|
|
701
|
+
})
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### 3. Add accessible close button
|
|
705
|
+
|
|
706
|
+
```vue
|
|
707
|
+
<UButton icon="i-heroicons-x-mark" aria-label="Close modal" @click="close" />
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
## After Fixes
|
|
711
|
+
|
|
712
|
+
✅ All WCAG 2.1 Level AA criteria met
|
|
713
|
+
✅ Keyboard navigation: Tab, Shift+Tab, Escape
|
|
714
|
+
✅ Screen reader friendly
|
|
715
|
+
✅ Color contrast: 7.8:1
|
|
716
|
+
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
---
|
|
720
|
+
|
|
721
|
+
## 8. Bug Fixing
|
|
722
|
+
|
|
723
|
+
### Skenario: Fix Hydration Mismatch
|
|
724
|
+
|
|
725
|
+
**Prompt:**
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
@frontend Ada error hydration mismatch di homepage:
|
|
729
|
+
"Hydration completed but contains mismatches."
|
|
730
|
+
|
|
731
|
+
Error terjadi di section hero dengan dynamic timestamp.
|
|
732
|
+
|
|
733
|
+
````
|
|
734
|
+
|
|
735
|
+
**Agent akan:**
|
|
736
|
+
1. ✅ Load skill `frontend-patterns`
|
|
737
|
+
2. ✅ Analyze SSR/CSR differences
|
|
738
|
+
3. ✅ Identify root cause
|
|
739
|
+
4. ✅ Provide fix dengan explanation
|
|
740
|
+
5. ✅ Add preventive measures
|
|
741
|
+
|
|
742
|
+
**Diagnosis:**
|
|
743
|
+
```markdown
|
|
744
|
+
# Hydration Mismatch Analysis
|
|
745
|
+
|
|
746
|
+
## Root Cause
|
|
747
|
+
Timestamp generated differently on server vs client:
|
|
748
|
+
- Server: Uses UTC time
|
|
749
|
+
- Client: Uses local timezone
|
|
750
|
+
|
|
751
|
+
## Code Causing Issue
|
|
752
|
+
```vue
|
|
753
|
+
<template>
|
|
754
|
+
<p>Last updated: {{ new Date().toLocaleString() }}</p>
|
|
755
|
+
</template>
|
|
756
|
+
````
|
|
757
|
+
|
|
758
|
+
## Fix
|
|
759
|
+
|
|
760
|
+
```vue
|
|
761
|
+
<script setup lang="ts">
|
|
762
|
+
// Option 1: Client-only rendering
|
|
763
|
+
const timestamp = ref('')
|
|
764
|
+
|
|
765
|
+
onMounted(() => {
|
|
766
|
+
timestamp.value = new Date().toLocaleString()
|
|
767
|
+
})
|
|
768
|
+
</script>
|
|
769
|
+
|
|
770
|
+
<template>
|
|
771
|
+
<ClientOnly fallback="Loading...">
|
|
772
|
+
<p>Last updated: {{ timestamp }}</p>
|
|
773
|
+
</ClientOnly>
|
|
774
|
+
</template>
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
```vue
|
|
778
|
+
<!-- Option 2: Use consistent format -->
|
|
779
|
+
<script setup lang="ts">
|
|
780
|
+
const timestamp = new Date().toISOString()
|
|
781
|
+
</script>
|
|
782
|
+
|
|
783
|
+
<template>
|
|
784
|
+
<p>Last updated: {{ timestamp }}</p>
|
|
785
|
+
</template>
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
## Prevention
|
|
789
|
+
|
|
790
|
+
- ✅ Always use ClientOnly for browser APIs
|
|
791
|
+
- ✅ Use ISO format untuk dates
|
|
792
|
+
- ✅ Test with SSR enabled
|
|
793
|
+
- ✅ Add hydration tests
|
|
794
|
+
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
---
|
|
798
|
+
|
|
799
|
+
## Tips untuk Prompt yang Efektif
|
|
800
|
+
|
|
801
|
+
### ✅ Good Prompts
|
|
802
|
+
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
@frontend Build login form dengan email/password, validation, dan error handling
|
|
806
|
+
|
|
807
|
+
```
|
|
808
|
+
- Specific dan actionable
|
|
809
|
+
- Jelas output yang diharapkan
|
|
810
|
+
- Focused scope
|
|
811
|
+
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
@frontend Check accessibility untuk ProductCard component, target WCAG 2.1 AA
|
|
815
|
+
|
|
816
|
+
```
|
|
817
|
+
- Clear success criteria
|
|
818
|
+
- Specific component
|
|
819
|
+
- Defined standard
|
|
820
|
+
|
|
821
|
+
### ❌ Bad Prompts
|
|
822
|
+
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
@frontend Bantu saya
|
|
826
|
+
|
|
827
|
+
```
|
|
828
|
+
- Terlalu vague
|
|
829
|
+
- Tidak ada context
|
|
830
|
+
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
@frontend Build full e-commerce website
|
|
834
|
+
|
|
835
|
+
```
|
|
836
|
+
- Scope terlalu luas
|
|
837
|
+
- Perlu breakdown
|
|
838
|
+
|
|
839
|
+
### Best Practices
|
|
840
|
+
|
|
841
|
+
1. **Be Specific**: Sebutkan exact component/page/feature
|
|
842
|
+
2. **Provide Context**: Jika ada existing code, mention file path
|
|
843
|
+
3. **Set Standards**: Sebutkan requirements (accessibility, performance, etc.)
|
|
844
|
+
4. **Ask Questions**: Agent bisa tanya jika butuh clarification
|
|
845
|
+
5. **Iterate**: Start small, kemudian expand
|
|
846
|
+
|
|
847
|
+
---
|
|
848
|
+
|
|
849
|
+
## MCP Integration Examples
|
|
850
|
+
|
|
851
|
+
### Query Nuxt Documentation
|
|
852
|
+
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
@frontend Bagaimana cara implement custom error page di Nuxt 4?
|
|
856
|
+
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
Agent akan:
|
|
860
|
+
1. Query Nuxt MCP untuk error handling docs
|
|
861
|
+
2. Get latest Nuxt 4 patterns
|
|
862
|
+
3. Provide code example dengan explanation
|
|
863
|
+
|
|
864
|
+
### Check Nuxt UI Components
|
|
865
|
+
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
@frontend Apa komponen terbaik untuk notification system?
|
|
869
|
+
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
Agent akan:
|
|
873
|
+
1. Query Nuxt UI MCP untuk Toast/Notification components
|
|
874
|
+
2. Compare options (`<UNotification>` vs `<UToast>`)
|
|
875
|
+
3. Provide implementation recommendation
|
|
876
|
+
|
|
877
|
+
### Use Playwright for Testing
|
|
878
|
+
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
@frontend Create E2E test untuk login flow
|
|
882
|
+
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
Agent akan:
|
|
886
|
+
1. Use Playwright MCP untuk browser automation
|
|
887
|
+
2. Generate test script
|
|
888
|
+
3. Add assertions dan error cases
|
|
889
|
+
4. Setup test runners
|
|
890
|
+
|
|
891
|
+
---
|
|
892
|
+
|
|
893
|
+
## Common Workflows Cheatsheet
|
|
894
|
+
|
|
895
|
+
| Task | Prompt Example |
|
|
896
|
+
|------|----------------|
|
|
897
|
+
| Create Component | `@frontend Create Button component dengan variants primary/secondary` |
|
|
898
|
+
| Fix Bug | `@frontend Fix hydration error di app/pages/index.vue` |
|
|
899
|
+
| Add Feature | `@frontend Add dark mode toggle menggunakan Nuxt UI` |
|
|
900
|
+
| Optimize | `@frontend Optimize bundle size untuk /dashboard route` |
|
|
901
|
+
| Review | `@frontend Review accessibility untuk Modal component` |
|
|
902
|
+
| Test | `@frontend Add unit tests untuk useCart composable` |
|
|
903
|
+
| Document | `@frontend Add JSDoc comments untuk ProductCard props` |
|
|
904
|
+
| Refactor | `@frontend Refactor UserList component, extract reusable logic` |
|
|
905
|
+
|
|
906
|
+
---
|
|
907
|
+
|
|
908
|
+
## Troubleshooting
|
|
909
|
+
|
|
910
|
+
### Agent tidak load skill yang expected
|
|
911
|
+
|
|
912
|
+
**Solusi:**
|
|
913
|
+
- Explicitly mention skill: `@frontend Gunakan skill web-design-guidelines untuk review ini`
|
|
914
|
+
- Check skill available: List skills di `.opencode/skills/` dan `~/.opencode/skills/`
|
|
915
|
+
|
|
916
|
+
### MCP server tidak respond
|
|
917
|
+
|
|
918
|
+
**Solusi:**
|
|
919
|
+
- Check `.opencode/config.json` - pastikan `enabled: true`
|
|
920
|
+
- Restart OpenCode session
|
|
921
|
+
- Verify internet connection (untuk remote MCP)
|
|
922
|
+
|
|
923
|
+
### Agent terlalu verbose
|
|
924
|
+
|
|
925
|
+
**Solusi:**
|
|
926
|
+
- Add constraint: `@frontend (concise) Create button component`
|
|
927
|
+
- Request specific output: `@frontend Show only code, no explanation`
|
|
928
|
+
|
|
929
|
+
### Need Figma access
|
|
930
|
+
|
|
931
|
+
**Solusi:**
|
|
932
|
+
1. Get token dari https://www.figma.com/developers/api#access-tokens
|
|
933
|
+
2. Set `FIGMA_ACCESS_TOKEN` di `.env`
|
|
934
|
+
3. Enable di `.opencode/config.json`: `"enabled": true`
|
|
935
|
+
4. Restart session
|
|
936
|
+
|
|
937
|
+
---
|
|
938
|
+
|
|
939
|
+
## Next Steps
|
|
940
|
+
|
|
941
|
+
Setelah familiar dengan examples di atas:
|
|
942
|
+
|
|
943
|
+
1. **Explore Skills**: Check `~/.opencode/skills/` untuk available skills
|
|
944
|
+
2. **Read Workflows**: Baca `WORKFLOWS.md` untuk detailed workflows
|
|
945
|
+
3. **Check MCP Guide**: Read `MCP_GUIDE.md` untuk advanced MCP usage
|
|
946
|
+
4. **Practice**: Start dengan simple components, gradually increase complexity
|
|
947
|
+
5. **Contribute**: Share your own examples dan workflows dengan team
|
|
948
|
+
|
|
949
|
+
---
|
|
950
|
+
|
|
951
|
+
**Happy Coding! 🚀**
|
|
952
|
+
|
|
953
|
+
Untuk pertanyaan atau feedback:
|
|
954
|
+
- Check dokumentasi lengkap di `.opencode/agents/`
|
|
955
|
+
- Atau mention `@frontend` dengan pertanyaan Anda
|
|
956
|
+
```
|