@bdayadev/flutter-ultra-mcp 1.3.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@
10
10
  {
11
11
  "name": "flutter",
12
12
  "description": "Durable cross-platform Flutter automation via 8 specialized MCP servers, in-app mixin binding, and an optional DevTools panel. Replaces marionette_mcp and the official dart mcp-server for Claude Code.",
13
- "version": "1.3.2",
13
+ "version": "1.5.0",
14
14
  "author": {
15
15
  "name": "Bdaya-Dev",
16
16
  "url": "https://github.com/Bdaya-Dev"
@@ -31,5 +31,5 @@
31
31
  ]
32
32
  }
33
33
  ],
34
- "version": "1.3.2"
34
+ "version": "1.5.0"
35
35
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "flutter",
4
- "version": "1.3.2",
4
+ "version": "1.5.0",
5
5
  "description": "Durable cross-platform Flutter automation via 8 specialized MCP servers, in-app mixin binding, and an optional DevTools panel. Replaces marionette_mcp and the official dart mcp-server for Claude Code.",
6
6
  "author": {
7
7
  "name": "Bdaya-Dev",
@@ -15,8 +15,6 @@ topics:
15
15
  - agent
16
16
  - testing
17
17
 
18
- publish_to: none
19
-
20
18
  environment:
21
19
  sdk: '>=3.6.0 <4.0.0'
22
20
  flutter: '>=3.27.0'
@@ -7,8 +7,6 @@ homepage: https://github.com/Bdaya-Dev/flutter-ultra-mcp
7
7
  repository: https://github.com/Bdaya-Dev/flutter-ultra-mcp
8
8
  issue_tracker: https://github.com/Bdaya-Dev/flutter-ultra-mcp/issues
9
9
 
10
- publish_to: none
11
-
12
10
  environment:
13
11
  sdk: ^3.5.0
14
12
  flutter: '>=3.24.0'
@@ -17,8 +17,8 @@ In debug mode the `UltraFlutterBinding` is automatically initialized, exposing
17
17
 
18
18
  ## Widget Keys
19
19
 
20
- | Key | Widget | Purpose |
21
- |-----|--------|---------|
22
- | `counter_value` | Text | Displays current count |
23
- | `increment` | FAB | Increments counter |
24
- | `decrement` | FAB | Decrements counter |
20
+ | Key | Widget | Purpose |
21
+ | --------------- | ------ | ---------------------- |
22
+ | `counter_value` | Text | Displays current count |
23
+ | `increment` | FAB | Increments counter |
24
+ | `decrement` | FAB | Decrements counter |
@@ -18,6 +18,8 @@ dependencies:
18
18
  dev_dependencies:
19
19
  flutter_test:
20
20
  sdk: flutter
21
+ integration_test:
22
+ sdk: flutter
21
23
 
22
24
  flutter:
23
25
  uses-material-design: true
@@ -19,11 +19,13 @@ interception and CCT (Custom Chrome Tab) OAuth solver on mobile.
19
19
  ## Running
20
20
 
21
21
  1. Start the mock OIDC server:
22
+
22
23
  ```bash
23
24
  dart run lib/mock_oidc_server.dart
24
25
  ```
25
26
 
26
27
  2. Run the Flutter app:
28
+
27
29
  ```bash
28
30
  flutter run -d chrome
29
31
  ```
@@ -32,14 +34,14 @@ interception and CCT (Custom Chrome Tab) OAuth solver on mobile.
32
34
 
33
35
  ## Widget Keys
34
36
 
35
- | Key | Widget | Purpose |
36
- |-----|--------|---------|
37
- | `login_button` | FilledButton | Initiates OIDC flow |
38
- | `logout_button` | FilledButton.tonal | Clears token |
39
- | `auth_status` | Text | Shows "Authenticated" or "Not authenticated" |
40
- | `token_preview` | SelectableText | Truncated token display |
41
- | `loading_indicator` | CircularProgressIndicator | During OAuth exchange |
42
- | `error_text` | Text | Error message |
37
+ | Key | Widget | Purpose |
38
+ | ------------------- | ------------------------- | -------------------------------------------- |
39
+ | `login_button` | FilledButton | Initiates OIDC flow |
40
+ | `logout_button` | FilledButton.tonal | Clears token |
41
+ | `auth_status` | Text | Shows "Authenticated" or "Not authenticated" |
42
+ | `token_preview` | SelectableText | Truncated token display |
43
+ | `loading_indicator` | CircularProgressIndicator | During OAuth exchange |
44
+ | `error_text` | Text | Error message |
43
45
 
44
46
  ## CI Usage
45
47
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bdayadev/flutter-ultra-mcp",
3
- "version": "1.3.2",
3
+ "version": "1.5.0",
4
4
  "description": "Flutter Ultra MCP plugin monorepo — 8 MCP servers + ultra_flutter Dart packages + skills for Claude Code.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/Bdaya-Dev/flutter-ultra-mcp",
@@ -28,7 +28,10 @@
28
28
  "format": "prettier --write \"**/*.{ts,tsx,js,json,md,yml,yaml}\"",
29
29
  "format:check": "prettier --check \"**/*.{ts,tsx,js,json,md,yml,yaml}\"",
30
30
  "bundle": "node scripts/bundle.mjs",
31
- "prepare": "npm run build --if-present || true"
31
+ "prepare": "npm run build --if-present || true",
32
+ "test:e2e:web": "vitest run tests/e2e/web/",
33
+ "test:e2e:oidc": "vitest run tests/e2e/oidc/",
34
+ "test:dogfood": "vitest run tests/e2e/dogfood/"
32
35
  },
