feat(studio-bridge): add persistent sessions with v2 protocol#669
Open
feat(studio-bridge): add persistent sessions with v2 protocol#669
Conversation
PRD, 9 tech specs, 9 execution phases with agent prompts and validation criteria, and research notes for evolving studio-bridge from a launch-per-session tool into a persistent session system.
…ture Cover persistent plugin, host/client topology, session management, all 13 CLI commands, MCP server integration, v2 WebSocket protocol, plugin discovery, and programmatic API.
…nnect Health endpoint returns 503 and /plugin rejects WebSocket upgrades when the host is shutting down, preventing the plugin from rediscovering and reconnecting to a host that's about to close.
Surface plugin error code and message instead of generic "Unexpected response type" errors. Increase shutdown drain from 100ms to 250ms to give the plugin more time to close its WebSocket cleanly.
- Fix execute field name mismatch: read payload.script (spec) with fallback to payload.code (backward compat) - Add QueryStateAction: returns Studio run mode, placeId, placeName, gameId - Add QueryLogsAction: reads from MessageBuffer with direction, count, level filtering, and includeInternal support - Add CaptureScreenshotAction stub: returns CAPABILITY_NOT_SUPPORTED - Add SubscribeAction stubs: echo back requested events for subscribe and unsubscribe (actual event push not yet implemented) - Wire all handlers into StudioBridgePlugin.server.lua - Update capabilities list to include all supported actions - Fix resolveSession test timeout (waitForSession adds 5s)
…+ EditableImage Captures the Studio viewport using CaptureService:CaptureScreenshot(), loads the temp content into an EditableImage, scales down if larger than 1024x1024, reads RGBA pixels via ReadPixelsBuffer, base64-encodes with an optimized buffer-based encoder, and sends over WebSocket. The CLI converts RGBA to PNG using a minimal zlib-based encoder before saving. Also fixes response matching in sendToPluginAsync to normalize empty requestId as absent, matching the plugin convention.
Vendors png-luau v0.2.1 single-file bundle and uses it to compress RGBA pixel data into PNG before base64-encoding and sending over WebSocket. Reduces wire bandwidth ~3x (2.2MB → 712KB for a 1024x411 screenshot). Falls back to raw RGBA if the PNG encoder is unavailable (Lune tests).
- Add GUID nonce to unpublished place session IDs for uniqueness - Handle duplicate sessionId in bridge-host by closing old connection - Replace Heartbeat tick loop with task.spawn polling loop that threads remaining execution time through all async calls - Simplify DiscoveryStateMachine: remove backoff/reconnecting state, always poll at consistent interval, rename deadlineSec to remainingExecTimeSec - Fix waitForSessionsToSettleAsync cleanup bug (closures captured stale done reference) - Add waitForSessions option to BridgeConnection.connectAsync
Extract withSessionAsync/withConnectionAsync and addSessionOptions into with-connection.ts to eliminate repeated connect/resolve/disconnect boilerplate across all 7 CLI commands.
…lution Move LogService.MessageOut listener to top-level scope in the plugin so logs are captured from the moment the plugin loads, not only after a WebSocket connects. Use a hybrid clock (os.time + os.clock delta) for correct wall-clock timestamps with sub-second precision, and fix the CLI to convert epoch seconds to milliseconds for Date parsing. Hoist the wait-for-sessions logic to the top of resolveSessionAsync so --session and --instance targeting also wait for persistent plugins to discover the host before performing lookups.
The error listed instance IDs but suggested --session, so users would copy an instance ID into --session and get a not-found error. List session IDs instead so they can be copied directly.
…exts Use task.defer instead of task.spawn to resume the caller thread in scanPortsAsync, preventing "cannot resume non-suspended coroutine" errors. Skip plugin initialization in client/server play-mode contexts since HttpService is restricted to the game server. Increase session settle timeout from 2.5s to 4s to allow more time for persistent plugins to discover the ephemeral host.
…ands Replace 13 flat CLI commands with a declarative defineCommand() system that drives CLI, MCP, and terminal from a single source per command. Commands are now grouped (console, explorer, viewport, process, plugin) and co-located with their Luau action files, which are pushed to the plugin dynamically over the wire instead of bundled statically.
a45bded to
cf9cc1a
Compare
…d watch mode Wire the --format, --output, --open, --watch, and --interval flags that were declared but ignored in the CLI adapter. Restructure the handler into composable helpers (extractCommandArgs, executeCommandAsync, formatForOutput, outputResult) and add rich text formatters to all six commands: exec (output lines), logs (timestamped colored entries), list (session table), info (key-value state), query (indented tree), and screenshot (summary text + binary file writes via binaryField).
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.
Summary
Adds persistent sessions to studio-bridge. The plugin now stays running in Roblox Studio and maintains a WebSocket connection to the bridge server, replacing the one-shot launch-execute-exit workflow. This enables multiple concurrent Studio instances, structured commands (exec, query, state, logs, screenshot), split-server mode for devcontainers, host failover, and MCP integration for AI agents.
@modelcontextprotocol/sdkAlso includes
cli-output-helperspackage for structured output (table, JSON, watch renderers).Test plan
npx vitest run)studio-bridge sessionsand verify connected instance appears