neoagent 2.3.1-beta.4 → 2.3.1-beta.41

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 (290) hide show
  1. package/.env.example +45 -0
  2. package/docs/capabilities.md +2 -2
  3. package/docs/configuration.md +12 -5
  4. package/docs/hardware.md +1 -1
  5. package/docs/integrations.md +2 -3
  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 +99 -0
  66. package/flutter_app/lib/main_account_settings.dart +1250 -0
  67. package/flutter_app/lib/main_admin.dart +886 -0
  68. package/flutter_app/lib/main_app_shell.dart +1682 -0
  69. package/flutter_app/lib/main_chat.dart +3352 -0
  70. package/flutter_app/lib/main_controller.dart +6781 -0
  71. package/flutter_app/lib/main_devices.dart +2301 -0
  72. package/flutter_app/lib/main_integrations.dart +1129 -0
  73. package/flutter_app/lib/main_launcher.dart +959 -0
  74. package/flutter_app/lib/main_launcher_entry.dart +5 -0
  75. package/flutter_app/lib/main_models.dart +3546 -0
  76. package/flutter_app/lib/main_navigation.dart +193 -0
  77. package/flutter_app/lib/main_operations.dart +4851 -0
  78. package/flutter_app/lib/main_recordings.dart +870 -0
  79. package/flutter_app/lib/main_runtime.dart +806 -0
  80. package/flutter_app/lib/main_settings.dart +2024 -0
  81. package/flutter_app/lib/main_shared.dart +2861 -0
  82. package/flutter_app/lib/main_theme.dart +204 -0
  83. package/flutter_app/lib/main_voice_assistant.dart +957 -0
  84. package/flutter_app/lib/src/android_apk_drop_zone.dart +32 -0
  85. package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +16 -0
  86. package/flutter_app/lib/src/android_apk_drop_zone_web.dart +348 -0
  87. package/flutter_app/lib/src/android_app_installer.dart +22 -0
  88. package/flutter_app/lib/src/android_app_installer_io.dart +122 -0
  89. package/flutter_app/lib/src/android_app_installer_stub.dart +21 -0
  90. package/flutter_app/lib/src/android_launcher_bridge.dart +239 -0
  91. package/flutter_app/lib/src/app_launch_bridge.dart +29 -0
  92. package/flutter_app/lib/src/app_release_updater.dart +511 -0
  93. package/flutter_app/lib/src/backend_client.dart +1833 -0
  94. package/flutter_app/lib/src/desktop_companion.dart +2 -0
  95. package/flutter_app/lib/src/desktop_companion_actions.dart +586 -0
  96. package/flutter_app/lib/src/desktop_companion_io.dart +538 -0
  97. package/flutter_app/lib/src/desktop_companion_stub.dart +59 -0
  98. package/flutter_app/lib/src/desktop_native_bridge.dart +91 -0
  99. package/flutter_app/lib/src/desktop_screen_capture.dart +21 -0
  100. package/flutter_app/lib/src/desktop_screen_capture_io.dart +142 -0
  101. package/flutter_app/lib/src/desktop_screen_capture_stub.dart +12 -0
  102. package/flutter_app/lib/src/diagnostics_logger.dart +119 -0
  103. package/flutter_app/lib/src/health_bridge.dart +136 -0
  104. package/flutter_app/lib/src/live_voice_capture.dart +85 -0
  105. package/flutter_app/lib/src/messaging_access_summary.dart +46 -0
  106. package/flutter_app/lib/src/network/app_http_client.dart +53 -0
  107. package/flutter_app/lib/src/network/app_http_client_factory.dart +6 -0
  108. package/flutter_app/lib/src/network/app_http_client_io.dart +138 -0
  109. package/flutter_app/lib/src/network/app_http_client_stub.dart +3 -0
  110. package/flutter_app/lib/src/network/app_http_client_web.dart +94 -0
  111. package/flutter_app/lib/src/oauth_launcher.dart +33 -0
  112. package/flutter_app/lib/src/oauth_launcher_io.dart +77 -0
  113. package/flutter_app/lib/src/oauth_launcher_stub.dart +33 -0
  114. package/flutter_app/lib/src/oauth_launcher_web.dart +107 -0
  115. package/flutter_app/lib/src/recording_bridge.dart +232 -0
  116. package/flutter_app/lib/src/recording_bridge_io.dart +1019 -0
  117. package/flutter_app/lib/src/recording_bridge_stub.dart +120 -0
  118. package/flutter_app/lib/src/recording_bridge_web.dart +689 -0
  119. package/flutter_app/lib/src/recording_payloads.dart +86 -0
  120. package/flutter_app/lib/src/theme/palette.dart +81 -0
  121. package/flutter_app/lib/src/widget_bridge.dart +49 -0
  122. package/flutter_app/linux/CMakeLists.txt +128 -0
  123. package/flutter_app/linux/flutter/CMakeLists.txt +88 -0
  124. package/flutter_app/linux/flutter/generated_plugin_registrant.cc +43 -0
  125. package/flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
  126. package/flutter_app/linux/flutter/generated_plugins.cmake +31 -0
  127. package/flutter_app/linux/runner/CMakeLists.txt +26 -0
  128. package/flutter_app/linux/runner/main.cc +6 -0
  129. package/flutter_app/linux/runner/my_application.cc +144 -0
  130. package/flutter_app/linux/runner/my_application.h +18 -0
  131. package/flutter_app/linux/runner/resources/app_icon.png +0 -0
  132. package/flutter_app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
  133. package/flutter_app/macos/Flutter/Flutter-Release.xcconfig +2 -0
  134. package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +40 -0
  135. package/flutter_app/macos/Podfile +42 -0
  136. package/flutter_app/macos/Podfile.lock +87 -0
  137. package/flutter_app/macos/Runner/AppDelegate.swift +576 -0
  138. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  139. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  140. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  141. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  142. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  143. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  144. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  145. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  146. package/flutter_app/macos/Runner/Base.lproj/MainMenu.xib +342 -0
  147. package/flutter_app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  148. package/flutter_app/macos/Runner/Configs/Debug.xcconfig +2 -0
  149. package/flutter_app/macos/Runner/Configs/Release.xcconfig +2 -0
  150. package/flutter_app/macos/Runner/Configs/Warnings.xcconfig +13 -0
  151. package/flutter_app/macos/Runner/DebugProfile.entitlements +16 -0
  152. package/flutter_app/macos/Runner/Info.plist +36 -0
  153. package/flutter_app/macos/Runner/MainFlutterWindow.swift +19 -0
  154. package/flutter_app/macos/Runner/Release.entitlements +12 -0
  155. package/flutter_app/macos/Runner.xcodeproj/project.pbxproj +801 -0
  156. package/flutter_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  157. package/flutter_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
  158. package/flutter_app/macos/Runner.xcworkspace/contents.xcworkspacedata +10 -0
  159. package/flutter_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  160. package/flutter_app/macos/RunnerTests/RunnerTests.swift +12 -0
  161. package/flutter_app/patch_strings.py +12 -0
  162. package/flutter_app/pubspec.lock +1088 -0
  163. package/flutter_app/pubspec.yaml +53 -0
  164. package/flutter_app/test/messaging_access_summary_test.dart +22 -0
  165. package/flutter_app/test/recording_payloads_test.dart +53 -0
  166. package/flutter_app/third_party/desktop_audio_capture/LICENSE +21 -0
  167. package/flutter_app/third_party/desktop_audio_capture/README.md +262 -0
  168. package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +65 -0
  169. package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +153 -0
  170. package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +110 -0
  171. package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +461 -0
  172. package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +91 -0
  173. package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +106 -0
  174. package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +219 -0
  175. package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +336 -0
  176. package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +101 -0
  177. package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +692 -0
  178. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +35 -0
  179. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +36 -0
  180. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +32 -0
  181. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +32 -0
  182. package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +878 -0
  183. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +27 -0
  184. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +1172 -0
  185. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +655 -0
  186. package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +12 -0
  187. package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +30 -0
  188. package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +87 -0
  189. package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +105 -0
  190. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +80 -0
  191. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +31 -0
  192. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +12 -0
  193. package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +23 -0
  194. package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +25 -0
  195. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +1117 -0
  196. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +115 -0
  197. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +777 -0
  198. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +87 -0
  199. package/flutter_app/third_party/flutter_secure_storage_linux/linux/CMakeLists.txt +30 -0
  200. package/flutter_app/third_party/flutter_secure_storage_linux/linux/flutter_secure_storage_linux_plugin.cc +215 -0
  201. package/flutter_app/third_party/flutter_secure_storage_linux/linux/include/flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h +27 -0
  202. package/flutter_app/third_party/flutter_secure_storage_linux/pubspec.yaml +20 -0
  203. package/flutter_app/tool/generate_desktop_branding.py +219 -0
  204. package/flutter_app/web/favicon.png +0 -0
  205. package/flutter_app/web/favicon.svg +12 -0
  206. package/flutter_app/web/icons/Icon-192.png +0 -0
  207. package/flutter_app/web/icons/Icon-512.png +0 -0
  208. package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
  209. package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
  210. package/flutter_app/web/index.html +39 -0
  211. package/flutter_app/web/manifest.json +35 -0
  212. package/flutter_app/windows/CMakeLists.txt +108 -0
  213. package/flutter_app/windows/flutter/CMakeLists.txt +109 -0
  214. package/flutter_app/windows/flutter/generated_plugin_registrant.cc +47 -0
  215. package/flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
  216. package/flutter_app/windows/flutter/generated_plugins.cmake +35 -0
  217. package/flutter_app/windows/runner/CMakeLists.txt +41 -0
  218. package/flutter_app/windows/runner/Runner.rc +121 -0
  219. package/flutter_app/windows/runner/flutter_window.cpp +533 -0
  220. package/flutter_app/windows/runner/flutter_window.h +37 -0
  221. package/flutter_app/windows/runner/main.cpp +53 -0
  222. package/flutter_app/windows/runner/resource.h +16 -0
  223. package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
  224. package/flutter_app/windows/runner/runner.exe.manifest +14 -0
  225. package/flutter_app/windows/runner/utils.cpp +65 -0
  226. package/flutter_app/windows/runner/utils.h +19 -0
  227. package/flutter_app/windows/runner/win32_window.cpp +299 -0
  228. package/flutter_app/windows/runner/win32_window.h +102 -0
  229. package/lib/install_helpers.js +31 -0
  230. package/lib/manager.js +227 -6
  231. package/package.json +3 -1
  232. package/server/db/database.js +110 -0
  233. package/server/http/middleware.js +55 -2
  234. package/server/http/routes.js +1 -0
  235. package/server/index.js +3 -0
  236. package/server/public/.last_build_id +1 -1
  237. package/server/public/assets/NOTICES +1 -1
  238. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  239. package/server/public/canvaskit/wimp.wasm +0 -0
  240. package/server/public/flutter_bootstrap.js +2 -2
  241. package/server/public/main.dart.js +74324 -73132
  242. package/server/routes/integrations.js +108 -1
  243. package/server/routes/memory.js +11 -2
  244. package/server/{http/routes → routes}/screenHistory.js +2 -2
  245. package/server/routes/settings.js +75 -2
  246. package/server/{http/routes → routes}/triggers.js +2 -2
  247. package/server/routes/wearable.js +67 -0
  248. package/server/services/ai/models.js +30 -0
  249. package/server/services/ai/providers/githubCopilot.js +97 -0
  250. package/server/services/ai/providers/openai.js +2 -1
  251. package/server/services/ai/providers/openaiCodex.js +31 -0
  252. package/server/services/ai/settings.js +20 -0
  253. package/server/services/ai/toolSelector.js +14 -1
  254. package/server/services/ai/tools.js +77 -4
  255. package/server/services/desktop/screenRecorder.js +65 -9
  256. package/server/services/integrations/env.js +5 -0
  257. package/server/services/integrations/figma/provider.js +1 -0
  258. package/server/services/integrations/github/common.js +106 -0
  259. package/server/services/integrations/github/provider.js +499 -0
  260. package/server/services/integrations/github/repos.js +1124 -0
  261. package/server/services/integrations/google/provider.js +1 -0
  262. package/server/services/integrations/home_assistant/provider.js +325 -26
  263. package/server/services/integrations/manager.js +88 -12
  264. package/server/services/integrations/microsoft/provider.js +1 -0
  265. package/server/services/integrations/oauth_provider.js +25 -8
  266. package/server/services/integrations/provider_config_store.js +85 -0
  267. package/server/services/integrations/registry.js +4 -0
  268. package/server/services/integrations/spotify/provider.js +1 -0
  269. package/server/services/integrations/trello/provider.js +842 -0
  270. package/server/services/manager.js +46 -1
  271. package/server/services/mcp/client.js +120 -23
  272. package/server/services/memory/manager.js +39 -2
  273. package/server/services/messaging/access_policy.js +10 -0
  274. package/server/services/messaging/manager.js +49 -0
  275. package/server/services/messaging/meshtastic.js +260 -0
  276. package/server/services/messaging/meshtastic_env.js +100 -0
  277. package/server/services/messaging/meshtastic_protocol.js +476 -0
  278. package/server/services/messaging/meshtastic_tcp_transport.js +25 -0
  279. package/server/services/tasks/runtime.js +1 -1
  280. package/server/services/voice/openaiClient.js +4 -1
  281. package/server/services/voice/openaiSpeech.js +6 -1
  282. package/server/services/voice/providers.js +52 -12
  283. package/server/services/voice/runtimeManager.js +136 -19
  284. package/server/services/voice/turnRunner.js +29 -9
  285. package/server/services/wearable/firmware_manifest.js +370 -0
  286. package/server/services/wearable/gateway.js +350 -0
  287. package/server/services/wearable/protocol.js +45 -0
  288. package/server/services/wearable/service.js +244 -0
  289. package/server/utils/local_secrets.js +56 -0
  290. package/server/utils/logger.js +37 -9