33
36
  "devDependencies": {
34
37
  "@commitlint/cli": "^19.0.0",
@@ -36,4 +36,4 @@
36
36
  "typescript": "^5.6.0",
37
37
  "vitest": "^2.0.0"
38
38
  }
39
- }
39
+ }
@@ -35,4 +35,4 @@
35
35
  "@types/proper-lockfile": "^4.1.4",
36
36
  "vitest": "^2.1.9"
37
37
  }
38
- }
38
+ }
@@ -33,4 +33,4 @@
33
33
  "typescript": "^5.6.0",
34
34
  "vitest": "^3.2.4"
35
35
  }
36
- }
36
+ }
@@ -55,4 +55,4 @@
55
55
  "publishConfig": {
56
56
  "access": "public"
57
57
  }
58
- }
58
+ }
@@ -78,4 +78,4 @@
78
78
  "publishConfig": {
79
79
  "access": "public"
80
80
  }
81
- }
81
+ }
@@ -69,4 +69,4 @@
69
69
  "publishConfig": {
70
70
  "access": "public"
71
71
  }
72
- }
72
+ }
@@ -22,12 +22,12 @@ MCP server orchestrating **Patrol E2E tests** across web, Android, iOS, and desk
22
22
 
23
23
  ## Environment contract (from plugin `.mcp.json`)
24
24
 
25
- | Var | Used for |
26
- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
27
- | `FLUTTER_ULTRA_PATROL_FORK` | Absolute path to `vendor/patrol/`. |
28
- | `FLUTTER_ULTRA_STATE_DIR` | Future on-disk job persistence (in-memory in v1.0). |
25
+ | Var | Used for |
26
+ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
27
+ | `FLUTTER_ULTRA_PATROL_FORK` | Absolute path to `vendor/patrol/`. |
28
+ | `FLUTTER_ULTRA_STATE_DIR` | Future on-disk job persistence (in-memory in v1.0). |
29
29
  | `PATROL_WEB_BROWSER_ARGS` | Comma-separated Chromium flags merged into every `--web-browser-args`. Default: `--enable-unsafe-swiftshader,--disable-renderer-backgrounding,--disable-background-timer-throttling`. |
