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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (390) hide show
  1. package/.env.example +53 -5
  2. package/README.md +16 -7
  3. package/com.neoagent.plist +1 -1
  4. package/docs/automation.md +82 -41
  5. package/docs/capabilities.md +85 -89
  6. package/docs/configuration.md +87 -94
  7. package/docs/getting-started.md +46 -27
  8. package/docs/hardware.md +1 -1
  9. package/docs/index.md +24 -30
  10. package/docs/integrations.md +46 -64
  11. package/docs/migration.md +41 -146
  12. package/docs/operations.md +23 -20
  13. package/docs/skills.md +20 -20
  14. package/docs/why-neoagent.md +15 -13
  15. package/extensions/chrome-browser/background.mjs +10 -2
  16. package/flutter_app/.metadata +42 -0
  17. package/flutter_app/DESIGN_SYSTEM.md +166 -0
  18. package/flutter_app/README.md +21 -0
  19. package/flutter_app/analysis_options.yaml +32 -0
  20. package/flutter_app/android/app/build.gradle.kts +111 -0
  21. package/flutter_app/android/app/src/debug/AndroidManifest.xml +7 -0
  22. package/flutter_app/android/app/src/main/AndroidManifest.xml +185 -0
  23. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +888 -0
  24. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/auto/NeoAgentCarAppService.kt +114 -0
  25. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthConnectGateway.kt +280 -0
  26. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncNotifications.kt +113 -0
  27. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncPayload.kt +57 -0
  28. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncScheduler.kt +78 -0
  29. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncWorker.kt +253 -0
  30. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/PermissionsRationaleActivity.kt +46 -0
  31. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +21 -0
  32. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +586 -0
  33. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +78 -0
  34. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +104 -0
  35. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/telecom/NeoAgentConnection.kt +118 -0
  36. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/telecom/NeoAgentConnectionService.kt +86 -0
  37. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiHomeWidgetProvider.kt +457 -0
  38. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiWidgetStore.kt +194 -0
  39. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/VoiceLaunchWidgetProvider.kt +67 -0
  40. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetConfigActivity.kt +228 -0
  41. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncScheduler.kt +72 -0
  42. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncWorker.kt +186 -0
  43. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetTaskRunWorker.kt +210 -0
  44. package/flutter_app/android/app/src/main/res/drawable/launch_background.xml +12 -0
  45. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_bg.xml +11 -0
  46. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_task_bg.xml +8 -0
  47. package/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  48. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget.xml +138 -0
  49. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget_task_row.xml +52 -0
  50. package/flutter_app/android/app/src/main/res/layout/neoagent_voice_widget.xml +49 -0
  51. package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  52. package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  53. package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  54. package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  55. package/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  56. package/flutter_app/android/app/src/main/res/values/arrays.xml +8 -0
  57. package/flutter_app/android/app/src/main/res/values/strings.xml +12 -0
  58. package/flutter_app/android/app/src/main/res/values/styles.xml +18 -0
  59. package/flutter_app/android/app/src/main/res/values-night/styles.xml +18 -0
  60. package/flutter_app/android/app/src/main/res/xml/automotive_app_desc.xml +4 -0
  61. package/flutter_app/android/app/src/main/res/xml/file_paths.xml +6 -0
  62. package/flutter_app/android/app/src/main/res/xml/neoagent_ai_widget_info.xml +12 -0
  63. package/flutter_app/android/app/src/main/res/xml/neoagent_voice_widget_info.xml +12 -0
  64. package/flutter_app/android/app/src/profile/AndroidManifest.xml +7 -0
  65. package/flutter_app/android/build.gradle.kts +24 -0
  66. package/flutter_app/android/ci-release.keystore +0 -0
  67. package/flutter_app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  68. package/flutter_app/android/gradle.properties +3 -0
  69. package/flutter_app/android/key.properties +4 -0
  70. package/flutter_app/android/settings.gradle.kts +26 -0
  71. package/flutter_app/assets/branding/app_icon_1024.png +0 -0
  72. package/flutter_app/assets/branding/app_icon_128.png +0 -0
  73. package/flutter_app/assets/branding/app_icon_192.png +0 -0
  74. package/flutter_app/assets/branding/app_icon_256.png +0 -0
  75. package/flutter_app/assets/branding/app_icon_32.png +0 -0
  76. package/flutter_app/assets/branding/app_icon_512.png +0 -0
  77. package/flutter_app/assets/branding/app_icon_64.png +0 -0
  78. package/flutter_app/assets/branding/onboarding_intro.mp4 +0 -0
  79. package/flutter_app/assets/branding/tray_icon_template.png +0 -0
  80. package/flutter_app/lib/features/location/location_service.dart +117 -0
  81. package/flutter_app/lib/features/notifications/notification_interceptor.dart +73 -0
  82. package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +571 -0
  83. package/flutter_app/lib/features/onboarding/onboarding_messaging_step.dart +275 -0
  84. package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +366 -0
  85. package/flutter_app/lib/features/onboarding/onboarding_shell.dart +57 -0
  86. package/flutter_app/lib/features/onboarding/onboarding_video_step.dart +218 -0
  87. package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +46 -0
  88. package/flutter_app/lib/main.dart +107 -0
  89. package/flutter_app/lib/main_account_settings.dart +1340 -0
  90. package/flutter_app/lib/main_admin.dart +900 -0
  91. package/flutter_app/lib/main_app_shell.dart +2162 -0
  92. package/flutter_app/lib/main_chat.dart +3902 -0
  93. package/flutter_app/lib/main_controller.dart +7229 -0
  94. package/flutter_app/lib/main_devices.dart +1738 -0
  95. package/flutter_app/lib/main_integrations.dart +917 -0
  96. package/flutter_app/lib/main_launcher.dart +959 -0
  97. package/flutter_app/lib/main_launcher_entry.dart +5 -0
  98. package/flutter_app/lib/main_models.dart +3807 -0
  99. package/flutter_app/lib/main_navigation.dart +206 -0
  100. package/flutter_app/lib/main_operations.dart +5249 -0
  101. package/flutter_app/lib/main_recordings.dart +920 -0
  102. package/flutter_app/lib/main_runtime.dart +869 -0
  103. package/flutter_app/lib/main_settings.dart +2288 -0
  104. package/flutter_app/lib/main_shared.dart +3393 -0
  105. package/flutter_app/lib/main_spacing.dart +33 -0
  106. package/flutter_app/lib/main_theme.dart +276 -0
  107. package/flutter_app/lib/main_unified.dart +388 -0
  108. package/flutter_app/lib/main_voice_assistant.dart +957 -0
  109. package/flutter_app/lib/src/analytics_service.dart +294 -0
  110. package/flutter_app/lib/src/android_apk_drop_zone.dart +32 -0
  111. package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +16 -0
  112. package/flutter_app/lib/src/android_apk_drop_zone_web.dart +348 -0
  113. package/flutter_app/lib/src/android_app_installer.dart +22 -0
  114. package/flutter_app/lib/src/android_app_installer_io.dart +122 -0
  115. package/flutter_app/lib/src/android_app_installer_stub.dart +21 -0
  116. package/flutter_app/lib/src/android_auto_bridge.dart +59 -0
  117. package/flutter_app/lib/src/android_launcher_bridge.dart +239 -0
  118. package/flutter_app/lib/src/app_launch_bridge.dart +58 -0
  119. package/flutter_app/lib/src/app_release_updater.dart +511 -0
  120. package/flutter_app/lib/src/backend_client.dart +1870 -0
  121. package/flutter_app/lib/src/desktop_companion.dart +2 -0
  122. package/flutter_app/lib/src/desktop_companion_actions.dart +586 -0
  123. package/flutter_app/lib/src/desktop_companion_io.dart +538 -0
  124. package/flutter_app/lib/src/desktop_companion_stub.dart +59 -0
  125. package/flutter_app/lib/src/desktop_native_bridge.dart +91 -0
  126. package/flutter_app/lib/src/desktop_screen_capture.dart +21 -0
  127. package/flutter_app/lib/src/desktop_screen_capture_io.dart +142 -0
  128. package/flutter_app/lib/src/desktop_screen_capture_stub.dart +12 -0
  129. package/flutter_app/lib/src/diagnostics_logger.dart +119 -0
  130. package/flutter_app/lib/src/health_bridge.dart +136 -0
  131. package/flutter_app/lib/src/live_voice_capture.dart +85 -0
  132. package/flutter_app/lib/src/messaging_access_summary.dart +46 -0
  133. package/flutter_app/lib/src/network/app_http_client.dart +53 -0
  134. package/flutter_app/lib/src/network/app_http_client_factory.dart +6 -0
  135. package/flutter_app/lib/src/network/app_http_client_io.dart +138 -0
  136. package/flutter_app/lib/src/network/app_http_client_stub.dart +3 -0
  137. package/flutter_app/lib/src/network/app_http_client_web.dart +94 -0
  138. package/flutter_app/lib/src/oauth_launcher.dart +33 -0
  139. package/flutter_app/lib/src/oauth_launcher_io.dart +95 -0
  140. package/flutter_app/lib/src/oauth_launcher_stub.dart +33 -0
  141. package/flutter_app/lib/src/oauth_launcher_web.dart +107 -0
  142. package/flutter_app/lib/src/recording_bridge.dart +232 -0
  143. package/flutter_app/lib/src/recording_bridge_io.dart +1019 -0
  144. package/flutter_app/lib/src/recording_bridge_stub.dart +120 -0
  145. package/flutter_app/lib/src/recording_bridge_web.dart +689 -0
  146. package/flutter_app/lib/src/recording_payloads.dart +86 -0
  147. package/flutter_app/lib/src/theme/palette.dart +81 -0
  148. package/flutter_app/lib/src/web_app_update_monitor.dart +17 -0
  149. package/flutter_app/lib/src/web_app_update_monitor_stub.dart +24 -0
  150. package/flutter_app/lib/src/web_app_update_monitor_web.dart +123 -0
  151. package/flutter_app/lib/src/widget_bridge.dart +49 -0
  152. package/flutter_app/linux/CMakeLists.txt +128 -0
  153. package/flutter_app/linux/flutter/CMakeLists.txt +88 -0
  154. package/flutter_app/linux/flutter/generated_plugin_registrant.cc +47 -0
  155. package/flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
  156. package/flutter_app/linux/flutter/generated_plugins.cmake +32 -0
  157. package/flutter_app/linux/runner/CMakeLists.txt +26 -0
  158. package/flutter_app/linux/runner/main.cc +6 -0
  159. package/flutter_app/linux/runner/my_application.cc +144 -0
  160. package/flutter_app/linux/runner/my_application.h +18 -0
  161. package/flutter_app/linux/runner/resources/app_icon.png +0 -0
  162. package/flutter_app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
  163. package/flutter_app/macos/Flutter/Flutter-Release.xcconfig +2 -0
  164. package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +48 -0
  165. package/flutter_app/macos/Podfile +42 -0
  166. package/flutter_app/macos/Podfile.lock +87 -0
  167. package/flutter_app/macos/Runner/AppDelegate.swift +576 -0
  168. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  169. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  170. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  171. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  172. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  173. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  174. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  175. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  176. package/flutter_app/macos/Runner/Base.lproj/MainMenu.xib +342 -0
  177. package/flutter_app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  178. package/flutter_app/macos/Runner/Configs/Debug.xcconfig +2 -0
  179. package/flutter_app/macos/Runner/Configs/Release.xcconfig +2 -0
  180. package/flutter_app/macos/Runner/Configs/Warnings.xcconfig +13 -0
  181. package/flutter_app/macos/Runner/DebugProfile.entitlements +16 -0
  182. package/flutter_app/macos/Runner/Info.plist +36 -0
  183. package/flutter_app/macos/Runner/MainFlutterWindow.swift +19 -0
  184. package/flutter_app/macos/Runner/Release.entitlements +12 -0
  185. package/flutter_app/macos/Runner.xcodeproj/project.pbxproj +801 -0
  186. package/flutter_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  187. package/flutter_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
  188. package/flutter_app/macos/Runner.xcworkspace/contents.xcworkspacedata +10 -0
  189. package/flutter_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  190. package/flutter_app/macos/RunnerTests/RunnerTests.swift +12 -0
  191. package/flutter_app/patch_strings.py +12 -0
  192. package/flutter_app/pubspec.lock +1256 -0
  193. package/flutter_app/pubspec.yaml +59 -0
  194. package/flutter_app/third_party/desktop_audio_capture/LICENSE +21 -0
  195. package/flutter_app/third_party/desktop_audio_capture/README.md +262 -0
  196. package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +65 -0
  197. package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +153 -0
  198. package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +110 -0
  199. package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +461 -0
  200. package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +91 -0
  201. package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +106 -0
  202. package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +219 -0
  203. package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +336 -0
  204. package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +101 -0
  205. package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +692 -0
  206. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +35 -0
  207. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +36 -0
  208. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +32 -0
  209. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +32 -0
  210. package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +878 -0
  211. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +27 -0
  212. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +1172 -0
  213. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +655 -0
  214. package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +12 -0
  215. package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +30 -0
  216. package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +87 -0
  217. package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +105 -0
  218. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +80 -0
  219. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +31 -0
  220. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +12 -0
  221. package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +23 -0
  222. package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +25 -0
  223. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +1117 -0
  224. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +115 -0
  225. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +777 -0
  226. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +87 -0
  227. package/flutter_app/third_party/flutter_secure_storage_linux/linux/CMakeLists.txt +30 -0
  228. package/flutter_app/third_party/flutter_secure_storage_linux/linux/flutter_secure_storage_linux_plugin.cc +215 -0
  229. package/flutter_app/third_party/flutter_secure_storage_linux/linux/include/flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h +27 -0
  230. package/flutter_app/third_party/flutter_secure_storage_linux/pubspec.yaml +20 -0
  231. package/flutter_app/tool/generate_desktop_branding.py +219 -0
  232. package/flutter_app/web/favicon.png +0 -0
  233. package/flutter_app/web/favicon.svg +12 -0
  234. package/flutter_app/web/icons/Icon-192.png +0 -0
  235. package/flutter_app/web/icons/Icon-512.png +0 -0
  236. package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
  237. package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
  238. package/flutter_app/web/index.html +39 -0
  239. package/flutter_app/web/manifest.json +35 -0
  240. package/flutter_app/windows/CMakeLists.txt +108 -0
  241. package/flutter_app/windows/flutter/CMakeLists.txt +109 -0
  242. package/flutter_app/windows/flutter/generated_plugin_registrant.cc +50 -0
  243. package/flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
  244. package/flutter_app/windows/flutter/generated_plugins.cmake +36 -0
  245. package/flutter_app/windows/runner/CMakeLists.txt +41 -0
  246. package/flutter_app/windows/runner/Runner.rc +121 -0
  247. package/flutter_app/windows/runner/flutter_window.cpp +533 -0
  248. package/flutter_app/windows/runner/flutter_window.h +37 -0
  249. package/flutter_app/windows/runner/main.cpp +53 -0
  250. package/flutter_app/windows/runner/resource.h +16 -0
  251. package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
  252. package/flutter_app/windows/runner/runner.exe.manifest +14 -0
  253. package/flutter_app/windows/runner/utils.cpp +65 -0
  254. package/flutter_app/windows/runner/utils.h +19 -0
  255. package/flutter_app/windows/runner/win32_window.cpp +299 -0
  256. package/flutter_app/windows/runner/win32_window.h +102 -0
  257. package/lib/install_helpers.js +31 -0
  258. package/lib/manager.js +579 -122
  259. package/package.json +10 -3
  260. package/runtime/paths.js +137 -0
  261. package/server/config/analytics.js +30 -0
  262. package/server/db/database.js +296 -22
  263. package/server/guest-agent.android.package.json +13 -0
  264. package/server/guest-agent.browser.package.json +14 -0
  265. package/server/guest_agent.js +98 -52
  266. package/server/http/middleware.js +5 -2
  267. package/server/http/routes.js +3 -0
  268. package/server/http/static.js +41 -1
  269. package/server/index.js +15 -16
  270. package/server/public/.last_build_id +1 -1
  271. package/server/public/assets/AssetManifest.bin +1 -1
  272. package/server/public/assets/AssetManifest.bin.json +1 -1
  273. package/server/public/assets/AssetManifest.json +1 -1
  274. package/server/public/assets/NOTICES +644 -155
  275. package/server/public/assets/assets/branding/onboarding_intro.mp4 +0 -0
  276. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  277. package/server/public/assets/packages/mixpanel_flutter/assets/mixpanel.js +3 -0
  278. package/server/public/canvaskit/wimp.wasm +0 -0
  279. package/server/public/flutter_bootstrap.js +2 -2
  280. package/server/public/main.dart.js +96067 -88139
  281. package/server/routes/account.js +26 -1
  282. package/server/routes/agents.js +6 -2
  283. package/server/routes/android.js +22 -6
  284. package/server/routes/auth.js +25 -5
  285. package/server/routes/browser.js +47 -13
  286. package/server/routes/integrations.js +22 -1
  287. package/server/routes/memory.js +168 -6
  288. package/server/routes/runtime.js +14 -0
  289. package/server/routes/settings.js +102 -24
  290. package/server/routes/skills.js +12 -0
  291. package/server/routes/social_video.js +66 -0
  292. package/server/routes/tasks.js +22 -2
  293. package/server/routes/triggers.js +44 -35
  294. package/server/routes/wearable.js +67 -0
  295. package/server/routes/widgets.js +4 -4
  296. package/server/services/ai/capabilityHealth.js +23 -51
  297. package/server/services/ai/compaction.js +1 -1
  298. package/server/services/ai/deliverables/artifact_helpers.js +190 -0
  299. package/server/services/ai/deliverables/contracts.js +113 -0
  300. package/server/services/ai/deliverables/index.js +20 -0
  301. package/server/services/ai/deliverables/selector.js +94 -0
  302. package/server/services/ai/deliverables/validator.js +63 -0
  303. package/server/services/ai/deliverables/workflows.js +207 -0
  304. package/server/services/ai/engine.js +363 -27
  305. package/server/services/ai/hooks.js +127 -0
  306. package/server/services/ai/integrated_tools/index.js +98 -0
  307. package/server/services/ai/integrated_tools/remotion.js +373 -0
  308. package/server/services/ai/integrated_tools/shared.js +204 -0
  309. package/server/services/ai/integrated_tools/slidev.js +207 -0
  310. package/server/services/ai/loopPolicy.js +146 -0
  311. package/server/services/ai/models.js +31 -4
  312. package/server/services/ai/providers/claudeCode.js +49 -0
  313. package/server/services/ai/providers/openai.js +2 -1
  314. package/server/services/ai/providers/openaiCodex.js +422 -15
  315. package/server/services/ai/recordingInsights.js +11 -13
  316. package/server/services/ai/runEvents.js +100 -0
  317. package/server/services/ai/settings.js +12 -2
  318. package/server/services/ai/systemPrompt.js +15 -1
  319. package/server/services/ai/taskAnalysis.js +2 -0
  320. package/server/services/ai/toolResult.js +20 -0
  321. package/server/services/ai/toolRunner.js +46 -6
  322. package/server/services/ai/toolSelector.js +54 -1
  323. package/server/services/ai/tools.js +210 -116
  324. package/server/services/android/android_bootstrap_worker.js +63 -0
  325. package/server/services/android/controller.js +442 -1760
  326. package/server/services/bootstrap_helpers.js +0 -34
  327. package/server/services/browser/controller.js +279 -49
  328. package/server/services/cli/executor.js +40 -1
  329. package/server/services/desktop/screenRecorder.js +65 -9
  330. package/server/services/integrations/figma/provider.js +1 -0
  331. package/server/services/integrations/github/provider.js +3 -3
  332. package/server/services/integrations/google/provider.js +1 -0
  333. package/server/services/integrations/manager.js +25 -5
  334. package/server/services/integrations/microsoft/provider.js +1 -0
  335. package/server/services/integrations/oauth_provider.js +15 -5
  336. package/server/services/integrations/provider_config_store.js +22 -13
  337. package/server/services/integrations/registry.js +2 -4
  338. package/server/services/integrations/spotify/provider.js +1 -0
  339. package/server/services/integrations/trello/provider.js +842 -0
  340. package/server/services/manager.js +88 -155
  341. package/server/services/mcp/client.js +120 -23
  342. package/server/services/memory/llm_transfer.js +218 -0
  343. package/server/services/memory/manager.js +260 -33
  344. package/server/services/messaging/access_policy.js +10 -0
  345. package/server/services/messaging/automation.js +1 -1
  346. package/server/services/messaging/manager.js +64 -1
  347. package/server/services/messaging/meshtastic.js +277 -0
  348. package/server/services/messaging/meshtastic_env.js +40 -0
  349. package/server/services/messaging/meshtastic_protocol.js +530 -0
  350. package/server/services/messaging/meshtastic_tcp_transport.js +25 -0
  351. package/server/services/runtime/backends/local-vm.js +221 -158
  352. package/server/services/runtime/docker-vm-manager.js +392 -0
  353. package/server/services/runtime/guest_bootstrap.js +654 -0
  354. package/server/services/runtime/manager.js +85 -29
  355. package/server/services/runtime/settings.js +22 -31
  356. package/server/services/runtime/validation.js +16 -31
  357. package/server/services/social_video/adapters/base.js +26 -0
  358. package/server/services/social_video/adapters/index.js +27 -0
  359. package/server/services/social_video/adapters/instagram.js +17 -0
  360. package/server/services/social_video/adapters/tiktok.js +17 -0
  361. package/server/services/social_video/adapters/x.js +17 -0
  362. package/server/services/social_video/adapters/youtube.js +17 -0
  363. package/server/services/social_video/captions.js +187 -0
  364. package/server/services/social_video/frame.js +42 -0
  365. package/server/services/social_video/index.js +7 -0
  366. package/server/services/social_video/metadata.js +63 -0
  367. package/server/services/social_video/result.js +63 -0
  368. package/server/services/social_video/service.js +720 -0
  369. package/server/services/social_video/url.js +83 -0
  370. package/server/services/tasks/integration_runtime.js +1 -1
  371. package/server/services/tasks/runtime.js +1 -1
  372. package/server/services/tasks/task_repository.js +3 -6
  373. package/server/services/voice/openaiSpeech.js +6 -1
  374. package/server/services/voice/providers.js +142 -14
  375. package/server/services/voice/runtime.js +8 -8
  376. package/server/services/voice/runtimeManager.js +156 -19
  377. package/server/services/voice/turnRunner.js +29 -9
  378. package/server/services/wearable/firmware_manifest.js +353 -0
  379. package/server/services/wearable/gateway.js +350 -0
  380. package/server/services/wearable/protocol.js +45 -0
  381. package/server/services/wearable/service.js +240 -0
  382. package/server/services/websocket.js +3 -1
  383. package/server/services/widgets/focus_widget.js +137 -0
  384. package/server/services/widgets/service.js +133 -2
  385. package/server/services/workspace/manager.js +301 -0
  386. package/server/utils/deployment.js +16 -9
  387. package/server/services/integrations/home_assistant/provider.js +0 -630
  388. package/server/services/messaging/access_policy.test.js +0 -228
  389. package/server/services/runtime/backends/host.js +0 -37
  390. package/server/services/runtime/qemu.js +0 -391
