@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,66 @@
1
+ # @flutter-ultra/state-store
2
+
3
+ File-based IPC for the flutter-ultra-mcp plugin's 8 servers. Atomic
4
+ read-modify-write of JSON state files via [`proper-lockfile`](https://www.npmjs.com/package/proper-lockfile),
5
+ plus an append-only JSONL writer for streams (log tails, screencast frames).
6
+
7
+ ## Why files, not a daemon
8
+
9
+ Each MCP server is a separate process spawned by Claude Code. A daemon would
10
+ add another moving part with its own failure surface; the file model means:
11
+
12
+ - **No bootstrap order**: servers start independently.
13
+ - **Survives restarts**: state persists when a single server crashes and is
14
+ re-spawned.
15
+ - **Cross-tool inspection**: `cat ${CLAUDE_PLUGIN_DATA}/state/sessions.json`
16
+ works as a debugging primitive.
17
+
18
+ ## Storage layout
19
+
20
+ ```
21
+ ${CLAUDE_PLUGIN_DATA}/state/
22
+ sessions.json ← runtime server writes, others read
23
+ jobs/<jobId>.json ← split-tool job state (build_runner_build, etc.)
24
+ streams/<streamId>.jsonl ← append-only event streams (tail_logs, etc.)
25
+ locks/ ← proper-lockfile metadata
26
+ ```
27
+
28
+ `CLAUDE_PLUGIN_DATA` is set by Claude Code; otherwise we fall back to
29
+ `%LOCALAPPDATA%/flutter-ultra-mcp` (Windows),
30
+ `~/Library/Application Support/flutter-ultra-mcp` (macOS),
31
+ `$XDG_DATA_HOME/flutter-ultra-mcp` (Linux).
32
+
33
+ ## API
34
+
35
+ ```ts
36
+ import { stateUpdate, stateRead, sessionsFilePath } from '@flutter-ultra/state-store';
37
+ import { SessionsFileSchema, emptySessionsFile } from '@flutter-ultra/mcp-runtime';
38
+
39
+ // Read with default fallback
40
+ const file = await stateRead(sessionsFilePath(), emptySessionsFile(), SessionsFileSchema);
41
+
42
+ // Lock-guarded mutation
43
+ await stateUpdate(sessionsFilePath(), emptySessionsFile(), SessionsFileSchema, (current) => ({
44
+ ...current,
45
+ sessions: [...current.sessions, newSession],
46
+ }));
47
+ ```
48
+
49
+ For continuous streams (log tails):
50
+
51
+ ```ts
52
+ import { appendJsonl, readJsonl, streamFilePath } from '@flutter-ultra/state-store';
53
+
54
+ await appendJsonl(
55
+ streamFilePath('s1'),
56
+ { ts: Date.now(), level: 'info', msg: '…' },
57
+ { maxLines: 10_000 },
58
+ );
59
+
60
+ // Reader polls with a cursor
61
+ const { entries, cursor } = await readJsonl(streamFilePath('s1'), (raw) => raw, /*afterCursor*/ 0);
62
+ ```
63
+
64
+ ## License
65
+
66
+ Apache-2.0. See [LICENSE](../../LICENSE).
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@flutter-ultra/state-store",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "File-based IPC for cross-server shared state. Atomic read-modify-write via proper-lockfile.",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/tree/main/shared/state-store",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Bdaya-Dev/flutter-ultra-mcp.git",
11
+ "directory": "shared/state-store"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/issues"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "flutter-ultra",
19
+ "ipc",
20
+ "state"
21
+ ],
22
+ "type": "module",
23
+ "main": "dist/index.js",
24
+ "module": "dist/index.js",
25
+ "types": "dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ }
31
+ },
32
+ "sideEffects": false,
33
+ "files": [
34
+ "dist",
35
+ "README.md"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsc -b",
39
+ "lint": "eslint src",
40
+ "test": "vitest run",
41
+ "typecheck": "tsc -b --noEmit",
42
+ "clean": "rimraf dist .turbo *.tsbuildinfo"
43
+ },
44
+ "dependencies": {
45
+ "proper-lockfile": "^4.1.2",
46
+ "zod": "^3.23.8"
47
+ },
48
+ "devDependencies": {
49
+ "@types/proper-lockfile": "^4.1.4",
50
+ "rimraf": "^6.0.0",
51
+ "typescript": "^5.6.0",
52
+ "vitest": "^2.1.0"
53
+ },
54
+ "engines": {
55
+ "node": ">=20"
56
+ },
57
+ "publishConfig": {
58
+ "access": "public"
59
+ }
60
+ }
@@ -0,0 +1,135 @@
1
+ # @flutter-ultra/vm-service-client
2
+
3
+ TypeScript Dart VM Service client with DDS multi-client coordination. Backs the
4
+ `flutter-ultra-runtime`, `flutter-ultra-gesture`, `flutter-ultra-devtools`, and
5
+ `flutter-ultra-patrol` MCP servers in the [flutter-ultra-mcp](https://github.com/Bdaya-Dev/flutter-ultra-mcp)
6
+ plugin.
7
+
8
+ Ports the subset of [`package:vm_service`](https://pub.dev/packages/vm_service)
9
+ those servers actually call (~15 methods) plus the two DDS extensions that make
10
+ coexistence with VS Code's Dart debugger safe.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @flutter-ultra/vm-service-client
16
+ ```
17
+
18
+ ## Quick start
19
+
20
+ ```ts
21
+ import { VmServiceClient } from '@flutter-ultra/vm-service-client';
22
+
23
+ const client = new VmServiceClient('ws://127.0.0.1:8181/abc/ws', {
24
+ // DDS multi-client identity. Format recommendation: flutter-ultra/<server>/<pid>
25
+ clientName: `flutter-ultra/runtime/${process.pid}`,
26
+ });
27
+
28
+ await client.connect();
29
+
30
+ const vm = await client.getVM();
31
+ console.log(`pid=${vm.pid} isolates=${vm.isolates.length}`);
32
+
33
+ await client.streamListen('Logging');
34
+ client.on('loggingEvent', (event) => {
35
+ console.log('log:', event);
36
+ });
37
+
38
+ await client.dispose();
39
+ ```
40
+
41
+ Connection target also accepts `{host, port, ws_path}`:
42
+
43
+ ```ts
44
+ const client = new VmServiceClient({ host: '127.0.0.1', port: 8181, ws_path: 'abc/ws' });
45
+ ```
46
+
47
+ ## Ported method surface
48
+
49
+ | Group | RPCs |
50
+ | ---------------- | ----------------------------------------------------------------------------- |
51
+ | Inspection | `getVM`, `getIsolate`, `getObject`, `getFlagList`, `getInstances`, `getStack` |
52
+ | Evaluation | `evaluate`, `evaluateInFrame`, `callServiceExtension` |
53
+ | Streams | `streamListen`, `streamCancel` |
54
+ | Execution | `pause`, `resume`, `setLibraryDebuggable` |
55
+ | DDS coordination | `setClientName`, `getStreamHistory` |
56
+
57
+ Plus typed event subscriptions:
58
+
59
+ - `client.on('isolateEvent' | 'extensionEvent' | 'loggingEvent' | 'stdoutEvent' | 'stderrEvent' | 'vmEvent' | 'debugEvent' | 'serviceEvent' | 'timelineEvent', (event) => …)`
60
+ - `for await (const event of client.onIsolateEvent()) { … }` (AsyncIterable)
61
+ - Catch-all: `client.on('event', (streamId, event) => …)`
62
+
63
+ ## DDS coexistence (plan §7.2)
64
+
65
+ The client is designed to share a DDS instance with VS Code's Dart debugger
66
+ without conflict. Two rules:
67
+
68
+ 1. Always set `clientName` to something unique-per-process. DDS uses the name
69
+ to identify cooperating clients for resume coordination.
70
+ 2. **Never** call `requirePermissionToResume(...)` — VS Code's debugger must
71
+ remain the sole resume authority. This client deliberately does NOT expose
72
+ that DDS RPC.
73
+
74
+ ## Polymorphic responses
75
+
76
+ `evaluate` and `evaluateInFrame` return one of three shapes — narrow on
77
+ `result.type`:
78
+
79
+ ```ts
80
+ const result = await client.evaluate(isolateId, targetId, 'someExpression');
81
+ switch (result.type) {
82
+ case '@Instance':
83
+ console.log('value =', result.valueAsString);
84
+ break;
85
+ case '@Error':
86
+ console.log('eval failed:', result.message);
87
+ break;
88
+ case 'Sentinel':
89
+ console.log('isolate state changed:', result.kind);
90
+ break;
91
+ }
92
+ ```
93
+
94
+ `getIsolate` / `getObject` throw `SentinelException` instead of returning a
95
+ sentinel union, since the caller almost always wants to re-discover and retry
96
+ rather than handle the sentinel inline.
97
+
98
+ ## Reconnect
99
+
100
+ Auto-reconnect is on by default with exponential backoff
101
+ (`[500, 1000, 2000, 4000, 8000, 14500] ms`). Tune via:
102
+
103
+ ```ts
104
+ new VmServiceClient(uri, {
105
+ autoReconnect: true,
106
+ reconnectDelaysMs: [500, 1_000, 2_000, 5_000],
107
+ });
108
+ ```
109
+
110
+ Pending in-flight requests reject with `ConnectionDisposedError` on disconnect;
111
+ listen for the `disconnect` event on the client (and the `reconnected` event
112
+ on `client.transport`) to drive a retry loop in your tool layer.
113
+
114
+ ## Error model
115
+
116
+ | Class | Thrown on |
117
+ | ------------------------- | --------------------------------------------------------------------------------------------- |
118
+ | `RpcError` | JSON-RPC error response (carries `code`, `message`, optional `data`, originating method name) |
119
+ | `SentinelException` | `getIsolate` / `getObject` got back a `Sentinel` instead of the requested type |
120
+ | `ConnectionDisposedError` | Transport closed before the request completed |
121
+ | `ConnectionTimeoutError` | WS connect or per-request timeout fired |
122
+
123
+ `RpcErrorCode` exports the documented VM service + DDS error codes
124
+ (`-32601` `MethodNotFound`, `106` `IsolateMustBePaused`, etc.).
125
+
126
+ ## Strict typing
127
+
128
+ All response shapes are validated at runtime via Zod (`.strict()` everywhere,
129
+ no `z.any()`/`z.record()` in the schema graph), then surfaced as inferred
130
+ TypeScript types. Schema drift in the VM service protocol fails loudly rather
131
+ than silently corrupting downstream consumers.
132
+
133
+ ## License
134
+
135
+ Apache-2.0. See [LICENSE](../../LICENSE).
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@flutter-ultra/vm-service-client",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "TypeScript Dart VM Service client with DDS multi-client coordination. Backs the runtime, gesture, devtools, and patrol MCP servers.",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/tree/main/shared/vm-service-client",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Bdaya-Dev/flutter-ultra-mcp.git",
11
+ "directory": "shared/vm-service-client"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/issues"
15
+ },
16
+ "keywords": [
17
+ "dart",
18
+ "flutter",
19
+ "vm-service",
20
+ "dds",
21
+ "debugger",
22
+ "mcp"
23
+ ],
24
+ "type": "module",
25
+ "main": "dist/index.js",
26
+ "module": "dist/index.js",
27
+ "types": "dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ }
33
+ },
34
+ "sideEffects": false,
35
+ "files": [
36
+ "dist",
37
+ "README.md"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsc -b",
41
+ "lint": "eslint src",
42
+ "test": "vitest run",
43
+ "typecheck": "tsc -b --noEmit",
44
+ "clean": "rimraf dist .turbo *.tsbuildinfo"
45
+ },
46
+ "dependencies": {
47
+ "ws": "^8.18.0",
48
+ "zod": "^3.23.8"
49
+ },
50
+ "devDependencies": {
51
+ "@types/ws": "^8.5.13",
52
+ "rimraf": "^6.0.0",
53
+ "typescript": "^5.6.0",
54
+ "vitest": "^2.1.0"
55
+ },
56
+ "engines": {
57
+ "node": ">=20"
58
+ },
59
+ "publishConfig": {
60
+ "access": "public"
61
+ }
62
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: _internal-on-tool-failure
3
+ description: Internal skill invoked by the PostToolUse hook when a flutter-ultra tool returns isError. Captures structured remediation context. Not for direct user invocation.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Internal: On Tool Failure (stub)
8
+
9
+ **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §12).
10
+
11
+ Triggered by the `PostToolUse` hook when an `mcp__flutter-ultra-*__*` tool returns `isError: true`. Reads the failure event from `state/tool-events.jsonl`, formats a one-line remediation summary, and appends it to the conversation as a system reminder.
12
+
13
+ Not advertised in the user-facing skill list.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: _internal-session-bootstrap
3
+ description: Internal skill invoked by the SessionStart hook to detect Flutter context and warm cached state. Not for direct user invocation.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Internal: Session Bootstrap (stub)
8
+
9
+ **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §12).
10
+
11
+ Triggered by the `SessionStart` hook. Performs:
12
+
13
+ - Project root detection (`pubspec.yaml` walk)
14
+ - Cached session discovery refresh
15
+ - Plugin-doctor self-check
16
+ - Initial telemetry frame written to `state/tool-events.jsonl`
17
+
18
+ Not advertised in the user-facing skill list.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: debug
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
+ ---
5
+
6
+ # Debug (stub)
7
+
8
+ **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §8.3, §12).
9
+
10
+ ## Workflow
11
+
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.
17
+
18
+ ## See also
19
+
20
+ - Plan §8.3
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: devtools
3
+ description: Wiring up the Flutter DevTools panel for this plugin so the user can see live MCP activity inside their IDE. Use when the user wants to inspect the plugin's recent tool calls, attached sessions, or activity timeline.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # DevTools (stub)
8
+
9
+ **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §8.6, §12).
10
+
11
+ User-triggered only — installing a dev dependency and editing pubspec is opinionated.
12
+
13
+ ## Workflow
14
+
15
+ - Detect `ultra_flutter_devtools` in `dev_dependencies`; add via `mcp__flutter-ultra-build__pub_add` if missing.
16
+ - Start the panel WebSocket via `mcp__flutter-ultra-devtools__start_panel_server`.
17
+ - Print the DevTools URL with the `flutter-ultra` tab anchor.
18
+
19
+ ## See also
20
+
21
+ - Plan §8.6, §6.2
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: drive
3
+ description: Driving multi-step user flows in a running Flutter app via gestures and assertions. Use when reproducing a bug across several screens, validating an onboarding flow, or running an ad-hoc end-to-end scenario without writing a patrol test.
4
+ ---
5
+
6
+ # Drive (stub)
7
+
8
+ **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §8.2, §12).
9
+
10
+ ## Workflow
11
+
12
+ - Enumerate interactive elements via `mcp__flutter-ultra-gesture__interactive_elements`.
13
+ - Tap or enter text using key-based finders.
14
+ - Verify intermediate state via `mcp__flutter-ultra-runtime__get_widget_tree`.
15
+ - For OAuth/popups: delegate to `mcp__flutter-ultra-browser__*` (web) or `mcp__flutter-ultra-native-mobile__*` (mobile).
16
+
17
+ ## See also
18
+
19
+ - Plan §8.2
20
+ - Sibling skill: `test` for orchestrated patrol runs
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: scaffold
3
+ description: Scaffolding new Flutter projects or features following the conventions detected in the existing codebase. Use when starting a fresh app, adding a feature module, or generating boilerplate that should match an existing project's structure.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Scaffold (stub)
8
+
9
+ **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §8.4, §12).
10
+
11
+ This skill is opinionated and destructive (creates files), so it is **not** auto-invocable. The user must trigger it explicitly with `/flutter:scaffold`.
12
+
13
+ ## Workflow
14
+
15
+ - Project mode: `flutter create` via shell with detected channel + org.
16
+ - Feature mode: read the existing structure via `mcp__flutter-ultra-build__project_info`, then create files that match.
17
+
18
+ ## See also
19
+
20
+ - Plan §8.4
21
+ - Sibling skill: `setup` for plugging the plugin into an existing codebase
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: setup
3
+ description: Bootstrapping flutter-ultra-mcp into an existing Flutter codebase end-to-end. Use when the user wants the plugin enabled for the first time on a project, or when re-running after a clean install. Idempotent.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Setup (stub)
8
+
9
+ **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §8.7, §12).
10
+
11
+ User-triggered only — patches pubspec, entry points, and `.vscode/launch.json`.
12
+
13
+ ## Workflow (target)
14
+
15
+ 1. Detect project layout via `mcp__flutter-ultra-build__project_info` (entry points, existing bindings, Sentry usage, patrol).
16
+ 2. Add `ultra_flutter` to `dev_dependencies`; if Sentry detected, show the direct `// ignore: implementation_imports` binding pattern.
17
+ 3. Patch entry point(s) with AST-aware edits to mix in `UltraFlutterBinding` under `kDebugMode`.
18
+ 4. Optional: add a launch.json profile pre-applying dart-defines for session discovery.
19
+ 5. Detect existing patrol setup and offer the `run_patrol_web` wrapper.
20
+ 6. Generate per-project `.flutter-ultra.config.yaml`.
21
+ 7. Run a smoke launch + screenshot + detach.
22
+ 8. Emit `SETUP-REPORT.md` at project root.
23
+
24
+ ## See also
25
+
26
+ - Plan §8.7
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: test
3
+ description: Orchestrating Flutter unit, widget, and patrol E2E tests with focused reporting. Use when the user asks to run tests, validate a fix, or check coverage on a Flutter project.
4
+ ---
5
+
6
+ # Test (stub)
7
+
8
+ **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §8.5, §12).
9
+
10
+ ## Workflow
11
+
12
+ - `mcp__flutter-ultra-build__analyze` first; fail fast on lint errors.
13
+ - `mcp__flutter-ultra-build__run_unit_tests` / `run_widget_tests` per the input pattern.
14
+ - `mcp__flutter-ultra-patrol__*` for E2E.
15
+ - Report failures with file:line + a screenshot snapshot when available.
16
+
17
+ ## See also
18
+
19
+ - Plan §8.5
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: tour
3
+ description: Running route-by-route screenshot tours of a Flutter app. Use when capturing visual state across many app routes, doing pre-release visual regression sweeps, or documenting a feature's UI for review.
4
+ ---
5
+
6
+ # Route Tour (stub)
7
+
8
+ **Status:** scaffold stub. Implementation owner: wave-3 skills worker (see plan §8.1, §12).
9
+
10
+ ## Quick start
11
+
12
+ 1. Identify the active session via `mcp__flutter-ultra-runtime__discover_sessions`.
13
+ 2. For each route in the input list:
14
+ - Navigate (web: browser navigate, mobile/desktop: GoRouter evaluate)
15
+ - Wait for the root widget key
16
+ - Take a screenshot, save to `.omc/research/tour-<date>/<route-slug>.png`
17
+ 3. Write `tour-report.md` summarizing route to screenshot mapping.
18
+
19
+ ## See also
20
+
21
+ - Plan §8.1
22
+ - Sibling skill: `drive` for multi-step interaction flows