From 6aaa25869375f9516edcb02596960829c1841e64 Mon Sep 17 00:00:00 2001 From: gabrielmoro Date: Mon, 10 Aug 2026 21:51:24 -0300 Subject: [PATCH 1/2] AGENTS.md --- AGENTS.md | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..574b58f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,136 @@ +# AGENTS.md + +`[opencode] AGENTS.md loaded` + +## Project Overview + +TodoApp is a sample Flutter project built as a testing playground. It manages +checklists and tasks using sqflite for local persistence. Targets Android, iOS, +and macOS. Uses flutter_bloc (Cubit) for state management, get_it + injectable +for DI, auto_route for navigation, freezed for immutable models, and supports +English/Portuguese localization. + +## Dev Environment Setup + +1. Install Flutter 3.38.x (see `.github/actions/setup-flutter/action.yml` for + the pinned version) +2. `flutter pub get` +3. `dart run build_runner build --delete-conflicting-outputs` +4. `flutter gen-l10n` + +Steps 3 and 4 must be re-run after any changes to annotated classes +(`*.freezed.dart`, router config, injectable config) or `.arb` localization +files. + +## Project Architecture + +### Layer-first layout + +``` +lib/ + data/ — models (freezed), DAOs (sqflite), repository, share handler + domain/ — sort & summary helpers + ui/ — screens (features), shared components, widgets, l10n + util/ — DI (get_it + injectable), navigation provider +``` + +### Key patterns + +- **State management:** flutter_bloc (Cubit) with freezed immutable states. + Cubits are `@Injectable()` and used via `BlocProvider`/`BlocBuilder`. +- **DI:** get_it + injectable with code-gen. Initialized at startup via + `GetItStartupHandlerWrapper`. +- **Navigation:** auto_route (generated router). Abstracted behind + `NavigatorProvider` interface for testability. +- **Data:** Abstract repository → Impl → DAO pattern. The Abstract + Impl + convention is also used for `NavigatorProvider`, `ShareMessageHandler`, and + `TaskListSortHelper`. + +### Code generation + +Generated files (`*.freezed.dart`, `*.config.dart`, `*.gr.dart`, +`app_localizations*.dart`) are gitignored. Generated on demand via +`build_runner`. + +## Coding Conventions + +### Naming + +- Files: `snake_case` (enforced by `file_names` lint) +- Classes/widgets: `PascalCase` +- Methods/variables: `camelCase` +- Abstract interfaces: plain name (e.g. `TodoRepository`); implementation: + name + `Impl` + +### Imports + +- Always use package imports (`package:todoapp/...`), never relative (enforced + by `always_use_package_imports` and `avoid_relative_lib_imports`) +- Directives ordered as: `dart:` → `package:` → project (enforced by + `directives_ordering`) + +### Style + +- Single quotes (enforced) +- `const` constructors wherever possible (enforced) +- Lines max 80 chars (enforced by `lines_longer_than_80_chars`) +- Curly braces required on all flow control (enforced by + `curly_braces_in_flow_control_structures`) +- Always declare return types (enforced by `always_declare_return_types`) + +### Architecture rules (eagle_eye) + +- `data/model/*` must have zero external dependencies +- `*viewmodel.dart` must not depend on `*_screen.dart` +- `util/*_provider.dart` and `util/*_handler.dart` must have zero external + dependencies + +## Testing + +### Running tests + +``` +flutter test +``` + +Code generation (`build_runner` + `flutter gen-l10n`) must complete before +tests pass. + +### Organization + +Tests mirror `lib/` structure under `test/` (layer-first). + +### Patterns + +- **Domain/logic tests:** Pure Dart, no widget testing. Use + Arrange/Act/Assert with real implementations (no mocking framework). +- **ViewModel (Cubit) tests:** Use `FakeRepository` (in-memory) from + `test/test_utils/fakes/`. Test initial state, then state transitions after + method calls. +- **Widget tests:** Wrap with `WidgetsUtil.buildMaterialAppWidgetTest()` + (sets up MaterialApp + localization delegates, forced English locale). Use + `testWidgets()`, `pumpWidget()`, `find.byKey()`, `find.text()`. + +### Test doubles + +Hand-written fakes in `test/test_utils/fakes/` (no mockito): +`FakeRepository`, `FakeNavigatorProvider`, `FakeCallbacks`, `FakeStates`. + +## PR & CI + +### PR checks (`.github/workflows/pr.yml`) + +Triggered on PRs to `main`. Runs on every PR: + +1. `flutter gen-l10n` — generate localizations +2. `dart run eagle_eye:main` — check architecture violations +3. `flutter test` — run test suite +4. `dart analyze` — static analysis +5. `flutter build apk --debug` — verify build compiles + +All steps must pass before merging. + +### Release (`.github/workflows/release_flutter_app.yaml`) + +Triggered on any tag push. Builds APK (uploaded to Firebase App Distribution) +and macOS `.app.zip` (attached to GitHub Release). From 4063266a0caec73adec5554d6999d7dbdbdd36a5 Mon Sep 17 00:00:00 2001 From: gabrielmoro Date: Mon, 10 Aug 2026 21:55:53 -0300 Subject: [PATCH 2/2] feat(skills): add feature-branch-pr skill --- .opencode/skills/feature-branch-pr/SKILL.md | 181 ++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 .opencode/skills/feature-branch-pr/SKILL.md diff --git a/.opencode/skills/feature-branch-pr/SKILL.md b/.opencode/skills/feature-branch-pr/SKILL.md new file mode 100644 index 0000000..e2a1501 --- /dev/null +++ b/.opencode/skills/feature-branch-pr/SKILL.md @@ -0,0 +1,181 @@ +--- +name: feature-branch-pr +description: Automate Git workflow: create feature branch from main/master, commit changes with auto-generated messages, and open PRs with auto-generated descriptions. Use when user wants to commit changes, create branches, or open PRs. +--- + +Automate the Git/GitHub workflow: create feature branches, commit changes with auto-generated messages, and open PRs with auto-generated descriptions. + +## Process + +### 1. Detect current branch + +Run `git branch --show-current` to get the current branch name. + +- If on `main` or `master` → proceed to step 2 (create feature branch) +- If on a feature branch → skip to step 3 (stage and commit) + +**Completion criterion:** Current branch name captured and decision made. + +### 2. Create feature branch (if on main/master) + +1. Check for uncommitted changes: `git status --porcelain` +2. If changes exist, ask user: "You're on main/master with uncommitted changes. Create a feature branch first?" +3. Ask user: "What's the feature name?" (e.g., "add-login-page") +4. Create and switch to feature branch: `git checkout -b feature/` +5. Display: "Created and switched to feature/" + +**Completion criterion:** On feature branch with name confirmed. + +### 3. Stage changes + +1. Run `git status` to check for changes +2. If no changes → display "No changes to commit" and stop +3. Stage changes: `git add .` +4. Confirm staging: `git diff --cached --stat` +5. If no staged changes → display "No changes to commit" and stop + +**Completion criterion:** Changes staged and ready to commit. + +### 4. Generate commit message + +Analyze staged changes with `git diff --cached` to generate a commit message following conventional commits format: + +**Type detection:** +- New files only → `feat` +- Modified files → Analyze changes: + - Documentation (*.md, *.txt) → `docs` + - Tests (*test*, *spec*) → `test` + - Config files → `chore` + - Code logic changes → `fix` or `feat` based on scope + - Code formatting/style → `style` + - Code restructuring → `refactor` +- Deleted files → `refactor` or `feat` + +**Scope detection:** +- Use the common directory prefix of changed files +- If files span multiple directories, use the most prominent one +- Omit scope if changes are too diverse + +**Description rules:** +- Imperative mood ("add" not "added" or "adds") +- Lowercase first letter +- No period at end +- Keep under 50 characters +- Focus on *what* changed, not *how* + +**Example:** `feat(auth): add login page with OAuth support` + +### 5. Commit changes + +1. Run `git commit -m ""` +2. Verify commit: `git log -1 --oneline` +3. Display: "Committed: " + +**Completion criterion:** Changes committed successfully. + +### 6. Ask about PR + +Ask user: "Do you want to open a PR? (yes/no)" + +- If no → display "Done! Changes committed to feature/" and stop +- If yes → proceed to step 7 + +**Completion criterion:** User decision received. + +### 7. Detect base branch + +1. Check if `main` exists: `git branch --list main` +2. Check if `master` exists: `git branch --list master` +3. If both exist, ask user which to use as base +4. If only one exists, use that one +5. If neither exists, ask user for base branch name + +**Completion criterion:** Base branch identified. + +### 8. Generate PR description + +Analyze the feature branch changes to generate a PR description: + +1. Get commit history: `git log ..HEAD --oneline` +2. Get diff summary: `git diff ...HEAD --stat` +3. Get full diff: `git diff ...HEAD` + +**Generate description with:** + +```markdown +## Summary +[1-2 sentences describing overall purpose of changes] + +## Changes +- [Bullet point for each significant change, derived from commits and diff] + +## Testing +- [How to test these changes, if discernible from code] +- [Any test files added/modified] + +## Related +[List of commits from feature branch] +``` + +**Completion criterion:** PR description generated. + +### 9. Create PR + +1. Check gh CLI is available: `gh --version` +2. Check authentication: `gh auth status` +3. If not authenticated → display instructions and stop +4. Check for existing PR: `gh pr list --head feature/` +5. If PR exists → display existing PR URL and stop +6. Create PR: + ```bash + gh pr create \ + --base \ + --head feature/ \ + --title "" \ + --body "" + ``` +7. Extract PR URL from output +8. Display: `🚀 your PR is opened take a look: ` + +**Completion criterion:** PR created and URL displayed. + +## Edge Cases + +- **No changes to commit:** Stop with message "No changes to commit" +- **gh CLI missing:** Display "GitHub CLI (gh) is not installed. Install from https://cli.github.com/" +- **gh not authenticated:** Display "Run 'gh auth login' to authenticate with GitHub" +- **PR already exists:** Display "PR already exists: " +- **Empty diff after commits:** Don't create PR, display message +- **User cancels:** Gracefully stop at any prompt with "Operation cancelled" + +## Examples + +### Scenario 1: On main, create new feature +``` +$ git branch --show-current +main + +→ You're on main. What's the feature name? +user: add-dark-mode + +→ Created and switched to feature/add-dark-mode +→ Changes staged: 3 files changed, 45 insertions(+), 12 deletions(-) +→ Committed: feat(ui): add dark mode toggle +→ Do you want to open a PR? (yes/no) +user: yes + +→ 🚀 your PR is opened take a look: https://github.com/user/repo/pull/42 +``` + +### Scenario 2: On feature branch, commit directly +``` +$ git branch --show-current +feature/add-login + +→ Changes staged: 2 files changed, 28 insertions(+), 5 deletions(-) +→ Committed: feat(auth): implement login form validation +→ Do you want to open a PR? (yes/no) +user: no + +→ Done! Changes committed to feature/add-login +```