neoagent 2.3.1-beta.0 → 2.3.1-beta.100
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 +63 -5
- package/README.md +16 -5
- package/com.neoagent.plist +1 -1
- package/docs/automation.md +82 -41
- package/docs/capabilities.md +85 -89
- package/docs/configuration.md +89 -87
- package/docs/getting-started.md +46 -27
- package/docs/hardware.md +1 -1
- package/docs/index.md +24 -30
- package/docs/integrations.md +46 -60
- package/docs/migration.md +41 -146
- package/docs/operations.md +23 -20
- package/docs/skills.md +20 -20
- package/docs/why-neoagent.md +15 -13
- package/extensions/chrome-browser/background.mjs +10 -2
- package/flutter_app/.metadata +42 -0
- package/flutter_app/DESIGN_SYSTEM.md +166 -0
- package/flutter_app/README.md +21 -0
- package/flutter_app/analysis_options.yaml +32 -0
- package/flutter_app/android/app/build.gradle.kts +111 -0
- package/flutter_app/android/app/src/debug/AndroidManifest.xml +7 -0
- package/flutter_app/android/app/src/main/AndroidManifest.xml +185 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +888 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/auto/NeoAgentCarAppService.kt +114 -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/telecom/NeoAgentConnection.kt +118 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/telecom/NeoAgentConnectionService.kt +86 -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/arrays.xml +8 -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/automotive_app_desc.xml +4 -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/onboarding_intro.mp4 +0 -0
- package/flutter_app/assets/branding/tray_icon_template.png +0 -0
- package/flutter_app/lib/features/location/location_service.dart +117 -0
- package/flutter_app/lib/features/notifications/notification_interceptor.dart +73 -0
- package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +571 -0
- package/flutter_app/lib/features/onboarding/onboarding_messaging_step.dart +275 -0
- package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +366 -0
- package/flutter_app/lib/features/onboarding/onboarding_shell.dart +57 -0
- package/flutter_app/lib/features/onboarding/onboarding_video_step.dart +218 -0
- package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +46 -0
- package/flutter_app/lib/main.dart +107 -0
- package/flutter_app/lib/main_account_settings.dart +1340 -0
- package/flutter_app/lib/main_admin.dart +900 -0
- package/flutter_app/lib/main_app_shell.dart +2162 -0
- package/flutter_app/lib/main_chat.dart +3902 -0
- package/flutter_app/lib/main_controller.dart +7229 -0
- package/flutter_app/lib/main_devices.dart +1738 -0
- package/flutter_app/lib/main_integrations.dart +917 -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 +3807 -0
- package/flutter_app/lib/main_navigation.dart +206 -0
- package/flutter_app/lib/main_operations.dart +5249 -0
- package/flutter_app/lib/main_recordings.dart +920 -0
- package/flutter_app/lib/main_runtime.dart +869 -0
- package/flutter_app/lib/main_settings.dart +2288 -0
- package/flutter_app/lib/main_shared.dart +3393 -0
- package/flutter_app/lib/main_spacing.dart +33 -0
- package/flutter_app/lib/main_theme.dart +276 -0
- package/flutter_app/lib/main_unified.dart +388 -0
- package/flutter_app/lib/main_voice_assistant.dart +957 -0
- package/flutter_app/lib/src/analytics_service.dart +294 -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_auto_bridge.dart +59 -0
- package/flutter_app/lib/src/android_launcher_bridge.dart +239 -0
- package/flutter_app/lib/src/app_launch_bridge.dart +58 -0
- package/flutter_app/lib/src/app_release_updater.dart +511 -0
- package/flutter_app/lib/src/backend_client.dart +1870 -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 +95 -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/web_app_update_monitor.dart +17 -0
- package/flutter_app/lib/src/web_app_update_monitor_stub.dart +24 -0
- package/flutter_app/lib/src/web_app_update_monitor_web.dart +123 -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 +47 -0
- package/flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
- package/flutter_app/linux/flutter/generated_plugins.cmake +32 -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 +48 -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 +1256 -0
- package/flutter_app/pubspec.yaml +59 -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 +50 -0
- package/flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
- package/flutter_app/windows/flutter/generated_plugins.cmake +36 -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 +465 -43
- package/package.json +11 -3
- package/runtime/paths.js +137 -0
- package/server/config/analytics.js +30 -0
- package/server/db/database.js +363 -21
- package/server/guest-agent.android.package.json +13 -0
- package/server/guest-agent.browser.package.json +14 -0
- package/server/guest_agent.js +98 -52
- package/server/http/middleware.js +55 -2
- package/server/http/routes.js +6 -1
- package/server/http/static.js +41 -1
- package/server/index.js +16 -16
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/AssetManifest.bin +1 -1
- package/server/public/assets/AssetManifest.bin.json +1 -1
- package/server/public/assets/AssetManifest.json +1 -1
- package/server/public/assets/NOTICES +679 -129
- package/server/public/assets/assets/branding/onboarding_intro.mp4 +0 -0
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/assets/packages/mixpanel_flutter/assets/mixpanel.js +3 -0
- package/server/public/canvaskit/wimp.wasm +0 -0
- package/server/public/flutter_bootstrap.js +2 -2
- package/server/public/main.dart.js +95866 -87333
- package/server/routes/account.js +26 -1
- package/server/routes/agents.js +6 -2
- package/server/routes/android.js +22 -6
- package/server/routes/auth.js +25 -5
- package/server/routes/browser.js +47 -13
- package/server/routes/integrations.js +119 -9
- package/server/routes/memory.js +179 -8
- package/server/routes/runtime.js +14 -0
- package/server/routes/screenHistory.js +46 -0
- package/server/routes/settings.js +102 -24
- package/server/routes/skills.js +12 -0
- package/server/routes/social_video.js +66 -0
- package/server/routes/tasks.js +22 -2
- package/server/routes/triggers.js +90 -0
- package/server/routes/wearable.js +67 -0
- package/server/routes/widgets.js +4 -4
- package/server/services/ai/capabilityHealth.js +23 -51
- package/server/services/ai/compaction.js +1 -1
- package/server/services/ai/deliverables/artifact_helpers.js +190 -0
- package/server/services/ai/deliverables/contracts.js +113 -0
- package/server/services/ai/deliverables/index.js +20 -0
- package/server/services/ai/deliverables/selector.js +94 -0
- package/server/services/ai/deliverables/validator.js +63 -0
- package/server/services/ai/deliverables/workflows.js +207 -0
- package/server/services/ai/engine.js +372 -27
- package/server/services/ai/hooks.js +127 -0
- package/server/services/ai/integrated_tools/index.js +98 -0
- package/server/services/ai/integrated_tools/remotion.js +373 -0
- package/server/services/ai/integrated_tools/shared.js +204 -0
- package/server/services/ai/integrated_tools/slidev.js +207 -0
- package/server/services/ai/loopPolicy.js +146 -0
- package/server/services/ai/models.js +36 -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 +384 -0
- package/server/services/ai/recordingInsights.js +11 -13
- package/server/services/ai/runEvents.js +100 -0
- package/server/services/ai/settings.js +20 -0
- package/server/services/ai/systemPrompt.js +16 -2
- package/server/services/ai/taskAnalysis.js +2 -0
- package/server/services/ai/toolResult.js +20 -0
- package/server/services/ai/toolRunner.js +46 -6
- package/server/services/ai/toolSelector.js +54 -1
- package/server/services/ai/tools.js +360 -127
- package/server/services/android/android_bootstrap_worker.js +63 -0
- package/server/services/android/controller.js +442 -1760
- package/server/services/bootstrap_helpers.js +0 -34
- package/server/services/browser/controller.js +326 -52
- package/server/services/cli/executor.js +40 -1
- package/server/services/desktop/screenRecorder.js +182 -0
- package/server/services/integrations/env.js +10 -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/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 +8 -2
- package/server/services/integrations/spotify/provider.js +488 -0
- package/server/services/integrations/trello/provider.js +842 -0
- package/server/services/integrations/weather/provider.js +559 -0
- package/server/services/integrations/whatsapp/provider.js +6 -2
- package/server/services/manager.js +109 -154
- package/server/services/mcp/client.js +120 -23
- package/server/services/memory/llm_transfer.js +218 -0
- package/server/services/memory/manager.js +299 -35
- package/server/services/messaging/access_policy.js +10 -0
- package/server/services/messaging/automation.js +1 -1
- package/server/services/messaging/manager.js +93 -8
- package/server/services/messaging/meshtastic.js +277 -0
- package/server/services/messaging/meshtastic_env.js +40 -0
- package/server/services/messaging/meshtastic_protocol.js +530 -0
- package/server/services/messaging/meshtastic_tcp_transport.js +25 -0
- package/server/services/runtime/backends/local-vm.js +221 -158
- package/server/services/runtime/docker-vm-manager.js +392 -0
- package/server/services/runtime/guest_bootstrap.js +654 -0
- package/server/services/runtime/manager.js +85 -29
- package/server/services/runtime/settings.js +22 -31
- package/server/services/runtime/validation.js +16 -31
- package/server/services/skills/base_catalog.js +33 -0
- package/server/services/social_video/adapters/base.js +26 -0
- package/server/services/social_video/adapters/index.js +27 -0
- package/server/services/social_video/adapters/instagram.js +17 -0
- package/server/services/social_video/adapters/tiktok.js +17 -0
- package/server/services/social_video/adapters/x.js +17 -0
- package/server/services/social_video/adapters/youtube.js +17 -0
- package/server/services/social_video/captions.js +187 -0
- package/server/services/social_video/frame.js +42 -0
- package/server/services/social_video/index.js +7 -0
- package/server/services/social_video/metadata.js +63 -0
- package/server/services/social_video/result.js +63 -0
- package/server/services/social_video/service.js +720 -0
- package/server/services/social_video/url.js +83 -0
- package/server/services/tasks/adapters/index.js +2 -0
- package/server/services/tasks/adapters/manual.js +12 -0
- package/server/services/tasks/adapters/schedule.js +33 -5
- package/server/services/tasks/adapters/weather_event.js +84 -0
- package/server/services/tasks/integration_runtime.js +86 -1
- package/server/services/tasks/runtime.js +3 -3
- package/server/services/tasks/task_repository.js +3 -6
- package/server/services/voice/agentBridge.js +20 -4
- package/server/services/voice/message.js +3 -0
- package/server/services/voice/openaiClient.js +4 -1
- package/server/services/voice/openaiSpeech.js +6 -1
- package/server/services/voice/providers.js +144 -15
- package/server/services/voice/runtime.js +8 -8
- package/server/services/voice/runtimeManager.js +292 -20
- package/server/services/voice/turnRunner.js +29 -9
- package/server/services/wearable/firmware_manifest.js +353 -0
- package/server/services/wearable/gateway.js +350 -0
- package/server/services/wearable/protocol.js +45 -0
- package/server/services/wearable/service.js +240 -0
- package/server/services/websocket.js +3 -1
- package/server/services/widgets/focus_widget.js +137 -0
- package/server/services/widgets/service.js +182 -6
- package/server/services/workspace/manager.js +301 -0
- package/server/utils/deployment.js +16 -9
- package/server/utils/local_secrets.js +56 -0
- package/server/utils/logger.js +37 -9
- package/server/services/integrations/home_assistant/provider.js +0 -350
- package/server/services/messaging/access_policy.test.js +0 -228
- package/server/services/runtime/backends/host.js +0 -37
- package/server/services/runtime/qemu.js +0 -391
package/lib/manager.js
CHANGED
|
@@ -18,6 +18,7 @@ const {
|
|
|
18
18
|
LOG_DIR,
|
|
19
19
|
ENV_FILE,
|
|
20
20
|
PID_FILE,
|
|
21
|
+
getDefaultVmBaseImageUrl,
|
|
21
22
|
ensureRuntimeDirs,
|
|
22
23
|
migrateLegacyRuntime
|
|
23
24
|
} = require('../runtime/paths');
|
|
@@ -118,28 +119,45 @@ function readEnvFileRaw() {
|
|
|
118
119
|
return fs.readFileSync(ENV_FILE, 'utf8');
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
function sanitizeEnvKey(key) {
|
|
123
|
+
return String(key).replace(/[\r\n]/g, '');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function sanitizeEnvValue(value) {
|
|
127
|
+
return String(value).replace(/[\r\n]/g, '');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function validateEnvKey(key) {
|
|
131
|
+
if (!/^[A-Z][A-Z0-9_]*$/.test(key)) {
|
|
132
|
+
throw new Error(`Invalid env key "${key}". Keys must be uppercase letters, digits, and underscores (e.g. PORT, ANTHROPIC_API_KEY).`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
121
136
|
function upsertEnvValue(key, value) {
|
|
137
|
+
const safeKey = sanitizeEnvKey(key);
|
|
138
|
+
const safeValue = sanitizeEnvValue(value);
|
|
122
139
|
const raw = readEnvFileRaw();
|
|
123
140
|
const lines = raw ? raw.split('\n') : [];
|
|
124
141
|
let replaced = false;
|
|
125
142
|
|
|
126
143
|
for (let i = 0; i < lines.length; i++) {
|
|
127
|
-
if (lines[i].startsWith(`${
|
|
128
|
-
lines[i] = `${
|
|
144
|
+
if (lines[i].startsWith(`${safeKey}=`)) {
|
|
145
|
+
lines[i] = `${safeKey}=${safeValue}`;
|
|
129
146
|
replaced = true;
|
|
130
147
|
break;
|
|
131
148
|
}
|
|
132
149
|
}
|
|
133
150
|
|
|
134
|
-
if (!replaced) lines.push(`${
|
|
151
|
+
if (!replaced) lines.push(`${safeKey}=${safeValue}`);
|
|
135
152
|
const output = lines.filter((_, idx, arr) => idx !== arr.length - 1 || arr[idx] !== '').join('\n') + '\n';
|
|
136
153
|
fs.writeFileSync(ENV_FILE, output, { mode: 0o600 });
|
|
137
154
|
}
|
|
138
155
|
|
|
139
156
|
function removeEnvValue(key) {
|
|
157
|
+
const safeKey = sanitizeEnvKey(key);
|
|
140
158
|
const raw = readEnvFileRaw();
|
|
141
159
|
if (!raw) return false;
|
|
142
|
-
const lines = raw.split('\n').filter((line) => !line.startsWith(`${
|
|
160
|
+
const lines = raw.split('\n').filter((line) => !line.startsWith(`${safeKey}=`));
|
|
143
161
|
const output = lines.filter((_, idx, arr) => idx !== arr.length - 1 || arr[idx] !== '').join('\n') + '\n';
|
|
144
162
|
fs.writeFileSync(ENV_FILE, output, { mode: 0o600 });
|
|
145
163
|
return true;
|
|
@@ -287,6 +305,38 @@ function ensureLogDir() {
|
|
|
287
305
|
ensureRuntimeDirs();
|
|
288
306
|
}
|
|
289
307
|
|
|
308
|
+
function pruneOldRuntimeBackups(backupsDir, keepLatest = 3) {
|
|
309
|
+
if (!fs.existsSync(backupsDir) || keepLatest < 0) return;
|
|
310
|
+
|
|
311
|
+
const backupDirs = fs
|
|
312
|
+
.readdirSync(backupsDir, { withFileTypes: true })
|
|
313
|
+
.filter((entry) => entry.isDirectory() && entry.name.startsWith('pre-update-'))
|
|
314
|
+
.map((entry) => {
|
|
315
|
+
const fullPath = path.join(backupsDir, entry.name);
|
|
316
|
+
let mtimeMs = 0;
|
|
317
|
+
try {
|
|
318
|
+
mtimeMs = fs.statSync(fullPath).mtimeMs;
|
|
319
|
+
} catch {
|
|
320
|
+
// Skip entries that disappear or cannot be statted.
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
return { name: entry.name, fullPath, mtimeMs };
|
|
324
|
+
})
|
|
325
|
+
.filter(Boolean)
|
|
326
|
+
.sort((a, b) => {
|
|
327
|
+
if (b.mtimeMs !== a.mtimeMs) return b.mtimeMs - a.mtimeMs;
|
|
328
|
+
return b.name.localeCompare(a.name);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
for (const backup of backupDirs.slice(keepLatest)) {
|
|
332
|
+
try {
|
|
333
|
+
fs.rmSync(backup.fullPath, { recursive: true, force: true });
|
|
334
|
+
} catch {
|
|
335
|
+
// Best-effort cleanup only.
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
290
340
|
function backupRuntimeData() {
|
|
291
341
|
const backupsDir = path.join(RUNTIME_HOME, 'backups');
|
|
292
342
|
fs.mkdirSync(backupsDir, { recursive: true });
|
|
@@ -296,6 +346,7 @@ function backupRuntimeData() {
|
|
|
296
346
|
|
|
297
347
|
if (fs.existsSync(ENV_FILE)) fs.copyFileSync(ENV_FILE, path.join(target, '.env'));
|
|
298
348
|
if (fs.existsSync(DATA_DIR)) fs.cpSync(DATA_DIR, path.join(target, 'data'), { recursive: true, force: false, errorOnExist: false });
|
|
349
|
+
pruneOldRuntimeBackups(backupsDir, 3);
|
|
299
350
|
}
|
|
300
351
|
|
|
301
352
|
function killByPort(port) {
|
|
@@ -347,15 +398,19 @@ function listNeoAgentServerProcesses() {
|
|
|
347
398
|
};
|
|
348
399
|
})
|
|
349
400
|
.filter(Boolean)
|
|
350
|
-
.filter((entry) =>
|
|
351
|
-
entry.pid
|
|
352
|
-
|
|
353
|
-
(
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
401
|
+
.filter((entry) => {
|
|
402
|
+
if (entry.pid === process.pid) return false;
|
|
403
|
+
const cmd = String(entry.command || '');
|
|
404
|
+
const cmdNormalized = cmd.replace(/\\/g, '/');
|
|
405
|
+
const executablePart = cmd.split(/\s+/)[0] || '';
|
|
406
|
+
const executableBase = path.basename(executablePart);
|
|
407
|
+
const isNode = /^node\d*$/.test(executableBase) || /(^|\s)node\d*(\s|$)/.test(cmd);
|
|
408
|
+
return isNode && (
|
|
409
|
+
appIndexPattern.test(cmdNormalized) ||
|
|
410
|
+
genericNeoAgentPattern.test(cmdNormalized) ||
|
|
411
|
+
repoNamePattern.test(cmd)
|
|
412
|
+
);
|
|
413
|
+
});
|
|
359
414
|
}
|
|
360
415
|
|
|
361
416
|
function killNeoAgentServerProcesses() {
|
|
@@ -425,18 +480,24 @@ async function cmdSetup() {
|
|
|
425
480
|
ensureRuntimeDirs();
|
|
426
481
|
|
|
427
482
|
const current = Object.fromEntries(parseEnv(readEnvFileRaw()).entries());
|
|
483
|
+
const defaultVmBaseImageUrl = getDefaultVmBaseImageUrl();
|
|
428
484
|
|
|
429
485
|
logInfo('Press Enter to keep the current value shown in brackets.');
|
|
430
486
|
|
|
431
487
|
heading('Core');
|
|
432
|
-
const
|
|
488
|
+
const portRaw = await ask('Server port', current.PORT || '3333');
|
|
489
|
+
const portNum = Number(portRaw);
|
|
490
|
+
if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) {
|
|
491
|
+
throw new Error(`Invalid port "${portRaw}". Must be an integer between 1 and 65535.`);
|
|
492
|
+
}
|
|
493
|
+
const port = String(portNum);
|
|
433
494
|
const publicUrl = await ask('Public base URL', current.PUBLIC_URL || '');
|
|
434
495
|
const secureCookiesDefault = current.SECURE_COOKIES ||
|
|
435
496
|
(String(publicUrl || '').trim().startsWith('https://') ? 'true' : 'false');
|
|
436
497
|
const secureCookies = await ask('Secure cookies (true/false)', secureCookiesDefault);
|
|
437
498
|
const trustProxyDefault = current.TRUST_PROXY || secureCookiesDefault;
|
|
438
499
|
const trustProxy = await ask('Trust reverse proxy headers (true/false)', trustProxyDefault);
|
|
439
|
-
const sessionSecret =
|
|
500
|
+
const sessionSecret = current.SESSION_SECRET || randomSecret();
|
|
440
501
|
const deploymentMode = await ask(
|
|
441
502
|
'Deployment mode (self_hosted/managed)',
|
|
442
503
|
current.NEOAGENT_DEPLOYMENT_MODE || 'self_hosted'
|
|
@@ -446,6 +507,11 @@ async function cmdSetup() {
|
|
|
446
507
|
current.NEOAGENT_RELEASE_CHANNEL || 'stable'
|
|
447
508
|
);
|
|
448
509
|
const origins = await ask('Allowed CORS origins', current.ALLOWED_ORIGINS || '');
|
|
510
|
+
const deploymentProfile = current.NEOAGENT_PROFILE || 'prod';
|
|
511
|
+
const vmBaseImageUrl = current.NEOAGENT_VM_BASE_IMAGE_URL || defaultVmBaseImageUrl;
|
|
512
|
+
const vmMemoryMb = current.NEOAGENT_VM_MEMORY_MB || '4096';
|
|
513
|
+
const vmCpus = current.NEOAGENT_VM_CPUS || '2';
|
|
514
|
+
const vmGuestToken = current.NEOAGENT_VM_GUEST_TOKEN || randomSecret();
|
|
449
515
|
|
|
450
516
|
heading('AI Providers');
|
|
451
517
|
const anthropic = await askSecret('Anthropic API key', current.ANTHROPIC_API_KEY || '');
|
|
@@ -542,6 +608,19 @@ async function cmdSetup() {
|
|
|
542
608
|
const normalizedDeploymentMode = parseDeploymentMode(deploymentMode);
|
|
543
609
|
const normalizedReleaseChannel = parseReleaseChannel(releaseChannel) || 'stable';
|
|
544
610
|
|
|
611
|
+
const githubOauthClientId = await askSecret(
|
|
612
|
+
'GitHub OAuth client ID',
|
|
613
|
+
current.GITHUB_OAUTH_CLIENT_ID || ''
|
|
614
|
+
);
|
|
615
|
+
const githubOauthClientSecret = await askSecret(
|
|
616
|
+
'GitHub OAuth client secret',
|
|
617
|
+
current.GITHUB_OAUTH_CLIENT_SECRET || ''
|
|
618
|
+
);
|
|
619
|
+
const githubOauthRedirectUri = await ask(
|
|
620
|
+
'GitHub OAuth redirect URI',
|
|
621
|
+
current.GITHUB_OAUTH_REDIRECT_URI || ''
|
|
622
|
+
);
|
|
623
|
+
|
|
545
624
|
const lines = [
|
|
546
625
|
`NODE_ENV=production`,
|
|
547
626
|
`PORT=${port}`,
|
|
@@ -549,8 +628,13 @@ async function cmdSetup() {
|
|
|
549
628
|
`SECURE_COOKIES=${normalizedSecureCookies}`,
|
|
550
629
|
`TRUST_PROXY=${normalizedTrustProxy}`,
|
|
551
630
|
`SESSION_SECRET=${sessionSecret}`,
|
|
631
|
+
`NEOAGENT_PROFILE=${deploymentProfile}`,
|
|
552
632
|
`NEOAGENT_DEPLOYMENT_MODE=${normalizedDeploymentMode}`,
|
|
553
633
|
`NEOAGENT_RELEASE_CHANNEL=${normalizedReleaseChannel}`,
|
|
634
|
+
`NEOAGENT_VM_BASE_IMAGE_URL=${vmBaseImageUrl}`,
|
|
635
|
+
`NEOAGENT_VM_MEMORY_MB=${vmMemoryMb}`,
|
|
636
|
+
`NEOAGENT_VM_CPUS=${vmCpus}`,
|
|
637
|
+
`NEOAGENT_VM_GUEST_TOKEN=${vmGuestToken}`,
|
|
554
638
|
anthropic ? `ANTHROPIC_API_KEY=${anthropic}` : '',
|
|
555
639
|
anthropicBaseUrl ? `ANTHROPIC_BASE_URL=${anthropicBaseUrl}` : '',
|
|
556
640
|
openai ? `OPENAI_API_KEY=${openai}` : '',
|
|
@@ -576,6 +660,9 @@ async function cmdSetup() {
|
|
|
576
660
|
figmaOauthClientId ? `FIGMA_OAUTH_CLIENT_ID=${figmaOauthClientId}` : '',
|
|
577
661
|
figmaOauthClientSecret ? `FIGMA_OAUTH_CLIENT_SECRET=${figmaOauthClientSecret}` : '',
|
|
578
662
|
figmaOauthRedirectUri ? `FIGMA_OAUTH_REDIRECT_URI=${figmaOauthRedirectUri}` : '',
|
|
663
|
+
githubOauthClientId ? `GITHUB_OAUTH_CLIENT_ID=${githubOauthClientId}` : '',
|
|
664
|
+
githubOauthClientSecret ? `GITHUB_OAUTH_CLIENT_SECRET=${githubOauthClientSecret}` : '',
|
|
665
|
+
githubOauthRedirectUri ? `GITHUB_OAUTH_REDIRECT_URI=${githubOauthRedirectUri}` : '',
|
|
579
666
|
deepgramApiKey ? `DEEPGRAM_API_KEY=${deepgramApiKey}` : '',
|
|
580
667
|
deepgramBaseUrl ? `DEEPGRAM_BASE_URL=${deepgramBaseUrl}` : '',
|
|
581
668
|
deepgramModel ? `DEEPGRAM_MODEL=${deepgramModel}` : '',
|
|
@@ -674,6 +761,141 @@ async function cmdMigrate(args = []) {
|
|
|
674
761
|
});
|
|
675
762
|
}
|
|
676
763
|
|
|
764
|
+
async function pollDeviceCode({ pollUrl, pollBody, pollHeaders = {}, intervalMs, timeoutMs, onToken }) {
|
|
765
|
+
const start = Date.now();
|
|
766
|
+
let currentInterval = intervalMs;
|
|
767
|
+
while (Date.now() - start < timeoutMs) {
|
|
768
|
+
await new Promise((r) => setTimeout(r, currentInterval));
|
|
769
|
+
const res = await fetch(pollUrl, {
|
|
770
|
+
method: 'POST',
|
|
771
|
+
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', ...pollHeaders },
|
|
772
|
+
body: JSON.stringify(pollBody()),
|
|
773
|
+
});
|
|
774
|
+
if (res.status === 403 || res.status === 404) continue;
|
|
775
|
+
if (!res.ok) {
|
|
776
|
+
const text = await res.text().catch(() => 'Unknown error');
|
|
777
|
+
throw new Error(`Token poll failed: HTTP ${res.status} — ${text}`);
|
|
778
|
+
}
|
|
779
|
+
const data = await res.json();
|
|
780
|
+
const done = await onToken(data);
|
|
781
|
+
if (done) return;
|
|
782
|
+
if (data.error === 'authorization_pending') continue;
|
|
783
|
+
if (data.error === 'slow_down') { currentInterval += 5000; continue; }
|
|
784
|
+
if (data.error) throw new Error(`Authentication failed: ${data.error_description || data.error}`);
|
|
785
|
+
}
|
|
786
|
+
throw new Error('Authentication timed out after 15 minutes.');
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
async function cmdLogin(args = []) {
|
|
790
|
+
const provider = args[0];
|
|
791
|
+
if (provider !== 'github-copilot' && provider !== 'openai-codex') {
|
|
792
|
+
throw new Error(`Unsupported login provider: ${provider || 'none'}. Available: github-copilot, openai-codex`);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
if (provider === 'github-copilot') {
|
|
796
|
+
heading('GitHub Copilot Login');
|
|
797
|
+
const clientId = '01ab8ac9400c4e429b23';
|
|
798
|
+
logInfo('Requesting device code from GitHub...');
|
|
799
|
+
|
|
800
|
+
const reqRes = await fetch('https://github.com/login/device/code', {
|
|
801
|
+
method: 'POST',
|
|
802
|
+
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
|
|
803
|
+
body: JSON.stringify({ client_id: clientId, scope: 'user:email' })
|
|
804
|
+
});
|
|
805
|
+
if (!reqRes.ok) throw new Error(`Failed to request device code: HTTP ${reqRes.status}`);
|
|
806
|
+
|
|
807
|
+
const { device_code, user_code, verification_uri, interval } = await reqRes.json();
|
|
808
|
+
console.log(`\n ${COLORS.cyan}Please visit:${COLORS.reset} ${verification_uri}`);
|
|
809
|
+
console.log(` ${COLORS.cyan}Enter code:${COLORS.reset} ${COLORS.bold}${user_code}${COLORS.reset}\n`);
|
|
810
|
+
logInfo('Waiting for authorization (timeout in 15m)...');
|
|
811
|
+
|
|
812
|
+
await pollDeviceCode({
|
|
813
|
+
pollUrl: 'https://github.com/login/oauth/access_token',
|
|
814
|
+
pollBody: () => ({ client_id: clientId, device_code, grant_type: 'urn:ietf:params:oauth:grant-type:device_code' }),
|
|
815
|
+
intervalMs: (interval || 5) * 1000,
|
|
816
|
+
timeoutMs: 15 * 60 * 1000,
|
|
817
|
+
onToken: async (data) => {
|
|
818
|
+
if (!data.access_token) return false;
|
|
819
|
+
upsertEnvValue('GITHUB_COPILOT_ACCESS_TOKEN', data.access_token);
|
|
820
|
+
logOk('Saved GitHub Copilot access token to .env');
|
|
821
|
+
logInfo('Restarting NeoAgent to apply credentials...');
|
|
822
|
+
cmdRestart();
|
|
823
|
+
return true;
|
|
824
|
+
},
|
|
825
|
+
});
|
|
826
|
+
return;
|
|
827
|
+
} else if (provider === 'openai-codex') {
|
|
828
|
+
heading('OpenAI Codex Login');
|
|
829
|
+
const clientId = 'app_EMoamEEZ73f0CkXaXp7hrann';
|
|
830
|
+
logInfo('Requesting device code from OpenAI...');
|
|
831
|
+
|
|
832
|
+
const reqRes = await fetch('https://auth.openai.com/api/accounts/deviceauth/usercode', {
|
|
833
|
+
method: 'POST',
|
|
834
|
+
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
|
|
835
|
+
body: JSON.stringify({ client_id: clientId, scope: 'openid profile email offline_access model.request model.read model.create' })
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
if (!reqRes.ok) {
|
|
839
|
+
throw new Error(`Failed to request device code: HTTP ${reqRes.status}`);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
const data = await reqRes.json();
|
|
843
|
+
const { device_auth_id, interval } = data;
|
|
844
|
+
const user_code = data.user_code || data.usercode;
|
|
845
|
+
const verification_uri = 'https://auth.openai.com/codex/device';
|
|
846
|
+
|
|
847
|
+
console.log(`\n ${COLORS.cyan}Please visit:${COLORS.reset} ${verification_uri}`);
|
|
848
|
+
console.log(` ${COLORS.cyan}Enter code:${COLORS.reset} ${COLORS.bold}${user_code}${COLORS.reset}\n`);
|
|
849
|
+
logInfo('Waiting for authorization (timeout in 15m)...');
|
|
850
|
+
|
|
851
|
+
let authorizationCode = null;
|
|
852
|
+
let codeVerifier = null;
|
|
853
|
+
|
|
854
|
+
await pollDeviceCode({
|
|
855
|
+
pollUrl: 'https://auth.openai.com/api/accounts/deviceauth/token',
|
|
856
|
+
pollBody: () => ({ device_auth_id, user_code }),
|
|
857
|
+
intervalMs: (interval || 5) * 1000,
|
|
858
|
+
timeoutMs: 15 * 60 * 1000,
|
|
859
|
+
onToken: async (data) => {
|
|
860
|
+
if (!data.authorization_code || !data.code_verifier) return false;
|
|
861
|
+
authorizationCode = data.authorization_code;
|
|
862
|
+
codeVerifier = data.code_verifier;
|
|
863
|
+
return true;
|
|
864
|
+
},
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
logInfo('Exchanging authorization code for access token...');
|
|
868
|
+
const exchangeRes = await fetch('https://auth.openai.com/oauth/token', {
|
|
869
|
+
method: 'POST',
|
|
870
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
871
|
+
body: new URLSearchParams({
|
|
872
|
+
grant_type: 'authorization_code',
|
|
873
|
+
code: authorizationCode,
|
|
874
|
+
redirect_uri: 'https://auth.openai.com/deviceauth/callback',
|
|
875
|
+
client_id: clientId,
|
|
876
|
+
code_verifier: codeVerifier,
|
|
877
|
+
}),
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
if (!exchangeRes.ok) {
|
|
881
|
+
const errorText = await exchangeRes.text().catch(() => 'Unknown error');
|
|
882
|
+
throw new Error(`OpenAI token exchange failed: HTTP ${exchangeRes.status} — ${errorText}`);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
const exchangeData = await exchangeRes.json();
|
|
886
|
+
if (!exchangeData.access_token) {
|
|
887
|
+
throw new Error('OpenAI token exchange succeeded but did not return an access token.');
|
|
888
|
+
}
|
|
889
|
+
upsertEnvValue('OPENAI_CODEX_ACCESS_TOKEN', exchangeData.access_token);
|
|
890
|
+
if (exchangeData.refresh_token) {
|
|
891
|
+
upsertEnvValue('OPENAI_CODEX_REFRESH_TOKEN', exchangeData.refresh_token);
|
|
892
|
+
}
|
|
893
|
+
logOk('Saved OpenAI Codex tokens to .env');
|
|
894
|
+
logInfo('Restarting NeoAgent to apply credentials...');
|
|
895
|
+
cmdRestart();
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
677
899
|
function installDependencies() {
|
|
678
900
|
heading('Dependencies');
|
|
679
901
|
runOrThrow('npm', ['install', '--omit=dev', '--no-audit', '--no-fund'], {
|
|
@@ -770,6 +992,109 @@ function startFallback() {
|
|
|
770
992
|
logOk(`Started detached process (pid ${child.pid})`);
|
|
771
993
|
}
|
|
772
994
|
|
|
995
|
+
async function ensureQemuInstalled() {
|
|
996
|
+
heading('Ensure QEMU Installed');
|
|
997
|
+
const platform = detectPlatform();
|
|
998
|
+
|
|
999
|
+
const hasSystem = commandExists('qemu-system-x86_64') || commandExists('qemu-system-aarch64');
|
|
1000
|
+
const hasImg = commandExists('qemu-img');
|
|
1001
|
+
|
|
1002
|
+
if (hasSystem && hasImg) {
|
|
1003
|
+
logOk('QEMU components are already installed');
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
logInfo('QEMU components not found. Attempting to install...');
|
|
1008
|
+
|
|
1009
|
+
if (platform === 'macos') {
|
|
1010
|
+
if (!commandExists('brew')) {
|
|
1011
|
+
throw new Error('Homebrew is required to install QEMU on macOS. Please install it first: https://brew.sh/');
|
|
1012
|
+
}
|
|
1013
|
+
logInfo('Running "brew install qemu"...');
|
|
1014
|
+
runOrThrow('brew', ['install', 'qemu']);
|
|
1015
|
+
} else if (platform === 'linux') {
|
|
1016
|
+
const isArm = process.arch === 'arm64' || process.arch === 'aarch64';
|
|
1017
|
+
if (commandExists('apt-get')) {
|
|
1018
|
+
const pkgs = ['qemu-utils'];
|
|
1019
|
+
if (isArm) {
|
|
1020
|
+
pkgs.push('qemu-system-arm');
|
|
1021
|
+
} else {
|
|
1022
|
+
pkgs.push('qemu-system-x86');
|
|
1023
|
+
}
|
|
1024
|
+
logInfo(`Running "sudo apt-get update && sudo apt-get install -y ${pkgs.join(' ')}"...`);
|
|
1025
|
+
runOrThrow('sudo', ['apt-get', 'update']);
|
|
1026
|
+
runOrThrow('sudo', ['apt-get', 'install', '-y', ...pkgs]);
|
|
1027
|
+
} else if (commandExists('dnf')) {
|
|
1028
|
+
logInfo('Running "sudo dnf install -y qemu-kvm qemu-img"...');
|
|
1029
|
+
runOrThrow('sudo', ['dnf', 'install', '-y', 'qemu-kvm', 'qemu-img']);
|
|
1030
|
+
} else if (commandExists('yum')) {
|
|
1031
|
+
logInfo('Running "sudo yum install -y qemu-kvm qemu-img"...');
|
|
1032
|
+
runOrThrow('sudo', ['yum', 'install', '-y', 'qemu-kvm', 'qemu-img']);
|
|
1033
|
+
} else {
|
|
1034
|
+
throw new Error('Unsupported Linux distribution. Please install qemu-system and qemu-utils manually.');
|
|
1035
|
+
}
|
|
1036
|
+
} else {
|
|
1037
|
+
throw new Error('Unsupported platform for automatic QEMU installation. Please install QEMU manually.');
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
const verifiedSystem = commandExists('qemu-system-x86_64') || commandExists('qemu-system-aarch64');
|
|
1041
|
+
const verifiedImg = commandExists('qemu-img');
|
|
1042
|
+
|
|
1043
|
+
if (verifiedSystem && verifiedImg) {
|
|
1044
|
+
logOk('QEMU installed successfully');
|
|
1045
|
+
} else {
|
|
1046
|
+
throw new Error('QEMU installation failed or components not found in PATH after install.');
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
function ensureYtDlpInstalled() {
|
|
1051
|
+
heading('Ensure yt-dlp Installed');
|
|
1052
|
+
if (commandExists('yt-dlp')) {
|
|
1053
|
+
const ver = runQuiet('yt-dlp', ['--version']);
|
|
1054
|
+
logOk(`yt-dlp ${ver.status === 0 ? ver.stdout.trim() : '(version unknown)'}`);
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
logInfo('yt-dlp not found. Attempting to install...');
|
|
1059
|
+
const platform = detectPlatform();
|
|
1060
|
+
|
|
1061
|
+
if (platform === 'macos') {
|
|
1062
|
+
if (!commandExists('brew')) {
|
|
1063
|
+
logWarn('Homebrew not found — skipping yt-dlp install. Install manually: brew install yt-dlp');
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
try {
|
|
1067
|
+
runOrThrow('brew', ['install', 'yt-dlp']);
|
|
1068
|
+
logOk('yt-dlp installed via Homebrew');
|
|
1069
|
+
} catch {
|
|
1070
|
+
logWarn('yt-dlp install failed. Install manually: brew install yt-dlp');
|
|
1071
|
+
}
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
if (platform === 'linux') {
|
|
1076
|
+
if (commandExists('pipx')) {
|
|
1077
|
+
try {
|
|
1078
|
+
runOrThrow('pipx', ['install', 'yt-dlp']);
|
|
1079
|
+
logOk('yt-dlp installed via pipx');
|
|
1080
|
+
return;
|
|
1081
|
+
} catch {
|
|
1082
|
+
// fall through to pip3
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
if (commandExists('pip3')) {
|
|
1086
|
+
try {
|
|
1087
|
+
runOrThrow('pip3', ['install', '--user', 'yt-dlp']);
|
|
1088
|
+
logOk('yt-dlp installed via pip3');
|
|
1089
|
+
return;
|
|
1090
|
+
} catch {
|
|
1091
|
+
// fall through to warn
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
logWarn('Could not install yt-dlp automatically. Install manually: pipx install yt-dlp');
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
|
|
773
1098
|
async function cmdInstall() {
|
|
774
1099
|
heading(`Install ${APP_NAME}`);
|
|
775
1100
|
if (!fs.existsSync(ENV_FILE)) {
|
|
@@ -778,6 +1103,8 @@ async function cmdInstall() {
|
|
|
778
1103
|
}
|
|
779
1104
|
|
|
780
1105
|
installDependencies();
|
|
1106
|
+
await ensureQemuInstalled();
|
|
1107
|
+
ensureYtDlpInstalled();
|
|
781
1108
|
buildBundledWebClientIfPossible({ required: true });
|
|
782
1109
|
|
|
783
1110
|
const platform = detectPlatform();
|
|
@@ -839,7 +1166,7 @@ function cmdStop() {
|
|
|
839
1166
|
logOk(`Stopped pid ${pid}`);
|
|
840
1167
|
stopped = true;
|
|
841
1168
|
} catch {
|
|
842
|
-
logWarn(`pid ${pid} not running`);
|
|
1169
|
+
logWarn(`pid ${pid} was not running (stale PID file)`);
|
|
843
1170
|
}
|
|
844
1171
|
}
|
|
845
1172
|
fs.rmSync(pidPath, { force: true });
|
|
@@ -867,6 +1194,11 @@ function cmdRestart() {
|
|
|
867
1194
|
cmdStart();
|
|
868
1195
|
}
|
|
869
1196
|
|
|
1197
|
+
async function cmdRebuildWeb() {
|
|
1198
|
+
heading(`Rebuild Flutter Web Client`);
|
|
1199
|
+
buildBundledWebClientIfPossible();
|
|
1200
|
+
}
|
|
1201
|
+
|
|
870
1202
|
function cmdUninstall() {
|
|
871
1203
|
heading(`Uninstall ${APP_NAME}`);
|
|
872
1204
|
const platform = detectPlatform();
|
|
@@ -895,22 +1227,52 @@ async function cmdStatus() {
|
|
|
895
1227
|
const port = loadEnvPort();
|
|
896
1228
|
const running = await isPortOpen(port);
|
|
897
1229
|
const releaseChannel = currentReleaseChannel();
|
|
1230
|
+
const platform = detectPlatform();
|
|
898
1231
|
|
|
899
1232
|
if (running) {
|
|
900
|
-
logOk(`
|
|
1233
|
+
logOk(`server http://localhost:${port}`);
|
|
1234
|
+
} else {
|
|
1235
|
+
logWarn(`server not reachable on port ${port}`);
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
if (platform === 'macos' && fs.existsSync(PLIST_DST)) {
|
|
1239
|
+
const svcRes = runQuiet('launchctl', ['list', SERVICE_LABEL]);
|
|
1240
|
+
if (svcRes.status === 0 && svcRes.stdout.trim()) {
|
|
1241
|
+
logOk(`service launchd (${SERVICE_LABEL})`);
|
|
1242
|
+
} else {
|
|
1243
|
+
logWarn(`service launchd unit not loaded — run: neoagent install`);
|
|
1244
|
+
}
|
|
1245
|
+
} else if (platform === 'linux' && fs.existsSync(SYSTEMD_UNIT)) {
|
|
1246
|
+
const svcRes = runQuiet('systemctl', ['--user', 'is-active', 'neoagent']);
|
|
1247
|
+
if (svcRes.status === 0 && svcRes.stdout.trim() === 'active') {
|
|
1248
|
+
logOk('service systemd (neoagent)');
|
|
1249
|
+
} else {
|
|
1250
|
+
logWarn('service systemd unit not active — run: neoagent install');
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
if (fs.existsSync(ENV_FILE)) {
|
|
1255
|
+
logOk(`config ${ENV_FILE}`);
|
|
1256
|
+
} else {
|
|
1257
|
+
logWarn(`config .env not found — run: neoagent setup`);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
if (hasBundledWebClient(WEB_CLIENT_DIR)) {
|
|
1261
|
+
logOk('web bundled Flutter client present');
|
|
901
1262
|
} else {
|
|
902
|
-
logWarn(
|
|
1263
|
+
logWarn('web no bundled client — run: neoagent rebuild-web');
|
|
903
1264
|
}
|
|
904
1265
|
|
|
905
|
-
console.log(
|
|
906
|
-
console.log(`
|
|
907
|
-
console.log(`
|
|
1266
|
+
console.log('');
|
|
1267
|
+
console.log(` install ${APP_DIR}`);
|
|
1268
|
+
console.log(` version ${currentInstalledVersionLabel()}`);
|
|
1269
|
+
console.log(` channel ${releaseChannelSummary(releaseChannel)}`);
|
|
908
1270
|
|
|
909
1271
|
const processes = listNeoAgentServerProcesses();
|
|
910
1272
|
if (processes.length > 0) {
|
|
911
|
-
console.log(`
|
|
1273
|
+
console.log(` pids ${processes.map((proc) => proc.pid).join(', ')}`);
|
|
912
1274
|
if (processes.length > 1) {
|
|
913
|
-
logWarn(`multiple NeoAgent
|
|
1275
|
+
logWarn(`multiple NeoAgent processes detected (${processes.length})`);
|
|
914
1276
|
}
|
|
915
1277
|
}
|
|
916
1278
|
}
|
|
@@ -962,6 +1324,8 @@ function cmdUpdate(args = []) {
|
|
|
962
1324
|
}
|
|
963
1325
|
const versionBefore = currentInstalledVersionLabel();
|
|
964
1326
|
let versionAfter = versionBefore;
|
|
1327
|
+
const githubInstallRef = releaseChannel === 'beta' ? '#beta' : '';
|
|
1328
|
+
const githubInstallSpec = `git+https://github.com/NeoLabs-Systems/NeoAgent.git${githubInstallRef}`;
|
|
965
1329
|
|
|
966
1330
|
if (fs.existsSync(path.join(APP_DIR, '.git')) && commandExists('git')) {
|
|
967
1331
|
const current = runQuiet('git', ['rev-parse', '--short', 'HEAD']);
|
|
@@ -970,6 +1334,7 @@ function cmdUpdate(args = []) {
|
|
|
970
1334
|
const targetBranch = resolvePreferredGitBranch(releaseChannel);
|
|
971
1335
|
logInfo(`Using git branch ${targetBranch} for the ${releaseChannel} channel.`);
|
|
972
1336
|
ensureGitBranchForReleaseChannel(targetBranch);
|
|
1337
|
+
backupRuntimeData();
|
|
973
1338
|
runOrThrow('git', ['pull', '--rebase', '--autostash', 'origin', targetBranch]);
|
|
974
1339
|
|
|
975
1340
|
const next = runQuiet('git', ['rev-parse', '--short', 'HEAD']);
|
|
@@ -982,17 +1347,16 @@ function cmdUpdate(args = []) {
|
|
|
982
1347
|
buildBundledWebClientIfPossible();
|
|
983
1348
|
}
|
|
984
1349
|
} else {
|
|
985
|
-
|
|
986
|
-
logWarn(`No git repo detected; attempting npm global update from ${npmTag}.`);
|
|
1350
|
+
logWarn(`No git repo detected; attempting npm global update from ${githubInstallSpec}.`);
|
|
987
1351
|
if (commandExists('npm')) {
|
|
988
1352
|
try {
|
|
989
1353
|
backupRuntimeData();
|
|
990
|
-
runOrThrow('npm', ['install', '-g',
|
|
1354
|
+
runOrThrow('npm', ['install', '-g', githubInstallSpec, '--force'], {
|
|
991
1355
|
env: withInstallEnv()
|
|
992
1356
|
});
|
|
993
|
-
logOk('npm global update completed (forced reinstall)');
|
|
1357
|
+
logOk('npm global update completed (forced reinstall from GitHub)');
|
|
994
1358
|
} catch {
|
|
995
|
-
logWarn(`npm global update failed. Run: npm install -g
|
|
1359
|
+
logWarn(`npm global update failed. Run: npm install -g ${githubInstallSpec} --force`);
|
|
996
1360
|
}
|
|
997
1361
|
} else {
|
|
998
1362
|
logWarn('npm not found. Cannot perform global update.');
|
|
@@ -1000,6 +1364,7 @@ function cmdUpdate(args = []) {
|
|
|
1000
1364
|
}
|
|
1001
1365
|
|
|
1002
1366
|
versionAfter = currentInstalledVersionLabel();
|
|
1367
|
+
ensureYtDlpInstalled();
|
|
1003
1368
|
|
|
1004
1369
|
if (!hasBundledWebClient(WEB_CLIENT_DIR)) {
|
|
1005
1370
|
throw new Error('No bundled Flutter web client found after update.');
|
|
@@ -1011,11 +1376,16 @@ function cmdUpdate(args = []) {
|
|
|
1011
1376
|
|
|
1012
1377
|
async function cmdEnv(args = []) {
|
|
1013
1378
|
heading('Environment Variables');
|
|
1014
|
-
|
|
1379
|
+
const action = (args[0] || '').trim().toLowerCase();
|
|
1015
1380
|
|
|
1016
1381
|
if (!action) {
|
|
1017
|
-
|
|
1018
|
-
|
|
1382
|
+
console.log('Usage: neoagent env <subcommand>');
|
|
1383
|
+
console.log('');
|
|
1384
|
+
console.log(' neoagent env list List all variables (secrets masked)');
|
|
1385
|
+
console.log(' neoagent env get KEY Print a single variable');
|
|
1386
|
+
console.log(' neoagent env set KEY VALUE Set a variable');
|
|
1387
|
+
console.log(' neoagent env unset KEY Remove a variable');
|
|
1388
|
+
return;
|
|
1019
1389
|
}
|
|
1020
1390
|
|
|
1021
1391
|
if (action === 'list') {
|
|
@@ -1040,16 +1410,17 @@ async function cmdEnv(args = []) {
|
|
|
1040
1410
|
}
|
|
1041
1411
|
|
|
1042
1412
|
if (action === 'set') {
|
|
1043
|
-
const key = args[1]
|
|
1044
|
-
const value = args.slice(2).join(' ')
|
|
1413
|
+
const key = args[1];
|
|
1414
|
+
const value = args.slice(2).join(' ');
|
|
1045
1415
|
if (!key || !value) throw new Error('Usage: neoagent env set <KEY> <VALUE>');
|
|
1416
|
+
validateEnvKey(key);
|
|
1046
1417
|
upsertEnvValue(key, value);
|
|
1047
1418
|
logOk(`Set ${key} in ${ENV_FILE}`);
|
|
1048
1419
|
return;
|
|
1049
1420
|
}
|
|
1050
1421
|
|
|
1051
1422
|
if (action === 'unset') {
|
|
1052
|
-
const key = args[1]
|
|
1423
|
+
const key = args[1];
|
|
1053
1424
|
if (!key) throw new Error('Usage: neoagent env unset <KEY>');
|
|
1054
1425
|
removeEnvValue(key);
|
|
1055
1426
|
logOk(`Removed ${key} from ${ENV_FILE}`);
|
|
@@ -1059,15 +1430,55 @@ async function cmdEnv(args = []) {
|
|
|
1059
1430
|
throw new Error('Usage: neoagent env [list|get|set|unset] ...');
|
|
1060
1431
|
}
|
|
1061
1432
|
|
|
1433
|
+
function cmdVersion() {
|
|
1434
|
+
console.log(currentInstalledVersionLabel());
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1062
1437
|
function printHelp() {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1438
|
+
const c = COLORS;
|
|
1439
|
+
const W = 38;
|
|
1440
|
+
|
|
1441
|
+
function row(cmd, desc) {
|
|
1442
|
+
const padded = ` neoagent ${cmd}`.padEnd(W);
|
|
1443
|
+
console.log(`${padded}${c.dim}${desc}${c.reset}`);
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
console.log(`\n${c.bold}neoagent${c.reset} — manage your NeoAgent server\n`);
|
|
1447
|
+
console.log(`${c.bold}Usage${c.reset} neoagent <command> [args]\n`);
|
|
1448
|
+
|
|
1449
|
+
console.log(`${c.bold}Lifecycle${c.reset}`);
|
|
1450
|
+
row('install', 'First-time install and service setup');
|
|
1451
|
+
row('start', 'Start the server');
|
|
1452
|
+
row('stop', 'Stop the server');
|
|
1453
|
+
row('restart', 'Stop, then start');
|
|
1454
|
+
row('status', 'Health overview (server, service, config)');
|
|
1455
|
+
row('logs', 'Tail server logs');
|
|
1456
|
+
row('uninstall', 'Remove the system service');
|
|
1457
|
+
console.log('');
|
|
1458
|
+
|
|
1459
|
+
console.log(`${c.bold}Configuration${c.reset}`);
|
|
1460
|
+
row('setup', 'Interactive configuration wizard');
|
|
1461
|
+
row('env list', 'List all variables (secrets masked)');
|
|
1462
|
+
row('env get KEY', 'Print a single variable');
|
|
1463
|
+
row('env set KEY VALUE', 'Set a variable');
|
|
1464
|
+
row('env unset KEY', 'Remove a variable');
|
|
1465
|
+
row('channel', 'Show current release channel');
|
|
1466
|
+
row('channel stable|beta', 'Switch release channel');
|
|
1467
|
+
console.log('');
|
|
1468
|
+
|
|
1469
|
+
console.log(`${c.bold}Updates & Auth${c.reset}`);
|
|
1470
|
+
row('update', 'Update to latest on current channel');
|
|
1471
|
+
row('update stable|beta', 'Update and switch channel');
|
|
1472
|
+
row('login github-copilot','Authenticate GitHub Copilot');
|
|
1473
|
+
row('login openai-codex', 'Authenticate OpenAI Codex');
|
|
1474
|
+
console.log('');
|
|
1475
|
+
|
|
1476
|
+
console.log(`${c.bold}Maintenance${c.reset}`);
|
|
1477
|
+
row('migrate', 'Migrate from another agent installation');
|
|
1478
|
+
row('migrate dry-run', 'Preview what would be migrated');
|
|
1479
|
+
row('rebuild-web', 'Rebuild the bundled Flutter web client');
|
|
1480
|
+
row('version', 'Print installed version');
|
|
1481
|
+
console.log('');
|
|
1071
1482
|
}
|
|
1072
1483
|
|
|
1073
1484
|
async function runCLI(argv) {
|
|
@@ -1094,6 +1505,9 @@ async function runCLI(argv) {
|
|
|
1094
1505
|
case 'restart':
|
|
1095
1506
|
cmdRestart();
|
|
1096
1507
|
break;
|
|
1508
|
+
case 'rebuild-web':
|
|
1509
|
+
await cmdRebuildWeb();
|
|
1510
|
+
break;
|
|
1097
1511
|
case 'start':
|
|
1098
1512
|
cmdStart();
|
|
1099
1513
|
break;
|
|
@@ -1112,13 +1526,21 @@ async function runCLI(argv) {
|
|
|
1112
1526
|
case 'migrate':
|
|
1113
1527
|
await cmdMigrate(argv.slice(1));
|
|
1114
1528
|
break;
|
|
1529
|
+
case 'login':
|
|
1530
|
+
await cmdLogin(argv.slice(1));
|
|
1531
|
+
break;
|
|
1532
|
+
case 'version':
|
|
1533
|
+
case '--version':
|
|
1534
|
+
case '-V':
|
|
1535
|
+
cmdVersion();
|
|
1536
|
+
break;
|
|
1115
1537
|
case 'help':
|
|
1116
1538
|
case '--help':
|
|
1117
1539
|
case '-h':
|
|
1118
1540
|
printHelp();
|
|
1119
1541
|
break;
|
|
1120
1542
|
default:
|
|
1121
|
-
throw new Error(`Unknown command: ${command}
|
|
1543
|
+
throw new Error(`Unknown command: ${command}. Run "neoagent --help" for usage.`);
|
|
1122
1544
|
}
|
|
1123
1545
|
}
|
|
1124
1546
|
|