@bdayadev/flutter-ultra-mcp 0.0.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.
Files changed (57) hide show
  1. package/.claude-plugin/plugin.json +14 -0
  2. package/.mcp.json +67 -0
  3. package/CODE_OF_CONDUCT.md +83 -0
  4. package/CONTRIBUTING.md +108 -0
  5. package/LICENSE +201 -0
  6. package/README.md +77 -0
  7. package/SECURITY.md +19 -0
  8. package/dart/ultra_flutter/CHANGELOG.md +34 -0
  9. package/dart/ultra_flutter/EXTENSIONS.md +61 -0
  10. package/dart/ultra_flutter/README.md +109 -0
  11. package/dart/ultra_flutter/pubspec.yaml +37 -0
  12. package/dart/ultra_flutter_devtools/README.md +7 -0
  13. package/dart/ultra_flutter_devtools/pubspec.yaml +27 -0
  14. package/docs/UPSTREAM-PATROL-PRS.md +5 -0
  15. package/docs/UPSTREAM-SENTRY-PR.md +62 -0
  16. package/docs/discovery-empirics.md +435 -0
  17. package/examples/counter-app/README.md +24 -0
  18. package/examples/counter-app/pubspec.yaml +23 -0
  19. package/examples/oidc-app/README.md +48 -0
  20. package/examples/oidc-app/pubspec.yaml +24 -0
  21. package/package.json +82 -0
  22. package/packages/flutter-ultra-browser/README.md +29 -0
  23. package/packages/flutter-ultra-browser/package.json +39 -0
  24. package/packages/flutter-ultra-build/README.md +60 -0
  25. package/packages/flutter-ultra-build/package.json +38 -0
  26. package/packages/flutter-ultra-devtools/README.md +7 -0
  27. package/packages/flutter-ultra-devtools/package.json +36 -0
  28. package/packages/flutter-ultra-gesture/README.md +51 -0
  29. package/packages/flutter-ultra-gesture/package.json +58 -0
  30. package/packages/flutter-ultra-native-desktop/README.md +131 -0
  31. package/packages/flutter-ultra-native-desktop/package.json +81 -0
  32. package/packages/flutter-ultra-native-mobile/README.md +103 -0
  33. package/packages/flutter-ultra-native-mobile/package.json +72 -0
  34. package/packages/flutter-ultra-patrol/README.md +40 -0
  35. package/packages/flutter-ultra-patrol/package.json +38 -0
  36. package/packages/flutter-ultra-runtime/README.md +63 -0
  37. package/packages/flutter-ultra-runtime/package.json +69 -0
  38. package/shared/contracts/package.json +31 -0
  39. package/shared/device-router/README.md +51 -0
  40. package/shared/device-router/package.json +62 -0
  41. package/shared/keyring/README.md +7 -0
  42. package/shared/keyring/package.json +24 -0
  43. package/shared/mcp-runtime/README.md +116 -0
  44. package/shared/mcp-runtime/package.json +58 -0
  45. package/shared/state-store/README.md +66 -0
  46. package/shared/state-store/package.json +60 -0
  47. package/shared/vm-service-client/README.md +135 -0
  48. package/shared/vm-service-client/package.json +62 -0
  49. package/skills/_internal-on-tool-failure/SKILL.md +13 -0
  50. package/skills/_internal-session-bootstrap/SKILL.md +18 -0
  51. package/skills/debug/SKILL.md +20 -0
  52. package/skills/devtools/SKILL.md +21 -0
  53. package/skills/drive/SKILL.md +20 -0
  54. package/skills/scaffold/SKILL.md +21 -0
  55. package/skills/setup/SKILL.md +26 -0
  56. package/skills/test/SKILL.md +19 -0
  57. package/skills/tour/SKILL.md +22 -0