@@ -192,6 +192,54 @@ function isProactiveTrigger(triggerSource) {
192
192
  return triggerSource === 'schedule' || triggerSource === 'tasks';
193
193
  }
194
194
 
195
+ function normalizeSendMessagePurpose(value) {
196
+ const normalized = String(value || '').trim().toLowerCase();
197
+ if (normalized === 'final_result' || normalized === 'blocker' || normalized === 'no_response') {
198
+ return normalized;
199
+ }
200
+ return '';
201
+ }
202
+
203
+ function validateProactiveSendMessageArgs({ purpose, normalizedMessage }) {
204
+ const normalizedPurpose = normalizeSendMessagePurpose(purpose);
205
+ if (!normalizedPurpose) {
206
+ return {
207
+ ok: false,
208
+ error: 'Background send_message requires purpose=final_result, blocker, or no_response.',
209
+ reason: 'Background send_message requires purpose=final_result, blocker, or no_response.',
210
+ };
211
+ }
212
+
213
+ if (normalizedPurpose === 'no_response') {
214
+ if (normalizedMessage !== '[NO RESPONSE]') {
215
+ return {
216
+ ok: false,
217
+ error: 'purpose=no_response requires content "[NO RESPONSE]".',
218
+ reason: 'purpose=no_response requires content "[NO RESPONSE]".',
219
+ };
220
+ }
221
+ return {
222
+ ok: false,
223
+ skipped: true,
224
+ suppressed: true,
225
+ reason: 'no_response',
226
+ };
227
+ }
228
+
229
+ if (normalizedMessage === '[NO RESPONSE]') {
230
+ return {
231
+ ok: false,
232
+ error: `purpose=${normalizedPurpose} cannot use content "[NO RESPONSE]".`,
233
+ reason: `purpose=${normalizedPurpose} cannot use content "[NO RESPONSE]".`,
234
+ };
235
+ }
236
+
237
+ return {
238
+ ok: true,
239
+ purpose: normalizedPurpose,
240
+ };
241
+ }
242
+
195
243
  function getRunState(engine, runId) {
196
244
  if (!engine || !runId) return null;
197
245
  return engine.activeRuns.get(runId) || null;
@@ -742,14 +790,15 @@ function getAvailableTools(app, options = {}) {
742
790
  },
743
791
  {
744
792
  name: 'send_message',
745
- description: `Send a message on a connected messaging platform. Supports WhatsApp (text/media), Telnyx Voice (phone calls — TTS), Discord, Telegram, Slack, Google Chat, Microsoft Teams, Matrix, Signal, iMessage/BlueBubbles, IRC, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, WeChat, WebChat, and configurable webhook bridges. ${buildSendMessageFormattingReference()} For WhatsApp: use media_path to attach files. Use content "[NO RESPONSE]" only when the user explicitly asked for silence or no reply.`,
793
+ description: `Send a message on a connected messaging platform. Supports WhatsApp (text/media), Telnyx Voice (phone calls — TTS), Discord, Telegram, Slack, Google Chat, Microsoft Teams, Matrix, Signal, iMessage/BlueBubbles, IRC, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, WeChat, WebChat, and configurable webhook bridges. ${buildSendMessageFormattingReference()} For WhatsApp: use media_path to attach files. Use content "[NO RESPONSE]" only when the user explicitly asked for silence or no reply. For background task or schedule runs, set purpose to final_result, blocker, or no_response.`,
746
794
  parameters: {
747
795
  type: 'object',
748
796
  properties: {
749
797
  platform: { type: 'string', description: 'Platform name, for example whatsapp, telnyx, discord, telegram, slack, google_chat, teams, matrix, signal, imessage, bluebubbles, irc, line, mattermost, or webchat' },
750
798
  to: { type: 'string', description: 'Recipient/chat ID for the connected platform, such as a WhatsApp chat ID, Telnyx call_control_id, Slack channel ID, Matrix room ID, Discord channel snowflake / "dm_<userId>", Telegram "dm_<userId>" / raw group chat ID, IRC channel, or webhook target' },
751
799
  content: { type: 'string', description: 'Message text. Write one compact natural chat reply; the runtime adapts final formatting for the destination platform.' },
752
- media_path: { type: 'string', description: 'WhatsApp only: absolute path to a local file to attach. Leave empty for text-only or Telnyx.' }
800
+ media_path: { type: 'string', description: 'WhatsApp only: absolute path to a local file to attach. Leave empty for text-only or Telnyx.' },
801
+ purpose: { type: 'string', enum: ['final_result', 'blocker', 'no_response'], description: 'For background task or schedule runs, required intent for this outbound message. Use final_result for a concrete useful outcome, blocker for a real issue the user should know about, or no_response to intentionally send nothing.' }
753
802
  },
754
803
  required: ['platform', 'to', 'content']
755
804
  }
@@ -1986,6 +2035,25 @@ async function executeTool(toolName, args, context, engine) {
1986
2035
  stripNoResponseMarker: false
1987
2036
  });
1988
2037
  const suppressReply = normalizedMessage === '[NO RESPONSE]';
2038
+ if (isProactiveTrigger(triggerSource)) {
2039
+ const proactiveValidation = validateProactiveSendMessageArgs({
2040
+ purpose: args.purpose,
2041
+ normalizedMessage,
2042
+ });
2043
+ if (!proactiveValidation.ok) {
2044
+ if (proactiveValidation.error) {
2045
+ return {
2046
+ error: proactiveValidation.error,
2047
+ };
2048
+ }
2049
+ return {
2050
+ sent: false,
2051
+ suppressed: proactiveValidation.suppressed === true,
2052
+ skipped: proactiveValidation.skipped === true,
2053
+ reason: proactiveValidation.reason,
2054
+ };
2055
+ }
2056
+ }
1989
2057
  if (!suppressReply && hasAlreadySentProactiveMessage({
1990
2058
  triggerSource,
1991
2059
  runState,
@@ -2676,7 +2744,12 @@ async function executeTool(toolName, args, context, engine) {
2676
2744
  const { detectPromptInjection } = require('../../utils/security');
2677
2745
  const mcpManager = mcp();
2678
2746
  if (mcpManager) {
2679
- const mcpResult = await mcpManager.callToolByName(toolName, args, userId, { agentId });
2747
+ let mcpResult = null;
2748
+ try {
2749
+ mcpResult = await mcpManager.callToolByName(toolName, args, userId, { agentId });
2750
+ } catch (mcpErr) {
2751
+ return { error: mcpErr.message, tool: toolName, source: 'mcp' };
2752
+ }
2680
2753
  if (mcpResult !== null) {
2681
2754
  const resultText = typeof mcpResult === 'string' ? mcpResult : JSON.stringify(mcpResult);
2682
2755
  if (detectPromptInjection(resultText)) {
@@ -2701,4 +2774,4 @@ async function executeTool(toolName, args, context, engine) {
2701
2774
  }
2702
2775
  }
2703
2776
 
2704
- module.exports = { getAvailableTools, executeTool };
2777
+ module.exports = { getAvailableTools, executeTool, validateProactiveSendMessageArgs };
@@ -12,16 +12,52 @@ const { getErrorMessage } = require('../bootstrap_helpers');
12
12
  const execAsync = promisify(exec);
13
13
 
14
14
  class ScreenRecorder {
15
- constructor() {
15
+ constructor(options = {}) {
16
16
  this.intervalMs = 10000; // 10 seconds
17
17
  this.intervalId = null;
18
18
  this.cleanupIntervalId = null;
19
19
  this.isRecording = false;
20
20
  this.isProcessing = false;
21
21
  this.tempFilePath = path.join(os.tmpdir(), `neoagent-screen-${Date.now()}.png`);
22
+ this.lastBenignSkipAt = 0;
23
+ this.hasActiveRemoteCaptureSession = typeof options.hasActiveRemoteCaptureSession === 'function'
24
+ ? options.hasActiveRemoteCaptureSession
25
+ : () => false;
26
+ }
27
+
28
+ _isCaptureInactiveApp(appName) {
29
+ const normalized = String(appName || '').trim().toLowerCase();
30
+ return normalized === '' || normalized === 'loginwindow' || normalized === 'screensaverengine';
31
+ }
32
+
33
+ _isBenignCaptureError(message) {
34
+ const text = String(message || '').toLowerCase();
35
+ return (
36
+ text.includes('operation not permitted') ||
37
+ text.includes('not authorized') ||
38
+ text.includes('user canceled') ||
39
+ text.includes('cgwindowlistcreateimage') ||
40
+ text.includes('screencapture') ||
41
+ text.includes('timed out')
42
+ );
43
+ }
44
+
45
+ _logBenignSkip(reason) {
46
+ const now = Date.now();
47
+ if (now - this.lastBenignSkipAt < 5 * 60 * 1000) {
48
+ return;
49
+ }
50
+ this.lastBenignSkipAt = now;
51
+ console.log(`[ScreenRecorder] Capture skipped: ${reason}`);
22
52
  }
23
53
 
24
54
  start() {
55
+ const enabledEnv = String(process.env.NEOAGENT_SCREEN_RECORDER_ENABLED || '').trim().toLowerCase();
56
+ if (enabledEnv === '0' || enabledEnv === 'false' || enabledEnv === 'off' || enabledEnv === 'no') {
57
+ console.log('[ScreenRecorder] Not starting: disabled by NEOAGENT_SCREEN_RECORDER_ENABLED.');
58
+ return;
59
+ }
60
+
25
61
  if (process.platform !== 'darwin') {
26
62
  console.log('[ScreenRecorder] Not starting: Screen recording is currently macOS only.');
27
63
  return;
@@ -61,6 +97,27 @@ class ScreenRecorder {
61
97
  this.isProcessing = true;
62
98
 
63
99
  try {
100
+ // Only capture while at least one external device/session is actively connected.
101
+ // This prevents host-level screenshots when no user-side capture source is live.
102
+ if (!this.hasActiveRemoteCaptureSession()) {
103
+ this._logBenignSkip('no active external capture session');
104
+ return;
105
+ }
106
+
107
+ // Skip capture when the desktop session is inactive (e.g. locked screen).
108
+ let frontmostApp = '';
109
+ try {
110
+ const { stdout } = await execAsync(`osascript -e 'tell application "System Events" to get name of first application process whose frontmost is true'`);
111
+ frontmostApp = (stdout || '').trim();
112
+ } catch {
113
+ frontmostApp = '';
114
+ }
115
+
116
+ if (this._isCaptureInactiveApp(frontmostApp)) {
117
+ this._logBenignSkip('no active frontmost app');
118
+ return;
119
+ }
120
+
64
121
  // Capture screen silently (-x) to file
65
122
  await execAsync(`screencapture -x "${this.tempFilePath}"`);
66
123
 
@@ -80,13 +137,7 @@ class ScreenRecorder {
80
137
  const userRow = db.prepare('SELECT id FROM users ORDER BY id ASC LIMIT 1').get();
81
138
  if (userRow) {
82
139
  // Identify the active foreground app via AppleScript
83
- let appName = 'Unknown';
84
- try {
85
- const { stdout } = await execAsync(`osascript -e 'tell application "System Events" to get name of first application process whose frontmost is true'`);
86
- appName = stdout.trim();
87
- } catch (e) {
88
- // Ignore AppleScript errors
89
- }
140
+ let appName = frontmostApp || 'Unknown';
90
141
 
91
142
  db.prepare(`
92
143
  INSERT INTO screen_history (user_id, app_name, text_content)
@@ -96,7 +147,12 @@ class ScreenRecorder {
96
147
  }
97
148
 
98
149
  } catch (err) {
99
- console.error('[ScreenRecorder] Capture/OCR failed:', getErrorMessage(err));
150
+ const errorMessage = getErrorMessage(err);
151
+ if (this._isBenignCaptureError(errorMessage)) {
152
+ this._logBenignSkip(errorMessage);
153
+ } else {
154
+ console.error('[ScreenRecorder] Capture/OCR failed:', errorMessage);
155
+ }
100
156
  } finally {
101
157
  // Always cleanup the screenshot image immediately
102
158
  try {
@@ -68,6 +68,10 @@ function resolveSpotifyOAuthConfig() {
68
68
  return resolveOAuthConfig('SPOTIFY');
69
69
  }
70
70
 
71
+ function resolveGithubOAuthConfig() {
72
+ return resolveOAuthConfig('GITHUB');
73
+ }
74
+
71
75
  function describeEnvStatus(config, options = {}) {
72
76
  const label = String(options.label || 'This integration').trim() || 'This integration';
73
77
  if (config.configured) {
@@ -96,4 +100,5 @@ module.exports = {
96
100
  resolvePublicBaseUrl,
97
101
  resolveSpotifyOAuthConfig,
98
102
  resolveSlackOAuthConfig,
103
+ resolveGithubOAuthConfig,
99
104
  };
@@ -240,6 +240,7 @@ function createFigmaProvider() {
240
240
  description:
241
241
  'Official Figma OAuth account connections for future design file and collaboration workflows.',
242
242
  icon: 'figma',
243
+ requiresRefreshToken: true,
243
244
  apps: FIGMA_APPS,
244
245
  toolDefinitions: figmaToolDefinitions,
245
246
  connectPrompt:
@@ -0,0 +1,106 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('crypto');
4
+
5
+ function base64UrlSha256(value) {
6
+ return crypto
7
+ .createHash('sha256')
8
+ .update(String(value || ''))
9
+ .digest('base64')
10
+ .replace(/\+/g, '-')
11
+ .replace(/\//g, '_')
12
+ .replace(/=+$/g, '');
13
+ }
14
+
15
+ async function githubApiRequest(auth, options = {}) {
16
+ const {
17
+ method = 'GET',
18
+ path,
19
+ query = null,
20
+ body = null,
21
+ baseUrl = 'https://api.github.com',
22
+ token: overrideToken = '',
23
+ } = options;
24
+
25
+ const token = String(overrideToken || auth?.token || '').trim();
26
+ if (!token) {
27
+ throw new Error('GitHub authentication token is required for GitHub API requests.');
28
+ }
29
+
30
+ const url = new URL(path, baseUrl);
31
+ if (query && typeof query === 'object') {
32
+ for (const [key, value] of Object.entries(query)) {
33
+ if (value !== undefined && value !== null) {
34
+ url.searchParams.set(key, String(value));
35
+ }
36
+ }
37
+ }
38
+
39
+ const headers = {
40
+ 'Accept': 'application/vnd.github.v3+json',
41
+ 'Authorization': `Bearer ${token}`,
42
+ 'X-GitHub-Api-Version': '2022-11-28',
43
+ };
44
+
45
+ if (body && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
46
+ headers['Content-Type'] = 'application/json';
47
+ }
48
+
49
+ const response = await fetch(url.toString(), {
50
+ method,
51
+ headers,
52
+ body: body ? JSON.stringify(body) : undefined,
53
+ });
54
+
55
+ let data = null;
56
+ if (response.status !== 204 && response.status !== 205) {
57
+ const rawBody = await response.text();
58
+ if (rawBody.trim()) {
59
+ try {
60
+ data = JSON.parse(rawBody);
61
+ } catch {
62
+ if (!response.ok) {
63
+ const error = new Error(`GitHub API error ${response.status}: ${rawBody}`);
64
+ error.status = response.status;
65
+ error.data = rawBody;
66
+ throw error;
67
+ }
68
+ data = rawBody;
69
+ }
70
+ }
71
+ }
72
+
73
+ if (!response.ok) {
74
+ const errorMessage =
75
+ (data && typeof data === 'object' ? data.message : null) ||
76
+ `GitHub API error: ${response.status}`;
77
+ const error = new Error(errorMessage);
78
+ error.status = response.status;
79
+ error.data = data;
80
+ throw error;
81
+ }
82
+
83
+ return data;
84
+ }
85
+
86
+ function buildPaginationParams(options = {}) {
87
+ const params = {};
88
+ if (options.page) params.page = Number(options.page);
89
+ if (options.per_page) params.per_page = Math.min(Number(options.per_page) || 30, 100);
90
+ return params;
91
+ }
92
+
93
+ function parseOwnerRepo(ownerRepo) {
94
+ const parts = String(ownerRepo || '').split('/');
95
+ if (parts.length !== 2) {
96
+ throw new Error('owner_repo must be in format "owner/repo"');
97
+ }
98
+ return { owner: parts[0], repo: parts[1] };
99
+ }
100
+
101
+ module.exports = {
102
+ base64UrlSha256,
103
+ buildPaginationParams,
104
+ githubApiRequest,
105
+ parseOwnerRepo,
106
+ };