diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..a6c6e4f --- /dev/null +++ b/.cursorrules @@ -0,0 +1,16 @@ +# EagleEye — Cursor Rules + +> Read `AGENTS.md` at the start of every session for full project context. + +EagleEye is a Dart CLI tool for detecting architecture violations in Dart projects. + +## Critical Rules + +- Dart CLI only — no platform dependencies in `lib/` +- No cyclic dependencies between `lib/` subdirectories +- `lib/model/` depends on nothing +- Tests use `package:test` framework +- Commit messages: English, semantic +- Never expose internal implementation from `lib/` as public API + +For complete rules and skills, read `ai/`. diff --git a/.gemini/context.md b/.gemini/context.md new file mode 100644 index 0000000..8282910 --- /dev/null +++ b/.gemini/context.md @@ -0,0 +1,18 @@ +# EagleEye — Gemini + +> Read `AGENTS.md` at the start of every session for full project context. + +EagleEye is a Dart CLI tool for detecting architecture violations in Dart projects. + +## Critical Rules + +- Dart CLI only — no platform dependencies in `lib/` +- No cyclic dependencies between `lib/` subdirectories +- `lib/model/` depends on nothing; `lib/data/` depends on `model/`; `lib/analyzer/` depends on `model/`, `data/`, and `util/` +- `lib/util/` has zero internal dependencies +- `bin/main.dart` only accesses the public API entry point +- Tests use `package:test` framework, naming: `_test.dart` +- Commit messages: English, semantic (`feat:`, `fix:`, `test:`, `chore:`, `docs:`) +- Never expose internal implementation from `lib/` as public API + +For complete rules and skills, read `ai/`. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..962c6a9 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,18 @@ +# EagleEye — GitHub Copilot + +> Read `AGENTS.md` at the start of every session for full project context. + +EagleEye is a Dart CLI tool for detecting architecture violations in Dart projects. + +## Critical Rules + +- Dart CLI only — no platform dependencies in `lib/` +- No cyclic dependencies between `lib/` subdirectories +- `lib/model/` depends on nothing; `lib/data/` depends on `model/`; `lib/analyzer/` depends on `model/` and `data/` +- `lib/util/` has zero internal dependencies +- `bin/main.dart` only accesses the public API entry point +- Tests use `package:test` framework, naming: `_test.dart` +- Commit messages: English, semantic (`feat:`, `fix:`, `test:`, `chore:`, `docs:`) +- Never expose internal implementation from `lib/` as public API + +For complete rules and skills, read `ai/`. diff --git a/AGENTS.md b/AGENTS.md index d84085f..42076a7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -74,3 +74,12 @@ example/ 6. Publish to pub.dev (`dart pub publish`) - **Git tag strategy:** `vX.Y.Z` (e.g., `v2.0.2`) - **Versioning strategy:** Semantic Versioning (SemVer) + +## Available Skills + +Before starting any task: +1. List all directories in `ai/skills/` +2. Identify which one covers the current task +3. Read that file in full before proceeding + +Each skill file is a self-contained guide. Never skip this step — the skill may contain patterns, checklists, or constraints that are not obvious from the code alone. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ed1d77a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +# EagleEye — Claude Code + +> Read `AGENTS.md` at the start of every session for full project context. + +EagleEye is a Dart CLI tool for detecting architecture violations in Dart projects. diff --git a/README-AI-CONTEXT.md b/README-AI-CONTEXT.md new file mode 100644 index 0000000..bbdf918 --- /dev/null +++ b/README-AI-CONTEXT.md @@ -0,0 +1,69 @@ +# AI Context Structure + +EagleEye uses multiple AI coding tools (OpenCode, Claude Code, GitHub Copilot, Gemini, Cursor, etc.). Instead of maintaining separate context files for each tool — which would quickly diverge — all tools point to the same source. + +``` +📄 AGENTS.md ← single source of truth (master initializer) +📁 ai/ ← detailed context: instructions, skills, module graph +``` + +```mermaid +graph LR + OPENCODE["OpenCode
opencode.json → AGENTS.md"] + CLAUDE["Claude Code
CLAUDE.md"] + COPILOT["GitHub Copilot
.github/copilot-instructions.md"] + CURSOR["Cursor
.cursorrules"] + GEMINI["Gemini
.gemini/context.md"] + CODEX["Codex / OpenAI
(reads natively)"] + + AG["📄 AGENTS.md
Master Initializer"] + AI["📁 ai/
Detailed Context"] + + OPENCODE -->|reads| AG + CLAUDE -->|reads| AG + COPILOT -->|reads| AG + CURSOR -->|reads| AG + GEMINI -->|reads| AG + CODEX -->|reads| AG + + AG -->|references| AI +``` + +## ai/ structure + +``` +ai/ + module-graph.md ← module dependency graph + instructions/ + dart.md ← Dart CLI patterns and conventions + skills/ + architecture/ + SKILL.md ← architectural rules and code conventions + documentation-review/ + SKILL.md ← docs validation + generate-tests/ + SKILL.md ← test generation + minimum-requirements/ + SKILL.md ← version requirements + release-notes/ + SKILL.md ← release process + review-pr/ + SKILL.md ← PR review checklist + run-build/ + SKILL.md ← how to build and test + testing/ + SKILL.md ← testing strategies + validate-architecture/ + SKILL.md ← architectural validation +``` + +## Tool-specific config + +| Location | Tool | Purpose | +|---|---|---| +| `AGENTS.md` | All tools | Master initializer — single source of truth | +| `CLAUDE.md` | Claude Code | Entry point → reads `AGENTS.md` | +| `.gemini/context.md` | Gemini | Entry point → reads `AGENTS.md` | +| `.github/copilot-instructions.md` | GitHub Copilot | Entry point → reads `AGENTS.md` | +| `.cursorrules` | Cursor | Entry point → reads `AGENTS.md` | +| `opencode.json` → `AGENTS.md` | OpenCode | Reads `AGENTS.md` and `ai/skills/` | diff --git a/ai/instructions/dart.md b/ai/instructions/dart.md new file mode 100644 index 0000000..9c92400 --- /dev/null +++ b/ai/instructions/dart.md @@ -0,0 +1,100 @@ +# Dart CLI — Platform Instructions + +> Read this file when starting any EagleEye task. + +--- + +## Core Abstractions + +| Class/File | Role | +|---|---| +| `lib/analyzer/analyzer.dart` | Main analysis engine — walks files, resolves imports | +| `lib/analyzer/checker/` | Individual rule checkers | +| `lib/model/` | Domain models and exceptions | +| `lib/data/` | Config loading and data access | +| `lib/util/` | Shared utilities | +| `bin/main.dart` | CLI entry point | + +## Architecture Overview + +EagleEye works in three phases: + +1. **Config loading** — reads `eagle_eye_config.json` from the project root +2. **File scanning** — walks Dart files in the target project, resolves imports +3. **Rule checking** — applies each rule from the config against the import graph + +### Rule Engine + +Rules are defined in JSON config: +```json +[ + { + "filePattern": "*util.dart", + "dependenciesAllowed": false + }, + { + "filePattern": "*viewmodel.dart", + "exclusiveDependencies": ["*repository.dart"] + }, + { + "filePattern": "*repository.dart", + "forbiddenDependencies": ["*screen.dart"] + } +] +``` + +Each checker in `lib/analyzer/checker/` implements one rule type. + +## Folder Structure + +``` +lib/ + analyzer/ + analyzer.dart — main analysis engine + checker/ + checker.dart — base checker interface + no_depends_checker.dart + exclusive_depends_checker.dart + forbidden_depends_checker.dart + do_not_with_patterns_checker.dart + data/ + config_loader.dart — JSON config loading + model/ — internal data models + model/ + analysis_result.dart + violation.dart + rule_config.dart + exceptions/ + util/ + file_utils.dart + import_resolver.dart +test/ + analyzer/ + analyzer_test.dart + checker/ + model/ +``` + +## Dart Conventions + +- **Naming:** `snake_case` for files, `lowerCamelCase` for variables/functions, `UpperCamelCase` for classes +- **Imports:** Prefer `package:` imports over relative. `avoid_relative_lib_imports` is enforced +- **Testing:** `package:test` framework with descriptive test names +- **CLI:** `args` package for argument parsing, `stdout` for output, exit codes for success/failure + +## Build + +```bash +dart pub get # install dependencies +dart analyze # static analysis +dart test # run tests +dart run eagle_eye:main # run CLI locally +``` + +## Tests + +- Framework: `package:test` (defined in `pubspec.yaml`) +- File naming: `_test.dart` mirroring `.dart` in `lib/` +- Test names: descriptive strings, lowercase with spaces +- Structure: `group()` for logical grouping, `test()` for individual cases +- Assertions: `expect(actual, matcher)` diff --git a/ai/module-graph.md b/ai/module-graph.md new file mode 100644 index 0000000..99cc195 --- /dev/null +++ b/ai/module-graph.md @@ -0,0 +1,68 @@ +# EagleEye — Module Dependency Graph + +## Module Structure + +``` +lib/ + model/ ← data classes, enums, exceptions (zero internal deps) + data/ ← data access, serialization (depends on model/) + analyzer/ ← analysis engine, rule checkers (depends on model/, data/) + checker/ ← individual rule implementations (depends on model/) + util/ ← shared utilities (zero internal deps) +bin/ + main.dart ← CLI entry point (depends only on public API in lib/) +``` + +## Dependency Rules + +``` + ┌─────────────────────┐ + │ lib/util/ │ ← no internal dependencies + └─────────────────────┘ + + ┌─────────────────────┐ + │ lib/model/ │ ← no internal dependencies + └──────────┬──────────┘ + │ depends on + ▼ + ┌─────────────────────┐ + │ lib/data/ │ ← depends on model/ + └──────────┬──────────┘ + │ depends on + ▼ + ┌─────────────────────┐ + │ lib/analyzer/ │ ← depends on model/, data/, util/ + └──────────┬──────────┘ + │ depends on + ▼ + ┌─────────────────────┐ + │ lib/analyzer/ │ + │ checker/ │ ← depends on model/, analyzer/ + └─────────────────────┘ + + ✗ data/ → analyzer/ FORBIDDEN + ✗ data/ → util/ FORBIDDEN + ✗ model/ → data/ FORBIDDEN + ✗ model/ → analyzer/ FORBIDDEN + ✗ model/ → util/ FORBIDDEN + ✗ bin/ → lib/* (internal) FORBIDDEN (only public API entry point) +``` + +## Layer Responsibilities + +| Layer | Role | +|---|---| +| `model/` | Data classes, enums, custom exceptions. Zero knowledge of other layers. | +| `data/` | Config loading, JSON parsing, file I/O. Depends on `model/` for types. | +| `analyzer/` | Core logic: walks files, resolves imports, checks rules. Orchestrates the analysis. | +| `analyzer/checker/` | Individual rule implementations. Each checker validates one rule type. | +| `util/` | Shared helpers (string, file, path utilities). No knowledge of project domain. | +| `bin/main.dart` | CLI entry point. Only calls the public API — never internal modules directly. | + +## Adding a New Feature + +1. If a new domain type is needed → add to `model/` +2. If data loading/parsing is needed → add to `data/` +3. If a new rule type is needed → add to `analyzer/checker/` +4. If a shared utility is needed → add to `util/` +5. Wire it up in `analyzer/` or `bin/main.dart` diff --git a/ai/skills/architecture/SKILL.md b/ai/skills/architecture/SKILL.md new file mode 100644 index 0000000..2b6e08d --- /dev/null +++ b/ai/skills/architecture/SKILL.md @@ -0,0 +1,38 @@ +--- +name: architecture +description: Verify architectural consistency and dependency rules in EagleEye +trigger: when the user asks about architecture, rules, conventions, or what is/isn't allowed in the codebase +--- + +# EagleEye — Architectural Rules & Conventions + +## Architectural Rules — Never Violate + +1. **Layer separation is strict.** `lib/model/` depends on nothing. `lib/data/` may depend on `model/`. `lib/analyzer/` may depend on `model/`, `data/`, and `util/`. `lib/util/` depends on nothing. + +2. **No cyclic dependencies** between `lib/` subdirectories. + +3. **`bin/main.dart` only accesses the public API.** Never import internal modules directly from the CLI entry point. + +4. **Public API should be minimal and intentional.** Internal implementation details should not be exposed. + +5. **Files outside `lib/`** (e.g., `bin/`, `test/`) should not be imported by `lib/`. + +6. **`lib/util/` should be independent** of other layers — no imports from `model/`, `data/`, or `analyzer/`. + +7. **Test files mirror the `lib/` structure.** `test/analyzer/` mirrors `lib/analyzer/`, `test/model/` mirrors `lib/model/`. + +## Code Conventions + +- **Dart:** follows official Dart conventions. `snake_case` for files, `lowerCamelCase` for variables/functions, `UpperCamelCase` for classes. +- **Imports:** prefer `package:` imports over relative. `avoid_relative_lib_imports` is enforced. +- **Tests:** `package:test` framework. Descriptive test names, `group()` for logical grouping. +- **Commits:** messages in English, semantic (`feat:`, `fix:`, `test:`, `chore:`, `docs:`). + +## What NOT to Do + +- Do not add platform dependencies in `lib/` (Dart CLI only) +- Do not create cyclic dependencies between `lib/` subpackages +- Do not commit `local.properties` or credential files +- Do not use `--no-verify` to bypass CI hooks +- Do not expose internal implementation as public API diff --git a/.opencode/skills/documentation-review/SKILL.md b/ai/skills/documentation-review/SKILL.md similarity index 89% rename from .opencode/skills/documentation-review/SKILL.md rename to ai/skills/documentation-review/SKILL.md index 3f9d71e..ca658aa 100644 --- a/.opencode/skills/documentation-review/SKILL.md +++ b/ai/skills/documentation-review/SKILL.md @@ -1,8 +1,11 @@ --- name: documentation-review -description: Validate project documentation matches actual implementation +description: Validate EagleEye documentation matches actual implementation +trigger: when the user asks to review documentation, check for outdated docs, or verify docs match code --- +# Documentation Review for EagleEye + When invoked: 1. Scan all documentation: diff --git a/.opencode/skills/generate-tests/SKILL.md b/ai/skills/generate-tests/SKILL.md similarity index 92% rename from .opencode/skills/generate-tests/SKILL.md rename to ai/skills/generate-tests/SKILL.md index 9158e8f..7f9db1b 100644 --- a/.opencode/skills/generate-tests/SKILL.md +++ b/ai/skills/generate-tests/SKILL.md @@ -1,8 +1,11 @@ --- name: generate-tests description: Generate tests following project conventions +trigger: when the user asks to write tests, review test files, or generate new test cases --- +# Generate Tests + When invoked: 1. Detect testing framework: diff --git a/.opencode/skills/minimum-requirements/SKILL.md b/ai/skills/minimum-requirements/SKILL.md similarity index 80% rename from .opencode/skills/minimum-requirements/SKILL.md rename to ai/skills/minimum-requirements/SKILL.md index 3a55b43..3769b47 100644 --- a/.opencode/skills/minimum-requirements/SKILL.md +++ b/ai/skills/minimum-requirements/SKILL.md @@ -1,8 +1,11 @@ --- name: minimum-requirements -description: Determine minimum requirements to consume the library +description: Determine minimum requirements to consume the EagleEye library +trigger: when the user asks about minimum SDK version, requirements, or compatible Dart versions --- +# Minimum Requirements for EagleEye + When invoked: 1. Detect project type: diff --git a/.opencode/skills/release-notes/SKILL.md b/ai/skills/release-notes/SKILL.md similarity index 91% rename from .opencode/skills/release-notes/SKILL.md rename to ai/skills/release-notes/SKILL.md index 9744af8..e97e637 100644 --- a/.opencode/skills/release-notes/SKILL.md +++ b/ai/skills/release-notes/SKILL.md @@ -1,8 +1,11 @@ --- name: release-notes -description: Generate release notes and prepare the next release +description: Generate release notes and prepare the next release for EagleEye +trigger: when the user asks to prepare a release, bump version, or generate release notes --- +# EagleEye Release Process + When invoked: 1. Detect current version from `pubspec.yaml`: diff --git a/ai/skills/review-pr/SKILL.md b/ai/skills/review-pr/SKILL.md new file mode 100644 index 0000000..de7a6e6 --- /dev/null +++ b/ai/skills/review-pr/SKILL.md @@ -0,0 +1,34 @@ +--- +name: review-pr +description: Review an EagleEye pull request checking architecture, tests, docs, and completeness +trigger: when the user asks to review a PR, check a pull request, or validate changes +--- + +# EagleEye PR Review Checklist + +## 1. Architectural Rules + +- [ ] No cyclic dependencies between `lib/` subdirectories +- [ ] Layer separation respected: `model/` → `data/` → `analyzer/` → `checker/` +- [ ] `lib/util/` has no internal dependencies +- [ ] `bin/main.dart` only accesses the public API + +## 2. Tests + +- [ ] Unit tests present for new code +- [ ] Test file naming: `_test.dart` matching `.dart` +- [ ] Tests use `package:test` framework +- [ ] Edge cases and error paths covered + +## 3. Documentation + +- [ ] `doc/` updated if public behavior changed +- [ ] `README.md` updated if needed +- [ ] `CHANGELOG.md` updated if needed + +## 4. Code Standards + +- [ ] Follows Dart conventions +- [ ] No private API leaks (internal implementation not exposed) +- [ ] Imports use `package:` style (no relative `lib/` imports) +- [ ] Commit messages are semantic (`feat:`, `fix:`, `test:`, `chore:`, `docs:`) diff --git a/ai/skills/run-build/SKILL.md b/ai/skills/run-build/SKILL.md new file mode 100644 index 0000000..3891323 --- /dev/null +++ b/ai/skills/run-build/SKILL.md @@ -0,0 +1,50 @@ +--- +name: run-build +description: Run the EagleEye build and tests +trigger: when the user asks to build, compile, run tests, or validate the project +--- + +# Running the EagleEye Build + +## Commands + +Always run from the project root: + +```bash +# Install dependencies +dart pub get + +# Static analysis +dart analyze + +# Run tests +dart test + +# Run the CLI locally +dart run eagle_eye:main + +# Publish to pub.dev +dart pub publish +``` + +## When to Run + +Per AGENTS.md rules: **run `dart analyze` and `dart test` after every task before marking it complete**. Never mark a task complete without a passing build. + +## Common Errors + +| Error | Likely Cause | Fix | +|---|---|---| +| `Undefined name` | Missing import | Add the correct `package:` import | +| `The method doesn't override an inherited method` | Wrong method signature | Check the base class/interface | +| `Target of URI doesn't exist` | Wrong file path in import | Fix the import path | +| `A value of type X can't be assigned to Y` | Type mismatch | Check the expected type | +| Test failures | Logic error or outdated expectation | Debug and fix the implementation | + +## CI Pipeline + +The project has three CI workflows (see `.github/workflows/`): + +- **`pr.yml`** — runs `dart test` and `dart analyze` on every PR to `main` +- **`documentation.yml`** — deploys MkDocs site +- **`publish.yml`** — publishes to pub.dev diff --git a/ai/skills/testing/SKILL.md b/ai/skills/testing/SKILL.md new file mode 100644 index 0000000..f992103 --- /dev/null +++ b/ai/skills/testing/SKILL.md @@ -0,0 +1,41 @@ +--- +name: testing +description: Generate tests for EagleEye following project conventions +trigger: when the user asks to write tests, review test files, or generate new test cases +--- + +# Testing in EagleEye + +When invoked: + +1. Detect testing framework: + - Read `pubspec.yaml` `dev_dependencies:` for `test` (Dart `package:test`). + - This project uses `package:test` (`^1.31.1`). + +2. Analyze existing tests in `test/`: + - Read existing test files to determine naming conventions. + - Note the use of `test()`, `group()`, `expect()` patterns. + - Observe file naming (`*_test.dart` suffix). + - Observe directory structure mirroring `lib/`. + +3. Follow current naming conventions: + - File names: `_test.dart` matching `.dart` in `lib/`. + - Test names: descriptive strings, typically lowercase with spaces. + - Use `group()` for logical grouping. + - Use `test()` for individual test cases. + - Use `expect(actual, matcher)` for assertions. + +4. Generate unit tests for: + - Public API classes and functions in `lib/`. + - Edge cases (null inputs, empty collections, invalid patterns). + - Error paths (exceptions, validation failures). + +5. Generate integration tests when applicable: + - End-to-end CLI execution tests. + - Config file loading and parsing. + +6. Ensure generated tests use the project's assertion style and test architecture: + - Match existing `package:test` conventions. + - Use the same matchers and patterns found in existing tests. + +7. After writing tests, run `dart test` to verify they pass. diff --git a/.opencode/skills/validate-architecture/SKILL.md b/ai/skills/validate-architecture/SKILL.md similarity index 93% rename from .opencode/skills/validate-architecture/SKILL.md rename to ai/skills/validate-architecture/SKILL.md index d888603..c099c94 100644 --- a/.opencode/skills/validate-architecture/SKILL.md +++ b/ai/skills/validate-architecture/SKILL.md @@ -1,8 +1,11 @@ --- name: validate-architecture description: Verify architectural consistency and dependency rules +trigger: when the user asks about architecture, rules, conventions, or dependency validation --- +# Validate Architecture + When invoked: 1. Detect project structure: diff --git a/opencode.json b/opencode.json index 61966d8..43f3153 100644 --- a/opencode.json +++ b/opencode.json @@ -2,6 +2,6 @@ "$schema": "https://opencode.ai/config.json", "instructions": ["AGENTS.md"], "skills": { - "paths": [".opencode/skills"] + "paths": ["ai/skills"] } -} +} \ No newline at end of file