Skip to content

fix(hot-reload): drive Flutter Tools' reloadSources/hotRestart VM services so hot_reload/hot_restart actually apply changes - #58

Merged
charliewwdev merged 1 commit into
ai-dashboad:mainfrom
pierre-cheneau:fix/hot-reload-via-flutter-tools-services
Aug 21, 2026
Merged

fix(hot-reload): drive Flutter Tools' reloadSources/hotRestart VM services so hot_reload/hot_restart actually apply changes#58
charliewwdev merged 1 commit into
ai-dashboad:mainfrom
pierre-cheneau:fix/hot-reload-via-flutter-tools-services

Conversation

@pierre-cheneau

Copy link
Copy Markdown
Contributor

Problem

hot_reload / hot_restart report success but never apply source changes.

FlutterSkillClient.hotReload() calls the VM's raw reloadSources(isolateId).
A Flutter app embeds no kernel compiler, so the VM answers
ReloadReport{success:false, notices:["Error while starting Kernel isolate task"]};
the report is ignored and the tool returns "Hot reload triggered" while nothing
recompiled. hotRestart() is the same call (or throws UnsupportedError
claiming the VM Service cannot restart — it can, see below).

Fix

The flutter run process that launched the app owns the incremental compiler and
registers VM services reloadSources and hotRestart (alias "Flutter Tools",
callable as sN.reloadSources / sN.hotRestart, advertised on the Service
stream — the VM replays existing registrations on streamListen). That is exactly
what DevTools and the IDE plugins call.

  • FlutterSkillClient tracks those registrations (connect + reconnect) and
    hotReload/hotRestart invoke them → real recompile + reload + reassemble.
  • Without an attached tool (bare VM URI of a profile/release/detached app),
    hotReload falls back to the raw RPC and checks the report, surfacing a
    clear "launch the app with flutter run" error; hotRestart explains it needs
    the tool.
  • After a restart the main isolate is recreated: re-bind to the new isolate
    (id must differ — the old one may still be listed), then wait for
    ext.flutter.didSendFirstFrameEvent so the widget tree is populated for the
    caller's next call. (didSendFirstFrameRasterizedEvent never flips on Windows
    desktop; the value is a JSON bool.) _call also self-heals on a stale isolate
    (Sentinel: Collected), so a restart done from the terminal no longer breaks
    the session.
  • On Windows, hold until the wall-clock second rolls over before returning: Dart
    truncates file mtimes to whole seconds there, so flutter_tools'
    ProjectFileInvalidator ignores edits made in the same second as its last
    compile ("Compiling dart to kernel with 0 updated files"). Agents edit and
    reload back-to-back, so this hit every second call. (Reported upstream to
    Flutter separately.)
  • Responses now say what happened: Hot reload performed by Flutter Tools (330ms).

Verification

Minimal app showing a MARKER_Vn constant, launched with flutter run -d windows
(Flutter 3.44.9, Windows 10). Script drives the server over MCP stdio:
connect → edit → hot_reloadget_text_content → edit → hot_restart
get_text_content.

Server Result
0.9.34 release / HEAD 0/10 — text never changes, flutter run logs nothing
this PR 10/10 — Reloaded 1 of 756 libraries / Restarted application, every compile "1 updated files"

dart analyze clean on the touched files; no existing tests reference the old behaviour.

…vices

hot_reload called the VM's raw reloadSources RPC. A Flutter app embeds no
kernel compiler, so the VM answers success:false ("Error while starting
Kernel isolate task"); the report was ignored and the tool reported success
while nothing recompiled. hot_restart was the same call (or threw).

The flutter run process registers reloadSources/hotRestart as VM services
(alias "Flutter Tools") - what DevTools and IDEs call. The driver now
tracks registrations from the Service stream and invokes sN.reloadSources /
sN.hotRestart; without an attached tool it checks the ReloadReport and
surfaces a clear error instead of a fake success.

Also:
- re-bind to the new main isolate after a restart (old id -> Sentinel
  Collected on every later call) and self-heal on stale isolates
- wait for ext.flutter.didSendFirstFrameEvent so the tree is populated
- on Windows, hold until the wall-clock second rolls over: Dart truncates
  mtimes to seconds there, so the tool ignores edits made in the same
  second as its last compile ("0 updated files")
- report what happened: "Hot reload performed by Flutter Tools (330ms)"
@pierre-cheneau

Copy link
Copy Markdown
Contributor Author

The Windows mtime-granularity behaviour that motivates the _settleCompileClock wait is now reported upstream: flutter/flutter#191198 ("Hot reload/restart on Windows ignores files edited in the same second as the previous compile"). If Flutter fixes it in the tool, the guard here becomes a harmless ≤1 s wait that can be dropped for SDKs that carry the fix.

@pierre-cheneau

Copy link
Copy Markdown
Contributor Author

Follow-up: #59 (synthetic input engine — single tap activation, timestamped pointer events, drag hold, hittable flag, screenshot geometry) is stacked on this branch; it will be rebased onto main once this lands.

@charliewwdev
charliewwdev merged commit f6cc23a into ai-dashboad:main Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants