Auto-start died for the whole session whenever startup included a compile:
the ctor latched SessionState before the delayCall ran, and the reload wiped
the delayCall. Reload-resume died at multi-pass compiles: the one-shot flag
was consumed before the deferred (delayCall) resume ran, and the next
boundary deleted it again.
- Replace delayCall with EditorApplication.update ticks that the
[InitializeOnLoad] ctor re-arms on every domain load; latch only when the
deferred work actually dispatches, retry (bounded per domain) while editor
services are still initializing, and skip the subscription entirely in the
common case where auto-start is off and nothing is pending.
- Move the resume flag from EditorPrefs (per-user machine-global, survives
crashes, leaks across concurrently open editors) to SessionState; keep it
until the resume succeeds, is cancelled, or exhausts its retries, instead
of consuming it at boundaries where the bridge is down. Manual Connect,
End Session, transport switch, and orphan cleanup cancel a pending resume
through a named seam (CancelPendingResume), which also aborts an in-flight
retry loop; exhaustion erases the flag so later reloads don't replay 49s
failure loops.
- Serialize TransportManager.StartAsync per mode: concurrent starts coalesce
onto one in-flight attempt, so a manual Connect can no longer race the
resume/auto-start loops into bouncing a just-established session
(WebSocketTransportClient.StartAsync tears down a live connection first).
- A SessionState connect-pending marker lets the next domain load finish an
auto-start whose connect phase a reload killed — connect-only, never
re-spawning (StartLocalHttpServer stops a still-booting server first).
Whether a launch-process handle exists is now answered live by
ServerManagementService.HasManagedServerLaunchHandle; without one (post-
reload, or an externally started server) the wait polls to the 5-minute
hard cap instead of fail-fasting.
- Busy gate uses EditorStateCache.GetActualIsCompiling (now internal, with
the CompilationPipeline reflection bound once as a delegate): raw
isCompiling stays true all play session under
Recompile-After-Finished-Playing (#549).
- One-time (per session) migration deletes the legacy EditorPrefs flag.
The stdio sibling has the same defect class (StdioBridgeReloadHandler.cs:65
delete-when-not-running, :133 delayCall) — follow-up, kept out of scope here,
along with the remaining stdio copies of the isCompiling probe.
Convert the local MCP HTTP server launch from a visible-terminal model to a
headless background launch and make startup diagnosable and robust.
- Launch windowless via TerminalLauncher.CreateHeadlessProcessStartInfo;
combined stdout/stderr redirected to a per-port log at
Library/MCPForUnity/Logs/server-launch-{port}.log (truncated each launch)
- Replace the per-launch confirmation dialog with a one-time confirm gated on
the new EditorPrefs key HttpServerLaunchConfirmed; the quiet auto-start path
skips it and does not set the flag
- Prepend platform uv/uvx PATH entries so bare uvx/uv resolves under
GUI-launched Unity's minimal non-login PATH (notably macOS)
- Replace the fixed ~30-attempt reachability waits with open-ended polling
tied to the launched process's liveness (5-minute hard cap), emitting a
tail-of-log failure report when the server dies — in both
HttpAutoStartHandler and McpConnectionSection
- Simplify quit-time cleanup to a handshake-scoped StopManagedLocalHttpServer
so headless servers are not left as invisible orphans
- Transport-aware UI button labels (Connect/Disconnect vs Start/End Session),
a transient "Starting…" state, and clearer lifecycle logging
Tests: TerminalLauncherTests covers the headless start-info contract;
ServerManagementServiceCharacterizationTests covers the one-time-confirm gate,
quiet-path bypass, and per-port log redirection.