30
- | `FLUTTER_ULTRA_LOG_LEVEL` | `debug`/`info`/`warn`/`error`. Default `info`. |
30
+ | `FLUTTER_ULTRA_LOG_LEVEL` | `debug`/`info`/`warn`/`error`. Default `info`. |
31
31
 
32
32
  ## Invocation strategy
33
33
 
@@ -35,4 +35,4 @@
35
35
  "engines": {
36
36
  "node": ">=20"
37
37
  }
38
- }
38
+ }
@@ -66,4 +66,4 @@
66
66
  "publishConfig": {
67
67
  "access": "public"
68
68
  }
69
- }
69
+ }
@@ -2,7 +2,7 @@
2
2
  "name": "@flutter-ultra/contracts",
3
3
  "version": "0.0.0",
4
4
  "private": true,
5
- "description": "JSON Schema contract definitions for ext.flutter.ultra.* wire format \u00e2\u20ac\u201d single source of truth for TS\u00e2\u2020\u201dDart interop.",
5
+ "description": "JSON Schema contract definitions for ext.flutter.ultra.* wire format — single source of truth for TS↔Dart interop.",
6
6
  "license": "Apache-2.0",
7
7
  "type": "module",
8
8
  "main": "dist/index.js",
@@ -28,4 +28,4 @@
28
28
  "devDependencies": {
29
29
  "vitest": "^3.2.4"
30
30
  }
31
- }
31
+ }
@@ -59,4 +59,4 @@
59
59
  "publishConfig": {
60
60
  "access": "public"
61
61
  }
62
- }
62
+ }
@@ -21,4 +21,4 @@
21
21
  "dependencies": {
22
22
  "@napi-rs/keyring": "^1.3.0"
23
23
  }
24
- }
24
+ }
@@ -55,4 +55,4 @@
55
55
  "publishConfig": {
56
56
  "access": "public"
57
57
  }
58
- }
58
+ }
@@ -57,4 +57,4 @@
57
57
  "publishConfig": {
58
58
  "access": "public"
59
59
  }
60
- }
60
+ }
@@ -59,4 +59,4 @@
59
59
  "publishConfig": {
60
60
  "access": "public"
61
61
  }
