neoagent 2.3.1-beta.2 → 2.3.1-beta.21

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 (264) hide show
  1. package/.env.example +39 -0
  2. package/README.md +2 -0
  3. package/docs/capabilities.md +2 -2
  4. package/docs/configuration.md +13 -5
  5. package/docs/integrations.md +4 -1
  6. package/flutter_app/.metadata +42 -0
  7. package/flutter_app/README.md +21 -0
  8. package/flutter_app/analysis_options.yaml +32 -0
  9. package/flutter_app/android/app/build.gradle.kts +109 -0
  10. package/flutter_app/android/app/src/debug/AndroidManifest.xml +7 -0
  11. package/flutter_app/android/app/src/main/AndroidManifest.xml +147 -0
  12. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +747 -0
  13. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthConnectGateway.kt +280 -0
  14. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncNotifications.kt +113 -0
  15. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncPayload.kt +57 -0
  16. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncScheduler.kt +78 -0
  17. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncWorker.kt +253 -0
  18. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/PermissionsRationaleActivity.kt +46 -0
  19. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +21 -0
  20. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +586 -0
  21. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +78 -0
  22. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +104 -0
  23. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiHomeWidgetProvider.kt +457 -0
  24. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiWidgetStore.kt +194 -0
  25. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/VoiceLaunchWidgetProvider.kt +67 -0
  26. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetConfigActivity.kt +228 -0
  27. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncScheduler.kt +72 -0
  28. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncWorker.kt +186 -0
  29. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetTaskRunWorker.kt +210 -0
  30. package/flutter_app/android/app/src/main/res/drawable/launch_background.xml +12 -0
  31. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_bg.xml +11 -0
  32. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_task_bg.xml +8 -0
  33. package/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  34. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget.xml +138 -0
  35. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget_task_row.xml +52 -0
  36. package/flutter_app/android/app/src/main/res/layout/neoagent_voice_widget.xml +49 -0
  37. package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  38. package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  39. package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  40. package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  41. package/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  42. package/flutter_app/android/app/src/main/res/values/strings.xml +12 -0
  43. package/flutter_app/android/app/src/main/res/values/styles.xml +18 -0
  44. package/flutter_app/android/app/src/main/res/values-night/styles.xml +18 -0
  45. package/flutter_app/android/app/src/main/res/xml/file_paths.xml +6 -0
  46. package/flutter_app/android/app/src/main/res/xml/neoagent_ai_widget_info.xml +12 -0
  47. package/flutter_app/android/app/src/main/res/xml/neoagent_voice_widget_info.xml +12 -0
  48. package/flutter_app/android/app/src/profile/AndroidManifest.xml +7 -0
  49. package/flutter_app/android/build.gradle.kts +24 -0
  50. package/flutter_app/android/ci-release.keystore +0 -0
  51. package/flutter_app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  52. package/flutter_app/android/gradle.properties +3 -0
  53. package/flutter_app/android/key.properties +4 -0
  54. package/flutter_app/android/settings.gradle.kts +26 -0
  55. package/flutter_app/assets/branding/app_icon_1024.png +0 -0
  56. package/flutter_app/assets/branding/app_icon_128.png +0 -0
  57. package/flutter_app/assets/branding/app_icon_192.png +0 -0
  58. package/flutter_app/assets/branding/app_icon_256.png +0 -0
  59. package/flutter_app/assets/branding/app_icon_32.png +0 -0
  60. package/flutter_app/assets/branding/app_icon_512.png +0 -0
  61. package/flutter_app/assets/branding/app_icon_64.png +0 -0
  62. package/flutter_app/assets/branding/tray_icon_template.png +0 -0
  63. package/flutter_app/lib/features/location/location_service.dart +119 -0
  64. package/flutter_app/lib/features/notifications/notification_interceptor.dart +97 -0
  65. package/flutter_app/lib/main.dart +23057 -0
  66. package/flutter_app/lib/main_app_shell.dart +1682 -0
  67. package/flutter_app/lib/main_integrations.dart +931 -0
  68. package/flutter_app/lib/main_launcher.dart +959 -0
  69. package/flutter_app/lib/main_launcher_entry.dart +5 -0
  70. package/flutter_app/lib/main_models.dart +3473 -0
  71. package/flutter_app/lib/main_shared.dart +2861 -0
  72. package/flutter_app/lib/main_theme.dart +204 -0
  73. package/flutter_app/lib/main_voice_assistant.dart +831 -0
  74. package/flutter_app/lib/src/android_apk_drop_zone.dart +32 -0
  75. package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +16 -0
  76. package/flutter_app/lib/src/android_apk_drop_zone_web.dart +348 -0
  77. package/flutter_app/lib/src/android_app_installer.dart +22 -0
  78. package/flutter_app/lib/src/android_app_installer_io.dart +122 -0
  79. package/flutter_app/lib/src/android_app_installer_stub.dart +21 -0
  80. package/flutter_app/lib/src/android_launcher_bridge.dart +239 -0
  81. package/flutter_app/lib/src/app_launch_bridge.dart +29 -0
  82. package/flutter_app/lib/src/app_release_updater.dart +511 -0
  83. package/flutter_app/lib/src/backend_client.dart +1833 -0
  84. package/flutter_app/lib/src/desktop_companion.dart +2 -0
  85. package/flutter_app/lib/src/desktop_companion_actions.dart +586 -0
  86. package/flutter_app/lib/src/desktop_companion_io.dart +538 -0
  87. package/flutter_app/lib/src/desktop_companion_stub.dart +59 -0
  88. package/flutter_app/lib/src/desktop_native_bridge.dart +91 -0
  89. package/flutter_app/lib/src/desktop_screen_capture.dart +21 -0
  90. package/flutter_app/lib/src/desktop_screen_capture_io.dart +142 -0
  91. package/flutter_app/lib/src/desktop_screen_capture_stub.dart +12 -0
  92. package/flutter_app/lib/src/diagnostics_logger.dart +119 -0
  93. package/flutter_app/lib/src/health_bridge.dart +136 -0
  94. package/flutter_app/lib/src/live_voice_capture.dart +85 -0
  95. package/flutter_app/lib/src/messaging_access_summary.dart +46 -0
  96. package/flutter_app/lib/src/network/app_http_client.dart +53 -0
  97. package/flutter_app/lib/src/network/app_http_client_factory.dart +6 -0
  98. package/flutter_app/lib/src/network/app_http_client_io.dart +138 -0
  99. package/flutter_app/lib/src/network/app_http_client_stub.dart +3 -0
  100. package/flutter_app/lib/src/network/app_http_client_web.dart +94 -0
  101. package/flutter_app/lib/src/oauth_launcher.dart +33 -0
  102. package/flutter_app/lib/src/oauth_launcher_io.dart +77 -0
  103. package/flutter_app/lib/src/oauth_launcher_stub.dart +33 -0
  104. package/flutter_app/lib/src/oauth_launcher_web.dart +107 -0
  105. package/flutter_app/lib/src/recording_bridge.dart +232 -0
  106. package/flutter_app/lib/src/recording_bridge_io.dart +1019 -0
  107. package/flutter_app/lib/src/recording_bridge_stub.dart +120 -0
  108. package/flutter_app/lib/src/recording_bridge_web.dart +689 -0
  109. package/flutter_app/lib/src/recording_payloads.dart +86 -0
  110. package/flutter_app/lib/src/theme/palette.dart +81 -0
  111. package/flutter_app/lib/src/widget_bridge.dart +49 -0
  112. package/flutter_app/linux/CMakeLists.txt +128 -0
  113. package/flutter_app/linux/flutter/CMakeLists.txt +88 -0
  114. package/flutter_app/linux/flutter/generated_plugin_registrant.cc +43 -0
  115. package/flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
  116. package/flutter_app/linux/flutter/generated_plugins.cmake +31 -0
  117. package/flutter_app/linux/runner/CMakeLists.txt +26 -0
  118. package/flutter_app/linux/runner/main.cc +6 -0
  119. package/flutter_app/linux/runner/my_application.cc +144 -0
  120. package/flutter_app/linux/runner/my_application.h +18 -0
  121. package/flutter_app/linux/runner/resources/app_icon.png +0 -0
  122. package/flutter_app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
  123. package/flutter_app/macos/Flutter/Flutter-Release.xcconfig +2 -0
  124. package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +40 -0
  125. package/flutter_app/macos/Podfile +42 -0
  126. package/flutter_app/macos/Podfile.lock +87 -0
  127. package/flutter_app/macos/Runner/AppDelegate.swift +576 -0
  128. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  129. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  130. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  131. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  132. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  133. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  134. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  135. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  136. package/flutter_app/macos/Runner/Base.lproj/MainMenu.xib +342 -0
  137. package/flutter_app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  138. package/flutter_app/macos/Runner/Configs/Debug.xcconfig +2 -0
  139. package/flutter_app/macos/Runner/Configs/Release.xcconfig +2 -0
  140. package/flutter_app/macos/Runner/Configs/Warnings.xcconfig +13 -0
  141. package/flutter_app/macos/Runner/DebugProfile.entitlements +16 -0
  142. package/flutter_app/macos/Runner/Info.plist +36 -0
  143. package/flutter_app/macos/Runner/MainFlutterWindow.swift +19 -0
  144. package/flutter_app/macos/Runner/Release.entitlements +12 -0
  145. package/flutter_app/macos/Runner.xcodeproj/project.pbxproj +801 -0
  146. package/flutter_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  147. package/flutter_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
  148. package/flutter_app/macos/Runner.xcworkspace/contents.xcworkspacedata +10 -0
  149. package/flutter_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  150. package/flutter_app/macos/RunnerTests/RunnerTests.swift +12 -0
  151. package/flutter_app/patch_strings.py +12 -0
  152. package/flutter_app/pubspec.lock +1088 -0
  153. package/flutter_app/pubspec.yaml +53 -0
  154. package/flutter_app/test/messaging_access_summary_test.dart +22 -0
  155. package/flutter_app/test/recording_payloads_test.dart +53 -0
  156. package/flutter_app/third_party/desktop_audio_capture/LICENSE +21 -0
  157. package/flutter_app/third_party/desktop_audio_capture/README.md +262 -0
  158. package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +65 -0
  159. package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +153 -0
  160. package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +110 -0
  161. package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +461 -0
  162. package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +91 -0
  163. package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +106 -0
  164. package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +219 -0
  165. package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +336 -0
  166. package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +101 -0
  167. package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +692 -0
  168. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +35 -0
  169. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +36 -0
  170. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +32 -0
  171. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +32 -0
  172. package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +878 -0
  173. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +27 -0
  174. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +1172 -0
  175. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +655 -0
  176. package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +12 -0
  177. package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +30 -0
  178. package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +87 -0
  179. package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +105 -0
  180. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +80 -0
  181. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +31 -0
  182. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +12 -0
  183. package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +23 -0
  184. package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +25 -0
  185. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +1117 -0
  186. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +115 -0
  187. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +777 -0
  188. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +87 -0
  189. package/flutter_app/third_party/flutter_secure_storage_linux/linux/CMakeLists.txt +30 -0
  190. package/flutter_app/third_party/flutter_secure_storage_linux/linux/flutter_secure_storage_linux_plugin.cc +215 -0
  191. package/flutter_app/third_party/flutter_secure_storage_linux/linux/include/flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h +27 -0
  192. package/flutter_app/third_party/flutter_secure_storage_linux/pubspec.yaml +20 -0
  193. package/flutter_app/tool/generate_desktop_branding.py +219 -0
  194. package/flutter_app/web/favicon.png +0 -0
  195. package/flutter_app/web/favicon.svg +12 -0
  196. package/flutter_app/web/icons/Icon-192.png +0 -0
  197. package/flutter_app/web/icons/Icon-512.png +0 -0
  198. package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
  199. package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
  200. package/flutter_app/web/index.html +39 -0
  201. package/flutter_app/web/manifest.json +35 -0
  202. package/flutter_app/windows/CMakeLists.txt +108 -0
  203. package/flutter_app/windows/flutter/CMakeLists.txt +109 -0
  204. package/flutter_app/windows/flutter/generated_plugin_registrant.cc +47 -0
  205. package/flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
  206. package/flutter_app/windows/flutter/generated_plugins.cmake +35 -0
  207. package/flutter_app/windows/runner/CMakeLists.txt +41 -0
  208. package/flutter_app/windows/runner/Runner.rc +121 -0
  209. package/flutter_app/windows/runner/flutter_window.cpp +533 -0
  210. package/flutter_app/windows/runner/flutter_window.h +37 -0
  211. package/flutter_app/windows/runner/main.cpp +53 -0
  212. package/flutter_app/windows/runner/resource.h +16 -0
  213. package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
  214. package/flutter_app/windows/runner/runner.exe.manifest +14 -0
  215. package/flutter_app/windows/runner/utils.cpp +65 -0
  216. package/flutter_app/windows/runner/utils.h +19 -0
  217. package/flutter_app/windows/runner/win32_window.cpp +299 -0
  218. package/flutter_app/windows/runner/win32_window.h +102 -0
  219. package/lib/manager.js +231 -7
  220. package/package.json +3 -1
  221. package/server/db/database.js +68 -0
  222. package/server/http/middleware.js +50 -0
  223. package/server/http/routes.js +3 -1
  224. package/server/index.js +1 -0
  225. package/server/public/.last_build_id +1 -1
  226. package/server/public/assets/NOTICES +61 -0
  227. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  228. package/server/public/flutter_bootstrap.js +1 -1
  229. package/server/public/main.dart.js +65262 -64422
  230. package/server/routes/integrations.js +86 -0
  231. package/server/routes/memory.js +11 -2
  232. package/server/routes/screenHistory.js +46 -0
  233. package/server/routes/triggers.js +81 -0
  234. package/server/services/ai/models.js +30 -0
  235. package/server/services/ai/providers/githubCopilot.js +97 -0
  236. package/server/services/ai/providers/openai.js +2 -1
  237. package/server/services/ai/providers/openaiCodex.js +31 -0
  238. package/server/services/ai/settings.js +20 -0
  239. package/server/services/ai/systemPrompt.js +1 -1
  240. package/server/services/ai/tools.js +35 -6
  241. package/server/services/browser/controller.js +47 -3
  242. package/server/services/desktop/screenRecorder.js +172 -0
  243. package/server/services/integrations/env.js +5 -0
  244. package/server/services/integrations/github/common.js +106 -0
  245. package/server/services/integrations/github/provider.js +499 -0
  246. package/server/services/integrations/github/repos.js +1124 -0
  247. package/server/services/integrations/home_assistant/provider.js +306 -26
  248. package/server/services/integrations/manager.js +63 -7
  249. package/server/services/integrations/oauth_provider.js +13 -6
  250. package/server/services/integrations/provider_config_store.js +76 -0
  251. package/server/services/integrations/registry.js +4 -0
  252. package/server/services/integrations/trello/provider.js +744 -0
  253. package/server/services/integrations/whatsapp/provider.js +6 -2
  254. package/server/services/manager.js +22 -0
  255. package/server/services/memory/manager.js +39 -2
  256. package/server/services/skills/base_catalog.js +33 -0
  257. package/server/services/tasks/adapters/index.js +1 -0
  258. package/server/services/tasks/adapters/manual.js +12 -0
  259. package/server/services/tasks/runtime.js +1 -1
  260. package/server/services/voice/openaiClient.js +4 -1
  261. package/server/services/voice/providers.js +2 -1
  262. package/server/services/widgets/service.js +49 -4
  263. package/server/utils/local_secrets.js +56 -0
  264. package/server/utils/logger.js +37 -9
