@dewtech/dare-cli 2.16.0 → 3.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 +196 -3
- package/dist/__tests__/confidence.test.d.ts +2 -0
- package/dist/__tests__/confidence.test.d.ts.map +1 -0
- package/dist/__tests__/confidence.test.js +73 -0
- package/dist/__tests__/confidence.test.js.map +1 -0
- package/dist/__tests__/datamodel.test.d.ts +2 -0
- package/dist/__tests__/datamodel.test.d.ts.map +1 -0
- package/dist/__tests__/datamodel.test.js +131 -0
- package/dist/__tests__/datamodel.test.js.map +1 -0
- package/dist/__tests__/dna-detector.test.d.ts +2 -0
- package/dist/__tests__/dna-detector.test.d.ts.map +1 -0
- package/dist/__tests__/dna-detector.test.js +97 -0
- package/dist/__tests__/dna-detector.test.js.map +1 -0
- package/dist/__tests__/dna-facts.test.d.ts +2 -0
- package/dist/__tests__/dna-facts.test.d.ts.map +1 -0
- package/dist/__tests__/dna-facts.test.js +44 -0
- package/dist/__tests__/dna-facts.test.js.map +1 -0
- package/dist/__tests__/graph-renderer.test.d.ts +2 -0
- package/dist/__tests__/graph-renderer.test.d.ts.map +1 -0
- package/dist/__tests__/graph-renderer.test.js +85 -0
- package/dist/__tests__/graph-renderer.test.js.map +1 -0
- package/dist/__tests__/migration.test.d.ts +2 -0
- package/dist/__tests__/migration.test.d.ts.map +1 -0
- package/dist/__tests__/migration.test.js +77 -0
- package/dist/__tests__/migration.test.js.map +1 -0
- package/dist/__tests__/module-detector.test.d.ts +2 -0
- package/dist/__tests__/module-detector.test.d.ts.map +1 -0
- package/dist/__tests__/module-detector.test.js +83 -0
- package/dist/__tests__/module-detector.test.js.map +1 -0
- package/dist/__tests__/refine.test.d.ts +2 -0
- package/dist/__tests__/refine.test.d.ts.map +1 -0
- package/dist/__tests__/refine.test.js +186 -0
- package/dist/__tests__/refine.test.js.map +1 -0
- package/dist/__tests__/reverse-facts.test.d.ts +2 -0
- package/dist/__tests__/reverse-facts.test.d.ts.map +1 -0
- package/dist/__tests__/reverse-facts.test.js +78 -0
- package/dist/__tests__/reverse-facts.test.js.map +1 -0
- package/dist/__tests__/review.test.d.ts +2 -0
- package/dist/__tests__/review.test.d.ts.map +1 -0
- package/dist/__tests__/review.test.js +242 -0
- package/dist/__tests__/review.test.js.map +1 -0
- package/dist/__tests__/update.test.d.ts +2 -0
- package/dist/__tests__/update.test.d.ts.map +1 -0
- package/dist/__tests__/update.test.js +150 -0
- package/dist/__tests__/update.test.js.map +1 -0
- package/dist/__tests__/validate.test.js +65 -65
- package/dist/bin/dare.js +38 -3
- package/dist/bin/dare.js.map +1 -1
- package/dist/commands/blueprint.js +122 -122
- package/dist/commands/dag.d.ts.map +1 -1
- package/dist/commands/dag.js +43 -79
- package/dist/commands/dag.js.map +1 -1
- package/dist/commands/dna.d.ts +3 -0
- package/dist/commands/dna.d.ts.map +1 -0
- package/dist/commands/dna.js +69 -0
- package/dist/commands/dna.js.map +1 -0
- package/dist/commands/execute.d.ts.map +1 -1
- package/dist/commands/execute.js +76 -0
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/migrate.d.ts +3 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +101 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/new.d.ts +16 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +103 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/refine.d.ts +16 -0
- package/dist/commands/refine.d.ts.map +1 -0
- package/dist/commands/refine.js +167 -0
- package/dist/commands/refine.js.map +1 -0
- package/dist/commands/reverse.d.ts +3 -0
- package/dist/commands/reverse.d.ts.map +1 -0
- package/dist/commands/reverse.js +201 -0
- package/dist/commands/reverse.js.map +1 -0
- package/dist/commands/review.d.ts +16 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +106 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/update.d.ts +13 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +149 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/welcome.d.ts +14 -0
- package/dist/commands/welcome.d.ts.map +1 -0
- package/dist/commands/welcome.js +29 -0
- package/dist/commands/welcome.js.map +1 -0
- package/dist/skills/commands/add.d.ts +23 -0
- package/dist/skills/commands/add.d.ts.map +1 -0
- package/dist/skills/commands/add.js +206 -0
- package/dist/skills/commands/add.js.map +1 -0
- package/dist/skills/commands/info.d.ts +14 -0
- package/dist/skills/commands/info.d.ts.map +1 -0
- package/dist/skills/commands/info.js +99 -0
- package/dist/skills/commands/info.js.map +1 -0
- package/dist/skills/commands/list.d.ts +19 -0
- package/dist/skills/commands/list.d.ts.map +1 -0
- package/dist/skills/commands/list.js +163 -0
- package/dist/skills/commands/list.js.map +1 -0
- package/dist/skills/commands/publish.d.ts +56 -0
- package/dist/skills/commands/publish.d.ts.map +1 -0
- package/dist/skills/commands/publish.js +272 -0
- package/dist/skills/commands/publish.js.map +1 -0
- package/dist/skills/commands/remove.d.ts +19 -0
- package/dist/skills/commands/remove.d.ts.map +1 -0
- package/dist/skills/commands/remove.js +96 -0
- package/dist/skills/commands/remove.js.map +1 -0
- package/dist/skills/commands/update.d.ts +31 -0
- package/dist/skills/commands/update.d.ts.map +1 -0
- package/dist/skills/commands/update.js +132 -0
- package/dist/skills/commands/update.js.map +1 -0
- package/dist/skills/index.d.ts +22 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +33 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/manifest.d.ts +54 -0
- package/dist/skills/manifest.d.ts.map +1 -0
- package/dist/skills/manifest.js +162 -0
- package/dist/skills/manifest.js.map +1 -0
- package/dist/skills/registry-local.d.ts +67 -0
- package/dist/skills/registry-local.d.ts.map +1 -0
- package/dist/skills/registry-local.js +130 -0
- package/dist/skills/registry-local.js.map +1 -0
- package/dist/skills/registry-mock.json +109 -0
- package/dist/skills/registry-remote.d.ts +110 -0
- package/dist/skills/registry-remote.d.ts.map +1 -0
- package/dist/skills/registry-remote.js +246 -0
- package/dist/skills/registry-remote.js.map +1 -0
- package/dist/skills/registry.d.ts +49 -0
- package/dist/skills/registry.d.ts.map +1 -0
- package/dist/skills/registry.js +94 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/skills/tests/manifest.spec.d.ts +8 -0
- package/dist/skills/tests/manifest.spec.d.ts.map +1 -0
- package/dist/skills/tests/manifest.spec.js +176 -0
- package/dist/skills/tests/manifest.spec.js.map +1 -0
- package/dist/skills/tests/publish.spec.d.ts +12 -0
- package/dist/skills/tests/publish.spec.d.ts.map +1 -0
- package/dist/skills/tests/publish.spec.js +276 -0
- package/dist/skills/tests/publish.spec.js.map +1 -0
- package/dist/skills/tests/registry-local.spec.d.ts +8 -0
- package/dist/skills/tests/registry-local.spec.d.ts.map +1 -0
- package/dist/skills/tests/registry-local.spec.js +231 -0
- package/dist/skills/tests/registry-local.spec.js.map +1 -0
- package/dist/skills/tests/registry.spec.d.ts +7 -0
- package/dist/skills/tests/registry.spec.d.ts.map +1 -0
- package/dist/skills/tests/registry.spec.js +58 -0
- package/dist/skills/tests/registry.spec.js.map +1 -0
- package/dist/skills/tests/remote-registry.spec.d.ts +9 -0
- package/dist/skills/tests/remote-registry.spec.d.ts.map +1 -0
- package/dist/skills/tests/remote-registry.spec.js +357 -0
- package/dist/skills/tests/remote-registry.spec.js.map +1 -0
- package/dist/skills/tests/update.spec.d.ts +9 -0
- package/dist/skills/tests/update.spec.d.ts.map +1 -0
- package/dist/skills/tests/update.spec.js +166 -0
- package/dist/skills/tests/update.spec.js.map +1 -0
- package/dist/types/Refine.types.d.ts +96 -0
- package/dist/types/Refine.types.d.ts.map +1 -0
- package/dist/types/Refine.types.js +19 -0
- package/dist/types/Refine.types.js.map +1 -0
- package/dist/types/Review.types.d.ts +86 -0
- package/dist/types/Review.types.d.ts.map +1 -0
- package/dist/types/Review.types.js +15 -0
- package/dist/types/Review.types.js.map +1 -0
- package/dist/types/UpdateManifest.types.d.ts +91 -0
- package/dist/types/UpdateManifest.types.d.ts.map +1 -0
- package/dist/types/UpdateManifest.types.js +13 -0
- package/dist/types/UpdateManifest.types.js.map +1 -0
- package/dist/utils/ReviewRunner.d.ts +42 -0
- package/dist/utils/ReviewRunner.d.ts.map +1 -0
- package/dist/utils/ReviewRunner.js +175 -0
- package/dist/utils/ReviewRunner.js.map +1 -0
- package/dist/utils/UpdateApplier.d.ts +42 -0
- package/dist/utils/UpdateApplier.d.ts.map +1 -0
- package/dist/utils/UpdateApplier.js +207 -0
- package/dist/utils/UpdateApplier.js.map +1 -0
- package/dist/utils/UpdateDetector.d.ts +56 -0
- package/dist/utils/UpdateDetector.d.ts.map +1 -0
- package/dist/utils/UpdateDetector.js +164 -0
- package/dist/utils/UpdateDetector.js.map +1 -0
- package/dist/utils/banner.d.ts +28 -0
- package/dist/utils/banner.d.ts.map +1 -0
- package/dist/utils/banner.js +77 -0
- package/dist/utils/banner.js.map +1 -0
- package/dist/utils/banner.spec.d.ts +5 -0
- package/dist/utils/banner.spec.d.ts.map +1 -0
- package/dist/utils/banner.spec.js +253 -0
- package/dist/utils/banner.spec.js.map +1 -0
- package/dist/utils/complexity-analyzer.d.ts +60 -0
- package/dist/utils/complexity-analyzer.d.ts.map +1 -0
- package/dist/utils/complexity-analyzer.js +292 -0
- package/dist/utils/complexity-analyzer.js.map +1 -0
- package/dist/utils/confidence.d.ts +41 -0
- package/dist/utils/confidence.d.ts.map +1 -0
- package/dist/utils/confidence.js +101 -0
- package/dist/utils/confidence.js.map +1 -0
- package/dist/utils/datamodel.d.ts +41 -0
- package/dist/utils/datamodel.d.ts.map +1 -0
- package/dist/utils/datamodel.js +535 -0
- package/dist/utils/datamodel.js.map +1 -0
- package/dist/utils/dna-detector.d.ts +61 -0
- package/dist/utils/dna-detector.d.ts.map +1 -0
- package/dist/utils/dna-detector.js +354 -0
- package/dist/utils/dna-detector.js.map +1 -0
- package/dist/utils/dna-facts.d.ts +13 -0
- package/dist/utils/dna-facts.d.ts.map +1 -0
- package/dist/utils/dna-facts.js +109 -0
- package/dist/utils/dna-facts.js.map +1 -0
- package/dist/utils/excalidraw-renderer.d.ts +11 -71
- package/dist/utils/excalidraw-renderer.d.ts.map +1 -1
- package/dist/utils/excalidraw-renderer.js +29 -162
- package/dist/utils/excalidraw-renderer.js.map +1 -1
- package/dist/utils/graph-renderer.d.ts +115 -0
- package/dist/utils/graph-renderer.d.ts.map +1 -0
- package/dist/utils/graph-renderer.js +216 -0
- package/dist/utils/graph-renderer.js.map +1 -0
- package/dist/utils/migration.d.ts +64 -0
- package/dist/utils/migration.d.ts.map +1 -0
- package/dist/utils/migration.js +183 -0
- package/dist/utils/migration.js.map +1 -0
- package/dist/utils/module-detector.d.ts +46 -0
- package/dist/utils/module-detector.d.ts.map +1 -0
- package/dist/utils/module-detector.js +348 -0
- package/dist/utils/module-detector.js.map +1 -0
- package/dist/utils/project-generator.d.ts.map +1 -1
- package/dist/utils/project-generator.js +273 -254
- package/dist/utils/project-generator.js.map +1 -1
- package/dist/utils/reverse-facts.d.ts +50 -0
- package/dist/utils/reverse-facts.d.ts.map +1 -0
- package/dist/utils/reverse-facts.js +291 -0
- package/dist/utils/reverse-facts.js.map +1 -0
- package/dist/utils/stack-bootstrap.js +371 -371
- package/dist/utils/static-analyzer.d.ts +29 -0
- package/dist/utils/static-analyzer.d.ts.map +1 -0
- package/dist/utils/static-analyzer.js +390 -0
- package/dist/utils/static-analyzer.js.map +1 -0
- package/dist/utils/version-compare.d.ts +27 -0
- package/dist/utils/version-compare.d.ts.map +1 -0
- package/dist/utils/version-compare.js +47 -0
- package/dist/utils/version-compare.js.map +1 -0
- package/package.json +8 -3
- package/templates/DARE-dag-example.yaml +280 -280
- package/templates/UPDATE-MANIFEST.json +48 -0
- package/templates/backend/node-nestjs/.env.example +9 -9
- package/templates/backend/node-nestjs/nest-cli.json +8 -8
- package/templates/backend/node-nestjs/package.json +50 -50
- package/templates/backend/node-nestjs/src/app.controller.ts +12 -12
- package/templates/backend/node-nestjs/src/app.module.ts +15 -15
- package/templates/backend/node-nestjs/src/app.service.ts +8 -8
- package/templates/backend/node-nestjs/src/main.ts +24 -24
- package/templates/backend/node-nestjs/tsconfig.json +21 -21
- package/templates/backend/php-laravel/.env.example +22 -22
- package/templates/backend/php-laravel/app/Http/Controllers/HealthController.php +15 -15
- package/templates/backend/php-laravel/composer.json +40 -40
- package/templates/backend/python-fastapi/.env.example +4 -4
- package/templates/backend/python-fastapi/app/api/router.py +8 -8
- package/templates/backend/python-fastapi/app/core/config.py +20 -20
- package/templates/backend/python-fastapi/main.py +35 -35
- package/templates/backend/python-fastapi/requirements.txt +13 -13
- package/templates/backend/rust-axum/.env.example +3 -3
- package/templates/backend/rust-axum/Cargo.toml +23 -23
- package/templates/backend/rust-axum/src/errors.rs +30 -30
- package/templates/backend/rust-axum/src/main.rs +32 -32
- package/templates/backend/rust-axum/src/routes.rs +6 -6
- package/templates/frontend/leptos-csr/.cargo/config.toml +2 -2
- package/templates/frontend/leptos-csr/Cargo.toml +16 -16
- package/templates/frontend/leptos-csr/Trunk.toml +10 -10
- package/templates/frontend/leptos-csr/index.html +11 -11
- package/templates/frontend/leptos-csr/src/lib.rs +20 -20
- package/templates/frontend/leptos-csr/style/main.scss +19 -19
- package/templates/frontend/leptos-fullstack/.cargo/config.toml +4 -4
- package/templates/frontend/leptos-fullstack/Cargo.toml +56 -56
- package/templates/frontend/leptos-fullstack/src/app.rs +49 -49
- package/templates/frontend/leptos-fullstack/src/lib.rs +9 -9
- package/templates/frontend/leptos-fullstack/src/main.rs +29 -29
- package/templates/frontend/leptos-fullstack/style/main.scss +19 -19
- package/templates/frontend/react/index.html +12 -12
- package/templates/frontend/react/package.json +35 -35
- package/templates/frontend/react/src/App.tsx +25 -25
- package/templates/frontend/react/src/main.tsx +9 -9
- package/templates/frontend/vue/package.json +32 -32
- package/templates/frontend/vue/src/App.vue +7 -7
- package/templates/frontend/vue/src/main.ts +10 -10
- package/templates/frontend/vue/src/router/index.ts +14 -14
- package/templates/frontend/vue/src/views/HomeView.vue +6 -6
- package/templates/hooks/pre-commit-dare-validate +24 -24
- package/templates/ide/antigravity/.agents/skills/dare-ax/SKILL.md +152 -0
- package/templates/ide/antigravity/.agents/skills/dare-blueprint/SKILL.md +180 -36
- package/templates/ide/antigravity/.agents/skills/dare-dag-build/SKILL.md +154 -0
- package/templates/ide/antigravity/.agents/skills/dare-dag-run/SKILL.md +130 -0
- package/templates/ide/antigravity/.agents/skills/dare-dag-runner/SKILL.md +203 -203
- package/templates/ide/antigravity/.agents/skills/dare-dna/SKILL.md +63 -0
- package/templates/ide/antigravity/.agents/skills/dare-docker/SKILL.md +315 -0
- package/templates/ide/antigravity/.agents/skills/dare-frontend-design/SKILL.md +192 -0
- package/templates/ide/antigravity/.agents/skills/dare-laravel-api/SKILL.md +337 -0
- package/templates/ide/antigravity/.agents/skills/dare-layered-design/SKILL.md +166 -0
- package/templates/ide/antigravity/.agents/skills/dare-llm-integration/SKILL.md +217 -0
- package/templates/ide/antigravity/.agents/skills/dare-migrate/SKILL.md +61 -0
- package/templates/ide/antigravity/.agents/skills/dare-quality-telemetry/SKILL.md +187 -0
- package/templates/ide/antigravity/.agents/skills/dare-realtime/SKILL.md +217 -0
- package/templates/ide/antigravity/.agents/skills/dare-refine/SKILL.md +114 -0
- package/templates/ide/antigravity/.agents/skills/dare-reverse/SKILL.md +108 -0
- package/templates/ide/antigravity/.agents/skills/dare-review/SKILL.md +111 -0
- package/templates/ide/antigravity/.agents/skills/dare-rust-leptos/SKILL.md +263 -0
- package/templates/ide/antigravity/.agents/skills/dare-rust-workspace/SKILL.md +275 -275
- package/templates/ide/antigravity/.agents/skills/dare-security/SKILL.md +274 -0
- package/templates/ide/antigravity/.agents/skills/dare-tasks/SKILL.md +265 -224
- package/templates/ide/antigravity/.agents/skills/dare-telemetry/SKILL.md +188 -0
- package/templates/ide/antigravity/.agents/skills/skill-fastapi-api/SKILL.md +343 -0
- package/templates/ide/antigravity/.agents/skills/skill-go-gin-api/SKILL.md +377 -0
- package/templates/ide/antigravity/.agents/skills/skill-mcp-server/SKILL.md +382 -0
- package/templates/ide/antigravity/.agents/skills/skill-nestjs-api/SKILL.md +326 -0
- package/templates/ide/antigravity/.agents/skills/skill-rails-api/SKILL.md +393 -0
- package/templates/ide/antigravity/templates/BLUEPRINT-template.md +193 -193
- package/templates/ide/antigravity/templates/DESIGN-template.md +129 -129
- package/templates/ide/antigravity/templates/TASK-SPEC-template.md +141 -100
- package/templates/ide/claude/.claude/commands/dare-ax.md +131 -0
- package/templates/ide/claude/.claude/commands/dare-blueprint.md +134 -78
- package/templates/ide/claude/.claude/commands/dare-bugfix-design.md +119 -0
- package/templates/ide/claude/.claude/commands/dare-dag-build.md +151 -110
- package/templates/ide/claude/.claude/commands/dare-dag-run.md +109 -109
- package/templates/ide/claude/.claude/commands/dare-dag-runner.md +117 -0
- package/templates/ide/claude/.claude/commands/dare-dag-viz.md +197 -197
- package/templates/ide/claude/.claude/commands/dare-design.md +69 -69
- package/templates/ide/claude/.claude/commands/dare-dna.md +75 -0
- package/templates/ide/claude/.claude/commands/dare-docker.md +207 -0
- package/templates/ide/claude/.claude/commands/dare-execute.md +152 -152
- package/templates/ide/claude/.claude/commands/dare-feature-design.md +147 -0
- package/templates/ide/claude/.claude/commands/dare-frontend-design.md +149 -0
- package/templates/ide/claude/.claude/commands/dare-laravel-api.md +211 -0
- package/templates/ide/claude/.claude/commands/dare-layered-design.md +124 -0
- package/templates/ide/claude/.claude/commands/dare-llm-integration.md +148 -0
- package/templates/ide/claude/.claude/commands/dare-migrate.md +72 -0
- package/templates/ide/claude/.claude/commands/dare-quality-telemetry.md +166 -0
- package/templates/ide/claude/.claude/commands/dare-realtime.md +159 -0
- package/templates/ide/claude/.claude/commands/dare-refine.md +145 -0
- package/templates/ide/claude/.claude/commands/dare-reverse.md +139 -0
- package/templates/ide/claude/.claude/commands/dare-review.md +113 -0
- package/templates/ide/claude/.claude/commands/dare-rust-leptos.md +269 -269
- package/templates/ide/claude/.claude/commands/dare-rust-workspace.md +209 -209
- package/templates/ide/claude/.claude/commands/dare-security.md +232 -232
- package/templates/ide/claude/.claude/commands/dare-tasks.md +70 -70
- package/templates/ide/claude/.claude/commands/dare-telemetry.md +132 -0
- package/templates/ide/claude/.claude/commands/skill-fastapi-api.md +205 -0
- package/templates/ide/claude/.claude/commands/skill-go-gin-api.md +232 -0
- package/templates/ide/claude/.claude/commands/skill-mcp-server.md +228 -0
- package/templates/ide/claude/.claude/commands/skill-nestjs-api.md +210 -0
- package/templates/ide/claude/.claude/commands/skill-rails-api.md +236 -0
- package/templates/ide/claude/.claude/settings.example.json +35 -35
- package/templates/ide/claude/CLAUDE.md +146 -146
- package/templates/ide/claude/templates/BLUEPRINT-template.md +193 -193
- package/templates/ide/claude/templates/DESIGN-template.md +129 -129
- package/templates/ide/claude/templates/TASK-SPEC-template.md +141 -100
- package/templates/ide/cursor/.cursor/commands/dag-viz.md +139 -0
- package/templates/ide/cursor/.cursor/commands/generate-blueprint.md +86 -41
- package/templates/ide/cursor/.cursor/commands/generate-design.md +35 -35
- package/templates/ide/cursor/.cursor/commands/generate-tasks.md +184 -142
- package/templates/ide/cursor/.cursor/commands/refine-task.md +107 -0
- package/templates/ide/cursor/.cursor/commands/review-task.md +91 -0
- package/templates/ide/cursor/.cursor/commands/run-dag.md +110 -110
- package/templates/ide/cursor/.cursor/rules/skill-ax.mdc +263 -0
- package/templates/ide/cursor/.cursor/rules/skill-dag-build.mdc +173 -0
- package/templates/ide/cursor/.cursor/rules/skill-dag-run.mdc +134 -0
- package/templates/ide/cursor/.cursor/rules/skill-dag-runner.mdc +221 -221
- package/templates/ide/cursor/.cursor/rules/skill-dna.mdc +63 -0
- package/templates/ide/cursor/.cursor/rules/skill-fastapi-api.mdc +352 -0
- package/templates/ide/cursor/.cursor/rules/skill-frontend-design.mdc +244 -0
- package/templates/ide/cursor/.cursor/rules/skill-go-gin-api.mdc +371 -0
- package/templates/ide/cursor/.cursor/rules/skill-layered-design.mdc +266 -0
- package/templates/ide/cursor/.cursor/rules/skill-llm-integration.mdc +295 -0
- package/templates/ide/cursor/.cursor/rules/skill-mcp-server.mdc +367 -0
- package/templates/ide/cursor/.cursor/rules/skill-migrate.mdc +58 -0
- package/templates/ide/cursor/.cursor/rules/skill-nestjs-api.mdc +346 -0
- package/templates/ide/cursor/.cursor/rules/skill-quality-telemetry.mdc +248 -0
- package/templates/ide/cursor/.cursor/rules/skill-rails-api.mdc +400 -0
- package/templates/ide/cursor/.cursor/rules/skill-realtime.mdc +262 -0
- package/templates/ide/cursor/.cursor/rules/skill-reverse.mdc +107 -0
- package/templates/ide/cursor/.cursor/rules/skill-rust-leptos.mdc +281 -0
- package/templates/ide/cursor/.cursor/rules/skill-rust-workspace.mdc +312 -312
- package/templates/ide/cursor/.cursor/rules/skill-security.mdc +245 -245
- package/templates/ide/cursor/templates/BLUEPRINT-template.md +193 -193
- package/templates/ide/cursor/templates/DESIGN-template.md +129 -129
- package/templates/ide/cursor/templates/TASK-SPEC-template.md +141 -100
- package/templates/shared/docker-compose.yml +41 -41
- package/dist/__tests__/dag-runner/adapters.test.d.ts +0 -2
- package/dist/__tests__/dag-runner/adapters.test.d.ts.map +0 -1
- package/dist/__tests__/dag-runner/adapters.test.js +0 -134
- package/dist/__tests__/dag-runner/adapters.test.js.map +0 -1
- package/dist/dag-runner/adapters/antigravity.d.ts +0 -6
- package/dist/dag-runner/adapters/antigravity.d.ts.map +0 -1
- package/dist/dag-runner/adapters/antigravity.js +0 -54
- package/dist/dag-runner/adapters/antigravity.js.map +0 -1
- package/dist/dag-runner/adapters/claude.d.ts +0 -6
- package/dist/dag-runner/adapters/claude.d.ts.map +0 -1
- package/dist/dag-runner/adapters/claude.js +0 -48
- package/dist/dag-runner/adapters/claude.js.map +0 -1
- package/dist/dag-runner/adapters/cursor.d.ts +0 -6
- package/dist/dag-runner/adapters/cursor.d.ts.map +0 -1
- package/dist/dag-runner/adapters/cursor.js +0 -58
- package/dist/dag-runner/adapters/cursor.js.map +0 -1
- package/dist/dag-runner/adapters/index.d.ts +0 -46
- package/dist/dag-runner/adapters/index.d.ts.map +0 -1
- package/dist/dag-runner/adapters/index.js +0 -55
- package/dist/dag-runner/adapters/index.js.map +0 -1
- package/dist/dag-runner/utils/timeout.d.ts +0 -27
- package/dist/dag-runner/utils/timeout.d.ts.map +0 -1
- package/dist/dag-runner/utils/timeout.js +0 -55
- package/dist/dag-runner/utils/timeout.js.map +0 -1
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Padrões DARE para APIs REST em Python + FastAPI + Pydantic v2 + SQLAlchemy 2.0 async + alembic. Routers, dependency injection, schemas Pydantic, OAuth2+JWT, slowapi rate limit, pytest+httpx, OpenAPI auto-gerado.
|
|
3
|
+
globs: **/*.py,pyproject.toml,requirements.txt,alembic.ini,alembic/**/*.py
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: FastAPI API DARE
|
|
8
|
+
|
|
9
|
+
Você é um desenvolvedor sênior Python especialista em APIs REST com FastAPI. Esta skill garante código **assíncrono, fortemente tipado (Pydantic v2), com OpenAPI auto-gerado, auth/autz robustos**, seguindo Layered Design DARE.
|
|
10
|
+
|
|
11
|
+
## Stack canônica
|
|
12
|
+
|
|
13
|
+
- **Python 3.11+** com type hints obrigatórios
|
|
14
|
+
- **FastAPI 0.115+** com async/await
|
|
15
|
+
- **Pydantic v2** para schemas
|
|
16
|
+
- **SQLAlchemy 2.0** async + **asyncpg** (PostgreSQL)
|
|
17
|
+
- **alembic** para migrations
|
|
18
|
+
- **passlib + argon2** para hash de senhas
|
|
19
|
+
- **python-jose** ou **PyJWT** para JWT
|
|
20
|
+
- **slowapi** para rate limiting
|
|
21
|
+
- **pytest + pytest-asyncio + httpx**
|
|
22
|
+
- **ruff** (lint + format) + **mypy**
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Estrutura de pastas
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
app/
|
|
30
|
+
├── main.py ← FastAPI app + middlewares
|
|
31
|
+
├── core/
|
|
32
|
+
│ ├── config.py ← pydantic-settings
|
|
33
|
+
│ └── security.py ← hash, JWT
|
|
34
|
+
├── api/
|
|
35
|
+
│ ├── deps.py ← Depends() comuns
|
|
36
|
+
│ └── v1/
|
|
37
|
+
│ ├── users.py ← Handler (router)
|
|
38
|
+
│ └── auth.py
|
|
39
|
+
├── services/ ← Service layer
|
|
40
|
+
├── repositories/ ← Repository layer
|
|
41
|
+
├── models/ ← SQLAlchemy ORM
|
|
42
|
+
├── schemas/ ← Pydantic DTOs
|
|
43
|
+
└── tests/
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Routers (Handler)
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from fastapi import APIRouter, Depends, HTTPException, status
|
|
52
|
+
from app.api.deps import get_current_user
|
|
53
|
+
from app.schemas.user import UserCreate, UserOut
|
|
54
|
+
from app.services.register_user import RegisterUser, UserAlreadyExistsError
|
|
55
|
+
|
|
56
|
+
router = APIRouter(prefix="/users", tags=["users"])
|
|
57
|
+
|
|
58
|
+
@router.post("", response_model=UserOut, status_code=status.HTTP_201_CREATED)
|
|
59
|
+
async def create_user(
|
|
60
|
+
payload: UserCreate,
|
|
61
|
+
service: RegisterUser = Depends(),
|
|
62
|
+
_current: User = Depends(get_current_user),
|
|
63
|
+
):
|
|
64
|
+
try:
|
|
65
|
+
return await service.execute(payload)
|
|
66
|
+
except UserAlreadyExistsError:
|
|
67
|
+
raise HTTPException(status_code=409, detail="User already exists")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Regras:
|
|
71
|
+
- Apenas: valida via Pydantic → chama Service → retorna response_model
|
|
72
|
+
- NUNCA: SQLAlchemy direto, lógica de negócio, validação manual
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Schemas (Pydantic v2)
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from pydantic import BaseModel, EmailStr, Field
|
|
80
|
+
from datetime import datetime
|
|
81
|
+
|
|
82
|
+
class UserCreate(BaseModel):
|
|
83
|
+
email: EmailStr
|
|
84
|
+
name: str = Field(min_length=1, max_length=255)
|
|
85
|
+
password: str = Field(min_length=12)
|
|
86
|
+
|
|
87
|
+
class UserOut(BaseModel):
|
|
88
|
+
id: int
|
|
89
|
+
email: EmailStr
|
|
90
|
+
name: str
|
|
91
|
+
created_at: datetime
|
|
92
|
+
|
|
93
|
+
model_config = {"from_attributes": True} # Pydantic v2 substitui orm_mode
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Services
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
class UserAlreadyExistsError(Exception): ...
|
|
102
|
+
|
|
103
|
+
class RegisterUser:
|
|
104
|
+
def __init__(self, repo: UsersRepository = Depends()):
|
|
105
|
+
self.repo = repo
|
|
106
|
+
|
|
107
|
+
async def execute(self, payload: UserCreate) -> User:
|
|
108
|
+
if await self.repo.exists_by_email(payload.email):
|
|
109
|
+
raise UserAlreadyExistsError()
|
|
110
|
+
return await self.repo.create(
|
|
111
|
+
email=payload.email,
|
|
112
|
+
name=payload.name,
|
|
113
|
+
password_hash=hash_password(payload.password),
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Repositories (SQLAlchemy 2.0 async)
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from sqlalchemy import select
|
|
123
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
124
|
+
from fastapi import Depends
|
|
125
|
+
from app.api.deps import get_db
|
|
126
|
+
|
|
127
|
+
class UsersRepository:
|
|
128
|
+
def __init__(self, db: AsyncSession = Depends(get_db)):
|
|
129
|
+
self.db = db
|
|
130
|
+
|
|
131
|
+
async def exists_by_email(self, email: str) -> bool:
|
|
132
|
+
result = await self.db.execute(select(User.id).where(User.email == email))
|
|
133
|
+
return result.scalar_one_or_none() is not None
|
|
134
|
+
|
|
135
|
+
async def create(self, *, email: str, name: str, password_hash: str) -> User:
|
|
136
|
+
user = User(email=email, name=name, password_hash=password_hash)
|
|
137
|
+
self.db.add(user)
|
|
138
|
+
await self.db.commit()
|
|
139
|
+
await self.db.refresh(user)
|
|
140
|
+
return user
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Models (SQLAlchemy 2.0)
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
149
|
+
from datetime import datetime
|
|
150
|
+
|
|
151
|
+
class Base(DeclarativeBase): ...
|
|
152
|
+
|
|
153
|
+
class User(Base):
|
|
154
|
+
__tablename__ = "users"
|
|
155
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
156
|
+
email: Mapped[str] = mapped_column(unique=True, index=True)
|
|
157
|
+
name: Mapped[str]
|
|
158
|
+
password_hash: Mapped[str]
|
|
159
|
+
created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Auth (OAuth2 + JWT)
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
# app/core/security.py
|
|
168
|
+
from passlib.hash import argon2
|
|
169
|
+
from datetime import datetime, timedelta
|
|
170
|
+
from jose import jwt
|
|
171
|
+
from app.core.config import settings
|
|
172
|
+
|
|
173
|
+
def hash_password(p: str) -> str: return argon2.hash(p)
|
|
174
|
+
def verify_password(p: str, h: str) -> bool: return argon2.verify(p, h)
|
|
175
|
+
|
|
176
|
+
def create_access_token(sub: str) -> str:
|
|
177
|
+
expire = datetime.utcnow() + timedelta(minutes=15)
|
|
178
|
+
return jwt.encode({"sub": sub, "exp": expire}, settings.JWT_SECRET, algorithm="HS256")
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
# app/api/deps.py
|
|
183
|
+
from fastapi.security import OAuth2PasswordBearer
|
|
184
|
+
|
|
185
|
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/v1/auth/login")
|
|
186
|
+
|
|
187
|
+
async def get_current_user(token: str = Depends(oauth2_scheme)) -> User:
|
|
188
|
+
try:
|
|
189
|
+
payload = jwt.decode(token, settings.JWT_SECRET, algorithms=["HS256"])
|
|
190
|
+
except JWTError:
|
|
191
|
+
raise HTTPException(status_code=401, detail="Invalid token")
|
|
192
|
+
...
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Rate limiting (slowapi)
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from slowapi import Limiter
|
|
201
|
+
from slowapi.util import get_remote_address
|
|
202
|
+
|
|
203
|
+
limiter = Limiter(key_func=get_remote_address)
|
|
204
|
+
app.state.limiter = limiter
|
|
205
|
+
app.add_middleware(SlowAPIMiddleware)
|
|
206
|
+
|
|
207
|
+
@router.post("/login")
|
|
208
|
+
@limiter.limit("5/15minute")
|
|
209
|
+
async def login(request: Request, ...):
|
|
210
|
+
...
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## OpenAPI
|
|
216
|
+
|
|
217
|
+
FastAPI auto-gera em `/openapi.json`. Customize:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
app = FastAPI(
|
|
221
|
+
title="Projeto API",
|
|
222
|
+
version="1.0",
|
|
223
|
+
openapi_url="/openapi.json",
|
|
224
|
+
docs_url="/docs",
|
|
225
|
+
redoc_url="/redoc",
|
|
226
|
+
)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Settings (pydantic-settings)
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
235
|
+
|
|
236
|
+
class Settings(BaseSettings):
|
|
237
|
+
DATABASE_URL: str
|
|
238
|
+
JWT_SECRET: str
|
|
239
|
+
JWT_EXPIRE_MINUTES: int = 15
|
|
240
|
+
model_config = SettingsConfigDict(env_file=".env")
|
|
241
|
+
|
|
242
|
+
settings = Settings()
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Testes (pytest + httpx)
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
import pytest
|
|
251
|
+
from httpx import AsyncClient
|
|
252
|
+
|
|
253
|
+
@pytest.mark.asyncio
|
|
254
|
+
async def test_create_user(client: AsyncClient, admin_token: str):
|
|
255
|
+
response = await client.post(
|
|
256
|
+
"/v1/users",
|
|
257
|
+
json={"email": "jane@example.com", "name": "Jane", "password": "longsecret123"},
|
|
258
|
+
headers={"Authorization": f"Bearer {admin_token}"},
|
|
259
|
+
)
|
|
260
|
+
assert response.status_code == 201
|
|
261
|
+
assert response.json()["email"] == "jane@example.com"
|
|
262
|
+
|
|
263
|
+
@pytest.mark.asyncio
|
|
264
|
+
async def test_duplicate_email(client, admin_token):
|
|
265
|
+
await client.post("/v1/users", json={...}, headers={...})
|
|
266
|
+
response = await client.post("/v1/users", json={...}, headers={...})
|
|
267
|
+
assert response.status_code == 409
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Antipatterns
|
|
273
|
+
|
|
274
|
+
| AP | Antipattern | Correção |
|
|
275
|
+
|---|---|---|
|
|
276
|
+
| AP-01 | SQLAlchemy direto no router | Repository injetado via Depends |
|
|
277
|
+
| AP-02 | Validação manual no router | Pydantic schema |
|
|
278
|
+
| AP-03 | Lógica no router | Service |
|
|
279
|
+
| AP-04 | `return user` (ORM) sem response_model | `response_model=UserOut` |
|
|
280
|
+
| AP-05 | Secret hardcoded | pydantic-settings + .env |
|
|
281
|
+
| AP-06 | Login sem rate limit | `@limiter.limit("5/15minute")` |
|
|
282
|
+
| AP-07 | Senha em response | response_model sem password |
|
|
283
|
+
| AP-08 | Sem `from_attributes=True` | adicionar no model_config |
|
|
284
|
+
| AP-09 | `db.execute` sem await | sempre `await db.execute(...)` |
|
|
285
|
+
| AP-10 | Mistura sync/async no router | tudo `async def` |
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Segurança
|
|
290
|
+
|
|
291
|
+
- Senhas: `argon2.hash()` (passlib)
|
|
292
|
+
- JWT: HS256 com `JWT_SECRET ≥ 32 bytes`, ou RS256 com par de chaves
|
|
293
|
+
- Headers: middleware com HSTS, X-Frame-Options, CSP
|
|
294
|
+
- CORS específico, nunca `*`
|
|
295
|
+
- Rate limit em login + APIs públicas
|
|
296
|
+
- Refresh token com rotação no DB
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## CI
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
ruff check .
|
|
304
|
+
ruff format --check .
|
|
305
|
+
mypy app
|
|
306
|
+
pytest --cov=app --cov-fail-under=80
|
|
307
|
+
pip-audit
|
|
308
|
+
alembic upgrade head --sql > /dev/null
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Aplicação por fase DARE
|
|
314
|
+
|
|
315
|
+
### Design
|
|
316
|
+
- Endpoints REST com tags
|
|
317
|
+
- Schemas Pydantic de input/output
|
|
318
|
+
- Auth strategy
|
|
319
|
+
|
|
320
|
+
### Blueprint
|
|
321
|
+
- Estrutura de pastas
|
|
322
|
+
- SQLAlchemy models preliminares
|
|
323
|
+
- Roteamento `app.include_router(...)`
|
|
324
|
+
|
|
325
|
+
### Tasks
|
|
326
|
+
- Por feature: 4 tasks (Model, Schema, Repository, Service, Router)
|
|
327
|
+
- Task de configuração slowapi + auth + OpenAPI custom
|
|
328
|
+
|
|
329
|
+
### Execute
|
|
330
|
+
- Ralph Loop:
|
|
331
|
+
```bash
|
|
332
|
+
ruff check . && mypy app && pytest && pip-audit
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Checklist final
|
|
338
|
+
|
|
339
|
+
- [ ] Python 3.11+, ruff configurado
|
|
340
|
+
- [ ] Pydantic v2 com `model_config = {"from_attributes": True}` quando ORM
|
|
341
|
+
- [ ] SQLAlchemy 2.0 async com `Mapped[...]`
|
|
342
|
+
- [ ] Todos routers usam `response_model=`
|
|
343
|
+
- [ ] Services injetáveis via `Depends()`
|
|
344
|
+
- [ ] Repositories encapsulam SQLAlchemy
|
|
345
|
+
- [ ] `slowapi` em login + APIs públicas
|
|
346
|
+
- [ ] Settings via pydantic-settings + .env
|
|
347
|
+
- [ ] `mypy --strict` passa
|
|
348
|
+
- [ ] Cobertura ≥ 80%
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
Skill licenciada MIT — parte do DARE Method v3.
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Arquitetura frontend DARE para projetos React e Vue. Detecta god components (>300 linhas), fetch inline em JSX/template, garante error boundaries, loading states e bundle size monitorado.
|
|
3
|
+
globs: src/**/*.tsx,src/**/*.ts,src/**/*.jsx,src/**/*.js,src/**/*.vue,vite.config.ts,vite.config.js,webpack.config.js
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: Frontend Design DARE
|
|
8
|
+
|
|
9
|
+
Você é um arquiteto frontend especialista em React e Vue. Esta skill enforce arquitetura limpa em camadas no frontend, com **componentes pequenos, sem fetch inline, error boundaries explícitos e bundle monitorado**.
|
|
10
|
+
|
|
11
|
+
## Arquitetura recomendada
|
|
12
|
+
|
|
13
|
+
### React
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
┌──────────────────────────────────────────────────┐
|
|
17
|
+
│ Page (rota, layout) │ ← top-level
|
|
18
|
+
└──────────────────────────────────────────────────┘
|
|
19
|
+
↓ usa
|
|
20
|
+
┌──────────────────────────────────────────────────┐
|
|
21
|
+
│ Container (lógica + estado) │ ← orquestrador
|
|
22
|
+
└──────────────────────────────────────────────────┘
|
|
23
|
+
↓ injeta props
|
|
24
|
+
┌──────────────────────────────────────────────────┐
|
|
25
|
+
│ Presentational (puro, recebe props) │ ← visual
|
|
26
|
+
└──────────────────────────────────────────────────┘
|
|
27
|
+
|
|
28
|
+
┌──────────────────────────────────────────────────┐
|
|
29
|
+
│ Hook de dados (useUser, useOrders…) │ ← fetch + cache
|
|
30
|
+
└──────────────────────────────────────────────────┘
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Vue (Composition API)
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Page.vue
|
|
37
|
+
↓ usa
|
|
38
|
+
useUserData() (composable — fetch + reactive)
|
|
39
|
+
↓ injeta props
|
|
40
|
+
UserCard.vue (presentational)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## As 4 regras
|
|
46
|
+
|
|
47
|
+
### 1. Componente < 300 linhas (M-01)
|
|
48
|
+
|
|
49
|
+
Se um arquivo `.tsx`/`.vue` passar de 300 linhas, quebrar em:
|
|
50
|
+
- Sub-componentes lógicos
|
|
51
|
+
- Hook/composable separado para estado
|
|
52
|
+
- Helper para transformações de dados
|
|
53
|
+
|
|
54
|
+
### 2. Zero `fetch()` direto em JSX/template (M-02)
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
// ❌ Errado
|
|
58
|
+
function UserList() {
|
|
59
|
+
const [users, setUsers] = useState([]);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
fetch('/api/users').then(r => r.json()).then(setUsers);
|
|
62
|
+
}, []);
|
|
63
|
+
return <ul>{users.map(...)}</ul>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ✅ Certo — hook isolado e testável
|
|
67
|
+
function UserList() {
|
|
68
|
+
const { data, isLoading, error } = useUsers();
|
|
69
|
+
if (isLoading) return <Spinner />;
|
|
70
|
+
if (error) return <ErrorMessage error={error} />;
|
|
71
|
+
return <ul>{data.map(...)}</ul>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function useUsers() {
|
|
75
|
+
return useQuery({ queryKey: ['users'], queryFn: () => api.users.list() });
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Error Boundary em cada Page (M-03)
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
// React
|
|
83
|
+
class ErrorBoundary extends React.Component {
|
|
84
|
+
state = { error: null };
|
|
85
|
+
static getDerivedStateFromError(error: Error) { return { error }; }
|
|
86
|
+
componentDidCatch(error: Error, info: ErrorInfo) { logError(error, info); }
|
|
87
|
+
render() {
|
|
88
|
+
if (this.state.error) return this.props.fallback;
|
|
89
|
+
return this.props.children;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Wrap cada Page
|
|
94
|
+
<ErrorBoundary fallback={<ErrorPage />}>
|
|
95
|
+
<UsersPage />
|
|
96
|
+
</ErrorBoundary>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```vue
|
|
100
|
+
<!-- Vue -->
|
|
101
|
+
<script setup>
|
|
102
|
+
import { onErrorCaptured } from 'vue';
|
|
103
|
+
onErrorCaptured((err, instance, info) => {
|
|
104
|
+
logError(err, info);
|
|
105
|
+
return false; // stops propagation
|
|
106
|
+
});
|
|
107
|
+
</script>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 4. Bundle size monitorado (M-04)
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// vite.config.ts
|
|
114
|
+
import { visualizer } from 'rollup-plugin-visualizer';
|
|
115
|
+
|
|
116
|
+
export default defineConfig({
|
|
117
|
+
plugins: [
|
|
118
|
+
react(),
|
|
119
|
+
visualizer({ open: false, gzipSize: true, filename: 'dist/stats.html' }),
|
|
120
|
+
],
|
|
121
|
+
build: {
|
|
122
|
+
chunkSizeWarningLimit: 300, // KB
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Métricas (verificáveis em CI)
|
|
130
|
+
|
|
131
|
+
| ID | Métrica | Como medir |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| M-01 | 100% de componentes < 300 linhas | `wc -l` por arquivo, fail se >300 |
|
|
134
|
+
| M-02 | 0 `fetch()` direto em JSX/template | grep AST nos componentes |
|
|
135
|
+
| M-03 | 100% de páginas com error boundary | grep por `ErrorBoundary` ou `onErrorCaptured` |
|
|
136
|
+
| M-04 | Bundle config presente | `test -f vite.config.ts` + check de `chunkSizeWarningLimit` |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Antipatterns
|
|
141
|
+
|
|
142
|
+
| AP | Antipattern | Sinal | Correção |
|
|
143
|
+
|---|---|---|---|
|
|
144
|
+
| AP-01 | God component | >300 linhas | Quebrar em sub-componentes + hooks |
|
|
145
|
+
| AP-02 | Fetch em JSX | `useEffect(() => fetch())` | Hook customizado |
|
|
146
|
+
| AP-03 | Booleanos isLoading espalhados | `isLoading`, `isError`, `isSubmitting` separados | Discriminated union (`state: 'idle' \| 'loading' \| 'success' \| 'error'`) |
|
|
147
|
+
| AP-04 | Sem error boundary | erro derruba app | Wrap em `<ErrorBoundary>` |
|
|
148
|
+
| AP-05 | Estilo inline pesado | `style={{...30 props}}` | CSS Module / Tailwind / styled |
|
|
149
|
+
| AP-06 | Props drilling profundo | passa prop 5+ níveis | Context API ou Zustand/Pinia |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Stack recomendada
|
|
154
|
+
|
|
155
|
+
| Camada | React | Vue |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| Roteamento | React Router 7 / Next 14 / TanStack Router | Vue Router / Nuxt 3 |
|
|
158
|
+
| Estado server | TanStack Query | TanStack Vue Query / Pinia Colada |
|
|
159
|
+
| Estado client | Zustand / Jotai | Pinia |
|
|
160
|
+
| Forms | React Hook Form / TanStack Form | VeeValidate / TanStack Form |
|
|
161
|
+
| Styling | Tailwind + CSS Modules | Tailwind + SCSS |
|
|
162
|
+
| Testes | Vitest + Testing Library | Vitest + Testing Library |
|
|
163
|
+
| E2E | Playwright | Playwright |
|
|
164
|
+
| Bundler | Vite | Vite |
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Scaffold de página DARE-compliant
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
// src/pages/UsersPage.tsx
|
|
172
|
+
import { ErrorBoundary } from '@/components/ErrorBoundary';
|
|
173
|
+
import { UsersContainer } from '@/containers/UsersContainer';
|
|
174
|
+
|
|
175
|
+
export function UsersPage() {
|
|
176
|
+
return (
|
|
177
|
+
<ErrorBoundary fallback={<ErrorPage />}>
|
|
178
|
+
<UsersContainer />
|
|
179
|
+
</ErrorBoundary>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/containers/UsersContainer.tsx
|
|
184
|
+
import { useUsers } from '@/hooks/useUsers';
|
|
185
|
+
import { UserList } from '@/components/UserList';
|
|
186
|
+
|
|
187
|
+
export function UsersContainer() {
|
|
188
|
+
const { data, isLoading, error } = useUsers();
|
|
189
|
+
if (isLoading) return <Spinner />;
|
|
190
|
+
if (error) return <ErrorMessage error={error} />;
|
|
191
|
+
return <UserList users={data} />;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/components/UserList.tsx — presentational puro
|
|
195
|
+
export function UserList({ users }: { users: User[] }) {
|
|
196
|
+
return <ul>{users.map(u => <UserItem key={u.id} user={u} />)}</ul>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/hooks/useUsers.ts
|
|
200
|
+
export function useUsers() {
|
|
201
|
+
return useQuery({
|
|
202
|
+
queryKey: ['users'],
|
|
203
|
+
queryFn: () => api.users.list(),
|
|
204
|
+
staleTime: 60_000,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Aplicação por fase DARE
|
|
212
|
+
|
|
213
|
+
### Design
|
|
214
|
+
- Listar páginas/rotas no DESIGN.md
|
|
215
|
+
- Definir estados de cada rota (idle/loading/success/error)
|
|
216
|
+
|
|
217
|
+
### Blueprint
|
|
218
|
+
- Estrutura de pastas (`src/pages/`, `src/containers/`, `src/components/`, `src/hooks/`)
|
|
219
|
+
- Stack escolhida (React Query vs SWR, Zustand vs Redux, etc.)
|
|
220
|
+
|
|
221
|
+
### Tasks
|
|
222
|
+
- 1 task por página com 3 sub-tasks: Page, Container, Hook
|
|
223
|
+
- Task de configuração de Error Boundary global
|
|
224
|
+
- Task de configuração de bundle visualizer
|
|
225
|
+
|
|
226
|
+
### Execute
|
|
227
|
+
- Ralph Loop falha se: arquivo >300 linhas, `fetch()` em componente, página sem error boundary
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Checklist final
|
|
232
|
+
|
|
233
|
+
- [ ] Pastas `src/pages/`, `src/containers/`, `src/components/`, `src/hooks/`
|
|
234
|
+
- [ ] Todos os componentes < 300 linhas
|
|
235
|
+
- [ ] Zero `fetch()` direto em componente
|
|
236
|
+
- [ ] Cada Page tem `<ErrorBoundary>` ou `onErrorCaptured`
|
|
237
|
+
- [ ] `chunkSizeWarningLimit` configurado no bundler
|
|
238
|
+
- [ ] TanStack Query (ou equivalente) configurado
|
|
239
|
+
- [ ] Testes com Testing Library para Presentational
|
|
240
|
+
- [ ] Testes com mock do Hook para Container
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
Skill licenciada MIT — parte do DARE Method v3.
|