62
- }
62
+ }
@@ -0,0 +1,202 @@
1
+ ---
2
+ name: flutter-bisect
3
+ description: Automate git bisect to find the commit that introduced a bug. Flutter-aware: runs pub get + build_runner between commits. Use when a test passes on an older commit but fails on HEAD and you need to find exactly which commit broke it.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # flutter-bisect — Automated Regression Finder
8
+
9
+ ## When to use
10
+
11
+ Use this skill when a test (unit, widget, or patrol E2E) passes on an older commit but fails on HEAD and you need to pinpoint exactly which commit introduced the regression. Do not use for diagnosing a bug you already know the source of — use `flutter-debug` instead.
12
+
13
+ ## Prerequisites
14
+
15
+ - The working tree is in a git repository (`git status` returns without error).
16
+ - The user provides (or you can infer) a **known-good** commit reference: a tag (`v1.2.0`), a branch name (`main@{7 days ago}`), or a full SHA.
17
+ - A **test oracle** is specified: a unit/widget test name pattern, a patrol test file, or a Bash-style exit-code command.
18
+ - No uncommitted changes that would interfere — stash them first (see Edge cases).
19
+
20
+ ## Workflow
21
+
22
+ ### 1. Confirm inputs before starting
23
+
24
+ Ask (or confirm from context) the following before calling any git command:
25
+
26
+ - **Good commit**: the last-known-good reference (tag, SHA, or relative ref).
27
+ - **Bad commit**: defaults to `HEAD`.
28
+ - **Oracle type**: `unit`, `widget`, or `patrol`.
29
+ - **Oracle selector**: test name pattern or patrol `testFilePath`.
30
+ - **Project**: call `mcp__plugin_flutter_flutter-ultra-build__list_projects` if not already known.
31
+ - **Has build_runner**: check for `build.yaml` in the project root — if present, set `needs_build_runner=true`.
32
+
33
+ ### 2. Stash uncommitted changes
34
+
35
+ Before touching any git ref, check for dirty working tree:
36
+
37
+ ```bash
38
+ git -C <project-root> status --porcelain
39
+ ```
40
+
41
+ If output is non-empty, stash:
42
+
43
+ ```bash
44
+ git -C <project-root> stash push -m "flutter-bisect-autoStash"
45
+ ```
46
+
47
+ Record whether a stash was created — you must restore it in step 7.
48
+
49
+ ### 3. Start bisect
50
+
51
+ ```bash
52
+ git -C <project-root> bisect start --first-parent HEAD <good-commit>
53
+ ```
54
+
55
+ `--first-parent` skips noise from merged feature branches and keeps the walk on the mainline. Git prints the number of steps remaining — surface this to the user.
56
+
57
+ ### 4. At each bisect step — the Flutter-aware oracle loop
58
+
59
+ Repeat until git prints `<sha> is the first bad commit`:
60
+
61
+ #### 4a. Get current commit info
62
+
63
+ ```bash
64
+ git -C <project-root> log -1 --format="%H %s"
65
+ ```
66
+
67
+ Show the user which commit is under test and how many steps remain.
68
+
69
+ #### 4b. Restore Flutter state for this commit
70
+
71
+ Run these in order — do not skip even if pubspec.yaml looks unchanged (lockfile may differ):
72
+
73
+ 1. **pub get**: `mcp__plugin_flutter_flutter-ultra-build__pub_get` with the project name.
74
+ - If pub get fails (e.g. dependency conflict introduced by this commit), mark the commit **bad** and continue — a broken dep is a broken state.
75
+ 2. **build_runner** (only if `needs_build_runner=true`):
76
+ - Call `mcp__plugin_flutter_flutter-ultra-build__start_build_runner_build`.
77
+ - Poll `mcp__plugin_flutter_flutter-ultra-build__poll_build_runner_job` until done.
78
+ - Get result via `mcp__plugin_flutter_flutter-ultra-build__get_build_runner_result`.
79
+ - If build_runner fails: mark the commit **bad** and continue.
80
+
81
+ #### 4c. Run the oracle
82
+
83
+ **Unit/widget oracle:**
84
+
85
+ - Start: `mcp__plugin_flutter_flutter-ultra-build__start_run_unit_tests` with `testNamePattern` (or `start_run_widget_tests`).
86
+ - Poll: `mcp__plugin_flutter_flutter-ultra-build__poll_run_unit_tests` (or `poll_run_widget_tests`).
87
+ - Result: `mcp__plugin_flutter_flutter-ultra-build__get_run_unit_tests_result` (or `get_run_widget_tests_result`).
88
+ - If all targeted tests pass → **good**. If any fail → **bad**.
89
+
90
+ **Patrol oracle:**
91
+
92
+ - Start: `mcp__plugin_flutter_flutter-ultra-patrol__start_patrol_test` with `testFilePath` and `device`.
93
+ - Poll: `mcp__plugin_flutter_flutter-ultra-patrol__poll_patrol_job`.
94
+ - Result: `mcp__plugin_flutter_flutter-ultra-patrol__get_patrol_result`.
95
+ - If all steps pass → **good**. If any fail → **bad**.
96
+
97
+ #### 4d. Mark the commit
98
+
99
+ ```bash
100
+ # if oracle passed:
101
+ git -C <project-root> bisect good
102
+
103
+ # if oracle failed:
104
+ git -C <project-root> bisect bad
105
+ ```
106
+
107
+ Git will output the next commit to test, or the final verdict. Loop back to 4a.
108
+
109
+ ### 5. Capture and report the first bad commit
110
+
111
+ When git prints `<sha> is the first bad commit`, capture the full details:
112
+
113
+ ```bash
114
+ git -C <project-root> show --stat <sha>
115
+ git -C <project-root> log -1 --format="%H%n%an <%ae>%n%ad%n%s%n%b" --date=iso <sha>
116
+ ```
117
+
118
+ Present a structured report (see Output format).
119
+
120
+ ### 6. Reset bisect
121
+
122
+ Always reset, even on error:
123
+
124
+ ```bash
125
+ git -C <project-root> bisect reset
126
+ ```
127
+
128
+ ### 7. Restore stash (if created in step 2)
129
+
130
+ ```bash
131
+ git -C <project-root> stash pop
132
+ ```
133
+
134
+ ## Edge cases
135
+
136
+ | Situation | Handling |
137
+ | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
138
+ | **Merge commits on the walk** | `--first-parent` avoids them; if user omits it intentionally (to bisect a merged branch), remove the flag and warn that step count increases. |
139
+ | **Uncommitted changes** | Auto-stash in step 2; restore in step 7. If stash pop fails (conflict), warn the user and leave the stash intact — do not discard it. |
140
+ | **Submodule repo** | `git bisect` operates on the outer repo. If the Flutter project is a submodule, confirm the user wants to bisect the outer aggregate, not the inner submodule. Pass the correct `-C <path>` to all git commands. |
141
+ | **Flutter SDK version change** | If a commit changes the Flutter SDK constraint (`.tool-versions`, `fvm` config, `flutter.constraints`), call `mcp__plugin_flutter_flutter-ultra-build__flutter_clean` before pub get to clear the compiled kernel cache. |
142
+ | **pub get resolves a different lockfile** | Expected — this is exactly what the skill needs. Never pin the lockfile artificially during bisect. |
143
+ | **Oracle is flaky** | If the oracle fails on a commit that visually looks clean, re-run it once. If it fails again, mark bad. Do not retry more than once per commit — flakiness analysis is out of scope here; use `flutter-debug` after bisect completes. |
144
+ | **All commits bad (misconfigured good ref)** | If `git bisect start` immediately shows 0 steps or git says the good commit is not an ancestor, stop and ask the user to verify the good commit reference. |
145
+
146
+ ## Output format
147
+
148
+ After bisect completes, produce:
149
+
150
+ ```
151
+ ## Bisect Result
152
+
153
+ First bad commit: <sha>
154
+ Author: <name> <<email>>
155
+ Date: <iso date>
156
+ Message: <subject line>
157
+
158
+ <body if present>
159
+
160
+ Files changed:
161
+ <git show --stat output>
162
+
163
+ Steps taken: <N> commits tested across <M> total candidates.
164
+ ```
165
+
166
+ If bisect could not converge (user cancelled, all commits bad, or git error), produce:
167
+
168
+ ```
169
+ ## Bisect Aborted
170
+
171
+ Reason: <what went wrong>
172
+ Last tested commit: <sha or "none">
173
+ Recommendation: <next debugging step>
174
+ ```
175
+
176
+ ## Example
177
+
178
+ ```
179
+ User: "The InvoiceBloc unit test was green on v1.3.0 but fails on HEAD. Find which commit broke it."
180
+
181
+ 1. list_projects → project: "invora-flutter"
182
+ 2. Check build.yaml → present → needs_build_runner=true
183
+ 3. git status → clean → no stash needed
184
+ 4. git bisect start --first-parent HEAD v1.3.0 → "~6 steps (roughly 53 revisions)"
185
+ 5. [commit abc123] pub_get → ok; build_runner → ok; run_unit_tests(pattern: "InvoiceBloc") → FAIL → bisect bad
186
+ 6. [commit def456] pub_get → ok; build_runner → ok; run_unit_tests → FAIL → bisect bad
187
+ 7. [commit ghi789] pub_get → ok; build_runner → ok; run_unit_tests → PASS → bisect good
188
+ 8. [commit jkl012] pub_get → ok; build_runner → ok; run_unit_tests → FAIL → bisect bad
189
+ 9. [commit mno345] pub_get → ok; build_runner → ok; run_unit_tests → PASS → bisect good
190
+ 10. [commit pqr678] pub_get → ok; build_runner → ok; run_unit_tests → FAIL → bisect bad
191
+ 11. git: "pqr678 is the first bad commit"
192
+ 12. git show --stat pqr678 → "refactor(billing): collapse invoice state machine"
193
+ 13. git bisect reset
194
+ → Report: first bad commit pqr678, author, date, changed files
195
+ ```
196
+
197
+ ## See also
198
+
199
+ - `flutter-test` — run the full test suite without bisecting
200
+ - `flutter-debug` — inspect live runtime state after bisect identifies a suspect commit
201
+ - `mcp__plugin_flutter_flutter-ultra-build__start_build_runner_build` — build_runner reference
202
+ - `mcp__plugin_flutter_flutter-ultra-patrol__start_patrol_test` — patrol oracle reference
@@ -1,20 +1,156 @@
1
1
  ---