@@ -0,0 +1,21 @@
1
+ import 'desktop_screen_capture_stub.dart'
2
+ if (dart.library.io) 'desktop_screen_capture_io.dart';
3
+
4
+ DesktopScreenCapture createDesktopScreenCapture() =>
5
+ createPlatformDesktopScreenCapture();
6
+
7
+ class DesktopScreenCaptureResult {
8
+ const DesktopScreenCaptureResult({
9
+ required this.bytes,
10
+ required this.mimeType,
11
+ });
12
+
13
+ final List<int> bytes;
14
+ final String mimeType;
15
+ }
16
+
17
+ abstract class DesktopScreenCapture {
18
+ bool get isSupported;
19
+
20
+ Future<DesktopScreenCaptureResult?> captureCurrentScreen();
21
+ }
@@ -0,0 +1,142 @@
1
+ import 'dart:io';
2
+
3
+ import 'package:flutter/foundation.dart';
4
+
5
+ import 'desktop_native_bridge.dart';
6
+ import 'desktop_screen_capture.dart';
7
+
8
+ DesktopScreenCapture createPlatformDesktopScreenCapture() =>
9
+ _DesktopScreenCaptureIo();
10
+
11
+ class _DesktopScreenCaptureIo implements DesktopScreenCapture {
12
+ final DesktopNativeBridge _nativeBridge = DesktopNativeBridge();
13
+
14
+ @override
15
+ bool get isSupported =>
16
+ !kIsWeb &&
17
+ (defaultTargetPlatform == TargetPlatform.macOS ||
18
+ defaultTargetPlatform == TargetPlatform.windows ||
19
+ defaultTargetPlatform == TargetPlatform.linux);
20
+
21
+ @override
22
+ Future<DesktopScreenCaptureResult?> captureCurrentScreen() async {
23
+ if (!isSupported) {
24
+ return null;
25
+ }
26
+
27
+ switch (defaultTargetPlatform) {
28
+ case TargetPlatform.macOS:
29
+ return _captureMacos();
30
+ case TargetPlatform.windows:
31
+ return _captureWindows();
32
+ case TargetPlatform.linux:
33
+ return _captureLinux();
34
+ case TargetPlatform.android:
35
+ case TargetPlatform.iOS:
36
+ case TargetPlatform.fuchsia:
37
+ return null;
38
+ }
39
+ }
40
+
41
+ Future<DesktopScreenCaptureResult?> _captureMacos() async {
42
+ final result = await _nativeBridge.captureFrame();
43
+ final bytes = result['bytes'];
44
+ final mimeType = result['mimeType']?.toString() ?? 'image/png';
45
+ if (bytes is! Uint8List || bytes.isEmpty) {
46
+ return null;
47
+ }
48
+ return DesktopScreenCaptureResult(bytes: bytes, mimeType: mimeType);
49
+ }
50
+
51
+ Future<DesktopScreenCaptureResult?> _captureWindows() async {
52
+ final result = await _nativeBridge.captureFrame();
53
+ final bytes = result['bytes'];
54
+ final mimeType = result['mimeType']?.toString() ?? 'image/png';
55
+ if (bytes is! Uint8List || bytes.isEmpty) {
56
+ return null;
57
+ }
58
+ return DesktopScreenCaptureResult(bytes: bytes, mimeType: mimeType);
59
+ }
60
+
61
+ Future<DesktopScreenCaptureResult?> _captureLinux() async {
62
+ final attempts =
63
+ <
64
+ ({
65
+ String command,
66
+ List<String> args,
67
+ String extension,
68
+ String mimeType,
69
+ })
70
+ >[
71
+ (
72
+ command: 'grim',
73
+ args: <String>[],
74
+ extension: 'png',
75
+ mimeType: 'image/png',
76
+ ),
77
+ (
78
+ command: 'gnome-screenshot',
79
+ args: <String>['-f'],
80
+ extension: 'png',
81
+ mimeType: 'image/png',
82
+ ),
83
+ (
84
+ command: 'spectacle',
85
+ args: <String>['-b', '-n', '-o'],
86
+ extension: 'png',
87
+ mimeType: 'image/png',
88
+ ),
89
+ ];
90
+
91
+ Object? lastError;
92
+ for (final attempt in attempts) {
93
+ final file = await _temporaryFile(attempt.extension);
94
+ try {
95
+ final result = await Process.run(attempt.command, <String>[
96
+ ...attempt.args,
97
+ file.path,
98
+ ]);
99
+ if (result.exitCode == 0 && await file.exists()) {
100
+ return DesktopScreenCaptureResult(
101
+ bytes: await file.readAsBytes(),
102
+ mimeType: attempt.mimeType,
103
+ );
104
+ }
105
+ lastError = ProcessException(
106
+ attempt.command,
107
+ <String>[...attempt.args, file.path],
108
+ '${result.stderr}',
109
+ result.exitCode,
110
+ );
111
+ } on ProcessException catch (error) {
112
+ lastError = error;
113
+ } finally {
114
+ await _deleteIfExists(file);
115
+ }
116
+ }
117
+
118
+ if (lastError != null) {
119
+ throw lastError;
120
+ }
121
+ return null;
122
+ }
123
+
124
+ Future<File> _temporaryFile(String extension) async {
125
+ final directory = await Directory.systemTemp.createTemp(
126
+ 'neoagent-assistant-screen-',
127
+ );
128
+ return File('${directory.path}/capture.$extension');
129
+ }
130
+
131
+ Future<void> _deleteIfExists(File file) async {
132
+ try {
133
+ if (await file.exists()) {
134
+ await file.delete();
135
+ }
136
+ final parent = file.parent;
137
+ if (await parent.exists()) {
138
+ await parent.delete();
139
+ }
140
+ } catch (_) {}
141
+ }
142
+ }
@@ -0,0 +1,12 @@
1
+ import 'desktop_screen_capture.dart';
2
+
3
+ DesktopScreenCapture createPlatformDesktopScreenCapture() =>
4
+ _UnsupportedDesktopScreenCapture();
5
+
6
+ class _UnsupportedDesktopScreenCapture implements DesktopScreenCapture {
7
+ @override
8
+ bool get isSupported => false;
9
+
10
+ @override
11
+ Future<DesktopScreenCaptureResult?> captureCurrentScreen() async => null;
12
+ }
@@ -0,0 +1,119 @@
1
+ import 'dart:async';
2
+ import 'dart:convert';
3
+
4
+ import 'package:flutter/foundation.dart';
5
+
6
+ @immutable
7
+ class AppDiagnosticEntry {
8
+ const AppDiagnosticEntry({
9
+ required this.sequence,
10
+ required this.timestamp,
11
+ required this.area,
12
+ required this.event,
13
+ this.data = const <String, Object?>{},
14
+ this.error,
15
+ this.stackTrace,
16
+ });
17
+
18
+ final int sequence;
19
+ final DateTime timestamp;
20
+ final String area;
21
+ final String event;
22
+ final Map<String, Object?> data;
23
+ final String? error;
24
+ final String? stackTrace;
25
+ }
26
+
27
+ class AppDiagnostics {
28
+ AppDiagnostics._();
29
+
30
+ static bool enabled = const bool.fromEnvironment(
31
+ 'NEOAGENT_VERBOSE_LOGS',
32
+ defaultValue: true,
33
+ );
34
+
35
+ static int _sequence = 0;
36
+ static const int _maxRetainedEntries = 400;
37
+ static final StreamController<AppDiagnosticEntry> _controller =
38
+ StreamController<AppDiagnosticEntry>.broadcast(sync: true);
39
+ static final List<AppDiagnosticEntry> _entries = <AppDiagnosticEntry>[];
40
+
41
+ static Stream<AppDiagnosticEntry> get stream => _controller.stream;
42
+
43
+ static List<AppDiagnosticEntry> get recentEntries =>
44
+ List<AppDiagnosticEntry>.unmodifiable(_entries);
45
+
46
+ static void log(
47
+ String area,
48
+ String event, {
49
+ Map<String, Object?> data = const <String, Object?>{},
50
+ Object? error,
51
+ StackTrace? stackTrace,
52
+ }) {
53
+ if (!enabled) {
54
+ return;
55
+ }
56
+
57
+ final seq = ++_sequence;
58
+ final timestamp = DateTime.now();
59
+ final now = timestamp.toIso8601String();
60
+ final normalizedData = data.isEmpty
61
+ ? const <String, Object?>{}
62
+ : _normalizeMap(data);
63
+ final normalized = <String, Object?>{
64
+ 'ts': now,
65
+ 'area': area,
66
+ 'event': event,
67
+ if (normalizedData.isNotEmpty) 'data': normalizedData,
68
+ if (error != null) 'error': error.toString(),
69
+ };
70
+
71
+ debugPrint('[NeoDiag][$seq] ${jsonEncode(normalized)}');
72
+ if (stackTrace != null) {
73
+ debugPrint('[NeoDiag][$seq][stack] $stackTrace');
74
+ }
75
+
76
+ final entry = AppDiagnosticEntry(
77
+ sequence: seq,
78
+ timestamp: timestamp,
79
+ area: area,
80
+ event: event,
81
+ data: normalizedData,
82
+ error: error?.toString(),
83
+ stackTrace: stackTrace?.toString(),
84
+ );
85
+ _entries.add(entry);
86
+ if (_entries.length > _maxRetainedEntries) {
87
+ _entries.removeRange(0, _entries.length - _maxRetainedEntries);
88
+ }
89
+ if (!_controller.isClosed) {
90
+ _controller.add(entry);
91
+ }
92
+ }
93
+
94
+ static Map<String, Object?> _normalizeMap(Map<String, Object?> input) {
95
+ final output = <String, Object?>{};
96
+ input.forEach((key, value) {
97
+ output[key] = _normalizeValue(value);
98
+ });
99
+ return output;
100
+ }
101
+
102
+ static Object? _normalizeValue(Object? value) {
103
+ if (value == null ||
104
+ value is num ||
105
+ value is bool ||
106
+ value is String ||
107
+ value is Map<String, Object?> ||
108
+ value is List<Object?>) {
109
+ return value;
110
+ }
111
+ if (value is DateTime) {
112
+ return value.toIso8601String();
113
+ }
114
+ if (value is Duration) {
115
+ return value.inMilliseconds;
116
+ }
117
+ return value.toString();
118
+ }
119
+ }
@@ -0,0 +1,136 @@
1
+ import 'dart:convert';
2
+
3
+ import 'package:flutter/foundation.dart';
4
+ import 'package:flutter/services.dart';
5
+
6
+ class HealthBridge {
7
+ static const MethodChannel _channel = MethodChannel('neoagent/health');
8
+
9
+ Future<HealthBridgeStatus> getStatus() async {
10
+ if (!_isAndroid) {
11
+ return const HealthBridgeStatus(
12
+ available: false,
13
+ permissionsGranted: false,
14
+ message: 'Health sync is available on Android only.',
15
+ );
16
+ }
17
+
18
+ final result = await _channel.invokeMapMethod<String, dynamic>('status');
19
+ if (result == null) {
20
+ return const HealthBridgeStatus(
21
+ available: false,
22
+ permissionsGranted: false,
23
+ message: 'Health status is unavailable.',
24
+ );
25
+ }
26
+
27
+ return HealthBridgeStatus(
28
+ available: result['available'] == true,
29
+ permissionsGranted: result['permissionsGranted'] == true,
30
+ message: result['message']?.toString(),
31
+ grantedPermissions: _stringListFromDynamic(result['grantedPermissions']),
32
+ requiredPermissions: _stringListFromDynamic(
33
+ result['requiredPermissions'],
34
+ ),
35
+ );
36
+ }
37
+
38
+ Future<HealthBridgeStatus> requestPermissions() async {
39
+ if (!_isAndroid) {
40
+ return getStatus();
41
+ }
42
+ await _channel.invokeMethod('requestPermissions');
43
+ return getStatus();
44
+ }
45
+
46
+ Future<Map<String, dynamic>> collectBatch({
47
+ required DateTime windowStart,
48
+ required DateTime windowEnd,
49
+ }) async {
50
+ if (!_isAndroid) {
51
+ throw const HealthBridgeException(
52
+ 'Health sync is available on Android only.',
53
+ );
54
+ }
55
+ final raw = await _channel
56
+ .invokeMethod<String>('collectBatch', <String, dynamic>{
57
+ 'windowStart': windowStart.toUtc().toIso8601String(),
58
+ 'windowEnd': windowEnd.toUtc().toIso8601String(),
59
+ });
60
+ if (raw == null || raw.isEmpty) {
61
+ throw const HealthBridgeException('No health data payload returned.');
62
+ }
63
+ return jsonDecode(raw) as Map<String, dynamic>;
64
+ }
65
+
66
+ Future<void> configureBackgroundSync({
67
+ required bool enabled,
68
+ required String backendUrl,
69
+ required String sessionCookie,
70
+ }) async {
71
+ if (!_isAndroid) {
72
+ return;
73
+ }
74
+ await _channel.invokeMethod('configureBackgroundSync', <String, dynamic>{
75
+ 'enabled': enabled,
76
+ 'backendUrl': backendUrl,
77
+ 'sessionCookie': sessionCookie,
78
+ });
79
+ }
80
+
81
+ bool get _isAndroid =>
82
+ !kIsWeb && defaultTargetPlatform == TargetPlatform.android;
83
+ }
84
+
85
+ class HealthBridgeStatus {
86
+ const HealthBridgeStatus({
87
+ required this.available,
88
+ required this.permissionsGranted,
89
+ this.message,
90
+ this.grantedPermissions = const <String>[],
91
+ this.requiredPermissions = const <String>[],
92
+ });
93
+
94
+ final bool available;
95
+ final bool permissionsGranted;
96
+ final String? message;
97
+ final List<String> grantedPermissions;
98
+ final List<String> requiredPermissions;
99
+ }
100
+
101
+ class HealthBridgeException implements Exception {
102
+ const HealthBridgeException(this.message);
103
+
104
+ final String message;
105
+
106
+ @override
107
+ String toString() => message;
108
+ }
109
+
110
+ List<String> _stringListFromDynamic(dynamic value) {
111
+ if (value is List) {
112
+ return value
113
+ .map((item) => item?.toString() ?? '')
114
+ .where((item) => item.isNotEmpty)
115
+ .toList();
116
+ }
117
+ if (value is Map) {
118
+ for (final key in const <String>[
119
+ 'items',
120
+ 'data',
121
+ 'results',
122
+ 'rows',
123
+ 'values',
124
+ 'list',
125
+ ]) {
126
+ final nested = value[key];
127
+ if (nested is List) {
128
+ return nested
129
+ .map((item) => item?.toString() ?? '')
130
+ .where((item) => item.isNotEmpty)
131
+ .toList();
132
+ }
133
+ }
134
+ }
135
+ return const <String>[];
136
+ }
@@ -0,0 +1,85 @@
1
+ import 'dart:async';
2
+
3
+ import 'package:flutter/foundation.dart';
4
+ import 'package:record/record.dart';
5
+
6
+ class LiveVoiceCapture {
7
+ LiveVoiceCapture() : _recorder = AudioRecorder();
8
+
9
+ final AudioRecorder _recorder;
10
+ StreamSubscription<Uint8List>? _subscription;
11
+ StreamSubscription<RecordState>? _stateSubscription;
12
+ bool _stopping = false;
13
+
14
+ Future<void> start({
15
+ required void Function(Uint8List chunk) onChunk,
16
+ void Function(Object error, StackTrace stackTrace)? onError,
17
+ VoidCallback? onStoppedUnexpectedly,
18
+ int sampleRate = 16000,
19
+ int channels = 1,
20
+ }) async {
21
+ await stop();
22
+
23
+ final hasPermission = await _recorder.hasPermission();
24
+ if (!hasPermission) {
25
+ throw StateError('Microphone permission is required for live voice.');
26
+ }
27
+
28
+ _stopping = false;
29
+ _stateSubscription = _recorder.onStateChanged().listen(
30
+ (state) {
31
+ if (_stopping) {
32
+ return;
33
+ }
34
+ if (state == RecordState.stop) {
35
+ onStoppedUnexpectedly?.call();
36
+ }
37
+ },
38
+ onError: (Object error, StackTrace stackTrace) {
39
+ if (_stopping) {
40
+ return;
41
+ }
42
+ onError?.call(error, stackTrace);
43
+ },
44
+ );
45
+
46
+ final stream = await _recorder.startStream(
47
+ RecordConfig(
48
+ encoder: AudioEncoder.pcm16bits,
49
+ sampleRate: sampleRate,
50
+ numChannels: channels,
51
+ ),
52
+ );
53
+
54
+ _subscription = stream.listen(
55
+ onChunk,
56
+ onError: (Object error, StackTrace stackTrace) {
57
+ if (_stopping) {
58
+ return;
59
+ }
60
+ onError?.call(error, stackTrace);
61
+ },
62
+ onDone: () {
63
+ if (_stopping) {
64
+ return;
65
+ }
66
+ onStoppedUnexpectedly?.call();
67
+ },
68
+ cancelOnError: false,
69
+ );
70
+ }
71
+
72
+ Future<void> stop() async {
73
+ _stopping = true;
74
+ await _subscription?.cancel();
75
+ _subscription = null;
76
+ await _stateSubscription?.cancel();
77
+ _stateSubscription = null;
78
+ await _recorder.stop();
79
+ }
80
+
81
+ Future<void> dispose() async {
82
+ await stop();
83
+ await _recorder.dispose();
84
+ }
85
+ }
@@ -0,0 +1,46 @@
1
+ import 'package:flutter/material.dart';
2
+
3
+ class MessagingAccessSummaryCard extends StatelessWidget {
4
+ const MessagingAccessSummaryCard({
5
+ super.key,
6
+ required this.accent,
7
+ required this.summary,
8
+ required this.hint,
9
+ });
10
+
11
+ final Color accent;
12
+ final String summary;
13
+ final String hint;
14
+
15
+ @override
16
+ Widget build(BuildContext context) {
17
+ return Container(
18
+ width: double.infinity,
19
+ padding: const EdgeInsets.all(16),
20
+ decoration: BoxDecoration(
21
+ gradient: LinearGradient(
22
+ colors: <Color>[
23
+ accent.withValues(alpha: 0.18),
24
+ Theme.of(context).dialogTheme.backgroundColor ??
25
+ Theme.of(context).colorScheme.surface,
26
+ ],
27
+ begin: Alignment.topLeft,
28
+ end: Alignment.bottomRight,
29
+ ),
30
+ borderRadius: BorderRadius.circular(18),
31
+ border: Border.all(color: accent.withValues(alpha: 0.28)),
32
+ ),
33
+ child: Column(
34
+ crossAxisAlignment: CrossAxisAlignment.start,
35
+ children: <Widget>[
36
+ Text(
37
+ summary,
38
+ style: const TextStyle(fontWeight: FontWeight.w700),
39
+ ),
40
+ const SizedBox(height: 6),
41
+ Text(hint),
42
+ ],
43
+ ),
44
+ );
45
+ }
46
+ }
@@ -0,0 +1,53 @@
1
+ import 'dart:typed_data';
2
+
3
+ abstract class AppHttpClient {
4
+ Future<HttpResponseData> get(Uri uri, {Map<String, String>? headers});
5
+
6
+ Future<HttpResponseData> post(
7
+ Uri uri, {
8
+ Map<String, String>? headers,
9
+ Object? body,
10
+ });
11
+
12
+ Future<HttpResponseData> postMultipart(
13
+ Uri uri, {
14
+ Map<String, String>? headers,
15
+ required String fieldName,
16
+ required String filename,
17
+ required Uint8List bytes,
18
+ });
19
+
20
+ Future<HttpResponseData> put(
21
+ Uri uri, {
22
+ Map<String, String>? headers,
23
+ Object? body,
24
+ });
25
+
26
+ Future<HttpResponseData> delete(
27
+ Uri uri, {
28
+ Map<String, String>? headers,
29
+ Object? body,
30
+ });
31
+
32
+ Future<void> close();
33
+
34
+ void clearSession();
35
+
36
+ void restoreSession(String? sessionCookie);
37
+
38
+ String? get sessionCookie;
39
+ }
40
+
41
+ class HttpResponseData {
42
+ const HttpResponseData({
43
+ required this.statusCode,
44
+ required this.body,
45
+ required this.bodyBytes,
46
+ required this.headers,
47
+ });
48
+
49
+ final int statusCode;
50
+ final String body;
51
+ final Uint8List bodyBytes;
52
+ final Map<String, String> headers;
53
+ }
@@ -0,0 +1,6 @@
1
+ import 'app_http_client.dart';
2
+ import 'app_http_client_stub.dart'
3
+ if (dart.library.html) 'app_http_client_web.dart'
4
+ if (dart.library.io) 'app_http_client_io.dart';
5
+
6
+ AppHttpClient createAppHttpClient() => createPlatformHttpClient();