From 68cbf041a4b67212341379ee8850bc4e861ef9b3 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 11 Nov 2026 18:50:00 -0800 Subject: [PATCH] MCP: replies hide each sent path the same way whatever the outcome Each hidden id or path is replaced once, chosen from the reply as given, so a hidden path inside another library's shown id is not replaced again, and a readable id written with %XX escapes keeps the hidden path it begins with. A path quoted with {:?} is matched with its quotes and control characters escaped. A path outside the read roots that the request sent is shown by its file name in a reply that succeeded as in one that failed, and a path param counts with a relative path too. A relative path is not replaced where it ends a longer path. Without a read root, a file: URL that names another host stays in ui.inspect's recorded steps. --- crates/ui-egui/src/control.rs | 216 +++++++++++++------------ crates/ui-egui/src/control/tests.rs | 83 +++++++++- crates/ui-egui/src/tests/automation.rs | 5 +- docs/mcp.md | 8 +- 4 files changed, 200 insertions(+), 112 deletions(-) diff --git a/crates/ui-egui/src/control.rs b/crates/ui-egui/src/control.rs index a198810b41..c1b7350527 100644 --- a/crates/ui-egui/src/control.rs +++ b/crates/ui-egui/src/control.rs @@ -441,13 +441,19 @@ impl Hiding { } /// The paths outside the read roots that `v`'s strings and keys name at any depth, written as paths -/// ([`unreadable_path_like`]), each as a hidden library id (`loaded/`) with `loaded/` -/// shown. The error of a failed request hides them as it hides a hidden library's path, with that file -/// name also for a hidden library shown as `loaded/ (2)`, so that it reads the same whether -/// or not a library was loaded from one of them. +/// ([`unreadable_path_like`]) or held by a path param +/// ([`vectorcraft_engine::file_access::is_path_key`]), a relative one too, each as a hidden library id +/// (`loaded/`) with `loaded/` shown. A reply hides them as it hides a hidden library's +/// path, with that file name also for a hidden library shown as `loaded/ (2)`, so that it +/// reads the same whether or not a library was loaded from one of them. fn sent_paths(v: &Value, out: &mut Vec<(String, String)>) { - fn add(s: &str, out: &mut Vec<(String, String)>) { - if !unreadable_path_like(s) { + collect_sent_paths(v, false, out); +} + +/// [`sent_paths`] on `v`, which a path param holds when `path_param` is set. +fn collect_sent_paths(v: &Value, path_param: bool, out: &mut Vec<(String, String)>) { + fn add(s: &str, path_param: bool, out: &mut Vec<(String, String)>) { + if !unreadable_path_like(s) && !(path_param && !readable_value(s)) { return; } // A URL that names another host as the path after its scheme (`//host/share/…`). @@ -463,12 +469,12 @@ fn sent_paths(v: &Value, out: &mut Vec<(String, String)>) { } } match v { - Value::String(s) => add(s, out), - Value::Array(items) => items.iter().for_each(|item| sent_paths(item, out)), + Value::String(s) => add(s, path_param, out), + Value::Array(items) => items.iter().for_each(|item| collect_sent_paths(item, path_param, out)), Value::Object(fields) => { for (key, item) in fields { - add(key, out); - sent_paths(item, out); + add(key, false, out); + collect_sent_paths(item, vectorcraft_engine::file_access::is_path_key(key), out); } } _ => {} @@ -510,7 +516,7 @@ fn collect_library_panel_ids(v: &Value, ids: &mut std::collections::BTreeSet