Add syncback command handling to MCP stream and API

- Introduced a new `onSyncbackCommand` option in `McpStream` to handle syncback requests.
- Implemented the `handle_mcp_syncback` function in the API to process syncback requests, including validation and logging.
- Updated the `run_live_syncback` function to return statistics on added and removed files during the syncback process.
- Enhanced the MCP tools list to include the new syncback tool, with corresponding documentation added.

These changes aim to facilitate a complete syncback of the Roblox Studio state to the filesystem, improving project management capabilities.
This commit is contained in:
Joe 2026-03-01 18:49:34 -06:00
parent fc8a6e9b9c
commit c5502191d3
7 changed files with 248 additions and 24 deletions

View file

@ -8,7 +8,7 @@ mod doc;
mod fmt_project;
mod init;
mod plugin;
mod serve;
pub(crate) mod serve;
mod sourcemap;
mod studio;
mod syncback;

View file

@ -77,7 +77,7 @@ impl ServeCommand {
ServerExitReason::SyncbackRequested(payload) => {
log::info!("Live syncback requested, running...");
match run_live_syncback(&project_path, payload) {
Ok(()) => log::info!("Syncback complete, restarting serve..."),
Ok(_stats) => log::info!("Syncback complete, restarting serve..."),
Err(err) => {
log::error!("Live syncback failed: {err:#}. Restarting serve...")
}
@ -95,7 +95,15 @@ impl ServeCommand {
}
}
fn run_live_syncback(project_path: &Path, payload: SyncbackPayload) -> anyhow::Result<()> {
pub(crate) struct SyncbackStats {
pub added: usize,
pub removed: usize,
}
pub(crate) fn run_live_syncback(
project_path: &Path,
payload: SyncbackPayload,
) -> anyhow::Result<SyncbackStats> {
let new_dom = build_dom_from_chunks(payload)?;
let vfs = Vfs::new_oneshot();
@ -128,20 +136,23 @@ fn run_live_syncback(project_path: &Path, payload: SyncbackPayload) -> anyhow::R
.fs_snapshot
.write_to_vfs_parallel(base_path, session_old.vfs(), git_cache.as_ref())?;
let added = result.fs_snapshot.added_paths().len();
let removed = result.fs_snapshot.removed_paths().len();
log::info!(
"Finished live syncback: wrote {} files/folders, removed {}.",
result.fs_snapshot.added_paths().len(),
result.fs_snapshot.removed_paths().len()
added,
removed
);
crate::git::refresh_git_index(base_path);
drop(session_old);
Ok(())
Ok(SyncbackStats { added, removed })
}
fn build_dom_from_chunks(payload: SyncbackPayload) -> anyhow::Result<WeakDom> {
pub(crate) fn build_dom_from_chunks(payload: SyncbackPayload) -> anyhow::Result<WeakDom> {
use crate::syncback::VISIBLE_SERVICES;
let mut dom = WeakDom::new(InstanceBuilder::new("DataModel"));