@bonesofspring/ai-rules 0.2.31 → 0.2.32
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/CHANGELOG.md +11 -0
- package/docs/LOCAL-OVERLAY.md +14 -0
- package/package.json +1 -1
- package/presets/claude/android-kotlin/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/claude/go/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/claude/ios-swift/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/claude/java/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/claude/mcp-ts/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/claude/next/REPO_AGENTS.md +11 -1
- package/presets/claude/next/agents/build-verifier.md +1 -0
- package/presets/claude/next/agents/code-reviewer.md +1 -0
- package/presets/claude/next/agents/feature-developer.md +1 -0
- package/presets/claude/next/agents/openspec-author.md +2 -0
- package/presets/claude/next/agents/task-analyst.md +7 -0
- package/presets/claude/next/agents/task-router.md +1 -0
- package/presets/claude/next/rules/README.md +3 -0
- package/presets/claude/next/rules/anti-hallucination/react-next-anti-hallucination.md +10 -0
- package/presets/claude/next/rules/api-and-data/store-rtk.md +6 -0
- package/presets/claude/next/rules/architecture/feature-delivery-workflow.md +5 -1
- package/presets/claude/next/rules/architecture/product-specs-authoring.md +1 -0
- package/presets/claude/next/rules/architecture/product-specs.md +1 -0
- package/presets/claude/next/rules/architecture/reference-features.md +5 -0
- package/presets/claude/next/rules/stack/next-app-core.md +3 -0
- package/presets/claude/next/rules/stack/next-static-export.md +36 -0
- package/presets/claude/next/rules/testing/tests-e2e-structure.md +1 -0
- package/presets/claude/next/rules/testing/tests-unit.md +1 -0
- package/presets/claude/next/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/claude/next/rules/tooling-and-review/ai-local-overlay.md +16 -2
- package/presets/claude/next/rules/tooling-and-review/code-review-mr.md +4 -0
- package/presets/claude/next/rules/tooling-and-review/mcp-usage.md +1 -0
- package/presets/claude/next/rules/tooling-and-review/post-change-lint.md +4 -0
- package/presets/claude/next/rules/tooling-and-review/security-next.md +13 -0
- package/presets/claude/next/rules/ui-and-accessibility/component-catalog-gate.md +39 -0
- package/presets/claude/next/rules/ui-and-accessibility/design-tokens-binding.md +1 -1
- package/presets/claude/next/rules/ui-and-accessibility/forms-validation.md +35 -0
- package/presets/claude/next/rules/ui-and-accessibility/react-ui.md +19 -1
- package/presets/claude/next/team/fixtures/feature-with-ux-no-figma.json +3 -4
- package/presets/claude/nuxt/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/claude/php-hexagonal/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/claude/php-laravel/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/claude/svelte/rules/tooling-and-review/agent-team-orchestrator.md +1 -2
- package/presets/cursor/android-kotlin/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/cursor/go/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/cursor/ios-swift/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/cursor/java/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/cursor/mcp-ts/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/cursor/next/REPO_AGENTS.md +11 -1
- package/presets/cursor/next/agents/build-verifier.md +1 -0
- package/presets/cursor/next/agents/code-reviewer.md +1 -0
- package/presets/cursor/next/agents/feature-developer.md +1 -0
- package/presets/cursor/next/agents/openspec-author.md +2 -0
- package/presets/cursor/next/agents/task-analyst.md +7 -0
- package/presets/cursor/next/agents/task-router.md +1 -0
- package/presets/cursor/next/ai-local/rules-library/agent-artifacts-no-local-paths.md +41 -8
- package/presets/cursor/next/ai-local/rules-library/agent-pipeline-gates.md +19 -0
- package/presets/cursor/next/ai-local/rules-library/analytics-events.md +18 -0
- package/presets/cursor/next/ai-local/rules-library/api-contract-source.md +14 -0
- package/presets/cursor/next/ai-local/rules-library/artifact-lifecycle.md +17 -0
- package/presets/cursor/next/ai-local/rules-library/code-style.md +68 -0
- package/presets/cursor/next/ai-local/rules-library/component-child-decomposition.md +81 -0
- package/presets/cursor/next/ai-local/rules-library/feature-flags-experiments.md +15 -0
- package/presets/cursor/next/ai-local/rules-library/mcp-required-for-ui-layout.md +1 -1
- package/presets/cursor/next/ai-local/rules-library/no-react-fc.md +46 -0
- package/presets/cursor/next/ai-local/rules-library/no-test-driven-behavior-change.md +1 -1
- package/presets/cursor/next/ai-local/rules-library/pwa-service-worker.md +15 -0
- package/presets/cursor/next/ai-local/rules-library/qa-test-cases.md +14 -0
- package/presets/cursor/next/ai-local/rules-library/router-pages.md +4 -2
- package/presets/cursor/next/ai-local/rules-library/single-source-copy-constants.md +3 -1
- package/presets/cursor/next/ai-local/rules-library/storybook-catalog-structure.md +62 -0
- package/presets/cursor/next/ai-local/rules-library/storybook-cleanup-temp-screenshots.md +40 -0
- package/presets/cursor/next/ai-local/rules-library/storybook-csf-authoring.md +100 -0
- package/presets/cursor/next/ai-local/rules-library/storybook-dev-compare-figma.md +67 -0
- package/presets/cursor/next/ai-local/rules-library/storybook-keep-tests-current.md +75 -0
- package/presets/cursor/next/ai-local/rules-library/storybook-modals.md +64 -0
- package/presets/cursor/next/ai-local/rules-library/storybook-no-app-node-modules.md +40 -0
- package/presets/cursor/next/ai-local/rules-library/storybook-ui-quality-gate.md +38 -0
- package/presets/cursor/next/ai-local/rules-library/task-levels.md +28 -0
- package/presets/cursor/next/ai-local/rules-library/ui-change-review-gate.md +14 -0
- package/presets/cursor/next/rules/README.md +4 -1
- package/presets/cursor/next/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/cursor/next/rules/ai-local-overlay.mdc +16 -2
- package/presets/cursor/next/rules/code-review-mr.mdc +4 -0
- package/presets/cursor/next/rules/component-catalog-gate.mdc +38 -0
- package/presets/cursor/next/rules/design-tokens-binding.mdc +1 -1
- package/presets/cursor/next/rules/feature-delivery-workflow.mdc +5 -1
- package/presets/cursor/next/rules/forms-validation.mdc +33 -0
- package/presets/cursor/next/rules/mcp-usage.mdc +1 -0
- package/presets/cursor/next/rules/next-app-core.mdc +3 -0
- package/presets/cursor/next/rules/next-static-export.mdc +35 -0
- package/presets/cursor/next/rules/post-change-lint.mdc +4 -0
- package/presets/cursor/next/rules/product-specs-authoring.mdc +1 -0
- package/presets/cursor/next/rules/product-specs.mdc +1 -0
- package/presets/cursor/next/rules/react-next-anti-hallucination.mdc +10 -0
- package/presets/cursor/next/rules/react-ui.mdc +19 -1
- package/presets/cursor/next/rules/reference-features.mdc +5 -0
- package/presets/cursor/next/rules/security-next.mdc +12 -0
- package/presets/cursor/next/rules/store-rtk.mdc +6 -0
- package/presets/cursor/next/rules/tests-e2e-structure.mdc +1 -0
- package/presets/cursor/next/rules/tests-unit.mdc +1 -0
- package/presets/cursor/next/team/fixtures/feature-with-ux-no-figma.json +3 -4
- package/presets/cursor/nuxt/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/cursor/php-hexagonal/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/cursor/php-laravel/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/cursor/svelte/rules/agent-team-orchestrator.mdc +1 -1
- package/presets/mavis/android-kotlin/adapter-map.json +1 -1
- package/presets/mavis/android-kotlin/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/android-kotlin/rules/code-review-mr.md +6 -6
- package/presets/mavis/go/adapter-map.json +1 -1
- package/presets/mavis/go/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/go/rules/code-quality-and-refactoring.md +1 -1
- package/presets/mavis/ios-swift/adapter-map.json +1 -1
- package/presets/mavis/ios-swift/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/ios-swift/rules/code-quality-and-refactoring.md +1 -1
- package/presets/mavis/ios-swift/rules/code-review-mr.md +6 -6
- package/presets/mavis/ios-swift/rules/feature-delivery-workflow.md +14 -14
- package/presets/mavis/ios-swift/rules/reference-features.md +3 -3
- package/presets/mavis/java/adapter-map.json +1 -1
- package/presets/mavis/java/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/java/rules/code-quality-and-refactoring.md +1 -1
- package/presets/mavis/mcp-ts/adapter-map.json +1 -1
- package/presets/mavis/mcp-ts/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/next/REPO_AGENTS.md +11 -1
- package/presets/mavis/next/adapter-map.json +192 -8
- package/presets/mavis/next/agents/build-verifier.md +1 -0
- package/presets/mavis/next/agents/code-reviewer.md +1 -0
- package/presets/mavis/next/agents/feature-developer.md +1 -0
- package/presets/mavis/next/agents/openspec-author.md +2 -0
- package/presets/mavis/next/agents/task-analyst.md +7 -0
- package/presets/mavis/next/agents/task-router.md +1 -0
- package/presets/mavis/next/ai-local/rules-library/agent-artifacts-no-local-paths.md +41 -8
- package/presets/mavis/next/ai-local/rules-library/agent-pipeline-gates.md +19 -0
- package/presets/mavis/next/ai-local/rules-library/analytics-events.md +18 -0
- package/presets/mavis/next/ai-local/rules-library/api-contract-source.md +14 -0
- package/presets/mavis/next/ai-local/rules-library/artifact-lifecycle.md +17 -0
- package/presets/mavis/next/ai-local/rules-library/code-style.md +68 -0
- package/presets/mavis/next/ai-local/rules-library/component-child-decomposition.md +81 -0
- package/presets/mavis/next/ai-local/rules-library/feature-flags-experiments.md +15 -0
- package/presets/mavis/next/ai-local/rules-library/mcp-required-for-ui-layout.md +1 -1
- package/presets/mavis/next/ai-local/rules-library/no-react-fc.md +46 -0
- package/presets/mavis/next/ai-local/rules-library/no-test-driven-behavior-change.md +1 -1
- package/presets/mavis/next/ai-local/rules-library/pwa-service-worker.md +15 -0
- package/presets/mavis/next/ai-local/rules-library/qa-test-cases.md +14 -0
- package/presets/mavis/next/ai-local/rules-library/router-pages.md +4 -2
- package/presets/mavis/next/ai-local/rules-library/single-source-copy-constants.md +3 -1
- package/presets/mavis/next/ai-local/rules-library/storybook-catalog-structure.md +62 -0
- package/presets/mavis/next/ai-local/rules-library/storybook-cleanup-temp-screenshots.md +40 -0
- package/presets/mavis/next/ai-local/rules-library/storybook-csf-authoring.md +100 -0
- package/presets/mavis/next/ai-local/rules-library/storybook-dev-compare-figma.md +67 -0
- package/presets/mavis/next/ai-local/rules-library/storybook-keep-tests-current.md +75 -0
- package/presets/mavis/next/ai-local/rules-library/storybook-modals.md +64 -0
- package/presets/mavis/next/ai-local/rules-library/storybook-no-app-node-modules.md +40 -0
- package/presets/mavis/next/ai-local/rules-library/storybook-ui-quality-gate.md +38 -0
- package/presets/mavis/next/ai-local/rules-library/task-levels.md +28 -0
- package/presets/mavis/next/ai-local/rules-library/ui-change-review-gate.md +14 -0
- package/presets/mavis/next/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/next/rules/ai-local-overlay.md +16 -2
- package/presets/mavis/next/rules/code-quality-and-refactoring.md +2 -2
- package/presets/mavis/next/rules/code-review-mr.md +11 -7
- package/presets/mavis/next/rules/component-catalog-gate.md +31 -0
- package/presets/mavis/next/rules/design-tokens-binding.md +1 -1
- package/presets/mavis/next/rules/feature-delivery-workflow.md +22 -18
- package/presets/mavis/next/rules/forms-validation.md +26 -0
- package/presets/mavis/next/rules/mcp-usage.md +1 -0
- package/presets/mavis/next/rules/mockup-review.md +1 -1
- package/presets/mavis/next/rules/next-app-core.md +3 -0
- package/presets/mavis/next/rules/next-static-export.md +28 -0
- package/presets/mavis/next/rules/post-change-lint.md +4 -0
- package/presets/mavis/next/rules/product-specs-authoring.md +1 -0
- package/presets/mavis/next/rules/product-specs.md +1 -0
- package/presets/mavis/next/rules/react-next-anti-hallucination.md +10 -0
- package/presets/mavis/next/rules/react-ui.md +19 -1
- package/presets/mavis/next/rules/reference-features.md +7 -2
- package/presets/mavis/next/rules/security-next.md +12 -0
- package/presets/mavis/next/rules/store-rtk.md +6 -0
- package/presets/mavis/next/rules/tests-e2e-structure.md +2 -1
- package/presets/mavis/next/rules/tests-unit.md +1 -0
- package/presets/mavis/next/team/fixtures/feature-with-ux-no-figma.json +3 -4
- package/presets/mavis/nuxt/adapter-map.json +1 -1
- package/presets/mavis/nuxt/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/nuxt/rules/code-review-mr.md +6 -6
- package/presets/mavis/nuxt/rules/feature-delivery-workflow.md +15 -15
- package/presets/mavis/nuxt/rules/reference-features.md +2 -2
- package/presets/mavis/nuxt/rules/tests-e2e-structure.md +1 -1
- package/presets/mavis/php-hexagonal/adapter-map.json +1 -1
- package/presets/mavis/php-hexagonal/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/php-hexagonal/rules/code-quality-and-refactoring.md +1 -1
- package/presets/mavis/php-laravel/adapter-map.json +1 -1
- package/presets/mavis/php-laravel/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/php-laravel/rules/code-quality-and-refactoring.md +1 -1
- package/presets/mavis/svelte/adapter-map.json +1 -1
- package/presets/mavis/svelte/rules/agent-team-orchestrator.md +1 -2
- package/presets/mavis/svelte/rules/code-review-mr.md +6 -6
- package/presets/mavis/svelte/rules/feature-delivery-workflow.md +1 -1
- package/presets/mavis/svelte/rules/reference-features.md +2 -2
- package/presets/mavis/svelte/rules/tests-e2e-structure.md +1 -1
- package/presets/opencode/android-kotlin/adapter-map.json +1 -1
- package/presets/opencode/android-kotlin/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/android-kotlin/rules/code-review-mr.md +6 -6
- package/presets/opencode/go/adapter-map.json +1 -1
- package/presets/opencode/go/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/go/rules/code-quality-and-refactoring.md +1 -1
- package/presets/opencode/ios-swift/adapter-map.json +1 -1
- package/presets/opencode/ios-swift/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/ios-swift/rules/code-quality-and-refactoring.md +1 -1
- package/presets/opencode/ios-swift/rules/code-review-mr.md +6 -6
- package/presets/opencode/ios-swift/rules/feature-delivery-workflow.md +14 -14
- package/presets/opencode/ios-swift/rules/reference-features.md +3 -3
- package/presets/opencode/java/adapter-map.json +1 -1
- package/presets/opencode/java/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/java/rules/code-quality-and-refactoring.md +1 -1
- package/presets/opencode/mcp-ts/adapter-map.json +1 -1
- package/presets/opencode/mcp-ts/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/next/REPO_AGENTS.md +11 -1
- package/presets/opencode/next/adapter-map.json +192 -8
- package/presets/opencode/next/agents/build-verifier.md +1 -0
- package/presets/opencode/next/agents/code-reviewer.md +1 -0
- package/presets/opencode/next/agents/feature-developer.md +1 -0
- package/presets/opencode/next/agents/openspec-author.md +2 -0
- package/presets/opencode/next/agents/task-analyst.md +7 -0
- package/presets/opencode/next/agents/task-router.md +1 -0
- package/presets/opencode/next/ai-local/rules-library/agent-artifacts-no-local-paths.md +41 -8
- package/presets/opencode/next/ai-local/rules-library/agent-pipeline-gates.md +19 -0
- package/presets/opencode/next/ai-local/rules-library/analytics-events.md +18 -0
- package/presets/opencode/next/ai-local/rules-library/api-contract-source.md +14 -0
- package/presets/opencode/next/ai-local/rules-library/artifact-lifecycle.md +17 -0
- package/presets/opencode/next/ai-local/rules-library/code-style.md +68 -0
- package/presets/opencode/next/ai-local/rules-library/component-child-decomposition.md +81 -0
- package/presets/opencode/next/ai-local/rules-library/feature-flags-experiments.md +15 -0
- package/presets/opencode/next/ai-local/rules-library/mcp-required-for-ui-layout.md +1 -1
- package/presets/opencode/next/ai-local/rules-library/no-react-fc.md +46 -0
- package/presets/opencode/next/ai-local/rules-library/no-test-driven-behavior-change.md +1 -1
- package/presets/opencode/next/ai-local/rules-library/pwa-service-worker.md +15 -0
- package/presets/opencode/next/ai-local/rules-library/qa-test-cases.md +14 -0
- package/presets/opencode/next/ai-local/rules-library/router-pages.md +4 -2
- package/presets/opencode/next/ai-local/rules-library/single-source-copy-constants.md +3 -1
- package/presets/opencode/next/ai-local/rules-library/storybook-catalog-structure.md +62 -0
- package/presets/opencode/next/ai-local/rules-library/storybook-cleanup-temp-screenshots.md +40 -0
- package/presets/opencode/next/ai-local/rules-library/storybook-csf-authoring.md +100 -0
- package/presets/opencode/next/ai-local/rules-library/storybook-dev-compare-figma.md +67 -0
- package/presets/opencode/next/ai-local/rules-library/storybook-keep-tests-current.md +75 -0
- package/presets/opencode/next/ai-local/rules-library/storybook-modals.md +64 -0
- package/presets/opencode/next/ai-local/rules-library/storybook-no-app-node-modules.md +40 -0
- package/presets/opencode/next/ai-local/rules-library/storybook-ui-quality-gate.md +38 -0
- package/presets/opencode/next/ai-local/rules-library/task-levels.md +28 -0
- package/presets/opencode/next/ai-local/rules-library/ui-change-review-gate.md +14 -0
- package/presets/opencode/next/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/next/rules/ai-local-overlay.md +16 -2
- package/presets/opencode/next/rules/code-quality-and-refactoring.md +2 -2
- package/presets/opencode/next/rules/code-review-mr.md +11 -7
- package/presets/opencode/next/rules/component-catalog-gate.md +31 -0
- package/presets/opencode/next/rules/design-tokens-binding.md +1 -1
- package/presets/opencode/next/rules/feature-delivery-workflow.md +22 -18
- package/presets/opencode/next/rules/forms-validation.md +26 -0
- package/presets/opencode/next/rules/mcp-usage.md +1 -0
- package/presets/opencode/next/rules/mockup-review.md +1 -1
- package/presets/opencode/next/rules/next-app-core.md +3 -0
- package/presets/opencode/next/rules/next-static-export.md +28 -0
- package/presets/opencode/next/rules/post-change-lint.md +4 -0
- package/presets/opencode/next/rules/product-specs-authoring.md +1 -0
- package/presets/opencode/next/rules/product-specs.md +1 -0
- package/presets/opencode/next/rules/react-next-anti-hallucination.md +10 -0
- package/presets/opencode/next/rules/react-ui.md +19 -1
- package/presets/opencode/next/rules/reference-features.md +7 -2
- package/presets/opencode/next/rules/security-next.md +12 -0
- package/presets/opencode/next/rules/store-rtk.md +6 -0
- package/presets/opencode/next/rules/tests-e2e-structure.md +2 -1
- package/presets/opencode/next/rules/tests-unit.md +1 -0
- package/presets/opencode/next/team/fixtures/feature-with-ux-no-figma.json +3 -4
- package/presets/opencode/nuxt/adapter-map.json +1 -1
- package/presets/opencode/nuxt/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/nuxt/rules/code-review-mr.md +6 -6
- package/presets/opencode/nuxt/rules/feature-delivery-workflow.md +15 -15
- package/presets/opencode/nuxt/rules/reference-features.md +2 -2
- package/presets/opencode/nuxt/rules/tests-e2e-structure.md +1 -1
- package/presets/opencode/php-hexagonal/adapter-map.json +1 -1
- package/presets/opencode/php-hexagonal/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/php-hexagonal/rules/code-quality-and-refactoring.md +1 -1
- package/presets/opencode/php-laravel/adapter-map.json +1 -1
- package/presets/opencode/php-laravel/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/php-laravel/rules/code-quality-and-refactoring.md +1 -1
- package/presets/opencode/svelte/adapter-map.json +1 -1
- package/presets/opencode/svelte/rules/agent-team-orchestrator.md +1 -2
- package/presets/opencode/svelte/rules/code-review-mr.md +6 -6
- package/presets/opencode/svelte/rules/feature-delivery-workflow.md +1 -1
- package/presets/opencode/svelte/rules/reference-features.md +2 -2
- package/presets/opencode/svelte/rules/tests-e2e-structure.md +1 -1
- package/scripts/check-generated-drift.mjs +42 -2
- package/scripts/check-local-overlay.sh +39 -0
- package/scripts/fixtures/cli-golden/claude/next.json +44 -41
- package/scripts/fixtures/cli-golden/cursor/next.json +69 -46
- package/scripts/fixtures/cli-golden/mavis/android-kotlin.json +21 -21
- package/scripts/fixtures/cli-golden/mavis/go.json +8 -8
- package/scripts/fixtures/cli-golden/mavis/ios-swift.json +12 -12
- package/scripts/fixtures/cli-golden/mavis/java.json +8 -8
- package/scripts/fixtures/cli-golden/mavis/mcp-ts.json +5 -5
- package/scripts/fixtures/cli-golden/mavis/next.json +70 -47
- package/scripts/fixtures/cli-golden/mavis/nuxt.json +25 -25
- package/scripts/fixtures/cli-golden/mavis/php-hexagonal.json +8 -8
- package/scripts/fixtures/cli-golden/mavis/php-laravel.json +8 -8
- package/scripts/fixtures/cli-golden/mavis/svelte.json +25 -25
- package/scripts/fixtures/cli-golden/opencode/android-kotlin.json +21 -21
- package/scripts/fixtures/cli-golden/opencode/go.json +8 -8
- package/scripts/fixtures/cli-golden/opencode/ios-swift.json +12 -12
- package/scripts/fixtures/cli-golden/opencode/java.json +8 -8
- package/scripts/fixtures/cli-golden/opencode/mcp-ts.json +5 -5
- package/scripts/fixtures/cli-golden/opencode/next.json +70 -47
- package/scripts/fixtures/cli-golden/opencode/nuxt.json +25 -25
- package/scripts/fixtures/cli-golden/opencode/php-hexagonal.json +8 -8
- package/scripts/fixtures/cli-golden/opencode/php-laravel.json +8 -8
- package/scripts/fixtures/cli-golden/opencode/svelte.json +25 -25
- package/scripts/lib/generate-adapter-common.mjs +17 -0
- package/scripts/lib/generate-mavis-adapter.mjs +9 -3
- package/scripts/lib/generate-opencode-adapter.mjs +9 -3
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Forms and validation — use the repo's form library + design-system fields + shared validators, not ad-hoc state
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
paths:
|
|
5
|
+
- app/src/**/*Form*.tsx
|
|
6
|
+
- app/src/**/*Form*.ts
|
|
7
|
+
- app/src/**/*Modal*.tsx
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Forms and validation
|
|
11
|
+
|
|
12
|
+
Use the form solution already in the repo (`package.json` + the nearest form component). Do not hand-roll form state with `useState` when a form library is present.
|
|
13
|
+
|
|
14
|
+
## Rules
|
|
15
|
+
|
|
16
|
+
- One form-hook instance per form; register design-system fields through the library's controller/wrapper (controlled) — not a raw `<input>` when a DS field exists.
|
|
17
|
+
- Validate with the repo's resolver/schema library and reuse the shared validators under the repo's validation utils — never re-implement email / phone / date / length rules inline.
|
|
18
|
+
- Masked inputs (phone, date, card) go through the repo's mask library, not ad-hoc regex on change.
|
|
19
|
+
- Disable submit while `!isValid` / `isSubmitting`; surface field errors from the form library's error state.
|
|
20
|
+
- Keep side effects out of field components: the form owns `onSubmit`; data flows to store/API through the repo's layers (`architecture/architecture-boundaries-ui.md`).
|
|
21
|
+
|
|
22
|
+
## Accessibility
|
|
23
|
+
|
|
24
|
+
- Every field has a visible label and an associated error message; do not rely on placeholder-only labels.
|
|
25
|
+
- Field errors are announced and tied to the input; keep the DS field's wiring instead of a bespoke error node.
|
|
26
|
+
|
|
27
|
+
## Stack notes
|
|
28
|
+
|
|
29
|
+
- Library: `react-hook-form` + `yup` resolver; `mode: 'onTouched'`.
|
|
30
|
+
- DS fields: `app/src/ui/components/_form/**`; shared validators: `app/src/lib/utils/validations/**`; masks: `imask` / `react-imask`.
|
|
31
|
+
|
|
32
|
+
## Related
|
|
33
|
+
|
|
34
|
+
- `ui-and-accessibility/react-ui.md` — component structure and decomposition.
|
|
35
|
+
- `architecture/architecture-boundaries-ui.md` — no API/DTO in UI.
|
|
@@ -24,6 +24,24 @@ impact: HIGH
|
|
|
24
24
|
- No nested ternaries in JSX. For not-ready / empty / error, use an early return or a dedicated `EmptyState` / `ErrorState` component.
|
|
25
25
|
- A `variant` / `mode` flag that renders two unrelated layouts is **two** components, not one.
|
|
26
26
|
|
|
27
|
+
# One component / one styled element — one purpose
|
|
28
|
+
|
|
29
|
+
- Each component **and** each styled element serves exactly **one** purpose. Do not drive two distinct shapes (different padding, slot set, alignment, visual identity) from a `variant` / `is…` flag or branchy styles.
|
|
30
|
+
- Two call sites that need visibly different markup → two named components (or two named styled exports). Share the base via a small primitive (`BaseCard` styled block + two thin extensions), not a universal branchy `Card`.
|
|
31
|
+
- A flag that flips a single non-layout property (`compact`, `disabled`) is fine; a flag that flips layout, slots, or visual identity is not — split it.
|
|
32
|
+
|
|
33
|
+
# CSS-in-JS interpolation functions
|
|
34
|
+
|
|
35
|
+
- Inside `${…}` interpolations of a styled template (`styled.*`), do **not** write an inline arrow (`${({ tone }) => …}` or `${({ gap }) => gap}`). Reference a **module-level function** that takes the styled props: `${getPromoStatusColor}`.
|
|
36
|
+
- Name it `get` + the value (`getColor`, `getGap`, `getPromoStatusColor`); keep the prop type shared between the styled generic and the function parameter.
|
|
37
|
+
- A module-level function is debuggable, type-checkable in isolation, and reusable across sibling styled blocks; an inline arrow compiles to an untestable one-shot.
|
|
38
|
+
|
|
39
|
+
# Async UI states
|
|
40
|
+
|
|
41
|
+
- Loading, empty, error, and load-failed are **distinct** states — render each explicitly; do not collapse them into one spinner/blank branch.
|
|
42
|
+
- Prefer a **per-block skeleton** over a page-level spinner, and reuse the repo's existing primitives (`Skeleton`, `EmptyState`, `ErrorState`, load-failed stub, global `ErrorBoundary`) instead of inventing new ones.
|
|
43
|
+
- Error boundaries are usually mounted once at the app root; add a local boundary only when the repo already does so for that region.
|
|
44
|
+
|
|
27
45
|
## Incorrect
|
|
28
46
|
|
|
29
47
|
```tsx
|
|
@@ -99,7 +117,7 @@ For a reusable component:
|
|
|
99
117
|
- **Forbidden** to import another component's `styles` (`../Other/styles`, `../../styles`). Allowed: `./styles`, shared primitives from `@/ui/components/...` or design-system packages.
|
|
100
118
|
- CSS / `styled` order — Stylelint idiomatic-order: `ui-and-accessibility/css-property-order.md` (loads on `styles.ts` / `.css`).
|
|
101
119
|
- For visuals use **the style stack and tokens already in the project** (variables, theme, shared classes, design package).
|
|
102
|
-
- **Token binding (Figma → repo):** typography, color, spacing, radius, shadow, and imagery must bind to the project token module and the design system (`@sds/tokens-*` / `@sds/brand-colors` / DS components like `Text variant="…"`, `@sds/icon`,
|
|
120
|
+
- **Token binding (Figma → repo):** typography, color, spacing, radius, shadow, and imagery must bind to the project token module and the design system (`@sds/tokens-*` / `@sds/brand-colors` / DS components like `Text variant="…"`, `@sds/icon`, the project image primitive). Raw `#…` / `rgb(…)` / `px` where a token exists is a finding. The full discipline — including the per-element parity checklist and the developer self-check vs Figma — is in **`ui-and-accessibility/design-tokens-binding.md`**. When a Figma reference exists, the `mockup-review.md` `## Design contract` section is the binding table; use it.
|
|
103
121
|
- Avoid:
|
|
104
122
|
- inline styles except simple cases;
|
|
105
123
|
- duplicating styling already covered by shared primitives;
|
|
@@ -2,16 +2,15 @@
|
|
|
2
2
|
"slug": "example-feature-with-ux-no-figma",
|
|
3
3
|
"intent": "feature",
|
|
4
4
|
"profile": "standard",
|
|
5
|
-
"summary": "
|
|
5
|
+
"summary": "UI-scope feature with required-signal UX and no Figma URL — task-analyst loads skill ux-design; UI scope forces mockup-reviewer (reviewed against AC / ux-design.md)",
|
|
6
6
|
"steps": [
|
|
7
7
|
{ "agent": "task-analyst", "label": "Clarify, UX design, decompose" },
|
|
8
|
+
{ "agent": "mockup-reviewer", "label": "UI review vs AC / ux-design" },
|
|
8
9
|
{ "agent": "feature-developer", "label": "Implement" },
|
|
9
10
|
{ "agent": "build-verifier", "label": "Validation gate", "model": "cheap" },
|
|
10
11
|
{ "agent": "code-reviewer", "label": "Code review", "model": "cheap" }
|
|
11
12
|
],
|
|
12
13
|
"humanGates": ["after:task-analyst"],
|
|
13
14
|
"autoChain": true,
|
|
14
|
-
"skipped": [
|
|
15
|
-
{ "agent": "mockup-reviewer", "reason": "No figma.com URL; analyst skill ux-design covers behavioral UX" }
|
|
16
|
-
]
|
|
15
|
+
"skipped": []
|
|
17
16
|
}
|
|
@@ -96,8 +96,7 @@ Each slug has one `artifact-manifest.json` at `.ai.local/team/tasks/<slug>/`. Sc
|
|
|
96
96
|
|
|
97
97
|
- Read the manifest before broad prior-artifact discovery. Each step receives authoritative input entry IDs, owns named output entry IDs, and finishes with one terminal receipt linked to AC/task IDs.
|
|
98
98
|
- Markdown remains detailed evidence; the manifest records producer, status, authoritative paths, timestamps, outcome, and evidence paths.
|
|
99
|
-
-
|
|
100
|
-
Agents upsert only the items in `manifest.artifacts[]` they own and preserve foreign items. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges.
|
|
99
|
+
- Agents upsert only the items they own in `manifest.artifacts[]` and preserve all foreign items in that array. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges. The top-level array key is `artifacts` — not `entries`; see `agent-artifact-contracts.md` for the schema callout.
|
|
101
100
|
- The orchestration runtime/hook is the single writer for `status.json` lifecycle fields and `metrics.json`. Agents read status for eligibility but never rewrite state, gate, retry, attempt, timestamp, or metrics fields.
|
|
102
101
|
- Missing/stale manifests are reported as a handoff gap; fall back to `brief.md`, `decomposition.md`, and `pipeline.json` rather than inventing authority.
|
|
103
102
|
|
|
@@ -78,8 +78,7 @@ Each slug has one `artifact-manifest.json` at `.ai.local/team/tasks/<slug>/`. Sc
|
|
|
78
78
|
|
|
79
79
|
- Read the manifest before broad prior-artifact discovery. Each step receives authoritative input entry IDs, owns named output entry IDs, and finishes with one terminal receipt linked to AC/task IDs.
|
|
80
80
|
- Markdown remains detailed evidence; the manifest records producer, status, authoritative paths, timestamps, outcome, and evidence paths.
|
|
81
|
-
-
|
|
82
|
-
Agents upsert only the items in `manifest.artifacts[]` they own and preserve foreign items. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges.
|
|
81
|
+
- Agents upsert only the items they own in `manifest.artifacts[]` and preserve all foreign items in that array. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges. The top-level array key is `artifacts` — not `entries`; see `agent-artifact-contracts.md` for the schema callout.
|
|
83
82
|
- The orchestration runtime/hook is the single writer for `status.json` lifecycle fields and `metrics.json`. Agents read status for eligibility but never rewrite state, gate, retry, attempt, timestamp, or metrics fields.
|
|
84
83
|
- Missing/stale manifests are reported as a handoff gap; fall back to `brief.md`, `decomposition.md`, and `pipeline.json` rather than inventing authority.
|
|
85
84
|
|
|
@@ -74,8 +74,7 @@ Each slug has one `artifact-manifest.json` at `.ai.local/team/tasks/<slug>/`. Sc
|
|
|
74
74
|
|
|
75
75
|
- Read the manifest before broad prior-artifact discovery. Each step receives authoritative input entry IDs, owns named output entry IDs, and finishes with one terminal receipt linked to AC/task IDs.
|
|
76
76
|
- Markdown remains detailed evidence; the manifest records producer, status, authoritative paths, timestamps, outcome, and evidence paths.
|
|
77
|
-
-
|
|
78
|
-
Agents upsert only the items in `manifest.artifacts[]` they own and preserve foreign items. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges.
|
|
77
|
+
- Agents upsert only the items they own in `manifest.artifacts[]` and preserve all foreign items in that array. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges. The top-level array key is `artifacts` — not `entries`; see `agent-artifact-contracts.md` for the schema callout.
|
|
79
78
|
- The orchestration runtime/hook is the single writer for `status.json` lifecycle fields and `metrics.json`. Agents read status for eligibility but never rewrite state, gate, retry, attempt, timestamp, or metrics fields.
|
|
80
79
|
- Missing/stale manifests are reported as a handoff gap; fall back to `brief.md`, `decomposition.md`, and `pipeline.json` rather than inventing authority.
|
|
81
80
|
|
|
@@ -97,8 +97,7 @@ Each slug has one `artifact-manifest.json` at `.ai.local/team/tasks/<slug>/`. Sc
|
|
|
97
97
|
|
|
98
98
|
- Read the manifest before broad prior-artifact discovery. Each step receives authoritative input entry IDs, owns named output entry IDs, and finishes with one terminal receipt linked to AC/task IDs.
|
|
99
99
|
- Markdown remains detailed evidence; the manifest records producer, status, authoritative paths, timestamps, outcome, and evidence paths.
|
|
100
|
-
-
|
|
101
|
-
Agents upsert only the items in `manifest.artifacts[]` they own and preserve foreign items. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges.
|
|
100
|
+
- Agents upsert only the items they own in `manifest.artifacts[]` and preserve all foreign items in that array. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges. The top-level array key is `artifacts` — not `entries`; see `agent-artifact-contracts.md` for the schema callout.
|
|
102
101
|
- The orchestration runtime/hook is the single writer for `status.json` lifecycle fields and `metrics.json`. Agents read status for eligibility but never rewrite state, gate, retry, attempt, timestamp, or metrics fields.
|
|
103
102
|
- Missing/stale manifests are reported as a handoff gap; fall back to `brief.md`, `decomposition.md`, and `pipeline.json` rather than inventing authority.
|
|
104
103
|
|
|
@@ -74,7 +74,7 @@ Each slug has one `artifact-manifest.json` at `.ai.local/team/tasks/<slug>/`. Sc
|
|
|
74
74
|
|
|
75
75
|
- Read the manifest before broad prior-artifact discovery. Each step receives authoritative input entry IDs, owns named output entry IDs, and finishes with one terminal receipt linked to AC/task IDs.
|
|
76
76
|
- Markdown remains detailed evidence; the manifest records producer, status, authoritative paths, timestamps, outcome, and evidence paths.
|
|
77
|
-
- Agents upsert only the items in `manifest.artifacts[]`
|
|
77
|
+
- Agents upsert only the items they own in `manifest.artifacts[]` and preserve all foreign items in that array. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges. The top-level array key is `artifacts` — not `entries`; see `agent-artifact-contracts.md` for the schema callout.
|
|
78
78
|
- The orchestration runtime/hook is the single writer for `status.json` lifecycle fields and `metrics.json`. Agents read status for eligibility but never rewrite state, gate, retry, attempt, timestamp, or metrics fields.
|
|
79
79
|
- Missing/stale manifests are reported as a handoff gap; fall back to `brief.md`, `decomposition.md`, and `pipeline.json` rather than inventing authority.
|
|
80
80
|
|
|
@@ -72,7 +72,7 @@ Each slug has one `artifact-manifest.json` at `.ai.local/team/tasks/<slug>/`. Sc
|
|
|
72
72
|
|
|
73
73
|
- Read the manifest before broad prior-artifact discovery. Each step receives authoritative input entry IDs, owns named output entry IDs, and finishes with one terminal receipt linked to AC/task IDs.
|
|
74
74
|
- Markdown remains detailed evidence; the manifest records producer, status, authoritative paths, timestamps, outcome, and evidence paths.
|
|
75
|
-
- Agents upsert only the items in `manifest.artifacts[]`
|
|
75
|
+
- Agents upsert only the items they own in `manifest.artifacts[]` and preserve all foreign items in that array. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges. The top-level array key is `artifacts` — not `entries`; see `agent-artifact-contracts.md` for the schema callout.
|
|
76
76
|
- The orchestration runtime/hook is the single writer for `status.json` lifecycle fields and `metrics.json`. Agents read status for eligibility but never rewrite state, gate, retry, attempt, timestamp, or metrics fields.
|
|
77
77
|
- Missing/stale manifests are reported as a handoff gap; fall back to `brief.md`, `decomposition.md`, and `pipeline.json` rather than inventing authority.
|
|
78
78
|
|
|
@@ -74,7 +74,7 @@ Each slug has one `artifact-manifest.json` at `.ai.local/team/tasks/<slug>/`. Sc
|
|
|
74
74
|
|
|
75
75
|
- Read the manifest before broad prior-artifact discovery. Each step receives authoritative input entry IDs, owns named output entry IDs, and finishes with one terminal receipt linked to AC/task IDs.
|
|
76
76
|
- Markdown remains detailed evidence; the manifest records producer, status, authoritative paths, timestamps, outcome, and evidence paths.
|
|
77
|
-
- Agents upsert only the items in `manifest.artifacts[]`
|
|
77
|
+
- Agents upsert only the items they own in `manifest.artifacts[]` and preserve all foreign items in that array. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges. The top-level array key is `artifacts` — not `entries`; see `agent-artifact-contracts.md` for the schema callout.
|
|
78
78
|
- The orchestration runtime/hook is the single writer for `status.json` lifecycle fields and `metrics.json`. Agents read status for eligibility but never rewrite state, gate, retry, attempt, timestamp, or metrics fields.
|
|
79
79
|
- Missing/stale manifests are reported as a handoff gap; fall back to `brief.md`, `decomposition.md`, and `pipeline.json` rather than inventing authority.
|
|
80
80
|
|
|
@@ -72,7 +72,7 @@ Each slug has one `artifact-manifest.json` at `.ai.local/team/tasks/<slug>/`. Sc
|
|
|
72
72
|
|
|
73
73
|
- Read the manifest before broad prior-artifact discovery. Each step receives authoritative input entry IDs, owns named output entry IDs, and finishes with one terminal receipt linked to AC/task IDs.
|
|
74
74
|
- Markdown remains detailed evidence; the manifest records producer, status, authoritative paths, timestamps, outcome, and evidence paths.
|
|
75
|
-
- Agents upsert only the items in `manifest.artifacts[]`
|
|
75
|
+
- Agents upsert only the items they own in `manifest.artifacts[]` and preserve all foreign items in that array. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges. The top-level array key is `artifacts` — not `entries`; see `agent-artifact-contracts.md` for the schema callout.
|
|
76
76
|
- The orchestration runtime/hook is the single writer for `status.json` lifecycle fields and `metrics.json`. Agents read status for eligibility but never rewrite state, gate, retry, attempt, timestamp, or metrics fields.
|
|
77
77
|
- Missing/stale manifests are reported as a handoff gap; fall back to `brief.md`, `decomposition.md`, and `pipeline.json` rather than inventing authority.
|
|
78
78
|
|
|
@@ -72,7 +72,7 @@ Each slug has one `artifact-manifest.json` at `.ai.local/team/tasks/<slug>/`. Sc
|
|
|
72
72
|
|
|
73
73
|
- Read the manifest before broad prior-artifact discovery. Each step receives authoritative input entry IDs, owns named output entry IDs, and finishes with one terminal receipt linked to AC/task IDs.
|
|
74
74
|
- Markdown remains detailed evidence; the manifest records producer, status, authoritative paths, timestamps, outcome, and evidence paths.
|
|
75
|
-
- Agents upsert only the items in `manifest.artifacts[]`
|
|
75
|
+
- Agents upsert only the items they own in `manifest.artifacts[]` and preserve all foreign items in that array. Parallel agents use distinct IDs; the parent/orchestrator serializes manifest merges. The top-level array key is `artifacts` — not `entries`; see `agent-artifact-contracts.md` for the schema callout.
|
|
76
76
|
- The orchestration runtime/hook is the single writer for `status.json` lifecycle fields and `metrics.json`. Agents read status for eligibility but never rewrite state, gate, retry, attempt, timestamp, or metrics fields.
|
|
77
77
|
- Missing/stale manifests are reported as a handoff gap; fall back to `brief.md`, `decomposition.md`, and `pipeline.json` rather than inventing authority.
|
|
78
78
|
|
|
@@ -43,6 +43,8 @@ Working directory for app scripts: **`app/`**. Detect the package manager from l
|
|
|
43
43
|
|
|
44
44
|
After code edits: invoke **`post-change-lint`** (requestable). Full gate: agent `build-verifier`.
|
|
45
45
|
|
|
46
|
+
Repositories with more than one package (e.g. `app/` + `storybook/`) run each package's own scripts from its own directory; do not conflate runners.
|
|
47
|
+
|
|
46
48
|
## Security basics
|
|
47
49
|
|
|
48
50
|
- Do not commit secrets (`.env`, tokens, credentials).
|
|
@@ -65,10 +67,18 @@ Skills: `.cursor/skills/`, `.claude/skills/`, `.mavis/skills/`, or `.opencode/sk
|
|
|
65
67
|
|
|
66
68
|
Gotchas, local patterns, and team decisions: **`.ai.local/conventions.md`** (fill after init; `init` does not overwrite it).
|
|
67
69
|
|
|
70
|
+
## Seed library (`.ai.local/rules-library/`)
|
|
71
|
+
|
|
72
|
+
`init` seeds **staged-inactive** rule templates here (Cursor `.mdc` sources analog: `presets/cursor/next/ai-local/rules-library/**`). They are **not** active until moved into `.ai.local/rules/`. When a seed matches the task scope, apply it and tell the owner to move it. Typical seeds: `router-pages` (Pages Router override), `no-react-fc`, `component-child-decomposition`, `single-source-copy-constants`, `commit-hygiene`, `pre-pr-checklist`, `api-contract-source`, `agent-pipeline-gates`, `task-levels`, `analytics-events`, `feature-flags-experiments`, `pwa-service-worker`, `qa-test-cases`, `forms-validation`, and the `storybook-*` set.
|
|
73
|
+
|
|
74
|
+
## Managed vs preserved
|
|
75
|
+
|
|
76
|
+
`init` owns `.cursor/**`, `.claude/**`, `.mavis/**`, `.opencode/**`, root `AGENTS.md`, and the tool MCP config; it **overwrites/merges** them. Durable project config and authoritative specs belong **outside** those trees: `.ai.local/**`, `.ai/context/**`, `docs/specs/**`, `openspec/**`, repo-root `.mcp.json`. After a re-init, re-check any consumer-owned block added to a managed file.
|
|
77
|
+
|
|
68
78
|
## Local overlay (`.ai.local/`) — MANDATORY
|
|
69
79
|
|
|
70
80
|
A `.ai.local/` directory MAY exist at the repo root or at any nesting depth in monorepos. **All agents MUST read and apply it on every turn.** Rules there override preset rules; in conflicts, the local rule wins. `override: kill <preset-rule-name>` drops the named preset rule from the agent's context entirely.
|
|
71
81
|
|
|
72
|
-
Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with higher priority than preset rules. Living gotchas live in `.ai.local/conventions.md`.
|
|
82
|
+
Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with higher priority than preset rules. Living gotchas live in `.ai.local/conventions.md`. Staged seeds live in `.ai.local/rules-library/**`; a matching seed must be moved into `.ai.local/rules/` to activate.
|
|
73
83
|
|
|
74
84
|
On every turn, probe `ls -la .ai.local`, apply `.ai.local/rules/*.md` and `.ai.local/conventions.md`, and acknowledge `Using .ai.local: <rule-name>`. Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule is always-on on Cursor and session-start on Claude (no `paths:`). Mavis and OpenCode have no native `alwaysApply`; this section plus the platform entry's essential-rules list is the reinforcement.
|
|
@@ -23,6 +23,7 @@ Use **`package-manager.mdc`** for the repo package manager.
|
|
|
23
23
|
2. **`lint:css`** — full Stylelint.
|
|
24
24
|
3. **`type-check`** — when TypeScript changed.
|
|
25
25
|
4. **Unit tests** — run specs for changed modules (paths from diff); if unclear, run the narrowest parent suite that covers changed mappers/services/store.
|
|
26
|
+
5. **Component catalog** — when the repo ships a catalog (e.g. `storybook/`) and `app/src/ui/**` or catalog files changed, run the catalog's own test/visual-baseline suite from the catalog package and require green **without** `--update` (`component-catalog-gate`). A green app unit run does not cover catalog stories.
|
|
26
27
|
|
|
27
28
|
Prefer **`lint`** (= js + css + type-check) before handoff on large changes.
|
|
28
29
|
|
|
@@ -99,5 +99,6 @@ Do not mix this output with retrospective facilitation — keep review and retro
|
|
|
99
99
|
|
|
100
100
|
- **Authoritative inputs:** read `.ai.local/team/tasks/<slug>/artifact-manifest.json` first; consume handoff `artifactInputIds` when supplied, otherwise consume the items in `manifest.artifacts[]` for brief/decomposition, implementation, validation evidence, and the scoped git diff.
|
|
101
101
|
- **Owned outputs:** `review.md`; upsert only the entry in `manifest.artifacts[]` assigned by handoff (`artifactOutputId`; fallback `review`) and preserve all foreign items in `manifest.artifacts[]`.
|
|
102
|
+
- **Commit hygiene:** never run `git commit` / `git push`. Reviewer turns end with findings only; when asked for commit guidance, propose an area-split commit plan (source / artifacts / docs) with the owning slug.
|
|
102
103
|
- **Terminal receipt:** cover applicable AC/task IDs, list authoritative evidence paths, and emit `completed` or `changes_requested`. Bind it to the supplied `attemptId` when present.
|
|
103
104
|
- **Shared state:** never create or mutate `status.json` or `metrics.json`; the orchestration runtime/hook owns lifecycle, gates, retries, attempts, and timestamps.
|
|
@@ -126,5 +126,6 @@ Shipped browser split: Playwright MCP for e2e specs/selectors; Chrome DevTools M
|
|
|
126
126
|
|
|
127
127
|
- **Authoritative inputs:** read `.ai.local/team/tasks/<slug>/artifact-manifest.json` first; consume handoff `artifactInputIds` when supplied, otherwise consume the items in `manifest.artifacts[]` for `brief.md`, `decomposition.md`, current scope, and applicable prior findings.
|
|
128
128
|
- **Owned outputs:** `implementation.md` plus changed implementation/test paths; upsert only the entry in `manifest.artifacts[]` assigned by handoff (`artifactOutputId`; fallback `implementation`) and preserve all foreign items in `manifest.artifacts[]`.
|
|
129
|
+
- **Commit hygiene:** never run `git commit` / `git push`. At the end of the turn return a `## Human commits` block: files touched + a proposed commit message, split by area (source / artifacts / docs) with the owning slug/ticket in the subject. See the consumer `commit-hygiene` local rule.
|
|
129
130
|
- **Terminal receipt:** cover applicable AC/task IDs, list authoritative evidence paths, and emit `completed` or `blocked`. Bind it to the supplied `attemptId` when present.
|
|
130
131
|
- **Shared state:** never create or mutate `status.json` or `metrics.json`; the orchestration runtime/hook owns lifecycle, gates, retries, attempts, and timestamps.
|
|
@@ -61,6 +61,8 @@ Hard constraints (read `config.yaml rules.proposal` first — they win):
|
|
|
61
61
|
|
|
62
62
|
- `proposal.md` ≤ 500 words.
|
|
63
63
|
- `## Non-goals` section mandatory (omit → `blocked`).
|
|
64
|
+
- `## Compliance impact` block mandatory in `proposal.md` and `design.md` (None | Affected — list PD / medical / analytics / SSR-cookie / third-party surfaces); when unclear, default to `Affected` and block.
|
|
65
|
+
- `## Hard rules applied` block at the top of `proposal.md` / `design.md` / `tasks.md` (applicable rules + how applied; `N/A — reason` for the rest), when the consumer repo maintains hard rules.
|
|
64
66
|
- `## What Changes` lists capability deltas **only**; no implementation steps.
|
|
65
67
|
- `## Capabilities` table groups deltas by capability slug; cite spec paths.
|
|
66
68
|
- Spec deltas use `## MODIFIED Requirements` heading (or `## REMOVED Requirements`); Each `### Requirement:` block carries `SHALL` statements and `#### Scenario:` Given/When/Then. Mirror existing capability voice.
|
|
@@ -50,6 +50,13 @@ Create or update files under `.ai.local/team/tasks/<slug>/`:
|
|
|
50
50
|
## Slug
|
|
51
51
|
<slug>
|
|
52
52
|
|
|
53
|
+
## Hard rules applied
|
|
54
|
+
- <applicable preset/local rule> — <how applied>
|
|
55
|
+
- N/A — <reason> (list non-applicable hard rules explicitly)
|
|
56
|
+
|
|
57
|
+
## Compliance impact
|
|
58
|
+
None | Affected — <surfaces: PD / medical data / analytics / SSR cookies / error reporting / third-party scripts>
|
|
59
|
+
|
|
53
60
|
## Goal
|
|
54
61
|
...
|
|
55
62
|
|
|
@@ -101,6 +101,7 @@ Keep top-level `profile` and emit this top-level object in every new `pipeline.j
|
|
|
101
101
|
- If prompt or `brief.md` contains `figma.com` on `feature` / `refactor` / `spike` / `spec-gen`, insert **mockup-reviewer** after **task-analyst** (when present) and before **solution-architect** and **feature-developer**. Set `model: "strong"` on that step. Do not add static `humanGates: ["after:mockup-reviewer"]` (FAIL-only hook exception). Never put `mockup-reviewer` in a `parallel: true` step (FAIL-only gate is serial).
|
|
102
102
|
- Classify intent `mockup-review` **before** `ux-design` **before** `review-only`. A `figma.com` URL with review-not-implement language is `mockup-review` even without the word «макет», including when the user said «ревью UX». <!-- i18n-keep: E4 -->
|
|
103
103
|
- If UI stack and (required-signal or advisory UI AC), instruct **task-analyst** to load skill `ux-design` (no new pipeline step; analyst default model, not `strong`). Required-signal: user asked UX, or AC require flows/states, or spec-gen page/feature.
|
|
104
|
+
- If the resolved scope touches UI paths (`app/src/ui/**`, or the repo's component-catalog root) on `feature` / `refactor`, insert **mockup-reviewer** even **without** a `figma.com` URL — it reviews against the AC / `ux-design.md` instead of Figma. Pair it with a **`mockup-review.md`** terminal artifact requirement (the UI change is not complete without it) and, where the repo ships a component catalog, a catalog-test note on `build-verifier` (`component-catalog-gate`).
|
|
104
105
|
- Skip **task-analyst** if AC/scope fully specified → document in `skipped`.
|
|
105
106
|
- Add **solution-architect** for cross-layer / new public APIs — after analyst, before developer.
|
|
106
107
|
- Add **api-contract-reviewer** for new/changed backend contracts — before developer.
|
|
@@ -6,7 +6,18 @@ glob: always
|
|
|
6
6
|
|
|
7
7
|
When this rule applies, acknowledge: `Using .ai.local: agent-artifacts-no-local-paths(, …)*`.
|
|
8
8
|
|
|
9
|
-
Committed agent artifacts leak into git history. Absolute host paths expose the developer machine layout even if the file is deleted in a later MR.
|
|
9
|
+
Committed agent artifacts leak into git history. Absolute host paths (`/Users/<username>/…`) expose the developer machine layout even if the file is deleted in a later MR.
|
|
10
|
+
|
|
11
|
+
## Scope (mandatory)
|
|
12
|
+
|
|
13
|
+
Every agent-written file that may be committed, especially:
|
|
14
|
+
|
|
15
|
+
- `.ai.local/team/tasks/<slug>/pipeline.json`
|
|
16
|
+
- `.ai.local/team/tasks/<slug>/artifact-manifest.json` (`authoritativePaths`, `evidencePaths`, any path array)
|
|
17
|
+
- `.ai.local/team/**` markdown (`brief.md`, `decomposition.md`, `implementation.md`, `review.md`, `validation-report.md`, …)
|
|
18
|
+
- `.ai.local/team/active-task.json` and other team JSON
|
|
19
|
+
|
|
20
|
+
Same ban for any other agent-authored committed path (`openspec/**`, `docs/**`).
|
|
10
21
|
|
|
11
22
|
## Forbidden
|
|
12
23
|
|
|
@@ -14,20 +25,42 @@ Do **not** write host-absolute paths, including:
|
|
|
14
25
|
|
|
15
26
|
- `/Users/<username>/…` (macOS)
|
|
16
27
|
- `/home/<username>/…` (Linux)
|
|
17
|
-
- `C:\Users\<username>\…` and `C:/Users/<username
|
|
18
|
-
- Any other absolute checkout root
|
|
28
|
+
- `C:\Users\<username>\…` and `C:/Users/<username>\…` (Windows)
|
|
29
|
+
- Any other absolute checkout root (`/Users/…/<workspace>/<repo>`, `~/…` expanded)
|
|
19
30
|
|
|
20
|
-
Do **not** put those strings in `
|
|
31
|
+
Do **not** put those strings in `instructions[]`, config values, summaries, or `authoritativePaths` / `evidencePaths`.
|
|
21
32
|
|
|
22
33
|
## Required instead
|
|
23
34
|
|
|
24
|
-
- This repo: path from
|
|
25
|
-
- Task-local artifacts: basename is enough (`pipeline.json`, `brief.md`) when the file lives in the same task directory.
|
|
35
|
+
- This repo: repo-relative path from the repo root (`app/src/…`, `.ai.local/team/tasks/<slug>/pipeline.json`).
|
|
36
|
+
- Task-local artifacts: basename is enough (`pipeline.json`, `brief.md`) when the file lives in the same task directory — match `.ai.local/team/fixtures/artifact-manifest.example.json`.
|
|
26
37
|
- Sibling / other repo: **repo name** + repo-relative path. Never the filesystem location of that checkout.
|
|
27
38
|
|
|
39
|
+
```jsonc
|
|
40
|
+
// ❌ BAD — a receipt in artifact-manifest.json leaking the host path
|
|
41
|
+
{
|
|
42
|
+
"receipt": {
|
|
43
|
+
"evidencePaths": [
|
|
44
|
+
"/Users/<username>/<workspace>/other-repo/app/src/modules/health-tracking/"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ✅ GOOD — repo-relative; another repo is prefixed by its name
|
|
50
|
+
{
|
|
51
|
+
"receipt": {
|
|
52
|
+
"evidencePaths": [
|
|
53
|
+
"other-repo:app/src/modules/health-tracking/"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Prose: `other-repo` `app/src/modules/health-tracking/` — not a `/Users/…` prefix.
|
|
60
|
+
|
|
28
61
|
## Gate before finishing a write
|
|
29
62
|
|
|
30
|
-
After writing or editing a team artifact, scan the file (and
|
|
63
|
+
After writing or editing a team artifact, scan the file (and the JSON you are about to write) for `/Users/`, `/home/`, `C:\Users`, `C:/Users`. If any match, rewrite to repo-relative **before** considering the step done. Do not `git add` until clean.
|
|
31
64
|
|
|
32
65
|
Deleting a leaked file later does **not** remove it from git history — prevention is the only fix.
|
|
33
66
|
|
|
@@ -35,4 +68,4 @@ Deleting a leaked file later does **not** remove it from git history — prevent
|
|
|
35
68
|
|
|
36
69
|
- Repo-relative paths, `@/` aliases, URL paths (`/api/…`).
|
|
37
70
|
- Public URLs (`https://…`, `figma.com/…`).
|
|
38
|
-
- Ephemeral local logs that are **not** committed.
|
|
71
|
+
- Ephemeral local logs that are **not** committed (e.g. `/tmp/….log`). Do not copy those absolute paths into committed artifacts; cite the command or a repo-relative copy instead.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
glob: always
|
|
2
|
+
|
|
3
|
+
## Body
|
|
4
|
+
|
|
5
|
+
# Agent pipeline gates (local overlay)
|
|
6
|
+
|
|
7
|
+
These gates are **agent-enforced** (local rules; the preset hook/router is not edited). Treat them as MUST, not advisory. Acknowledge: `Using .ai.local: agent-pipeline-gates(, …)*`.
|
|
8
|
+
|
|
9
|
+
## Gates
|
|
10
|
+
|
|
11
|
+
- **UI scope** (`app/src/ui/**`): the pipeline MUST include `mockup-reviewer` — not only when a `figma.com` URL is present. A terminal `mockup-review.md` with verdict `PASS`/`PASS_WITH_NOTES` is required before the task is complete. Missing artifact = **blocked**, not a warning. (See `ui-change-review-gate`.)
|
|
12
|
+
- **DTO/type scope**: `api-contract-reviewer` is blocking per `api-contract-source`.
|
|
13
|
+
- **build-verifier**: when `storybook/**` or `app/src/ui/**` changed, run targeted storybook tests and require green **without** `--update`.
|
|
14
|
+
- **code-reviewer**: (a) a behaviour change under `app/src/**` without a matching `docs/qa/**` or `*.cases.md` update → WARN (REQUEST_CHANGES when AC names the case); (b) a production behaviour change made to satisfy a test → **blocker**; (c) every review artifact states the reviewed revision (sha or `working tree @ <date>`).
|
|
15
|
+
- **single writer**: do not rewrite a block shipped the same day without a new review artifact and an owner.
|
|
16
|
+
|
|
17
|
+
## Why local, not preset
|
|
18
|
+
|
|
19
|
+
The mechanical hook/router gate would live in the preset-managed hook + router, which `init` overwrites. Per project decision, all gate changes stay in `.ai.local` (agent-enforced).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
globs: app/src/analytics/**/*.{ts,tsx},app/src/ui/**/*.{ts,tsx}
|
|
2
|
+
|
|
3
|
+
## Body
|
|
4
|
+
|
|
5
|
+
# Analytics / telemetry events (team conventions template)
|
|
6
|
+
|
|
7
|
+
When emitting or changing an analytics/telemetry event, acknowledge: `Using .ai.local: analytics-events(, …)*`.
|
|
8
|
+
|
|
9
|
+
Events go through one owned module per domain — not scattered `pushEvent` / `track` calls in components.
|
|
10
|
+
|
|
11
|
+
## Rules
|
|
12
|
+
|
|
13
|
+
- Event modules live under `app/src/analytics/events/<domain>/` and expose `logX(...)` functions wrapping the analytics client (`pushEvent` or repo equivalent); payload types live in a sibling `*.types.ts`.
|
|
14
|
+
- Components emit events via a hook or store slice (`_complexSlices/Analytics` analog), not by importing the analytics client directly.
|
|
15
|
+
- Respect the repo's gating flag (e.g. `NEXT_PUBLIC_*_ANALYTICS_DISABLED`) and the init in the app root; do not initialize adapters twice.
|
|
16
|
+
- Deduplicate repeated events with the repo's cache idiom when it exists.
|
|
17
|
+
- **Never** put PD, medical/record text, raw auth tokens, or full URL search params into a payload. See the security rule's compliance section.
|
|
18
|
+
- Analytics is a side effect: cross-slice event emission belongs in listener middleware, not in a reducer (see `store-rtk`).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
globs: app/src/api/**/*.{ts,tsx},app/src/types/**/*.{ts,tsx},app/src/mocks/**/*.{ts,tsx}
|
|
2
|
+
|
|
3
|
+
## Body
|
|
4
|
+
|
|
5
|
+
# API contract source is mandatory (no invented DTOs)
|
|
6
|
+
|
|
7
|
+
When changing DTOs, response types, mappers, or mocks, acknowledge: `Using .ai.local: api-contract-source(, …)*`.
|
|
8
|
+
|
|
9
|
+
## Rules
|
|
10
|
+
|
|
11
|
+
- Any new/changed DTO, response type, response mapper, or shared type **names its contract source** in the task brief: an OpenAPI path + schema (or the project's equivalent contract), or an explicit `no in-repo contract — capture is provisional` risk.
|
|
12
|
+
- The API-contract reviewer is **blocking** when the contract source is a capture and the DTO is new/changed → emit `changes_requested`, not advisory notes.
|
|
13
|
+
- Map only fields present in the contract source. Do not add a field that exists only in mockup copy or a guessed payload.
|
|
14
|
+
- Watch nullability / object-vs-scalar: verify against the contract schema, not a single capture (a capture cannot show absent/empty cases).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
glob: always
|
|
2
|
+
|
|
3
|
+
## Body
|
|
4
|
+
|
|
5
|
+
# Agent artifact lifecycle
|
|
6
|
+
|
|
7
|
+
When writing team artifacts, acknowledge: `Using .ai.local: artifact-lifecycle(, …)*`.
|
|
8
|
+
|
|
9
|
+
Task-folder artifacts (`.ai.local/team/tasks/<slug>/**`) are an **audit trail**, not a second source of truth. Durable knowledge (decisions, contracts, product behaviour) belongs in `docs/specs/**` or `openspec/**`.
|
|
10
|
+
|
|
11
|
+
## Rules
|
|
12
|
+
|
|
13
|
+
- `.ai.local/team/tasks/**` stays **tracked in git** by default; do not add a gitignore entry. Committing task artifacts is the human's choice at the commit step.
|
|
14
|
+
- Keep artifacts **small**: no host paths (see `agent-artifacts-no-local-paths`), no raw diff dumps, no duplicate copies (`* (1).*`), no screenshots beyond intentional baselines.
|
|
15
|
+
- **Never bulk-purge** committed artifacts to "clean up". Deleting does not remove git history. Prevention only.
|
|
16
|
+
- Durable output (approved spec, ADR, contract, QA cases) is copied into `docs/specs/**` / `openspec/**`; the task folder is not the SoT.
|
|
17
|
+
- Follow `commit-hygiene`: artifact/doc churn does not share a commit with `app/src/**`.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
globs: app/src/**/*.{ts,tsx},app/__tests__/**/*.{ts,tsx}
|
|
2
|
+
|
|
3
|
+
## Body
|
|
4
|
+
|
|
5
|
+
# Code style (team conventions template)
|
|
6
|
+
|
|
7
|
+
When editing TS/TSX, acknowledge: `Using .ai.local: code-style(, …)*`.
|
|
8
|
+
|
|
9
|
+
The preset is generic. This repo has its own naming and file shapes — **open the nearest analog in the same layer and mirror it**. Where a preset example differs, this rule wins.
|
|
10
|
+
|
|
11
|
+
## Reference analogs (mirror these)
|
|
12
|
+
|
|
13
|
+
| Layer | Analog |
|
|
14
|
+
|-------|--------|
|
|
15
|
+
| UI page | `app/src/ui/pages/<Domain>/` |
|
|
16
|
+
| UI component | `app/src/ui/components/<Name>/` |
|
|
17
|
+
| Store slice | `app/src/store/slices/<Domain>/` |
|
|
18
|
+
| API service | `app/src/api/services/<Service>/<Domain>/` |
|
|
19
|
+
| Types | `app/src/types/<Entity>.types.ts` |
|
|
20
|
+
| Unit tests | `app/__tests__/unit/<mirrored path>/` |
|
|
21
|
+
|
|
22
|
+
## Naming
|
|
23
|
+
|
|
24
|
+
- Domain types — `T` prefix: `TAnalysis`, `TUserProfile`. Transport/response types — `T…Response` (`TAnalysisResponse`).
|
|
25
|
+
- Interfaces / props — `I` prefix: `interface IProps`, `IRootState`.
|
|
26
|
+
- DTO → domain mappers — verb `format`: `formatAnalysis`, `formatBiomarkers`. Not `map…`.
|
|
27
|
+
- Endpoint constants — `SCREAMING_SNAKE` + `_ENDPOINT` (`DOMAIN_ANALYSIS_ENDPOINT`); dynamic — `prepare…Endpoint`.
|
|
28
|
+
- No `FC` / `React.FC` (see `no-react-fc`).
|
|
29
|
+
|
|
30
|
+
## Components
|
|
31
|
+
|
|
32
|
+
- `export const X = ({ ... }: IProps) => (...)`; no `FC`.
|
|
33
|
+
- Styles: a sibling styles module; root export `Root`.
|
|
34
|
+
- Local children in `./components/<Name>/`: `Name.tsx` + `styles.ts` (or `Name.styles.ts` when the parent already has a `styles.ts`) + optional `Name.data.ts` / `Name.utils.ts` / `Name.hooks.ts` + `index.ts`. **Strictly forbidden:** declaring a subcomponent in the same file as the parent — see `component-child-decomposition`.
|
|
35
|
+
- Layout sizes of one component (skeleton `height` / `width` / `maxWidth`, one-off `px`) stay as literals in the JSX prop or in `styles.ts`. Do not hoist them into `SCREAMING_SNAKE` constants or a `*.data.ts`.
|
|
36
|
+
- `*.data.ts` is for copy, labels, lookup maps, and values imported by another module. A file that only names pixels is overhead — delete it and inline.
|
|
37
|
+
|
|
38
|
+
## API layer (`app/src/api/services/<Service>/<Domain>/`)
|
|
39
|
+
|
|
40
|
+
- `<Domain>.apiMethods.ts` — `export const XxxApiMethods = { fetchX, createX, saveX, deleteX: async (...) => { … } }`.
|
|
41
|
+
- `<Domain>.endpoints.ts` — path constants.
|
|
42
|
+
- `<Domain>.responseTypes.ts` — `T…Response` (DTO).
|
|
43
|
+
- `<Domain>.responseMappers.ts` — `formatXxx(data: T…Response): T…`.
|
|
44
|
+
- `index.ts` — re-export the four above.
|
|
45
|
+
- Cross-entity mappers — `_shared/<Entity>/<Entity>.responseMappers.ts`.
|
|
46
|
+
- Outside the layer, import only from the `@/api` barrel.
|
|
47
|
+
|
|
48
|
+
## Store (`app/src/store/slices/<Domain>/`)
|
|
49
|
+
|
|
50
|
+
- Folder: `<Domain>.ts` (slice + thunks + selectors), `types.ts`, `utils.ts`, `index.ts` barrel.
|
|
51
|
+
- Slice named `xxxSlice`, re-exported via the barrel; not a default export.
|
|
52
|
+
- Thunks: `fetchX` / `createX` / `saveX` / `deleteX`; error typing via `rejectWithValue`.
|
|
53
|
+
- Selectors: curried `xxxSelector = (args) => (state: IRootState) => …`; memoize derived values with `createSelector`.
|
|
54
|
+
- Local `interface IRootState { <sliceName>: TState }` in the slice file; state shape typed in `types.ts`.
|
|
55
|
+
- Errors: follow the existing slice pattern; do not rewrite the error model in a point task.
|
|
56
|
+
- Domain comments — in the project language.
|
|
57
|
+
|
|
58
|
+
## Types (`app/src/types`)
|
|
59
|
+
|
|
60
|
+
- Project-language JSDoc; `[computed]` prefix on frontend-derived fields; `Xxx.types.ts` or a folder + barrel `index.ts`.
|
|
61
|
+
|
|
62
|
+
## Tests
|
|
63
|
+
|
|
64
|
+
- Mirrored path `app/__tests__/unit/<rel>`, `*.spec.ts(x)`; project-language `describe` / `it`.
|
|
65
|
+
|
|
66
|
+
## Format
|
|
67
|
+
|
|
68
|
+
- Prettier: no semicolons, single quotes, trailing commas, width 100. The linter enforces it — run the post-change gate.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
globs: app/src/**/*.{ts,tsx},storybook/stories/**/*.stories.tsx
|
|
2
|
+
|
|
3
|
+
## Body
|
|
4
|
+
|
|
5
|
+
# Component child decomposition (strict)
|
|
6
|
+
|
|
7
|
+
When this rule applies, acknowledge: `Using .ai.local: component-child-decomposition(, …)*`.
|
|
8
|
+
|
|
9
|
+
A subcomponent of a parent UI component **must** live in a dedicated `components/<Name>/` subfolder of the parent. Defining a subcomponent in the same file as the parent is a **forbidden** shortcut — it breaks the convention used by every other modal/card in the repo, makes the parent file mix orchestration with detail rendering, and prevents re-use of the child from sibling features.
|
|
10
|
+
|
|
11
|
+
This is enforced by the file structure visible in the working tree. A reviewer or `code-reviewer` agent who finds a subcomponent declared alongside the parent's main export must request changes with reference to this rule.
|
|
12
|
+
|
|
13
|
+
## File structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Parent/
|
|
17
|
+
├── Parent.tsx ← public export, thin composition only
|
|
18
|
+
├── Parent.styles.ts ← only styles used directly by Parent (Root, Title, layout shell, list)
|
|
19
|
+
├── index.ts ← re-export of Parent
|
|
20
|
+
└── components/
|
|
21
|
+
└── Child/
|
|
22
|
+
├── Child.tsx ← public export of the subcomponent
|
|
23
|
+
├── Child.styles.ts ← styles specific to the child (its own Card, Icon, Title, etc.)
|
|
24
|
+
├── Child.utils.ts ← OPTIONAL: pure helpers
|
|
25
|
+
├── Child.data.ts ← OPTIONAL: lookup maps / constants
|
|
26
|
+
└── index.ts ← re-export of Child
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Child file name: `Child.tsx` (PascalCase, same as folder name). Styles: `Child.styles.ts` (prefixed with child name) to avoid collision when the parent also has a `styles.ts`.
|
|
30
|
+
- Parent uses `import { Child } from './components/Child'` (or `./components/Child/index`); never imports from `../Child.tsx` or `../../Child`.
|
|
31
|
+
- The child does not import from the parent's `styles.ts`. If both share a token, they each import it from the design-token source directly.
|
|
32
|
+
- `Child.utils.ts` / `Child.data.ts` are optional and only added when there are real helpers/maps. Do not create empty files.
|
|
33
|
+
|
|
34
|
+
## Subcomponents
|
|
35
|
+
|
|
36
|
+
A **subcomponent** is any JSX `<X .../>` (a) the parent repeats, (b) the parent passes resolved props to (instead of letting the child compute them), or (c) that owns its own layout/typography/visual contract. Inline JSX like `<s.Icon><img/></s.Icon>` is a styled element, not a subcomponent.
|
|
37
|
+
|
|
38
|
+
When the parent has more than one or two branches, several repeated JSX subtrees, or any non-trivial rendering block, that block **must** be extracted to a subcomponent in `./components/<Name>/`. The parent then becomes a thin switch — it owns the wiring, the wrapper, and the iteration that maps data into `<Child>` instances.
|
|
39
|
+
|
|
40
|
+
## Forbidden
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
// ❌ Parent file with a co-located subcomponent
|
|
44
|
+
export const ItemsModal = () => (
|
|
45
|
+
<Modal>
|
|
46
|
+
{items.map((item) => (
|
|
47
|
+
<s.Card key={item.id}>
|
|
48
|
+
<s.Icon><s.IconImage src={...} /></s.Icon>
|
|
49
|
+
<s.Body><s.Title>{item.title}</s.Title>...</s.Body>
|
|
50
|
+
</s.Card>
|
|
51
|
+
))}
|
|
52
|
+
</Modal>
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
// Declared in the same file — file structure is wrong
|
|
56
|
+
const CardItem = ({ item }) => <s.Card>...</s.Card>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Correct
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
// ItemsModal/ItemsModal.tsx
|
|
63
|
+
import { CardItem } from './components/CardItem'
|
|
64
|
+
|
|
65
|
+
export const ItemsModal = () => (
|
|
66
|
+
<Modal>{items.map((i) => <CardItem key={i.id} item={i} />)}</Modal>
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
// ItemsModal/components/CardItem/CardItem.tsx
|
|
70
|
+
import * as s from './CardItem.styles'
|
|
71
|
+
|
|
72
|
+
export const CardItem = ({ item }: { item: TItem }) => <s.Card>...</s.Card>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Why the rule is strict, not a preference
|
|
76
|
+
|
|
77
|
+
- **Diffability:** a change to the child shows up in `components/Child/Child.tsx`, not as noise in the parent file.
|
|
78
|
+
- **Reviewability:** the parent file stays short (~50 lines) and the reviewer reads orchestration without scrolling past detail rendering.
|
|
79
|
+
- **Re-use:** the child can be imported by other stories, modals, or pages without copy-paste.
|
|
80
|
+
- **Tests:** a child-only story (visual regression of the card alone) is possible without re-rendering the whole modal.
|
|
81
|
+
- **Lint / IDE:** per-folder patterns scale better than 200-line parent files mixing styles + helpers + subcomponents + data.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
globs: app/src/constants/**/*.{ts,tsx},app/src/ui/**/*.{ts,tsx}
|
|
2
|
+
|
|
3
|
+
## Body
|
|
4
|
+
|
|
5
|
+
# Feature flags & experiments (team conventions template)
|
|
6
|
+
|
|
7
|
+
When gating UI/behaviour by a flag or A/B experiment, acknowledge: `Using .ai.local: feature-flags-experiments(, …)*`.
|
|
8
|
+
|
|
9
|
+
## Rules
|
|
10
|
+
|
|
11
|
+
- Local flags live in one module (e.g. `app/src/constants/localFeatureFlags.ts`) as `isFeature…Enabled`; remote experiments come from the experiments client (`@sh/experiments` analog).
|
|
12
|
+
- Read a flag through the repo's access path — a store slice / provider / singleton mounted at the app root — not by scattering `process.env` checks or ad-hoc constants.
|
|
13
|
+
- Experiment-gated routes are registered in the repo's allowlist (e.g. `EXPERIMENT_PAGES`); do not invent a parallel mechanism.
|
|
14
|
+
- Experimental / legacy page variants are **non-canonical** — do not copy them as the reference for new work, and do not delete a flag without the paired spec / story / e2e sync (flag removal is a cross-cutting change).
|
|
15
|
+
- A flag that flips layout or visual identity is still one purpose per component after the flag is removed — do not bake the flag into a universal branchy component (`react-ui`).
|