@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,72 @@
1
+ {
2
+ "name": "@flutter-ultra/flutter-ultra-native-mobile",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "MCP server for native mobile overlays: Android UIAutomator via adb, iOS XCUITest via xcrun + go-ios. Solves Chrome Custom Tabs / SafariViewController OAuth via Playwright + deep-link intent dispatch.",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/tree/main/packages/flutter-ultra-native-mobile",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Bdaya-Dev/flutter-ultra-mcp.git",
11
+ "directory": "packages/flutter-ultra-native-mobile"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/issues"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "flutter-ultra",
19
+ "android",
20
+ "ios",
21
+ "adb",
22
+ "uiautomator",
23
+ "xcuitest",
24
+ "go-ios",
25
+ "oauth",
26
+ "chrome-custom-tabs"
27
+ ],
28
+ "type": "module",
29
+ "main": "dist/index.js",
30
+ "module": "dist/index.js",
31
+ "types": "dist/index.d.ts",
32
+ "bin": {
33
+ "flutter-ultra-native-mobile": "dist/bin.js"
34
+ },
35
+ "exports": {
36
+ ".": {
37
+ "types": "./dist/index.d.ts",
38
+ "import": "./dist/index.js"
39
+ }
40
+ },
41
+ "sideEffects": false,
42
+ "files": [
43
+ "dist",
44
+ "README.md"
45
+ ],
46
+ "scripts": {
47
+ "build": "tsc -b",
48
+ "lint": "eslint src",
49
+ "test": "vitest run",
50
+ "typecheck": "tsc -b --noEmit",
51
+ "clean": "rimraf dist .turbo *.tsbuildinfo"
52
+ },
53
+ "dependencies": {
54
+ "@flutter-ultra/mcp-runtime": "^0.0.1",
55
+ "@flutter-ultra/state-store": "^0.0.1",
56
+ "@modelcontextprotocol/sdk": "^1.29.0",
57
+ "fast-xml-parser": "^4.5.0",
58
+ "playwright-core": "^1.49.0",
59
+ "zod": "^3.23.8"
60
+ },
61
+ "devDependencies": {
62
+ "rimraf": "^6.0.0",
63
+ "typescript": "^5.6.0",
64
+ "vitest": "^2.1.0"
65
+ },
66
+ "engines": {
67
+ "node": ">=20"
68
+ },
69
+ "publishConfig": {
70
+ "access": "public"
71
+ }
72
+ }
@@ -0,0 +1,40 @@
1
+ # @flutter-ultra/flutter-ultra-patrol
2
+
3
+ MCP server orchestrating **Patrol E2E tests** across web, Android, iOS, and desktop. Wraps `patrol_cli` and bundles the [Bdaya patrol fork](https://github.com/Bdaya-Dev/patrol) as a submodule at `vendor/patrol/` so external contributors get the fork automatically with `git clone --recurse-submodules`.
4
+
5
+ ## Tool catalogue (13 tools per plan §17B.1)
6
+
7
+ | Tool | Purpose |
8
+ | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
9
+ | `list_tests` | Walk `integration_test/` + `patrol_test/`, return `[{file, testNames[], tags[]}]`. |
10
+ | `start_patrol_test` | MARATHON: spawn `patrol test ...`, return taskId immediately. |
11
+ | `poll_patrol_job` | Non-blocking status + rolling log tail for any marathon job. |
12
+ | `get_patrol_result` | Final structured `{passed, failed, skipped, durations, failures[]}` for a completed test job. |
13
+ | `cancel_patrol_job` | SIGTERM + SIGKILL grace period. Idempotent. |
14
+ | `start_patrol_develop` | MARATHON: warm `patrol develop` session for repeat runs. |
15
+ | `patrol_develop_run` | Dispatch named test inside the warm session (much faster than a fresh `patrol test`). |
16
+ | `patrol_hot_reload` | `r` / `R` to the develop session's stdin. |
17
+ | `take_patrol_screenshot` | CDP screenshot via the develop session (Bdaya `f26306f6`). |
18
+ | `start_patrol_recording` | Bdaya CDP-based GIF/webm recorder. |
19
+ | `stop_patrol_recording` | Finalize the active recording. |
20
+ | `get_patrol_browser_errors` | CDP-captured browser console errors (Bdaya `b591a390`). Defaults to warm session, falls back to most recent test job, or pass `taskId`. |
21
+ | `get_patrol_web_debugger_port` | Surfaces the CDP port the Bdaya fork prints at web target startup so Playwright / DevTools can co-attach. |
22
+
23
+ ## Environment contract (from plugin `.mcp.json`)
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). |
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`. |
31
+
32
+ ## Invocation strategy
33
+
34
+ For each call we pick (in order):
35
+
36
+ 1. `useRawCli: true` → skip wrapper detection.
37
+ 2. `./scripts/run_patrol_web.ps1` (Windows) or `./scripts/run_patrol_web.sh` (Unix) at the project root → use it. Some projects standardize on this wrapper to pre-apply env vars + flags.
38
+ 3. Otherwise spawn `dart run patrol_cli` from the project root, which resolves through `pubspec_overrides.yaml` to `vendor/patrol/packages/patrol_cli`.
39
+
40
+ Web invocations always set `--web-init-timeout 180000` by default (vs upstream's 60000 hardcode — see Bdaya fork PR #9 in `docs/UPSTREAM-PATROL-PRS.md`).
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@flutter-ultra/flutter-ultra-patrol",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "MCP server for orchestrating patrol_cli E2E tests (web + Android + iOS) using the bundled Bdaya patrol fork.",
6
+ "license": "Apache-2.0",
7
+ "type": "module",
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "bin": {
11
+ "flutter-ultra-patrol": "dist/bin.js"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc -b",
19
+ "lint": "eslint src",
20
+ "test": "vitest run",
21
+ "test:watch": "vitest",
22
+ "typecheck": "tsc -b --noEmit",
23
+ "clean": "rimraf dist .turbo *.tsbuildinfo"
24
+ },
25
+ "dependencies": {
26
+ "@modelcontextprotocol/sdk": "^1.29.0",
27
+ "zod": "^3.23.8"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.0.0",
31
+ "rimraf": "^6.0.0",
32
+ "typescript": "^5.6.0",
33
+ "vitest": "^2.1.0"
34
+ },
35
+ "engines": {
36
+ "node": ">=20"
37
+ }
38
+ }
@@ -0,0 +1,63 @@
1
+ # @flutter-ultra/flutter-ultra-runtime
2
+
3
+ MCP server for Flutter **runtime control**: discover + attach to `flutter run`
4
+ debug sessions over DDS, introspect the widget tree (read-only), hot
5
+ reload/restart, evaluate Dart, capture HTTP/gRPC traffic, tail logs.
6
+
7
+ Part of the [flutter-ultra-mcp](https://github.com/Bdaya-Dev/flutter-ultra-mcp)
8
+ plugin. See plan §5.2 for the full catalogue.
9
+
10
+ ## Tools (28)
11
+
12
+ | Group | Tools |
13
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
14
+ | Discovery + lifecycle | `discover_sessions`, `attach`, `detach`, `list_sessions`, `launch_app`, `poll_launch_app`, `stop_app`, `hot_reload`, `hot_restart` |
15
+ | Inspection (read-only) | `get_widget_tree`, `get_widget_details`, `get_selected_widget`, `set_selected_widget`, `widget_exists` (rev 23), `find_widget` (rev 23), `count_widget_tree_nodes`, `screenshot`, `dump_render_tree`, `dump_layer_tree`, `dump_semantics_tree`, `evaluate` |
16
+ | Toggles | `toggle_debug_paint`, `toggle_perf_overlay`, `set_time_dilation`, `set_platform_override` |
17
+ | Logs | `get_logs`, `start_tail_logs`, `poll_tail_logs`, `stop_tail_logs`, `get_runtime_errors`, `log_buffer_stats` |
18
+ | HTTP / gRPC capture | `start_http_capture`, `get_http_events`, `stop_http_capture`, `decode_grpc_message` |
19
+
20
+ All inspect tools are read-only side-effect-free; `widget_exists` / `find_widget`
21
+ walk `ext.flutter.inspector.getRootWidgetSummaryTree` per AC-R5.
22
+
23
+ ## Session model
24
+
25
+ Sessions persist to `${CLAUDE_PLUGIN_DATA}/state/sessions.json` so the
26
+ gesture, devtools, and patrol servers can read the WS URI without IPC.
27
+ This server is the sole writer. Each session is a `VmServiceClient`
28
+ behind a reference-counted `SessionResource` — parallel tool calls share
29
+ one WebSocket per plan §17.10.
30
+
31
+ DDS multi-client coexistence with VS Code's Dart debugger is automatic;
32
+ our connection sets `setClientName('flutter-ultra/runtime/<pid>')` per
33
+ plan §7.2.
34
+
35
+ ## Discovery ladder
36
+
37
+ Implemented per worker-P's empirical report
38
+ ([`docs/discovery-empirics.md`](../../docs/discovery-empirics.md)):
39
+
40
+ 1. Process scan for `dart` / `flutter` / `dartvm` / `chrome` with
41
+ `--enable-vm-service=<port>` in cmdline.
42
+ 2. HTTP GET the raw VM port — the body redirects us to the DDS URI.
43
+ 3. Convert `http://...` → `ws://.../ws`.
44
+ 4. Probe `getVM` to confirm the URI is alive before returning.
45
+
46
+ ## Acceptance criteria covered
47
+
48
+ - **AC-R1**: `hot_reload` completes < 5 s; `get_widget_tree` returns the
49
+ post-reload tree without re-attach.
50
+ - **AC-R2**: WS drop triggers exp-backoff reconnect inside
51
+ `@flutter-ultra/vm-service-client` (0.5/1/2/4/8/14.5 s).
52
+ - **AC-R3**: Per-session `SessionResource<VmServiceClient>` keeps two
53
+ attached sessions strictly isolated.
54
+ - **AC-R4**: `screenshot` returns a PNG ≥ 200 bytes.
55
+ - **AC-R5 (rev 23)**: `widget_exists({kind:'key', value:'X'})` returns
56
+ `{exists, count, bounds?}` in < 300 ms on a 500-node tree without
57
+ triggering setState / hot-reload / route navigation side effects
58
+ (verified via the summary tree extension which is explicitly
59
+ side-effect-free).
60
+
61
+ ## License
62
+
63
+ Apache-2.0.
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@flutter-ultra/flutter-ultra-runtime",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "MCP server for Flutter runtime: discover + attach to flutter run sessions over DDS, introspect VM Service, hot reload, screenshots, HTTP/gRPC capture.",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/tree/main/packages/flutter-ultra-runtime",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Bdaya-Dev/flutter-ultra-mcp.git",
11
+ "directory": "packages/flutter-ultra-runtime"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/issues"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "flutter",
19
+ "dart",
20
+ "vm-service",
21
+ "dds",
22
+ "hot-reload"
23
+ ],
24
+ "type": "module",
25
+ "main": "dist/index.js",
26
+ "module": "dist/index.js",
27
+ "types": "dist/index.d.ts",
28
+ "bin": {
29
+ "flutter-ultra-runtime": "dist/bin.js"
30
+ },
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.js"
35
+ }
36
+ },
37
+ "sideEffects": false,
38
+ "files": [
39
+ "dist",
40
+ "README.md"
41
+ ],
42
+ "scripts": {
43
+ "build": "tsc -b",
44
+ "lint": "eslint src",
45
+ "test": "vitest run",
46
+ "typecheck": "tsc -b --noEmit",
47
+ "clean": "rimraf dist .turbo *.tsbuildinfo"
48
+ },
49
+ "dependencies": {
50
+ "@flutter-ultra/device-router": "^0.0.1",
51
+ "@flutter-ultra/mcp-runtime": "^0.0.1",
52
+ "@flutter-ultra/state-store": "^0.0.1",
53
+ "@flutter-ultra/vm-service-client": "^0.0.1",
54
+ "@modelcontextprotocol/sdk": "^1.29.0",
55
+ "protobufjs": "^7.4.0",
56
+ "zod": "^3.23.8"
57
+ },
58
+ "devDependencies": {
59
+ "rimraf": "^6.0.0",
60
+ "typescript": "^5.6.0",
61
+ "vitest": "^2.1.0"
62
+ },
63
+ "engines": {
64
+ "node": ">=20"
65
+ },
66
+ "publishConfig": {
67
+ "access": "public"
68
+ }
69
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@flutter-ultra/contracts",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "JSON Schema contract definitions for ext.flutter.ultra.* wire format — single source of truth for TS↔Dart interop.",
6
+ "license": "Apache-2.0",
7
+ "type": "module",
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "files": [
11
+ "dist",
12
+ "ext-flutter-ultra",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc -b",
17
+ "lint": "eslint src",
18
+ "test": "vitest run",
19
+ "test:contract": "vitest run",
20
+ "typecheck": "tsc -b --noEmit",
21
+ "clean": "rimraf dist .turbo *.tsbuildinfo"
22
+ },
23
+ "dependencies": {
24
+ "ajv": "^8.20.0",
25
+ "ajv-formats": "^3.0.1",
26
+ "zod": "^3.24.0"
27
+ },
28
+ "devDependencies": {
29
+ "vitest": "^3.2.4"
30
+ }
31
+ }
@@ -0,0 +1,51 @@
1
+ # @flutter-ultra/device-router
2
+
3
+ Device abstraction for flutter-ultra-mcp: run commands on local, WSL, or SSH-remote targets from a single interface.
4
+
5
+ ## Usage
6
+
7
+ ```typescript
8
+ import { DeviceRouter } from '@flutter-ultra/device-router';
9
+
10
+ const router = new DeviceRouter();
11
+
12
+ // List available devices (local + WSL distros + SSH hosts)
13
+ const devices = await router.listAvailable();
14
+
15
+ // Connect to a WSL distro
16
+ const { device, probe } = await router.connect({ kind: 'wsl', distro: 'Ubuntu-22.04' });
17
+
18
+ // Run a command on the device
19
+ const result = await device.exec(['flutter', 'build', 'linux', '--release']);
20
+
21
+ // Forward a TCP port from the remote device to local
22
+ const fwd = await device.forwardTcpPort('localhost', 8080);
23
+ console.log(`VM service available at ws://localhost:${fwd.localPort}/ws`);
24
+
25
+ // Clean up
26
+ await fwd.close();
27
+ await router.disconnect(device.id);
28
+ ```
29
+
30
+ ## Device types
31
+
32
+ | Kind | Transport | Platform | Use case |
33
+ | ------- | --------------------- | ----------- | --------------------------------------- |
34
+ | `local` | `child_process` | Host OS | Default — same machine |
35
+ | `wsl` | `wsl.exe -d <distro>` | Linux | Flutter Linux builds/tests from Windows |
36
+ | `ssh` | SSH ControlMaster | Linux/macOS | Flutter macOS builds via remote Mac |
37
+
38
+ ## Legacy adapter
39
+
40
+ Existing code using worker-J's v1 Device shape (`label/isLocal/exec/uploadFile/fileExists/openRpcStream`) can use the `LegacyDeviceAdapter`:
41
+
42
+ ```typescript
43
+ import { LegacyDeviceAdapter } from '@flutter-ultra/device-router';
44
+
45
+ const legacy = new LegacyDeviceAdapter(device);
46
+ // legacy.label, legacy.isLocal, legacy.exec(), legacy.fileExists(), legacy.openRpcStream()
47
+ ```
48
+
49
+ ## License
50
+
51
+ Apache-2.0
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@flutter-ultra/device-router",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "Device abstraction for flutter-ultra-mcp: run commands on local, WSL, or SSH-remote targets from a single interface.",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/tree/main/shared/device-router",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Bdaya-Dev/flutter-ultra-mcp.git",
11
+ "directory": "shared/device-router"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/issues"
15
+ },
16
+ "keywords": [
17
+ "flutter",
18
+ "mcp",
19
+ "device",
20
+ "wsl",
21
+ "ssh",
22
+ "remote"
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
+ "execa": "^9.5.1",
48
+ "ssh-config": "^5.0.0",
49
+ "zod": "^3.25.76"
50
+ },
51
+ "devDependencies": {
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,7 @@
1
+ # @flutter-ultra/keyring
2
+
3
+ OS-keyring-backed secret storage for plugin-managed credentials: signing certs, OIDC tokens, Sentry DSNs.
4
+
5
+ **Status:** scaffold stub. Implementation owner: shared infra (wave 2).
6
+
7
+ Cross-platform via native APIs — Windows Credential Manager, macOS Keychain, Linux Secret Service. Plain-filesystem fallback is intentionally absent to preserve the plan §19 security guarantee.
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@flutter-ultra/keyring",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "OS-keyring-backed secret storage for plugin-managed credentials (signing certs, OIDC tokens, Sentry DSNs).",
6
+ "license": "Apache-2.0",
7
+ "type": "module",
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc -b",
16
+ "lint": "eslint src",
17
+ "test": "vitest run",
18
+ "typecheck": "tsc -b --noEmit",
19
+ "clean": "rimraf dist .turbo *.tsbuildinfo"
20
+ },
21
+ "dependencies": {
22
+ "@napi-rs/keyring": "^1.3.0"
23
+ }
24
+ }
@@ -0,0 +1,116 @@
1
+ # @flutter-ultra/mcp-runtime
2
+
3
+ Shared MCP server scaffolding for the flutter-ultra-mcp plugin's 8 servers.
4
+ Encapsulates the recurring patterns — stdio transport boot, Zod-validated
5
+ tools, watchdog/timeout enforcement, keep-alive against
6
+ [Claude Code #58004](https://github.com/anthropics/claude-code/issues/58004),
7
+ the cross-server session model, and the canonical FinderSpec for widget
8
+ lookups — so each server's `src/index.ts` stays focused on its tool catalogue.
9
+
10
+ ## Quick start
11
+
12
+ ```ts
13
+ import { createServer } from '@flutter-ultra/mcp-runtime';
14
+ import { z } from 'zod';
15
+
16
+ const server = createServer({
17
+ info: { name: 'flutter-ultra-runtime', version: '0.0.1' },
18
+ });
19
+
20
+ server.defineTool(
21
+ {
22
+ name: 'list_sessions',
23
+ description: 'List active Flutter sessions attached by this server.',
24
+ timeoutClass: 'instant',
25
+ annotations: { readOnlyHint: true, idempotentHint: true },
26
+ },
27
+ async () => ({
28
+ sessions: [
29
+ /* ... */
30
+ ],
31
+ }),
32
+ );
33
+
34
+ server.defineTool(
35
+ {
36
+ name: 'hot_reload',
37
+ description: 'Trigger a hot reload on the given session.',
38
+ inputShape: { sessionId: z.string().min(8) },
39
+ timeoutClass: 'quick',
40
+ ceilingMs: 60_000,
41
+ },
42
+ async ({ sessionId }, { signal, sendProgress }) => {
43
+ sendProgress({ progress: 0, message: 'Sending reloadSources to VM service' });
44
+ // ... handler body with signal-aware aborts
45
+ return { ok: true, sessionId };
46
+ },
47
+ );
48
+
49
+ await server.start();
50
+ process.on('SIGTERM', () => server.stop());
51
+ ```
52
+
53
+ ## Components
54
+
55
+ | Module | Exports |
56
+ | -------------- | ------------------------------------------------------------------------------------------------------ |
57
+ | `server.ts` | `createServer`, `defineTool` — high-level builder over `@modelcontextprotocol/sdk` |
58
+ | `watchdog.ts` | `runWithWatchdog`, `TimeoutClass`, `DEFAULT_CEILINGS_MS` — per-tool hard cap + AbortSignal propagation |
59
+ | `keepAlive.ts` | `startKeepAlive` — periodic `notifications/message` debug ping (plan §17.9) |
60
+ | `logger.ts` | `createLogger` — JSON-lines stderr logger with per-tool child loggers |
61
+ | `session.ts` | `Session`, `SessionResource`, `SessionsFile` — cross-server session model |
62
+ | `finder.ts` | `FinderSchema`, `FinderSpec`, `matchesText` — shared discriminated union for widget lookups |
63
+ | `errors.ts` | `ToolWatchdogTimeoutError`, `SessionNotFoundError`, etc. |
64
+
65
+ ## Timeout classes (plan §17.2)
66
+
67
+ | Class | Ceiling | When to use |
68
+ | ---------- | ------- | ------------------------------------------------------------------ |
69
+ | `instant` | 10 s | < 1 s p95: `list_sessions`, `get_widget_tree` on small trees |
70
+ | `quick` | 30 s | 1–5 s p95: `hot_reload`, `screenshot`, `tap` |
71
+ | `long` | 55 s | 5–55 s p95: `dump_render_tree`, `wait_for` (always emit progress) |
72
+ | `marathon` | 55 s | > 55 s: MUST be split-tool (`start_*` / `poll_*` / `get_*_result`) |
73
+
74
+ Per-tool override via env var: `FLUTTER_ULTRA_TOOL_TIMEOUT_<NAME_UPPER>=120000`.
75
+
76
+ ## Session model
77
+
78
+ Sessions live as JSON in `${CLAUDE_PLUGIN_DATA}/state/sessions.json` (path
79
+ resolved by `@flutter-ultra/state-store`). The runtime server is the sole
80
+ writer; gesture / devtools / patrol read-only. Each session carries:
81
+
82
+ ```
83
+ { id, uri, source, clientName, attachedAt, lastSeenAt,
84
+ status, pid?, projectRoot?, device?, isolateIds?, appName? }
85
+ ```
86
+
87
+ `SessionResource<T>` reference-counts an expensive per-session resource
88
+ (e.g. the `VmServiceClient` WebSocket) so multiple parallel tool calls
89
+ share one connection per plan §17.10.
90
+
91
+ ## FinderSpec
92
+
93
+ Discriminated union used by both runtime (`widget_exists`, `find_widget`)
94
+ and gesture (`tap`, `enter_text`, `wait_for`) so an agent's "is the widget
95
+ in the tree?" check uses the exact same matcher as the subsequent tap:
96
+
97
+ ```ts
98
+ type FinderSpec =
99
+ | { kind: 'key'; value: string }
100
+ | {
101
+ kind: 'text';
102
+ value: string;
103
+ matchType?: 'exact' | 'contains' | 'regex';
104
+ caseInsensitive?: boolean;
105
+ }
106
+ | { kind: 'type'; value: string }
107
+ | { kind: 'coords'; x: number; y: number }
108
+ | { kind: 'semanticsLabel'; value: string; matchType?: 'exact' | 'contains' | 'regex' }
109
+ | { kind: 'tooltip'; value: string; matchType?: 'exact' | 'contains' | 'regex' };
110
+ ```
111
+
112
+ `matchesText(candidate, spec)` is the shared comparator both consumers use.
113
+
114
+ ## License
115
+
116
+ Apache-2.0. See [LICENSE](../../LICENSE).
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@flutter-ultra/mcp-runtime",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "Shared MCP server scaffolding: stdio transport, watchdog/timeout, structured logging, session model, finder spec.",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/tree/main/shared/mcp-runtime",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Bdaya-Dev/flutter-ultra-mcp.git",
11
+ "directory": "shared/mcp-runtime"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Bdaya-Dev/flutter-ultra-mcp/issues"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "model-context-protocol",
19
+ "flutter-ultra"
20
+ ],
21
+ "type": "module",
22
+ "main": "dist/index.js",
23
+ "module": "dist/index.js",
24
+ "types": "dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/index.js"
29
+ }
30
+ },
31
+ "sideEffects": false,
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsc -b",
38
+ "lint": "eslint src",
39
+ "test": "vitest run",
40
+ "typecheck": "tsc -b --noEmit",
41
+ "clean": "rimraf dist .turbo *.tsbuildinfo"
42
+ },
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.29.0",
45
+ "zod": "^3.23.8"
46
+ },
47
+ "devDependencies": {
48
+ "rimraf": "^6.0.0",
49
+ "typescript": "^5.6.0",
50
+ "vitest": "^2.1.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=20"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ }
58
+ }