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.
- package/.env.example +45 -0
- package/docs/capabilities.md +2 -2
- package/docs/configuration.md +12 -5
- package/docs/hardware.md +1 -1
- package/docs/integrations.md +2 -3
- package/flutter_app/.metadata +42 -0
- package/flutter_app/README.md +21 -0
- package/flutter_app/analysis_options.yaml +32 -0
- package/flutter_app/android/app/build.gradle.kts +109 -0
- package/flutter_app/android/app/src/debug/AndroidManifest.xml +7 -0
- package/flutter_app/android/app/src/main/AndroidManifest.xml +147 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +747 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthConnectGateway.kt +280 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncNotifications.kt +113 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncPayload.kt +57 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncScheduler.kt +78 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncWorker.kt +253 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/PermissionsRationaleActivity.kt +46 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +21 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +586 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +78 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +104 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiHomeWidgetProvider.kt +457 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiWidgetStore.kt +194 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/VoiceLaunchWidgetProvider.kt +67 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetConfigActivity.kt +228 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncScheduler.kt +72 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncWorker.kt +186 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetTaskRunWorker.kt +210 -0
- package/flutter_app/android/app/src/main/res/drawable/launch_background.xml +12 -0
- package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_bg.xml +11 -0
- package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_task_bg.xml +8 -0
- package/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
- package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget.xml +138 -0
- package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget_task_row.xml +52 -0
- package/flutter_app/android/app/src/main/res/layout/neoagent_voice_widget.xml +49 -0
- package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/values/strings.xml +12 -0
- package/flutter_app/android/app/src/main/res/values/styles.xml +18 -0
- package/flutter_app/android/app/src/main/res/values-night/styles.xml +18 -0
- package/flutter_app/android/app/src/main/res/xml/file_paths.xml +6 -0
- package/flutter_app/android/app/src/main/res/xml/neoagent_ai_widget_info.xml +12 -0
- package/flutter_app/android/app/src/main/res/xml/neoagent_voice_widget_info.xml +12 -0
- package/flutter_app/android/app/src/profile/AndroidManifest.xml +7 -0
- package/flutter_app/android/build.gradle.kts +24 -0
- package/flutter_app/android/ci-release.keystore +0 -0
- package/flutter_app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/flutter_app/android/gradle.properties +3 -0
- package/flutter_app/android/key.properties +4 -0
- package/flutter_app/android/settings.gradle.kts +26 -0
- package/flutter_app/assets/branding/app_icon_1024.png +0 -0
- package/flutter_app/assets/branding/app_icon_128.png +0 -0
- package/flutter_app/assets/branding/app_icon_192.png +0 -0
- package/flutter_app/assets/branding/app_icon_256.png +0 -0
- package/flutter_app/assets/branding/app_icon_32.png +0 -0
- package/flutter_app/assets/branding/app_icon_512.png +0 -0
- package/flutter_app/assets/branding/app_icon_64.png +0 -0
- package/flutter_app/assets/branding/tray_icon_template.png +0 -0
- package/flutter_app/lib/features/location/location_service.dart +119 -0
- package/flutter_app/lib/features/notifications/notification_interceptor.dart +97 -0
- package/flutter_app/lib/main.dart +99 -0
- package/flutter_app/lib/main_account_settings.dart +1250 -0
- package/flutter_app/lib/main_admin.dart +886 -0
- package/flutter_app/lib/main_app_shell.dart +1682 -0
- package/flutter_app/lib/main_chat.dart +3352 -0
- package/flutter_app/lib/main_controller.dart +6781 -0
- package/flutter_app/lib/main_devices.dart +2301 -0
- package/flutter_app/lib/main_integrations.dart +1129 -0
- package/flutter_app/lib/main_launcher.dart +959 -0
- package/flutter_app/lib/main_launcher_entry.dart +5 -0
- package/flutter_app/lib/main_models.dart +3546 -0
- package/flutter_app/lib/main_navigation.dart +193 -0
- package/flutter_app/lib/main_operations.dart +4851 -0
- package/flutter_app/lib/main_recordings.dart +870 -0
- package/flutter_app/lib/main_runtime.dart +806 -0
- package/flutter_app/lib/main_settings.dart +2024 -0
- package/flutter_app/lib/main_shared.dart +2861 -0
- package/flutter_app/lib/main_theme.dart +204 -0
- package/flutter_app/lib/main_voice_assistant.dart +957 -0
- package/flutter_app/lib/src/android_apk_drop_zone.dart +32 -0
- package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +16 -0
- package/flutter_app/lib/src/android_apk_drop_zone_web.dart +348 -0
- package/flutter_app/lib/src/android_app_installer.dart +22 -0
- package/flutter_app/lib/src/android_app_installer_io.dart +122 -0
- package/flutter_app/lib/src/android_app_installer_stub.dart +21 -0
- package/flutter_app/lib/src/android_launcher_bridge.dart +239 -0
- package/flutter_app/lib/src/app_launch_bridge.dart +29 -0
- package/flutter_app/lib/src/app_release_updater.dart +511 -0
- package/flutter_app/lib/src/backend_client.dart +1833 -0
- package/flutter_app/lib/src/desktop_companion.dart +2 -0
- package/flutter_app/lib/src/desktop_companion_actions.dart +586 -0
- package/flutter_app/lib/src/desktop_companion_io.dart +538 -0
- package/flutter_app/lib/src/desktop_companion_stub.dart +59 -0
- package/flutter_app/lib/src/desktop_native_bridge.dart +91 -0
- package/flutter_app/lib/src/desktop_screen_capture.dart +21 -0
- package/flutter_app/lib/src/desktop_screen_capture_io.dart +142 -0
- package/flutter_app/lib/src/desktop_screen_capture_stub.dart +12 -0
- package/flutter_app/lib/src/diagnostics_logger.dart +119 -0
- package/flutter_app/lib/src/health_bridge.dart +136 -0
- package/flutter_app/lib/src/live_voice_capture.dart +85 -0
- package/flutter_app/lib/src/messaging_access_summary.dart +46 -0
- package/flutter_app/lib/src/network/app_http_client.dart +53 -0
- package/flutter_app/lib/src/network/app_http_client_factory.dart +6 -0
- package/flutter_app/lib/src/network/app_http_client_io.dart +138 -0
- package/flutter_app/lib/src/network/app_http_client_stub.dart +3 -0
- package/flutter_app/lib/src/network/app_http_client_web.dart +94 -0
- package/flutter_app/lib/src/oauth_launcher.dart +33 -0
- package/flutter_app/lib/src/oauth_launcher_io.dart +77 -0
- package/flutter_app/lib/src/oauth_launcher_stub.dart +33 -0
- package/flutter_app/lib/src/oauth_launcher_web.dart +107 -0
- package/flutter_app/lib/src/recording_bridge.dart +232 -0
- package/flutter_app/lib/src/recording_bridge_io.dart +1019 -0
- package/flutter_app/lib/src/recording_bridge_stub.dart +120 -0
- package/flutter_app/lib/src/recording_bridge_web.dart +689 -0
- package/flutter_app/lib/src/recording_payloads.dart +86 -0
- package/flutter_app/lib/src/theme/palette.dart +81 -0
- package/flutter_app/lib/src/widget_bridge.dart +49 -0
- package/flutter_app/linux/CMakeLists.txt +128 -0
- package/flutter_app/linux/flutter/CMakeLists.txt +88 -0
- package/flutter_app/linux/flutter/generated_plugin_registrant.cc +43 -0
- package/flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
- package/flutter_app/linux/flutter/generated_plugins.cmake +31 -0
- package/flutter_app/linux/runner/CMakeLists.txt +26 -0
- package/flutter_app/linux/runner/main.cc +6 -0
- package/flutter_app/linux/runner/my_application.cc +144 -0
- package/flutter_app/linux/runner/my_application.h +18 -0
- package/flutter_app/linux/runner/resources/app_icon.png +0 -0
- package/flutter_app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
- package/flutter_app/macos/Flutter/Flutter-Release.xcconfig +2 -0
- package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +40 -0
- package/flutter_app/macos/Podfile +42 -0
- package/flutter_app/macos/Podfile.lock +87 -0
- package/flutter_app/macos/Runner/AppDelegate.swift +576 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
- package/flutter_app/macos/Runner/Base.lproj/MainMenu.xib +342 -0
- package/flutter_app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
- package/flutter_app/macos/Runner/Configs/Debug.xcconfig +2 -0
- package/flutter_app/macos/Runner/Configs/Release.xcconfig +2 -0
- package/flutter_app/macos/Runner/Configs/Warnings.xcconfig +13 -0
- package/flutter_app/macos/Runner/DebugProfile.entitlements +16 -0
- package/flutter_app/macos/Runner/Info.plist +36 -0
- package/flutter_app/macos/Runner/MainFlutterWindow.swift +19 -0
- package/flutter_app/macos/Runner/Release.entitlements +12 -0
- package/flutter_app/macos/Runner.xcodeproj/project.pbxproj +801 -0
- package/flutter_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/flutter_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
- package/flutter_app/macos/Runner.xcworkspace/contents.xcworkspacedata +10 -0
- package/flutter_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/flutter_app/macos/RunnerTests/RunnerTests.swift +12 -0
- package/flutter_app/patch_strings.py +12 -0
- package/flutter_app/pubspec.lock +1088 -0
- package/flutter_app/pubspec.yaml +53 -0
- package/flutter_app/test/messaging_access_summary_test.dart +22 -0
- package/flutter_app/test/recording_payloads_test.dart +53 -0
- package/flutter_app/third_party/desktop_audio_capture/LICENSE +21 -0
- package/flutter_app/third_party/desktop_audio_capture/README.md +262 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +65 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +153 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +110 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +461 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +91 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +106 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +219 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +336 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +101 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +692 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +35 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +36 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +32 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +32 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +878 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +27 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +1172 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +655 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +12 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +30 -0
- package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +87 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +105 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +80 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +31 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +12 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +23 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +25 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +1117 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +115 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +777 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +87 -0
- package/flutter_app/third_party/flutter_secure_storage_linux/linux/CMakeLists.txt +30 -0
- package/flutter_app/third_party/flutter_secure_storage_linux/linux/flutter_secure_storage_linux_plugin.cc +215 -0
- package/flutter_app/third_party/flutter_secure_storage_linux/linux/include/flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h +27 -0
- package/flutter_app/third_party/flutter_secure_storage_linux/pubspec.yaml +20 -0
- package/flutter_app/tool/generate_desktop_branding.py +219 -0
- package/flutter_app/web/favicon.png +0 -0
- package/flutter_app/web/favicon.svg +12 -0
- package/flutter_app/web/icons/Icon-192.png +0 -0
- package/flutter_app/web/icons/Icon-512.png +0 -0
- package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
- package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
- package/flutter_app/web/index.html +39 -0
- package/flutter_app/web/manifest.json +35 -0
- package/flutter_app/windows/CMakeLists.txt +108 -0
- package/flutter_app/windows/flutter/CMakeLists.txt +109 -0
- package/flutter_app/windows/flutter/generated_plugin_registrant.cc +47 -0
- package/flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
- package/flutter_app/windows/flutter/generated_plugins.cmake +35 -0
- package/flutter_app/windows/runner/CMakeLists.txt +41 -0
- package/flutter_app/windows/runner/Runner.rc +121 -0
- package/flutter_app/windows/runner/flutter_window.cpp +533 -0
- package/flutter_app/windows/runner/flutter_window.h +37 -0
- package/flutter_app/windows/runner/main.cpp +53 -0
- package/flutter_app/windows/runner/resource.h +16 -0
- package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
- package/flutter_app/windows/runner/runner.exe.manifest +14 -0
- package/flutter_app/windows/runner/utils.cpp +65 -0
- package/flutter_app/windows/runner/utils.h +19 -0
- package/flutter_app/windows/runner/win32_window.cpp +299 -0
- package/flutter_app/windows/runner/win32_window.h +102 -0
- package/lib/install_helpers.js +31 -0
- package/lib/manager.js +227 -6
- package/package.json +3 -1
- package/server/db/database.js +110 -0
- package/server/http/middleware.js +55 -2
- package/server/http/routes.js +1 -0
- package/server/index.js +3 -0
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/NOTICES +1 -1
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/canvaskit/wimp.wasm +0 -0
- package/server/public/flutter_bootstrap.js +2 -2
- package/server/public/main.dart.js +74324 -73132
- package/server/routes/integrations.js +108 -1
- package/server/routes/memory.js +11 -2
- package/server/{http/routes → routes}/screenHistory.js +2 -2
- package/server/routes/settings.js +75 -2
- package/server/{http/routes → routes}/triggers.js +2 -2
- package/server/routes/wearable.js +67 -0
- package/server/services/ai/models.js +30 -0
- package/server/services/ai/providers/githubCopilot.js +97 -0
- package/server/services/ai/providers/openai.js +2 -1
- package/server/services/ai/providers/openaiCodex.js +31 -0
- package/server/services/ai/settings.js +20 -0
- package/server/services/ai/toolSelector.js +14 -1
- package/server/services/ai/tools.js +77 -4
- package/server/services/desktop/screenRecorder.js +65 -9
- package/server/services/integrations/env.js +5 -0
- package/server/services/integrations/figma/provider.js +1 -0
- package/server/services/integrations/github/common.js +106 -0
- package/server/services/integrations/github/provider.js +499 -0
- package/server/services/integrations/github/repos.js +1124 -0
- package/server/services/integrations/google/provider.js +1 -0
- package/server/services/integrations/home_assistant/provider.js +325 -26
- package/server/services/integrations/manager.js +88 -12
- package/server/services/integrations/microsoft/provider.js +1 -0
- package/server/services/integrations/oauth_provider.js +25 -8
- package/server/services/integrations/provider_config_store.js +85 -0
- package/server/services/integrations/registry.js +4 -0
- package/server/services/integrations/spotify/provider.js +1 -0
- package/server/services/integrations/trello/provider.js +842 -0
- package/server/services/manager.js +46 -1
- package/server/services/mcp/client.js +120 -23
- package/server/services/memory/manager.js +39 -2
- package/server/services/messaging/access_policy.js +10 -0
- package/server/services/messaging/manager.js +49 -0
- package/server/services/messaging/meshtastic.js +260 -0
- package/server/services/messaging/meshtastic_env.js +100 -0
- package/server/services/messaging/meshtastic_protocol.js +476 -0
- package/server/services/messaging/meshtastic_tcp_transport.js +25 -0
- package/server/services/tasks/runtime.js +1 -1
- package/server/services/voice/openaiClient.js +4 -1
- package/server/services/voice/openaiSpeech.js +6 -1
- package/server/services/voice/providers.js +52 -12
- package/server/services/voice/runtimeManager.js +136 -19
- package/server/services/voice/turnRunner.js +29 -9
- package/server/services/wearable/firmware_manifest.js +370 -0
- package/server/services/wearable/gateway.js +350 -0
- package/server/services/wearable/protocol.js +45 -0
- package/server/services/wearable/service.js +244 -0
- package/server/utils/local_secrets.js +56 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
+
};
|