From af19880390148eba43df56940e687c83ebc5c34c Mon Sep 17 00:00:00 2001 From: Deng Liu Date: Sat, 7 Nov 2026 11:29:36 -0800 Subject: [PATCH] feat(plugins): PTY session bridge for plugin web views (#2038) A plugin web view can open interactive PTY sessions (spawn, input, resize, kill, streamed output and exit). Spawning requires the exact granted `process:` and its pinned executable, with no PATH re-resolution or fallback shell; the cwd is the trusted project, arguments, environment (append-only) and sizes are validated, and at most eight sessions run per plugin. A frame can only drive the sessions it opened; output is acknowledged chunk by chunk and input/output are bounded. Sessions end on permission change, reload, disable, uninstall, frame teardown or window close. Requires API ^1.3; adds a web-pty test fixture. Verified on macOS; Windows/Linux not run. Co-authored-by: dengliu <5108773+dengliu@users.noreply.github.com> --- crates/ide-host/src/plugins/api.rs | 4 + crates/ide-host/src/plugins/mod.rs | 7 + crates/ide-host/src/plugins/web.rs | 149 ++++++++ crates/ide-host/tests/plugins.rs | 172 +++++++++ .../tests/fixtures/commit/dist/plugin.wasm | Bin 97343 -> 97343 bytes .../fixtures/detail-views/dist/plugin.wasm | Bin 105774 -> 105781 bytes .../tests/fixtures/endpoints/dist/plugin.wasm | Bin 78636 -> 78636 bytes .../fixtures/file-templates/dist/plugin.wasm | Bin 68052 -> 68048 bytes .../fixtures/grouped-views/dist/plugin.wasm | Bin 89148 -> 89154 bytes .../tests/fixtures/hello/dist/plugin.wasm | Bin 141562 -> 141562 bytes .../tests/fixtures/hover/dist/plugin.wasm | Bin 86780 -> 86785 bytes .../tests/fixtures/indexer/dist/plugin.wasm | Bin 79926 -> 79926 bytes .../fixtures/inlay-hints/dist/plugin.wasm | Bin 88681 -> 88686 bytes .../tests/fixtures/jobs/dist/plugin.wasm | Bin 147785 -> 147779 bytes .../fixtures/path-events/dist/plugin.wasm | Bin 91110 -> 91110 bytes .../fixtures/semantic-tokens/dist/plugin.wasm | Bin 88860 -> 88860 bytes .../tests/fixtures/storage/dist/plugin.wasm | Bin 71118 -> 71114 bytes .../tests/fixtures/symbols/dist/plugin.wasm | Bin 103930 -> 103940 bytes .../tests/fixtures/tables/dist/plugin.wasm | Bin 116494 -> 116494 bytes .../tests/fixtures/web-pty/Cargo.lock | 333 ++++++++++++++++++ .../tests/fixtures/web-pty/Cargo.toml | 20 ++ .../tests/fixtures/web-pty/dist/plugin.wasm | Bin 0 -> 68026 bytes .../fixtures/web-pty/dist/plugin.wasm.sources | 1 + .../tests/fixtures/web-pty/plugin.toml | 21 ++ .../tests/fixtures/web-pty/src/lib.rs | 15 + .../tests/fixtures/web-pty/web/index.html | 27 ++ crates/ide-terminal/src/lib.rs | 63 +++- plugins/README.md | 39 ++ .../official/ai-completion/dist/plugin.wasm | Bin 169102 -> 169568 bytes plugins/official/checkstyle/dist/plugin.wasm | Bin 166512 -> 166523 bytes plugins/official/csv-editor/dist/plugin.wasm | Bin 130597 -> 130591 bytes plugins/official/git-toolbox/dist/plugin.wasm | Bin 108501 -> 108493 bytes plugins/official/graphviz/dist/plugin.wasm | Bin 126104 -> 126104 bytes .../official/key-promoter/dist/plugin.wasm | Bin 97368 -> 97364 bytes .../official/license-header/dist/plugin.wasm | Bin 150760 -> 150770 bytes plugins/official/mybatis/dist/plugin.wasm | Bin 166708 -> 166698 bytes .../official/regex-tester/dist/plugin.wasm | Bin 932220 -> 932819 bytes plugins/official/solidity/dist/plugin.wasm | Bin 105039 -> 105046 bytes .../official/string-tools/dist/plugin.wasm | Bin 162796 -> 162792 bytes sdk/rust/openidea-plugin/README.md | 15 + src-tauri/src/commands/mod.rs | 1 + src-tauri/src/commands/plugin.rs | 30 ++ src/bindings.ts | 10 + .../plugins/__tests__/ptyBridge.test.ts | 211 +++++++++++ .../plugins/__tests__/webViews.test.tsx | 70 +++- src/features/plugins/views/WebView.tsx | 71 +++- src/features/plugins/views/ptyBridge.ts | 286 +++++++++++++++ src/platform/locales/text/en.json | 7 + src/platform/locales/text/zh.json | 7 + 49 files changed, 1548 insertions(+), 11 deletions(-) create mode 100644 crates/ide-plugin/tests/fixtures/web-pty/Cargo.lock create mode 100644 crates/ide-plugin/tests/fixtures/web-pty/Cargo.toml create mode 100644 crates/ide-plugin/tests/fixtures/web-pty/dist/plugin.wasm create mode 100644 crates/ide-plugin/tests/fixtures/web-pty/dist/plugin.wasm.sources create mode 100644 crates/ide-plugin/tests/fixtures/web-pty/plugin.toml create mode 100644 crates/ide-plugin/tests/fixtures/web-pty/src/lib.rs create mode 100644 crates/ide-plugin/tests/fixtures/web-pty/web/index.html create mode 100644 sdk/rust/openidea-plugin/README.md create mode 100644 src/features/plugins/__tests__/ptyBridge.test.ts create mode 100644 src/features/plugins/views/ptyBridge.ts diff --git a/crates/ide-host/src/plugins/api.rs b/crates/ide-host/src/plugins/api.rs index 040fc1c8e..4017a5b44 100644 --- a/crates/ide-host/src/plugins/api.rs +++ b/crates/ide-host/src/plugins/api.rs @@ -565,6 +565,10 @@ impl Shared { self.closed_clients.lock().remove(client); } + pub fn client_closed(&self, client: &str) -> bool { + self.closed_clients.lock().contains(client) + } + /// Withdraws a plugin's run-time state (it stopped or failed). Its /// subscriptions go only with `subscriptions`, as they survive restarts. pub fn clear_plugin(&self, plugin: &str, subscriptions: bool) { diff --git a/crates/ide-host/src/plugins/mod.rs b/crates/ide-host/src/plugins/mod.rs index b055c0eb4..e83aadb03 100644 --- a/crates/ide-host/src/plugins/mod.rs +++ b/crates/ide-host/src/plugins/mod.rs @@ -326,6 +326,7 @@ pub struct PluginHost { providers: Arc, navigation: Mutex, endpoints: Mutex, + web_ptys: Mutex>>, /// Validated UI declarations of installed packages (start-up reuses them). index: Arc, ledger: Mutex, @@ -417,6 +418,7 @@ impl PluginHost { providers, navigation: Mutex::default(), endpoints: Mutex::default(), + web_ptys: Mutex::default(), index, plugins: RwLock::default(), state: Mutex::new(state), @@ -1370,6 +1372,7 @@ impl PluginHost { pub fn forget_client(&self, label: &str) { self.queues.lock().retain(|(_, client), _| client.as_deref() != Some(label)); self.shared.forget_client(label); + self.forget_web_ptys(label); } /// The user cancelled a plugin task (`task_id` from `TaskStarted`). @@ -1762,6 +1765,7 @@ impl PluginHost { let actors: Vec<_> = self.plugins.read().values().filter_map(|p| p.runtime.lock().take()).collect(); for id in self.plugins.read().keys() { self.shared.block_prompts(id); + self.stop_web_ptys(id); } for a in &actors { a.stop(false); @@ -2178,6 +2182,7 @@ impl PluginHost { } fn stop(&self, plugin: &LoadedPlugin) { + self.stop_web_ptys(plugin.id()); self.clear_plugin_navigation(plugin.id()); self.clear_plugin_endpoints(plugin.id()); // A call waiting on the user would keep the join below waiting. @@ -2198,6 +2203,8 @@ impl PluginHost { let mut meta = plugin.meta.lock(); meta.status = PluginStatus::Failed; meta.error = Some(error); + drop(meta); + self.stop_web_ptys(plugin.id()); } fn fail(&self, plugin: &LoadedPlugin, error: &str, client: Option<&str>) { diff --git a/crates/ide-host/src/plugins/web.rs b/crates/ide-host/src/plugins/web.rs index 11a109f8e..eb67a1a98 100644 --- a/crates/ide-host/src/plugins/web.rs +++ b/crates/ide-host/src/plugins/web.rs @@ -100,6 +100,23 @@ pub struct WebPage { pub path: String, } +/// A web frame's API 1.3 PTY request. The frame never supplies an executable path or cwd. +#[derive(Clone, Debug, Serialize, Deserialize, Type)] +#[serde(rename_all = "camelCase")] +pub struct WebPtyCommand { + pub program: String, + pub args: Vec, + pub env: std::collections::BTreeMap, + pub cols: u16, + pub rows: u16, +} + +pub(super) struct WebPtySession { + id: ide_core::TerminalId, + host: std::sync::Weak, + window: String, +} + /// A file of a web view. pub struct WebFile { pub bytes: Vec, @@ -107,6 +124,138 @@ pub struct WebFile { } impl PluginHost { + /// Uses the normal PTY backend, without user shell fallback or startup commands. + #[allow(clippy::too_many_arguments)] + pub fn spawn_web_pty( + &self, + host: &std::sync::Arc, + plugin_id: &str, + view: &str, + window: &str, + command: WebPtyCommand, + output: crate::ops::Emit, + ) -> IdeResult { + let _guard = self.lifecycle.lock(); + let mut sessions = self.web_ptys.lock(); + if self.shared.client_closed(window) { + return Err(IdeError::cancelled()); + } + let options = self.web_pty_options(plugin_id, view, window, command)?; + let entries = sessions.entry(plugin_id.to_owned()).or_default(); + entries.retain(|s| s.host.upgrade().is_some_and(|h| h.terminals.contains(s.id))); + if entries.len() >= 8 { + return Err(IdeError::invalid("a plugin may own at most 8 PTYs")); + } + let cwd = options.cwd.0.clone(); + let info = host.terminals.spawn_program( + options, + host.owner_window(window).to_owned(), + host.window_sink(window), + Box::new(move |data| output(data)), + )?; + if !self + .shared + .workspace() + .is_some_and(|workspace| workspace.project_of(window).as_ref() == Some(&cwd) && workspace.trusted(&cwd)) + { + let _ = host.terminals.kill(info.id); + return Err(IdeError::cancelled()); + } + entries.push(WebPtySession { id: info.id, host: std::sync::Arc::downgrade(host), window: window.to_owned() }); + Ok(info) + } + + pub(super) fn forget_web_ptys(&self, window: &str) { + for sessions in self.web_ptys.lock().values_mut() { + sessions.retain(|session| { + if session.window != window { + return true; + } + if let Some(host) = session.host.upgrade() { + let _ = host.terminals.kill(session.id); + } + false + }); + } + } + + pub(super) fn stop_web_ptys(&self, plugin: &str) { + if let Some(sessions) = self.web_ptys.lock().remove(plugin) { + for session in sessions { + if let Some(host) = session.host.upgrade() { + let _ = host.terminals.kill(session.id); + } + } + } + } + + /// Authorizes a PTY immediately before spawning through the existing terminal backend. + pub fn web_pty_options( + &self, + plugin_id: &str, + view: &str, + window: &str, + command: WebPtyCommand, + ) -> IdeResult { + self.web_page(plugin_id, view)?; + let plugin = self.get(plugin_id)?; + plugin.pkg.manifest.needs_api("web view PTYs", 3).map_err(IdeError::invalid)?; + let cap = ide_extension::Capability::Process(command.program.clone()); + if !plugin.meta.lock().granted.contains(&cap) { + return Err(IdeError::new( + ide_core::error::ErrorKind::PermissionDenied, + format!("{cap} capability not granted"), + )); + } + if command.program.is_empty() + || command.program.len() > 256 + || command.program.trim() != command.program + || command.program.contains(['\0', '\r', '\n']) + || command.args.len() > 256 + || command.args.iter().any(|a| a.len() > 4096 || a.contains('\0')) + || !(2..=500).contains(&command.cols) + || !(1..=500).contains(&command.rows) + { + return Err(IdeError::invalid("invalid PTY program, arguments or dimensions")); + } + if command.env.len() > 64 + || command.env.iter().any(|(k, v)| { + k.is_empty() + || k.len() > 256 + || k.contains(['=', '\0']) + || v.len() > 4096 + || v.contains('\0') + || std::env::vars_os().any(|(inherited, _)| { + if cfg!(windows) { + inherited.to_string_lossy().eq_ignore_ascii_case(k) + } else { + inherited == k.as_str() + } + }) + }) + { + return Err(IdeError::invalid("PTY environment may only add variables, within the size limits")); + } + let workspace = self.shared.workspace().ok_or_else(|| IdeError::unavailable("no workspace"))?; + let cwd = workspace.project_of(window).ok_or_else(|| IdeError::invalid("no project in this window"))?; + if !cwd.is_absolute() || !cwd.is_dir() { + return Err(IdeError::invalid("the project directory no longer exists")); + } + if !workspace.trusted(&cwd) { + return Err(IdeError::new(ide_core::error::ErrorKind::PermissionDenied, "project is not trusted")); + } + let program = self.program_for(plugin_id, &command.program)?; + Ok(ide_terminal::TerminalOptions { + cwd: cwd.into(), + shell: Some(program.to_string_lossy().into_owned()), + args: command.args, + env: command.env, + cols: command.cols, + rows: command.rows, + shell_integration: false, + }) + } + /// The web roots `plugin` declares (entry directories, package-relative, `/`-terminated). fn web_dirs(&self, plugin: &str) -> Vec { [super::ui_points::VIEWS, super::ui_points::CUSTOM_EDITORS] diff --git a/crates/ide-host/tests/plugins.rs b/crates/ide-host/tests/plugins.rs index 1d5991252..1c6dc6e44 100644 --- a/crates/ide-host/tests/plugins.rs +++ b/crates/ide-host/tests/plugins.rs @@ -22,6 +22,7 @@ struct TestWorkspace { other_roots: Mutex>, documents: Arc, trusted: bool, + project_queries_left: Mutex>, /// (producer, path) → published diagnostics. diagnostics: Mutex>>, /// plugin → its settings as the user set them. @@ -39,6 +40,7 @@ impl TestWorkspace { other_roots: Mutex::default(), documents: Arc::new(documents), trusted: true, + project_queries_left: Mutex::new(None), diagnostics: Mutex::default(), settings: Mutex::default(), }) @@ -93,6 +95,12 @@ impl PluginWorkspace for TestWorkspace { self.trusted } fn project_of(&self, _window: &str) -> Option { + if let Some(left) = self.project_queries_left.lock().as_mut() { + if *left == 0 { + return None; + } + *left -= 1; + } Some(self.root.clone()) } fn publish_diagnostics( @@ -1947,6 +1955,7 @@ fn git_toolbox_does_not_fetch_untrusted_projects() { git(&f.project, &["init", "-b", "main"]); f.install(&official("git-toolbox")); let untrusted = Arc::new(TestWorkspace { + project_queries_left: Mutex::new(None), root: f.project.clone(), other_roots: Mutex::default(), documents: f.workspace.documents.clone(), @@ -4434,6 +4443,169 @@ fn view_messages_accept_multi_megabyte_snapshots_and_cap_at_8_mib() { assert!(err.message.contains("limited to"), "{}", err.message); } +#[test] +fn web_ptys_require_a_current_exact_program_grant_and_project() { + use ide_host::plugins::web::WebPtyCommand; + let f = fixture(Limits::default()); + let info = f.host.install_from_dir(&sample("web-pty"), &Consent::default()).unwrap(); + assert!(info.capabilities.iter().any(|c| c.id == "process:git" && !c.granted)); + let command = || WebPtyCommand { + program: "git".into(), + args: vec!["--version".into()], + env: Default::default(), + cols: 80, + rows: 24, + }; + let options = |cmd| f.host.web_pty_options("web-pty", "terminal", "main", cmd); + assert_eq!(options(command()).unwrap_err().kind, ErrorKind::PermissionDenied); + f.host.set_capability("web-pty", "process:git", true).unwrap(); + let approved = f.host.program_for("web-pty", "git").unwrap(); + let got = options(command()).unwrap(); + assert_eq!(got.shell.as_deref(), approved.to_str()); + assert!(approved.is_absolute()); + assert_eq!(got.cwd.0, f.project); + assert!(!got.shell_integration); + assert_eq!(f.run("web-pty", "ping", None).unwrap().as_deref(), Some("Web PTY ready")); + for program in ["sh", "bash", "git-other", "./git", "/tmp/git"] { + let cmd = WebPtyCommand { program: program.into(), ..command() }; + assert!(options(cmd).is_err(), "{program}"); + } + for cmd in [ + WebPtyCommand { cols: 0, ..command() }, + WebPtyCommand { rows: 501, ..command() }, + WebPtyCommand { args: vec!["x".repeat(4097)], ..command() }, + WebPtyCommand { args: vec!["x".into(); 257], ..command() }, + WebPtyCommand { args: vec!["\0".into()], ..command() }, + WebPtyCommand { env: [("PATH".into(), "/tmp".into())].into(), ..command() }, + WebPtyCommand { env: [("a=b".into(), "x".into())].into(), ..command() }, + WebPtyCommand { env: [("a".into(), "x".repeat(4097))].into(), ..command() }, + ] { + assert!(options(cmd).is_err()); + } + let got = options(WebPtyCommand { env: [("OPENIDEA_WEB_PTY_TEST_NEW".into(), "yes".into())].into(), ..command() }) + .unwrap(); + assert_eq!(got.env["OPENIDEA_WEB_PTY_TEST_NEW"], "yes"); + assert!(f.host.web_pty_options("web-pty", "missing", "main", command()).is_err()); + f.host.set_workspace(None); + assert!(options(command()).is_err()); + let mut untrusted = TestWorkspace::new(&f.project); + Arc::get_mut(&mut untrusted).unwrap().trusted = false; + f.host.set_workspace(Some(untrusted)); + assert_eq!(options(command()).unwrap_err().kind, ErrorKind::PermissionDenied); + f.host.set_workspace(Some(f.workspace.clone())); + std::fs::rename(&f.project, f.project.with_extension("moved")).unwrap(); + assert!(options(command()).unwrap_err().message.contains("no longer exists")); + std::fs::rename(f.project.with_extension("moved"), &f.project).unwrap(); + f.host.set_capability("web-pty", "process:git", false).unwrap(); + assert_eq!(options(command()).unwrap_err().kind, ErrorKind::PermissionDenied); + f.host.set_enabled("web-pty", false).unwrap(); + assert!(options(command()).is_err()); + f.host.uninstall("web-pty").unwrap(); + assert!(options(command()).is_err()); +} + +#[cfg(unix)] +#[test] +fn web_ptys_keep_the_approved_file_and_require_api_1_3() { + use ide_host::plugins::web::WebPtyCommand; + use std::os::unix::fs::PermissionsExt; + let f = fixture(Limits::default()); + let bin = f.plugins_dir.parent().unwrap().join("bin"); + std::fs::create_dir_all(&bin).unwrap(); + let executable = bin.join("git"); + std::fs::write(&executable, "#!/bin/sh\nexit 0\n").unwrap(); + std::fs::set_permissions(&executable, std::fs::Permissions::from_mode(0o755)).unwrap(); + let path = bin.clone(); + f.host.set_program_path(Arc::new(move || Some(path.clone().into_os_string()))); + f.install(&sample("web-pty")); + let command = || WebPtyCommand { program: "git".into(), args: vec![], env: Default::default(), cols: 80, rows: 24 }; + f.host.set_program_path(Arc::new(|| Some("/unapproved-path".into()))); + assert_eq!( + f.host.web_pty_options("web-pty", "terminal", "main", command()).unwrap().shell.unwrap(), + executable.canonicalize().unwrap().to_string_lossy() + ); + std::fs::write(&executable, "#!/bin/sh\nexit 42\n").unwrap(); + assert!(f.host.web_pty_options("web-pty", "terminal", "main", command()).unwrap_err().message.contains("changed")); + std::fs::remove_file(&executable).unwrap(); + assert!(f.host.web_pty_options("web-pty", "terminal", "main", command()).is_err()); + + let old = tempfile::tempdir().unwrap(); + let pkg = old.path().join("old"); + copy_dir(&sample("web-pty"), &pkg); + let manifest = pkg.join("plugin.toml"); + let text = std::fs::read_to_string(&manifest).unwrap().replace("^1.3", "^1.2"); + std::fs::write(manifest, text).unwrap(); + let f = fixture(Limits::default()); + f.install(&pkg); + assert!(f.host.web_pty_options("web-pty", "terminal", "main", command()).unwrap_err().message.contains("1.3")); +} + +#[tokio::test] +async fn web_ptys_are_capped_across_windows_and_end_with_the_plugin() { + use ide_host::{Host, HostConfig, plugins::web::WebPtyCommand}; + let f = fixture(Limits::default()); + f.install(&sample("web-pty")); + let root = tempfile::tempdir().unwrap(); + let host = Arc::new(Host::new(HostConfig { + config_dir: root.path().join("config"), + data_dir: root.path().join("data"), + local_data_dir: root.path().join("local"), + languages: Arc::new(ide_language::LanguageRegistry::load(None).unwrap()), + syntax: Arc::default(), + sink_for: Box::new(|_| Arc::new(ide_core::NullSink)), + owner: |w| w, + runtime: tokio::runtime::Handle::current(), + project_environment: false, + })); + let spawn = |window: &str| { + f.host.spawn_web_pty( + &host, + "web-pty", + "terminal", + window, + WebPtyCommand { + program: "git".into(), + args: vec!["hash-object".into(), "--stdin".into()], + env: Default::default(), + cols: 80, + rows: 24, + }, + Arc::new(|_| {}), + ) + }; + *f.workspace.project_queries_left.lock() = Some(1); + assert!(spawn("main").is_err(), "project closed while spawning"); + assert!(host.terminals.list().is_empty()); + *f.workspace.project_queries_left.lock() = None; + let mut ids = Vec::new(); + for i in 0..8 { + ids.push(spawn(&format!("window-{i}")).unwrap().id); + } + assert!(spawn("ninth-window").unwrap_err().message.contains("8 PTYs")); + host.terminals.kill(ids[0]).unwrap(); + let replacement = spawn("another-window").unwrap(); + f.host.reload("web-pty").unwrap(); + assert!(!host.terminals.contains(replacement.id)); + assert!(ids.into_iter().all(|id| !host.terminals.contains(id))); + let id = spawn("main").unwrap().id; + f.host.set_capability("web-pty", "process:git", false).unwrap(); + assert!(!host.terminals.contains(id)); + assert!(spawn("main").is_err()); + f.host.set_capability("web-pty", "process:git", true).unwrap(); + let id = spawn("main").unwrap().id; + f.host.set_enabled("web-pty", false).unwrap(); + assert!(!host.terminals.contains(id)); + f.host.set_enabled("web-pty", true).unwrap(); + let id = spawn("main").unwrap().id; + f.host.forget_client("main"); + assert!(!host.terminals.contains(id)); + assert!(spawn("main").is_err()); + f.host.reopen_client("main"); + let id = spawn("main").unwrap().id; + f.host.uninstall("web-pty").unwrap(); + assert!(!host.terminals.contains(id)); +} + #[test] fn marker_icons_ship_sanitized_light_and_dark_assets() { let f = fixture(Limits::default()); diff --git a/crates/ide-plugin/tests/fixtures/commit/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/commit/dist/plugin.wasm index ef28558499dced88af31c4cc4205337c0449cbff..5b8ede3d68966f96333b81be5843b045eee5dad6 100644 GIT binary patch delta 770 zcmbV{T}V@57{|}^p0jmgx}EIHIm$CvsQYrxxmMZ7MEr`%pprQi`atYdLPV5y;gET; zsH+ECS`;LHWJ_nSq&KmllBIzc1(Ad<6pSvUpo>8U9hW!W>>_yhJum;~dH($0NL&$# zE5a6ymQMjbl~?nG=Xn)NSRf!5Ap}b`=1praHNS;6Yg8PjNwqkqb)tXkIDDjK+eTQJ z#G~o@|7MleN`(x7j3++^XWrjkS@gHIi)=2-7q@+m#_kQ>nW?5G-6aBDv}2bNU;rQO zo=CRboS90X6T7nW=qvp(fF&e`99W_zLp7J)>GSy*QR#jFlFXbntTK|YNV~F6C5@oS zRcxHYhKN{Xs>CMaNU~r>rXz$40B|_lqJ=01^IpoVw6#JXPTNGhZ4vRi%_D0i`4`|B z_U8xW-`edR_|T$P4<(W_Zq6NLggB1d&t-O|&|!@!6I&WwaqPtDnlxOl+0N}* zoBg!vKtY Sg3ADGFjNkP(GTTtrQk1LPaIJI delta 729 zcmbV|T}YE*6vyB5zT0|bb9<{Pez5JGL)@JEu(`F$jJJ!m^+6w4F*bKmFly973d(LA zM1lz297G*a(O9YZF?%Gh!jWYW5fY5B3!NHe&_z%egQ9vI-FUN$o{QhZ`JZ$C{5i7) z`D{U+v1zJRJn-ebnrC^QXE&ab;{bpK^l6&502S0*dD5j(%CJ)V3>L_ucAA4MW~z+; z&DClcyb>9>@3&-zYU(7A#a^G+1iM94T3qzz|rvP|> zxAk+ShPw>qEF>}6;2=+ohXB@)HJM?JSWTy8Rmnsm!H5cJ5Mq?(4g6wa!bg&9I9@V> z+#=uHhfNW&)p`))jnk!qwOaSF_|-1r7pGDEuo#4qWKxz93i!Sy0BJP34V02QPg&>j zQT}$G50v7{;GFgD^}^dfNd;aCBF&Y^1o$ zNlxtWHWJV76bEDE!`?X_R`8DRBCHVAfhfQPUiN>cQYdf?9+9y?frBZMKJp4+l*Eq? zC`nnU9$*c4Q*Wi;(6ctgaqZWE#`?|eQcjF4bD0@gV5&7HbISDN)3H&8hncZ$@;>6F?aGo^*W%j4jKoL z6)~cEYI2sA*W_ePU7*5=nkWjWUpZj{pUDj3w zW=&=erwLy^UEXtb@*>vF9a2t=OmmngGp-Yv{6Kmq9+jJAc$gVmCm)bMfk)9Ih5L*w z=b0Hzdn?6sIk!>=ky8Pq=N_}#uZjeB@p|vG|mvJ(qw9@8&B4Gpx(VM@7_O*2ea{D-kDTvR#^gsAW1Zx~{lWt2AD`}v_HfCu;tL>6qa_}sdA?*5&?&4o zL+6M({9is%Zo$ub{GO+ZiqD_+pLfFUCfVU+du7k}n*i1QG1n_NzL%xQ&;B~rdYb9 delta 506 zcmZ4UjAhL;mJQAP+)PYNT+ED&OpJ_-ll%BpnfMtuZ{>f%B6V=zlbKWQeVD-1s=%zt z%;9vkdw>6oACp$zXV|=5M3@PW{NyKM+ZeBGo-KZnk@526TuCj)%bRCNu3}_dJlR>= znsM>wdg*k0`Zvk3G9nw#h-&?0dHH|H(rB&&N_$Oa7FC=qtfasn%E(x+z~E?-C9t@m zp@Cs?xrPSo0R|v%@?rJ0K=%}CxB*FD4QWR1%?lL*8CAi`6c`0wfs_O3mtdO3(I86& z$ZBBVp25h-Jh?GWc(Rw0E91(^6O?2bS8ZOWv=rpK5EUbKumL=bliw?gZCrCJt@OE%xr3S(qkI@wew5=i#zG%>E(ETpT+ z3N-Jas_5iEBWYlWXpV_dPB+tPxOartH!s~^mat2f))onT~KwwcXg6Z2$w7cJ&A qU<_VV5}SO{*>AI_OV@G%M|n%jOp?OGL>HJLe_*3SCA=JE5F+g~zlJ|uXPk#R0imH6b%!qs?GPWBWjVw^U4kH{os zMU1G%P0kd}1}XxX_C^%1X_=y4lh24LZf2DTU}T&>IZRSv@>?;5$z_r;@(UXp8Wxxd^EG@=3fAcBnY{tpF z;*){KEfjYHlC|Q}jNF?|WCa)*mrQn*i)37~dA^(tE8~LAca$v{8Ru;lRV`s*T)eqU l^8_#qHV128StP*lQA^JA(QG^2vvW=Dmgi?~Ha|Dl8UQQ=l579~ delta 332 zcmcaGndQo4mJP)mjI%eFa2#jhU}EB8W@Kby-0aL7&CK|7@_d0j#_N;$1ZPTb*);Fn zhi4Dg@2GE8VAf>ja9Z5-cgFsU@A@0-Hy;$d$;dbls7!qFCgEy)N+-LE6fsVpyh~&f ziYi7_11Hysc}?CRst8mGGV`Sv--Ah}XTnvr|+3$Z{( zAjb+QStSv}xM=cq30cO)o4-md1qsiVGGd&&`J7ZX<7Puyevl6w!^*gD z^9^MSM#cr31yxH}7?*5r(>%e*IDfOh_LW5fCNq!onm5PqP1N+|&#KnV7k$_xYyBs*lw$d*h2Ej-4b<`{g#M#~-B^PbH2n?p03 zO1DD2RH%3}lo?I`SYA~-nQToGSiyzj;ayxPTP>{5=B4lz=j;hbA@4*Uue&R3035Np z*s#0^Fp5!SU^lSdd7TUrOf~F7bl%8!Lg7R4q&tM|E+-6fq>Lj@KW@0H@&o@}#sjTv z#j~IV6>oVJjMXVP>%9o~aj(w~518MV1VN3*;~J6Zakb8ZI|t36GM&E_$N^1G*>YFI zBu;xuu-_pIQqFD6n)f4mN;r7hV`pt;Mu0~c4@7u>RUKqS!7zop?EK*;1d_~rY{$f% zy^TS3^i)4^-eT1sF^5uUxu-=^d8n5=E`=Qb&+9Y>3gSOITQDNVlL@yIUECsP>y*Omjf&w8TTA+Q? zqz5ae_TqK+rZ_ri_5wvcD9PTx= z%G6DTium`bmse7mOg^()q68*z%o_POgm#OWowvCur1AbLr7+i4_Se?hQe^<_u{c>z z;TS+SMx2Exn5`I*>;I!SI*yZ0f?op5@si{8Vi0ngMUS%yI#ua~#Z2x%D&xbBA_rb{ z$z%m-7f7!bhI0|op_4(H!SY61{-)3tBB-|nYxn2zkj#cSbVPtRm``wi)6-;_0o^bNTlwO)&5K1(4e&X8-^I diff --git a/crates/ide-plugin/tests/fixtures/hello/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/hello/dist/plugin.wasm index 612cf46bb7bd493db1d39a5064e0613046ef1dce..046be405603b52a2588a4eb65c96b39e65592ae5 100644 GIT binary patch delta 269 zcmex$k>l4zjt!}1Qg@d1JfFRF#lo)oRt08FW)7$R$1k2g+Vb{w&E|TuYn=Gx^Bv@w z@yV}nmSaPgmq0TAf#+UUba`a^xBEX}M3HAib>GH7CscV<_fOs!Xw&Q&yxlXHu`^pB hM)>ibl?$D^`VD{SEZchh&ved%jB49C_A`FU1OS;LjdcJ3 delta 269 zcmex$k>l4zjt!}1QhSbHTJ!YT>BqMjS{0ZznK_*Lj&-b9{Ot4&_RaNX*EsRX=R3$V z++Z})$|h$7F3>b{MEPN?#z?w`Cd(5Bflc)MpXV`sL& gp2br_&Ge5)^C>f#8tE6ZPv<xT6ljEgsK;JC)Z$;HgX$jHRZ$h5hiSAd1_z~lvjd5pg%^9xOtYJ0w+ zsdM`5EB_f<6<9QxC7izheS3aq&!?pUllKb!Wjwigw{RK<86T zPC=1z8qn}bC<;-X092U0IZr8ok#XVVhw9?&23aZ%KrlH(QEBphxT6ljPo{c;JC)Z$;8CP%*e>Z%(%IqSAd0a_v8hFd5k|N^9xOtytS%v z|KXP#t|+%EuxK(%I2~{5+1|Nx=I^A*`-J{7p4z-eIE{nx>SSIy@yS*)O~}fbHJLdO z$~Rw=F=J$$15`K(x1z~A<%*c5GEIJ*MmH+?% diff --git a/crates/ide-plugin/tests/fixtures/indexer/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/indexer/dist/plugin.wasm index 0238937a4d17307d9137a60dc21024f605508b8d..f4c49c9cb2c3b7e01b8deebf5206807dbab595e7 100644 GIT binary patch delta 475 zcmdn?fo0nVmJQXs{9MdTjEq18BAA$%Hh1xguu6S7`|8)!EzdUoVQ5ug)@0^znttWO zo9k0IE*IRqL+B(UKKa=qta#;jiLT~E(a(rt{^WZ3e<;$Z)&r%zCbI}DZe~*4$jH*k z$jCDJeYeDB7Znpm#>JB>RTU<0R#KQeQ#D3@X+uK;g93x&ie(2H7_t+!)e>9wdq=Tk2ph>=O1Ve&zBvB|HM76Uc+E4u;7Y-Q=mAC(P(EO|rk$%k}x8P`t!pc~1! zcC(kBFEiu1$ukTiIoE+*!0c!++1o&Cvx?C~M$Yw6A(P1q45cRDFg9mgzgfV9gPC#p zW=Zoiyo^gWKXb8QWL&ga-t7l7 KxViM}K_>uVIKcD( delta 476 zcmdn?fo0nVmJQXs{7gW=#mvaa#0UgTjGMc7MOdXKZ8$mg+2)fys;vsln#>$dS2jP` zc<;jb>+cyh?+`l4h);gD2rFLsU81Wwk@Yj8nm@T-{vWb5n)N_wugNUJikq1fH!@CE zQBh!0XPCUvUv#pa&Jy;84Gj$p{M=xEg0ARfVO=rCg_HN|NKbavHDp}4d7V-yBT#@v zMPagwN(|$Q$qQ9v8CP!Judz&(Vw1P1H88H8Y^q+!xMuQl zb!Q;?8c434tgiuL7i*X@uG_p)Lz@X`#Z|2!ptB6!CLhw(Wn47*gKi|_qRn1uFEEsve8bqBami)@6Aos^RhuQv&+sxX z-~7zQf{}6AW_hp>>~ D&%nD8 diff --git a/crates/ide-plugin/tests/fixtures/inlay-hints/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/inlay-hints/dist/plugin.wasm index 943a63cefa0eb4c2d2d01603d9c9bf40d66320ac..4b3f14ace642698d0e024c8008901e9cd9dadf93 100644 GIT binary patch delta 346 zcmaF4h4tMQ)(z`97#D8dz;T;}lZ%~^nURr+k!kZ3USk%gQs L+dr@~Rt5n8gJqOc delta 341 zcmaF2h4tkY)(z`980T!>z;T;}lZlI+k(rT^iE;B3USk%<&dDbP^B7-FHW!*IIcMLD z-cK{P{!(mJV9{ijaN7QG#ltgq{x-XBekL@5jq&Q_L}~HKeUeSc3Yj&TIgk`;NtrP+ z&H*Z%gj>;MUYR1ssgoOIP}DG@7&KW&HXEoWQCe>DJQ_)8_T$^X JvNKi&0RT)KkqrO< diff --git a/crates/ide-plugin/tests/fixtures/jobs/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/jobs/dist/plugin.wasm index 8bbe87f6d5505b2111da67c7951032b3901dc85f..2400a63005fa5a537cb881ac4548deefadd4edaf 100644 GIT binary patch delta 1176 zcmbVLe{7RQ82+BScKz1Q@Rf}**U7%E3l_5((FS#HvM$ic#;|NK9Zp9yf!GKp_=jQ? z%a1KOG0eUr<(G4H%&~Mr=WRhsS2_uCAkLu<6=EDQWLrW^6cUM|cr7NT{=pw!E^qFA z?s=bk@44LRZRsbsrH3zA@r$@<{Y|xMoO6IdWw!?Cr`!q$gPAehnsUd?VFIA?*$Pa| zq;l1g$N*7e%QT>#n)5p{{@9%s=1j44N;w*EWQk0@8aPPL6s*Jv5iWR^qk}NN;QvOk ze!iPwKOJ_AKk^86tb3~%vB5Nn%Et1{HB+3H|UqBXBE$+_$&y92by>ZJ9&mEw5N()7C zMYj!GS`|vJu1a`zgEavcJ#i!dY@%3KT^~ zuQ6E>UBf`bo_c&GtSeQp2_FSrh2(K%Q+?e|5qoMDaGu7R8rgXty?$tk*zmN4VS+X{ zH>OV{^|&jC^j95%udU%26^}m`VK^yBh%LPR!O&DcX{w{O56QMzLt@HqurrX=)M zs|RPqh1TmFW8&+!QQ$LiU}rU#&px&5y8IH8?Pkr$6~*#WV5^Qf{-90Um$ZjDSVn;{gB$fwJvwM&DY i&G*{8TTWfMvtxzbqaDo-L0yKlfbAOWM=P(vRQop}v9E>z delta 1119 zcmbW0ZEVw36vq49+qM6;C@me(Y(xHC25Yc zXtZn$<6JV91ABovMeG>agu>~v!WkUJlF0-Uo82|0>y=_;f8=Kzc_p|y1e&nKT6L6SHa|-Y| z*XR5x(ZkhGW=foLKia{3D@!R%ULL~1OV zZ&SHf5n2*f&0rg#+-KwZ1E+KS=X7;D0*`<`Sf0sQD-WdLD+;XEX`-m%VY?+Neg^|I zZ&lAM3bX4*msV9PDzJJs^+0tM<>wbm-UE*Fb-z)dnpi2^I5kkr!6HEflePg8;`j&4m~Vle=pJMkulE2|CoZfU7p!gk|_%n)JD7v@(tM z1fRw*j|AV680C^zP6(W57o8 j8E+i2=Dr&LD@apU7B}_TyP=h|WZZ@hQ{S@Nu&(_F3h1r2 diff --git a/crates/ide-plugin/tests/fixtures/path-events/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/path-events/dist/plugin.wasm index 84a342d639ef0a1214dc1b5887901af2451edd32..85c41c4771a277da34a842eddad278c7ea2af28d 100644 GIT binary patch delta 395 zcmaEMob}mp)(zbPT-?k|jEqdoj7&_ErwXVru?uY8Es(~{XuMfTWIChN+CN9W?cMtP zfnKWuizc&#)7k6)-t`>6vEn|%=F6gHjEtKnbBX^#R>iEz%z>;*PC}d&pS-`U3KP(j z5_vlyxmo@WvRXz|vnC%@beQ~7VIQ&*H0yv$jxuiE+^*Eh!gy;kuet`1G*dU)yjCNC zk#X(hf0_!DGt?C(%V~u$uAf}2rN_8o^CGRKASn+WBgVCxt97`TCwHhH019|&xB zMBWZaZkE4;qLvZGtjPxz9VWk2*oUG7)jFV(ql{}dw=1=>Fy5TZtF8eg&D4!1-_%f; zoS=7rarIdk!7+#x5VZabrVLQ=uV)jpBf>I8z=i|>M?HGT&uYh zB&@7$#J;+rp@D&iaq>PbvCT!=@0d2X>hm))uAMy9Ad+$I=Jy7ojEtK%vl=C_F>ctL zVPV0@xPJ3O%OA{)TQ<+KJ;BJhZgaBz8urP{-L)q3yU*Bs(Or&(@z&-K-t`9rj88om Y+OAwz^{MMQ<0{cR=eF1LFs6qC0FBM5+W-In diff --git a/crates/ide-plugin/tests/fixtures/semantic-tokens/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/semantic-tokens/dist/plugin.wasm index ccbdb011fc65f26f00bbe98cbcc0200d1c1299e1..126b88723e227dbd6c48347b0712e0af13ffe660 100644 GIT binary patch delta 347 zcmbQUjdjj8)(suJTwKgdjEq3U$h3J9uPdwMpUY1loZj(izF?~YvnDf#)5OM|*S25W zb$QX|4?Z2o5UgPC#l=J!@77#SCD-eGh1l)#@%$vsC-+6zu}I9JvEYT2UgOW7IAg8`H6 BnRfsH delta 390 zcmbQUjdjj8)(suJTue+{%#4gojEsz%C-J(nN-kY_XXT<33l1{2Dlls@b2!~Qv}@_T zmD}#`*!)4riw%!-u;eL5Jkn;;Y$(!~ zLqh`t|KvVZ@yP|6T8xV)8)!8FI93LDz(7=$Tz@)$=Fb^!mT697(SFRhYO{q-3n%09&3jEP7#Wvs{$}=rnQ_hL o_f{tu8JBL}VRQGCz)}%&Ri~yV#<+#+p7`F}w`2QKcE<8x06!_7?EnA( diff --git a/crates/ide-plugin/tests/fixtures/storage/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/storage/dist/plugin.wasm index eaaa37edbab1911cc3859ae45ad2437d67dee2a2..acb7a86ff3db4f41debf6a87a864d9defdabdde4 100644 GIT binary patch delta 375 zcmX@Nn&s4LmJJ^{7-w$&#KF(X!OhIX$jHRVw3(AHlbL5?4|6*c69ab|BV*m^6Tn$0GH64J^%m! delta 386 zcmX@Ln&sSTmJJ^{80T*O#KF(X!NkPP%*e>ZxS5kLlbL5~4|6*c69ab|BV*m<31SM9 z=LtG9UZ1={LVWU1!6vEx1CJ*heSduVONLejW=&=er?zb^OJ=kj`h9ux6rm@~jPrmh zySpu!Cjs0vZ-1uD#$Y$2^MSzLZH z;bA$&n>XVCm+|(n}fH=YvFem?m$K7oR*$R+Mr6<~6d}jGOrt_!$`&OqN%S zWL&VhQqhK$aq;GDY8H%)i#ESkFJWO^wmC)T1S8|Z&ANJND+Tx;NCef$>u0h_H?}Bp Md=K8d_`13s0I3*~&j0`b diff --git a/crates/ide-plugin/tests/fixtures/symbols/dist/plugin.wasm b/crates/ide-plugin/tests/fixtures/symbols/dist/plugin.wasm index 255d942b8e216ce20d54c54f28a0cb3716de87b3..f1ad28ffa320fcc2e4148c50cc73a9e30bdb1122 100644 GIT binary patch delta 1965 zcmdUuYfMvT7{~jZ)6$j}JzUCdIu0O4Zp8=_5GWjm!q5Z(hXMJZq8sZ5(~V>%Mgap( zM4;u7i((wiEWuDH@H$bz0Fuoi$qd=Wm@RWlrW+yQug^G?#9_x%3< z=hi-FzRRV`=F)3&g-=Pc>ur^<1~^W~1Fr`8;^>`oTxb-wd2#ds+?*dbP;eTJ21vb7 zq5=~x7#g7g8@wmLhWS3(aDjCB?Bw;oTShAsX3103N#}6=3*P?|uy<7xe1m_9cK@rk z>87z`k00k%i^@>mH}%Zyx0Um~{nncb99@lY9Cy6Bq!3vFl&8CzytnvrPMf|9oA8a4~l z2;t9+v%LC5_z>8!IwC-Auc)X{=*FMl?on=-L+dFo{C--4dSk=VR$$q1Gf|oN*cb`J zG_8m$jS+Y#YWLEBW&MzusAdjs;E4?tK9dddss(yVE`bKUk1n`UZcv)SfM`SH9j581 zW?uyFmTDeMn`Kl>BitE%!l+zXV6@t?`m`Snr7Ib&!&|f;E7Ro4 zZcJ-tR7t6x(X;3tW61Adnwn~^OzUJ+&ZA|tn^8HBhS5Go<=)kd4q|zXA##*y^6#T! z+9ad$1WHD~z%d$ehiP(Uj%nX9Dn|gL_X+>fAAl#~PeUuN-jwduE&ny5O468x9>-BB z*zwRNJ8p|h!-FrCAsx4^ln?n$nWG z!MWjjzyqn?csI3BL6_VZ@ z1j3jjIS74p9TgO=F$>N&XFG7%e%=pn$0pG@LtHFc;?P-hr4FsN>o6zYm$O$O#QVGG zbe{mIanxia>hxbZ7{R$$3SflfW?rD(l0UZ=@i2q&e3?O zaB&Kem#&nXgE(QxF&-xjI_|tw{I8+x=~1wg`vnmIeZ;eHfrm>(*qy@zVo^~9v=K|u z0>EWbx4)C4BW)}W;bDjrzWJL9hDp}J6xnDg3!+9+cFhGWc<^uuSjgSOuK`@aEk}N$ z$ar)+5K?}0j)!aH(6P?|dWlrktmb$HepPFQMtuEL5S``ZsRD3sa<;sV(+8?V5SlCT ziOCOF)N7!H_|#W%?q{AgoOKwqzNH&E4fVI-=ax>elJ~5oK&BgeI2>zQ3m@XoO*wFy zBs7=v*wPe62G4{6w32&g`*~_^Jzv`)#ODoqc+LI&wO>MP`}-3?nFG-&FraREln&k6 fk~j8=Ch@KPr3395@PQlfEs1#$JW!MeEy@1?J+aHY delta 1977 zcmdUwZA?>F7{~jZ+tQX6y~Gw2MQ#C&A_bMY`U1#BUJPnP-840BGrn#`NVaH}jZKSz z_zuWpDb#F)xh*Qy7LHmJa3G7~7sE1_WzK!j#ORVS9od_v)1BLL79d%cecVafp8o#- z=Q+oQO*oB?_%+Z<+u}C}#v66LE|pWBBpKu;oI5q{e*(5lbHg3{Q}Rz4 z3U#~O5AJ=pphi;97AEKS-#XX-{OjwXOzcZUQX}AVDGql{Z~A8=ot|U`_!w780T}+5 zoYyUF@<9l z^4_@Eu^Y(2!PG6_#jF{9<9wsmpc7_-n$<6+{RWRvJ7>(9j4NkwP8ay_XnK;)r<7v2 z_FwmM(JDh1{%-Y+t_Q~MxhLZt(!~>dMjOXf)00txH?3Cs_S_@_gV-?NWxXBlN6RER z%3?Og8&aymCw7NZ9iwra-p8d`X6q2wG)yybZJ1LfViKp%uqw;!c)>M2(_*=HuwHo* zMphO%t>sk7Gm+CqPSuP~;M9wcSv@VIH6zzfajInz22Ri7Je%3k&NXERdahmKR9QpE z=@m|u+O?eabE=$L6sI?_#b&nN=9;ntHP`NPszeB!-p6}3bNoZDDG|W6$24ZauYg}2 zmXH=KXI&I3uvx-gB&lShGa1Bya#s?F?d;N245m6oAFe5Ujd=rwc5Gc(fDa3i{i`f0 zB0d+&MG0U)u)CoXJ@#VL#c;ev);YzF@Knv>hwc99hXB<4;StM{RjEvMsYZIE6H^vF zU>Wp_SDQK`VY2vl26+$%a~9)giw`nO=8}DEb^nq>Y`!RaxxOoG7sL)coc$AH@8%Ru z>}-tAZAtn(%vExyPiYg0NJKmnvC3+v*h>d;KLwV&B5ywXZp}Nx(yfrc zgbqy1Kf&f5`4`xH=dx-x|8dz3{G?<)jV*pcqR&Takb6~VIhKG=>+EozzFKmMC8Mx% ztDyIf7;Itvz-l}Av1(f(RhPB_v}0h61KMfy+Lr++zP`=@lwMxv1h_y`U)i9B2Kv6k z2FA!e3Gyc8O1d{nCJuHp5LrO<(I*?z0fIDfQ%Ha-G-2~v0UEG;YdUzTcWVgPJIJ&B zG+~A1y)i?8KDwi9SOeFnrX>HtvO!7UXUvKb3=fjw>b@4-8117 z4!G9>(y5L61o}mD8i0pB_I3!`dL^eJ3+Eo0O8Y-@wuGC={b6#JEI+U@(S{vNQz6B^tk`w8Rfg zA>I&BG=xP(3vTa2MHB>M)IXOP{Q(nPqiiZ@MX7J5purC&lXLI8=j3khx!qc~TYI&W z*DvHajsOrKgy1bc)u7cfPx(MktglsezR@B396w5r7~3HF zzdE7+>QuS5F9M8OW~2qNeS~F-jytZPi9U}zA$L$1A2)9YEh|&!@-Sx*w3@OpWA%sm zhOnC22^B2&)vWT{BmrA01=J)LM0Y9^sjR(^dL@-zAOhjrln}A1?fhjbC7%PWM~>(T z-V>MNhLn(*GvK|o26{Lp31AF8sbRq(DnZ37T0v#i+j$R$i$!n^9by`*+AVHk=nx|y zkoKqY0N3$(T0X;s^d10A-YW)8LUN`$$rH$R!pNP|XUaJw^9md$d^WqtZ(9OhLg27mXjeg)CTXawMY zNLYbk3lhtdiH;q;^lo)EfpN@s=WE7gDaMqn!e{PrGNmYSuto>JFz941uCF!07c8sI zXXvw;aiVsDO#9P`GwFOx=!CDzEqrBr+=v!5^A6=%li3z3aX%WtNfDa>zTuj>-3;Az zo9U}McJISwuZUM&ya)z)8<8_>EgSa$yo%J08PNTHg7ho3Gz$ Xc6q%!_YGLQgYWnUeK&IK&{gmU!=;Ur delta 976 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 literal 0 HcmV?d00001 diff --git a/crates/ide-plugin/tests/fixtures/web-pty/dist/plugin.wasm.sources b/crates/ide-plugin/tests/fixtures/web-pty/dist/plugin.wasm.sources new file mode 100644 index 000000000..c1cf5b704 --- /dev/null +++ b/crates/ide-plugin/tests/fixtures/web-pty/dist/plugin.wasm.sources @@ -0,0 +1 @@ +bb6e1eba6b9f28ca769bee0c6dad9ceab536d486efcbe0ad56bbfe621e2d7679 diff --git a/crates/ide-plugin/tests/fixtures/web-pty/plugin.toml b/crates/ide-plugin/tests/fixtures/web-pty/plugin.toml new file mode 100644 index 000000000..3209898b7 --- /dev/null +++ b/crates/ide-plugin/tests/fixtures/web-pty/plugin.toml @@ -0,0 +1,21 @@ +id = "web-pty" +name = "Web PTY Probe" +version = "0.1.0" +description = "Test fixture for capability-gated web frame PTYs." +engines.openidea = "^1.3" +wasm = "dist/plugin.wasm" +activation = ["on-command:ping"] + +[capabilities] +optional = ["process:bash", "process:git"] + +[[contributes.views]] +id = "terminal" +title = "PTY Probe" +icon = "toolwindow-terminal" +location = "right" +web = "web/index.html" + +[[contributes.commands]] +id = "ping" +title = "PTY Probe: Ping" diff --git a/crates/ide-plugin/tests/fixtures/web-pty/src/lib.rs b/crates/ide-plugin/tests/fixtures/web-pty/src/lib.rs new file mode 100644 index 000000000..91eefdb01 --- /dev/null +++ b/crates/ide-plugin/tests/fixtures/web-pty/src/lib.rs @@ -0,0 +1,15 @@ +use openidea_plugin::{Error, Invocation, Plugin, register_plugin}; + +#[derive(Default)] +struct WebPty; + +impl Plugin for WebPty { + fn run_command(&mut self, id: &str, _ctx: &Invocation, _arg: Option<&str>) -> Result, Error> { + match id { + "ping" => Ok(Some("Web PTY ready".into())), + _ => Err(Error::NotFound(id.into())), + } + } +} + +register_plugin!(WebPty); diff --git a/crates/ide-plugin/tests/fixtures/web-pty/web/index.html b/crates/ide-plugin/tests/fixtures/web-pty/web/index.html new file mode 100644 index 000000000..4040b0847 --- /dev/null +++ b/crates/ide-plugin/tests/fixtures/web-pty/web/index.html @@ -0,0 +1,27 @@ + +PTY Probe + +

Web PTY Probe

+ +

+
+ diff --git a/crates/ide-terminal/src/lib.rs b/crates/ide-terminal/src/lib.rs index 26d7fe3c9..098ffcab8 100644 --- a/crates/ide-terminal/src/lib.rs +++ b/crates/ide-terminal/src/lib.rs @@ -91,12 +91,45 @@ impl TerminalManager { key: String, sink: SharedSink, on_output: Box, + ) -> IdeResult { + self.spawn_impl(options, key, sink, on_output, false) + } + + /// Runs an approved absolute executable with exact arguments and cwd. + /// A missing project directory fails instead of falling back to the home directory. + pub fn spawn_program( + &self, + options: TerminalOptions, + key: String, + sink: SharedSink, + on_output: Box, + ) -> IdeResult { + if !options.shell.as_deref().is_some_and(|p| Path::new(p).is_absolute()) + || !options.cwd.is_absolute() + || !options.cwd.is_dir() + { + return Err(IdeError::invalid("a program PTY requires an absolute executable and an existing cwd")); + } + self.spawn_impl(options, key, sink, on_output, true) + } + + fn spawn_impl( + &self, + options: TerminalOptions, + key: String, + sink: SharedSink, + on_output: Box, + exact: bool, ) -> IdeResult { let size = pty_size(options.cols, options.rows); let pair = native_pty_system().openpty(size).map_err(|e| IdeError::internal(format!("openpty failed: {e}")))?; - let wsl = if cfg!(windows) { wsl_shell(&options) } else { None }; - let (shell, mut args) = wsl.clone().unwrap_or_else(|| resolve_shell(options.shell.as_deref(), &options.args)); + let wsl = if cfg!(windows) && !exact { wsl_shell(&options) } else { None }; + let (shell, mut args) = if exact { + (options.shell.clone().expect("spawn_program checked the executable"), options.args.clone()) + } else { + wsl.clone().unwrap_or_else(|| resolve_shell(options.shell.as_deref(), &options.args)) + }; let mut env = terminal_env(&options.env); if let Some(msystem) = default_msystem(&shell, &options.env, std::env::var("MSYSTEM").ok().as_deref()) { env.insert("MSYSTEM".to_owned(), msystem.to_owned()); @@ -104,13 +137,19 @@ impl TerminalManager { if default_chere_invoking(&shell, &options.env, std::env::var("CHERE_INVOKING").ok().as_deref()) { env.insert("CHERE_INVOKING".to_owned(), "1".to_owned()); } - if options.shell_integration { + if options.shell_integration && !exact { integration::apply(&shell_title(&shell), &mut args, &mut env); } let mut cmd = CommandBuilder::new(&shell); cmd.args(&args); // wsl.exe takes the directory through `--cd`; a UNC share is no valid process cwd. - cmd.cwd(if wsl.is_some() { resolve_cwd(Path::new("")) } else { resolve_cwd(&options.cwd) }); + cmd.cwd(if exact { + options.cwd.0.clone() + } else if wsl.is_some() { + resolve_cwd(Path::new("")) + } else { + resolve_cwd(&options.cwd) + }); for (k, v) in ide_core::process::host_env_fixes() { match v { Some(v) => cmd.env(k, v), @@ -770,6 +809,22 @@ mod tests { all } + #[test] + fn program_sessions_never_fall_back_to_another_executable_or_cwd() { + let h = harness(); + let mut options = sh("exit 0"); + options.shell = None; + assert!(h.manager.spawn_program(options, "test".into(), h.sink.clone(), Box::new(|_| {})).is_err()); + let mut options = sh("exit 0"); + options.shell = Some("sh".into()); + assert!(h.manager.spawn_program(options, "test".into(), h.sink.clone(), Box::new(|_| {})).is_err()); + let mut options = sh("exit 0"); + options.cwd = std::env::temp_dir().join(format!("openidea-missing-{}", std::process::id())).into(); + assert!(!options.cwd.exists()); + assert!(h.manager.spawn_program(options, "test".into(), h.sink.clone(), Box::new(|_| {})).is_err()); + assert!(h.manager.list().is_empty()); + } + #[test] fn output_and_exit_code() { let h = harness(); diff --git a/plugins/README.md b/plugins/README.md index 4695c798c..0b9f307e1 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -962,6 +962,45 @@ sends what Graphviz reports to the plugin, which publishes it as problems. The b checked in (it is tens of MB): run `plugins/build.sh official/excalidraw` before installing the plugin from the repository. +### Web frame PTYs (API 1.3) + +Packages requiring `engines.openidea = "^1.3"` can exchange JSON strings through +`openidea.postMessage` / `onMessage` to own an interactive PTY. Declare +`process:` in the manifest; the install dialog shows its high-risk +permission and the user must grant it. The host runs the exact approved file, +never a fresh PATH lookup or an implicit fallback shell. A shell requires its +own grant. The cwd is always this window's trusted project root; a frame cannot +supply a cwd. Environment entries only add variables: replacing an inherited +variable (including PATH) is refused. + +| Message | Fields beyond `op` and `sessionId` | +| ------------ | ------------------------------------------------------------------------------------------ | +| `pty-spawn` | `program`, optional `args` (default `[]`), `env` (default `{}`), `cols` (100), `rows` (28) | +| `pty-input` | `data`, at most 64 Ki UTF-16 code units pending or in flight | +| `pty-resize` | Integer `cols` (2–500), `rows` (1–500) | +| `pty-kill` | None | +| `pty-ack` | `sequence` from the last `pty-data`, after consuming its data | + +`sessionId` is 1–64 ASCII letters, digits, underscores, dots or hyphens. Duplicate +live session ids are refused. There are at most 8 sessions per plugin across its +frames, including pending spawns. A frame controls only its own sessions. Limits: +256 arguments of 4096 UTF-8 bytes each, 64 new environment entries (names 256 +bytes, values 4096), no NUL. Bridge messages are at most 2 Mi UTF-16 code units. + +The host sends `pty-data { sessionId, data, sequence }`, +`pty-exit { sessionId, exitCode }` (nullable), or +`pty-error { sessionId, error }`. Only one output chunk is unacknowledged at a +time. Outstanding output, including that chunk, is capped at 256 Ki UTF-16 code +units; overflowing input or output terminates the session and reports an error. +Exit follows consumption of the remaining output. Unmounting, reloading, +disabling, unloading, changing grants, switching projects or closing the window +kills its PTYs, including spawns that complete after cleanup. Pages may start fresh sessions after a reload or grant change. + +`crates/ide-plugin/tests/fixtures/web-pty` is a minimal built Wasm package with a +web page: start bash without the optional grant to see refusal, grant +`process:bash` in Settings → Plugins, then send commands and resize or stop it. +This API is a web bridge extension; existing WIT signatures are unchanged. + ### Translations A package translates its own text with `locales/.json`, one file per language diff --git a/plugins/official/ai-completion/dist/plugin.wasm b/plugins/official/ai-completion/dist/plugin.wasm index a628301c07d09f53bd761e30b13e4365dfefce7d..867eac614d36dd6ab9764532da97726e3d397c01 100644 GIT binary patch delta 15814 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 QK^cm2+_%4zbSCkC0J4~JK>z>% delta 15510 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 o%-r{Dc<+tU$H3zi0wkN%-bRpsY0e5gLl>h($ diff --git a/plugins/official/checkstyle/dist/plugin.wasm b/plugins/official/checkstyle/dist/plugin.wasm index c3a69de28ecc2db374856c68af2a4ac0ee905e48..bbd70c1ae2ee762b31ef7578cef34ae36853981d 100644 GIT binary patch delta 1453 zcma)3ZBSHI7{1TByX-C?T^0i5%PU4MOirsH5{j@*`7w$g;Skf;jA`I7$slUh2)es0 z2(mTm>&(>=;I9b3VcT{CO6G`6}##k6kP$UTq201DU zGI(-ypFZLkAlVR7xJTZq`w5koQ3Xm)XvSy!Tta&gex{2O?M)z-4m~r5%#$2XUJ5KUn{G~e8yjhE+Nmdr|4`@8rjKUW#B(#+053h95?JsP zrJT*Yj{=N`7^QzKU_N*Ca*ta z;@-K6t8Bnddn+ffyLNuLGG9gyPjSqKI9596!aPo5xvFGgl5PErQIaYtLzG$mk?5nN zd2P1g#h66A;AEz_vLQM|6R%d2T2QRJ5hspIAvHB5Hy_vZjJfVJj1b*k9 zov-Rp&7a!6i{TbO-26yJFK^lZij3+lEziNtC$u~Q?(oz@oqBf9&WDfo>)D{4_qOE- z3QahXBsdFBd>I5Mg`HjwC$BhN1oYEy?cE}Eu44iI;PGdMWOm=qqrU9`Zqm=+y@3Xr z+8K`rRM=T6{yREXV3@yfJ`W<;aN!+1;Jp`I5#pW7yWAo*(sfPX*KV{Ra);B`z0ShQ z#u`+e%`25C52&I0h`{rDRxoVmCvR<*#k?2xEfafNUjc@A_?<*x2U)!{gykBqQ#}2! zHyuOteE+O5fBMHMCX~U%gj7QY(+T0DC{Z5z5c;Yw&X`%EjQE371DVv{pCptc2U5g7 zeV`H}{P;knENrswj~j(X?JXIt;t1Elf<{l44vE1`mb8K}Y=%p#R}dQtm;%DqXwx4Q>_g+xE z$WnZeHwX$X%T{Q0sM~D1azoS!0?xKvSvKjSEw~p=G3evGm;M0$XrA}od3K)XcYeR; zoacGp$>soebHJxh2jP3ZE-20~p3NSw6%_9*&P zDPrZ}w;ue`dSUW>64{ompw8rH@cTpI!YMjsHCm`N<$pN&QqyWbc9p4{E+d9I(_3cB zOR19IEcskIkg-~SmqDUeevY8$mm6p@qhrpNxfzcwegO{J@Wi)sa5Jd+q9u_GO}rrM z6fj0CdsfDC(iqCV!7e;x!n<+yP!69djM-=E%c&%LdIBjq3#n;&=}hDt*}j|=eBFuy z;1;P*x^Rov}qYDO9#vm*O`%VyzYRPPVm$25Z4y zuZB+U(QM%3G`K5{uG^L}kCnph$7x_!9u3(iC}Zaj#(P#R9fQShn|y~NcR6|JtLtHW z;PvV)vhebX*J7Ffl-DDPWlLoy=Kt+oGWpK5rS{6@6jr4&tBp=pEn+qszh1Rb!X3W2 zx(LF&v3m{p#achf-#txaS)#6e1W{ymB$M$(Fx(V>BA@T9{}^oCO7V_jVR)5eBiLOl z^*0pz-~Df2I$0fQ{JH&QA^3xzedk#{>Uh+9oeUHF>tjQ)J# z3lpP<39Zh2J>mk?(jXi_t=c9d%0H$&i}@*#>zq;ZQ3LGN+=-}no|aJt+2K7P)7su3 zPz`Eku!!zgi-U0-b|*qmE`E_Z=k`!sVd{tBNK?(>D0L2oW1plp#3C&;Ld%>flA>1x zh2o?5%5OWjM=lm%SyM3_7S(1!&qo6&Ifr&vmey~Y$JvxxJU`eC~d+yY;EzW!3z4%j>!#l}4zUTl8R|A*LusAz@^;6eX5~ZK6?O z7d&~Xyq6DoA$8WfBBs%*DP;7JNFY5(VD%DRwVD+p*I}69{O5Q6XAUz>ORBmhReQA- zp0XP44&_EQrIY{=AdZ3W+|vRGXow?rOf4ZADu4)Dx=G|p;XH7B>*=3DeIvbef7T3g1hzp(8bdA4FIF~%P_p&%(-F^ zTiSYraKq%lMamQ6LR;4-tf`JlW1%oefL1OWK!=USJ5Df!(6#WPuzVQgjxshG!%#9E zcY=BI&Ts;z8BL6YhpE_P)R@5Ax*IKHc%+Q&(V5VV+896RVaAvyN5`*Xx2tSct5u-^ z?1=SX@}4BX#K=JC$GpfS=)>oc*<{d)=K>5U2Y3+4h9{#A5Sv5Mftp$3B!D5jvNxR! zS#hpsKid*t?+zVoIHjLJCo4$%>b94uP=o5JRH(qLsR?+%Ow%q?QodQ=;q&!z#%${Br4&&z K_Lv{S`>elnp>*kz_l|80uPYC*>hxCU*uRjv966`7kZTF80_j^9)d+t5wHjK-!j?103 z3UIMH#eCT`GPOb|r2qu*ZDbK$w-EfyPN@x+Wn(W5`UJpTBq_1Q#_RY&JgjoEtg;aKJO)|;+lsL{TFCj6wm z7f1>JQS4E)8laWEi>V;c$@axs0bDqy(}M%G`WR@#h5A@phx$<~QY@V6P4TDrs{^Q&>}hJT z92F)VeqNFYw=r^QKHS2sOShAD5tk(_5|mC+6obM-u=}PF7i32fr-<(pqM2dA0|_|s z%VHhaanH3V%rz~CE<9tJ3Ek|v=_>GGUe-Ktvhu7FAQu6ldOC{PW5gw**s+dxF0C{T z1y2;y$!qo!r32t8|yf zD*nmoTo&<&H;t)x%@W`;W|r-O%j`;hsBM_)CI20Vo^&-I_QP z2hB|Mmg;0qbh6bR98J-J`4P?y9&7so3Rslq~bUmKQKgDFrWB;){W}i9JLT z(P%0dQ6Xd$sK0qlqJqkY(n6t3B6Pu$qL*^hkow(K)S#En!#BhH-+c2ibEYShFDH~e zb87fV=hZH*>YY3RAV3@++C7bg01fiW7GP00^NA%#Dd_f|0ba_ zq(;$7fXD2|-gsXhiBCh0Y^B3CO_V|g@s-hli4n&<9yl08 zgcu^|*sGP3t#~)W4+iM7h%Nw%m66d5Z$#c^nn~v8S{+9cM9x4sx#6&y6FFH?E)1_V zYE&X8jG(8fCgUKhuMgz}=TJ^|FBhDCIN5tM4c<)6>#1tj_I8{$wJ{4-VaZB|fCj5g z-qbBh12BfZ(FHI@Yop6}Sisr6Rj@#h#*_l|V{hyND|N(WK_6X=t5v`tEjsW5pcf62 z5q_XWY6Lq@OX)C*x`Z<@LR%6-c@`cfb?#VS9g&A%!yu90a^=D(J)6=5u!0?_Ihc}~ z>BuPi57X1G0obW6JsX&KOlG}i)UjJ$o`iCCgP-^$Q?GQM4S!q0sc)7R*tGa;Zx%4e za)qJIa-EeLbMgo~^UU#6tR&^uF`L7=T6agUNMwOILR)Ss+le_ZV7GIr8a22pR2#3w zdHq1CSH4cc{KXgcG5lI+U@pB*SP0=cEG^21&-kb)2o~vFQ7lmZ;zLSoE(?Jr+E@0T zhh=)XVh>gp}@+%{P1P`hlt8hKZR1X>cY9mP5g%ZL$J%gZ2ve GuPiJrd delta 989 zcmbVKZAepL6u#%Zb6Ruml39L~UO%QzQ`gECM9pa_HN}r=Gqco?q|H94NG!w^6$lo} zq1KNyK_bK`=R4F~K@n0BHi@Drv(!QhA%Z>?qjy^-_M;!&AI~|Q_j#WC-1FXkm-MMi z+A$)BaXKpZ^^+6t6Tkxyz;8h+0)$2_GV+j$)gc|whzX$&paDOJ=EE178MccDD=v?S z{BN9&I0r+BVoR9w}!JQI$74MhcS9k4|tNzU0)>@h!IiDxZ1n*QWMAx(w zSBOjSY|Qq5X^1(s(oXF`VW`VlN3Yo|WUYQPGFAKu5 z6jRUw#t<$XXUDAC+*P)Y!-k}w7{TrqF@3Q4Pa8Aas@*M0)i$tWvpQ4iVJomDB^V#6 zmO=|os5%*5N~mRoh(r-f61S+G9!ny^Dk4O)msvS|%fM|bXBG*I$v`j**S#Ef?3;8n z@iH)dU6O|3&7@Z5Sekr~lI04R*X<$ldNuAV4aJojEp*dLO$84h@JZ@k_(0QF?FQ(@ zHtiT2HLlKs8+2s#VF}!#rnUD0dQjA<;45y@oq+Gyugifh3`;uz4qBfU$Ft(dxabq& z-2&0~z|6N3{d3MNbkRK}?DGKM>0nMiF!SWx8b#OdpaWnQ zLHL2axv|WBI5!Vi(c}lSf`)iuz8rPnEAc X-P-*)1AfHWTow?)w|l|@!)ty4JQQym diff --git a/plugins/official/graphviz/dist/plugin.wasm b/plugins/official/graphviz/dist/plugin.wasm index 2fc3e6e28c7d677e384c6c03a634f6af5af83de5..b2bbb98176fa3bce3759941a500f880a42fd723e 100644 GIT binary patch delta 713 zcmZ{gUr1AN6vuad*V`7ZywDO`k#}pj&0L!WDkaM+5+wy%G)ST~8$*{x^b{6sd+22` z%1*@spe6D%HfSSd8NaWG7e?za;dp?%WuCYYeoah+23-nhEnF) zS4R{gCkb95g3D(=%aTOTqLXk69E$G|;sN+^h;d(xusELapf}0S{gXZ^ou<`^{`M y?aOZ9;RD`VaKH@aS)9Tnxfo2-iZ7u@LhwN7ivHq2^ib=y$mFQa5*ZJ|qU$fLe<0uh delta 714 zcmZ{gUr1AN6vuadx4D%oFSK-N>Afay^G}XIvnkdjBBCHCNl36}W6rXtsK_36d*~&I zTBmG6(Mv>w%GsG&FF|i%EuB|$E=$Lrgl2EU9-@BN9@0TSejNCHKi~5`hhKQk5S}wc zTg@iMPoW?P01WW3`L-Fj1b?rAGZPrM0DU(P=(k7GlQWB%hsl=fl3*7s?P@gjc+YHZtM3Q3KBnnx_Z+}H z&NtY2)jRg!m*y;sDwy6UjNs9( z2D~_3OeL*O0f^lD+Zel7M>T><0o4uS%=(1S8sAuOsfihR-YjLO+ZhvdR6naS>`m3&N%c}FwOJ3- s_-LUE5}4z49FHxI!zZ$&Z$`w3BetphaHi; zc9c*gm)xu`>B7Wxm1(kJsmSC`=@!Y!_ck9o_G0C}@>T_AO=b?K{eO<0|MTYE&9Ket zGHvWkb08`YE7#&yIXOzDh;i!VvnrF2)i9!%HhH3&{p200I!r4e2L4jTW8mhAYLgfl zH&0g4@MK)GIZxv+h?Aq02qe#GSut*$%&D!xxMp&mhRkF?ZEqldmi9Hq&6^8#_AoMT z+N`JN%M9ez7`ib|&NPu_dT@Mlhsj0|Wo=pq)V9l1Ve%m(1;&Mw8`DH5e=xN(Sl7_d zz@WgSz-Y!Kpxg-JI6gRjpn)Mvfyt2tL6{!o$R^z#y<` zGQY)QkPTZbjtS{7FgYkNXfQE2*1PdCfMvfJc>yi9H$KV^*2K>}c|oS=WCas#ps0_D z?B*&E+Rft87L1ImHwVO&urO}ed^F(%Bjc*ceMvq*uiZ}i scuYX}y-$YA@|y4VbstZr@7{cE`yEZjE6R*))7SbkDsR8y%h;j^0JQDxNdN!< delta 624 zcmccegZ0J_)(v+#8Lw@=$2pson+XKCnHd?G7&o`@UuR}~I5|f6B;$w8Y9d>h86Qk` zlu#s>+^jF@!o+lqX|iIf*yL{MCaK1zdk1f9`1Q29Re@QPnZxPpy^WuD&3MqXwSKdj zOdC7XT#!|tbFvsp{eml?>bFmz*_tZ$+qq{G1EpunKP#Nb%(#>=36Z3IyhjO&0J_)Qch z`q)aoy$zRz?bp8#fC_TQD+i*z6Ni z!os*^^TC7@jEw6icP04%eRw_T<1qooM)Qu=m#2T1=I5+C+`zhZ`wdOTE6US1_%bRm MvTZ->%h;|50CY#~fdBvi diff --git a/plugins/official/license-header/dist/plugin.wasm b/plugins/official/license-header/dist/plugin.wasm index a73f82c970694e478ff88c56608fc69759cbefe9..3a78025b9758afb1ac15ebe08cd24e5ba4bd027d 100644 GIT binary patch delta 1268 zcma)5e@t6d6z03{6?h2p!XUsLt`G(VS%)nB!%3m9F4eG@^JCT!77Nx+b7PUpf9 zC2`7}+X>VqkTAE&m_Gu$8X}_O*S5}5esl~(8Huz8bulv-l_k@7TM{GuL3Z!UJNJC& zd*^)joV=e-Df6e4j(yP>`P<92|Oxes)Pu!5gihe z7?CKbDuW^^3MBAti4CEc;j?RpWqeMZsg0}u`t0UVU0v7do+I^oIYUaYj(K}q-#_Mi zJBO;*o2hwS0s8KZ7*9W^<>MDYjwefc%?g?MWO}#6+8HH(xtczC=-?8nlp%#L6LBa@ zgNu5ynwJxoswMd*gY4|9LoBT^9$ilUUsnFLF%i^eiX#7pPw@k%>>j|!?KxJ!%V}dQ z6Fom~YLRiBY@0qLgmrt|i zEOueBNM_zj?c&{eBKGv z#`&#XzX208UFOhD1kzILs~Uf;JQ|p!cXm6J$wdiTHr;+MoyYEZL`EMk+PgzWKmV|z zmEkgfyz;ID7vEf6ETNyA`?GM35AMGUe8c-*9@b%mzjt_ECuaOcoh85+tWOb)x%#g{ zaf!|~RN@j}b!;y%M2Fs;6VRUHc3kEB_=1En{xP|LK|0X5^TFBIg+69k+9r%a zs6a3E6{?qRH&%%$Jlj-_>wL7SElN1AoPAylVCL+v3|<;)GYIF8HkTCd4P=UfKEl9K zlbJq3TT`Jy_4DzMPRn9cg`FFzya=r|C>s>Hjy(-uTKf{2Y4F0O~4r*U%v zlR{{>`-J#?e|M*Z^#=;v*X-1QII1bjrZdmXP`+ooxJi>ICG2uAeCEF}mxq&}UJamn zW?+%YIz3buJv<^BMI|HW(aZlHsRDm#%pFGVDI=YnYNbt6nLOvaFBBf<_kwQuGWpz( vnZOkuGv|sC^Z)+NW3u>g?LTQ=^y{PS>_k(BXdplRpdp delta 1235 zcma)6e@s(X6z=!l!@XBPUMgAX0$7MbK~|W|efHQ`BrgaFDQ&nJh+` zlRr#EGLDs?Wx*c_ZX>gJml@4e&`OJxQrLh&hz^zMVw}OaMHBbqwk`{hnC<4}-E+?O z-Sf`*?#X-9uH0)^JXLY%XVr1*6r=EbDOf5()FZqEzLP(pDh+}VepF6TMd+cA19Uo* z-o#0&07X=wKx7+D2bbUnc58W1!Z*~j!etu&DfoEoW}v&F$t-1v3HhIUe|I0AI61bH zv@9EStSm(D|Kb_xewrP>aITTWG$T3Ft6rR&O{HHDahhh{QBL+XMH1)^DdkUM^g%wgqisVVm8yopgBBa!R&k(T+FYesL4j zZL>4co&sE8*{;8{u z+to+vafMAC>5ApfzEkh>dhVTiARt8JT^9c7zqjRtjw z-T3Ob#4oAQ^A>;mJk1e1mmZ#7M#p+A-1GK?k?6CYe-Q^}SPru#Q2k&FdI^D4xi6eO z+6{s&p4kKMfh&u^D|Bf{mc0?|WCSC7Acq-(Nl^R4QL|tXVp5{aP<><{=33B>;nTRx zqC<83r=nxKMuuJ@!&D|J+deZOo_Z%u^xcg>o;&6 lW}g;FJVnNzX`^bHhqnH)+W9#7L`T8-LtoxMR}lj3{u^s64%Gkv diff --git a/plugins/official/mybatis/dist/plugin.wasm b/plugins/official/mybatis/dist/plugin.wasm index 56953a3764da0c27b67fb288080ebf852895740c..b17ee3ee317644e1eb869c57b78cba4377c70516 100644 GIT binary patch delta 1510 zcmah}4NR3)80I+{)FX{D= zB!K@MdPawBRm|sGQpJ3e#g10`-O}~s7?fj8 zpzh3Yx|!C1VX97_v@4TK6Wo5B7Uf6KsKrcco-l8MIBvmT4@(~j85Qn`mgQt#}> zG#bcAq4RU|eEFEvJ~=brqUMa*=<(+HBV(^GcXB=4nRz=JpYqzAZW&I#=-rc&P@(VH zgK>v%U3Um*;?oPNK*u&+4!Nc%il0$u3$PmosJTd^jE%4H<(row>>sa3wi$%y;q)B! z7iaL%k1iqbx)+iR1N>rf8lL*sYqEz-MpueoqE#jPag)YMV%UhnBeyJ*Fu>Q9z6qf^ z$`*hQuTO-Vde<++9WoZag9+MNxD@y3m%@`waZvq+!@P8(6`VP)fK@p7pXCuAO%oNX zJ!VejDTezLzhjk36>jYM5%`M+ zzR!(qEEjdM`42v$E|D2+W!Y0a2V%4vT=af-0UD{ddjs73)f2^m!stBx0bJbl(^?r# zRC9J%$eq0%LfX#HpcUuhyr@RAdvkp}P2xISK7S!f?Dw(3Jt9i>P>~4v-B6!S7~cEW8%&oy{m|YDfdb+#*f_l&_AwWQqOWCd*eaRvh9?g-QZSJbvPEI zJ|Y<(r?@oP9}C2@qAk&*b_$$Ye;BrfFv(BNjYl2I)w=1J78qTS&H{`uRA`|llmS&9 z*rea?i5z@@j&9G=?oUSy4AmaQ$P!sdyiV|I)MPWnd8&)dI1Gp8HlqNlJweEN?P3Co zm{v3k23dQ1CK7h%JIYoDc{m|-u)Bt&XTDu$T)Oe&UZ`DvI5>` h9NO-AP=7V#jzquSqx7UzpXoGh3A}i%)$%m^_&*IVXsZAK delta 1569 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 o>n!hq;-8*{I*>?{ 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 delta 73054 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 J?zyT!`~M?`Vn6@@ diff --git a/plugins/official/solidity/dist/plugin.wasm b/plugins/official/solidity/dist/plugin.wasm index 0cfff4ffa39ad82145b916f88b63d301350763d5..a9fc62c5214e387e874de8a2ebcc684a7f55b6dc 100644 GIT binary patch delta 557 zcmX@Vh3(oFwhhG`jQcj1a9m;G5~gAP*pLa`e?F@ zWj0V%pt;=SJ`0`6mn=Q-nki%HwYko!l6^D3Ge0Ban$7Yqg^Y~rCQo!#nEc&QVe&@T z7{(2g`P^g~H*VH(Tgu43uA!lUfrn}G1}E{!@7+a#N?AR&Fm9eK@6tZm(Q_r^Rv^oK zvy#^aM%HhPjEwb@9o$7G8#q+~6|Q!2V_MfRxzI_9k$dw+ZvjTe?UNt*L^5vQY~x$R z%(!Xu`T#W+#x0ZA2dGZ|9TLvCZgX&`Ff-$7kih1ii0>?n>o>Q=S}-!M-MlyM2Q%Zg p&D)YrFfy*%T%U5{ra;fB``;}U%$r_E>s^2HM|Jx4a685y(Ezw~?Lq(m delta 565 zcmcb%h3)(nwhhG`jN3Pta9m;GV`AdsVPs}xWa44uVPxDK#w*Oqcy4o+5Dz2ERVGH3 z$rCL_Cie+VI(Pt%Ev8+@t8_|l> z6bnQce^0({ItSf;355NV`^=6p&Yj$6DL476sm$bl^9XdsNRFM%WKqO2jfs(Ya==N6 z$rCKfQPeV`cx&QB-NYsv zxX)nRGMUf0eR6=uO2%zKmicBw&kc;5Z+ZhwTRr)uPbBARka`7XM}x@=0<|`m`Z_Q( zZl0VMp}P5Y03!?IRuFSCQ)oETs)orMy+k(WhyG(?T)R0hLWY%b!{+W-3r5EEn~%i( sUiP+hp@yqHnakv>{d3H}<&*^rD-foAw5Y2X5!)%iI&jyl}nRdy}^N>iPPLy@=%WyFD;7_Ebzts0V3Wbpe)HP?C!x!f4^j< z&I<^zptEOn2Wxb8^w1eG@P`|5?q;;SdUbv6XVm%;{;2$miM?{$(8tp5$Lb88^dZLV z9*NzlkywSNe%o`u-!Di)Mc<8>Uuc$yL=1!3h*XHph6z6E2_q-AlIRI*a~CjQtyv`k zwIP)|P&X+jwqpyMt?5<6vu>9yTiu{jMX}i-7&0AM-tc|p)$!%JX&}y~Pt_sLchq-R zVTSS0Im~c-e-kjyu7*FVQR~2QJmaweuZS1CY%mUt@#P2Y4SFgFx(}c^K3oQy_gLiH zd6<$L^Kl;UmDl+gBbZfg84=Zpodg;=SqzihZABqca>R;VNGb2E7!s9Z1t^Ac-G-%< l!Mm?LIZ-+KV`*W0b~L~@Q6VZ)1voY=}p6HKH~!YBybh82j~ zg|B%sko;%^HQeYO9T3+1sAfS|Dj_6YxaA<}q8p(u>||HocoFo!c=+>t{F0mL8=L8& zMKz|_lDa)b%`3M@0C>;~`ffdVtqL3f12F(x24Uaz6TJG=G$MG7S8&i#!wAON8KadT z#F`F-c??ruuJxa_)%-&NUCZnI3(BPR`I>Fm|N2_Z+01pYO+{7-9S$1l=fhpugYVb6 zN5&rxCAkM8U&yDOPCo5f+?rn9P_d4}sSG68(b5P(oP8^MOfW=!<$b$sXp!v}2Iw=} z&JuQjX@k9r_E%VyqOUxUMr=iWcIPfo)?hzjps6*YWGp}qg?k_+>h*fLz4TnIiH6-r z5T#$-W}yoZq$?%J!VC>pzf|ki>m3O8pvqAUr44Y0-u? z`J)z5f+e|EkBCaXnu|jaItf%#TRsd@qX{`kNFEc8At47%2nkZi42$eHV` in `plugin.toml`, then send +`pty-spawn`, `pty-input`, `pty-resize` and `pty-kill` JSON strings using +`openidea.postMessage`. Consume `pty-data` and acknowledge its `sequence` using +`pty-ack`; handle `pty-exit` and `pty-error` through `openidea.onMessage`. + +See [the protocol, permission and resource limits](../../../plugins/README.md#web-frame-ptys-api-13) +and the [minimal fixture](../../../crates/ide-plugin/tests/fixtures/web-pty). +The frame cannot access IPC directly. Its sessions belong to that frame and +end with its view or plugin. There is no new WIT import for this API. diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index 454c924b1..c715d8a40 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -499,6 +499,7 @@ pub fn builder() -> tauri_specta::Builder { plugin::plugin_service_detail, plugin::plugin_service_log, plugin::plugin_web_page, + plugin::plugin_web_pty_spawn, plugin::plugin_web_save_file, plugin::plugin_web_read_file, plugin::plugin_line_markers, diff --git a/src-tauri/src/commands/plugin.rs b/src-tauri/src/commands/plugin.rs index 2d69c0edd..39d22a488 100644 --- a/src-tauri/src/commands/plugin.rs +++ b/src-tauri/src/commands/plugin.rs @@ -23,6 +23,7 @@ use tauri::{AppHandle, Manager, State, Window}; /// How long `plugin_list` waits for the startup load before answering with what it has. const INITIAL_LOAD_WAIT: Duration = Duration::from_secs(5); + /// `on-startup-finished` fires this long after the installed plugins are loaded. const STARTUP_FINISHED_DELAY: Duration = Duration::from_millis(1500); /// How often the marketplace index is read again (revocations). @@ -531,6 +532,35 @@ pub fn plugin_web_page( state.plugins.web_page(&plugin_id, &view) } +#[tauri::command] +#[specta::specta] +pub async fn plugin_web_pty_spawn( + window: Window, + state: State<'_, AppState>, + plugin_id: String, + view: String, + command: ide_host::plugins::web::WebPtyCommand, + on_output: Channel, +) -> IdeResult { + let plugins = state.plugins.clone(); + let host = state.host.clone(); + let window = window.label().to_owned(); + tauri::async_runtime::spawn_blocking(move || { + plugins.spawn_web_pty( + &host, + &plugin_id, + &view, + &window, + command, + Arc::new(move |chunk| { + let _ = on_output.send(chunk); + }), + ) + }) + .await + .map_err(|e| IdeError::internal(e.to_string()))? +} + /// Largest file a web view saves or opens (`openidea.saveFile` / `openFile`). const MAX_WEB_VIEW_FILE: u64 = 64 << 20; diff --git a/src/bindings.ts b/src/bindings.ts index 6e6bdbc58..12dd4034a 100644 --- a/src/bindings.ts +++ b/src/bindings.ts @@ -1128,6 +1128,7 @@ export const commands = { pluginServiceLog: (request: RequestId, pluginId: string, view: string, key: string, tab: string, on: string[], onLine: Channel) => typedError(__TAURI_INVOKE("plugin_service_log", { request, pluginId, view, key, tab, on, onLine })), /** The page of a plugin's web view or custom editor (`web = …`). */ pluginWebPage: (pluginId: string, view: string) => typedError(__TAURI_INVOKE("plugin_web_page", { pluginId, view })), + pluginWebPtySpawn: (pluginId: string, view: string, command: WebPtyCommand, onOutput: Channel) => typedError(__TAURI_INVOKE("plugin_web_pty_spawn", { pluginId, view, command, onOutput })), /** * Writes what a web view saves (`openidea.saveFile`) to the path the user * chose in the save dialog, on this machine. @@ -8277,6 +8278,15 @@ export type WebPage = { path: string, }; +/** A web frame's API 1.3 PTY request. The frame never supplies an executable path or cwd. */ +export type WebPtyCommand = { + program: string, + args: string[], + env: { [key in string]: string }, + cols: number, + rows: number, +}; + export type WebReference = { kind: WebReferenceKind, /** Without sigil: `card`, `main`, `--accent`. */ diff --git a/src/features/plugins/__tests__/ptyBridge.test.ts b/src/features/plugins/__tests__/ptyBridge.test.ts new file mode 100644 index 000000000..556a06474 --- /dev/null +++ b/src/features/plugins/__tests__/ptyBridge.test.ts @@ -0,0 +1,211 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; +import type { TerminalId, TerminalInfo } from "@/bindings"; +import { ptyBridge, type PtyBackend } from "../views/ptyBridge"; + +const cleanup: Array<() => void> = []; +afterEach(async () => { + for (const close of cleanup.splice(0)) close(); + await tick(); +}); +const tick = async () => { + for (let i = 0; i < 10; i++) await Promise.resolve(); +}; +function setup(plugin = "acme.pty") { + let output: (data: string) => void = () => {}; + let exit: (id: TerminalId, code: number | null) => void = () => {}; + let serial = 0; + const backend: PtyBackend = { + spawn: vi.fn(async (_command, listener) => { + output = listener; + return { id: ++serial as TerminalId } as TerminalInfo; + }), + write: vi.fn(async () => {}), + resize: vi.fn(async () => {}), + kill: vi.fn(async () => {}), + onExit: (listener) => { + exit = listener; + return vi.fn(); + }, + }; + const sent: Record[] = []; + const bridge = ptyBridge(plugin, backend, (m) => sent.push(m as Record)); + cleanup.push(bridge.close); + const send = (m: object) => bridge.handle(JSON.stringify({ sessionId: "s", ...m })); + const spawn = () => send({ op: "pty-spawn", program: "bash", args: ["-i"] }); + return { + backend, + sent, + bridge, + send, + spawn, + output: (data: string) => output(data), + exit: (id: number, code: number | null) => exit(id as TerminalId, code), + }; +} + +describe("web frame PTY ownership and limits", () => { + it("rejects malformed types, sizes, paths and dimensions without starting a process", () => { + const f = setup(); + for (const bad of [ + { program: "\0" }, + { program: " bash" }, + { args: [1] }, + { args: ["x".repeat(4097)] }, + { args: Array(257).fill("x") }, + { args: ["\0"] }, + { cols: -1 }, + { rows: 501 }, + { cols: 2.5 }, + { cols: "80" }, + { env: [] }, + { env: { PATH: 1 } }, + { env: { "a=b": "v" } }, + { env: { a: "\0" } }, + { cwd: "/" }, + { sessionId: "x".repeat(65) }, + ]) + f.send({ op: "pty-spawn", program: "bash", ...bad }); + expect(f.backend.spawn).not.toHaveBeenCalled(); + expect(f.bridge.handle("null")).toBe(false); + expect(f.bridge.handle("[1]")).toBe(false); + expect(f.bridge.handle("garbage")).toBe(false); + expect(f.bridge.handle(JSON.stringify({ op: "plugin-state", data: "x".repeat(3 << 20) }))).toBe(false); + f.send({ op: "pty-spawn", program: "bash", padding: "x".repeat(3 << 20) }); + expect(f.sent.every((m) => m.op === "pty-error")).toBe(true); + }); + + it("caps sessions across frames of one plugin, including cancelled pending starts", async () => { + const a = setup(); + const b = setup(); + const other = setup("other.pty"); + const resolves: Array<(info: TerminalInfo) => void> = []; + vi.mocked(a.backend.spawn).mockImplementation( + () => + new Promise((r) => { + resolves.push(r); + }), + ); + for (let i = 0; i < 8; i++) a.send({ op: "pty-spawn", program: "bash", sessionId: `s${i}` }); + b.spawn(); + expect(b.backend.spawn).not.toHaveBeenCalled(); + a.send({ op: "pty-kill", sessionId: "s7" }); + b.spawn(); + expect(b.backend.spawn).not.toHaveBeenCalled(); + other.spawn(); + expect(other.backend.spawn).toHaveBeenCalledOnce(); + resolves[7]!({ id: 77 as TerminalId } as TerminalInfo); + await tick(); + expect(a.backend.kill).toHaveBeenCalledWith(77); + b.spawn(); + await tick(); + expect(b.backend.spawn).toHaveBeenCalledOnce(); + // Finish the other pending starts so their reservations cannot leak between tests. + a.bridge.close(); + for (let i = 0; i < 7; i++) resolves[i]!({ id: (80 + i) as TerminalId } as TerminalInfo); + await tick(); + }); + + it("serializes bounded pending and in-flight input and coalesces resizes", async () => { + const f = setup(); + let resolve!: (info: TerminalInfo) => void; + vi.mocked(f.backend.spawn).mockImplementation( + () => + new Promise((r) => { + resolve = r; + }), + ); + f.spawn(); + f.send({ op: "pty-input", data: "hello" }); + f.send({ op: "pty-resize", cols: 90, rows: 30 }); + f.send({ op: "pty-resize", cols: 100, rows: 40 }); + resolve({ id: 1 as TerminalId } as TerminalInfo); + await tick(); + expect(f.backend.write).toHaveBeenCalledWith(1, "hello"); + expect(f.backend.resize).toHaveBeenCalledExactlyOnceWith(1, 100, 40); + vi.mocked(f.backend.write).mockImplementation(() => new Promise(() => {})); + f.send({ op: "pty-input", data: "x".repeat(64 << 10) }); + f.send({ op: "pty-input", data: "x" }); + await tick(); + expect(f.backend.kill).toHaveBeenCalledWith(1); + expect(f.sent.at(-1)?.error).toBe("PTY input limit exceeded"); + }); + + it("never lets one frame write, resize or kill another frame's terminals", async () => { + const a = setup("ownership.pty"); + const b = setup("ownership.pty"); + a.spawn(); + await tick(); + b.send({ op: "pty-input", data: "bad" }); + b.send({ op: "pty-resize", cols: 80, rows: 24 }); + b.send({ op: "pty-kill" }); + expect(a.backend.write).not.toHaveBeenCalled(); + expect(a.backend.resize).not.toHaveBeenCalled(); + expect(a.backend.kill).not.toHaveBeenCalled(); + a.send({ op: "pty-input", data: "yes" }); + await tick(); + expect(a.backend.write).toHaveBeenCalledWith(1, "yes"); + }); + + it("allows one unacknowledged chunk and caps all outstanding output", async () => { + const f = setup("output.pty"); + f.spawn(); + await tick(); + f.output("hello"); + f.output("world"); + expect(f.sent).toHaveLength(1); + f.send({ op: "pty-ack", sequence: 999 }); + expect(f.sent).toHaveLength(1); + f.send({ op: "pty-ack", sequence: 1 }); + expect(f.sent.at(-1)).toMatchObject({ data: "world", sequence: 2 }); + f.output("x".repeat(256 << 10)); + await tick(); + expect(f.backend.kill).toHaveBeenCalledWith(1); + expect(f.sent.at(-1)?.error).toBe("PTY output limit exceeded"); + }); + + it("handles output and exit before spawn resolves and drains before reporting exit", async () => { + const f = setup("early.pty"); + vi.mocked(f.backend.spawn).mockImplementation(async (_command, output) => { + output("early"); + f.exit(42, 7); + return { id: 42 as TerminalId } as TerminalInfo; + }); + f.spawn(); + await tick(); + expect(f.sent).toHaveLength(1); + f.send({ op: "pty-ack", sequence: 1 }); + expect(f.sent.at(-1)).toEqual({ op: "pty-exit", sessionId: "s", exitCode: 7 }); + f.spawn(); + await tick(); + expect(f.backend.spawn).toHaveBeenCalledTimes(2); + }); + + it("cleans failed and late spawns, catches operation failures and closes idempotently", async () => { + const f = setup("cleanup.pty"); + vi.mocked(f.backend.spawn).mockRejectedValueOnce(new Error("denied")); + f.spawn(); + await tick(); + f.spawn(); + await tick(); + expect(f.backend.spawn).toHaveBeenCalledTimes(2); + vi.mocked(f.backend.resize).mockRejectedValueOnce(new Error("gone")); + f.send({ op: "pty-resize", cols: 80, rows: 24 }); + await tick(); + expect(f.backend.kill).toHaveBeenCalledWith(1); + let resolve!: (info: TerminalInfo) => void; + vi.mocked(f.backend.spawn).mockImplementation( + () => + new Promise((r) => { + resolve = r; + }), + ); + f.spawn(); + f.bridge.close(); + f.bridge.close(); + resolve({ id: 2 as TerminalId } as TerminalInfo); + await tick(); + expect(f.backend.kill).toHaveBeenCalledWith(2); + f.spawn(); + expect(f.backend.spawn).toHaveBeenCalledTimes(3); + }); +}); diff --git a/src/features/plugins/__tests__/webViews.test.tsx b/src/features/plugins/__tests__/webViews.test.tsx index 9ee8f0b93..51c47fb20 100644 --- a/src/features/plugins/__tests__/webViews.test.tsx +++ b/src/features/plugins/__tests__/webViews.test.tsx @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { render, waitFor } from "@testing-library/react"; +import { act, render, waitFor } from "@testing-library/react"; import type { PluginInfo, ViewEvent } from "@/bindings"; import { addFileIconProvider, fileIconName, registerExternalIcons } from "@/ui"; import { @@ -12,6 +12,7 @@ import { createMemoryPluginsBackend, setPluginsBackend, webSchemeUrl } from "../ import { defineViewUiPoints } from "../uiPoints"; import { clearUiContributions, syncUiContributions } from "../projection"; import { usePlugins } from "../store"; +import * as ptyModule from "../views/ptyBridge"; import { FRAME_TAG, frameDocument } from "../views/frame"; import { WebView, @@ -153,7 +154,7 @@ describe("WebView", () => { viewEvent: vi.fn(async (_p: string, _v: string, e: ViewEvent) => void events.push(e)), }); usePlugins.setState({ - plugins: [{ id: "acme.draw", hasCode, capabilities: [] } as unknown as PluginInfo], + plugins: [{ id: "acme.draw", hasCode, enabled: true, capabilities: [] } as unknown as PluginInfo], }); const doc = memoryDocument("hello world"); const view = render(); @@ -251,6 +252,71 @@ describe("WebView", () => { view.unmount(); } }); + + it("closes frame PTYs on plugin changes, navigation, window teardown and unmount", async () => { + const original = ptyModule.ptyBridge; + const closes: ReturnType[] = []; + const spy = vi.spyOn(ptyModule, "ptyBridge").mockImplementation((...args) => { + const bridge = original(...args); + const close = vi.fn(bridge.close); + closes.push(close); + return { ...bridge, close }; + }); + try { + const { view } = setup(true); + const { frame, send, posted } = await frameOf(view.container); + for (const change of [ + (p: PluginInfo) => ({ ...p, enabled: false }), + (p: PluginInfo) => ({ ...p, enabled: true, capabilities: [] }), + (p: PluginInfo) => ({ ...p, version: "2.0.0" }), + ]) { + const close = closes.at(-1)!; + act(() => usePlugins.setState((s) => ({ plugins: s.plugins.map(change) }))); + expect(close).toHaveBeenCalled(); + } + const close = closes.at(-1)!; + act(() => { + frame.dispatchEvent(new Event("load")); + frame.dispatchEvent(new Event("load")); + }); + expect(close).toHaveBeenCalled(); + const windowClose = closes.at(-1)!; + act(() => window.dispatchEvent(new Event("pagehide"))); + expect(windowClose).toHaveBeenCalled(); + // Another window cannot request a PTY through this frame's listener. + window.dispatchEvent( + new MessageEvent("message", { + source: window, + data: { tag: FRAME_TAG, text: JSON.stringify({ op: "pty-spawn", sessionId: "s", program: "sh" }) }, + }), + ); + await new Promise((r) => setTimeout(r, 0)); + expect(posted.filter((m) => m.text)).toEqual([]); + send({ text: "message" }); + view.unmount(); + expect(closes.every((close) => close.mock.calls.length > 0)).toBe(true); + } finally { + spy.mockRestore(); + } + }); + + it("refuses pty-spawn messages when process: capability is not granted", async () => { + const { view, events } = setup(true); + const { posted, send } = await frameOf(view.container); + send({ text: JSON.stringify({ op: "pty-spawn", sessionId: "s1", program: "sh", args: ["-i"] }) }); + await waitFor(() => + expect( + posted.some( + (m) => + typeof m.text === "string" && + m.text.includes('"op":"pty-error"') && + m.text.includes("process:sh capability not granted"), + ), + ).toBe(true), + ); + expect(events).toEqual([]); + view.unmount(); + }); }); describe("contributed file icons and templates", () => { diff --git a/src/features/plugins/views/WebView.tsx b/src/features/plugins/views/WebView.tsx index b59d7269f..d1a57a25e 100644 --- a/src/features/plugins/views/WebView.tsx +++ b/src/features/plugins/views/WebView.tsx @@ -16,13 +16,17 @@ * - passes on IDE shortcuts it doesn't handle itself (Save, Close…). */ import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react"; +import { Channel } from "@tauri-apps/api/core"; import { tx } from "@/platform/i18n"; +import { call, commands, isTauri, onIdeEvent } from "@/platform/ipc"; +import { useProject } from "@/platform/project"; import { subscribeTheme, themeKey } from "@/platform/themeWatch"; import { EmptyState, Spinner } from "@/ui"; import { pluginsBackend, type FileFilter } from "../backend"; import { errorText, usePlugins } from "../store"; import { FRAME_TAG, frameTheme, frameThemeMessage } from "./frame"; import { onViewMessage } from "./viewStore"; +import { ptyBridge } from "./ptyBridge"; import styles from "./PluginView.module.css"; /** One change of a document, in UTF-16 offsets of the text it applies to. */ @@ -152,6 +156,55 @@ export function WebView({ pluginId, view, label, document = null, doc = null }: useEffect(() => { let dialog = false; + const createPtys = () => + ptyBridge( + pluginId, + { + spawn: async (command, output) => { + const current = usePlugins.getState().plugins.find((p) => p.id === pluginId); + if ( + !isTauri() || + !current?.enabled || + !current.capabilities.some((c) => c.id === `process:${command.program}` && c.granted) + ) + throw new Error(tx`Cannot start PTY: process:${command.program} capability not granted.`); + const channel = new Channel(); + channel.onmessage = output; + return call(commands.pluginWebPtySpawn(pluginId, view, command, channel)); + }, + write: (id, data) => call(commands.termWrite(id, data)), + resize: (id, cols, rows) => call(commands.termResize(id, cols, rows)), + kill: (id) => call(commands.termKill(id)), + onExit: (listener) => onIdeEvent("terminalExited", (ev) => listener(ev.terminal, ev.code)), + }, + (message) => post({ text: JSON.stringify(message) }), + ); + let ptys = createPtys(); + const resetPtys = () => { + ptys.close(); + ptys = createPtys(); + }; + const offProject = useProject.subscribe((state, previous) => { + if (state.project !== previous.project) resetPtys(); + }); + const pluginKey = (plugins: ReturnType["plugins"]) => { + const p = plugins.find((p) => p.id === pluginId); + return p && JSON.stringify([p.path, p.version, p.enabled, p.status, p.capabilities]); + }; + const offPlugins = usePlugins.subscribe((state, previous) => { + if (pluginKey(state.plugins) !== pluginKey(previous.plugins)) resetPtys(); + }); + const onUnload = () => ptys.close(); + window.addEventListener("pagehide", onUnload); + const currentFrame = frame.current; + // A navigation keeps the iframe's WindowProxy, but must drop its old sessions. + let loaded = false; + const onLoad = () => { + if (loaded) resetPtys(); + loaded = true; + }; + currentFrame?.addEventListener("load", onLoad); + const run = async (op: string, args: Record): Promise<[unknown, Transferable[]?]> => { switch (op) { case "document.get": { @@ -218,10 +271,13 @@ export function WebView({ pluginId, view, label, document = null, doc = null }: ([value, transfer]) => post({ reply: id, value }, transfer), (err: unknown) => post({ reply: id, error: errorText(err) }), ); - } else if (typeof m.text === "string" && hasCode) { - pluginsBackend() - .viewEvent(pluginId, view, { kind: "message", text: m.text }, doc) - .catch((err: unknown) => console.warn(`plugin ${pluginId}: ${errorText(err)}`)); + } else if (typeof m.text === "string") { + if (ptys.handle(m.text)) return; + if (hasCode) { + pluginsBackend() + .viewEvent(pluginId, view, { kind: "message", text: m.text }, doc) + .catch((err: unknown) => console.warn(`plugin ${pluginId}: ${errorText(err)}`)); + } } }; window.addEventListener("message", onMessage); @@ -229,8 +285,13 @@ export function WebView({ pluginId, view, label, document = null, doc = null }: return () => { window.removeEventListener("message", onMessage); off(); + ptys.close(); + offPlugins(); + offProject(); + window.removeEventListener("pagehide", onUnload); + currentFrame?.removeEventListener("load", onLoad); }; - }, [pluginId, view, document, doc, hasCode, post]); + }, [pluginId, view, document, doc, hasCode, post, page]); if (!page) return ( diff --git a/src/features/plugins/views/ptyBridge.ts b/src/features/plugins/views/ptyBridge.ts new file mode 100644 index 000000000..f2dc53734 --- /dev/null +++ b/src/features/plugins/views/ptyBridge.ts @@ -0,0 +1,286 @@ +import type { TerminalId, TerminalInfo, WebPtyCommand } from "@/bindings"; +import { tx } from "@/platform/i18n"; + +const MAX_SESSIONS = 8; +const MAX_INPUT = 64 << 10; +const MAX_OUTPUT = 256 << 10; +const MAX_MESSAGE = 2 << 20; +const counts = new Map(); + +export interface PtyBackend { + spawn(command: WebPtyCommand, output: (data: string) => void): Promise; + write(id: TerminalId, data: string): Promise; + resize(id: TerminalId, cols: number, rows: number): Promise; + kill(id: TerminalId): Promise; + onExit(listener: (id: TerminalId, code: number | null) => void): () => void; +} + +interface Session { + id?: TerminalId; + stopped: boolean; + release(): void; + inputs: string[]; + inputSize: number; + writing: boolean; + size?: [number, number]; + resizing: boolean; + output: string[]; + outputSize: number; + awaiting?: number; + sentSize?: number; + sequence: number; + exit?: { code: number | null }; +} + +function dimensions(cols: unknown, rows: unknown): cols is number { + return ( + Number.isInteger(cols) && + Number.isInteger(rows) && + Number(cols) >= 2 && + Number(cols) <= 500 && + Number(rows) >= 1 && + Number(rows) <= 500 + ); +} + +/** One opaque frame owns this bridge. Terminal ids never cross the frame boundary. */ +export function ptyBridge(pluginId: string, backend: PtyBackend, send: (message: object) => void) { + const sessions = new Map(); + const earlyExits = new Map(); + let closed = false; + const error = (sessionId: string, message: string) => send({ op: "pty-error", sessionId, error: message }); + const stop = (sid: string, entry: Session) => { + if (entry.stopped) return; + entry.stopped = true; + if (sessions.get(sid) === entry) sessions.delete(sid); + entry.inputs = []; + entry.output = []; + if (entry.id !== undefined) + void backend + .kill(entry.id) + .catch(() => {}) + .finally(entry.release); + // A pending spawn keeps its slot until its returned terminal is killed. + }; + const flush = (sid: string, entry: Session) => { + if (closed || entry.stopped || entry.awaiting !== undefined) return; + const data = entry.output.shift(); + if (data !== undefined) { + entry.sentSize = data.length; + entry.awaiting = ++entry.sequence; + send({ op: "pty-data", sessionId: sid, data, sequence: entry.awaiting }); + } else if (entry.exit) { + send({ op: "pty-exit", sessionId: sid, exitCode: entry.exit.code }); + entry.stopped = true; + sessions.delete(sid); + entry.release(); + } + }; + const exited = (id: TerminalId, code: number | null) => { + const found = [...sessions].find(([, e]) => e.id === id); + if (found) { + const [sid, entry] = found; + entry.exit = { code }; + flush(sid, entry); + } else if ([...sessions.values()].some((e) => e.id === undefined) && earlyExits.size < 32) { + earlyExits.set(id, code); + } + }; + const off = backend.onExit(exited); + const write = async (sid: string, entry: Session) => { + if (entry.writing || entry.id === undefined) return; + entry.writing = true; + try { + while (!entry.stopped && entry.inputs.length) { + const data = entry.inputs.shift()!; + await backend.write(entry.id, data); + entry.inputSize -= data.length; + } + } catch { + if (!entry.stopped) error(sid, tx("Cannot write to PTY")); + stop(sid, entry); + } finally { + entry.writing = false; + } + }; + const resize = async (sid: string, entry: Session) => { + if (entry.resizing || entry.id === undefined) return; + entry.resizing = true; + try { + while (!entry.stopped && entry.size) { + const [cols, rows] = entry.size; + entry.size = undefined; + await backend.resize(entry.id, cols, rows); + } + } catch { + if (!entry.stopped) error(sid, tx("Cannot resize PTY")); + stop(sid, entry); + } finally { + entry.resizing = false; + } + }; + return { + handle(text: string): boolean { + let m: Record; + try { + const value: unknown = JSON.parse(text); + if (!value || typeof value !== "object" || Array.isArray(value)) return false; + m = value as Record; + } catch { + return false; + } + if (typeof m.op !== "string" || !m.op.startsWith("pty-")) return false; + if (closed) return true; + const sid = typeof m.sessionId === "string" ? m.sessionId : ""; + if (text.length > MAX_MESSAGE || !/^[\w.-]{1,64}$/.test(sid)) { + error("", tx("Invalid PTY request")); + return true; + } + const invalid = () => error(sid, tx("Invalid PTY request")); + const entry = sessions.get(sid); + switch (m.op) { + case "pty-spawn": { + const { program, args = [], env = {}, cols = 100, rows = 28 } = m; + if ( + entry || + typeof program !== "string" || + !program || + program.length > 256 || + program.trim() !== program || + /[\0\r\n]/.test(program) || + !Array.isArray(args) || + args.length > 256 || + args.some((a) => typeof a !== "string" || a.length > 4096 || a.includes("\0")) || + !env || + typeof env !== "object" || + Array.isArray(env) || + Object.keys(env).length > 64 || + Object.entries(env).some( + ([k, v]) => + !k || k.length > 256 || /[=\0]/.test(k) || typeof v !== "string" || v.length > 4096 || v.includes("\0"), + ) || + !dimensions(cols, rows) || + "cwd" in m + ) { + invalid(); + return true; + } + const count = counts.get(pluginId) ?? 0; + if (count >= MAX_SESSIONS) { + error(sid, tx("Too many PTY sessions")); + return true; + } + counts.set(pluginId, count + 1); + let released = false; + const created: Session = { + stopped: false, + inputs: [], + inputSize: 0, + writing: false, + resizing: false, + output: [], + outputSize: 0, + sequence: 0, + release() { + if (released) return; + released = true; + const left = (counts.get(pluginId) ?? 1) - 1; + if (left) counts.set(pluginId, left); + else counts.delete(pluginId); + }, + }; + sessions.set(sid, created); + void backend + .spawn( + { program, args: args as string[], env: env as Record, cols, rows: Number(rows) }, + (data) => { + if (closed || created.stopped || !data) return; + created.outputSize += data.length; + if (created.outputSize > MAX_OUTPUT) { + error(sid, tx("PTY output limit exceeded")); + stop(sid, created); + return; + } + created.output.push(data); + flush(sid, created); + }, + ) + .then( + (info) => { + created.id = info.id; + if (closed || created.stopped) { + void backend + .kill(info.id) + .catch(() => {}) + .finally(created.release); + return; + } + if (earlyExits.has(info.id)) { + created.exit = { code: earlyExits.get(info.id)! }; + earlyExits.delete(info.id); + flush(sid, created); + } else { + void write(sid, created); + void resize(sid, created); + } + if (![...sessions.values()].some((e) => e.id === undefined)) earlyExits.clear(); + }, + (err: unknown) => { + if (!closed && !created.stopped) error(sid, String(err)); + created.release(); + stop(sid, created); + }, + ); + return true; + } + case "pty-input": + if (typeof m.data !== "string" || m.data.length > MAX_INPUT) { + invalid(); + break; + } + if (entry && !entry.exit && m.data.length) { + entry.inputSize += m.data.length; + if (entry.inputSize > MAX_INPUT) { + error(sid, tx("PTY input limit exceeded")); + stop(sid, entry); + break; + } + entry.inputs.push(m.data); + void write(sid, entry); + } + break; + case "pty-resize": + if (!dimensions(m.cols, m.rows)) { + invalid(); + break; + } + if (entry && !entry.exit) { + entry.size = [Number(m.cols), Number(m.rows)]; + void resize(sid, entry); + } + break; + case "pty-kill": + if (entry) stop(sid, entry); + break; + case "pty-ack": + if (entry && Number.isSafeInteger(m.sequence) && m.sequence === entry.awaiting) { + // The in-flight chunk counts against the same bound as the unsent queue. + entry.outputSize -= entry.sentSize ?? 0; + entry.awaiting = undefined; + flush(sid, entry); + } + break; + default: + invalid(); + } + return true; + }, + close() { + if (closed) return; + closed = true; + off(); + for (const [sid, entry] of sessions) stop(sid, entry); + earlyExits.clear(); + }, + }; +} diff --git a/src/platform/locales/text/en.json b/src/platform/locales/text/en.json index a17b7f7d2..5005493ac 100644 --- a/src/platform/locales/text/en.json +++ b/src/platform/locales/text/en.json @@ -1,4 +1,11 @@ { + "Invalid PTY request": "Invalid PTY request", + "Cannot write to PTY": "Cannot write to PTY", + "Cannot resize PTY": "Cannot resize PTY", + "Too many PTY sessions": "Too many PTY sessions", + "PTY output limit exceeded": "PTY output limit exceeded", + "PTY input limit exceeded": "PTY input limit exceeded", + "Cannot start PTY: process:{program} capability not granted.": "Cannot start PTY: process:{program} capability not granted.", "Marker Icons": "Marker Icons", "this data source does not list databases": "this data source does not list databases", "commit or roll back before clearing the selected database": "commit or roll back before clearing the selected database", diff --git a/src/platform/locales/text/zh.json b/src/platform/locales/text/zh.json index 9f497af11..130ba8560 100644 --- a/src/platform/locales/text/zh.json +++ b/src/platform/locales/text/zh.json @@ -1,4 +1,11 @@ { + "Invalid PTY request": "无效的 PTY 请求", + "Cannot write to PTY": "无法写入 PTY", + "Cannot resize PTY": "无法调整 PTY 大小", + "Too many PTY sessions": "PTY 会话过多", + "PTY output limit exceeded": "PTY 输出超出限制", + "PTY input limit exceeded": "PTY 输入超出限制", + "Cannot start PTY: process:{program} capability not granted.": "无法启动 PTY:未授予 process:{program} 权限。", "Marker Icons": "行标记图标", "this data source does not list databases": "此数据源不支持列出数据库", "commit or roll back before clearing the selected database": "清除所选数据库前,请先提交或回滚事务",