neoagent 2.3.1-beta.11 → 2.3.1-beta.111

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (390) hide show
  1. package/.env.example +53 -5
  2. package/README.md +16 -7
  3. package/com.neoagent.plist +1 -1
  4. package/docs/automation.md +82 -41
  5. package/docs/capabilities.md +85 -89
  6. package/docs/configuration.md +87 -94
  7. package/docs/getting-started.md +46 -27
  8. package/docs/hardware.md +1 -1
  9. package/docs/index.md +24 -30
  10. package/docs/integrations.md +46 -64
  11. package/docs/migration.md +41 -146
  12. package/docs/operations.md +23 -20
  13. package/docs/skills.md +20 -20
  14. package/docs/why-neoagent.md +15 -13
  15. package/extensions/chrome-browser/background.mjs +10 -2
  16. package/flutter_app/.metadata +42 -0
  17. package/flutter_app/DESIGN_SYSTEM.md +166 -0
  18. package/flutter_app/README.md +21 -0
  19. package/flutter_app/analysis_options.yaml +32 -0
  20. package/flutter_app/android/app/build.gradle.kts +111 -0
  21. package/flutter_app/android/app/src/debug/AndroidManifest.xml +7 -0
  22. package/flutter_app/android/app/src/main/AndroidManifest.xml +185 -0
  23. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +888 -0
  24. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/auto/NeoAgentCarAppService.kt +114 -0
  25. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthConnectGateway.kt +280 -0
  26. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncNotifications.kt +113 -0
  27. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncPayload.kt +57 -0
  28. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncScheduler.kt +78 -0
  29. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncWorker.kt +253 -0
  30. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/PermissionsRationaleActivity.kt +46 -0
  31. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +21 -0
  32. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +586 -0
  33. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +78 -0
  34. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +104 -0
  35. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/telecom/NeoAgentConnection.kt +118 -0
  36. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/telecom/NeoAgentConnectionService.kt +86 -0
  37. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiHomeWidgetProvider.kt +457 -0
  38. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiWidgetStore.kt +194 -0
  39. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/VoiceLaunchWidgetProvider.kt +67 -0
  40. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetConfigActivity.kt +228 -0
  41. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncScheduler.kt +72 -0
  42. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncWorker.kt +186 -0
  43. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetTaskRunWorker.kt +210 -0
  44. package/flutter_app/android/app/src/main/res/drawable/launch_background.xml +12 -0
  45. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_bg.xml +11 -0
  46. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_task_bg.xml +8 -0
  47. package/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  48. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget.xml +138 -0
  49. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget_task_row.xml +52 -0
  50. package/flutter_app/android/app/src/main/res/layout/neoagent_voice_widget.xml +49 -0
  51. package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  52. package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  53. package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  54. package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  55. package/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  56. package/flutter_app/android/app/src/main/res/values/arrays.xml +8 -0
  57. package/flutter_app/android/app/src/main/res/values/strings.xml +12 -0
  58. package/flutter_app/android/app/src/main/res/values/styles.xml +18 -0
  59. package/flutter_app/android/app/src/main/res/values-night/styles.xml +18 -0
  60. package/flutter_app/android/app/src/main/res/xml/automotive_app_desc.xml +4 -0
  61. package/flutter_app/android/app/src/main/res/xml/file_paths.xml +6 -0
  62. package/flutter_app/android/app/src/main/res/xml/neoagent_ai_widget_info.xml +12 -0
  63. package/flutter_app/android/app/src/main/res/xml/neoagent_voice_widget_info.xml +12 -0
  64. package/flutter_app/android/app/src/profile/AndroidManifest.xml +7 -0
  65. package/flutter_app/android/build.gradle.kts +24 -0
  66. package/flutter_app/android/ci-release.keystore +0 -0
  67. package/flutter_app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  68. package/flutter_app/android/gradle.properties +3 -0
  69. package/flutter_app/android/key.properties +4 -0
  70. package/flutter_app/android/settings.gradle.kts +26 -0
  71. package/flutter_app/assets/branding/app_icon_1024.png +0 -0
  72. package/flutter_app/assets/branding/app_icon_128.png +0 -0
  73. package/flutter_app/assets/branding/app_icon_192.png +0 -0
  74. package/flutter_app/assets/branding/app_icon_256.png +0 -0
  75. package/flutter_app/assets/branding/app_icon_32.png +0 -0
  76. package/flutter_app/assets/branding/app_icon_512.png +0 -0
  77. package/flutter_app/assets/branding/app_icon_64.png +0 -0
  78. package/flutter_app/assets/branding/onboarding_intro.mp4 +0 -0
  79. package/flutter_app/assets/branding/tray_icon_template.png +0 -0
  80. package/flutter_app/lib/features/location/location_service.dart +117 -0
  81. package/flutter_app/lib/features/notifications/notification_interceptor.dart +73 -0
  82. package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +571 -0
  83. package/flutter_app/lib/features/onboarding/onboarding_messaging_step.dart +275 -0
  84. package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +366 -0
  85. package/flutter_app/lib/features/onboarding/onboarding_shell.dart +57 -0
  86. package/flutter_app/lib/features/onboarding/onboarding_video_step.dart +218 -0
  87. package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +46 -0
  88. package/flutter_app/lib/main.dart +107 -0
  89. package/flutter_app/lib/main_account_settings.dart +1340 -0
  90. package/flutter_app/lib/main_admin.dart +900 -0
  91. package/flutter_app/lib/main_app_shell.dart +2162 -0
  92. package/flutter_app/lib/main_chat.dart +3902 -0
  93. package/flutter_app/lib/main_controller.dart +7229 -0
  94. package/flutter_app/lib/main_devices.dart +1738 -0
  95. package/flutter_app/lib/main_integrations.dart +917 -0
  96. package/flutter_app/lib/main_launcher.dart +959 -0
  97. package/flutter_app/lib/main_launcher_entry.dart +5 -0
  98. package/flutter_app/lib/main_models.dart +3807 -0
  99. package/flutter_app/lib/main_navigation.dart +206 -0
  100. package/flutter_app/lib/main_operations.dart +5249 -0
  101. package/flutter_app/lib/main_recordings.dart +920 -0
  102. package/flutter_app/lib/main_runtime.dart +869 -0
  103. package/flutter_app/lib/main_settings.dart +2288 -0
  104. package/flutter_app/lib/main_shared.dart +3393 -0
  105. package/flutter_app/lib/main_spacing.dart +33 -0
  106. package/flutter_app/lib/main_theme.dart +276 -0
  107. package/flutter_app/lib/main_unified.dart +388 -0
  108. package/flutter_app/lib/main_voice_assistant.dart +957 -0
  109. package/flutter_app/lib/src/analytics_service.dart +294 -0
  110. package/flutter_app/lib/src/android_apk_drop_zone.dart +32 -0
  111. package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +16 -0
  112. package/flutter_app/lib/src/android_apk_drop_zone_web.dart +348 -0
  113. package/flutter_app/lib/src/android_app_installer.dart +22 -0
  114. package/flutter_app/lib/src/android_app_installer_io.dart +122 -0
  115. package/flutter_app/lib/src/android_app_installer_stub.dart +21 -0
  116. package/flutter_app/lib/src/android_auto_bridge.dart +59 -0
  117. package/flutter_app/lib/src/android_launcher_bridge.dart +239 -0
  118. package/flutter_app/lib/src/app_launch_bridge.dart +58 -0
  119. package/flutter_app/lib/src/app_release_updater.dart +511 -0
  120. package/flutter_app/lib/src/backend_client.dart +1870 -0
  121. package/flutter_app/lib/src/desktop_companion.dart +2 -0
  122. package/flutter_app/lib/src/desktop_companion_actions.dart +586 -0
  123. package/flutter_app/lib/src/desktop_companion_io.dart +538 -0
  124. package/flutter_app/lib/src/desktop_companion_stub.dart +59 -0
  125. package/flutter_app/lib/src/desktop_native_bridge.dart +91 -0
  126. package/flutter_app/lib/src/desktop_screen_capture.dart +21 -0
  127. package/flutter_app/lib/src/desktop_screen_capture_io.dart +142 -0
  128. package/flutter_app/lib/src/desktop_screen_capture_stub.dart +12 -0
  129. package/flutter_app/lib/src/diagnostics_logger.dart +119 -0
  130. package/flutter_app/lib/src/health_bridge.dart +136 -0
  131. package/flutter_app/lib/src/live_voice_capture.dart +85 -0
  132. package/flutter_app/lib/src/messaging_access_summary.dart +46 -0
  133. package/flutter_app/lib/src/network/app_http_client.dart +53 -0
  134. package/flutter_app/lib/src/network/app_http_client_factory.dart +6 -0
  135. package/flutter_app/lib/src/network/app_http_client_io.dart +138 -0
  136. package/flutter_app/lib/src/network/app_http_client_stub.dart +3 -0
  137. package/flutter_app/lib/src/network/app_http_client_web.dart +94 -0
  138. package/flutter_app/lib/src/oauth_launcher.dart +33 -0
  139. package/flutter_app/lib/src/oauth_launcher_io.dart +95 -0
  140. package/flutter_app/lib/src/oauth_launcher_stub.dart +33 -0
  141. package/flutter_app/lib/src/oauth_launcher_web.dart +107 -0
  142. package/flutter_app/lib/src/recording_bridge.dart +232 -0
  143. package/flutter_app/lib/src/recording_bridge_io.dart +1019 -0
  144. package/flutter_app/lib/src/recording_bridge_stub.dart +120 -0
  145. package/flutter_app/lib/src/recording_bridge_web.dart +689 -0
  146. package/flutter_app/lib/src/recording_payloads.dart +86 -0
  147. package/flutter_app/lib/src/theme/palette.dart +81 -0
  148. package/flutter_app/lib/src/web_app_update_monitor.dart +17 -0
  149. package/flutter_app/lib/src/web_app_update_monitor_stub.dart +24 -0
  150. package/flutter_app/lib/src/web_app_update_monitor_web.dart +123 -0
  151. package/flutter_app/lib/src/widget_bridge.dart +49 -0
  152. package/flutter_app/linux/CMakeLists.txt +128 -0
  153. package/flutter_app/linux/flutter/CMakeLists.txt +88 -0
  154. package/flutter_app/linux/flutter/generated_plugin_registrant.cc +47 -0
  155. package/flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
  156. package/flutter_app/linux/flutter/generated_plugins.cmake +32 -0
  157. package/flutter_app/linux/runner/CMakeLists.txt +26 -0
  158. package/flutter_app/linux/runner/main.cc +6 -0
  159. package/flutter_app/linux/runner/my_application.cc +144 -0
  160. package/flutter_app/linux/runner/my_application.h +18 -0
  161. package/flutter_app/linux/runner/resources/app_icon.png +0 -0
  162. package/flutter_app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
  163. package/flutter_app/macos/Flutter/Flutter-Release.xcconfig +2 -0
  164. package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +48 -0
  165. package/flutter_app/macos/Podfile +42 -0
  166. package/flutter_app/macos/Podfile.lock +87 -0
  167. package/flutter_app/macos/Runner/AppDelegate.swift +576 -0
  168. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  169. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  170. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  171. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  172. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  173. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  174. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  175. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  176. package/flutter_app/macos/Runner/Base.lproj/MainMenu.xib +342 -0
  177. package/flutter_app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  178. package/flutter_app/macos/Runner/Configs/Debug.xcconfig +2 -0
  179. package/flutter_app/macos/Runner/Configs/Release.xcconfig +2 -0
  180. package/flutter_app/macos/Runner/Configs/Warnings.xcconfig +13 -0
  181. package/flutter_app/macos/Runner/DebugProfile.entitlements +16 -0
  182. package/flutter_app/macos/Runner/Info.plist +36 -0
  183. package/flutter_app/macos/Runner/MainFlutterWindow.swift +19 -0
  184. package/flutter_app/macos/Runner/Release.entitlements +12 -0
  185. package/flutter_app/macos/Runner.xcodeproj/project.pbxproj +801 -0
  186. package/flutter_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  187. package/flutter_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
  188. package/flutter_app/macos/Runner.xcworkspace/contents.xcworkspacedata +10 -0
  189. package/flutter_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  190. package/flutter_app/macos/RunnerTests/RunnerTests.swift +12 -0
  191. package/flutter_app/patch_strings.py +12 -0
  192. package/flutter_app/pubspec.lock +1256 -0
  193. package/flutter_app/pubspec.yaml +59 -0
  194. package/flutter_app/third_party/desktop_audio_capture/LICENSE +21 -0
  195. package/flutter_app/third_party/desktop_audio_capture/README.md +262 -0
  196. package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +65 -0
  197. package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +153 -0
  198. package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +110 -0
  199. package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +461 -0
  200. package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +91 -0
  201. package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +106 -0
  202. package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +219 -0
  203. package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +336 -0
  204. package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +101 -0
  205. package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +692 -0
  206. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +35 -0
  207. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +36 -0
  208. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +32 -0
  209. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +32 -0
  210. package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +878 -0
  211. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +27 -0
  212. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +1172 -0
  213. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +655 -0
  214. package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +12 -0
  215. package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +30 -0
  216. package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +87 -0
  217. package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +105 -0
  218. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +80 -0
  219. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +31 -0
  220. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +12 -0
  221. package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +23 -0
  222. package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +25 -0
  223. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +1117 -0
  224. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +115 -0
  225. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +777 -0
  226. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +87 -0
  227. package/flutter_app/third_party/flutter_secure_storage_linux/linux/CMakeLists.txt +30 -0
  228. package/flutter_app/third_party/flutter_secure_storage_linux/linux/flutter_secure_storage_linux_plugin.cc +215 -0
  229. package/flutter_app/third_party/flutter_secure_storage_linux/linux/include/flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h +27 -0
  230. package/flutter_app/third_party/flutter_secure_storage_linux/pubspec.yaml +20 -0
  231. package/flutter_app/tool/generate_desktop_branding.py +219 -0
  232. package/flutter_app/web/favicon.png +0 -0
  233. package/flutter_app/web/favicon.svg +12 -0
  234. package/flutter_app/web/icons/Icon-192.png +0 -0
  235. package/flutter_app/web/icons/Icon-512.png +0 -0
  236. package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
  237. package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
  238. package/flutter_app/web/index.html +39 -0
  239. package/flutter_app/web/manifest.json +35 -0
  240. package/flutter_app/windows/CMakeLists.txt +108 -0
  241. package/flutter_app/windows/flutter/CMakeLists.txt +109 -0
  242. package/flutter_app/windows/flutter/generated_plugin_registrant.cc +50 -0
  243. package/flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
  244. package/flutter_app/windows/flutter/generated_plugins.cmake +36 -0
  245. package/flutter_app/windows/runner/CMakeLists.txt +41 -0
  246. package/flutter_app/windows/runner/Runner.rc +121 -0
  247. package/flutter_app/windows/runner/flutter_window.cpp +533 -0
  248. package/flutter_app/windows/runner/flutter_window.h +37 -0
  249. package/flutter_app/windows/runner/main.cpp +53 -0
  250. package/flutter_app/windows/runner/resource.h +16 -0
  251. package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
  252. package/flutter_app/windows/runner/runner.exe.manifest +14 -0
  253. package/flutter_app/windows/runner/utils.cpp +65 -0
  254. package/flutter_app/windows/runner/utils.h +19 -0
  255. package/flutter_app/windows/runner/win32_window.cpp +299 -0
  256. package/flutter_app/windows/runner/win32_window.h +102 -0
  257. package/lib/install_helpers.js +31 -0
  258. package/lib/manager.js +579 -122
  259. package/package.json +10 -3
  260. package/runtime/paths.js +137 -0
  261. package/server/config/analytics.js +30 -0
  262. package/server/db/database.js +296 -22
  263. package/server/guest-agent.android.package.json +13 -0
  264. package/server/guest-agent.browser.package.json +14 -0
  265. package/server/guest_agent.js +98 -52
  266. package/server/http/middleware.js +5 -2
  267. package/server/http/routes.js +3 -0
  268. package/server/http/static.js +41 -1
  269. package/server/index.js +15 -16
  270. package/server/public/.last_build_id +1 -1
  271. package/server/public/assets/AssetManifest.bin +1 -1
  272. package/server/public/assets/AssetManifest.bin.json +1 -1
  273. package/server/public/assets/AssetManifest.json +1 -1
  274. package/server/public/assets/NOTICES +644 -155
  275. package/server/public/assets/assets/branding/onboarding_intro.mp4 +0 -0
  276. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  277. package/server/public/assets/packages/mixpanel_flutter/assets/mixpanel.js +3 -0
  278. package/server/public/canvaskit/wimp.wasm +0 -0
  279. package/server/public/flutter_bootstrap.js +2 -2
  280. package/server/public/main.dart.js +96067 -88139
  281. package/server/routes/account.js +26 -1
  282. package/server/routes/agents.js +6 -2
  283. package/server/routes/android.js +22 -6
  284. package/server/routes/auth.js +25 -5
  285. package/server/routes/browser.js +47 -13
  286. package/server/routes/integrations.js +22 -1
  287. package/server/routes/memory.js +168 -6
  288. package/server/routes/runtime.js +14 -0
  289. package/server/routes/settings.js +102 -24
  290. package/server/routes/skills.js +12 -0
  291. package/server/routes/social_video.js +66 -0
  292. package/server/routes/tasks.js +22 -2
  293. package/server/routes/triggers.js +44 -35
  294. package/server/routes/wearable.js +67 -0
  295. package/server/routes/widgets.js +4 -4
  296. package/server/services/ai/capabilityHealth.js +23 -51
  297. package/server/services/ai/compaction.js +1 -1
  298. package/server/services/ai/deliverables/artifact_helpers.js +190 -0
  299. package/server/services/ai/deliverables/contracts.js +113 -0
  300. package/server/services/ai/deliverables/index.js +20 -0
  301. package/server/services/ai/deliverables/selector.js +94 -0
  302. package/server/services/ai/deliverables/validator.js +63 -0
  303. package/server/services/ai/deliverables/workflows.js +207 -0
  304. package/server/services/ai/engine.js +363 -27
  305. package/server/services/ai/hooks.js +127 -0
  306. package/server/services/ai/integrated_tools/index.js +98 -0
  307. package/server/services/ai/integrated_tools/remotion.js +373 -0
  308. package/server/services/ai/integrated_tools/shared.js +204 -0
  309. package/server/services/ai/integrated_tools/slidev.js +207 -0
  310. package/server/services/ai/loopPolicy.js +146 -0
  311. package/server/services/ai/models.js +31 -4
  312. package/server/services/ai/providers/claudeCode.js +49 -0
  313. package/server/services/ai/providers/openai.js +2 -1
  314. package/server/services/ai/providers/openaiCodex.js +422 -15
  315. package/server/services/ai/recordingInsights.js +11 -13
  316. package/server/services/ai/runEvents.js +100 -0
  317. package/server/services/ai/settings.js +12 -2
  318. package/server/services/ai/systemPrompt.js +15 -1
  319. package/server/services/ai/taskAnalysis.js +2 -0
  320. package/server/services/ai/toolResult.js +20 -0
  321. package/server/services/ai/toolRunner.js +46 -6
  322. package/server/services/ai/toolSelector.js +54 -1
  323. package/server/services/ai/tools.js +210 -116
  324. package/server/services/android/android_bootstrap_worker.js +63 -0
  325. package/server/services/android/controller.js +442 -1760
  326. package/server/services/bootstrap_helpers.js +0 -34
  327. package/server/services/browser/controller.js +279 -49
  328. package/server/services/cli/executor.js +40 -1
  329. package/server/services/desktop/screenRecorder.js +65 -9
  330. package/server/services/integrations/figma/provider.js +1 -0
  331. package/server/services/integrations/github/provider.js +3 -3
  332. package/server/services/integrations/google/provider.js +1 -0
  333. package/server/services/integrations/manager.js +25 -5
  334. package/server/services/integrations/microsoft/provider.js +1 -0
  335. package/server/services/integrations/oauth_provider.js +15 -5
  336. package/server/services/integrations/provider_config_store.js +22 -13
  337. package/server/services/integrations/registry.js +2 -4
  338. package/server/services/integrations/spotify/provider.js +1 -0
  339. package/server/services/integrations/trello/provider.js +842 -0
  340. package/server/services/manager.js +88 -155
  341. package/server/services/mcp/client.js +120 -23
  342. package/server/services/memory/llm_transfer.js +218 -0
  343. package/server/services/memory/manager.js +260 -33
  344. package/server/services/messaging/access_policy.js +10 -0
  345. package/server/services/messaging/automation.js +1 -1
  346. package/server/services/messaging/manager.js +64 -1
  347. package/server/services/messaging/meshtastic.js +277 -0
  348. package/server/services/messaging/meshtastic_env.js +40 -0
  349. package/server/services/messaging/meshtastic_protocol.js +530 -0
  350. package/server/services/messaging/meshtastic_tcp_transport.js +25 -0
  351. package/server/services/runtime/backends/local-vm.js +221 -158
  352. package/server/services/runtime/docker-vm-manager.js +392 -0
  353. package/server/services/runtime/guest_bootstrap.js +654 -0
  354. package/server/services/runtime/manager.js +85 -29
  355. package/server/services/runtime/settings.js +22 -31
  356. package/server/services/runtime/validation.js +16 -31
  357. package/server/services/social_video/adapters/base.js +26 -0
  358. package/server/services/social_video/adapters/index.js +27 -0
  359. package/server/services/social_video/adapters/instagram.js +17 -0
  360. package/server/services/social_video/adapters/tiktok.js +17 -0
  361. package/server/services/social_video/adapters/x.js +17 -0
  362. package/server/services/social_video/adapters/youtube.js +17 -0
  363. package/server/services/social_video/captions.js +187 -0
  364. package/server/services/social_video/frame.js +42 -0
  365. package/server/services/social_video/index.js +7 -0
  366. package/server/services/social_video/metadata.js +63 -0
  367. package/server/services/social_video/result.js +63 -0
  368. package/server/services/social_video/service.js +720 -0
  369. package/server/services/social_video/url.js +83 -0
  370. package/server/services/tasks/integration_runtime.js +1 -1
  371. package/server/services/tasks/runtime.js +1 -1
  372. package/server/services/tasks/task_repository.js +3 -6
  373. package/server/services/voice/openaiSpeech.js +6 -1
  374. package/server/services/voice/providers.js +142 -14
  375. package/server/services/voice/runtime.js +8 -8
  376. package/server/services/voice/runtimeManager.js +156 -19
  377. package/server/services/voice/turnRunner.js +29 -9
  378. package/server/services/wearable/firmware_manifest.js +353 -0
  379. package/server/services/wearable/gateway.js +350 -0
  380. package/server/services/wearable/protocol.js +45 -0
  381. package/server/services/wearable/service.js +240 -0
  382. package/server/services/websocket.js +3 -1
  383. package/server/services/widgets/focus_widget.js +137 -0
  384. package/server/services/widgets/service.js +133 -2
  385. package/server/services/workspace/manager.js +301 -0
  386. package/server/utils/deployment.js +16 -9
  387. package/server/services/integrations/home_assistant/provider.js +0 -630
  388. package/server/services/messaging/access_policy.test.js +0 -228
  389. package/server/services/runtime/backends/host.js +0 -37
  390. package/server/services/runtime/qemu.js +0 -391