@@ -0,0 +1,435 @@
1
+ # Flutter Session Discovery Empirics — 2026-05-17
2
+
3
+ **Investigator:** worker-P
4
+ **Environment:** Windows 11 Pro 10.0.26200, Flutter 3.41.9 (stable), Dart SDK 3.11.5, VS Code Dart-Code 3.134.0 (flutter-3.134.0), IntelliJ: NOT INSTALLED
5
+ **Guinea pig:** a Flutter app (`lib/main_development.dart`)
6
+
7
+ ---
8
+
9
+ ## 1. Environment Audit
10
+
11
+ | Item | Value |
12
+ | ------------------------- | --------------------------- |
13
+ | OS | Windows 11 Pro 10.0.26200 |
14
+ | Flutter | 3.41.9 (stable, 2026-04-29) |
15
+ | Dart SDK | 3.11.5 (stable) |
16
+ | DevTools | 2.54.2 |
17
+ | VS Code Dart-Code | 3.134.0 |
18
+ | VS Code Flutter ext | 3.134.0 |
19
+ | IntelliJ / Android Studio | NOT INSTALLED |
20
+
21
+ ---
22
+
23
+ ## 2. Terminal-Launched Session (Empirically Observed)
24
+
25
+ Two live `flutter run -d chrome` sessions were found already running on the machine at observation time. Session analysis is from those live processes — no new flutter run was spawned (ports were already in use at 4206; spawning would have required a different port).
26
+
27
+ ### Process Tree (Session 1, flutter_tools.f19e916)
28
+
29
+ ```
30
+ PID 83892 dart.exe flutter_tools.snapshot run -d chrome -t lib/main_development.dart
31
+ --web-port=4206
32
+ --web-browser-flag=--headless=new
33
+ --web-browser-flag=--disable-gpu
34
+ --web-browser-flag=--no-sandbox
35
+ --dart-define=env=tests
36
+
37
+ PID 72124 dartvm.exe (the actual Dart VM running the app)
38
+ --enable-vm-service=44456/127.0.0.1
39
+ (inferred from: port 44456 owned by PID 72124)
40
+
41
+ PID 72328 dartaotruntime.exe frontend_server_aot.dart.snapshot
42
+ --sdk-root .../flutter_web_sdk/
43
+ --packages .dart_tool/package_config.json
44
+ --output-dill C:\...\flutter_tools.f19e916\flutter_tool.960a6eb6\app.dill
45
+ (incremental compiler)
46
+
47
+ PID 53908 dartaotruntime.exe dds_aot.dart.snapshot
48
+ --vm-service-uri=http://127.0.0.1:44456/4hT1IFnQtjM=
49
+ --bind-address=127.0.0.1
50
+ --bind-port=0 ← port assigned dynamically
51
+ --serve-devtools
52
+
53
+ PID 69232 chrome.exe (headless)
54
+ --user-data-dir=...\flutter_tools.f19e916\flutter_tools_chrome_device.9397ec92
55
+ --remote-debugging-port=50550
56
+ http://localhost:4206
57
+ ```
58
+
59
+ ### Key URIs (Session 1)
60
+
61
+ | Service | URI |
62
+ | ------------------- | -------------------------------------------------------------------------------------------- |
63
+ | Raw Dart VM service | `http://127.0.0.1:44456/4hT1IFnQtjM=` |
64
+ | DDS (multi-client) | `ws://127.0.0.1:50639/VQKkdeOH2R8=/ws` |
65
+ | DDS devtools port | `http://127.0.0.1:50638/` (requires token, returns "missing or invalid authentication code") |
66
+ | Chrome CDP | `http://127.0.0.1:50550` (`--remote-debugging-port`) |
67
+ | App web port | `http://localhost:4206` |
68
+
69
+ ### VM → DDS redirection (CRITICAL empirical observation)
70
+
71
+ Attempting HTTP GET on the raw VM URI `http://127.0.0.1:44456/4hT1IFnQtjM=` returns:
72
+
73
+ ```
74
+ Cannot connect directly to the VM service as a Dart Development Service (DDS) instance
75
+ has taken control and can be found at http://127.0.0.1:50639/VQKkdeOH2R8=/.
76
+ ```
77
+
78
+ **Implication for process-scan discovery:** The raw VM port (44456) is always available in the process cmdline as `--enable-vm-service=<port>/<host>` on the `dartvm.exe` process. But connecting to it directly is rejected when DDS is running — the redirect response **gives you the DDS URI**. This is a reliable discovery mechanism: parse the redirect body to extract the real DDS URI.
79
+
80
+ ### Ports Summary (Session 1)
81
+
82
+ | Port | Owner PID | Process | Purpose |
83
+ | ----- | --------------- | ------------------ | ------------------------------- |
84
+ | 4206 | 72124 (dartvm) | dartvm.exe | App web server |
85
+ | 44456 | 72124 (dartvm) | dartvm.exe | Raw VM service (DDS takes over) |
86
+ | 50639 | 53908 (dds_aot) | dartaotruntime.exe | DDS multi-client WS endpoint |
87
+ | 50638 | 53908 (dds_aot) | dartaotruntime.exe | DDS devtools endpoint |
88
+ | 50550 | 69232 (chrome) | chrome.exe | Chrome CDP |
89
+
90
+ ### DDS `--bind-port=0` → dynamic port assignment
91
+
92
+ The DDS process is always launched with `--bind-port=0`, meaning **the DDS port is always dynamic and cannot be predicted**. The port must be discovered from:
93
+
94
+ 1. The redirect response from the raw VM port (most reliable)
95
+ 2. Port scan + `getVM` probe
96
+ 3. Process netstat join (DDS PID → LISTEN port)
97
+
98
+ ### Temp dir layout for terminal-launched sessions
99
+
100
+ ```
101
+ %TEMP%\flutter_tools.<random8hex>\
102
+ flutter_tool.<random8hex>\
103
+ app.dill (compiled app)
104
+ app.dill.json (source map)
105
+ app.dill.map
106
+ app.dill.metadata
107
+ app.dill.sources
108
+ app.dill.incremental.dill
109
+ flutter_tools.<random8hex>\
110
+ web_entrypoint.dart
111
+ web_plugin_registrant.dart
112
+ flutter_tools_chrome_device.<random8hex>\
113
+ Local State
114
+ Last Browser
115
+ Last Version
116
+ (Chrome profile files — no session JSON here)
117
+ ```
118
+
119
+ **No DTD info file written here.** No `*dtd*.json` found in any `flutter_tools.*` directory. The DTD info file mechanism (`--dtd-write-info-file`) is only used when the spawner (VS Code Dart-Code) passes that flag — terminal `flutter run` does NOT pass it.
120
+
121
+ ### `.dart_tool/` directory (project-local)
122
+
123
+ Pre-existing content in the project's `.dart_tool/`:
124
+
125
+ ```
126
+ .dart_tool/
127
+ build/ (build_runner artifacts)
128
+ build_resolvers/
129
+ chrome-device/ (EMPTY — not used by flutter run -d chrome)
130
+ dartpad/ (EMPTY — not used locally)
131
+ extension_discovery/
132
+ flutter_build/
133
+ hooks_runner/
134
+ native_assets/
135
+ pub/
136
+ native_assets.yaml
137
+ package_config.json (dep resolution — critical for flutter run)
138
+ package_graph.json
139
+ version → "3.41.9"
140
+ ```
141
+
142
+ **`chrome-device/` is empty.** No session info written there by flutter run.
143
+
144
+ **No dart_tool files at user home level:**
145
+
146
+ - `~/.dart_tool/` — NOT FOUND
147
+ - `~/.dart-tool/` — NOT FOUND
148
+ - `%TEMP%\dart_tool\` — NOT FOUND
149
+ - `%LOCALAPPDATA%\dart\` — only contains pub global install bundles (jaspr_cli etc.)
150
+ - `%APPDATA%\dart\` — only `pub-credentials.json` and `pub-tokens.json`
151
+
152
+ ### Environment variables
153
+
154
+ No flutter/dart session env vars injected into terminal-launched processes:
155
+
156
+ - `DART_TOOL_DAEMON_URI` — NOT SET (in this terminal session)
157
+ - `FLUTTER_TOOL_LOG` — NOT SET
158
+ - `DART_VM_OPTIONS` — NOT SET
159
+
160
+ These are only injected by VS Code's Dart extension into its integrated terminals.
161
+
162
+ ---
163
+
164
+ ## 3. VS Code F5 Session — Dart-Code 3.134.0 Analysis
165
+
166
+ VS Code was **not running** at observation time, so no live VS Code session could be captured. The following is derived from static analysis of the Dart-Code 3.134.0 extension bundle (`out/dist/extension.js`).
167
+
168
+ ### What Dart-Code does when you press F5
169
+
170
+ 1. Launches `flutter run --machine` as a child process via the Dart Debug Adapter (DAP).
171
+ 2. Listens for the `dart.debuggerUris` DAP event from the debug adapter, which carries:
172
+ - `body.vmServiceUri` — the DDS URI (already DDS-proxied, not raw VM)
173
+ - `body.clientVmServiceUri` — exposed URI for remote scenarios
174
+ - `body.observatoryUri` — legacy alias
175
+ 3. Stores these on the `DartDebugSession` object.
176
+ 4. Fires `onDebugSessionVmServiceAvailableEmitter` — this is the signal that a VM service is ready.
177
+
178
+ ### DTD (Dart Tooling Daemon) — the critical VS Code mechanism
179
+
180
+ Dart-Code 3.134.0 spawns its **own DTD** process:
181
+
182
+ ```
183
+ dart.exe tooling-daemon --machine [additionalArgs]
184
+ ```
185
+
186
+ The DTD prints one JSON line to stdout on startup:
187
+
188
+ ```json
189
+ {
190
+ "tooling_daemon_details": {
191
+ "uri": "ws://127.0.0.1:<port>/...",
192
+ "trusted_client_secret": "<secret>"
193
+ }
194
+ }
195
+ ```
196
+
197
+ Dart-Code reads this via `DartToolingDaemonProcess.processUnhandledMessage()` and resolves `dtdUriCompleter` with the URI. **This URI is never written to a file on disk by Dart-Code itself** — it lives only in memory in the extension host.
198
+
199
+ ### What Dart-Code registers on the DTD
200
+
201
+ Once the DTD is running, Dart-Code registers these JSON-RPC services on it:
202
+
203
+ | DTD Method | What it does |
204
+ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
205
+ | `ConnectedApp.registerVmService` | Called when a debug session's VM service becomes available — registers `{uri, name, exposedUri}` |
206
+ | `ConnectedApp.unregisterVmService` | Called when debug session stops |
207
+ | `ConnectedApp.getVmServices` | **QUERYABLE** — returns all currently registered VM services |
208
+ | `Editor.getDebugSessions` | Returns all active debug sessions with shape: `{id, name, debuggerType, flutterDeviceId, flutterMode, projectRootPath, vmServiceUri}` |
209
+ | `Editor.getActiveLocation` | Current cursor location |
210
+ | `Editor.hotReload` / `Editor.hotRestart` | Trigger reload on a session by `debugSessionId` |
211
+
212
+ ### `Editor.getDebugSessions` response shape
213
+
214
+ ```json
215
+ {
216
+ "type": "GetDebugSessionsResult",
217
+ "debugSessions": [
218
+ {
219
+ "id": "<vscode-debug-session-id>",
220
+ "name": "Launch development",
221
+ "debuggerType": "Flutter",
222
+ "flutterDeviceId": "chrome",
223
+ "flutterMode": "debug",
224
+ "projectRootPath": "D:\\projects\\my-flutter-app",
225
+ "vmServiceUri": "ws://127.0.0.1:<dds-port>/<token>/ws"
226
+ }
227
+ ]
228
+ }
229
+ ```
230
+
231
+ ### `dart.getActiveSessions` — DEBUNKED
232
+
233
+ The plan §7.1 mentioned `dart.getActiveSessions` as a VS Code LSP custom method. **This does not exist in Dart-Code 3.134.0.** Grep of the entire extension bundle found zero matches. The correct API is `Editor.getDebugSessions` called via DTD JSON-RPC, not via LSP.
234
+
235
+ ### How to access the DTD URI from an external tool
236
+
237
+ **Problem:** The DTD URI is only in the extension host's memory. Dart-Code does not write it to a file.
238
+
239
+ **Known workaround (observed in Dart-Code source):** The extension exposes a public API via `vscode.extensions.getExtension('Dart-Code.dart-code').exports`:
240
+
241
+ - `exports.dtdUri` — `Promise<string | undefined>` — resolves to the DTD URI when available
242
+ - `exports.onDtdUriChanged` — VS Code event emitter
243
+
244
+ This requires being a VS Code extension to call. An external MCP server cannot use this directly.
245
+
246
+ **Alternative:** The `DART_TOOL_DAEMON_URI` env var. Dart-Code injects this into terminals it opens (via VS Code's terminal environment variable injection API). An MCP server that is launched from such a terminal would inherit this. However:
247
+
248
+ - It is NOT set in terminals opened outside VS Code
249
+ - It is NOT set in processes launched by the MCP server itself unless the MCP server inherits it
250
+
251
+ **Process-scan fallback is most reliable for external tools** — dart tooling-daemon process will appear as `dart.exe tooling-daemon --machine` and its WS port is discoverable via netstat.
252
+
253
+ ### `.dart_code_tooling.json` — NOT FOUND
254
+
255
+ The plan mentioned `.vscode/.dart_code_tooling.json` as a possible file written by Dart-Code. This file does **not exist** in:
256
+
257
+ - `<project>/.vscode/`
258
+ - `D:\projects\devops-aggregate\.vscode\`
259
+ - `%APPDATA%\Code\`
260
+
261
+ After static analysis of Dart-Code 3.134.0: no code writes such a file. **The assumption was fabricated.** Dart-Code does not write a tooling JSON file to disk.
262
+
263
+ ### `DART_TOOL_DAEMON_URI` env var injection (not a file, an env var)
264
+
265
+ Dart-Code 3.134.0 injects `DART_TOOL_DAEMON_URI` into VS Code integrated terminals via `vscode.workspace.onDidOpenTerminal` + terminal environment variable injection. This is the primary mechanism for cooperating tools (like dart pub global executables) running inside VS Code terminals. External tools not launched from a VS Code terminal don't get this.
266
+
267
+ ---
268
+
269
+ ## 4. IntelliJ / Android Studio
270
+
271
+ **NOT INSTALLED** on this machine (Windows). Neither `%APPDATA%\JetBrains\` nor `%LOCALAPPDATA%\JetBrains\` exists. The IntelliJ Flutter plugin's session discovery mechanism is **UNVERIFIED — flagged for follow-up by Worker H in wave 3.**
272
+
273
+ ---
274
+
275
+ ## 5. Cross-OS Notes (UNVERIFIED — not empirically tested)
276
+
277
+ | Path | macOS (unverified) | Linux (unverified) |
278
+ | ------------------- | ------------------------------------- | ------------------------------- |
279
+ | VS Code user data | `~/Library/Application Support/Code/` | `~/.config/Code/` |
280
+ | VS Code extensions | `~/.vscode/extensions/` | `~/.vscode/extensions/` |
281
+ | Pub cache global | `~/.pub-cache/global_packages/` | `~/.pub-cache/global_packages/` |
282
+ | Flutter temp dir | `/tmp/flutter_tools.<hex>/` | `/tmp/flutter_tools.<hex>/` |
283
+ | DTD tooling env var | `DART_TOOL_DAEMON_URI` (same) | `DART_TOOL_DAEMON_URI` (same) |
284
+
285
+ Port mechanics and process structure are the same across OSes — DDS always uses `--bind-port=0` dynamic assignment, raw VM port 44456 redirect trick works identically.
286
+
287
+ ---
288
+
289
+ ## 6. What's Actually Findable on Disk
290
+
291
+ | Artifact | Path | Available? | Notes |
292
+ | ------------------------------ | -------------------------------------------------------- | ----------------------------- | ------------------------------------------------------------ |
293
+ | Raw VM port | `dartvm.exe --enable-vm-service=<port>` cmdline | YES (via process scan) | PID → port via WMI/netstat |
294
+ | DDS URI | HTTP GET raw VM port → redirect body | YES (probe raw port) | Returns `http://127.0.0.1:<dds-port>/<token>=` |
295
+ | DDS WS URI | `ws://127.0.0.1:<dds-port>/<token>=/ws` | YES (construct from redirect) | Just append `/ws` |
296
+ | Chrome CDP port | `chrome.exe --remote-debugging-port=<port>` cmdline | YES (via process scan) | Match by `--user-data-dir=...\flutter_tools_chrome_device.*` |
297
+ | Compiled app dill | `%TEMP%\flutter_tools.<hex>\flutter_tool.<hex>\app.dill` | YES | Only useful for debugging |
298
+ | DTD URI (VS Code) | Memory-only in extension host | NO (from external process) | Use process scan for `dart.exe tooling-daemon` instead |
299
+ | Session registry file | Any `*session*.json`, `*dtd*.json` | NO | Does not exist |
300
+ | `~/.dart-tool/...` (plan §7.1) | `~/.dart-tool/dart-services/dtd-info.json` etc. | NO — DEBUNKED | Fabricated paths, confirmed absent |
301
+ | `.dart_code_tooling.json` | `.vscode/.dart_code_tooling.json` | NO — DEBUNKED | Not written by Dart-Code 3.134.0 |
302
+
303
+ ---
304
+
305
+ ## 7. What's NOT Findable (Debunking Plan Assumptions)
306
+
307
+ These paths were referenced in earlier plan drafts and are now empirically confirmed as non-existent:
308
+
309
+ | Claimed path | Status |
310
+ | --------------------------------------------------- | ------------------------------------------------------------- |
311
+ | `~/.dart-tool/dart-services/dtd-info.json` | NOT FOUND — directory doesn't exist |
312
+ | `~/.dart-tool/dart-code/active-sessions.json` | NOT FOUND — directory doesn't exist |
313
+ | `~/.dart_tool/` (user home) | NOT FOUND |
314
+ | `<project>/.dart_tool/dartpad/info.json` | NOT FOUND — `.dart_tool/dartpad/` is EMPTY |
315
+ | `<project>/.dart_tool/chrome-device/<session>.json` | NOT FOUND — chrome-device/ is EMPTY |
316
+ | `.vscode/.dart_code_tooling.json` | NOT FOUND — Dart-Code 3.134.0 never writes this |
317
+ | `dart.getActiveSessions` (LSP method) | NOT FOUND in Dart-Code 3.134.0 source |
318
+ | Port range "8181-8200" for VM service | DEBUNKED — observed port 44456; DDS on 50639. No fixed range. |
319
+
320
+ ---
321
+
322
+ ## 8. Recommended Discovery Ladder (Concrete Sequence, Windows-First)
323
+
324
+ Based on empirical observation:
325
+
326
+ ### Strategy S1: CLI arg `--vm-uri` (explicit)
327
+
328
+ User passes URI directly. Return immediately. Most reliable.
329
+
330
+ ### Strategy S2: Process scan + raw VM port redirect trick (BEST FALLBACK)
331
+
332
+ ```typescript
333
+ // Step 1: Find dartvm.exe processes with --enable-vm-service in cmdline
334
+ // Windows: WMI Win32_Process query
335
+ // macOS/Linux: ps aux | grep 'enable-vm-service'
336
+ const dartVmProcs = await getProcessesWithCmdlineMatch(/--enable-vm-service=(\d+)/);
337
+
338
+ // Step 2: For each, extract raw VM port from cmdline flag
339
+ for (const proc of dartVmProcs) {
340
+ const port = proc.cmdline.match(/--enable-vm-service=(\d+)/)?.[1];
341
+
342
+ // Step 3: HTTP GET the raw VM port — DDS redirect gives us the real URI
343
+ const resp = await fetch(`http://127.0.0.1:${port}/${token}/`);
344
+ // Response body (even on "error") contains:
345
+ // "Cannot connect directly ... DDS at http://127.0.0.1:<dds-port>/<dds-token>=/"
346
+ const ddsUri = extractDdsUriFromRedirectBody(resp.body);
347
+
348
+ // Step 4: Construct WS URI: http → ws, append /ws
349
+ const wsUri = ddsUri.replace('http://', 'ws://').replace(/\/?$/, '/ws');
350
+
351
+ // Step 5: Verify with getVM RPC
352
+ const vm = await vmServiceCall(wsUri, 'getVM');
353
+ if (vm) yield { uri: wsUri, source: 'process-scan', pid: proc.pid };
354
+ }
355
+ ```
356
+
357
+ **Token extraction from cmdline:** The raw VM URI token (`4hT1IFnQtjM=`) appears in the `dds_aot` process cmdline as `--vm-service-uri=http://127.0.0.1:<port>/<token>=`. It's also in the redirect response body. So you can get the full URI from either the `dds_aot` cmdline or the redirect response.
358
+
359
+ ### Strategy S3: DTD query via `ConnectedApp.getVmServices` (VS Code sessions)
360
+
361
+ When VS Code is running with Dart-Code:
362
+
363
+ 1. Find `dart.exe tooling-daemon --machine` process (distinct from `dartvm.exe`)
364
+ 2. Get its WS port via `Get-NetTCPConnection` (single listening port)
365
+ 3. Connect WS to `ws://127.0.0.1:<dtd-port>/`
366
+ 4. Send JSON-RPC: `{"jsonrpc":"2.0","id":1,"method":"ConnectedApp.getVmServices","params":{"secret":"<trusted_client_secret>"}}`
367
+ 5. Returns list of registered VM service URIs
368
+
369
+ **Problem:** `trusted_client_secret` is required. It's only printed once to DTD's stdout at startup, captured by Dart-Code extension host. External tools cannot get it from disk.
370
+
371
+ **Alternative — `Editor.getDebugSessions`:** Same DTD WS, but this method may not require the secret (needs verification). Returns `vmServiceUri` per session. Worth trying without secret first.
372
+
373
+ ### Strategy S4: `DART_TOOL_DAEMON_URI` env var
374
+
375
+ If the MCP server process inherits `DART_TOOL_DAEMON_URI` from a VS Code terminal:
376
+
377
+ ```typescript
378
+ const dtdUri = process.env.DART_TOOL_DAEMON_URI;
379
+ if (dtdUri) {
380
+ /* connect to DTD, call Editor.getDebugSessions */
381
+ }
382
+ ```
383
+
384
+ Only works for MCP servers launched from VS Code integrated terminal.
385
+
386
+ ### Strategy S5: MCP-spawned `flutter run --machine` stdout parse (most reliable for lifecycle-owned sessions)
387
+
388
+ ```typescript
389
+ // flutter run --machine emits machine-mode JSON events:
390
+ // {"event":"app.started","params":{"appId":"...","vmServiceUri":"ws://...","...":...}}
391
+ const proc = spawn('flutter', ['run', '--machine', '-d', 'chrome', ...]);
392
+ proc.stdout.on('data', (chunk) => {
393
+ for (const line of chunk.toString().split('\n')) {
394
+ const json = tryParse(line);
395
+ if (json?.event === 'app.started') {
396
+ yield { uri: json.params.vmServiceUri, source: 'machine-stdout' };
397
+ }
398
+ }
399
+ });
400
+ ```
401
+
402
+ ### Strategy S6: Return empty + user help
403
+
404
+ ```
405
+ No sessions found. Either:
406
+ 1. Pass --vm-uri <ws://...> explicitly
407
+ 2. Run launch_app to have flutter-ultra own the lifecycle
408
+ 3. Start flutter run with: flutter run -d chrome --enable-vm-service
409
+ ```
410
+
411
+ ---
412
+
413
+ ## 9. Chrome CDP Discovery (Bonus)
414
+
415
+ For tools that need Chrome CDP (playwright-equivalent):
416
+
417
+ ```powershell
418
+ # Find Chrome processes launched by flutter_tools (not the user's regular Chrome)
419
+ Get-CimInstance Win32_Process | Where-Object {
420
+ $_.Name -eq 'chrome.exe' -and
421
+ $_.CommandLine -match 'flutter_tools_chrome_device' -and
422
+ $_.CommandLine -match '--remote-debugging-port=(\d+)'
423
+ } | ForEach-Object {
424
+ $port = [regex]::Match($_.CommandLine, '--remote-debugging-port=(\d+)').Groups[1].Value
425
+ "CDP at http://localhost:$port"
426
+ }
427
+ ```
428
+
429
+ The `--user-data-dir` path contains `flutter_tools_chrome_device` as a discriminator — use this to distinguish flutter-launched Chrome from the user's regular Chrome browser.
430
+
431
+ ---
432
+
433
+ ## 10. Cleanup
434
+
435
+ No new `flutter run` processes were spawned during this investigation. The two pre-existing sessions (PIDs 83892/69232 and stale 66812 Chrome) were not killed — they belong to the user's ongoing work session. The `dds_aot` process (PID 53908) and `dartvm` (PID 72124) were observed but not modified.
@@ -0,0 +1,24 @@
1
+ # Counter App
2
+
3
+ Minimal Flutter counter demonstrating `ultra_flutter` binding integration.
4
+
5
+ Used as the primary E2E test fixture for the flutter-ultra-mcp plugin — all
6
+ platform-specific CI workflows drive this app to verify gesture, runtime, and
7
+ native automation servers.
8
+
9
+ ## Running
10
+
11
+ ```bash
12
+ flutter run -d chrome
13
+ ```
14
+
15
+ In debug mode the `UltraFlutterBinding` is automatically initialized, exposing
16
+ `ext.flutter.ultra.*` VM service extensions that the MCP servers connect to.
17
+
18
+ ## Widget Keys
19
+
20
+ | Key | Widget | Purpose |
21
+ |-----|--------|---------|
22
+ | `counter_value` | Text | Displays current count |
23
+ | `increment` | FAB | Increments counter |
24
+ | `decrement` | FAB | Decrements counter |
@@ -0,0 +1,23 @@
1
+ name: counter_app
2
+ description: Minimal counter app demonstrating ultra_flutter binding for MCP-driven E2E testing.
3
+ publish_to: none
4
+ version: 1.0.0
5
+
6
+ resolution: workspace
7
+
8
+ environment:
9
+ sdk: '>=3.6.0 <4.0.0'
10
+ flutter: '>=3.27.0'
11
+
12
+ dependencies:
13
+ flutter:
14
+ sdk: flutter
15
+ ultra_flutter:
16
+ path: ../../dart/ultra_flutter
17
+
18
+ dev_dependencies:
19
+ flutter_test:
20
+ sdk: flutter
21
+
22
+ flutter:
23
+ uses-material-design: true
@@ -0,0 +1,48 @@
1
+ # OIDC App
2
+
3
+ Flutter example demonstrating OIDC PKCE authorization code flow with a mock
4
+ identity provider, used to verify the flutter-ultra-browser MCP server's OAuth
5
+ interception and CCT (Custom Chrome Tab) OAuth solver on mobile.
6
+
7
+ ## Architecture
8
+
9
+ ```
10
+ [Flutter App] --launch--> [Browser: /authorize]
11
+ |
12
+ [Mock OIDC Server]
13
+ |
14
+ [302 → localhost:9981/callback]
15
+ |
16
+ [Flutter App] <--code----- [Local HTTP server]
17
+ ```
18
+
19
+ ## Running
20
+
21
+ 1. Start the mock OIDC server:
22
+ ```bash
23
+ dart run lib/mock_oidc_server.dart
24
+ ```
25
+
26
+ 2. Run the Flutter app:
27
+ ```bash
28
+ flutter run -d chrome
29
+ ```
30
+
31
+ 3. Click "Login with OIDC" — the browser server intercepts the redirect.
32
+
33
+ ## Widget Keys
34
+
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 |
43
+
44
+ ## CI Usage
45
+
46
+ The `ci-e2e-web.yml` workflow starts `mock_oidc_server.dart` as a background
47
+ process, then drives the app via Playwright to complete the full OAuth flow
48
+ end-to-end.
@@ -0,0 +1,24 @@
1
+ name: oidc_app
2
+ description: OIDC example app demonstrating browser-server OAuth flow with ultra_flutter binding.
3
+ publish_to: none
4
+ version: 1.0.0
5
+
6
+ resolution: workspace
7
+
8
+ environment:
9
+ sdk: '>=3.6.0 <4.0.0'
10
+ flutter: '>=3.27.0'
11
+
12
+ dependencies:
13
+ flutter:
14
+ sdk: flutter
15
+ ultra_flutter:
16
+ path: ../../dart/ultra_flutter
17
+ url_launcher: ^6.3.0
18
+
19
+ dev_dependencies:
20
+ flutter_test:
21
+ sdk: flutter
22
+
23
+ flutter:
24
+ uses-material-design: true
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@bdayadev/flutter-ultra-mcp",
3
+ "version": "0.0.0",
4
+ "description": "Flutter Ultra MCP plugin monorepo \u00e2\u20ac\u201d 8 MCP servers + ultra_flutter Dart packages + skills for Claude Code.",
5
+ "license": "Apache-2.0",
6
+ "homepage": "https://github.com/Bdaya-Dev/flutter-ultra-mcp",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/Bdaya-Dev/flutter-ultra-mcp.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/issues"
13
+ },
14
+ "engines": {
15
+ "node": ">=20"
16
+ },
17
+ "packageManager": "npm@10.9.0",
18
+ "workspaces": [
19
+ "packages/*",
20
+ "shared/*"
21
+ ],
22
+ "scripts": {
23
+ "build": "turbo run build",
24
+ "lint": "turbo run lint",
25
+ "test": "turbo run test",
26
+ "typecheck": "turbo run typecheck",
27
+ "clean": "turbo run clean && rimraf node_modules",
28
+ "format": "prettier --write \"**/*.{ts,tsx,js,json,md,yml,yaml}\"",
29
+ "format:check": "prettier --check \"**/*.{ts,tsx,js,json,md,yml,yaml}\"",
30
+ "changeset": "changeset",
31
+ "version": "changeset version",
32
+ "release": "turbo run build && changeset publish",
33
+ "prepare": "husky"
34
+ },
35
+ "devDependencies": {
36
+ "@changesets/cli": "^2.27.0",
37
+ "@commitlint/cli": "^19.0.0",
38
+ "@commitlint/config-conventional": "^19.0.0",
39
+ "@eslint/js": "^9.39.4",
40
+ "@types/node": "^22.0.0",
41
+ "eslint": "^9.0.0",
42
+ "eslint-config-prettier": "^10.1.8",
43
+ "husky": "^9.0.0",
44
+ "prettier": "^3.3.0",
45
+ "rimraf": "^6.0.0",
46
+ "turbo": "^2.3.0",
47
+ "typescript": "^5.6.0",
48
+ "typescript-eslint": "^8.59.3",
49
+ "vitest": "^3.2.4"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public",
53
+ "registry": "https://registry.npmjs.org"
54
+ },
55
+ "files": [
56
+ ".claude-plugin/",
57
+ ".mcp.json",
58
+ "skills/",
59
+ "packages/*/dist/",
60
+ "packages/*/package.json",
61
+ "packages/*/README.md",
62
+ "packages/*/sidecars/",
63
+ "shared/*/dist/",
64
+ "shared/*/package.json",
65
+ "shared/*/README.md",
66
+ "dart/*/lib/",
67
+ "dart/*/pubspec.yaml",
68
+ "dart/*/README.md",
69
+ "dart/*/CHANGELOG.md",
70
+ "dart/*/EXTENSIONS.md",
71
+ "docs/",
72
+ "examples/*/lib/",
73
+ "examples/*/pubspec.yaml",
74
+ "examples/*/web/",
75
+ "examples/*/README.md",
76
+ "README.md",
77
+ "LICENSE",
78
+ "CONTRIBUTING.md",
79
+ "SECURITY.md",
80
+ "CODE_OF_CONDUCT.md"
81
+ ]
82
+ }
@@ -0,0 +1,29 @@
1
+ # @flutter-ultra/flutter-ultra-browser
2
+
3
+ MCP server for **Playwright-driven browser automation**: navigate, click, fill, screenshot, console / network capture, OAuth redirect handling, and sandboxed Playwright scripts for Flutter web apps.
4
+
5
+ ## Tools
6
+
7
+ | Tool | Purpose |
8
+ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
+ | `launch_browser` / `close_browser` | Lifecycle of a single per-session browser instance |
10
+ | `new_context` / `new_tab` | Cookie/storage-isolated contexts; pages within a context |
11
+ | `navigate` | `page.goto(url)` with load wait |
12
+ | `intercept_redirect` / `wait_for_url` | Wait for navigation matching URL pattern; auth flows |
13
+ | `click` / `fill` / `press_key` | Interaction primitives by selector |
14
+ | `screenshot` | PNG screenshot of page or element (works on CanvasKit) |
15
+ | `console_logs` | One-shot read of recent console events |
16
+ | `start_console_capture` / `get_console_capture` / `stop_console_capture` | **rev-23** persistent buffer of `console.*` + `pageerror` + `crash`, survives navigation, captures Dart `print()` on Flutter web within 100ms (AC-Br4) |
17
+ | `network_requests` | Recent network events for a page |
18
+ | `evaluate_js` | Run JS expression in page context, return JSON-serialized value |
19
+ | `run_playwright_script` | **Sandboxed** Node `vm` execution of Playwright TS/JS with `page` / `context` / `browser` / `expect` / `console` / `fetch` exposed; **no** `process`/`require`/`import`; CPU + wall-time watchdog |
20
+ | `eval_playwright_recipe` | Run a named recipe from `${CLAUDE_PLUGIN_DATA}/recipes/*.ts` |
21
+ | `set_storage` / `get_storage` | Pre-seed / export cookies + localStorage |
22
+ | `link_to_flutter` | Associate this browser context with a Flutter sessionId (used by `/flutter:drive`) |
23
+
24
+ See plan §5.4 lines 596-660 for the full design, AC-Br1..AC-Br4 acceptance criteria, and `run_playwright_script` sandbox boundary rationale.
25
+
26
+ State files this server owns:
27
+
28
+ - `${FLUTTER_ULTRA_STATE_DIR}/browsers.json` — active browser instances and their `link_to_flutter` mappings (plan §4)
29
+ - `${FLUTTER_ULTRA_STATE_DIR}/captures/console-<captureId>.jsonl` — append-only console event buffer per active capture (rev-23, survives server restart)