feat(flutter-cursor-templates): introduce MCP integration and conventions in project brief
- Added optional MCP integration settings in project-brief.yaml, allowing for environment-based server configurations. - Introduced conventions for strict package imports to enhance code organization and maintainability. - Updated brief schema to validate new MCP properties and ensure correct usage. - Implemented MCP JSON builder to generate .cursor/mcp.json based on project brief settings. - Enhanced resolver to include MCP configuration in generated files when enabled. This update improves integration capabilities and enforces coding standards across the project.
This commit is contained in:
@@ -8,6 +8,7 @@ import '../src/resolver.dart';
|
||||
import '../src/renderer.dart';
|
||||
import '../src/validator.dart';
|
||||
import '../src/models.dart';
|
||||
import '../src/mcp_json.dart';
|
||||
|
||||
void main() {
|
||||
// ─── Resolver tests ─────────────────────────────────────────────────────────
|
||||
@@ -17,10 +18,26 @@ void main() {
|
||||
final files = Resolver.resolve(kBlocCleanFirebaseBrief);
|
||||
|
||||
// Universal — always present
|
||||
expect(files.first, equals('rules/universal/rule-authoring'));
|
||||
expect(files, contains('rules/universal/flutter-core'));
|
||||
expect(files, contains('rules/universal/ui-ux-standards'));
|
||||
expect(files, contains('rules/universal/project-context'));
|
||||
|
||||
// CI/CD rule when cicd set or multiple flavors
|
||||
expect(files, contains('rules/cicd/cicd'));
|
||||
|
||||
// Feature stubs from brief
|
||||
expect(files, contains('rules/features/auth'));
|
||||
expect(files, contains('rules/features/home'));
|
||||
expect(files, contains('rules/features/products'));
|
||||
|
||||
// Cursor workspace extras
|
||||
expect(files, contains('root/.cursorignore'));
|
||||
expect(files, contains('root/tool/cursor_audit.sh'));
|
||||
expect(files, contains('onboarding/ONBOARDING'));
|
||||
expect(files, contains('commands/build'));
|
||||
expect(files, contains('commands/debug-issue'));
|
||||
|
||||
// Security — always present (Pillar 5)
|
||||
expect(files, contains('rules/security/security-standards'));
|
||||
|
||||
@@ -57,6 +74,9 @@ void main() {
|
||||
expect(files, containsNot('rules/architecture/feature_first'));
|
||||
expect(files, containsNot('rules/routing/getx_nav'));
|
||||
|
||||
expect(files, contains('commands/verify-change'));
|
||||
expect(files, contains('commands/explain-code'));
|
||||
expect(files, containsNot('config/mcp-json'));
|
||||
expect(files, contains('root/AGENTS.md'));
|
||||
expect(files, contains('root/lefthook.yaml'));
|
||||
});
|
||||
@@ -72,6 +92,175 @@ void main() {
|
||||
expect(files, containsNot('agents/migration-agent'));
|
||||
});
|
||||
|
||||
test('featureRuleKey sanitizes module names', () {
|
||||
expect(Resolver.featureRuleKey('My Cart'), 'rules/features/my_cart');
|
||||
expect(Resolver.featureRuleKey('auth'), 'rules/features/auth');
|
||||
expect(Resolver.featureRuleKey(' '), isNull);
|
||||
});
|
||||
|
||||
test('MCP template key when integrations.mcp.enabled', () {
|
||||
final brief = ProjectBrief(
|
||||
projectName: 'McpApp',
|
||||
packageId: 'com.test.mcp',
|
||||
description: '',
|
||||
scale: 'small',
|
||||
stateManagement: 'bloc',
|
||||
routing: 'gorouter',
|
||||
architecture: 'clean',
|
||||
backends: ['firebase'],
|
||||
auth: 'none',
|
||||
platforms: ['ios'],
|
||||
codegenTools: [],
|
||||
flavors: ['dev'],
|
||||
cicd: 'none',
|
||||
testingDepth: 'unit_widget',
|
||||
e2eTool: 'patrol',
|
||||
designSource: 'none',
|
||||
figmaUrl: '',
|
||||
apiDocsFormat: 'none',
|
||||
apiDocsPath: '',
|
||||
referenceRepos: [],
|
||||
localPaths: [],
|
||||
featureModules: [],
|
||||
specialFeatures: [],
|
||||
i18nEnabled: false,
|
||||
locales: ['en'],
|
||||
mcpConfigEnabled: true,
|
||||
);
|
||||
expect(Resolver.resolve(brief), contains('config/mcp-json'));
|
||||
});
|
||||
|
||||
test('Push/deeplink rule when special features request it', () {
|
||||
final brief = ProjectBrief(
|
||||
projectName: 'PushApp',
|
||||
packageId: 'com.test.push',
|
||||
description: '',
|
||||
scale: 'small',
|
||||
stateManagement: 'bloc',
|
||||
routing: 'gorouter',
|
||||
architecture: 'clean',
|
||||
backends: ['rest'],
|
||||
auth: 'none',
|
||||
platforms: ['ios'],
|
||||
codegenTools: [],
|
||||
flavors: ['dev'],
|
||||
cicd: 'none',
|
||||
testingDepth: 'unit_widget',
|
||||
e2eTool: 'patrol',
|
||||
designSource: 'none',
|
||||
figmaUrl: '',
|
||||
apiDocsFormat: 'none',
|
||||
apiDocsPath: '',
|
||||
referenceRepos: [],
|
||||
localPaths: [],
|
||||
featureModules: [],
|
||||
specialFeatures: ['push_notifications'],
|
||||
i18nEnabled: false,
|
||||
locales: ['en'],
|
||||
);
|
||||
expect(Resolver.resolve(brief), contains('rules/integrations/push-deeplink'));
|
||||
});
|
||||
|
||||
test('Theming rule when high contrast requested', () {
|
||||
final brief = ProjectBrief(
|
||||
projectName: 'A11yApp',
|
||||
packageId: 'com.test.a11y',
|
||||
description: '',
|
||||
scale: 'small',
|
||||
stateManagement: 'bloc',
|
||||
routing: 'gorouter',
|
||||
architecture: 'clean',
|
||||
backends: ['rest'],
|
||||
auth: 'none',
|
||||
platforms: ['ios'],
|
||||
codegenTools: [],
|
||||
flavors: ['dev'],
|
||||
cicd: 'none',
|
||||
testingDepth: 'unit_widget',
|
||||
e2eTool: 'patrol',
|
||||
designSource: 'none',
|
||||
figmaUrl: '',
|
||||
apiDocsFormat: 'none',
|
||||
apiDocsPath: '',
|
||||
referenceRepos: [],
|
||||
localPaths: [],
|
||||
featureModules: [],
|
||||
specialFeatures: [],
|
||||
i18nEnabled: false,
|
||||
locales: ['en'],
|
||||
themeVariants: const ['light', 'dark', 'high_contrast'],
|
||||
);
|
||||
expect(Resolver.resolve(brief), contains('rules/theming/theming'));
|
||||
});
|
||||
|
||||
test('Telemetry helpers when telemetry_opt_in', () {
|
||||
final brief = ProjectBrief(
|
||||
projectName: 'TelApp',
|
||||
packageId: 'com.test.tel',
|
||||
description: '',
|
||||
scale: 'small',
|
||||
stateManagement: 'bloc',
|
||||
routing: 'gorouter',
|
||||
architecture: 'clean',
|
||||
backends: ['rest'],
|
||||
auth: 'none',
|
||||
platforms: ['ios'],
|
||||
codegenTools: [],
|
||||
flavors: ['dev'],
|
||||
cicd: 'none',
|
||||
testingDepth: 'unit_widget',
|
||||
e2eTool: 'patrol',
|
||||
designSource: 'none',
|
||||
figmaUrl: '',
|
||||
apiDocsFormat: 'none',
|
||||
apiDocsPath: '',
|
||||
referenceRepos: [],
|
||||
localPaths: [],
|
||||
featureModules: [],
|
||||
specialFeatures: [],
|
||||
i18nEnabled: false,
|
||||
locales: ['en'],
|
||||
telemetryOptIn: true,
|
||||
);
|
||||
final files = Resolver.resolve(brief);
|
||||
expect(files, contains('telemetry/gitignore'));
|
||||
expect(files, contains('telemetry/log-sh'));
|
||||
expect(files, contains('rules/telemetry/usage-logging'));
|
||||
});
|
||||
|
||||
test('McpJsonBuilder minimal preset emits empty mcpServers', () {
|
||||
const brief = ProjectBrief(
|
||||
projectName: 'M',
|
||||
packageId: 'com.m.m',
|
||||
description: '',
|
||||
scale: 'small',
|
||||
stateManagement: 'bloc',
|
||||
routing: 'gorouter',
|
||||
architecture: 'clean',
|
||||
backends: ['rest'],
|
||||
auth: 'none',
|
||||
platforms: ['ios'],
|
||||
codegenTools: [],
|
||||
flavors: ['dev'],
|
||||
cicd: 'none',
|
||||
testingDepth: 'unit_widget',
|
||||
e2eTool: 'patrol',
|
||||
designSource: 'none',
|
||||
figmaUrl: '',
|
||||
apiDocsFormat: 'none',
|
||||
apiDocsPath: '',
|
||||
referenceRepos: [],
|
||||
localPaths: [],
|
||||
featureModules: [],
|
||||
specialFeatures: [],
|
||||
i18nEnabled: false,
|
||||
locales: ['en'],
|
||||
mcpConfigEnabled: true,
|
||||
mcpPreset: 'minimal',
|
||||
);
|
||||
expect(McpJsonBuilder.build(brief), contains('"mcpServers": {}'));
|
||||
});
|
||||
|
||||
test('GetX + MVC includes migration-agent', () {
|
||||
final files = Resolver.resolve(kGetxMvcRestBrief);
|
||||
expect(files, contains('agents/migration-agent'));
|
||||
@@ -245,6 +434,51 @@ void main() {
|
||||
'Default template dir should resolve real arch-guard.ts.tmpl');
|
||||
expect(content, contains('arch-guard'));
|
||||
});
|
||||
|
||||
test('mcp.json renders from config/mcp-json key', () async {
|
||||
final templateDir = _templateDir();
|
||||
if (!Directory(templateDir).existsSync()) {
|
||||
markTestSkipped('Template directory not found');
|
||||
return;
|
||||
}
|
||||
final brief = ProjectBrief(
|
||||
projectName: 'McpApp',
|
||||
packageId: 'com.test.mcp',
|
||||
description: '',
|
||||
scale: 'small',
|
||||
stateManagement: 'bloc',
|
||||
routing: 'gorouter',
|
||||
architecture: 'clean',
|
||||
backends: const ['firebase'],
|
||||
auth: 'none',
|
||||
platforms: const ['ios'],
|
||||
codegenTools: const [],
|
||||
flavors: const ['dev'],
|
||||
cicd: 'none',
|
||||
testingDepth: 'unit_widget',
|
||||
e2eTool: 'patrol',
|
||||
designSource: 'none',
|
||||
figmaUrl: '',
|
||||
apiDocsFormat: 'none',
|
||||
apiDocsPath: '',
|
||||
referenceRepos: const [],
|
||||
localPaths: const [],
|
||||
featureModules: const [],
|
||||
specialFeatures: const [],
|
||||
i18nEnabled: false,
|
||||
locales: const ['en'],
|
||||
mcpConfigEnabled: true,
|
||||
);
|
||||
final rendered = await Renderer.render(
|
||||
brief: brief,
|
||||
templateFiles: const ['config/mcp-json'],
|
||||
templateSrc: templateDir,
|
||||
);
|
||||
final json = rendered['mcp.json']!;
|
||||
expect(json, contains('mcpServers'));
|
||||
expect(json, contains('filesystem'));
|
||||
expect(json, contains('firebase'));
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Validator tests ─────────────────────────────────────────────────────────
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Cursor — TestApp
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Open this repo in **Cursor** so `.cursor/rules/` and `.cursor/skills/` load automatically.
|
||||
2. Read **`rules/universal/rule-authoring.mdc`** — how we maintain AI rules.
|
||||
3. Stack and product context live in **`project-brief.yaml`** at the repo root; regenerate `.cursor/` with `cursor_gen` after changing it.
|
||||
4. **Slash skills** (primary workflows): open the Command Palette and use the project commands, or reference:
|
||||
- `.cursor/skills/build/SKILL.md` — end-to-end feature implementation
|
||||
- `.cursor/skills/debug-issue/SKILL.md` — structured debugging
|
||||
- `.cursor/skills/verify-change/SKILL.md` — pre-PR verification
|
||||
- `.cursor/skills/explain-code/SKILL.md` — explain-only walkthroughs
|
||||
5. **Agents** (`.cursor/agents/*.mdc`) are reusable reviewer personas — attach when asking for code review or focused passes.
|
||||
6. **Custom overrides**: files under `.cursor/custom/` and `CURSOR:CUSTOM` blocks in generated files are preserved on `cursor_gen --refresh` (see generator docs).
|
||||
|
||||
## Optional
|
||||
|
||||
- **`integrations.mcp.enabled`** in `project-brief.yaml` — generates `.cursor/mcp.json` with env-based server entries (no secrets in git).
|
||||
- **`telemetry_opt_in: true`** — emits local telemetry helpers under `.cursor/telemetry/` (never commit usage logs if you enable logging).
|
||||
- Run **`bash tool/cursor_audit.sh`** from the project root periodically to catch stale feature rules and overly broad `alwaysApply` usage.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# Build artefacts
|
||||
build/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
*.g.dart
|
||||
*.freezed.dart
|
||||
*.gr.dart
|
||||
*.config.dart
|
||||
|
||||
# Secrets
|
||||
.env
|
||||
.env.*
|
||||
firebase_options.dart
|
||||
google-services.json
|
||||
GoogleService-Info.plist
|
||||
|
||||
# Large binary assets
|
||||
assets/fonts/
|
||||
assets/videos/
|
||||
*.aab
|
||||
*.apk
|
||||
*.ipa
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
*.iml
|
||||
+2
-1
@@ -3,4 +3,5 @@
|
||||
Repo-level notes for AI assistants. Authoritative stack and conventions are in `project-brief.yaml` and `.cursor/` (regenerate with `cursor_gen` from the project root).
|
||||
|
||||
- **Package:** `com.test.testapp`
|
||||
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain`
|
||||
- **Onboarding:** `.cursor/ONBOARDING.md` — layout, slash commands → skills, MCP opt-in, audits
|
||||
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain` (see `.cursor/commands/*.md`)
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
# TestApp — generated by cursor_gen; adjust commands to your repo
|
||||
# Optional: run `bash tool/cursor_audit.sh` after changing features.modules or rule files.
|
||||
pre-commit:
|
||||
commands:
|
||||
flutter-analyze:
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
# TestApp — Cursor rule hygiene (generated by cursor_gen)
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
CURSOR="${ROOT}/.cursor"
|
||||
RULES="${CURSOR}/rules"
|
||||
|
||||
echo "== cursor_audit (${ROOT}) =="
|
||||
|
||||
if [[ ! -d "$CURSOR" ]]; then
|
||||
echo "ERROR: missing ${CURSOR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "$RULES" ]]; then
|
||||
ac="$(grep -R "alwaysApply: true" "$RULES" --include='*.mdc' 2>/dev/null | wc -l | tr -d ' ')"
|
||||
echo "alwaysApply: true occurrences in .cursor/rules: ${ac}"
|
||||
echo " (expect a small number — meta/safety; prefer scoped globs for domain rules)"
|
||||
else
|
||||
echo "WARN: no ${RULES}"
|
||||
fi
|
||||
|
||||
if [[ -d "$RULES/features" ]]; then
|
||||
shopt -s nullglob
|
||||
for f in "$RULES/features"/*.mdc; do
|
||||
base="$(basename "$f" .mdc)"
|
||||
if [[ ! -d "${ROOT}/lib/features/${base}" ]] && [[ ! -d "${ROOT}/lib/feature_${base}" ]]; then
|
||||
echo "WARN: rules/features/${base}.mdc has no obvious lib/features/${base} folder — update features.modules or lib layout"
|
||||
fi
|
||||
done
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
echo "OK — review warnings above after brief or folder renames"
|
||||
@@ -0,0 +1 @@
|
||||
End-to-end feature implementation (research, TDD, integration tests, verification). Follow the workflow and constraints in `@file:.cursor/skills/build/SKILL.md`. Use `project-brief.yaml` as the source of truth for stack and platforms.
|
||||
+1
@@ -0,0 +1 @@
|
||||
Structured bug triage and evidence-first debugging. Follow `@file:.cursor/skills/debug-issue/SKILL.md`. Gather reproduction steps, logs, and failing commands before proposing fixes.
|
||||
+1
@@ -0,0 +1 @@
|
||||
Explain-only walkthrough of code paths and stack behavior (no edits). Follow `@file:.cursor/skills/explain-code/SKILL.md`. Do not modify source files unless the user explicitly asks.
|
||||
+1
@@ -0,0 +1 @@
|
||||
Pre-PR verification checklist (analyze, tests, hooks) without full /build lifecycle. Follow `@file:.cursor/skills/verify-change/SKILL.md` for the change in scope.
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
---
|
||||
description: CI/CD, flavours, and quality gates for TestApp
|
||||
globs: [".github/**", "codemagic.yaml", "Makefile", "pubspec.yaml", "fastlane/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# CI/CD & flavours — TestApp
|
||||
|
||||
## Context
|
||||
Pipeline and flavour setup must stay aligned with how the app is built and released.
|
||||
|
||||
## Flavours
|
||||
- Documented in `project-brief.yaml`: **dev, prod**
|
||||
- Use `--flavor` / `-t lib/main_<flavour>.dart` (or your project’s entrypoints) consistently across local, CI, and store builds
|
||||
- Configuration via `--dart-define` / `--dart-define-from-file` — **never** hardcode secrets in source
|
||||
|
||||
## Quality gates (recommended stages)
|
||||
- **Lint:** `dart format --set-exit-if-changed .` and `flutter analyze`
|
||||
- **Unit + widget:** `flutter test` (with coverage if the team tracks it)
|
||||
- **Goldens:** fixed device/locale; CI fails on drift unless intentionally updated
|
||||
- **Smoke build:** e.g. `flutter build apk` or `flutter build ios --no-codesign` for the primary flavour
|
||||
- **E2E:** when `testing.depth` includes e2e — patrol on CI devices or Firebase Test Lab
|
||||
|
||||
## Cursor integration
|
||||
- After substantive edits: run analyze and relevant tests before PR
|
||||
- For release-oriented tasks, use the **deploy** skill at `.cursor/skills/deploy/SKILL.md` when present
|
||||
|
||||
## CI/CD tool
|
||||
- Selected in brief: **GitHub Actions** (`github_actions`)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: "Feature module auth — contracts, boundaries, and ownership (fill after design)"
|
||||
globs: ["lib/**/auth/**", "test/**/auth/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Feature — Auth
|
||||
|
||||
## Context
|
||||
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `auth` so agents do not invent cross-feature wiring.
|
||||
|
||||
## Constraints
|
||||
- List external dependencies (other features, packages, backend endpoints) explicitly
|
||||
- Document invariants (auth required, idempotency, offline behavior) when known
|
||||
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
|
||||
|
||||
## Patterns
|
||||
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
|
||||
|
||||
## Anti-patterns
|
||||
- Empty file left forever — either fill it or delete the module entry from the brief
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: "Feature module home — contracts, boundaries, and ownership (fill after design)"
|
||||
globs: ["lib/**/home/**", "test/**/home/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Feature — Home
|
||||
|
||||
## Context
|
||||
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `home` so agents do not invent cross-feature wiring.
|
||||
|
||||
## Constraints
|
||||
- List external dependencies (other features, packages, backend endpoints) explicitly
|
||||
- Document invariants (auth required, idempotency, offline behavior) when known
|
||||
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
|
||||
|
||||
## Patterns
|
||||
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
|
||||
|
||||
## Anti-patterns
|
||||
- Empty file left forever — either fill it or delete the module entry from the brief
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: "Feature module products — contracts, boundaries, and ownership (fill after design)"
|
||||
globs: ["lib/**/products/**", "test/**/products/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Feature — Products
|
||||
|
||||
## Context
|
||||
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `products` so agents do not invent cross-feature wiring.
|
||||
|
||||
## Constraints
|
||||
- List external dependencies (other features, packages, backend endpoints) explicitly
|
||||
- Document invariants (auth required, idempotency, offline behavior) when known
|
||||
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
|
||||
|
||||
## Patterns
|
||||
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
|
||||
|
||||
## Anti-patterns
|
||||
- Empty file left forever — either fill it or delete the module entry from the brief
|
||||
+6
-5
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "Core Flutter conventions for TestApp — always applied"
|
||||
alwaysApply: true
|
||||
description: "Core Flutter conventions for TestApp"
|
||||
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Flutter Core Standards — TestApp
|
||||
@@ -29,9 +30,9 @@ alwaysApply: true
|
||||
- Private members: `_camelCase`
|
||||
|
||||
## Imports
|
||||
- Order: dart: → package: → relative
|
||||
- Use relative imports within a feature; absolute for cross-feature
|
||||
- Never import a feature's internal files from outside that feature
|
||||
### Imports (strict — `conventions.strict_package_imports: true`)
|
||||
- Use `package:<your_pubspec_name>/...` imports everywhere in `lib/` and `test/` — **no** relative `../` across feature boundaries (the brief `project.package` id is often the app bundle id; prefer the **pubspec.yaml `name`** for Dart imports)
|
||||
- Barrel files (`index.dart`) at feature roots; do not wildcard re-export third-party packages
|
||||
|
||||
## Code quality
|
||||
- Max function length: 40 lines. Extract widgets and helpers aggressively
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "Project context for TestApp — always applied"
|
||||
alwaysApply: true
|
||||
description: "Stack summary and product context for TestApp"
|
||||
globs: ["project-brief.yaml", ".cursor/**/*.md", ".cursor/**/*.mdc", "pubspec.yaml"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Project Context — TestApp
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
---
|
||||
description: How Cursor rules in this repository must be written and maintained.
|
||||
globs: [".cursor/rules/**/*.mdc"]
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Rule authoring — TestApp
|
||||
|
||||
## Context
|
||||
Rules are version-controlled contracts for AI assistants. Poor rules waste context and silently steer every edit.
|
||||
|
||||
## Constraints
|
||||
- One focused concern per file; split broad topics instead of one mega-rule
|
||||
- Every rule MUST have a clear `description` in frontmatter (one sentence)
|
||||
- Prefer `alwaysApply: false` with **narrow** `globs` for domain rules — reserve `alwaysApply: true` for meta and safety
|
||||
- `globs` must be as specific as possible — never `["**/*"]` unless tooling requires it
|
||||
- Code samples in rules MUST be valid for this project (Dart/Flutter/YAML as appropriate)
|
||||
- Deprecated guidance is removed, not left commented out
|
||||
- Each substantive rule includes **Context** (why), **Constraints** (must/must not), and where helpful **Patterns** / **Anti-patterns**
|
||||
|
||||
## Anti-patterns
|
||||
- Domain rules (testing, l10n, a feature) with `alwaysApply: true` — burns context
|
||||
- Rules with no concrete examples when the topic is code-facing
|
||||
- Stale feature rules after modules are removed — run `tool/cursor_audit.sh` periodically
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "UI/UX standards for TestApp — always applied"
|
||||
alwaysApply: true
|
||||
description: "UI/UX standards for TestApp"
|
||||
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# UI / UX Standards — TestApp
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Cursor — LegacyApp
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Open this repo in **Cursor** so `.cursor/rules/` and `.cursor/skills/` load automatically.
|
||||
2. Read **`rules/universal/rule-authoring.mdc`** — how we maintain AI rules.
|
||||
3. Stack and product context live in **`project-brief.yaml`** at the repo root; regenerate `.cursor/` with `cursor_gen` after changing it.
|
||||
4. **Slash skills** (primary workflows): open the Command Palette and use the project commands, or reference:
|
||||
- `.cursor/skills/build/SKILL.md` — end-to-end feature implementation
|
||||
- `.cursor/skills/debug-issue/SKILL.md` — structured debugging
|
||||
- `.cursor/skills/verify-change/SKILL.md` — pre-PR verification
|
||||
- `.cursor/skills/explain-code/SKILL.md` — explain-only walkthroughs
|
||||
5. **Agents** (`.cursor/agents/*.mdc`) are reusable reviewer personas — attach when asking for code review or focused passes.
|
||||
6. **Custom overrides**: files under `.cursor/custom/` and `CURSOR:CUSTOM` blocks in generated files are preserved on `cursor_gen --refresh` (see generator docs).
|
||||
|
||||
## Optional
|
||||
|
||||
- **`integrations.mcp.enabled`** in `project-brief.yaml` — generates `.cursor/mcp.json` with env-based server entries (no secrets in git).
|
||||
- **`telemetry_opt_in: true`** — emits local telemetry helpers under `.cursor/telemetry/` (never commit usage logs if you enable logging).
|
||||
- Run **`bash tool/cursor_audit.sh`** from the project root periodically to catch stale feature rules and overly broad `alwaysApply` usage.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Build artefacts
|
||||
build/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
*.g.dart
|
||||
*.freezed.dart
|
||||
*.gr.dart
|
||||
*.config.dart
|
||||
|
||||
# Secrets
|
||||
.env
|
||||
.env.*
|
||||
firebase_options.dart
|
||||
google-services.json
|
||||
GoogleService-Info.plist
|
||||
|
||||
# Large binary assets
|
||||
assets/fonts/
|
||||
assets/videos/
|
||||
*.aab
|
||||
*.apk
|
||||
*.ipa
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
*.iml
|
||||
@@ -3,4 +3,5 @@
|
||||
Repo-level notes for AI assistants. Authoritative stack and conventions are in `project-brief.yaml` and `.cursor/` (regenerate with `cursor_gen` from the project root).
|
||||
|
||||
- **Package:** `com.test.legacy`
|
||||
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain`
|
||||
- **Onboarding:** `.cursor/ONBOARDING.md` — layout, slash commands → skills, MCP opt-in, audits
|
||||
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain` (see `.cursor/commands/*.md`)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# LegacyApp — generated by cursor_gen; adjust commands to your repo
|
||||
# Optional: run `bash tool/cursor_audit.sh` after changing features.modules or rule files.
|
||||
pre-commit:
|
||||
commands:
|
||||
flutter-analyze:
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
# LegacyApp — Cursor rule hygiene (generated by cursor_gen)
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
CURSOR="${ROOT}/.cursor"
|
||||
RULES="${CURSOR}/rules"
|
||||
|
||||
echo "== cursor_audit (${ROOT}) =="
|
||||
|
||||
if [[ ! -d "$CURSOR" ]]; then
|
||||
echo "ERROR: missing ${CURSOR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "$RULES" ]]; then
|
||||
ac="$(grep -R "alwaysApply: true" "$RULES" --include='*.mdc' 2>/dev/null | wc -l | tr -d ' ')"
|
||||
echo "alwaysApply: true occurrences in .cursor/rules: ${ac}"
|
||||
echo " (expect a small number — meta/safety; prefer scoped globs for domain rules)"
|
||||
else
|
||||
echo "WARN: no ${RULES}"
|
||||
fi
|
||||
|
||||
if [[ -d "$RULES/features" ]]; then
|
||||
shopt -s nullglob
|
||||
for f in "$RULES/features"/*.mdc; do
|
||||
base="$(basename "$f" .mdc)"
|
||||
if [[ ! -d "${ROOT}/lib/features/${base}" ]] && [[ ! -d "${ROOT}/lib/feature_${base}" ]]; then
|
||||
echo "WARN: rules/features/${base}.mdc has no obvious lib/features/${base} folder — update features.modules or lib layout"
|
||||
fi
|
||||
done
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
echo "OK — review warnings above after brief or folder renames"
|
||||
@@ -0,0 +1 @@
|
||||
End-to-end feature implementation (research, TDD, integration tests, verification). Follow the workflow and constraints in `@file:.cursor/skills/build/SKILL.md`. Use `project-brief.yaml` as the source of truth for stack and platforms.
|
||||
@@ -0,0 +1 @@
|
||||
Structured bug triage and evidence-first debugging. Follow `@file:.cursor/skills/debug-issue/SKILL.md`. Gather reproduction steps, logs, and failing commands before proposing fixes.
|
||||
@@ -0,0 +1 @@
|
||||
Explain-only walkthrough of code paths and stack behavior (no edits). Follow `@file:.cursor/skills/explain-code/SKILL.md`. Do not modify source files unless the user explicitly asks.
|
||||
@@ -0,0 +1 @@
|
||||
Pre-PR verification checklist (analyze, tests, hooks) without full /build lifecycle. Follow `@file:.cursor/skills/verify-change/SKILL.md` for the change in scope.
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"filesystem": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-filesystem",
|
||||
"."
|
||||
],
|
||||
"description": "Read/write project files under the workspace root"
|
||||
},
|
||||
"flutter-docs": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-fetch"
|
||||
],
|
||||
"env": {
|
||||
"BASE_URL": "https://api.flutter.dev/flutter"
|
||||
},
|
||||
"description": "Flutter API documentation lookup"
|
||||
},
|
||||
"dart-pub": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-fetch"
|
||||
],
|
||||
"env": {
|
||||
"BASE_URL": "https://pub.dev/api"
|
||||
},
|
||||
"description": "Pub.dev package metadata and versions"
|
||||
},
|
||||
"github": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-github"
|
||||
],
|
||||
"env": {
|
||||
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
|
||||
},
|
||||
"description": "GitHub issues and PR context (requires GITHUB_TOKEN)"
|
||||
},
|
||||
"openapi-ref": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-fetch"
|
||||
],
|
||||
"env": {
|
||||
"OPENAPI_SPEC_URL": "${OPENAPI_SPEC_URL}"
|
||||
},
|
||||
"description": "Optional fetch MCP — point OPENAPI_SPEC_URL at a hosted spec or file:// URL you expose locally"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
description: CI/CD, flavours, and quality gates for LegacyApp
|
||||
globs: [".github/**", "codemagic.yaml", "Makefile", "pubspec.yaml", "fastlane/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# CI/CD & flavours — LegacyApp
|
||||
|
||||
## Context
|
||||
Pipeline and flavour setup must stay aligned with how the app is built and released.
|
||||
|
||||
## Flavours
|
||||
- Documented in `project-brief.yaml`: **dev, prod**
|
||||
- Use `--flavor` / `-t lib/main_<flavour>.dart` (or your project’s entrypoints) consistently across local, CI, and store builds
|
||||
- Configuration via `--dart-define` / `--dart-define-from-file` — **never** hardcode secrets in source
|
||||
|
||||
## Quality gates (recommended stages)
|
||||
- **Lint:** `dart format --set-exit-if-changed .` and `flutter analyze`
|
||||
- **Unit + widget:** `flutter test` (with coverage if the team tracks it)
|
||||
- **Goldens:** fixed device/locale; CI fails on drift unless intentionally updated
|
||||
- **Smoke build:** e.g. `flutter build apk` or `flutter build ios --no-codesign` for the primary flavour
|
||||
- **E2E:** when `testing.depth` includes e2e — patrol on CI devices or Firebase Test Lab
|
||||
|
||||
## Cursor integration
|
||||
- After substantive edits: run analyze and relevant tests before PR
|
||||
- For release-oriented tasks, use the **deploy** skill at `.cursor/skills/deploy/SKILL.md` when present
|
||||
|
||||
## CI/CD tool
|
||||
- Selected in brief: **Codemagic** (`codemagic`)
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: "Feature module auth — contracts, boundaries, and ownership (fill after design)"
|
||||
globs: ["lib/**/auth/**", "test/**/auth/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Feature — Auth
|
||||
|
||||
## Context
|
||||
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `auth` so agents do not invent cross-feature wiring.
|
||||
|
||||
## Constraints
|
||||
- List external dependencies (other features, packages, backend endpoints) explicitly
|
||||
- Document invariants (auth required, idempotency, offline behavior) when known
|
||||
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
|
||||
|
||||
## Patterns
|
||||
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
|
||||
|
||||
## Anti-patterns
|
||||
- Empty file left forever — either fill it or delete the module entry from the brief
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: "Feature module dashboard — contracts, boundaries, and ownership (fill after design)"
|
||||
globs: ["lib/**/dashboard/**", "test/**/dashboard/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Feature — Dashboard
|
||||
|
||||
## Context
|
||||
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `dashboard` so agents do not invent cross-feature wiring.
|
||||
|
||||
## Constraints
|
||||
- List external dependencies (other features, packages, backend endpoints) explicitly
|
||||
- Document invariants (auth required, idempotency, offline behavior) when known
|
||||
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
|
||||
|
||||
## Patterns
|
||||
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
|
||||
|
||||
## Anti-patterns
|
||||
- Empty file left forever — either fill it or delete the module entry from the brief
|
||||
+7
-5
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "Core Flutter conventions for LegacyApp — always applied"
|
||||
alwaysApply: true
|
||||
description: "Core Flutter conventions for LegacyApp"
|
||||
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Flutter Core Standards — LegacyApp
|
||||
@@ -29,9 +30,10 @@ alwaysApply: true
|
||||
- Private members: `_camelCase`
|
||||
|
||||
## Imports
|
||||
- Order: dart: → package: → relative
|
||||
- Use relative imports within a feature; absolute for cross-feature
|
||||
- Never import a feature's internal files from outside that feature
|
||||
### Imports (default)
|
||||
- Order: `dart:` → `package:` → relative
|
||||
- Relative imports are allowed **within** the same feature directory; use `package:` imports for cross-feature code
|
||||
- Never import another feature's internals from outside that feature
|
||||
|
||||
## Code quality
|
||||
- Max function length: 40 lines. Extract widgets and helpers aggressively
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "Project context for LegacyApp — always applied"
|
||||
alwaysApply: true
|
||||
description: "Stack summary and product context for LegacyApp"
|
||||
globs: ["project-brief.yaml", ".cursor/**/*.md", ".cursor/**/*.mdc", "pubspec.yaml"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Project Context — LegacyApp
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
---
|
||||
description: How Cursor rules in this repository must be written and maintained.
|
||||
globs: [".cursor/rules/**/*.mdc"]
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Rule authoring — LegacyApp
|
||||
|
||||
## Context
|
||||
Rules are version-controlled contracts for AI assistants. Poor rules waste context and silently steer every edit.
|
||||
|
||||
## Constraints
|
||||
- One focused concern per file; split broad topics instead of one mega-rule
|
||||
- Every rule MUST have a clear `description` in frontmatter (one sentence)
|
||||
- Prefer `alwaysApply: false` with **narrow** `globs` for domain rules — reserve `alwaysApply: true` for meta and safety
|
||||
- `globs` must be as specific as possible — never `["**/*"]` unless tooling requires it
|
||||
- Code samples in rules MUST be valid for this project (Dart/Flutter/YAML as appropriate)
|
||||
- Deprecated guidance is removed, not left commented out
|
||||
- Each substantive rule includes **Context** (why), **Constraints** (must/must not), and where helpful **Patterns** / **Anti-patterns**
|
||||
|
||||
## Anti-patterns
|
||||
- Domain rules (testing, l10n, a feature) with `alwaysApply: true` — burns context
|
||||
- Rules with no concrete examples when the topic is code-facing
|
||||
- Stale feature rules after modules are removed — run `tool/cursor_audit.sh` periodically
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "UI/UX standards for LegacyApp — always applied"
|
||||
alwaysApply: true
|
||||
description: "UI/UX standards for LegacyApp"
|
||||
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# UI / UX Standards — LegacyApp
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Cursor — TaskFlow
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Open this repo in **Cursor** so `.cursor/rules/` and `.cursor/skills/` load automatically.
|
||||
2. Read **`rules/universal/rule-authoring.mdc`** — how we maintain AI rules.
|
||||
3. Stack and product context live in **`project-brief.yaml`** at the repo root; regenerate `.cursor/` with `cursor_gen` after changing it.
|
||||
4. **Slash skills** (primary workflows): open the Command Palette and use the project commands, or reference:
|
||||
- `.cursor/skills/build/SKILL.md` — end-to-end feature implementation
|
||||
- `.cursor/skills/debug-issue/SKILL.md` — structured debugging
|
||||
- `.cursor/skills/verify-change/SKILL.md` — pre-PR verification
|
||||
- `.cursor/skills/explain-code/SKILL.md` — explain-only walkthroughs
|
||||
5. **Agents** (`.cursor/agents/*.mdc`) are reusable reviewer personas — attach when asking for code review or focused passes.
|
||||
6. **Custom overrides**: files under `.cursor/custom/` and `CURSOR:CUSTOM` blocks in generated files are preserved on `cursor_gen --refresh` (see generator docs).
|
||||
|
||||
## Optional
|
||||
|
||||
- **`integrations.mcp.enabled`** in `project-brief.yaml` — generates `.cursor/mcp.json` with env-based server entries (no secrets in git).
|
||||
- **`telemetry_opt_in: true`** — emits local telemetry helpers under `.cursor/telemetry/` (never commit usage logs if you enable logging).
|
||||
- Run **`bash tool/cursor_audit.sh`** from the project root periodically to catch stale feature rules and overly broad `alwaysApply` usage.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# Build artefacts
|
||||
build/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
*.g.dart
|
||||
*.freezed.dart
|
||||
*.gr.dart
|
||||
*.config.dart
|
||||
|
||||
# Secrets
|
||||
.env
|
||||
.env.*
|
||||
firebase_options.dart
|
||||
google-services.json
|
||||
GoogleService-Info.plist
|
||||
|
||||
# Large binary assets
|
||||
assets/fonts/
|
||||
assets/videos/
|
||||
*.aab
|
||||
*.apk
|
||||
*.ipa
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
*.iml
|
||||
+2
-1
@@ -3,4 +3,5 @@
|
||||
Repo-level notes for AI assistants. Authoritative stack and conventions are in `project-brief.yaml` and `.cursor/` (regenerate with `cursor_gen` from the project root).
|
||||
|
||||
- **Package:** `com.test.taskflow`
|
||||
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain`
|
||||
- **Onboarding:** `.cursor/ONBOARDING.md` — layout, slash commands → skills, MCP opt-in, audits
|
||||
- **Slash skills** (see `.cursor/skills/`): `/build`, `/debug`, `/verify`, `/explain` (see `.cursor/commands/*.md`)
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
# TaskFlow — generated by cursor_gen; adjust commands to your repo
|
||||
# Optional: run `bash tool/cursor_audit.sh` after changing features.modules or rule files.
|
||||
pre-commit:
|
||||
commands:
|
||||
flutter-analyze:
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
# TaskFlow — Cursor rule hygiene (generated by cursor_gen)
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
CURSOR="${ROOT}/.cursor"
|
||||
RULES="${CURSOR}/rules"
|
||||
|
||||
echo "== cursor_audit (${ROOT}) =="
|
||||
|
||||
if [[ ! -d "$CURSOR" ]]; then
|
||||
echo "ERROR: missing ${CURSOR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "$RULES" ]]; then
|
||||
ac="$(grep -R "alwaysApply: true" "$RULES" --include='*.mdc' 2>/dev/null | wc -l | tr -d ' ')"
|
||||
echo "alwaysApply: true occurrences in .cursor/rules: ${ac}"
|
||||
echo " (expect a small number — meta/safety; prefer scoped globs for domain rules)"
|
||||
else
|
||||
echo "WARN: no ${RULES}"
|
||||
fi
|
||||
|
||||
if [[ -d "$RULES/features" ]]; then
|
||||
shopt -s nullglob
|
||||
for f in "$RULES/features"/*.mdc; do
|
||||
base="$(basename "$f" .mdc)"
|
||||
if [[ ! -d "${ROOT}/lib/features/${base}" ]] && [[ ! -d "${ROOT}/lib/feature_${base}" ]]; then
|
||||
echo "WARN: rules/features/${base}.mdc has no obvious lib/features/${base} folder — update features.modules or lib layout"
|
||||
fi
|
||||
done
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
echo "OK — review warnings above after brief or folder renames"
|
||||
@@ -0,0 +1 @@
|
||||
End-to-end feature implementation (research, TDD, integration tests, verification). Follow the workflow and constraints in `@file:.cursor/skills/build/SKILL.md`. Use `project-brief.yaml` as the source of truth for stack and platforms.
|
||||
+1
@@ -0,0 +1 @@
|
||||
Structured bug triage and evidence-first debugging. Follow `@file:.cursor/skills/debug-issue/SKILL.md`. Gather reproduction steps, logs, and failing commands before proposing fixes.
|
||||
+1
@@ -0,0 +1 @@
|
||||
Explain-only walkthrough of code paths and stack behavior (no edits). Follow `@file:.cursor/skills/explain-code/SKILL.md`. Do not modify source files unless the user explicitly asks.
|
||||
+1
@@ -0,0 +1 @@
|
||||
Pre-PR verification checklist (analyze, tests, hooks) without full /build lifecycle. Follow `@file:.cursor/skills/verify-change/SKILL.md` for the change in scope.
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
---
|
||||
description: CI/CD, flavours, and quality gates for TaskFlow
|
||||
globs: [".github/**", "codemagic.yaml", "Makefile", "pubspec.yaml", "fastlane/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# CI/CD & flavours — TaskFlow
|
||||
|
||||
## Context
|
||||
Pipeline and flavour setup must stay aligned with how the app is built and released.
|
||||
|
||||
## Flavours
|
||||
- Documented in `project-brief.yaml`: **dev, prod**
|
||||
- Use `--flavor` / `-t lib/main_<flavour>.dart` (or your project’s entrypoints) consistently across local, CI, and store builds
|
||||
- Configuration via `--dart-define` / `--dart-define-from-file` — **never** hardcode secrets in source
|
||||
|
||||
## Quality gates (recommended stages)
|
||||
- **Lint:** `dart format --set-exit-if-changed .` and `flutter analyze`
|
||||
- **Unit + widget:** `flutter test` (with coverage if the team tracks it)
|
||||
- **Goldens:** fixed device/locale; CI fails on drift unless intentionally updated
|
||||
- **Smoke build:** e.g. `flutter build apk` or `flutter build ios --no-codesign` for the primary flavour
|
||||
- **E2E:** when `testing.depth` includes e2e — patrol on CI devices or Firebase Test Lab
|
||||
|
||||
## Cursor integration
|
||||
- After substantive edits: run analyze and relevant tests before PR
|
||||
- For release-oriented tasks, use the **deploy** skill at `.cursor/skills/deploy/SKILL.md` when present
|
||||
|
||||
## CI/CD tool
|
||||
- Selected in brief: **GitHub Actions** (`github_actions`)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: "Feature module auth — contracts, boundaries, and ownership (fill after design)"
|
||||
globs: ["lib/**/auth/**", "test/**/auth/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Feature — Auth
|
||||
|
||||
## Context
|
||||
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `auth` so agents do not invent cross-feature wiring.
|
||||
|
||||
## Constraints
|
||||
- List external dependencies (other features, packages, backend endpoints) explicitly
|
||||
- Document invariants (auth required, idempotency, offline behavior) when known
|
||||
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
|
||||
|
||||
## Patterns
|
||||
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
|
||||
|
||||
## Anti-patterns
|
||||
- Empty file left forever — either fill it or delete the module entry from the brief
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: "Feature module profile — contracts, boundaries, and ownership (fill after design)"
|
||||
globs: ["lib/**/profile/**", "test/**/profile/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Feature — Profile
|
||||
|
||||
## Context
|
||||
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `profile` so agents do not invent cross-feature wiring.
|
||||
|
||||
## Constraints
|
||||
- List external dependencies (other features, packages, backend endpoints) explicitly
|
||||
- Document invariants (auth required, idempotency, offline behavior) when known
|
||||
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
|
||||
|
||||
## Patterns
|
||||
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
|
||||
|
||||
## Anti-patterns
|
||||
- Empty file left forever — either fill it or delete the module entry from the brief
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: "Feature module tasks — contracts, boundaries, and ownership (fill after design)"
|
||||
globs: ["lib/**/tasks/**", "test/**/tasks/**"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Feature — Tasks
|
||||
|
||||
## Context
|
||||
This stub was generated from `features.modules` in `project-brief.yaml`. Use it to capture **public contracts** (routes, DTOs, events) and **dependencies** for `tasks` so agents do not invent cross-feature wiring.
|
||||
|
||||
## Constraints
|
||||
- List external dependencies (other features, packages, backend endpoints) explicitly
|
||||
- Document invariants (auth required, idempotency, offline behavior) when known
|
||||
- Update or delete this file when the module is removed or renamed — run `bash tool/cursor_audit.sh` to catch drift
|
||||
|
||||
## Patterns
|
||||
- Link to key entry points: primary screen(s), state holder(s), repository interface(s)
|
||||
|
||||
## Anti-patterns
|
||||
- Empty file left forever — either fill it or delete the module entry from the brief
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "Localization / i18n conventions for TaskFlow"
|
||||
alwaysApply: true
|
||||
globs: ["lib/l10n/**", "lib/**/*.dart", "test/**/*.dart"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Localization Standards — TaskFlow
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
---
|
||||
description: Semantic colours and theme extensions for TaskFlow
|
||||
globs: ["lib/**/*.dart", "test/**/*.dart"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Theming — TaskFlow
|
||||
|
||||
## Context
|
||||
Theme variants from brief: **light, dark, high contrast**.
|
||||
- **High contrast:** validate contrast, borders, and focus in the high-contrast theme alongside light/dark (WCAG).
|
||||
|
||||
|
||||
## Constraints
|
||||
- Prefer **`ThemeExtension`** (or design-system equivalents) for app-specific colours and radii — avoid raw `Color(0xFF...)` in feature code except in central token definitions
|
||||
- Use **`Theme.of(context).colorScheme`** / `TextTheme` for Material-aligned roles where appropriate
|
||||
- **High contrast:** when supported, verify WCAG contrast for text and controls; never rely on colour alone for state (pair with icon or label)
|
||||
- **High contrast theme:** validate loading, empty, and error states; never rely on color alone for meaning (use icons/text/semantics).
|
||||
- Touch targets: respect platform minimums (e.g. ~48 logical pixels) for interactive widgets
|
||||
|
||||
## Anti-patterns
|
||||
- Hard-coded `Colors.*` scattered across feature widgets instead of theme tokens
|
||||
- Ignoring `MediaQuery.of(context).platformBrightness` / high-contrast modes when the product claims support
|
||||
+7
-5
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "Core Flutter conventions for TaskFlow — always applied"
|
||||
alwaysApply: true
|
||||
description: "Core Flutter conventions for TaskFlow"
|
||||
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Flutter Core Standards — TaskFlow
|
||||
@@ -29,9 +30,10 @@ alwaysApply: true
|
||||
- Private members: `_camelCase`
|
||||
|
||||
## Imports
|
||||
- Order: dart: → package: → relative
|
||||
- Use relative imports within a feature; absolute for cross-feature
|
||||
- Never import a feature's internal files from outside that feature
|
||||
### Imports (default)
|
||||
- Order: `dart:` → `package:` → relative
|
||||
- Relative imports are allowed **within** the same feature directory; use `package:` imports for cross-feature code
|
||||
- Never import another feature's internals from outside that feature
|
||||
|
||||
## Code quality
|
||||
- Max function length: 40 lines. Extract widgets and helpers aggressively
|
||||
|
||||
+6
-3
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "Project context for TaskFlow — always applied"
|
||||
alwaysApply: true
|
||||
description: "Stack summary and product context for TaskFlow"
|
||||
globs: ["project-brief.yaml", ".cursor/**/*.md", ".cursor/**/*.mdc", "pubspec.yaml"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Project Context — TaskFlow
|
||||
@@ -42,10 +43,12 @@ _No Git repository URLs listed._ Add entries under `references.repos` in project
|
||||
_No local paths listed._ Add monorepo packages or sibling folders under `references.local_paths` in project-brief.yaml when relevant.
|
||||
|
||||
## Product UX / themes & roles
|
||||
- **Theme variants:** light, dark
|
||||
- **Theme variants:** light, dark, high contrast
|
||||
- **Roles:** Not enabled (`app_context.roles_enabled: false`).
|
||||
|
||||
|
||||
- **High contrast:** validate contrast, borders, and focus in the high-contrast theme alongside light/dark (WCAG).
|
||||
|
||||
## Reviews — which rule owns what
|
||||
- **Theme, colors, typography, spacing/radius tokens** → `ui-ux-standards.mdc` (widgets read `Theme.of(context)` only)
|
||||
- **User-visible copy & locales** → `localization.mdc` (ARB / `AppLocalizations`; no UI string literals)
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
---
|
||||
description: How Cursor rules in this repository must be written and maintained.
|
||||
globs: [".cursor/rules/**/*.mdc"]
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Rule authoring — TaskFlow
|
||||
|
||||
## Context
|
||||
Rules are version-controlled contracts for AI assistants. Poor rules waste context and silently steer every edit.
|
||||
|
||||
## Constraints
|
||||
- One focused concern per file; split broad topics instead of one mega-rule
|
||||
- Every rule MUST have a clear `description` in frontmatter (one sentence)
|
||||
- Prefer `alwaysApply: false` with **narrow** `globs` for domain rules — reserve `alwaysApply: true` for meta and safety
|
||||
- `globs` must be as specific as possible — never `["**/*"]` unless tooling requires it
|
||||
- Code samples in rules MUST be valid for this project (Dart/Flutter/YAML as appropriate)
|
||||
- Deprecated guidance is removed, not left commented out
|
||||
- Each substantive rule includes **Context** (why), **Constraints** (must/must not), and where helpful **Patterns** / **Anti-patterns**
|
||||
|
||||
## Anti-patterns
|
||||
- Domain rules (testing, l10n, a feature) with `alwaysApply: true` — burns context
|
||||
- Rules with no concrete examples when the topic is code-facing
|
||||
- Stale feature rules after modules are removed — run `tool/cursor_audit.sh` periodically
|
||||
+4
-2
@@ -1,6 +1,7 @@
|
||||
---
|
||||
description: "UI/UX standards for TaskFlow — always applied"
|
||||
alwaysApply: true
|
||||
description: "UI/UX standards for TaskFlow"
|
||||
globs: ["lib/**/*.dart", "test/**/*.dart", "integration_test/**/*.dart"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# UI / UX Standards — TaskFlow
|
||||
@@ -46,3 +47,4 @@ alwaysApply: true
|
||||
- Minimum contrast ratio: 4.5:1 (WCAG AA)
|
||||
- Test with TalkBack / VoiceOver before each release
|
||||
|
||||
- **High contrast theme:** validate loading, empty, and error states; never rely on color alone for meaning (use icons/text/semantics).
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// Shared ProjectBrief fixtures for golden tests and tool/refresh_goldens.dart
|
||||
|
||||
import '../src/models.dart';
|
||||
|
||||
final kBlocCleanFirebaseBrief = ProjectBrief(
|
||||
projectName: 'TestApp',
|
||||
packageId: 'com.test.testapp',
|
||||
description: 'Test app for golden tests',
|
||||
scale: 'medium',
|
||||
stateManagement: 'bloc',
|
||||
routing: 'gorouter',
|
||||
architecture: 'clean',
|
||||
backends: ['firebase'],
|
||||
auth: 'firebase_auth',
|
||||
platforms: ['ios', 'android'],
|
||||
codegenTools: ['freezed'],
|
||||
flavors: ['dev', 'prod'],
|
||||
cicd: 'github_actions',
|
||||
testingDepth: 'unit_widget',
|
||||
e2eTool: 'patrol',
|
||||
designSource: 'none',
|
||||
figmaUrl: '',
|
||||
apiDocsFormat: 'none',
|
||||
apiDocsPath: '',
|
||||
referenceRepos: [],
|
||||
localPaths: [],
|
||||
featureModules: ['auth', 'home', 'products'],
|
||||
specialFeatures: [],
|
||||
i18nEnabled: false,
|
||||
locales: ['en'],
|
||||
strictPackageImports: true,
|
||||
);
|
||||
|
||||
final kRiverpodFfSupabaseBrief = ProjectBrief(
|
||||
projectName: 'TaskFlow',
|
||||
packageId: 'com.test.taskflow',
|
||||
description: 'Task management app',
|
||||
scale: 'small',
|
||||
stateManagement: 'riverpod',
|
||||
routing: 'gorouter',
|
||||
architecture: 'feature_first',
|
||||
backends: ['supabase'],
|
||||
auth: 'supabase_auth',
|
||||
platforms: ['ios', 'android', 'web'],
|
||||
codegenTools: ['freezed', 'json_serializable'],
|
||||
flavors: ['dev', 'prod'],
|
||||
cicd: 'github_actions',
|
||||
testingDepth: 'unit_widget',
|
||||
e2eTool: 'patrol',
|
||||
designSource: 'none',
|
||||
figmaUrl: '',
|
||||
apiDocsFormat: 'none',
|
||||
apiDocsPath: '',
|
||||
referenceRepos: [],
|
||||
localPaths: [],
|
||||
featureModules: ['auth', 'tasks', 'profile'],
|
||||
specialFeatures: [],
|
||||
i18nEnabled: true,
|
||||
locales: ['en', 'fr'],
|
||||
themeVariants: const ['light', 'dark', 'high_contrast'],
|
||||
);
|
||||
|
||||
final kGetxMvcRestBrief = ProjectBrief(
|
||||
projectName: 'LegacyApp',
|
||||
packageId: 'com.test.legacy',
|
||||
description: 'Legacy GetX app',
|
||||
scale: 'medium',
|
||||
stateManagement: 'getx',
|
||||
routing: 'getx_nav',
|
||||
architecture: 'mvc',
|
||||
backends: ['rest'],
|
||||
auth: 'jwt_rest',
|
||||
platforms: ['ios', 'android'],
|
||||
codegenTools: [],
|
||||
flavors: ['dev', 'prod'],
|
||||
cicd: 'codemagic',
|
||||
testingDepth: 'unit_widget',
|
||||
e2eTool: 'patrol',
|
||||
designSource: 'none',
|
||||
figmaUrl: '',
|
||||
apiDocsFormat: 'openapi',
|
||||
apiDocsPath: 'docs/api.yaml',
|
||||
referenceRepos: [],
|
||||
localPaths: [],
|
||||
featureModules: ['auth', 'dashboard'],
|
||||
specialFeatures: [],
|
||||
i18nEnabled: false,
|
||||
locales: ['en'],
|
||||
mcpConfigEnabled: true,
|
||||
mcpPreset: 'auto',
|
||||
);
|
||||
Reference in New Issue
Block a user