feat: named server registry and --server flag for CLI commands#38
Open
vinifig wants to merge 6 commits intoai-dashboad:mainfrom
Open
feat: named server registry and --server flag for CLI commands#38vinifig wants to merge 6 commits intoai-dashboad:mainfrom
vinifig wants to merge 6 commits intoai-dashboad:mainfrom
Conversation
Introduces a TCP IPC layer so any MCP action can be invoked against a named, running server instance from plain CLI commands. New files: - lib/src/server_registry.dart — ServerRegistry + ServerEntry (reads/writes ~/.flutter_skill/servers/<id>.json) - lib/src/skill_server.dart — SkillServer: JSON-RPC 2.0 over TCP (+ optional Unix socket on macOS/Linux) - lib/src/skill_client.dart — SkillClient: resolves named servers and sends JSON-RPC requests - lib/src/cli/connect.dart — `flutter_skill connect --id=<name> [--port|--uri]` command - lib/src/cli/server_cmd.dart — `flutter_skill server list/stop/status` subcommands - lib/src/cli/output_format.dart — isCiEnvironment() + OutputFormat helpers Modified files: - lib/src/cli/launch.dart — adds --id=<name> and --detach flags; registers SkillServer on URI discovery - lib/src/cli/inspect.dart — adds --server=<id>[,<id2>,...] for parallel forwarding; --output flag - lib/src/cli/act.dart — adds --server=<id>[,<id2>,...] for parallel forwarding; --output flag - bin/flutter_skill.dart — routes `connect`, `servers`, and `server list/stop/status` to new handlers Usage examples: flutter_skill connect --id=myapp --port=50000 flutter_skill server list flutter_skill server stop --id=myapp flutter_skill tap "Login" --server=myapp flutter_skill screenshot --server=app-a,app-b # parallel
- CRITICAL-1: add shutdown case to _dispatch in skill_server.dart; move ServerRegistry.unregister into catch block only in server_cmd.dart - CRITICAL-2: replace Future.delayed park hack with Completer in connect.dart - CRITICAL-3: fix Windows _isPidAlive false-positive with word-boundary matching - MAJOR-1: add hot_restart and scroll_to cases to _dispatch; add phase-1 comment - MAJOR-2: fix _spawnDetachedServer to detect dart run context and construct correct invocation - MAJOR-3: fix scroll direction hardcoded to 'up'; split scroll/scroll_to RPC cases - MAJOR-4: deduplicate _parseServerIds -> parseServerIds in output_format.dart; extract ServerCallResult replacing _ActResult/_ServerResult - MAJOR-5: add ID validation in ServerRegistry.register to prevent path traversal - MINOR-1: add https -> wss normalization in connect.dart - MINOR-2: replace as dynamic with proper type check in _vmServiceUri - MINOR-3: rename stripOutputFlag to stripOutputFormatFlag (keep old name as shim) - NIT-1: remove _padRight wrapper in server_cmd.dart; use .padRight() directly - NIT-2: remove unused findFreePort from skill_server.dart
- CRITICAL-1: Add go_back case to _dispatch in skill_server.dart - CRITICAL-2: Fix scroll semantic mismatch in act.dart _buildRpcCall (scroll_to with key) - MAJOR-1: Add assert_visible, assert_gone, wait_for_element, get_text, find_element to _dispatch - MAJOR-2: Implement hot_restart with FlutterSkillClient.hotRestart() and hotReload fallback - MAJOR-3: Throw on null screenshot instead of silently returning null - MAJOR-4: Extract prune() from listAll() in server_registry.dart; update server_cmd.dart to call prune() before listing - MAJOR-5: Add ID validation (regex) to SkillClient.byId, ServerRegistry.get, ServerRegistry.unixSocketPath - MAJOR-6: Pass process to _attachServer in launch.dart; stop skill server when flutter run exits - MINOR-1: Replace _nextId instance field with local const 1 in SkillClient.call - MINOR-2: Add stopping guard in connect.dart doShutdown to prevent double-stop on concurrent signals - MINOR-3: Replace doc-comment deprecation with @deprecated annotation on stripOutputFlag - MINOR-4: Rename id to requestId in _handleLine to avoid shadowing the server id field - NIT-1: Extract callServersParallel helper into output_format.dart; refactor act.dart and inspect.dart to use it
- CRITICAL-1: scroll_to now calls FlutterSkillClient.scrollTo() with swipe fallback - CRITICAL-2: hotRestart throws UnsupportedError (was silently calling reloadSources) - HIGH-1: _buildRpcCall covers assert_visible/gone, wait_for_element, get_text, find_element, hot_reload, hot_restart - HIGH-2: multi-server screenshot derives per-server filenames via _deriveServerPath - HIGH-3: SkillServer exposes onShutdownRequested stream; shutdown case no longer calls exit(0); connect.dart listens to it for orderly cleanup - MEDIUM-1: _sendResult/_sendError catch socket write errors and destroy broken sockets - MEDIUM-2: StreamSubscription cancelled once response matched in skill_client.dart - MEDIUM-3: ServerRegistry.register rejects collision with a live (pid-alive) server - MEDIUM-4: flutter_skill ping subcommand added (ping_cmd.dart) with docs - LOW-1: URI normalisation in connect.dart uses Uri.parse to strip path before adding /ws - LOW-2: removed deprecated stripOutputFlag alias - LOW-3: launch.dart uses Platform.executable with .dart-script detection - LOW-4: _elementMatches static helper extracted; assert/wait/find cases use it
Author
|
@charliewwdev and @carlye0304 may you guys take a look please? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Idea
This PR introduces a named server registry to
flutter_skill, drawing inspiration from how the Playwright CLI handles browser server instances — where you can start a server independently and then target it by name/endpoint from any command or test. The same pattern is applied here: instead of each command needing to discover and connect to a Flutter VM Service URI on its own, you attach once (flutter_skill connect), give the session a name, and every subsequent command just passes--server=<name>.This makes
flutter_skillfeel more like a proper CLI tool for automation pipelines: stateless commands, named sessions, parallel execution across multiple apps.Changes
Adds a named server registry + TCP IPC layer so every MCP action can also be invoked as a plain CLI command targeting a named, running server instance.
New commands
flutter_skill connect --id=myapp --port=50000— attach to a running Flutter app and give it a persistent nameflutter_skill server list— table of all running named serversflutter_skill server stop --id=myapp— stop a named serverflutter_skill server status --id=myapp— show port, PID, project path, VM URIflutter_skill servers— shorthand forserver listflutter_skill ping --server=myapp— health check a named serverflutter_skill tap "Login" --server=myapp— run any action via a named serverflutter_skill screenshot --server=app-a,app-b— parallel execution across multiple serversArchitecture
lib/src/server_registry.dart~/.flutter_skill/servers/<id>.json; PID-alive filtering, collision guard, path-traversal validationlib/src/skill_server.dartlib/src/skill_client.dartlib/src/cli/connect.dartflutter_skill connectcommandlib/src/cli/server_cmd.dartflutter_skill server list/stop/statuslib/src/cli/ping_cmd.dartflutter_skill pingcommandlib/src/cli/output_format.dartisCiEnvironment()helper;--output=json|humanflag;callServersParallel()Modified files (additive only — no breaking changes)
lib/src/cli/launch.dart— new--id=<name>and--detachflags; auto-registers a SkillServer when the VM URI is discoveredlib/src/cli/inspect.dart— new--server=<id>[,...]flag for parallel forwarding;--outputflaglib/src/cli/act.dart— same--serverpattern for all act subcommandsbin/flutter_skill.dart— routes new commands while keepingserveralone as the MCP serverCI output
When
CI,GITHUB_ACTIONS,CIRCLECI,TRAVIS, orBUILDKITEenv vars are set, output defaults to JSON. Always overridable with--output=jsonor--output=human.Reference
The full development history, code review rounds, and discussion are in vinifig#1.
Test plan
flutter_skill connect --id=myapp --port=50000registers entry in~/.flutter_skill/servers/myapp.jsonflutter_skill server listshows the registered serverflutter_skill tap "Submit" --server=myappforwards tap to the named serverflutter_skill screenshot --server=a,bruns in parallel and writesscreenshot_a.png/screenshot_b.pngflutter_skill server stop --id=myappremoves the registry entry and stops the server processflutter_skill ping --server=myappexits 0 when reachable, 1 when notlaunch,inspect,actwithout--server) behave identically to beforedart test test/server_registry_test.dart test/skill_server_client_test.dart