2
- name: debug
2
+ name: flutter-debug
3
3
  description: Attaching to a running Flutter app and triaging an error from the stack trace, widget tree, render tree, and recent screenshot. Use when the user reports a runtime exception, layout overflow, or unexpected behaviour and you need to inspect live state.
4
4
  ---
5
5
 
6
- # Debug (stub)
6
+ # flutter-debug — Attach, Inspect, and Triage
7
7
 
8
- **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §8.3, §12).
8
+ ## When to use
9
+
10
+ Use this skill when the user reports a runtime exception, a layout overflow, a blank screen, unexpected navigation, or any "it's broken" situation in a running Flutter app. The goal is to collect enough live evidence to diagnose the root cause without guessing. Propose code fixes only after inspecting live state — never before.
11
+
12
+ ## Prerequisites
13
+
14
+ - A Flutter app is running in debug mode (VM Service available).
15
+ - The user has described the symptom: exception message, screen name, reproduction steps, or "just broke".
16
+ - Do **not** modify any source files during this skill unless the user explicitly asks for a fix.
9
17
 
10
18
  ## Workflow
11
19
 
12
- - `mcp__flutter-ultra-runtime__discover_sessions` and pick the target app.
13
- - Pull recent errors with `mcp__flutter-ultra-runtime__get_runtime_errors`.
14
- - Cross-reference frames with `mcp__flutter-ultra-runtime__get_widget_tree` and `dump_render_tree`.
15
- - Capture a screenshot for context.
16
- - Propose a fix inline; do not edit code unless asked.
20
+ Follow the triage ladder in order — stop at the level where the root cause becomes clear.
21
+
22
+ ### 1. Attach to the session
23
+
24
+ - Call `mcp__plugin_flutter_flutter-ultra-runtime__discover_sessions` list all active sessions.
25
+ - Pick the session matching the reported app (by name or port).
26
+ - Call `mcp__plugin_flutter_flutter-ultra-runtime__attach` with `sessionId`.
27
+
28
+ ### 2. Capture initial state
29
+
30
+ Run these together immediately after attach:
31
+
32
+ - `mcp__plugin_flutter_flutter-ultra-runtime__screenshot` — visual snapshot of the current screen.
33
+ - `mcp__plugin_flutter_flutter-ultra-runtime__get_runtime_errors` — all unhandled exceptions since last clear.
34
+ - `mcp__plugin_flutter_flutter-ultra-runtime__get_logs` — recent `debugPrint` / `print` / framework log output.
35
+
36
+ ### 3. Triage by error type
37
+
38
+ #### 3a. Runtime exception (stack trace present)
39
+
40
+ 1. Read the stack trace from `get_runtime_errors` — identify the throwing file and line.
41
+ 2. Call `mcp__plugin_flutter_flutter-ultra-runtime__evaluate` to inspect the problematic object:
42
+ ```dart
43
+ // Example: check if a value is null
44
+ MyWidget.of(context)?.someField?.toString() ?? 'NULL'
45
+ ```
46
+ 3. Call `mcp__plugin_flutter_flutter-ultra-runtime__get_widget_tree` focused on the widget subtree around the reported location — pass `widgetId` if known from the stack frame.
47
+ 4. Look for: null state, missing providers, incorrect key types, uninitialized controllers.
48
+
49
+ #### 3b. Layout overflow (RenderFlex / RenderBox overflow)
50
+
51
+ 1. Call `mcp__plugin_flutter_flutter-ultra-runtime__dump_render_tree` — search the output for `OVERFLOWED` or constraint violations.
52
+ 2. Call `mcp__plugin_flutter_flutter-ultra-runtime__toggle_debug_paint` to enable visual constraint overlays; take another `screenshot`.
53
+ 3. Identify the overflowing `RenderFlex` or `RenderConstrainedBox` and trace it back to the widget via `get_widget_tree`.
54
+ 4. Common causes: missing `Expanded`/`Flexible`, fixed height in a `Column` inside a scrollable, `Text` without `overflow: TextOverflow.ellipsis`.
55
+
56
+ #### 3c. Blank screen / wrong route
57
+
58
+ 1. Call `mcp__plugin_flutter_flutter-ultra-runtime__evaluate`:
59
+ ```dart
60
+ GoRouter.of(context).routerDelegate.currentConfiguration.fullPath
61
+ ```
62
+ to confirm the actual current route.
63
+ 2. Call `mcp__plugin_flutter_flutter-ultra-runtime__get_widget_tree` from root — look for `ErrorWidget`, empty `SizedBox`, or a redirect loop (same route repeated in the navigator stack).
64
+ 3. Check `get_logs` for GoRouter redirect events or `debugPrint` from route guards.
65
+
66
+ #### 3d. State / data issue (wrong data shown, stale UI)
67
+
68
+ 1. Call `mcp__plugin_flutter_flutter-ultra-runtime__evaluate` to read the current BLoC/Riverpod/Provider state:
69
+ ```dart
70
+ context.read<MyBloc>().state.toString()
71
+ // or for Riverpod:
72
+ ProviderScope.containerOf(context).read(myProvider).toString()
73
+ ```
74
+ 2. Compare against expected values from the user's description.
75
+ 3. Call `mcp__plugin_flutter_flutter-ultra-runtime__get_widget_tree` to verify the widget rebuilds are reaching the right subtree.
76
+
77
+ #### 3e. Accessibility / semantics issue
78
+
79
+ 1. Call `mcp__plugin_flutter_flutter-ultra-runtime__dump_semantics_tree` — look for missing labels, incorrect roles, or hidden interactive elements.
80
+ 2. Check for `excludeFromSemantics: true` incorrectly applied to interactive widgets.
81
+
82
+ ### 4. Inspect the widget tree around the problem
83
+
84
+ - Call `mcp__plugin_flutter_flutter-ultra-runtime__get_widget_tree` with the suspected parent widget key or type as anchor.
85
+ - Call `mcp__plugin_flutter_flutter-ultra-runtime__get_widget_details` on a specific widget ID to get its full properties (constraints, size, key, state).
86
+ - Call `mcp__plugin_flutter_flutter-ultra-runtime__find_widget` to locate a specific widget by key or text when the tree is large.
87
+
88
+ ### 5. Deeper render inspection
89
+
90
+ If layout is the issue and the widget tree alone is not enough:
91
+
92
+ - Call `mcp__plugin_flutter_flutter-ultra-runtime__dump_render_tree` — this shows sizes, constraints, and positions for every render object.
93
+ - Call `mcp__plugin_flutter_flutter-ultra-runtime__dump_layer_tree` for compositing and repaint boundary issues (useful for performance jank or incorrect clipping).
94
+
95
+ ### 6. Evaluate in-app expressions
96
+
97
+ Use `mcp__plugin_flutter_flutter-ultra-runtime__evaluate` freely to inspect live objects:
98
+
99
+ - Check if a future completed: `myCompleter.isCompleted`
100
+ - Read a stream's last value: `myStreamController.stream` (wrap in a Future)
101
+ - Confirm a service is initialized: `MyService.instance != null`
102
+
103
+ ### 7. Test the fix
104
+
105
+ Once the root cause is identified and a code fix is proposed (or applied at user request):
106
+
107
+ - Call `mcp__plugin_flutter_flutter-ultra-runtime__hot_reload` to apply changes without losing app state.
108
+ - Repeat step 3 (appropriate branch) to confirm the error is gone.
109
+ - Call `mcp__plugin_flutter_flutter-ultra-runtime__screenshot` for a before/after comparison.
110
+ - If hot reload is not sufficient (e.g. `initState` changed), call `mcp__plugin_flutter_flutter-ultra-runtime__hot_restart`.
111
+
112
+ ## Common patterns and their diagnosis
113
+
114
+ | Symptom | First tool | What to look for |
115
+ | ------------------------------------------ | ----------------------------------------- | -------------------------------------------------------------------- |
116
+ | `Null check operator used on a null value` | `get_runtime_errors` + `evaluate` | Null state before async load completes; missing null guard |
117
+ | `RenderFlex overflowed by N pixels` | `dump_render_tree` + `toggle_debug_paint` | Column/Row child without `Expanded`; fixed height container |
118
+ | Blank white screen | `get_widget_tree` + `evaluate` (route) | `ErrorWidget` at root; redirect loop; unhandled exception in build |
119
+ | `setState called after dispose` | `get_runtime_errors` + `get_logs` | Async callback holding stale `BuildContext`; missing `mounted` check |
120
+ | Navigation not working | `evaluate` (GoRouter path) + `get_logs` | Route guard redirecting; wrong named route; deep link not registered |
121
+ | Infinite loading spinner | `evaluate` (state) + `get_logs` | Future never completing; stream not emitting; provider not notifying |
122
+ | Wrong data displayed | `evaluate` (BLoC/provider state) | Stale state; `context.watch` vs `context.read` misuse |
123
+
124
+ ## Output format
125
+
126
+ After triage, produce:
127
+
128
+ 1. **Root cause**: one sentence identifying the exact problem.
129
+ 2. **Evidence**: which tool output revealed it (stack trace line, widget tree excerpt, render tree constraint).
130
+ 3. **Proposed fix**: specific code change with file and line reference (do not edit unless asked).
131
+ 4. **Screenshots**: before state screenshot path; after-fix screenshot path if hot_reload was applied.
132
+
133
+ ## Example
134
+
135
+ ```
136
+ User: "The invoices list is showing a blank white screen after I merged the new filter PR."
137
+
138
+ 1. discover_sessions → attach(sessionId: "flutter-1")
139
+ 2. screenshot → blank screen confirmed
140
+ 3. get_runtime_errors → "Null check operator used on null value at invoice_list_bloc.dart:47"
141
+ 4. evaluate: context.read<InvoiceListBloc>().state.toString() → "InvoiceListInitial"
142
+ (bloc never emitted data — the filter query returned null instead of empty list)
143
+ 5. get_widget_tree → root is ErrorWidget wrapping the list scaffold
144
+ 6. Root cause: InvoiceListBloc.mapEventToState at line 47 calls `event.filter!` but
145
+ filter is null on first load after the PR introduced a nullable field.
146
+ 7. Proposed fix: change `event.filter!` to `event.filter ?? const InvoiceFilter()` at
147
+ invoice_list_bloc.dart:47.
148
+ 8. hot_reload → screenshot → list loads correctly.
149
+ ```
17
150
 
18
151
  ## See also
19
152
 
20
- - Plan §8.3
153
+ - Sibling skill: `flutter-drive` for driving interactive flows before/after a fix
154
+ - `mcp__plugin_flutter_flutter-ultra-runtime__get_runtime_errors` — unhandled exception log
155
+ - `mcp__plugin_flutter_flutter-ultra-runtime__dump_render_tree` — full render object tree with constraints
156
+ - `mcp__plugin_flutter_flutter-ultra-runtime__evaluate` — arbitrary Dart expression in live app context