@@ -0,0 +1,33 @@
1
+ part of 'main.dart';
2
+
3
+ abstract class AppSpacing {
4
+ static const double xs = 8.0;
5
+ static const double sm = 12.0;
6
+ static const double md = 16.0;
7
+ static const double lg = 24.0;
8
+ static const double xl = 32.0;
9
+ }
10
+
11
+ abstract class AppBreakpoints {
12
+ static const double mobile = 480.0;
13
+ static const double tablet = 960.0;
14
+ }
15
+
16
+ /// Canonical border-radius scale. Use these instead of raw `circular()` values.
17
+ ///
18
+ /// tag → chips, code blocks, inline badges
19
+ /// card → secondary cards, list items, dialogs
20
+ /// input → buttons, text fields (matches theme InputDecorationTheme)
21
+ /// panel → major glass surfaces, primary cards (matches theme CardTheme)
22
+ /// pill → avatars, full-pill badges, status indicators
23
+ abstract class AppRadius {
24
+ static const double tag = 8.0;
25
+ static const double card = 14.0;
26
+ static const double input = 18.0;
27
+ static const double panel = 28.0;
28
+ static const double pill = 999.0;
29
+ }
30
+
31
+ /// Deep dark color used for QR code modules rendered on a white background.
32
+ /// Matches the dark theme's primary background hue for brand consistency.
33
+ const Color _qrDarkColor = Color(0xFF04111D);
@@ -0,0 +1,276 @@
1
+ part of 'main.dart';
2
+
3
+ const NeoAgentPalette _darkPalette = darkPalette;
4
+ const NeoAgentPalette _lightPalette = lightPalette;
5
+
6
+ NeoAgentPalette get _palette =>
7
+ WidgetsBinding.instance.platformDispatcher.platformBrightness ==
8
+ Brightness.light
9
+ ? _lightPalette
10
+ : _darkPalette;
11
+
12
+ Color get _bgPrimary => _palette.bgPrimary;
13
+ Color get _bgSecondary => _palette.bgSecondary;
14
+ Color get _bgTertiary => _palette.bgTertiary;
15
+ Color get _bgCard => _palette.bgCard;
16
+ Color get _textPrimary => _palette.textPrimary;
17
+ Color get _textSecondary => _palette.textSecondary;
18
+ Color get _textMuted => _palette.textMuted;
19
+ const Color _brandAccent = Color(0xFF8F6D3E);
20
+ const Color _brandAccentAlt = Color(0xFF2F7D6E);
21
+ Color get _accent => _palette.accent;
22
+ Color get _accentHover => _palette.accentHover;
23
+ Color get _accentAlt => _palette.accentAlt;
24
+ Color get _accentMuted => _palette.accentMuted;
25
+ Color get _border => _palette.border;
26
+ Color get _borderLight => _palette.borderLight;
27
+ Color get _success => _palette.success;
28
+ Color get _warning => _palette.warning;
29
+ Color get _danger => _palette.danger;
30
+ Color get _info => _palette.info;
31
+
32
+ LinearGradient get _appBackgroundGradient => LinearGradient(
33
+ colors: <Color>[
34
+ _bgPrimary,
35
+ Color.lerp(_bgSecondary, _accentAlt, 0.08)!.withValues(alpha: 0.98),
36
+ Color.lerp(_bgPrimary, _accent, 0.05)!,
37
+ ],
38
+ stops: const <double>[0, 0.52, 1],
39
+ begin: const Alignment(-0.95, -1),
40
+ end: const Alignment(1, 0.92),
41
+ );
42
+
43
+ LinearGradient get _panelGradient => LinearGradient(
44
+ colors: <Color>[
45
+ Colors.white.withValues(alpha: 0.08),
46
+ _bgCard.withValues(alpha: 0.9),
47
+ _bgSecondary.withValues(alpha: 0.82),
48
+ ],
49
+ stops: const <double>[0, 0.18, 1],
50
+ begin: const Alignment(-0.85, -1),
51
+ end: const Alignment(1, 1),
52
+ );
53
+
54
+ List<BoxShadow> get _softPanelShadow => <BoxShadow>[
55
+ BoxShadow(
56
+ color: Colors.black.withValues(alpha: 0.22),
57
+ blurRadius: 52,
58
+ offset: const Offset(0, 22),
59
+ ),
60
+ BoxShadow(
61
+ color: _accent.withValues(alpha: 0.08),
62
+ blurRadius: 30,
63
+ offset: const Offset(0, 8),
64
+ ),
65
+ ];
66
+
67
+ Color get _glassFill =>
68
+ _bgCard.withValues(alpha: _palette == _darkPalette ? 0.78 : 0.88);
69
+ Color get _glassOverlay =>
70
+ Colors.white.withValues(alpha: _palette == _darkPalette ? 0.04 : 0.12);
71
+ Color get _glassBorder =>
72
+ Colors.white.withValues(alpha: _palette == _darkPalette ? 0.12 : 0.26);
73
+ Color get _glassHighlight =>
74
+ Colors.white.withValues(alpha: _palette == _darkPalette ? 0.1 : 0.18);
75
+
76
+ LinearGradient get _liquidMetalGradient => LinearGradient(
77
+ colors: <Color>[
78
+ _glassOverlay,
79
+ Colors.white.withValues(alpha: 0.02),
80
+ _accentMuted.withValues(alpha: 0.16),
81
+ ],
82
+ stops: const <double>[0, 0.44, 1],
83
+ begin: const Alignment(-1, -1),
84
+ end: const Alignment(1, 1),
85
+ );
86
+
87
+ TextStyle _displayTitleStyle([double size = 28]) => TextStyle(
88
+ fontSize: size,
89
+ fontWeight: FontWeight.w700,
90
+ height: 1.08,
91
+ letterSpacing: -0.8,
92
+ color: _textPrimary,
93
+ );
94
+
95
+ /// Heavy hero text — use for prominent numeric/stat displays, empty-state
96
+ /// headlines, and splash copy where w700 reads too light.
97
+ TextStyle _heroTitleStyle([double size = 24]) => TextStyle(
98
+ fontSize: size,
99
+ fontWeight: FontWeight.w800,
100
+ height: 1.1,
101
+ letterSpacing: -1.0,
102
+ color: _textPrimary,
103
+ );
104
+
105
+ TextStyle _sectionEyebrowStyle() => TextStyle(
106
+ fontSize: 12,
107
+ fontWeight: FontWeight.w700,
108
+ letterSpacing: 1.0,
109
+ color: _accentHover,
110
+ );
111
+
112
+ ThemeData _buildNeoAgentTheme(NeoAgentPalette palette, Brightness brightness) {
113
+ final base = ThemeData(
114
+ useMaterial3: true,
115
+ colorScheme: ColorScheme.fromSeed(
116
+ seedColor: palette.accent,
117
+ brightness: brightness,
118
+ ),
119
+ );
120
+
121
+ return base.copyWith(
122
+ focusColor: palette.accent.withValues(alpha: 0.2),
123
+ scaffoldBackgroundColor: palette.bgPrimary,
124
+ colorScheme: base.colorScheme.copyWith(
125
+ primary: palette.accent,
126
+ secondary: palette.accentHover,
127
+ surface: palette.bgCard,
128
+ onSurface: palette.textPrimary,
129
+ error: palette.danger,
130
+ ),
131
+ textTheme: base.textTheme.apply(
132
+ bodyColor: palette.textPrimary,
133
+ displayColor: palette.textPrimary,
134
+ ),
135
+ cardTheme: CardThemeData(
136
+ color: palette.bgCard.withValues(
137
+ alpha: brightness == Brightness.dark ? 0.86 : 0.96,
138
+ ),
139
+ shadowColor: Colors.black.withValues(
140
+ alpha: brightness == Brightness.dark ? 0.24 : 0.12,
141
+ ),
142
+ surfaceTintColor: Colors.transparent,
143
+ elevation: brightness == Brightness.dark ? 8 : 3,
144
+ margin: EdgeInsets.zero,
145
+ shape: RoundedRectangleBorder(
146
+ borderRadius: BorderRadius.circular(28),
147
+ side: BorderSide(
148
+ color: Colors.white.withValues(
149
+ alpha: brightness == Brightness.dark ? 0.08 : 0.22,
150
+ ),
151
+ ),
152
+ ),
153
+ ),
154
+ inputDecorationTheme: InputDecorationTheme(
155
+ filled: true,
156
+ fillColor: palette.bgSecondary.withValues(
157
+ alpha: brightness == Brightness.dark ? 0.82 : 0.84,
158
+ ),
159
+ border: OutlineInputBorder(
160
+ borderRadius: BorderRadius.circular(18),
161
+ borderSide: BorderSide(color: palette.borderLight),
162
+ ),
163
+ enabledBorder: OutlineInputBorder(
164
+ borderRadius: BorderRadius.circular(18),
165
+ borderSide: BorderSide(color: palette.borderLight),
166
+ ),
167
+ focusedBorder: OutlineInputBorder(
168
+ borderRadius: BorderRadius.circular(18),
169
+ borderSide: BorderSide(color: palette.accentHover, width: 1.4),
170
+ ),
171
+ contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
172
+ labelStyle: TextStyle(
173
+ color: palette.textSecondary,
174
+ fontSize: 12,
175
+ fontWeight: FontWeight.w600,
176
+ letterSpacing: 0.15,
177
+ ),
178
+ hintStyle: TextStyle(color: palette.textMuted),
179
+ ),
180
+ dividerColor: palette.border,
181
+ iconTheme: IconThemeData(color: palette.textSecondary),
182
+ filledButtonTheme: FilledButtonThemeData(
183
+ style: FilledButton.styleFrom(
184
+ backgroundColor: palette.accent,
185
+ foregroundColor: brightness == Brightness.dark
186
+ ? palette.bgPrimary
187
+ : Colors.white,
188
+ disabledBackgroundColor: palette.bgTertiary,
189
+ disabledForegroundColor: palette.textMuted,
190
+ shadowColor: palette.accent.withValues(alpha: 0.3),
191
+ elevation: 0,
192
+ padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
193
+ shape: RoundedRectangleBorder(
194
+ borderRadius: BorderRadius.circular(18),
195
+ side: BorderSide(
196
+ color: Colors.white.withValues(
197
+ alpha: brightness == Brightness.dark ? 0.14 : 0.26,
198
+ ),
199
+ ),
200
+ ),
201
+ textStyle: const TextStyle(
202
+ fontSize: 15,
203
+ fontWeight: FontWeight.w700,
204
+ letterSpacing: -0.1,
205
+ ),
206
+ ),
207
+ ),
208
+ outlinedButtonTheme: OutlinedButtonThemeData(
209
+ style: OutlinedButton.styleFrom(
210
+ foregroundColor: palette.textPrimary,
211
+ side: BorderSide(
212
+ color: Colors.white.withValues(
213
+ alpha: brightness == Brightness.dark ? 0.12 : 0.26,
214
+ ),
215
+ ),
216
+ backgroundColor: palette.bgCard.withValues(
217
+ alpha: brightness == Brightness.dark ? 0.2 : 0.5,
218
+ ),
219
+ padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
220
+ shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
221
+ textStyle: const TextStyle(fontSize: 15, fontWeight: FontWeight.w700),
222
+ ),
223
+ ),
224
+ pageTransitionsTheme: const PageTransitionsTheme(
225
+ builders: <TargetPlatform, PageTransitionsBuilder>{
226
+ TargetPlatform.android: FadeForwardsPageTransitionsBuilder(),
227
+ TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
228
+ TargetPlatform.macOS: CupertinoPageTransitionsBuilder(),
229
+ TargetPlatform.windows: FadeForwardsPageTransitionsBuilder(),
230
+ TargetPlatform.linux: FadeForwardsPageTransitionsBuilder(),
231
+ },
232
+ ),
233
+ textButtonTheme: TextButtonThemeData(
234
+ style: TextButton.styleFrom(
235
+ foregroundColor: palette.accentHover,
236
+ textStyle: const TextStyle(
237
+ fontSize: 14,
238
+ fontWeight: FontWeight.w700,
239
+ letterSpacing: -0.05,
240
+ ),
241
+ ),
242
+ ),
243
+ elevatedButtonTheme: ElevatedButtonThemeData(
244
+ style: ElevatedButton.styleFrom(
245
+ padding: const EdgeInsets.symmetric(
246
+ horizontal: AppSpacing.md,
247
+ vertical: AppSpacing.sm,
248
+ ),
249
+ ),
250
+ ),
251
+ appBarTheme: AppBarTheme(
252
+ backgroundColor: Colors.transparent,
253
+ surfaceTintColor: Colors.transparent,
254
+ foregroundColor: palette.textPrimary,
255
+ elevation: 0,
256
+ titleTextStyle: TextStyle(
257
+ color: palette.textPrimary,
258
+ fontSize: 18,
259
+ fontWeight: FontWeight.w600,
260
+ letterSpacing: -0.3,
261
+ ),
262
+ ),
263
+ dialogTheme: DialogThemeData(
264
+ backgroundColor: palette.bgCard.withValues(alpha: 0.96),
265
+ surfaceTintColor: Colors.transparent,
266
+ shape: RoundedRectangleBorder(
267
+ borderRadius: BorderRadius.circular(24),
268
+ side: BorderSide(color: palette.borderLight),
269
+ ),
270
+ ),
271
+ snackBarTheme: SnackBarThemeData(
272
+ backgroundColor: palette.bgCard,
273
+ contentTextStyle: TextStyle(color: palette.textPrimary),
274
+ ),
275
+ );
276
+ }
@@ -0,0 +1,388 @@
1
+ part of 'main.dart';
2
+
3
+ enum _ToolsPageTab { integrations, mcp, skills }
4
+
5
+ enum _RunsPageTab { runs, logs }
6
+
7
+ enum _SettingsWorkspaceSection { app, account, security }
8
+
9
+ class ToolsPanel extends StatefulWidget {
10
+ const ToolsPanel({super.key, required this.controller});
11
+
12
+ final NeoAgentController controller;
13
+
14
+ @override
15
+ State<ToolsPanel> createState() => _ToolsPanelState();
16
+ }
17
+
18
+ class _ToolsPanelState extends State<ToolsPanel>
19
+ with SingleTickerProviderStateMixin {
20
+ late final TabController _tabController;
21
+
22
+ @override
23
+ void initState() {
24
+ super.initState();
25
+ _tabController = TabController(
26
+ length: _ToolsPageTab.values.length,
27
+ vsync: this,
28
+ initialIndex: _tabForSection(widget.controller.selectedSection).index,
29
+ );
30
+ }
31
+
32
+ @override
33
+ void didUpdateWidget(covariant ToolsPanel oldWidget) {
34
+ super.didUpdateWidget(oldWidget);
35
+ final selectedSection = widget.controller.selectedSection;
36
+ if (selectedSection != oldWidget.controller.selectedSection &&
37
+ (selectedSection == AppSection.integrations ||
38
+ selectedSection == AppSection.mcp ||
39
+ selectedSection == AppSection.skills)) {
40
+ final targetIndex = _tabForSection(selectedSection).index;
41
+ if (_tabController.index != targetIndex) {
42
+ _tabController.index = targetIndex;
43
+ }
44
+ }
45
+ }
46
+
47
+ @override
48
+ void dispose() {
49
+ _tabController.dispose();
50
+ super.dispose();
51
+ }
52
+
53
+ _ToolsPageTab _tabForSection(AppSection section) {
54
+ switch (section) {
55
+ case AppSection.mcp:
56
+ return _ToolsPageTab.mcp;
57
+ case AppSection.skills:
58
+ return _ToolsPageTab.skills;
59
+ default:
60
+ return _ToolsPageTab.integrations;
61
+ }
62
+ }
63
+
64
+ @override
65
+ Widget build(BuildContext context) {
66
+ final controller = widget.controller;
67
+ final visibleIntegrations = controller.officialIntegrations
68
+ .where(
69
+ (item) =>
70
+ item.env.configured ||
71
+ item.env.setupMode == 'user' ||
72
+ item.isConnected,
73
+ )
74
+ .length;
75
+ return Padding(
76
+ padding: _pagePadding(context),
77
+ child: Column(
78
+ children: <Widget>[
79
+ const _PageTitle(
80
+ title: 'Tools',
81
+ subtitle:
82
+ 'Manage official integrations, MCP servers, and reusable skills in one place.',
83
+ ),
84
+ const SizedBox(height: 12),
85
+ Container(
86
+ decoration: BoxDecoration(
87
+ color: _bgSecondary,
88
+ borderRadius: BorderRadius.circular(14),
89
+ border: Border.all(color: _border),
90
+ ),
91
+ child: TabBar(
92
+ controller: _tabController,
93
+ dividerColor: _border,
94
+ indicatorSize: TabBarIndicatorSize.tab,
95
+ labelStyle: const TextStyle(fontWeight: FontWeight.w700),
96
+ tabs: <Widget>[
97
+ Tab(text: 'Integrations ($visibleIntegrations)'),
98
+ Tab(text: 'MCP (${controller.mcpServers.length})'),
99
+ Tab(text: 'Skills (${controller.skills.length})'),
100
+ ],
101
+ ),
102
+ ),
103
+ const SizedBox(height: 12),
104
+ Expanded(
105
+ child: TabBarView(
106
+ controller: _tabController,
107
+ children: <Widget>[
108
+ IntegrationsPanel(controller: controller, embedded: true),
109
+ McpPanel(controller: controller, embedded: true),
110
+ SkillsPanel(controller: controller, embedded: true),
111
+ ],
112
+ ),
113
+ ),
114
+ ],
115
+ ),
116
+ );
117
+ }
118
+ }
119
+
120
+ class RunsAndLogsPanel extends StatefulWidget {
121
+ const RunsAndLogsPanel({super.key, required this.controller});
122
+
123
+ final NeoAgentController controller;
124
+
125
+ @override
126
+ State<RunsAndLogsPanel> createState() => _RunsAndLogsPanelState();
127
+ }
128
+
129
+ class _RunsAndLogsPanelState extends State<RunsAndLogsPanel>
130
+ with SingleTickerProviderStateMixin {
131
+ late final TabController _tabController;
132
+
133
+ @override
134
+ void initState() {
135
+ super.initState();
136
+ _tabController = TabController(
137
+ length: _RunsPageTab.values.length,
138
+ vsync: this,
139
+ initialIndex: _tabForSection(widget.controller.selectedSection).index,
140
+ );
141
+ }
142
+
143
+ @override
144
+ void didUpdateWidget(covariant RunsAndLogsPanel oldWidget) {
145
+ super.didUpdateWidget(oldWidget);
146
+ final selectedSection = widget.controller.selectedSection;
147
+ if (selectedSection != oldWidget.controller.selectedSection &&
148
+ (selectedSection == AppSection.runs ||
149
+ selectedSection == AppSection.logs)) {
150
+ final targetIndex = _tabForSection(selectedSection).index;
151
+ if (_tabController.index != targetIndex) {
152
+ _tabController.index = targetIndex;
153
+ }
154
+ }
155
+ }
156
+
157
+ @override
158
+ void dispose() {
159
+ _tabController.dispose();
160
+ super.dispose();
161
+ }
162
+
163
+ _RunsPageTab _tabForSection(AppSection section) {
164
+ switch (section) {
165
+ case AppSection.logs:
166
+ return _RunsPageTab.logs;
167
+ default:
168
+ return _RunsPageTab.runs;
169
+ }
170
+ }
171
+
172
+ @override
173
+ Widget build(BuildContext context) {
174
+ final controller = widget.controller;
175
+ return Padding(
176
+ padding: _pagePadding(context),
177
+ child: Column(
178
+ children: <Widget>[
179
+ const _PageTitle(
180
+ title: 'Runs & Logs',
181
+ subtitle:
182
+ 'Inspect execution history, failures, tool traces, and diagnostics from one workspace.',
183
+ ),
184
+ const SizedBox(height: 12),
185
+ Container(
186
+ decoration: BoxDecoration(
187
+ color: _bgSecondary,
188
+ borderRadius: BorderRadius.circular(14),
189
+ border: Border.all(color: _border),
190
+ ),
191
+ child: TabBar(
192
+ controller: _tabController,
193
+ dividerColor: _border,
194
+ indicatorSize: TabBarIndicatorSize.tab,
195
+ labelStyle: const TextStyle(fontWeight: FontWeight.w700),
196
+ tabs: <Widget>[
197
+ Tab(text: 'Runs (${controller.recentRuns.length})'),
198
+ Tab(text: 'Logs (${controller.logs.length})'),
199
+ ],
200
+ ),
201
+ ),
202
+ const SizedBox(height: 12),
203
+ Expanded(
204
+ child: TabBarView(
205
+ controller: _tabController,
206
+ children: <Widget>[
207
+ RunsPanel(controller: controller, embedded: true),
208
+ LogsPanel(controller: controller, embedded: true),
209
+ ],
210
+ ),
211
+ ),
212
+ ],
213
+ ),
214
+ );
215
+ }
216
+ }
217
+
218
+ class SettingsWorkspacePanel extends StatefulWidget {
219
+ const SettingsWorkspacePanel({super.key, required this.controller});
220
+
221
+ final NeoAgentController controller;
222
+
223
+ @override
224
+ State<SettingsWorkspacePanel> createState() => _SettingsWorkspacePanelState();
225
+ }
226
+
227
+ class _SettingsWorkspacePanelState extends State<SettingsWorkspacePanel> {
228
+ late _SettingsWorkspaceSection _selectedSection;
229
+
230
+ @override
231
+ void initState() {
232
+ super.initState();
233
+ _selectedSection =
234
+ widget.controller.selectedSection == AppSection.accountSettings
235
+ ? _SettingsWorkspaceSection.account
236
+ : _SettingsWorkspaceSection.app;
237
+ }
238
+
239
+ @override
240
+ void didUpdateWidget(covariant SettingsWorkspacePanel oldWidget) {
241
+ super.didUpdateWidget(oldWidget);
242
+ if (widget.controller.selectedSection == AppSection.settings &&
243
+ _selectedSection != _SettingsWorkspaceSection.app) {
244
+ _selectedSection = _SettingsWorkspaceSection.app;
245
+ }
246
+ if (widget.controller.selectedSection == AppSection.accountSettings &&
247
+ _selectedSection == _SettingsWorkspaceSection.app) {
248
+ _selectedSection = _SettingsWorkspaceSection.account;
249
+ }
250
+ }
251
+
252
+ @override
253
+ Widget build(BuildContext context) {
254
+ final compact = MediaQuery.sizeOf(context).width < AppBreakpoints.tablet;
255
+ return Padding(
256
+ padding: _pagePadding(context),
257
+ child: Column(
258
+ children: <Widget>[
259
+ const _PageTitle(
260
+ title: 'Settings',
261
+ subtitle:
262
+ 'Workspace configuration and account security in one place.',
263
+ ),
264
+ const SizedBox(height: 12),
265
+ Expanded(
266
+ child: Card(
267
+ child: Padding(
268
+ padding: const EdgeInsets.all(20),
269
+ child: compact
270
+ ? Column(
271
+ crossAxisAlignment: CrossAxisAlignment.start,
272
+ children: <Widget>[
273
+ _SettingsWorkspaceNav(
274
+ selected: _selectedSection,
275
+ compact: true,
276
+ onSelected: _selectSection,
277
+ ),
278
+ const SizedBox(height: 16),
279
+ Expanded(child: _buildContent()),
280
+ ],
281
+ )
282
+ : Row(
283
+ crossAxisAlignment: CrossAxisAlignment.start,
284
+ children: <Widget>[
285
+ SizedBox(
286
+ width: 220,
287
+ child: _SettingsWorkspaceNav(
288
+ selected: _selectedSection,
289
+ compact: false,
290
+ onSelected: _selectSection,
291
+ ),
292
+ ),
293
+ const SizedBox(width: 24),
294
+ Expanded(child: _buildContent()),
295
+ ],
296
+ ),
297
+ ),
298
+ ),
299
+ ),
300
+ ],
301
+ ),
302
+ );
303
+ }
304
+
305
+ void _selectSection(_SettingsWorkspaceSection section) {
306
+ setState(() => _selectedSection = section);
307
+ if (section == _SettingsWorkspaceSection.app) {
308
+ widget.controller.setSelectedSection(AppSection.settings);
309
+ return;
310
+ }
311
+ widget.controller.setSelectedSection(AppSection.accountSettings);
312
+ }
313
+
314
+ Widget _buildContent() {
315
+ switch (_selectedSection) {
316
+ case _SettingsWorkspaceSection.app:
317
+ return SettingsPanel(controller: widget.controller, embedded: true);
318
+ case _SettingsWorkspaceSection.account:
319
+ return AccountSettingsPanel(
320
+ controller: widget.controller,
321
+ embedded: true,
322
+ initialTab: AccountSettingsTab.account,
323
+ );
324
+ case _SettingsWorkspaceSection.security:
325
+ return AccountSettingsPanel(
326
+ controller: widget.controller,
327
+ embedded: true,
328
+ initialTab: AccountSettingsTab.security,
329
+ );
330
+ }
331
+ }
332
+ }
333
+
334
+ class _SettingsWorkspaceNav extends StatelessWidget {
335
+ const _SettingsWorkspaceNav({
336
+ required this.selected,
337
+ required this.compact,
338
+ required this.onSelected,
339
+ });
340
+
341
+ final _SettingsWorkspaceSection selected;
342
+ final bool compact;
343
+ final ValueChanged<_SettingsWorkspaceSection> onSelected;
344
+
345
+ @override
346
+ Widget build(BuildContext context) {
347
+ final items = <Widget>[
348
+ _navButton(
349
+ section: _SettingsWorkspaceSection.app,
350
+ icon: Icons.tune,
351
+ label: 'App Settings',
352
+ ),
353
+ _navButton(
354
+ section: _SettingsWorkspaceSection.account,
355
+ icon: Icons.person_outline,
356
+ label: 'Account',
357
+ ),
358
+ _navButton(
359
+ section: _SettingsWorkspaceSection.security,
360
+ icon: Icons.security_outlined,
361
+ label: 'Security',
362
+ ),
363
+ ];
364
+ return compact
365
+ ? Wrap(spacing: 8, runSpacing: 8, children: items)
366
+ : Column(
367
+ crossAxisAlignment: CrossAxisAlignment.stretch,
368
+ children: items,
369
+ );
370
+ }
371
+
372
+ Widget _navButton({
373
+ required _SettingsWorkspaceSection section,
374
+ required IconData icon,
375
+ required String label,
376
+ }) {
377
+ final button = _SidebarButton(
378
+ label: label,
379
+ icon: icon,
380
+ active: selected == section,
381
+ onTap: () => onSelected(section),
382
+ );
383
+ if (compact) {
384
+ return button;
385
+ }
386
+ return Padding(padding: const EdgeInsets.only(bottom: 8), child: button);
387
+ }
388
+ }