1#![allow(non_snake_case, unused_variables, dead_code, unused_imports)]
2
3pub mod Cocoon;
7
8pub mod Commands;
9
10pub mod Configuration;
11
12pub mod Encryption;
13
14pub mod Extension;
15
16pub mod ExtensionHost;
17
18pub mod Extensions;
19
20pub mod FileSystem;
21
22pub mod Git;
23
24pub mod Model;
25
26pub mod NativeDialog;
27
28pub mod NativeHost;
29
30pub mod Navigation;
31
32pub mod Output;
33
34pub mod Search;
35
36pub mod Sky;
37
38pub mod Storage;
39
40pub mod Terminal;
41
42pub mod UI;
43
44pub mod TreeView;
45
46pub mod Update;
47
48pub mod Utilities;
49
50use std::{collections::HashMap, path::PathBuf, sync::Arc};
56
57use Cocoon::{ExtensionHostMessage::CocoonExtensionHostMessage, Notify::CocoonNotify, Request::CocoonRequest};
58use ExtensionHost::{
59 DebugService::{ExtensionHostDebugClose, ExtensionHostDebugReload},
60 Starter::{
61 ExtensionHostStarterCreate,
62 ExtensionHostStarterGetExitInfo,
63 ExtensionHostStarterKill,
64 ExtensionHostStarterStart,
65 },
66};
67use Sky::ReplayEvents::SkyReplayEvents;
68use TreeView::GetChildren::TreeGetChildren;
69use Update::UpdateService::{
70 UpdateApplyUpdate,
71 UpdateCheckForUpdates,
72 UpdateDownloadUpdate,
73 UpdateGetInitialState,
74 UpdateIsLatestVersion,
75 UpdateQuitAndInstall,
76};
77use Commands::*;
78use Configuration::*;
79use Encryption::{Decrypt::Decrypt, Encrypt::Encrypt};
80use Extensions::{
81 ExtensionsGet::ExtensionsGet,
82 ExtensionsGetAll::ExtensionsGetAll,
83 ExtensionsGetInstalled::ExtensionsGetInstalled,
84 ExtensionsIsActive::ExtensionsIsActive,
85};
86use FileSystem::{
87 Managed::{
88 FileCopy::*,
89 FileDelete::*,
90 FileExists::*,
91 FileMkdir::*,
92 FileMove::*,
93 FileRead::*,
94 FileReadBinary::*,
95 FileReaddir::*,
96 FileStat::*,
97 FileWrite::*,
98 FileWriteBinary::*,
99 },
100 Native::{
101 FileCloneNative::*,
102 FileCloseFd::FileCloseFd,
103 FileDeleteNative::*,
104 FileExistsNative::*,
105 FileMkdirNative::*,
106 FileOpenFd::FileOpenFd,
107 FileReadNative::*,
108 FileReaddirNative::*,
109 FileRealpath::*,
110 FileRenameNative::*,
111 FileStatNative::*,
112 FileUnwatch::FileUnwatch,
113 FileWatch::FileWatch,
114 FileWriteNative::*,
115 },
116};
117use Model::{
118 ModelClose::ModelClose,
119 ModelGet::ModelGet,
120 ModelGetAll::ModelGetAll,
121 ModelOpen::ModelOpen,
122 ModelUpdateContent::ModelUpdateContent,
123 TextfileRead::TextfileRead,
124 TextfileSave::TextfileSave,
125 TextfileWrite::TextfileWrite,
126};
127use NativeHost::{
128 Clipboard::{
129 NativeHasClipboard,
130 NativeReadClipboardBuffer,
131 NativeReadClipboardFindText,
132 NativeReadClipboardText,
133 NativeReadImage,
134 NativeTriggerPaste,
135 NativeWriteClipboardBuffer,
136 NativeWriteClipboardFindText,
137 NativeWriteClipboardText,
138 },
139 Exit::Exit,
140 FindFreePort::*,
141 GetColorScheme::*,
142 GetEnvironmentPaths::NativeGetEnvironmentPaths,
143 InstallShellCommand::InstallShellCommand,
144 IsFullscreen::*,
145 IsMaximized::*,
146 IsRunningUnderARM64Translation::NativeIsRunningUnderARM64Translation,
147 KillProcess::KillProcess,
148 MoveItemToTrash::NativeMoveItemToTrash,
149 OSProperties::*,
150 OSStatistics::*,
151 OpenDevTools::OpenDevTools,
152 OpenExternal::*,
153 PickFolder::*,
154 Quit::Quit,
155 Relaunch::Relaunch,
156 Reload::Reload,
157 ShowItemInFolder::*,
158 ShowMessageBox::NativeShowMessageBox,
159 ShowOpenDialog::*,
160 ShowSaveDialog::{NativeShowSaveDialog, UserInterfaceShowSaveDialog},
161 ToggleDevTools::ToggleDevTools,
162 UninstallShellCommand::UninstallShellCommand,
163};
164use Navigation::{
165 HistoryCanGoBack::HistoryCanGoBack,
166 HistoryCanGoForward::HistoryCanGoForward,
167 HistoryClear::HistoryClear,
168 HistoryGetStack::HistoryGetStack,
169 HistoryGoBack::HistoryGoBack,
170 HistoryGoForward::HistoryGoForward,
171 HistoryPush::HistoryPush,
172 LabelGetBase::LabelGetBase,
173 LabelGetURI::LabelGetURI,
174 LabelGetWorkspace::LabelGetWorkspace,
175};
176use Output::{
177 OutputAppend::OutputAppend,
178 OutputAppendLine::OutputAppendLine,
179 OutputClear::OutputClear,
180 OutputCreate::OutputCreate,
181 OutputShow::OutputShow,
182};
183use Search::*;
184use Storage::{
185 StorageDelete::StorageDelete,
186 StorageGet::StorageGet,
187 StorageGetItems::StorageGetItems,
188 StorageKeys::StorageKeys,
189 StorageSet::StorageSet,
190 StorageUpdateItems::StorageUpdateItems,
191};
192use Terminal::{
193 AttachToProcess::AttachToProcess,
194 DetachFromProcess::DetachFromProcess,
195 LocalPTYCreateProcess::LocalPTYCreateProcess,
196 LocalPTYFreePortKillProcess::LocalPTYFreePortKillProcess,
197 LocalPTYGetDefaultShell::LocalPTYGetDefaultShell,
198 LocalPTYGetEnvironment::LocalPTYGetEnvironment,
199 LocalPTYGetProfiles::LocalPTYGetProfiles,
200 LocalPTYResize::LocalPTYResize,
201 ReviveTerminalProcesses::ReviveTerminalProcesses,
202 SerializeTerminalState::SerializeTerminalState,
203 TerminalCreate::TerminalCreate,
204 TerminalDispose::TerminalDispose,
205 TerminalHide::TerminalHide,
206 TerminalSendText::TerminalSendText,
207 TerminalShow::TerminalShow,
208};
209use UI::{
210 Decoration::*,
211 Keybinding::*,
212 Lifecycle::*,
213 Notification::*,
214 Progress::*,
215 QuickInput::*,
216 Theme::*,
217 WorkingCopy::*,
218 Workspace::*,
219};
220use Utilities::{
221 ApplicationRoot::*,
222 ChannelPriority::*,
223 JsonValueHelpers::*,
224 MetadataEncoding::*,
225 PathExtraction::*,
226 RecentlyOpened::*,
227 UserdataDir::*,
228};
229use Echo::Task::Priority::Priority as EchoPriority;
230use serde_json::{Value, json};
231use tauri::{AppHandle, Manager};
232use CommonLibrary::Configuration::DTO::{
234 ConfigurationOverridesDTO as ConfigurationOverridesDTOModule,
235 ConfigurationTarget as ConfigurationTargetModule,
236};
237
238use crate::dev_log;
239
240type ConfigurationOverridesDTO = ConfigurationOverridesDTOModule::ConfigurationOverridesDTO;
241
242type ConfigurationTarget = ConfigurationTargetModule::ConfigurationTarget;
243
244use CommonLibrary::{
245 Command::CommandExecutor::CommandExecutor,
246 Configuration::ConfigurationProvider::ConfigurationProvider,
247 Environment::Requires::Requires,
248 Error::CommonError::CommonError,
249 ExtensionManagement::ExtensionManagementService::ExtensionManagementService,
250 FileSystem::{FileSystemReader::FileSystemReader, FileSystemWriter::FileSystemWriter},
251 IPC::SkyEvent::SkyEvent,
252 Storage::StorageProvider::StorageProvider,
253};
254
255use crate::{
256 ApplicationState::{
257 DTO::WorkspaceFolderStateDTO::WorkspaceFolderStateDTO,
258 State::{
259 ApplicationState::ApplicationState,
260 WorkspaceState::WorkspaceDelta::UpdateWorkspaceFoldersAndBroadcast,
261 },
262 },
263 RunTime::ApplicationRunTime::ApplicationRunTime,
264};
265
266pub async fn mountain_ipc_invoke(
283 ApplicationHandle:AppHandle,
284
285 command:String,
286
287 Arguments:Vec<Value>,
288) -> Result<Value, String> {
289 let IsHighFrequencyCommand = matches!(
292 command.as_str(),
293 "logger:log"
294 | "logger:info"
295 | "logger:debug"
296 | "logger:trace"
297 | "logger:warn"
298 | "logger:error"
299 | "logger:critical"
300 | "logger:flush"
301 | "logger:setLevel"
302 | "logger:getLevel"
303 | "logger:registerLogger"
304 | "logger:createLogger"
305 | "logger:deregisterLogger"
306 | "logger:getRegisteredLoggers"
307 | "logger:setVisibility"
308 | "log:registerLogger"
309 | "log:createLogger"
310 | "file:stat"
312 | "file:readFile"
313 | "file:readdir"
314 | "file:writeFile"
315 | "file:delete"
316 | "file:rename"
317 | "file:realpath"
318 | "file:read"
319 | "file:write"
320 | "storage:getItems"
322 | "storage:updateItems"
323 | "configuration:lookup"
325 | "configuration:inspect"
326 | "themes:getColorTheme"
328 | "output:append"
330 | "progress:report"
331 | "menubar:updateMenubar"
333 | "storage:onDidChangeItems"
335 | "storage:logStorage"
336 | "configuration:onDidChange"
337 | "workspaces:onDidChangeWorkspaceFolders"
338 | "workspaces:onDidChangeWorkspaceName"
339 | "commands:registerCommand"
341 | "commands:unregisterCommand"
342 | "commands:onDidRegisterCommand"
343 | "commands:onDidExecuteCommand"
344 );
345
346 let OTLPStart = if IsHighFrequencyCommand { 0 } else { crate::IPC::DevLog::NowNano::Fn() };
347
348 if !IsHighFrequencyCommand {
356 dev_log!("ipc", "invoke: {} args_count={}", command, Arguments.len());
357 }
358
359 ensure_userdata_dirs();
361
362 let RunTime:Arc<ApplicationRunTime> = ApplicationHandle.state::<Arc<ApplicationRunTime>>().inner().clone();
366
367 if IsHighFrequencyCommand {
373 match command.as_str() {
374 "logger:error" | "logger:critical" => {
379 let Msg = Arguments.get(1).and_then(|V| V.as_str()).unwrap_or(
380 Arguments.first().and_then(|V| V.as_str()).unwrap_or(""),
381 );
382 if !Msg.is_empty() {
383 dev_log!("vscode-log", "[ERROR] {}", Msg);
384 }
385 return Ok(Value::Null);
386 },
387 "logger:warn" => {
388 let Msg = Arguments.get(1).and_then(|V| V.as_str()).unwrap_or(
389 Arguments.first().and_then(|V| V.as_str()).unwrap_or(""),
390 );
391 if !Msg.is_empty() {
392 dev_log!("vscode-log", "[WARN] {}", Msg);
393 }
394 return Ok(Value::Null);
395 },
396 "logger:log" | "logger:info" | "logger:debug" | "logger:trace"
397 | "logger:flush" | "logger:setLevel" | "logger:getLevel"
398 | "logger:createLogger" | "logger:registerLogger"
399 | "logger:deregisterLogger" | "logger:getRegisteredLoggers"
400 | "logger:setVisibility"
401 | "log:registerLogger" | "log:createLogger"
407 | "storage:onDidChangeItems" | "storage:logStorage"
409 | "commands:registerCommand" | "commands:unregisterCommand"
411 | "commands:onDidRegisterCommand" | "commands:onDidExecuteCommand"
412 | "configuration:onDidChange"
414 | "storage:optimize" | "storage:isUsed" | "storage:close"
416 | "workspaces:onDidChangeWorkspaceFolders"
418 | "workspaces:onDidChangeWorkspaceName" => {
419 return Ok(Value::Null);
420 },
421 "menubar:updateMenubar" => {
424 use std::sync::atomic::{AtomicU64, Ordering as AO};
425
426 static MENUBAR_CALLS_FAST:AtomicU64 = AtomicU64::new(0);
427
428 let N = MENUBAR_CALLS_FAST.fetch_add(1, AO::Relaxed) + 1;
429
430 if N == 1 || N % 100 == 0 {
431 dev_log!("menubar", "menubar:updateMenubar (fast-path call #{})", N);
432 }
433
434 return Ok(Value::Null);
435 },
436 _ => {}, }
438 }
439
440 let CommandPriority = ResolveChannelPriority(&command);
460
461 let Scheduler = RunTime.Scheduler.clone();
462
463 let (ResultSender, ResultReceiver) = tokio::sync::oneshot::channel::<Result<Value, String>>();
464
465 let DispatchAppHandle = ApplicationHandle.clone();
466
467 let DispatchRuntime = RunTime.clone();
468
469 let DispatchCommand = command.clone();
470
471 let DispatchArgs = Arguments;
472
473 Scheduler.Submit(
474 async move {
475 let ApplicationHandle = DispatchAppHandle;
476 let RunTime = DispatchRuntime;
477 let command = DispatchCommand;
478 let Arguments = DispatchArgs;
479
480 let MatchResult = match command.as_str() {
481 "configuration:get" | "configuration:getValue" => {
487 dev_log!("config", "{}", command);
488 ConfigurationGet(RunTime.clone(), Arguments).await
489 },
490 "configuration:update" | "configuration:updateValue" => {
491 dev_log!("config", "{}", command);
492 ConfigurationUpdate(RunTime.clone(), Arguments).await
493 },
494 "configuration:onDidChange" => Ok(Value::Null),
500
501 "configuration:lookup" => {
507 dev_log!("config", "configuration:lookup (→ get)");
508 ConfigurationGet(RunTime.clone(), Arguments).await
509 },
510
511 "configuration:inspect" => {
521 dev_log!("config", "configuration:inspect");
522 let CurrentValue = ConfigurationGet(RunTime.clone(), Arguments).await.unwrap_or(Value::Null);
523 Ok(json!({
524 "value": CurrentValue,
525 "default": CurrentValue,
526 "user": Value::Null,
527 "workspace": Value::Null,
528 "workspaceFolder": Value::Null,
529 "memory": Value::Null,
530 }))
531 },
532
533 "logger:log" | "logger:warn" | "logger:error" | "logger:info" | "logger:debug" | "logger:trace" => {
538 let Level = command.trim_start_matches("logger:");
539 let Msg = if Arguments.len() >= 2 {
540 let Tail:Vec<String> = Arguments
541 .iter()
542 .skip(1)
543 .filter_map(|V| V.as_str().map(str::to_owned).or_else(|| serde_json::to_string(V).ok()))
544 .collect();
545 Tail.join(" ")
546 } else {
547 Arguments
548 .first()
549 .and_then(|V| V.as_str().map(str::to_owned))
550 .unwrap_or_default()
551 };
552 if !Msg.is_empty() {
553 match Level {
554 "error" | "critical" => dev_log!("vscode-log", "[ERROR] {}", Msg),
555 "warn" => dev_log!("vscode-log", "[WARN] {}", Msg),
556 _ => dev_log!("vscode-log", "{}", Msg),
557 }
558 }
559 Ok(Value::Null)
560 },
561 "logger:flush"
562 | "logger:setLevel"
563 | "logger:getLevel"
564 | "logger:createLogger"
565 | "logger:registerLogger"
566 | "logger:deregisterLogger"
567 | "logger:getRegisteredLoggers"
568 | "logger:setVisibility" => Ok(Value::Null),
569
570 "file:read" | "file:readFile" => FileReadNative(Arguments).await,
582 "file:write" | "file:writeFile" => FileWriteNative(Arguments).await,
583 "file:stat" => FileStatNative(Arguments).await,
584 "file:exists" => FileExistsNative(Arguments).await,
585 "file:delete" => FileDeleteNative(Arguments).await,
586 "file:copy" => FileCloneNative(Arguments).await,
587 "file:move" | "file:rename" => FileRenameNative(Arguments).await,
588 "file:mkdir" => FileMkdirNative(Arguments).await,
589 "file:readdir" => FileReaddirNative(Arguments).await,
590 "file:readBinary" => FileReadBinary(RunTime.clone(), Arguments).await,
591 "file:writeBinary" => FileWriteBinary(RunTime.clone(), Arguments).await,
592 "file:watch" => FileWatch(RunTime.clone(), Arguments).await,
595 "file:unwatch" => FileUnwatch(RunTime.clone(), Arguments).await,
596
597 "storage:get" => StorageGet(RunTime.clone(), Arguments).await,
604 "storage:set" => StorageSet(RunTime.clone(), Arguments).await,
605 "storage:getItems" => {
606 dev_log!("storage-verbose", "storage:getItems");
610 StorageGetItems(RunTime.clone(), Arguments).await
611 },
612 "storage:updateItems" => {
613 dev_log!("storage-verbose", "storage:updateItems");
614 StorageUpdateItems(RunTime.clone(), Arguments).await
615 },
616 "storage:optimize" => {
617 dev_log!("storage", "storage:optimize");
618 Ok(Value::Null)
619 },
620 "storage:isUsed" => {
621 dev_log!("storage", "storage:isUsed");
622 Ok(Value::Null)
623 },
624 "storage:close" => {
625 dev_log!("storage", "storage:close");
626 Ok(Value::Null)
627 },
628 "storage:onDidChangeItems" | "storage:logStorage" => {
632 dev_log!("storage-verbose", "{} (stub-ack)", command);
633 Ok(Value::Null)
634 },
635
636 "environment:get" => {
638 dev_log!("config", "environment:get");
639 EnvironmentGet(RunTime.clone(), Arguments).await
640 },
641
642 "native:showItemInFolder" => ShowItemInFolder(RunTime.clone(), Arguments).await,
644 "native:openExternal" => OpenExternal(RunTime.clone(), Arguments).await,
645
646 "workbench:getConfiguration" => WorkbenchConfiguration(RunTime.clone(), Arguments).await,
648
649 "diagnostic:log" => {
655 let Tag = Arguments.first().and_then(|V| V.as_str()).unwrap_or("webview").to_string();
656 let Message = Arguments.get(1).and_then(|V| V.as_str()).unwrap_or("").to_string();
657 let Extras = if Arguments.len() > 2 {
658 let Tail:Vec<String> = Arguments
659 .iter()
660 .skip(2)
661 .map(|V| {
662 let S = serde_json::to_string(V).unwrap_or_default();
663 if S.len() > 240 {
669 let CutAt = S
670 .char_indices()
671 .map(|(Index, _)| Index)
672 .take_while(|Index| *Index <= 240)
673 .last()
674 .unwrap_or(0);
675 format!("{}…", &S[..CutAt])
676 } else {
677 S
678 }
679 })
680 .collect();
681 format!(" {}", Tail.join(" "))
682 } else {
683 String::new()
684 };
685 dev_log!("diagnostic", "[{}] {}{}", Tag, Message, Extras);
686 Ok(Value::Null)
687 },
688
689 "commands:execute" | "commands:executeCommand" => CommandsExecute(RunTime.clone(), Arguments).await,
694 "commands:getAll" | "commands:getCommands" => {
695 dev_log!("commands", "{}", command);
696 CommandsGetAll(RunTime.clone()).await
697 },
698 "commands:registerCommand"
703 | "commands:unregisterCommand"
704 | "commands:onDidRegisterCommand"
705 | "commands:onDidExecuteCommand" => Ok(Value::Null),
706
707 "extensions:getAll" => {
709 dev_log!("extensions", "extensions:getAll");
710 ExtensionsGetAll(RunTime.clone()).await
711 },
712 "extensions:get" => {
713 dev_log!("extensions", "extensions:get");
714 ExtensionsGet(RunTime.clone(), Arguments).await
715 },
716 "extensions:isActive" => {
717 dev_log!("extensions", "extensions:isActive");
718 ExtensionsIsActive(RunTime.clone(), Arguments).await
719 },
720 "extensions:activate" => {
726 let ExtensionId = Arguments.first().and_then(|V| V.as_str()).unwrap_or("").to_string();
727 dev_log!("extensions", "extensions:activate id={}", ExtensionId);
728 if ExtensionId.is_empty() {
729 Ok(Value::Null)
730 } else {
731 let Notification = json!({
732 "event": format!("onCustom:{}", ExtensionId),
733 "extensionId": ExtensionId,
734 });
735 let _ = crate::Vine::Client::SendNotification::Fn(
736 "cocoon-main".to_string(),
737 "$activateByEvent".to_string(),
738 Notification,
739 )
740 .await;
741 Ok(Value::Null)
742 }
743 },
744
745 "extensions:getInstalled" | "extensions:scanSystemExtensions" => {
758 let ArgsSummary = Arguments
764 .iter()
765 .enumerate()
766 .map(|(Idx, V)| {
767 let Preview = serde_json::to_string(V).unwrap_or_default();
768 let Trimmed = if Preview.len() > 180 {
771 let CutAt = Preview
772 .char_indices()
773 .map(|(Index, _)| Index)
774 .take_while(|Index| *Index <= 180)
775 .last()
776 .unwrap_or(0);
777 format!("{}…", &Preview[..CutAt])
778 } else {
779 Preview
780 };
781 format!("[{}]={}", Idx, Trimmed)
782 })
783 .collect::<Vec<_>>()
784 .join(" ");
785 dev_log!("extensions", "{} Arguments={}", command, ArgsSummary);
786 let EffectiveArgs = if command == "extensions:scanSystemExtensions" {
795 let mut Overridden = Arguments.clone();
796 if Overridden.is_empty() {
797 Overridden.push(Value::Null);
798 }
799 Overridden[0] = json!(0);
800 Overridden
801 } else {
802 Arguments.clone()
803 };
804 ExtensionsGetInstalled(RunTime.clone(), EffectiveArgs).await
805 },
806 "extensions:scanUserExtensions" => {
807 dev_log!("extensions", "{} (forwarded to getInstalled with type=User)", command);
816 let mut UserArgs = Arguments.clone();
817 if UserArgs.is_empty() {
818 UserArgs.push(Value::Null);
819 }
820 UserArgs[0] = json!(1);
821 ExtensionsGetInstalled(RunTime.clone(), UserArgs).await
822 },
823 "extensions:getUninstalled" => {
824 dev_log!("extensions", "{} (returning [])", command);
828 Ok(Value::Array(Vec::new()))
829 },
830 "extensions:query" | "extensions:getExtensions" | "extensions:getRecommendations" => {
834 dev_log!("extensions", "{} (offline gallery - returning [])", command);
835 Ok(Value::Array(Vec::new()))
836 },
837 "extensions:getExtensionsControlManifest" => {
843 dev_log!("extensions", "{} (offline gallery - empty manifest)", command);
844 Ok(json!({
845 "malicious": [],
846 "deprecated": {},
847 "search": [],
848 "autoUpdate": {},
849 }))
850 },
851 "extensions:resetPinnedStateForAllUserExtensions" => {
858 dev_log!("extensions", "{} (no-op, pin state is UI-local)", command);
859 Ok(Value::Null)
860 },
861 "extensions:install" => {
869 Extension::ExtensionInstall::ExtensionInstall(ApplicationHandle.clone(), RunTime.clone(), Arguments)
870 .await
871 },
872 "extensions:uninstall" => {
873 Extension::ExtensionUninstall::ExtensionUninstall(
874 ApplicationHandle.clone(),
875 RunTime.clone(),
876 Arguments,
877 )
878 .await
879 },
880
881 "extensions:getManifest" => {
890 let VsixPath = match Arguments.first() {
891 Some(serde_json::Value::String(Path)) => Path.clone(),
892 Some(Obj) => {
893 Obj.get("fsPath")
894 .and_then(|V| V.as_str())
895 .map(str::to_owned)
896 .or_else(|| Obj.get("path").and_then(|V| V.as_str()).map(str::to_owned))
897 .unwrap_or_default()
898 },
899 None => String::new(),
900 };
901 dev_log!("extensions", "extensions:getManifest vsix={}", VsixPath);
902 if VsixPath.is_empty() {
903 Err("extensions:getManifest: missing VSIX path argument".to_string())
904 } else {
905 let Path = std::path::PathBuf::from(&VsixPath);
906 match crate::ExtensionManagement::VsixInstaller::ReadFullManifest(&Path) {
907 Ok(Manifest) => Ok(Manifest),
908 Err(Error) => {
909 dev_log!(
910 "extensions",
911 "warn: [WindServiceHandlers] extensions:getManifest failed for '{}': {}",
912 VsixPath,
913 Error
914 );
915 Err(format!("extensions:getManifest failed: {}", Error))
916 },
917 }
918 }
919 },
920 "extensions:reinstall" | "extensions:updateMetadata" => {
925 dev_log!("extensions", "{} (no-op: no gallery backend)", command);
926 Ok(Value::Null)
927 },
928
929 "terminal:create" => {
931 dev_log!("terminal", "terminal:create");
932 TerminalCreate(RunTime.clone(), Arguments).await
933 },
934 "terminal:sendText" => {
935 dev_log!("terminal", "terminal:sendText");
936 TerminalSendText(RunTime.clone(), Arguments).await
937 },
938 "terminal:dispose" => {
939 dev_log!("terminal", "terminal:dispose");
940 TerminalDispose(RunTime.clone(), Arguments).await
941 },
942 "terminal:show" => {
943 dev_log!("terminal", "terminal:show");
944 TerminalShow(RunTime.clone(), Arguments).await
945 },
946 "terminal:hide" => {
947 dev_log!("terminal", "terminal:hide");
948 TerminalHide(RunTime.clone(), Arguments).await
949 },
950
951 "output:create" => OutputCreate(ApplicationHandle.clone(), Arguments).await,
953 "output:append" => {
954 dev_log!("output", "output:append");
955 OutputAppend(ApplicationHandle.clone(), Arguments).await
956 },
957 "output:appendLine" => {
958 dev_log!("output", "output:appendLine");
959 OutputAppendLine(ApplicationHandle.clone(), Arguments).await
960 },
961 "output:clear" => {
962 dev_log!("output", "output:clear");
963 OutputClear(ApplicationHandle.clone(), Arguments).await
964 },
965 "output:show" => {
966 dev_log!("output", "output:show");
967 OutputShow(ApplicationHandle.clone(), Arguments).await
968 },
969
970 "textFile:read" => {
972 dev_log!("textfile", "textFile:read");
973 TextfileRead(RunTime.clone(), Arguments).await
974 },
975 "textFile:write" => {
976 dev_log!("textfile", "textFile:write");
977 TextfileWrite(RunTime.clone(), Arguments).await
978 },
979 "textFile:save" => TextfileSave(RunTime.clone(), Arguments).await,
980
981 "storage:delete" => {
983 dev_log!("storage", "storage:delete");
984 StorageDelete(RunTime.clone(), Arguments).await
985 },
986 "storage:keys" => {
987 dev_log!("storage", "storage:keys");
988 StorageKeys(RunTime.clone()).await
989 },
990
991 "notification:show" => {
993 dev_log!("notification", "notification:show");
994 NotificationShow(ApplicationHandle.clone(), Arguments).await
995 },
996 "notification:showProgress" => {
997 dev_log!("notification", "notification:showProgress");
998 NotificationShowProgress(ApplicationHandle.clone(), Arguments).await
999 },
1000 "notification:updateProgress" => {
1001 dev_log!("notification", "notification:updateProgress");
1002 NotificationUpdateProgress(ApplicationHandle.clone(), Arguments).await
1003 },
1004 "notification:endProgress" => {
1005 dev_log!("notification", "notification:endProgress");
1006 NotificationEndProgress(ApplicationHandle.clone(), Arguments).await
1007 },
1008
1009 "progress:begin" => {
1011 dev_log!("progress", "progress:begin");
1012 ProgressBegin(ApplicationHandle.clone(), Arguments).await
1013 },
1014 "progress:report" => {
1015 dev_log!("progress", "progress:report");
1016 ProgressReport(ApplicationHandle.clone(), Arguments).await
1017 },
1018 "progress:end" => {
1019 dev_log!("progress", "progress:end");
1020 ProgressEnd(ApplicationHandle.clone(), Arguments).await
1021 },
1022
1023 "quickInput:showQuickPick" => {
1025 dev_log!("quickinput", "quickInput:showQuickPick");
1026 QuickInputShowQuickPick(RunTime.clone(), Arguments).await
1027 },
1028 "quickInput:showInputBox" => {
1029 dev_log!("quickinput", "quickInput:showInputBox");
1030 QuickInputShowInputBox(RunTime.clone(), Arguments).await
1031 },
1032
1033 "workspaces:getFolders" | "workspaces:getWorkspaceFolders" | "workspaces:getWorkspace" => {
1038 dev_log!("workspaces", "{}", command);
1039 WorkspacesGetFolders(RunTime.clone()).await
1040 },
1041 "workspaces:addFolder" | "workspaces:addWorkspaceFolders" => {
1042 dev_log!("workspaces", "{}", command);
1043 WorkspacesAddFolder(RunTime.clone(), Arguments).await
1044 },
1045 "workspaces:removeFolder" | "workspaces:removeWorkspaceFolders" => {
1046 dev_log!("workspaces", "{}", command);
1047 WorkspacesRemoveFolder(RunTime.clone(), Arguments).await
1048 },
1049 "workspaces:getName" => {
1050 dev_log!("workspaces", "{}", command);
1051 WorkspacesGetName(RunTime.clone()).await
1052 },
1053 "themes:getActive" => {
1055 dev_log!("themes", "themes:getActive");
1056 ThemesGetActive(RunTime.clone()).await
1057 },
1058 "themes:list" => {
1059 dev_log!("themes", "themes:list");
1060 ThemesList(RunTime.clone()).await
1061 },
1062 "themes:set" => {
1063 dev_log!("themes", "themes:set");
1064 ThemesSet(RunTime.clone(), Arguments).await
1065 },
1066 "themes:getColorTheme" => {
1071 dev_log!("themes", "themes:getColorTheme (→ getActive)");
1072 ThemesGetActive(RunTime.clone()).await
1073 },
1074
1075 "search:findInFiles" | "search:textSearch" | "search:searchText" => {
1079 dev_log!("search", "{}", command);
1080 SearchFindInFiles(RunTime.clone(), Arguments).await
1081 },
1082 "search:findFiles" | "search:fileSearch" | "search:searchFile" => {
1083 dev_log!("search", "{}", command);
1084 SearchFindFiles(RunTime.clone(), Arguments).await
1085 },
1086 "search:cancel" | "search:clearCache" | "search:onDidChangeResult" => {
1091 dev_log!("search", "{} (stub-ack)", command);
1092 Ok(Value::Null)
1093 },
1094
1095 "decorations:get" => {
1097 dev_log!("decorations", "decorations:get");
1098 DecorationsGet(RunTime.clone(), Arguments).await
1099 },
1100 "decorations:getMany" => {
1101 dev_log!("decorations", "decorations:getMany");
1102 DecorationsGetMany(RunTime.clone(), Arguments).await
1103 },
1104 "decorations:set" => {
1105 dev_log!("decorations", "decorations:set");
1106 DecorationsSet(RunTime.clone(), Arguments).await
1107 },
1108 "decorations:clear" => {
1109 dev_log!("decorations", "decorations:clear");
1110 DecorationsClear(RunTime.clone(), Arguments).await
1111 },
1112
1113 "workingCopy:isDirty" => {
1115 dev_log!("workingcopy", "workingCopy:isDirty");
1116 WorkingCopyIsDirty(RunTime.clone(), Arguments).await
1117 },
1118 "workingCopy:setDirty" => {
1119 dev_log!("workingcopy", "workingCopy:setDirty");
1120 WorkingCopySetDirty(RunTime.clone(), Arguments).await
1121 },
1122 "workingCopy:getAllDirty" => {
1123 dev_log!("workingcopy", "workingCopy:getAllDirty");
1124 WorkingCopyGetAllDirty(RunTime.clone()).await
1125 },
1126 "workingCopy:getDirtyCount" => {
1127 dev_log!("workingcopy", "workingCopy:getDirtyCount");
1128 WorkingCopyGetDirtyCount(RunTime.clone()).await
1129 },
1130
1131 "keybinding:add" => {
1133 dev_log!("keybinding", "keybinding:add");
1134 KeybindingAdd(RunTime.clone(), Arguments).await
1135 },
1136 "keybinding:remove" => {
1137 dev_log!("keybinding", "keybinding:remove");
1138 KeybindingRemove(RunTime.clone(), Arguments).await
1139 },
1140 "keybinding:lookup" => {
1141 dev_log!("keybinding", "keybinding:lookup");
1142 KeybindingLookup(RunTime.clone(), Arguments).await
1143 },
1144 "keybinding:getAll" => {
1145 dev_log!("keybinding", "keybinding:getAll");
1146 KeybindingGetAll(RunTime.clone()).await
1147 },
1148
1149 "lifecycle:getPhase" => {
1151 dev_log!("lifecycle", "lifecycle:getPhase");
1152 LifecycleGetPhase(RunTime.clone()).await
1153 },
1154 "lifecycle:whenPhase" => {
1155 dev_log!("lifecycle", "lifecycle:whenPhase");
1156 LifecycleWhenPhase(RunTime.clone(), Arguments).await
1157 },
1158 "lifecycle:requestShutdown" => {
1159 dev_log!("lifecycle", "lifecycle:requestShutdown");
1160 LifecycleRequestShutdown(ApplicationHandle.clone()).await
1161 },
1162 "lifecycle:advancePhase" | "lifecycle:setPhase" => {
1163 dev_log!("lifecycle", "{}", command);
1164 let NewPhase = Arguments.first().and_then(|V| V.as_u64()).unwrap_or(1) as u8;
1169 RunTime
1170 .Environment
1171 .ApplicationState
1172 .Feature
1173 .Lifecycle
1174 .AdvanceAndBroadcast(NewPhase, &ApplicationHandle);
1175
1176 if NewPhase >= 3 {
1190 if let Some(MainWindow) = ApplicationHandle.get_webview_window("main") {
1191 if let Ok(false) = MainWindow.is_visible() {
1192 if let Err(Error) = MainWindow.show() {
1193 dev_log!(
1194 "lifecycle",
1195 "warn: [Lifecycle] main window show() failed on phase {}: {}",
1196 NewPhase,
1197 Error
1198 );
1199 } else {
1200 dev_log!(
1201 "lifecycle",
1202 "[Lifecycle] main window revealed on phase {} (hidden-until-ready)",
1203 NewPhase
1204 );
1205 let _ = MainWindow.set_focus();
1206 }
1207 }
1208 }
1209 }
1210
1211 Ok(json!(RunTime.Environment.ApplicationState.Feature.Lifecycle.GetPhase()))
1212 },
1213
1214 "label:getUri" => {
1216 dev_log!("label", "label:getUri");
1217 LabelGetURI(RunTime.clone(), Arguments).await
1218 },
1219 "label:getWorkspace" => {
1220 dev_log!("label", "label:getWorkspace");
1221 LabelGetWorkspace(RunTime.clone()).await
1222 },
1223 "label:getBase" => {
1224 dev_log!("label", "label:getBase");
1225 LabelGetBase(Arguments).await
1226 },
1227
1228 "model:open" => {
1230 dev_log!("model", "model:open");
1231 ModelOpen(RunTime.clone(), Arguments).await
1232 },
1233 "model:close" => {
1234 dev_log!("model", "model:close");
1235 ModelClose(RunTime.clone(), Arguments).await
1236 },
1237 "model:get" => {
1238 dev_log!("model", "model:get");
1239 ModelGet(RunTime.clone(), Arguments).await
1240 },
1241 "model:getAll" => {
1242 dev_log!("model", "model:getAll");
1243 ModelGetAll(RunTime.clone()).await
1244 },
1245 "model:updateContent" => {
1246 dev_log!("model", "model:updateContent");
1247 ModelUpdateContent(RunTime.clone(), Arguments).await
1248 },
1249
1250 "history:goBack" => {
1252 dev_log!("history", "history:goBack");
1253 HistoryGoBack(RunTime.clone()).await
1254 },
1255 "history:goForward" => {
1256 dev_log!("history", "history:goForward");
1257 HistoryGoForward(RunTime.clone()).await
1258 },
1259 "history:canGoBack" => {
1260 dev_log!("history", "history:canGoBack");
1261 HistoryCanGoBack(RunTime.clone()).await
1262 },
1263 "history:canGoForward" => {
1264 dev_log!("history", "history:canGoForward");
1265 HistoryCanGoForward(RunTime.clone()).await
1266 },
1267 "history:push" => {
1268 dev_log!("history", "history:push");
1269 HistoryPush(RunTime.clone(), Arguments).await
1270 },
1271 "history:clear" => {
1272 dev_log!("history", "history:clear");
1273 HistoryClear(RunTime.clone()).await
1274 },
1275 "history:getStack" => {
1276 dev_log!("history", "history:getStack");
1277 HistoryGetStack(RunTime.clone()).await
1278 },
1279
1280 "mountain_get_status" => {
1282 let status = json!({
1283 "connected": true,
1284 "version": "1.0.0"
1285 });
1286 Ok(status)
1287 },
1288 "mountain_get_configuration" => {
1289 let config = json!({
1290 "editor": { "theme": "dark" },
1291 "extensions": { "installed": [] }
1292 });
1293 Ok(config)
1294 },
1295 "mountain_get_services_status" => {
1296 let services = json!({
1297 "editor": { "status": "running" },
1298 "extensionHost": { "status": "running" }
1299 });
1300 Ok(services)
1301 },
1302 "mountain_get_state" => {
1303 let state = json!({
1304 "ui": {},
1305 "editor": {},
1306 "workspace": {}
1307 });
1308 Ok(state)
1309 },
1310
1311 "file:realpath" => FileRealpath(Arguments).await,
1317 "file:open" => FileOpenFd(Arguments).await,
1318 "file:close" => FileCloseFd(Arguments).await,
1319 "file:cloneFile" => FileCloneNative(Arguments).await,
1320
1321 "nativeHost:pickFolderAndOpen" => NativePickFolder(ApplicationHandle.clone(), Arguments).await,
1327 "nativeHost:pickFileAndOpen" => NativePickFolder(ApplicationHandle.clone(), Arguments).await,
1328 "nativeHost:pickFileFolderAndOpen" => NativePickFolder(ApplicationHandle.clone(), Arguments).await,
1329 "nativeHost:pickWorkspaceAndOpen" => NativePickFolder(ApplicationHandle.clone(), Arguments).await,
1330 "nativeHost:showOpenDialog" => NativeShowOpenDialog(ApplicationHandle.clone(), Arguments).await,
1331
1332 "UserInterface.ShowOpenDialog" => {
1338 match NativeShowOpenDialog(ApplicationHandle.clone(), Arguments).await {
1339 Ok(Response) => {
1340 let Paths = Response
1341 .get("filePaths")
1342 .and_then(|V| V.as_array())
1343 .cloned()
1344 .unwrap_or_default();
1345 Ok(Value::Array(Paths))
1346 },
1347 Err(Error) => Err(Error),
1348 }
1349 },
1350 "nativeHost:showSaveDialog" => NativeShowSaveDialog(ApplicationHandle.clone(), Arguments).await,
1351 "UserInterface.ShowSaveDialog" => {
1354 UserInterfaceShowSaveDialog(ApplicationHandle.clone(), Arguments).await
1355 },
1356 "nativeHost:showMessageBox" => NativeShowMessageBox(ApplicationHandle.clone(), Arguments).await,
1357
1358 "nativeHost:getEnvironmentPaths" => NativeGetEnvironmentPaths(ApplicationHandle.clone()).await,
1360
1361 "nativeHost:getOSColorScheme" => {
1363 dev_log!("nativehost", "nativeHost:getOSColorScheme");
1364 NativeGetColorScheme().await
1365 },
1366 "nativeHost:getOSProperties" => {
1367 dev_log!("nativehost", "nativeHost:getOSProperties");
1368 NativeOSProperties().await
1369 },
1370 "nativeHost:getOSStatistics" => {
1371 dev_log!("nativehost", "nativeHost:getOSStatistics");
1372 NativeOSStatistics().await
1373 },
1374 "nativeHost:getOSVirtualMachineHint" => {
1375 dev_log!("nativehost", "nativeHost:getOSVirtualMachineHint");
1376 Ok(json!(0))
1377 },
1378
1379 "nativeHost:isWindowAlwaysOnTop" => {
1381 dev_log!("window", "nativeHost:isWindowAlwaysOnTop");
1382 Ok(json!(false))
1383 },
1384 "nativeHost:isFullScreen" => {
1385 dev_log!("window", "nativeHost:isFullScreen");
1386 NativeIsFullscreen(ApplicationHandle.clone()).await
1387 },
1388 "nativeHost:isMaximized" => {
1389 dev_log!("window", "nativeHost:isMaximized");
1390 NativeIsMaximized(ApplicationHandle.clone()).await
1391 },
1392 "nativeHost:getActiveWindowId" => {
1393 dev_log!("window", "nativeHost:getActiveWindowId");
1394 Ok(json!(1))
1395 },
1396 "nativeHost:getCursorScreenPoint" => {
1411 dev_log!("window", "nativeHost:getCursorScreenPoint");
1412 Ok(json!({ "x": 0, "y": 0 }))
1417 },
1418 "nativeHost:getWindows" => {
1419 let Title = std::env::var("ProductNameShort").unwrap_or_else(|_| "Land".into());
1420 let ActiveDoc = RunTime
1421 .Environment
1422 .ApplicationState
1423 .Workspace
1424 .GetActiveDocumentURI()
1425 .unwrap_or_default();
1426 Ok(json!([{ "id": 1, "title": Title, "filename": ActiveDoc }]))
1427 },
1428 "nativeHost:getWindowCount" => Ok(json!(1)),
1429
1430 "nativeHost:openAgentsWindow" | "nativeHost:openDevToolsWindow" | "nativeHost:openAuxiliaryWindow" => {
1440 dev_log!("window", "{} (acknowledged, no-op - aux window unsupported)", command);
1441 Ok(Value::Null)
1442 },
1443
1444 "nativeHost:focusWindow" => {
1448 dev_log!("window", "{}", command);
1449 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1450 let _ = Window.set_focus();
1451 }
1452 Ok(Value::Null)
1453 },
1454 "nativeHost:maximizeWindow" => {
1455 dev_log!("window", "{}", command);
1456 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1457 let _ = Window.maximize();
1458 }
1459 Ok(Value::Null)
1460 },
1461 "nativeHost:unmaximizeWindow" => {
1462 dev_log!("window", "{}", command);
1463 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1464 let _ = Window.unmaximize();
1465 }
1466 Ok(Value::Null)
1467 },
1468 "nativeHost:minimizeWindow" => {
1469 dev_log!("window", "{}", command);
1470 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1471 let _ = Window.minimize();
1472 }
1473 Ok(Value::Null)
1474 },
1475 "nativeHost:toggleFullScreen" => {
1476 dev_log!("window", "{}", command);
1477 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1478 let IsFullscreen = Window.is_fullscreen().unwrap_or(false);
1479 let _ = Window.set_fullscreen(!IsFullscreen);
1480 }
1481 Ok(Value::Null)
1482 },
1483 "nativeHost:closeWindow" => {
1484 dev_log!("window", "{}", command);
1485 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1491 let _ = Window.destroy();
1492 }
1493 Ok(Value::Null)
1494 },
1495 "nativeHost:setWindowAlwaysOnTop" => {
1496 dev_log!("window", "{}", command);
1497 let OnTop = Arguments.first().and_then(|V| V.as_bool()).unwrap_or(false);
1498 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1499 let _ = Window.set_always_on_top(OnTop);
1500 }
1501 Ok(Value::Null)
1502 },
1503 "nativeHost:toggleWindowAlwaysOnTop" => {
1504 dev_log!("window", "{}", command);
1505 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1511 let _ = Window.set_always_on_top(true);
1512 }
1513 Ok(Value::Null)
1514 },
1515 "nativeHost:setRepresentedFilename" => {
1519 dev_log!("window", "{}", command);
1520 let Path = Arguments.first().and_then(|V| V.as_str()).unwrap_or("").to_string();
1521 if !Path.is_empty() {
1522 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1523 let Filename = std::path::Path::new(&Path)
1526 .file_name()
1527 .and_then(|N| N.to_str())
1528 .unwrap_or(&Path);
1529 let _ = Window.set_title(Filename);
1530 }
1531 }
1532 Ok(Value::Null)
1533 },
1534
1535 "nativeHost:setDocumentEdited" => {
1539 let _ = Arguments;
1540 Ok(Value::Null)
1541 },
1542
1543 "nativeHost:setMinimumSize" => {
1546 let Width = Arguments.first().and_then(|V| V.as_u64()).unwrap_or(400) as u32;
1547 let Height = Arguments.get(1).and_then(|V| V.as_u64()).unwrap_or(300) as u32;
1548 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1549 let _ = Window.set_min_size(Some(tauri::Size::Physical(tauri::PhysicalSize {
1550 width:Width,
1551 height:Height,
1552 })));
1553 }
1554 Ok(Value::Null)
1555 },
1556
1557 "nativeHost:positionWindow" => {
1560 if let Some(Rect) = Arguments.first() {
1561 let X = Rect.get("x").and_then(|V| V.as_i64()).unwrap_or(0) as i32;
1562 let Y = Rect.get("y").and_then(|V| V.as_i64()).unwrap_or(0) as i32;
1563 let W = Rect.get("width").and_then(|V| V.as_u64()).unwrap_or(0) as u32;
1564 let H = Rect.get("height").and_then(|V| V.as_u64()).unwrap_or(0) as u32;
1565 if let Some(Window) = ApplicationHandle.get_webview_window("main") {
1566 let _ =
1567 Window.set_position(tauri::Position::Physical(tauri::PhysicalPosition { x:X, y:Y }));
1568 if W > 0 && H > 0 {
1569 let _ =
1570 Window.set_size(tauri::Size::Physical(tauri::PhysicalSize { width:W, height:H }));
1571 }
1572 }
1573 }
1574 Ok(Value::Null)
1575 },
1576
1577 "nativeHost:updateWindowControls"
1579 | "nativeHost:notifyReady"
1580 | "nativeHost:saveWindowSplash"
1581 | "nativeHost:updateTouchBar"
1582 | "nativeHost:moveWindowTop"
1583 | "nativeHost:setBackgroundThrottling"
1584 | "nativeHost:updateWindowAccentColor" => {
1585 dev_log!("window", "{}", command);
1586 Ok(Value::Null)
1587 },
1588
1589 "nativeHost:isAdmin" => Ok(json!(false)),
1591 "nativeHost:isRunningUnderARM64Translation" => NativeIsRunningUnderARM64Translation().await,
1592 "nativeHost:hasWSLFeatureInstalled" => {
1593 #[cfg(target_os = "windows")]
1594 {
1595 Ok(json!(std::path::Path::new("C:\\Windows\\System32\\wsl.exe").exists()))
1596 }
1597 #[cfg(not(target_os = "windows"))]
1598 {
1599 Ok(json!(false))
1600 }
1601 },
1602 "nativeHost:showItemInFolder" => ShowItemInFolder(RunTime.clone(), Arguments).await,
1603 "nativeHost:openExternal" => OpenExternal(RunTime.clone(), Arguments).await,
1604 "nativeHost:moveItemToTrash" => {
1606 dev_log!("nativehost", "nativeHost:moveItemToTrash");
1607 NativeMoveItemToTrash(Arguments).await
1608 },
1609
1610 "nativeHost:readClipboardText" => {
1612 dev_log!("clipboard", "readClipboardText");
1613 NativeReadClipboardText(Arguments).await
1614 },
1615 "nativeHost:writeClipboardText" => {
1616 dev_log!("clipboard", "writeClipboardText");
1617 NativeWriteClipboardText(Arguments).await
1618 },
1619 "nativeHost:readClipboardFindText" => {
1620 dev_log!("clipboard", "readClipboardFindText");
1621 NativeReadClipboardFindText(Arguments).await
1622 },
1623 "nativeHost:writeClipboardFindText" => {
1624 dev_log!("clipboard", "writeClipboardFindText");
1625 NativeWriteClipboardFindText(Arguments).await
1626 },
1627 "nativeHost:readClipboardBuffer" => {
1628 dev_log!("clipboard", "readClipboardBuffer");
1629 NativeReadClipboardBuffer(Arguments).await
1630 },
1631 "nativeHost:writeClipboardBuffer" => {
1632 dev_log!("clipboard", "writeClipboardBuffer");
1633 NativeWriteClipboardBuffer(Arguments).await
1634 },
1635 "nativeHost:hasClipboard" => {
1636 dev_log!("clipboard", "hasClipboard");
1637 NativeHasClipboard(Arguments).await
1638 },
1639 "nativeHost:readImage" => {
1640 dev_log!("clipboard", "readImage");
1641 NativeReadImage(Arguments).await
1642 },
1643 "nativeHost:triggerPaste" => {
1644 dev_log!("clipboard", "triggerPaste");
1645 NativeTriggerPaste(Arguments).await
1646 },
1647
1648 "nativeHost:getProcessId" => Ok(json!(std::process::id())),
1650 "nativeHost:killProcess" => KillProcess(Arguments).await,
1651
1652 "nativeHost:findFreePort" => NativeFindFreePort(Arguments).await,
1654 "nativeHost:isPortFree" => {
1655 let Port = Arguments.first().and_then(|V| V.as_u64()).unwrap_or(0) as u16;
1656 if Port == 0 {
1657 Ok(json!(false))
1658 } else {
1659 let Free = tokio::net::TcpListener::bind(std::net::SocketAddr::from(([127, 0, 0, 1], Port)))
1660 .await
1661 .is_ok();
1662 Ok(json!(Free))
1663 }
1664 },
1665 "nativeHost:resolveProxy" => {
1670 let Url = Arguments.first().and_then(|V| V.as_str()).unwrap_or("");
1671 let Scheme = if Url.starts_with("https") { "HTTPS" } else { "HTTP" };
1672 let ProxyEnv = std::env::var(format!("{}_PROXY", Scheme))
1673 .or_else(|_| std::env::var(format!("{}_proxy", Scheme.to_lowercase())))
1674 .or_else(|_| std::env::var("ALL_PROXY"))
1675 .or_else(|_| std::env::var("all_proxy"));
1676 match ProxyEnv {
1677 Ok(P) if !P.is_empty() => {
1678 Ok(json!(format!(
1679 "PROXY {}",
1680 P.trim_start_matches("http://").trim_start_matches("https://")
1681 )))
1682 },
1683 _ => Ok(json!("DIRECT")),
1684 }
1685 },
1686 "nativeHost:lookupAuthorization" => Ok(Value::Null),
1687 "nativeHost:lookupKerberosAuthorization" => Ok(Value::Null),
1688 "nativeHost:loadCertificates" => Ok(json!([])),
1689
1690 "nativeHost:relaunch" => Relaunch(ApplicationHandle.clone(), Arguments).await,
1692 "nativeHost:reload" => Reload(ApplicationHandle.clone(), Arguments).await,
1693 "nativeHost:quit" => Quit(ApplicationHandle.clone(), Arguments).await,
1694 "nativeHost:exit" => Exit(ApplicationHandle.clone(), Arguments).await,
1695
1696 "nativeHost:openDevTools" => OpenDevTools(ApplicationHandle.clone(), Arguments).await,
1698 "nativeHost:toggleDevTools" => ToggleDevTools(ApplicationHandle.clone(), Arguments).await,
1699
1700 "nativeHost:getSystemIdleState" => Ok(json!("active")),
1702 "nativeHost:getSystemIdleTime" => Ok(json!(0)),
1703 "nativeHost:getCurrentThermalState" => Ok(json!("nominal")),
1704 "nativeHost:isOnBatteryPower" => Ok(json!(false)),
1705 "nativeHost:startPowerSaveBlocker" => Ok(json!(0)),
1706 "nativeHost:stopPowerSaveBlocker" => Ok(json!(false)),
1707 "nativeHost:isPowerSaveBlockerStarted" => Ok(json!(false)),
1708
1709 "nativeHost:newWindowTab" => Ok(Value::Null),
1711 "nativeHost:showPreviousWindowTab" => Ok(Value::Null),
1712 "nativeHost:showNextWindowTab" => Ok(Value::Null),
1713 "nativeHost:moveWindowTabToNewWindow" => Ok(Value::Null),
1714 "nativeHost:mergeAllWindowTabs" => Ok(Value::Null),
1715 "nativeHost:toggleWindowTabsBar" => Ok(Value::Null),
1716 "nativeHost:installShellCommand" => InstallShellCommand(Arguments).await,
1717 "nativeHost:uninstallShellCommand" => UninstallShellCommand(Arguments).await,
1718
1719 "localPty:getProfiles" => {
1723 dev_log!("terminal", "localPty:getProfiles");
1724 LocalPTYGetProfiles().await
1725 },
1726 "localPty:getDefaultSystemShell" => {
1727 dev_log!("terminal", "localPty:getDefaultSystemShell");
1728 LocalPTYGetDefaultShell().await
1729 },
1730 "localPty:getTerminalLayoutInfo" => {
1738 dev_log!("terminal", "localPty:getTerminalLayoutInfo");
1739 use CommonLibrary::{Environment::Requires::Requires, Storage::StorageProvider::StorageProvider};
1740 let StorageProvider:Arc<dyn StorageProvider> = RunTime.Environment.Require();
1741 match StorageProvider.GetStorageValue(true, "terminal:layoutInfo").await {
1742 Ok(Some(Stored)) => Ok(Stored),
1743 Ok(None) => Ok(Value::Null),
1744 Err(Error) => {
1745 dev_log!("terminal", "warn: [getTerminalLayoutInfo] storage read failed: {}", Error);
1746 Ok(Value::Null)
1747 },
1748 }
1749 },
1750 "localPty:setTerminalLayoutInfo" => {
1753 dev_log!("terminal", "localPty:setTerminalLayoutInfo");
1754 use CommonLibrary::{Environment::Requires::Requires, Storage::StorageProvider::StorageProvider};
1755 let StorageProvider:Arc<dyn StorageProvider> = RunTime.Environment.Require();
1756 let Payload = Arguments.first().cloned().unwrap_or(Value::Null);
1757 let _ = StorageProvider
1758 .UpdateStorageValue(true, "terminal:layoutInfo".to_string(), Some(Payload))
1759 .await;
1760 Ok(Value::Null)
1761 },
1762 "localPty:getPerformanceMarks" => {
1763 dev_log!("terminal", "localPty:getPerformanceMarks");
1764 Ok(json!([]))
1765 },
1766 "localPty:reduceConnectionGraceTime" => {
1767 dev_log!("terminal", "localPty:reduceConnectionGraceTime");
1768 Ok(Value::Null)
1769 },
1770 "localPty:listProcesses" => {
1771 dev_log!("terminal", "localPty:listProcesses");
1772 Ok(json!([]))
1773 },
1774 "localPty:getEnvironment" => {
1775 dev_log!("terminal", "localPty:getEnvironment");
1776 LocalPTYGetEnvironment().await
1777 },
1778 "localPty:getLatency" => {
1790 dev_log!("terminal", "localPty:getLatency");
1791 Ok(json!([]))
1792 },
1793
1794 "cocoon:request" => {
1805 dev_log!("ipc", "cocoon:request method={:?}", Arguments.first());
1806 CocoonRequest(Arguments).await
1807 },
1808 "cocoon:notify" => {
1809 dev_log!("ipc", "cocoon:notify method={:?}", Arguments.first());
1810 CocoonNotify(Arguments).await
1811 },
1812
1813 "localPty:spawn" => {
1830 dev_log!("terminal", "{}", command);
1835 TerminalCreate(RunTime.clone(), Arguments).await
1836 },
1837 "localPty:createProcess" => {
1838 dev_log!("terminal", "{}", command);
1839 LocalPTYCreateProcess(RunTime.clone(), Arguments).await
1840 },
1841 "localPty:start" => {
1842 dev_log!("terminal", "{} no-op (eager-spawn)", command);
1855 Ok(Value::Null)
1856 },
1857 "localPty:input" | "localPty:write" => {
1858 dev_log!("terminal", "{}", command);
1859 TerminalSendText(RunTime.clone(), Arguments).await
1860 },
1861 "localPty:shutdown" | "localPty:dispose" => {
1862 dev_log!("terminal", "{}", command);
1863 TerminalDispose(RunTime.clone(), Arguments).await
1864 },
1865 "localPty:resize" => {
1866 dev_log!("terminal", "localPty:resize");
1867 LocalPTYResize(RunTime.clone(), Arguments).await
1868 },
1869 "localPty:acknowledgeDataEvent" => {
1870 Ok(Value::Null)
1872 },
1873 "localPty:getBackendOS" => {
1878 #[cfg(target_os = "macos")]
1879 {
1880 Ok(json!(1))
1881 }
1882 #[cfg(target_os = "linux")]
1883 {
1884 Ok(json!(2))
1885 }
1886 #[cfg(target_os = "windows")]
1887 {
1888 Ok(json!(3))
1889 }
1890 #[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
1891 {
1892 Ok(json!(2))
1893 }
1894 },
1895
1896 "localPty:refreshProperty" => {
1906 use CommonLibrary::{
1907 Environment::Requires::Requires,
1908 Terminal::TerminalProvider::TerminalProvider,
1909 };
1910 let TerminalId = Arguments.first().and_then(|V| V.as_u64()).unwrap_or(0);
1911 let PropId = Arguments.get(1).and_then(|V| V.as_u64()).unwrap_or(0);
1912 if TerminalId == 0 {
1913 Ok(Value::Null)
1914 } else if PropId == 1 {
1915 let Provider:Arc<dyn TerminalProvider> = RunTime.Environment.Require();
1916 match Provider.GetTerminalProcessId(TerminalId).await {
1917 Ok(Some(Pid)) => Ok(json!(Pid)),
1918 _ => Ok(Value::Null),
1919 }
1920 } else {
1921 Ok(Value::Null)
1922 }
1923 },
1924
1925 "localPty:updateProperty" => Ok(Value::Null),
1928
1929 "localPty:freePortKillProcess" => {
1932 dev_log!("terminal", "localPty:freePortKillProcess");
1933 LocalPTYFreePortKillProcess(Arguments).await
1934 },
1935
1936 "localPty:serializeTerminalState" => {
1941 dev_log!("terminal", "localPty:serializeTerminalState");
1942 SerializeTerminalState(RunTime.clone()).await
1943 },
1944
1945 "localPty:reviveTerminalProcesses" => {
1949 dev_log!(
1950 "terminal",
1951 "localPty:reviveTerminalProcesses count={}",
1952 Arguments.first().and_then(|V| V.as_array()).map(|A| A.len()).unwrap_or(0)
1953 );
1954 ReviveTerminalProcesses(RunTime.clone(), Arguments).await
1955 },
1956
1957 "localPty:getRevivedPtyNewId" => {
1963 let NewId = RunTime.Environment.ApplicationState.GetNextTerminalIdentifier();
1964 dev_log!("terminal", "localPty:getRevivedPtyNewId id={}", NewId);
1965 Ok(json!(NewId))
1966 },
1967
1968 "localPty:attachToProcess" => {
1974 dev_log!("terminal", "localPty:attachToProcess");
1975 AttachToProcess(RunTime.clone(), Arguments).await
1976 },
1977 "localPty:detachFromProcess" => {
1978 dev_log!("terminal", "localPty:detachFromProcess");
1979 DetachFromProcess(RunTime.clone(), Arguments).await
1980 },
1981
1982 "localPty:processBinary"
1986 | "localPty:orphanQuestionReply"
1987 | "localPty:updateTitle"
1988 | "localPty:updateIcon"
1989 | "localPty:installAutoReply"
1990 | "localPty:uninstallAllAutoReplies" => Ok(Value::Null),
1991
1992 "update:_getInitialState" => UpdateGetInitialState().await,
1996 "update:isLatestVersion" => UpdateIsLatestVersion().await,
1997 "update:checkForUpdates" => UpdateCheckForUpdates().await,
1998 "update:downloadUpdate" => UpdateDownloadUpdate().await,
1999 "update:applyUpdate" => UpdateApplyUpdate().await,
2000 "update:quitAndInstall" => UpdateQuitAndInstall().await,
2001
2002 "url:registerExternalUriOpener" => {
2014 dev_log!("url", "url:registerExternalUriOpener");
2015 Ok(Value::Null)
2016 },
2017
2018 "encryption:encrypt" => Encrypt(Arguments).await,
2022 "encryption:decrypt" => Decrypt(Arguments).await,
2023
2024 "extensionHostStarter:createExtensionHost" => {
2028 dev_log!("exthost", "extensionHostStarter:createExtensionHost");
2029 ExtensionHostStarterCreate(Arguments).await
2030 },
2031 "extensionHostStarter:start" => {
2032 dev_log!("exthost", "extensionHostStarter:start");
2033 ExtensionHostStarterStart(Arguments).await
2034 },
2035 "extensionHostStarter:kill" => {
2036 dev_log!("exthost", "extensionHostStarter:kill");
2037 ExtensionHostStarterKill(Arguments).await
2038 },
2039 "extensionHostStarter:getExitInfo" => {
2040 dev_log!("exthost", "extensionHostStarter:getExitInfo");
2041 ExtensionHostStarterGetExitInfo(Arguments).await
2042 },
2043
2044 "cocoon:extensionHostMessage" => {
2048 dev_log!("exthost", "cocoon:extensionHostMessage");
2049 CocoonExtensionHostMessage(ApplicationHandle.clone(), Arguments).await
2050 },
2051
2052 "extensionhostdebugservice:reload" => {
2056 dev_log!("exthost", "extensionhostdebugservice:reload");
2057 ExtensionHostDebugReload(ApplicationHandle.clone()).await
2058 },
2059 "extensionhostdebugservice:close" => {
2060 dev_log!("exthost", "extensionhostdebugservice:close");
2061 ExtensionHostDebugClose(ApplicationHandle.clone()).await
2062 },
2063 "extensionhostdebugservice:attachSession" | "extensionhostdebugservice:terminateSession" => {
2064 dev_log!("exthost", "{}", command);
2065 Ok(Value::Null)
2066 },
2067
2068 "workspaces:getRecentlyOpened" => {
2072 dev_log!("workspaces", "workspaces:getRecentlyOpened");
2073 ReadRecentlyOpened()
2074 },
2075 "workspaces:removeRecentlyOpened" => {
2076 dev_log!("workspaces", "workspaces:removeRecentlyOpened");
2077 let Uri = Arguments.first().and_then(|V| V.as_str()).unwrap_or("").to_string();
2078 if !Uri.is_empty() {
2079 MutateRecentlyOpened(|List| {
2080 if let Some(Workspaces) = List.get_mut("workspaces").and_then(|V| V.as_array_mut()) {
2081 Workspaces
2082 .retain(|Entry| Entry.get("uri").and_then(|V| V.as_str()).unwrap_or("") != Uri);
2083 }
2084 if let Some(Files) = List.get_mut("files").and_then(|V| V.as_array_mut()) {
2085 Files.retain(|Entry| Entry.get("uri").and_then(|V| V.as_str()).unwrap_or("") != Uri);
2086 }
2087 });
2088 }
2089 Ok(Value::Null)
2090 },
2091 "workspaces:addRecentlyOpened" => {
2092 dev_log!("workspaces", "workspaces:addRecentlyOpened");
2093 let Entries:Vec<Value> = Arguments.first().and_then(|V| V.as_array()).cloned().unwrap_or_default();
2095 if !Entries.is_empty() {
2096 MutateRecentlyOpened(|List| {
2097 let Workspaces = List
2098 .get_mut("workspaces")
2099 .and_then(|V| V.as_array_mut())
2100 .map(|V| std::mem::take(V))
2101 .unwrap_or_default();
2102 let Files = List
2103 .get_mut("files")
2104 .and_then(|V| V.as_array_mut())
2105 .map(|V| std::mem::take(V))
2106 .unwrap_or_default();
2107 let mut MergedWorkspaces = Workspaces;
2108 let mut MergedFiles = Files;
2109 for Entry in Entries {
2110 let Folder = Entry
2111 .get("folderUri")
2112 .cloned()
2113 .or_else(|| Entry.get("workspace").and_then(|W| W.get("configPath").cloned()));
2114 let File = Entry.get("fileUri").cloned();
2115 if let Some(FolderUri) = Folder.and_then(|V| v_str(&V)) {
2116 MergedWorkspaces
2117 .retain(|E| E.get("uri").and_then(|V| V.as_str()).unwrap_or("") != FolderUri);
2118 let mut Item = serde_json::Map::new();
2119 Item.insert("uri".into(), json!(FolderUri));
2120 if let Some(Label) = Entry.get("label").and_then(|V| V.as_str()) {
2121 Item.insert("label".into(), json!(Label));
2122 }
2123 MergedWorkspaces.insert(0, Value::Object(Item));
2124 }
2125 if let Some(FileUri) = File.and_then(|V| v_str(&V)) {
2126 MergedFiles
2127 .retain(|E| E.get("uri").and_then(|V| V.as_str()).unwrap_or("") != FileUri);
2128 let mut Item = serde_json::Map::new();
2129 Item.insert("uri".into(), json!(FileUri));
2130 MergedFiles.insert(0, Value::Object(Item));
2131 }
2132 }
2133 MergedWorkspaces.truncate(50);
2136 MergedFiles.truncate(50);
2137 List.insert("workspaces".into(), Value::Array(MergedWorkspaces));
2138 List.insert("files".into(), Value::Array(MergedFiles));
2139 });
2140 }
2141 Ok(Value::Null)
2142 },
2143 "workspaces:clearRecentlyOpened" => {
2144 dev_log!("workspaces", "workspaces:clearRecentlyOpened");
2145 MutateRecentlyOpened(|List| {
2146 List.insert("workspaces".into(), json!([]));
2147 List.insert("files".into(), json!([]));
2148 });
2149 Ok(Value::Null)
2150 },
2151 "workspaces:enterWorkspace" => {
2152 dev_log!("workspaces", "workspaces:enterWorkspace");
2153 Ok(Value::Null)
2154 },
2155 "workspaces:createUntitledWorkspace" => {
2156 dev_log!("workspaces", "workspaces:createUntitledWorkspace");
2157 Ok(Value::Null)
2158 },
2159 "workspaces:deleteUntitledWorkspace" => {
2160 dev_log!("workspaces", "workspaces:deleteUntitledWorkspace");
2161 Ok(Value::Null)
2162 },
2163 "workspaces:getWorkspaceIdentifier" => {
2164 let Workspace = &RunTime.Environment.ApplicationState.Workspace;
2171 let Folders = Workspace.GetWorkspaceFolders();
2172 if let Some(First) = Folders.first() {
2173 use std::{
2174 collections::hash_map::DefaultHasher,
2175 hash::{Hash, Hasher},
2176 };
2177 let mut Hasher = DefaultHasher::new();
2178 First.URI.as_str().hash(&mut Hasher);
2179 let Id = format!("{:016x}", Hasher.finish());
2180 Ok(json!({
2181 "id": Id,
2182 "configPath": Value::Null,
2183 "uri": First.URI.to_string(),
2184 }))
2185 } else {
2186 Ok(Value::Null)
2187 }
2188 },
2189 "workspaces:getDirtyWorkspaces" => Ok(json!([])),
2190
2191 "git:exec" => {
2196 dev_log!("git", "git:exec");
2197 Git::HandleExec::HandleExec(Arguments).await
2198 },
2199 "git:clone" => {
2200 dev_log!("git", "git:clone");
2201 Git::HandleClone::HandleClone(Arguments).await
2202 },
2203 "git:pull" => {
2204 dev_log!("git", "git:pull");
2205 Git::HandlePull::HandlePull(Arguments).await
2206 },
2207 "git:checkout" => {
2208 dev_log!("git", "git:checkout");
2209 Git::HandleCheckout::HandleCheckout(Arguments).await
2210 },
2211 "git:revParse" => {
2212 dev_log!("git", "git:revParse");
2213 Git::HandleRevParse::HandleRevParse(Arguments).await
2214 },
2215 "git:fetch" => {
2216 dev_log!("git", "git:fetch");
2217 Git::HandleFetch::HandleFetch(Arguments).await
2218 },
2219 "git:revListCount" => {
2220 dev_log!("git", "git:revListCount");
2221 Git::HandleRevListCount::HandleRevListCount(Arguments).await
2222 },
2223 "git:cancel" => {
2224 dev_log!("git", "git:cancel");
2225 Git::HandleCancel::HandleCancel(Arguments).await
2226 },
2227 "git:isAvailable" => {
2228 dev_log!("git", "git:isAvailable");
2229 Git::HandleIsAvailable::HandleIsAvailable(Arguments).await
2230 },
2231
2232 "tree:getChildren" => TreeGetChildren(ApplicationHandle.clone(), RunTime.clone(), Arguments).await,
2239
2240 "sky:replay-events" => SkyReplayEvents(ApplicationHandle.clone(), RunTime.clone()).await,
2242
2243 "editor:revealRange" | "window:revealRange" => {
2247 use tauri::Emitter;
2248 let Payload = Arguments.first().cloned().unwrap_or(Value::Null);
2249 let _ = ApplicationHandle.emit("sky://editor/revealRange", &Payload);
2250 Ok(Value::Null)
2251 },
2252
2253 "sky:editor:selectionChanged" => {
2261 let Uri = Arguments
2262 .first()
2263 .and_then(|V| V.get("uri"))
2264 .and_then(|V| V.as_str())
2265 .unwrap_or("")
2266 .to_string();
2267 let Selections = Arguments
2268 .first()
2269 .and_then(|V| V.get("selections"))
2270 .cloned()
2271 .unwrap_or(Value::Array(Vec::new()));
2272 dev_log!("model", "[SelectionChanged] uri={}", Uri);
2273 if !Uri.is_empty() {
2275 RunTime
2276 .Environment
2277 .ApplicationState
2278 .Workspace
2279 .SetActiveDocumentURI(Some(Uri.clone()));
2280 }
2281 let Payload = json!({ "uri": Uri, "selections": Selections });
2283 let _ = crate::Vine::Client::SendNotification::Fn(
2284 "cocoon-main".to_string(),
2285 "window.didChangeTextEditorSelection".to_string(),
2286 Payload,
2287 )
2288 .await;
2289 Ok(Value::Null)
2290 },
2291
2292 "sky:editor:activeChanged" => {
2294 let Payload = Arguments.first().cloned().unwrap_or(Value::Null);
2295 let Uri = Payload.get("uri").and_then(Value::as_str).unwrap_or("").to_string();
2296 dev_log!("model", "[ActiveEditorChanged] uri={}", Uri);
2297 if !Uri.is_empty() {
2298 RunTime
2299 .Environment
2300 .ApplicationState
2301 .Workspace
2302 .SetActiveDocumentURI(Some(Uri.clone()));
2303 }
2304 let _ = crate::Vine::Client::SendNotification::Fn(
2305 "cocoon-main".to_string(),
2306 "window.didChangeActiveTextEditor".to_string(),
2307 Payload,
2308 )
2309 .await;
2310 Ok(Value::Null)
2311 },
2312
2313 "languages:getAll" | "languages:getEncodedLanguageId" => {
2320 dev_log!("extensions", "languages: {} (→ Cocoon)", command);
2321 let Payload = Arguments.into_iter().next().unwrap_or(Value::Null);
2322 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2323 Ok(
2324 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 5_000)
2325 .await
2326 .unwrap_or(Value::Array(Vec::new())),
2327 )
2328 },
2329
2330 "scm:createSourceControl" | "scm:getSourceControls" | "scm:setActiveProvider" => {
2334 dev_log!("ipc", "scm: {} (→ Cocoon)", command);
2335 let Payload = if Arguments.is_empty() {
2336 Value::Null
2337 } else if Arguments.len() == 1 {
2338 Arguments.into_iter().next().unwrap()
2339 } else {
2340 Value::Array(Arguments)
2341 };
2342 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2343 Ok(
2344 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 10_000)
2345 .await
2346 .unwrap_or(Value::Null),
2347 )
2348 },
2349
2350 "debug:startDebugging"
2354 | "debug:stopDebugging"
2355 | "debug:getSessions"
2356 | "debug:getBreakpoints"
2357 | "debug:addBreakpoints"
2358 | "debug:removeBreakpoints" => {
2359 dev_log!("ipc", "debug: {} (→ Cocoon)", command);
2360 let Payload = if Arguments.is_empty() {
2361 Value::Null
2362 } else if Arguments.len() == 1 {
2363 Arguments.into_iter().next().unwrap()
2364 } else {
2365 Value::Array(Arguments)
2366 };
2367 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2368 Ok(
2369 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 10_000)
2370 .await
2371 .unwrap_or(Value::Null),
2372 )
2373 },
2374
2375 "tasks:executeTask" | "tasks:getTasks" | "tasks:getTaskExecution" => {
2379 dev_log!("ipc", "tasks: {} (→ Cocoon)", command);
2380 let Payload = if Arguments.is_empty() {
2381 Value::Null
2382 } else if Arguments.len() == 1 {
2383 Arguments.into_iter().next().unwrap()
2384 } else {
2385 Value::Array(Arguments)
2386 };
2387 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2388 Ok(
2389 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 10_000)
2390 .await
2391 .unwrap_or(Value::Null),
2392 )
2393 },
2394
2395 "auth:getSessions" | "auth:createSession" | "auth:removeSession" => {
2399 dev_log!("ipc", "auth: {} (→ Cocoon)", command);
2400 let Payload = if Arguments.is_empty() {
2401 Value::Null
2402 } else if Arguments.len() == 1 {
2403 Arguments.into_iter().next().unwrap()
2404 } else {
2405 Value::Array(Arguments)
2406 };
2407 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2408 Ok(
2409 crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 10_000)
2410 .await
2411 .unwrap_or(Value::Null),
2412 )
2413 },
2414
2415 _ => {
2428 use std::str::FromStr;
2429
2430 let TierIPC = std::env::var("TierIPC").unwrap_or_else(|_| "Mountain".into());
2435 let ShouldDefer = TierIPC == "NodeDeferred" || TierIPC == "Node";
2436
2437 if ShouldDefer {
2438 let Payload = if Arguments.is_empty() {
2442 Value::Null
2443 } else if Arguments.len() == 1 {
2444 Arguments.into_iter().next().unwrap()
2445 } else {
2446 Value::Array(Arguments)
2447 };
2448 dev_log!("ipc", "deferred → Cocoon: {}", command);
2449 let _ = crate::Vine::Client::WaitForClientConnection::Fn("cocoon-main", 3000).await;
2450 match crate::Vine::Client::SendRequest::Fn("cocoon-main", command.clone(), Payload, 15_000)
2451 .await
2452 {
2453 Ok(Response) => Ok(Response),
2454 Err(CocoonError) => {
2455 dev_log!(
2456 "ipc",
2457 "warn: [NodeDeferred] {} deferred but Cocoon rejected: {:?}",
2458 command,
2459 CocoonError
2460 );
2461 Ok(Value::Null)
2462 },
2463 }
2464 } else {
2465 match CommonLibrary::IPC::Channel::Channel::from_str(&command) {
2466 Ok(KnownChannel) => {
2467 dev_log!(
2468 "ipc",
2469 "error: [WindServiceHandlers] Channel {:?} is registered but has no dispatch arm",
2470 KnownChannel
2471 );
2472 Err(format!("IPC channel registered but unimplemented: {}", command))
2473 },
2474 Err(_) => {
2475 dev_log!("ipc", "error: [WindServiceHandlers] Unknown IPC command: {}", command);
2476 Err(format!("Unknown IPC command: {}", command))
2477 },
2478 }
2479 }
2480 },
2481 };
2482
2483 if ResultSender.send(MatchResult).is_err() {
2484 dev_log!(
2485 "ipc",
2486 "warn: [WindServiceHandlers] IPC result receiver dropped before dispatch completed"
2487 );
2488 }
2489 },
2490 CommandPriority,
2491 );
2492
2493 let Result = match ResultReceiver.await {
2494 Ok(Dispatched) => Dispatched,
2495 Err(_) => {
2496 dev_log!(
2497 "ipc",
2498 "error: [WindServiceHandlers] IPC task cancelled before producing a result"
2499 );
2500 Err("IPC task cancelled before result was produced".to_string())
2501 },
2502 };
2503
2504 if !IsHighFrequencyCommand {
2508 let IsErr = Result.is_err();
2509 let SpanName = if IsErr {
2510 format!("land:mountain:ipc:{}:error", command)
2511 } else {
2512 format!("land:mountain:ipc:{}", command)
2513 };
2514 crate::otel_span!(&SpanName, OTLPStart, &[("ipc.command", command.as_str())]);
2515
2516 let HandlerElapsedNanos = crate::IPC::DevLog::NowNano::Fn().saturating_sub(OTLPStart);
2520 let HandlerDurationMs = HandlerElapsedNanos / 1_000_000;
2521 crate::Binary::Build::PostHogPlugin::CaptureHandler::Fn(&command, HandlerDurationMs, !IsErr);
2522 }
2523
2524 if !IsHighFrequencyCommand {
2533 let ElapsedNanos = crate::IPC::DevLog::NowNano::Fn().saturating_sub(OTLPStart);
2534 dev_log!("ipc", "done: {} ok={} t_ns={}", command, !Result.is_err(), ElapsedNanos);
2535 }
2536
2537 Result
2538}
2539
2540pub fn register_wind_ipc_handlers(ApplicationHandle:&tauri::AppHandle) -> Result<(), String> {
2541 dev_log!("lifecycle", "registering IPC handlers");
2542
2543 Ok(())
2547}