From 11bc1745a6d3444f08623738359fcf463a8f3062 Mon Sep 17 00:00:00 2001 From: ysdirector Date: Sat, 10 Oct 2026 07:13:49 +0800 Subject: [PATCH] feat(control): expose external-change actions --- src/app/control/actions.rs | 21 +++++++++++++++++++++ src/app/control/mod.rs | 24 ++++++++++++++++++++++++ src/mcp.rs | 2 +- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/app/control/actions.rs b/src/app/control/actions.rs index 1ea345409..6af31b8cd 100644 --- a/src/app/control/actions.rs +++ b/src/app/control/actions.rs @@ -69,6 +69,16 @@ pub(crate) fn property_json(p: &crate::scene::model::object::Property) -> Value } pub(super) const NAMES: &[&str] = &[ "close_modal", + // Native-only: the "changed outside" dialog does not exist in the web + // build, so neither does its action set. + #[cfg(not(target_arch = "wasm32"))] + "external_change_reload", + #[cfg(not(target_arch = "wasm32"))] + "external_change_overwrite", + #[cfg(not(target_arch = "wasm32"))] + "external_change_save_as", + #[cfg(not(target_arch = "wasm32"))] + "external_change_cancel", "pdf_dialog_ok", "pdf_layer_toggle", "pc_manager_toggle", @@ -974,6 +984,17 @@ impl OpenCADStudio { let name = string(req, "name")?; let msg = match name { "close_modal" => Message::CloseModal, + // The "changed outside" modal's suggested actions (D6): reload + // the disk copy, keep the in-memory one and overwrite, save as, + // or dismiss. Native only — the web build has no such dialog. + #[cfg(not(target_arch = "wasm32"))] + "external_change_reload" => Message::ExternalChangeReload, + #[cfg(not(target_arch = "wasm32"))] + "external_change_overwrite" => Message::ExternalChangeOverwrite, + #[cfg(not(target_arch = "wasm32"))] + "external_change_save_as" => Message::ExternalChangeSaveAs, + #[cfg(not(target_arch = "wasm32"))] + "external_change_cancel" => Message::ExternalChangeCancel, // The open PDF dialog's OK button. // Underlay Layers: switch a layer of the shown underlay. "pdf_layer_toggle" => Message::PdfDialog( diff --git a/src/app/control/mod.rs b/src/app/control/mod.rs index 76badd918..beba3b588 100644 --- a/src/app/control/mod.rs +++ b/src/app/control/mod.rs @@ -1763,6 +1763,30 @@ mod tests { stale["request_id"] = json!("stale"); assert_eq!(app.control_request(stale).0["code"], "stale_state"); } + #[test] + fn external_change_modal_actions_are_automatable() { + let mut app = OpenCADStudio::new_for_test(); + let names = crate::app::automation_action_names(); + for name in [ + "external_change_reload", + "external_change_overwrite", + "external_change_save_as", + "external_change_cancel", + ] { + assert!(names.contains(&name), "{name} should be listed"); + } + // No conflict pending: the action is a harmless no-op, not an error. + let reply = request( + &mut app, + json!({ + "op":"action", + "request_id":"external-action-noop", + "name":"external_change_reload" + }), + ); + assert_eq!(reply["status"], "completed", "{reply}"); + } + #[test] fn control_errors_and_missing_entities_do_not_report_success() { let mut app = OpenCADStudio::new_for_test(); diff --git a/src/mcp.rs b/src/mcp.rs index 116beb0a3..201dfd6b5 100644 --- a/src/mcp.rs +++ b/src/mcp.rs @@ -29,7 +29,7 @@ const MODERN_PROTOCOL_VERSION: &str = "2026-07-28"; /// changes, so schema drift (new params, renamed tools) is always a conscious, /// reviewed edit — and clients can detect a stale bridge by comparing digests. #[cfg(test)] -const TOOL_SCHEMA_DIGEST: &str = "8dc370c3e4bde86a3c2f6be8488dd1ed318850303326b00e2c28e8c033006472"; +const TOOL_SCHEMA_DIGEST: &str = "e7bd01696f57143d7139aeb75d53389450b1102b603f2ba4ace8122cc692070e"; const MAX_REQUEST: usize = 1_048_576; const MAX_RESPONSE: u64 = 16 * 1024 * 1024; const CACHE_TTL_MS: u64 = 3_600_000;