@@ -0,0 +1,2 @@
1
+ export 'desktop_companion_stub.dart'
2
+ if (dart.library.io) 'desktop_companion_io.dart';
@@ -0,0 +1,586 @@
1
+ import 'dart:convert';
2
+ import 'dart:io';
3
+
4
+ import 'package:flutter/foundation.dart';
5
+ import 'package:image/image.dart' as img;
6
+ import 'package:package_info_plus/package_info_plus.dart';
7
+
8
+ import 'desktop_native_bridge.dart';
9
+ import 'desktop_screen_capture.dart';
10
+
11
+ class DesktopCompanionSnapshot {
12
+ const DesktopCompanionSnapshot({
13
+ required this.screenshotBase64,
14
+ required this.contentType,
15
+ required this.width,
16
+ required this.height,
17
+ required this.displays,
18
+ required this.activeDisplayId,
19
+ });
20
+
21
+ final String screenshotBase64;
22
+ final String contentType;
23
+ final int width;
24
+ final int height;
25
+ final List<Map<String, Object?>> displays;
26
+ final String activeDisplayId;
27
+ }
28
+
29
+ class DesktopCompanionActions {
30
+ DesktopCompanionActions({required DesktopScreenCapture screenCapture})
31
+ : _screenCapture = screenCapture;
32
+
33
+ final DesktopScreenCapture _screenCapture;
34
+ final DesktopNativeBridge _nativeBridge = DesktopNativeBridge();
35
+
36
+ bool get isCaptureSupported => _screenCapture.isSupported;
37
+
38
+ Future<Map<String, Object?>> buildHello({
39
+ required String deviceId,
40
+ required String activationId,
41
+ required String label,
42
+ required bool companionEnabled,
43
+ required bool paused,
44
+ String? activeDisplayId,
45
+ }) async {
46
+ final platformStatus = await _platformStatus();
47
+ final capabilities = await _capabilities(platformStatus: platformStatus);
48
+ final snapshot = await _safeSnapshotForStatus(
49
+ activeDisplayId: activeDisplayId,
50
+ platformStatus: platformStatus,
51
+ );
52
+ final packageInfo = await PackageInfo.fromPlatform();
53
+ return <String, Object?>{
54
+ 'deviceId': deviceId,
55
+ 'activationId': activationId,
56
+ 'label': label,
57
+ 'hostname': _localHostname(),
58
+ 'platform': defaultTargetPlatform.name,
59
+ 'platformVersion': Platform.operatingSystemVersion,
60
+ 'appVersion': packageInfo.version,
61
+ 'companionEnabled': companionEnabled,
62
+ 'paused': paused,
63
+ 'permissions': _permissions(capabilities, platformStatus: platformStatus),
64
+ 'capabilities': capabilities,
65
+ 'displays': snapshot?.displays ?? const <Map<String, Object?>>[],
66
+ 'activeDisplayId':
67
+ snapshot?.activeDisplayId ??
68
+ platformStatus['activeDisplayId']?.toString() ??
69
+ activeDisplayId ??
70
+ 'primary',
71
+ 'metadata': <String, Object?>{
72
+ 'captureSupported': _screenCapture.isSupported,
73
+ },
74
+ };
75
+ }
76
+
77
+ Future<DesktopCompanionSnapshot?> captureSnapshot({
78
+ String? activeDisplayId,
79
+ }) async {
80
+ if (_usesNativeDesktopBridge) {
81
+ final frame = await _nativeBridge.captureFrame(
82
+ displayId: activeDisplayId,
83
+ );
84
+ final bytes = frame['bytes'];
85
+ if (bytes is! Uint8List || bytes.isEmpty) {
86
+ return null;
87
+ }
88
+ final decoded = img.decodeImage(bytes);
89
+ final width = (frame['width'] as num?)?.round() ?? decoded?.width ?? 0;
90
+ final height = (frame['height'] as num?)?.round() ?? decoded?.height ?? 0;
91
+ final displays = _normalizeDisplays(
92
+ frame['displays'],
93
+ fallbackDisplayId:
94
+ frame['displayId']?.toString() ?? activeDisplayId ?? 'primary',
95
+ width: width,
96
+ height: height,
97
+ );
98
+ return DesktopCompanionSnapshot(
99
+ screenshotBase64: base64Encode(bytes),
100
+ contentType: frame['mimeType']?.toString() ?? 'image/png',
101
+ width: width,
102
+ height: height,
103
+ displays: displays,
104
+ activeDisplayId:
105
+ frame['displayId']?.toString() ?? activeDisplayId ?? 'primary',
106
+ );
107
+ }
108
+
109
+ final capture = await _screenCapture.captureCurrentScreen();
110
+ if (capture == null || capture.bytes.isEmpty) return null;
111
+ final bytes = Uint8List.fromList(capture.bytes);
112
+ final decoded = img.decodeImage(bytes);
113
+ final width = decoded?.width ?? 0;
114
+ final height = decoded?.height ?? 0;
115
+ return DesktopCompanionSnapshot(
116
+ screenshotBase64: base64Encode(bytes),
117
+ contentType: capture.mimeType,
118
+ width: width,
119
+ height: height,
120
+ activeDisplayId: activeDisplayId ?? 'primary',
121
+ displays: <Map<String, Object?>>[
122
+ <String, Object?>{
123
+ 'id': activeDisplayId ?? 'primary',
124
+ 'label': 'Primary Display',
125
+ 'width': width,
126
+ 'height': height,
127
+ 'scaleFactor': 1,
128
+ 'primary': true,
129
+ },
130
+ ],
131
+ );
132
+ }
133
+
134
+ Future<Map<String, Object?>> getStatus({
135
+ required String label,
136
+ required bool paused,
137
+ String? activeDisplayId,
138
+ }) async {
139
+ final platformStatus = await _platformStatus();
140
+ final capabilities = await _capabilities(platformStatus: platformStatus);
141
+ final snapshot = await _safeSnapshotForStatus(
142
+ activeDisplayId: activeDisplayId,
143
+ platformStatus: platformStatus,
144
+ );
145
+ return <String, Object?>{
146
+ 'paused': paused,
147
+ 'label': label,
148
+ 'activeDisplayId':
149
+ snapshot?.activeDisplayId ??
150
+ platformStatus['activeDisplayId']?.toString() ??
151
+ activeDisplayId ??
152
+ 'primary',
153
+ 'displays': snapshot?.displays ?? const <Map<String, Object?>>[],
154
+ 'permissions': _permissions(capabilities, platformStatus: platformStatus),
155
+ 'capabilities': capabilities,
156
+ if (platformStatus['frontmostApp'] != null)
157
+ 'frontmostApp': platformStatus['frontmostApp'],
158
+ if (platformStatus['frontmostWindowTitle'] != null)
159
+ 'frontmostWindowTitle': platformStatus['frontmostWindowTitle'],
160
+ };
161
+ }
162
+
163
+ Future<Map<String, Object?>> captureFrame({String? activeDisplayId}) async {
164
+ final snapshot = await captureSnapshot(activeDisplayId: activeDisplayId);
165
+ if (snapshot == null) {
166
+ throw Exception('Desktop capture is not available on this platform.');
167
+ }
168
+ return <String, Object?>{
169
+ 'screenshotBase64': snapshot.screenshotBase64,
170
+ 'contentType': snapshot.contentType,
171
+ 'width': snapshot.width,
172
+ 'height': snapshot.height,
173
+ 'displayId': snapshot.activeDisplayId,
174
+ 'displays': snapshot.displays,
175
+ 'capturedAt': DateTime.now().toUtc().toIso8601String(),
176
+ };
177
+ }
178
+
179
+ Future<Map<String, Object?>> observe({
180
+ bool includeTree = false,
181
+ String? activeDisplayId,
182
+ }) async {
183
+ final result = await captureFrame(activeDisplayId: activeDisplayId);
184
+ return <String, Object?>{
185
+ ...result,
186
+ 'tree': includeTree ? const <Map<String, Object?>>[] : null,
187
+ 'treeSupported': false,
188
+ };
189
+ }
190
+
191
+ Future<Map<String, Object?>> click({
192
+ required int x,
193
+ required int y,
194
+ String button = 'left',
195
+ String? displayId,
196
+ }) async {
197
+ await _assertInputSupported('click');
198
+ final normalizedButton = _normalizeMouseButton(button);
199
+ if (_usesNativeDesktopBridge) {
200
+ await _nativeBridge.click(
201
+ x: x,
202
+ y: y,
203
+ button: normalizedButton,
204
+ displayId: displayId,
205
+ );
206
+ } else if (defaultTargetPlatform == TargetPlatform.linux) {
207
+ final buttonCode = normalizedButton == 'right'
208
+ ? '3'
209
+ : (normalizedButton == 'middle' ? '2' : '1');
210
+ await _run(
211
+ _ShellCommand('xdotool', <String>[
212
+ 'mousemove',
213
+ '$x',
214
+ '$y',
215
+ 'click',
216
+ buttonCode,
217
+ ]),
218
+ );
219
+ } else {
220
+ throw Exception('click is not supported on this platform.');
221
+ }
222
+ return <String, Object?>{'success': true, 'x': x, 'y': y, 'button': button};
223
+ }
224
+
225
+ Future<Map<String, Object?>> drag({
226
+ required int x1,
227
+ required int y1,
228
+ required int x2,
229
+ required int y2,
230
+ int durationMs = 280,
231
+ String? displayId,
232
+ }) async {
233
+ await _assertInputSupported('drag');
234
+ if (_usesNativeDesktopBridge) {
235
+ await _nativeBridge.drag(
236
+ x1: x1,
237
+ y1: y1,
238
+ x2: x2,
239
+ y2: y2,
240
+ durationMs: durationMs,
241
+ displayId: displayId,
242
+ );
243
+ } else if (defaultTargetPlatform == TargetPlatform.linux) {
244
+ await _run(_ShellCommand('xdotool', <String>['mousemove', '$x1', '$y1']));
245
+ await _run(_ShellCommand('xdotool', const <String>['mousedown', '1']));
246
+ await Future<void>.delayed(
247
+ Duration(milliseconds: durationMs.clamp(40, 2000)),
248
+ );
249
+ await _run(_ShellCommand('xdotool', <String>['mousemove', '$x2', '$y2']));
250
+ await _run(_ShellCommand('xdotool', const <String>['mouseup', '1']));
251
+ } else {
252
+ throw Exception('drag is not supported on this platform.');
253
+ }
254
+ return <String, Object?>{
255
+ 'success': true,
256
+ 'x1': x1,
257
+ 'y1': y1,
258
+ 'x2': x2,
259
+ 'y2': y2,
260
+ 'durationMs': durationMs,
261
+ };
262
+ }
263
+
264
+ Future<Map<String, Object?>> scroll({
265
+ int deltaX = 0,
266
+ int deltaY = 0,
267
+ String? displayId,
268
+ }) async {
269
+ await _assertInputSupported('scroll');
270
+ if (deltaY == 0 && deltaX == 0) {
271
+ return <String, Object?>{
272
+ 'success': true,
273
+ 'deltaX': deltaX,
274
+ 'deltaY': deltaY,
275
+ };
276
+ }
277
+ if (_usesNativeDesktopBridge) {
278
+ await _nativeBridge.scroll(
279
+ deltaX: deltaX,
280
+ deltaY: deltaY,
281
+ displayId: displayId,
282
+ );
283
+ } else if (defaultTargetPlatform == TargetPlatform.linux) {
284
+ if (deltaY != 0) {
285
+ final clicks = (deltaY.abs() / 120).ceil().clamp(1, 12);
286
+ final button = deltaY < 0 ? '5' : '4';
287
+ await _run(
288
+ _ShellCommand('xdotool', <String>[
289
+ 'click',
290
+ '--repeat',
291
+ '$clicks',
292
+ button,
293
+ ]),
294
+ );
295
+ }
296
+ if (deltaX != 0) {
297
+ final clicks = (deltaX.abs() / 120).ceil().clamp(1, 12);
298
+ final button = deltaX < 0 ? '6' : '7';
299
+ await _run(
300
+ _ShellCommand('xdotool', <String>[
301
+ 'click',
302
+ '--repeat',
303
+ '$clicks',
304
+ button,
305
+ ]),
306
+ );
307
+ }
308
+ } else {
309
+ throw Exception('scroll is not supported on this platform.');
310
+ }
311
+ return <String, Object?>{
312
+ 'success': true,
313
+ 'deltaX': deltaX,
314
+ 'deltaY': deltaY,
315
+ };
316
+ }
317
+
318
+ Future<Map<String, Object?>> typeText({
319
+ required String text,
320
+ bool pressEnter = false,
321
+ }) async {
322
+ await _assertInputSupported('type text');
323
+ if (_usesNativeDesktopBridge) {
324
+ await _nativeBridge.typeText(text: text, pressEnter: pressEnter);
325
+ } else if (defaultTargetPlatform == TargetPlatform.linux) {
326
+ if (text.isNotEmpty) {
327
+ await _run(
328
+ _ShellCommand('xdotool', <String>[
329
+ 'type',
330
+ '--delay',
331
+ '1',
332
+ '--',
333
+ text,
334
+ ]),
335
+ );
336
+ }
337
+ if (pressEnter) {
338
+ await _run(_ShellCommand('xdotool', const <String>['key', 'Return']));
339
+ }
340
+ } else {
341
+ throw Exception('type text is not supported on this platform.');
342
+ }
343
+ return <String, Object?>{
344
+ 'success': true,
345
+ 'textLength': text.length,
346
+ 'pressEnter': pressEnter,
347
+ };
348
+ }
349
+
350
+ Future<Map<String, Object?>> pressKey({required String key}) async {
351
+ await _assertInputSupported('press keys');
352
+ if (_usesNativeDesktopBridge) {
353
+ await _nativeBridge.pressKey(key);
354
+ } else if (defaultTargetPlatform == TargetPlatform.linux) {
355
+ final normalized = key.trim();
356
+ if (normalized.isEmpty) {
357
+ throw Exception('Key is required.');
358
+ }
359
+ await _run(_ShellCommand('xdotool', <String>['key', normalized]));
360
+ } else {
361
+ throw Exception('press keys is not supported on this platform.');
362
+ }
363
+ return <String, Object?>{'success': true, 'key': key};
364
+ }
365
+
366
+ Future<Map<String, Object?>> launchApp({required String app}) async {
367
+ if (app.trim().isEmpty) {
368
+ throw Exception('App name is required.');
369
+ }
370
+ final command = switch (defaultTargetPlatform) {
371
+ TargetPlatform.macOS => _ShellCommand('open', <String>['-a', app]),
372
+ TargetPlatform.windows => _ShellCommand('powershell', <String>[
373
+ '-NoProfile',
374
+ '-NonInteractive',
375
+ '-Command',
376
+ 'Start-Process -FilePath ${_psQuote(app)}',
377
+ ]),
378
+ TargetPlatform.linux => _ShellCommand('sh', <String>[
379
+ '-lc',
380
+ 'if command -v ${_shQuote(app)} >/dev/null 2>&1; then ${_shQuote(app)} >/dev/null 2>&1 & disown; else gtk-launch ${_shQuote(app)} >/dev/null 2>&1 & disown; fi',
381
+ ]),
382
+ TargetPlatform.android ||
383
+ TargetPlatform.iOS ||
384
+ TargetPlatform.fuchsia => throw Exception(
385
+ 'Launching desktop apps is not supported on this platform.',
386
+ ),
387
+ };
388
+ await _run(command);
389
+ return <String, Object?>{'success': true, 'app': app};
390
+ }
391
+
392
+ Future<Map<String, Object?>> getTree() async {
393
+ return <String, Object?>{
394
+ 'supported': false,
395
+ 'nodes': const <Map<String, Object?>>[],
396
+ };
397
+ }
398
+
399
+ Future<Map<String, Object?>> _capabilities({
400
+ Map<String, Object?>? platformStatus,
401
+ }) async {
402
+ final status = platformStatus ?? await _platformStatus();
403
+ final inputSupported = await _inputSupported(platformStatus: status);
404
+ final permissions = status['permissions'];
405
+ final screenCapturePermission = permissions is Map
406
+ ? permissions['screenCapture']?.toString()
407
+ : null;
408
+ return <String, Object?>{
409
+ 'screenshot':
410
+ _screenCapture.isSupported &&
411
+ screenCapturePermission != 'required' &&
412
+ screenCapturePermission != 'unsupported',
413
+ 'click': inputSupported,
414
+ 'drag': inputSupported,
415
+ 'scroll': inputSupported,
416
+ 'typeText': inputSupported,
417
+ 'pressKey': inputSupported,
418
+ 'launchApp': _isDesktopPlatform,
419
+ 'accessibilityTree': false,
420
+ };
421
+ }
422
+
423
+ Map<String, Object?> _permissions(
424
+ Map<String, Object?> capabilities, {
425
+ Map<String, Object?>? platformStatus,
426
+ }) {
427
+ final status = platformStatus ?? const <String, Object?>{};
428
+ final reportedPermissions = status['permissions'];
429
+ if (reportedPermissions is Map) {
430
+ return reportedPermissions.map(
431
+ (key, value) => MapEntry(key.toString(), value),
432
+ );
433
+ }
434
+ final inputAvailable = capabilities['click'] == true;
435
+ return <String, Object?>{
436
+ 'screenCapture': _screenCapture.isSupported ? 'available' : 'unsupported',
437
+ 'inputControl': inputAvailable ? 'available' : 'unsupported',
438
+ 'accessibility': defaultTargetPlatform == TargetPlatform.windows
439
+ ? 'available'
440
+ : 'unsupported',
441
+ };
442
+ }
443
+
444
+ Future<bool> _inputSupported({Map<String, Object?>? platformStatus}) async {
445
+ switch (defaultTargetPlatform) {
446
+ case TargetPlatform.macOS:
447
+ final status = platformStatus ?? await _platformStatus();
448
+ final permissions = status['permissions'];
449
+ if (permissions is Map) {
450
+ return permissions['inputControl'] == 'available' &&
451
+ permissions['accessibility'] == 'available';
452
+ }
453
+ return false;
454
+ case TargetPlatform.windows:
455
+ return true;
456
+ case TargetPlatform.linux:
457
+ try {
458
+ final result = await Process.run('sh', <String>[
459
+ '-lc',
460
+ 'command -v xdotool >/dev/null 2>&1',
461
+ ]);
462
+ return result.exitCode == 0;
463
+ } catch (_) {
464
+ return false;
465
+ }
466
+ case TargetPlatform.android:
467
+ case TargetPlatform.iOS:
468
+ case TargetPlatform.fuchsia:
469
+ return false;
470
+ }
471
+ }
472
+
473
+ Future<Map<String, Object?>> _platformStatus() async {
474
+ if (_usesNativeDesktopBridge) {
475
+ return await _nativeBridge.getStatus();
476
+ }
477
+ return const <String, Object?>{};
478
+ }
479
+
480
+ bool get _usesNativeDesktopBridge =>
481
+ defaultTargetPlatform == TargetPlatform.macOS ||
482
+ defaultTargetPlatform == TargetPlatform.windows;
483
+
484
+ bool get _isDesktopPlatform =>
485
+ defaultTargetPlatform == TargetPlatform.macOS ||
486
+ defaultTargetPlatform == TargetPlatform.windows ||
487
+ defaultTargetPlatform == TargetPlatform.linux;
488
+
489
+ Future<void> _assertInputSupported(String action) async {
490
+ final supported = await _inputSupported();
491
+ if (!supported) {
492
+ throw Exception(
493
+ '$action is not available on ${defaultTargetPlatform.name} (missing runtime permission or dependency).',
494
+ );
495
+ }
496
+ }
497
+
498
+ Future<DesktopCompanionSnapshot?> _safeSnapshotForStatus({
499
+ required String? activeDisplayId,
500
+ required Map<String, Object?> platformStatus,
501
+ }) async {
502
+ final permissions = _permissions(
503
+ const <String, Object?>{},
504
+ platformStatus: platformStatus,
505
+ );
506
+ final screenCaptureState =
507
+ permissions['screenCapture']?.toString().toLowerCase() ?? 'unknown';
508
+ if (screenCaptureState == 'required' ||
509
+ screenCaptureState == 'unsupported') {
510
+ return null;
511
+ }
512
+ try {
513
+ return await captureSnapshot(activeDisplayId: activeDisplayId);
514
+ } catch (_) {
515
+ return null;
516
+ }
517
+ }
518
+
519
+ String _normalizeMouseButton(String button) {
520
+ final value = button.trim().toLowerCase();
521
+ if (value == 'left' || value == 'right' || value == 'middle') {
522
+ return value;
523
+ }
524
+ return 'left';
525
+ }
526
+
527
+ List<Map<String, Object?>> _normalizeDisplays(
528
+ Object? raw, {
529
+ required String fallbackDisplayId,
530
+ required int width,
531
+ required int height,
532
+ }) {
533
+ if (raw is List) {
534
+ final displays = raw
535
+ .whereType<Map>()
536
+ .map(
537
+ (item) => item.map((key, value) => MapEntry(key.toString(), value)),
538
+ )
539
+ .toList(growable: false);
540
+ if (displays.isNotEmpty) {
541
+ return displays;
542
+ }
543
+ }
544
+ return <Map<String, Object?>>[
545
+ <String, Object?>{
546
+ 'id': fallbackDisplayId,
547
+ 'label': 'Primary Display',
548
+ 'width': width,
549
+ 'height': height,
550
+ 'scaleFactor': 1,
551
+ 'primary': true,
552
+ },
553
+ ];
554
+ }
555
+
556
+ Future<void> _run(_ShellCommand command) async {
557
+ final result = await Process.run(command.command, command.args);
558
+ if (result.exitCode != 0) {
559
+ final stderr = result.stderr?.toString().trim();
560
+ final stdout = result.stdout?.toString().trim();
561
+ final details = stderr?.isNotEmpty == true
562
+ ? stderr
563
+ : (stdout?.isNotEmpty == true ? stdout : 'unknown error');
564
+ throw Exception('Command failed (${command.command}): $details');
565
+ }
566
+ }
567
+ }
568
+
569
+ class _ShellCommand {
570
+ const _ShellCommand(this.command, this.args);
571
+
572
+ final String command;
573
+ final List<String> args;
574
+ }
575
+
576
+ String _shQuote(String value) => "'${value.replaceAll("'", "'\"'\"'")}'";
577
+
578
+ String _psQuote(String value) => "'${value.replaceAll("'", "''")}'";
579
+
580
+ String _localHostname() {
581
+ final host = Platform.localHostname.trim();
582
+ if (host.isNotEmpty) {
583
+ return host;
584
+ }
585
+ return defaultTargetPlatform.name;
586
+ }