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.
Files changed (406) hide show
  1. package/.env.example +63 -5
  2. package/README.md +16 -5
  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 +89 -87
  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 -60
  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 +465 -43
  259. package/package.json +11 -3
  260. package/runtime/paths.js +137 -0
  261. package/server/config/analytics.js +30 -0
  262. package/server/db/database.js +363 -21
  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 +55 -2
  267. package/server/http/routes.js +6 -1
  268. package/server/http/static.js +41 -1
  269. package/server/index.js +16 -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 +679 -129
  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 +95866 -87333
  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 +119 -9
  287. package/server/routes/memory.js +179 -8
  288. package/server/routes/runtime.js +14 -0
  289. package/server/routes/screenHistory.js +46 -0
  290. package/server/routes/settings.js +102 -24
  291. package/server/routes/skills.js +12 -0
  292. package/server/routes/social_video.js +66 -0
  293. package/server/routes/tasks.js +22 -2
  294. package/server/routes/triggers.js +90 -0
  295. package/server/routes/wearable.js +67 -0
  296. package/server/routes/widgets.js +4 -4
  297. package/server/services/ai/capabilityHealth.js +23 -51
  298. package/server/services/ai/compaction.js +1 -1
  299. package/server/services/ai/deliverables/artifact_helpers.js +190 -0
  300. package/server/services/ai/deliverables/contracts.js +113 -0
  301. package/server/services/ai/deliverables/index.js +20 -0
  302. package/server/services/ai/deliverables/selector.js +94 -0
  303. package/server/services/ai/deliverables/validator.js +63 -0
  304. package/server/services/ai/deliverables/workflows.js +207 -0
  305. package/server/services/ai/engine.js +372 -27
  306. package/server/services/ai/hooks.js +127 -0
  307. package/server/services/ai/integrated_tools/index.js +98 -0
  308. package/server/services/ai/integrated_tools/remotion.js +373 -0
  309. package/server/services/ai/integrated_tools/shared.js +204 -0
  310. package/server/services/ai/integrated_tools/slidev.js +207 -0
  311. package/server/services/ai/loopPolicy.js +146 -0
  312. package/server/services/ai/models.js +36 -0
  313. package/server/services/ai/providers/githubCopilot.js +97 -0
  314. package/server/services/ai/providers/openai.js +2 -1
  315. package/server/services/ai/providers/openaiCodex.js +384 -0
  316. package/server/services/ai/recordingInsights.js +11 -13
  317. package/server/services/ai/runEvents.js +100 -0
  318. package/server/services/ai/settings.js +20 -0
  319. package/server/services/ai/systemPrompt.js +16 -2
  320. package/server/services/ai/taskAnalysis.js +2 -0
  321. package/server/services/ai/toolResult.js +20 -0
  322. package/server/services/ai/toolRunner.js +46 -6
  323. package/server/services/ai/toolSelector.js +54 -1
  324. package/server/services/ai/tools.js +360 -127
  325. package/server/services/android/android_bootstrap_worker.js +63 -0
  326. package/server/services/android/controller.js +442 -1760
  327. package/server/services/bootstrap_helpers.js +0 -34
  328. package/server/services/browser/controller.js +326 -52
  329. package/server/services/cli/executor.js +40 -1
  330. package/server/services/desktop/screenRecorder.js +182 -0
  331. package/server/services/integrations/env.js +10 -0
  332. package/server/services/integrations/figma/provider.js +1 -0
  333. package/server/services/integrations/github/common.js +106 -0
  334. package/server/services/integrations/github/provider.js +499 -0
  335. package/server/services/integrations/github/repos.js +1124 -0
  336. package/server/services/integrations/google/provider.js +1 -0
  337. package/server/services/integrations/manager.js +88 -12
  338. package/server/services/integrations/microsoft/provider.js +1 -0
  339. package/server/services/integrations/oauth_provider.js +25 -8
  340. package/server/services/integrations/provider_config_store.js +85 -0
  341. package/server/services/integrations/registry.js +8 -2
  342. package/server/services/integrations/spotify/provider.js +488 -0
  343. package/server/services/integrations/trello/provider.js +842 -0
  344. package/server/services/integrations/weather/provider.js +559 -0
  345. package/server/services/integrations/whatsapp/provider.js +6 -2
  346. package/server/services/manager.js +109 -154
  347. package/server/services/mcp/client.js +120 -23
  348. package/server/services/memory/llm_transfer.js +218 -0
  349. package/server/services/memory/manager.js +299 -35
  350. package/server/services/messaging/access_policy.js +10 -0
  351. package/server/services/messaging/automation.js +1 -1
  352. package/server/services/messaging/manager.js +93 -8
  353. package/server/services/messaging/meshtastic.js +277 -0
  354. package/server/services/messaging/meshtastic_env.js +40 -0
  355. package/server/services/messaging/meshtastic_protocol.js +530 -0
  356. package/server/services/messaging/meshtastic_tcp_transport.js +25 -0
  357. package/server/services/runtime/backends/local-vm.js +221 -158
  358. package/server/services/runtime/docker-vm-manager.js +392 -0
  359. package/server/services/runtime/guest_bootstrap.js +654 -0
  360. package/server/services/runtime/manager.js +85 -29
  361. package/server/services/runtime/settings.js +22 -31
  362. package/server/services/runtime/validation.js +16 -31
  363. package/server/services/skills/base_catalog.js +33 -0
  364. package/server/services/social_video/adapters/base.js +26 -0
  365. package/server/services/social_video/adapters/index.js +27 -0
  366. package/server/services/social_video/adapters/instagram.js +17 -0
  367. package/server/services/social_video/adapters/tiktok.js +17 -0
  368. package/server/services/social_video/adapters/x.js +17 -0
  369. package/server/services/social_video/adapters/youtube.js +17 -0
  370. package/server/services/social_video/captions.js +187 -0
  371. package/server/services/social_video/frame.js +42 -0
  372. package/server/services/social_video/index.js +7 -0
  373. package/server/services/social_video/metadata.js +63 -0
  374. package/server/services/social_video/result.js +63 -0
  375. package/server/services/social_video/service.js +720 -0
  376. package/server/services/social_video/url.js +83 -0
  377. package/server/services/tasks/adapters/index.js +2 -0
  378. package/server/services/tasks/adapters/manual.js +12 -0
  379. package/server/services/tasks/adapters/schedule.js +33 -5
  380. package/server/services/tasks/adapters/weather_event.js +84 -0
  381. package/server/services/tasks/integration_runtime.js +86 -1
  382. package/server/services/tasks/runtime.js +3 -3
  383. package/server/services/tasks/task_repository.js +3 -6
  384. package/server/services/voice/agentBridge.js +20 -4
  385. package/server/services/voice/message.js +3 -0
  386. package/server/services/voice/openaiClient.js +4 -1
  387. package/server/services/voice/openaiSpeech.js +6 -1
  388. package/server/services/voice/providers.js +144 -15
  389. package/server/services/voice/runtime.js +8 -8
  390. package/server/services/voice/runtimeManager.js +292 -20
  391. package/server/services/voice/turnRunner.js +29 -9
  392. package/server/services/wearable/firmware_manifest.js +353 -0
  393. package/server/services/wearable/gateway.js +350 -0
  394. package/server/services/wearable/protocol.js +45 -0
  395. package/server/services/wearable/service.js +240 -0
  396. package/server/services/websocket.js +3 -1
  397. package/server/services/widgets/focus_widget.js +137 -0
  398. package/server/services/widgets/service.js +182 -6
  399. package/server/services/workspace/manager.js +301 -0
  400. package/server/utils/deployment.js +16 -9
  401. package/server/utils/local_secrets.js +56 -0
  402. package/server/utils/logger.js +37 -9
  403. package/server/services/integrations/home_assistant/provider.js +0 -350
  404. package/server/services/messaging/access_policy.test.js +0 -228
  405. package/server/services/runtime/backends/host.js +0 -37
  406. package/server/services/runtime/qemu.js +0 -391
@@ -0,0 +1,90 @@
1
+ 'use strict';
2
+
3
+ const express = require('express');
4
+ const db = require('../db/database');
5
+ const { getErrorMessage } = require('../services/bootstrap_helpers');
6
+ const { requireAuth } = require('../middleware/auth');
7
+
8
+ const router = express.Router();
9
+
10
+ router.use(requireAuth);
11
+
12
+ router.post('/geofence', async (req, res) => {
13
+ const { label, latitude, longitude, radius_meters, action } = req.body;
14
+
15
+ try {
16
+ const userRow = db.prepare('SELECT id FROM users WHERE id = ?').get(req.user.id);
17
+ if (!userRow) return res.status(401).json({ error: 'Unauthorized' });
18
+
19
+ console.log(`[Triggers] Geofence entered: ${label} by user ${req.user.id}`);
20
+
21
+ res.json({ success: true, message: 'Geofence trigger processed' });
22
+ } catch (err) {
23
+ console.error('[Triggers] Geofence error:', getErrorMessage(err));
24
+ res.status(500).json({ error: 'Failed to process geofence trigger' });
25
+ return;
26
+ }
27
+
28
+ // Fire-and-forget after response is sent — errors here must never touch res.
29
+ Promise.resolve().then(() => {
30
+ const agentEngine = req.app.locals.agentEngine;
31
+ if (!agentEngine) return;
32
+ const defaultAgentId = db.prepare('SELECT id FROM agents WHERE user_id = ? ORDER BY is_default DESC LIMIT 1').get(req.user.id)?.id;
33
+ if (!defaultAgentId) return;
34
+ const prompt = [
35
+ `A geofence event was triggered.`,
36
+ `Location label: ${label || 'unknown'}`,
37
+ action ? `Suggested action: ${action}` : 'Check if there are any active reminders or tasks related to this location.',
38
+ ].join('\n');
39
+ return agentEngine.run(req.user.id, prompt, {
40
+ agentId: defaultAgentId,
41
+ triggerSource: 'tasks',
42
+ context: { source: 'geofence', label, latitude, longitude, radius_meters },
43
+ });
44
+ }).catch(err => console.error('[Triggers] Geofence agent run failed:', err.message));
45
+ });
46
+
47
+ router.post('/notification', async (req, res) => {
48
+ const { app_package, title, body, action_taken } = req.body;
49
+
50
+ try {
51
+ const userRow = db.prepare('SELECT id FROM users WHERE id = ?').get(req.session.userId);
52
+ if (!userRow) return res.status(401).json({ error: 'Unauthorized' });
53
+
54
+ console.log(`[Triggers] Notification received: ${app_package} - ${title} for user ${req.session.userId}`);
55
+
56
+ db.prepare(`
57
+ INSERT INTO notification_history (user_id, app_package, title, body, action_taken)
58
+ VALUES (?, ?, ?, ?, ?)
59
+ `).run(req.session.userId, app_package || 'unknown', title || '', body || '', action_taken || 'none');
60
+
61
+ // Respond immediately so the mobile client doesn't retry
62
+ res.json({ success: true, message: 'Notification trigger processed and stored' });
63
+ } catch (err) {
64
+ console.error('[Triggers] Notification error:', getErrorMessage(err));
65
+ res.status(500).json({ error: 'Failed to process notification trigger' });
66
+ return;
67
+ }
68
+
69
+ // Fire-and-forget after response is sent — errors here must never touch res.
70
+ Promise.resolve().then(() => {
71
+ const agentEngine = req.app.locals.agentEngine;
72
+ if (!agentEngine) return;
73
+ const defaultAgentId = db.prepare('SELECT id FROM agents WHERE user_id = ? ORDER BY is_default DESC LIMIT 1').get(req.session.userId)?.id;
74
+ if (!defaultAgentId) return;
75
+ const prompt = [
76
+ `A notification arrived on your device.`,
77
+ `App: ${app_package || 'unknown'}`,
78
+ title ? `Title: ${title}` : '',
79
+ body ? `Body: ${body}` : '',
80
+ `Evaluate whether this notification requires action or a reply. If it is routine or low-priority, do nothing.`,
81
+ ].filter(Boolean).join('\n');
82
+ return agentEngine.run(req.session.userId, prompt, {
83
+ agentId: defaultAgentId,
84
+ triggerSource: 'tasks',
85
+ context: { source: 'notification', app_package, title, body, action_taken },
86
+ });
87
+ }).catch(err => console.error('[Triggers] Notification agent run failed:', err.message));
88
+ });
89
+
90
+ module.exports = router;
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ const express = require('express');
4
+ const { requireAuth } = require('../middleware/auth');
5
+ const { sanitizeError } = require('../utils/security');
6
+
7
+ const router = express.Router();
8
+
9
+ function wearableService(req) {
10
+ return req.app?.locals?.wearableService || null;
11
+ }
12
+
13
+ // Intentionally public so an already-provisioned wearable can sync local time
14
+ // before the user finishes session-based pairing on the device.
15
+ router.get('/timezone', (req, res) => {
16
+ try {
17
+ const service = wearableService(req);
18
+ if (!service) {
19
+ return res.status(500).json({ error: 'Wearable service unavailable.' });
20
+ }
21
+ res.json(service.buildTimeConfig(req));
22
+ } catch (err) {
23
+ res.status(400).json({ error: sanitizeError(err) });
24
+ }
25
+ });
26
+
27
+ router.use(requireAuth);
28
+
29
+ router.get('/bootstrap', async (req, res) => {
30
+ try {
31
+ const service = wearableService(req);
32
+ if (!service) {
33
+ return res.status(500).json({ error: 'Wearable service unavailable.' });
34
+ }
35
+ res.json(await service.buildBootstrap(req));
36
+ } catch (err) {
37
+ res.status(400).json({ error: sanitizeError(err) });
38
+ }
39
+ });
40
+
41
+ router.get('/firmware/manifest', async (req, res) => {
42
+ try {
43
+ const service = wearableService(req);
44
+ if (!service) {
45
+ return res.status(500).json({ error: 'Wearable service unavailable.' });
46
+ }
47
+ res.json(await service.buildFirmwareManifest(req));
48
+ } catch (err) {
49
+ res.status(400).json({ error: sanitizeError(err) });
50
+ }
51
+ });
52
+
53
+ router.get('/connections', (req, res) => {
54
+ try {
55
+ const service = wearableService(req);
56
+ if (!service) {
57
+ return res.status(500).json({ error: 'Wearable service unavailable.' });
58
+ }
59
+ res.json({
60
+ connections: service.listConnections(req.session.userId),
61
+ });
62
+ } catch (err) {
63
+ res.status(400).json({ error: sanitizeError(err) });
64
+ }
65
+ });
66
+
67
+ module.exports = router;
@@ -78,7 +78,7 @@ router.delete('/:id', (req, res) => {
78
78
  }
79
79
  });
80
80
 
81
- router.post('/:id/refresh', (req, res) => {
81
+ router.post('/:id/refresh', async (req, res) => {
82
82
  try {
83
83
  const service = widgetService(req);
84
84
  const taskRuntime = req.app?.locals?.taskRuntime;
@@ -89,10 +89,10 @@ router.post('/:id/refresh', (req, res) => {
89
89
  if (!widget) {
90
90
  return res.status(404).json({ error: 'Widget not found.' });
91
91
  }
92
- if (!widget.scheduledTaskId) {
93
- return res.status(400).json({ error: 'Widget is missing its refresh task.' });
92
+ if (widget.isSystem || !widget.scheduledTaskId) {
93
+ return res.json(await service.refreshWidget(req.session.userId, req.params.id));
94
94
  }
95
- res.json(taskRuntime.runTaskNow(widget.scheduledTaskId, req.session.userId));
95
+ res.json(await taskRuntime.runTaskNow(widget.scheduledTaskId, req.session.userId));
96
96
  } catch (err) {
97
97
  res.status(400).json({ error: sanitizeError(err) });
98
98
  }
@@ -1,7 +1,5 @@
1
1
  const db = require('../../db/database');
2
2
  const { getProviderHealthCatalog } = require('./models');
3
- const { resolveBrowserExecutablePath } = require('../browser/controller');
4
- const { deriveCloudBrowserBackend } = require('../runtime/settings');
5
3
 
6
4
  function capabilityEntry(overrides = {}) {
7
5
  return {
@@ -38,7 +36,6 @@ function summarizeCapabilityHealth(health) {
38
36
 
39
37
  async function getBrowserHealth(userId, app, engine) {
40
38
  const runtimeManager = app?.locals?.runtimeManager || engine?.runtimeManager || null;
41
- const executablePath = resolveBrowserExecutablePath();
42
39
  const runtimeSettings = typeof runtimeManager?.getSettings === 'function'
43
40
  ? runtimeManager.getSettings(userId)
44
41
  : null;
@@ -78,26 +75,16 @@ async function getBrowserHealth(userId, app, engine) {
78
75
  }
79
76
 
80
77
  if (!controller) {
81
- try {
82
- const resolver = app?.locals?.getBrowserControllerForUser;
83
- controller = await Promise.resolve(
84
- typeof resolver === 'function'
85
- ? resolver(userId)
86
- : (app?.locals?.browserController || engine?.browserController || null)
87
- );
88
- } catch (err) {
89
- resolutionError = resolutionError || err;
90
- }
78
+ resolutionError = resolutionError || new Error('Browser provider is unavailable. VM runtime is required.');
91
79
  }
92
80
 
93
81
  if (!controller && resolutionError) {
94
82
  return capabilityEntry({
95
- configured: Boolean(executablePath),
83
+ configured: true,
96
84
  healthy: false,
97
85
  degraded: true,
98
86
  summary: `Browser controller resolution failed: ${resolutionError.message}`,
99
87
  details: {
100
- executablePath: executablePath || null,
101
88
  error: resolutionError.message,
102
89
  },
103
90
  });
@@ -117,23 +104,18 @@ async function getBrowserHealth(userId, app, engine) {
117
104
 
118
105
  return capabilityEntry({
119
106
  connected: launched,
120
- configured: Boolean(executablePath),
121
- healthy: Boolean(executablePath) && !error,
107
+ configured: true,
108
+ healthy: !error,
122
109
  degraded: Boolean(error) || runtimeSettings?.browser_backend === 'extension',
123
110
  summary: error
124
111
  ? `Browser runtime error: ${error}`
125
112
  : runtimeSettings?.browser_backend === 'extension'
126
- ? executablePath
127
- ? `No extension device is active. Falling back to the ${deriveCloudBrowserBackend(runtimeSettings)} browser runtime.`
128
- : 'No extension device is active and no browser executable was found for Puppeteer.'
129
- : executablePath
130
- ? (launched ? 'Browser runtime is ready.' : 'Browser executable is available but not launched.')
131
- : 'No browser executable was found for Puppeteer.',
113
+ ? `No extension device is active. Falling back to the vm browser runtime.`
114
+ : (launched ? 'Browser runtime is ready.' : 'Browser runtime is available but not launched.'),
132
115
  details: {
133
- executablePath: executablePath || null,
134
116
  preferredBackend: runtimeSettings?.browser_backend || null,
135
117
  backend: runtimeSettings?.browser_backend === 'extension'
136
- ? deriveCloudBrowserBackend(runtimeSettings)
118
+ ? 'vm'
137
119
  : runtimeSettings?.browser_backend || null,
138
120
  extensionConnected: extensionStatus?.connected === true,
139
121
  activeTokenCount: Array.isArray(extensionStatus?.tokens)
@@ -159,17 +141,7 @@ async function getAndroidHealth(userId, app, engine) {
159
141
  }
160
142
 
161
143
  if (!controller) {
162
- try {
163
- const resolver = app?.locals?.getAndroidControllerForUser;
164
- controller = await Promise.resolve(
165
- typeof resolver === 'function'
166
- ? resolver(userId)
167
- : (app?.locals?.androidController || engine?.androidController || null)
168
- );
169
- } catch (err) {
170
- resolutionError = resolutionError || err;
171
- controller = null;
172
- }
144
+ resolutionError = resolutionError || new Error('Android provider is unavailable. VM runtime is required.');
173
145
  }
174
146
 
175
147
  if (!controller || typeof controller.getStatus !== 'function') {
@@ -194,7 +166,7 @@ async function getAndroidHealth(userId, app, engine) {
194
166
  summary: status.lastStartError
195
167
  ? `Android tooling reported: ${status.lastStartError}`
196
168
  : bootstrapped
197
- ? 'Android environment is bootstrapped.'
169
+ ? 'Android environment is ready on this host.'
198
170
  : (canBootstrap ? 'Android environment can be bootstrapped on this host.' : 'Android tooling cannot bootstrap on this host.'),
199
171
  details: status,
200
172
  });
@@ -319,27 +291,27 @@ function getSkillHealth(app, engine) {
319
291
  });
320
292
  }
321
293
 
322
- function getFileHealth() {
294
+ function getFileHealth(app, engine) {
295
+ const workspaceManager = app?.locals?.workspaceManager || engine?.workspaceManager || null;
323
296
  return capabilityEntry({
324
- connected: true,
325
- configured: true,
326
- healthy: true,
327
- summary: 'Filesystem access is available.',
297
+ connected: Boolean(workspaceManager),
298
+ configured: Boolean(workspaceManager),
299
+ healthy: Boolean(workspaceManager),
300
+ summary: workspaceManager
301
+ ? 'Per-user workspace access is available.'
302
+ : 'Per-user workspace service is not available.',
328
303
  });
329
304
  }
330
305
 
331
306
  function getCommandHealth(userId, app, engine) {
332
307
  const runtimeManager = app?.locals?.runtimeManager || engine?.runtimeManager || null;
333
- const backend = runtimeManager?.getSettings?.(userId)?.runtime_backend || 'host';
334
308
  return capabilityEntry({
335
- connected: Boolean(runtimeManager || engine?.cliExecutor),
336
- configured: true,
337
- healthy: Boolean(runtimeManager || engine?.cliExecutor),
309
+ connected: Boolean(runtimeManager),
310
+ configured: Boolean(runtimeManager),
311
+ healthy: Boolean(runtimeManager),
338
312
  summary: runtimeManager
339
- ? `Shell command execution is available through the ${backend} runtime backend.`
340
- : engine?.cliExecutor
341
- ? 'Shell command execution is available.'
342
- : 'Shell executor is not available.',
313
+ ? 'Shell command execution is available.'
314
+ : 'Shell command execution is not available in this environment.',
343
315
  });
344
316
  }
345
317
 
@@ -376,7 +348,7 @@ async function getCapabilityHealth({ userId, agentId = null, app, engine }) {
376
348
  providers,
377
349
  capabilities: {
378
350
  command: getCommandHealth(userId, app, engine),
379
- files: getFileHealth(),
351
+ files: getFileHealth(app, engine),
380
352
  memory: getMemoryHealth(engine),
381
353
  search: getSearchHealth(),
382
354
  browser: await getBrowserHealth(userId, app, engine),
@@ -21,7 +21,7 @@ async function compact(messages, provider, model, contextWindow = null) {
21
21
  }).join('\n');
22
22
 
23
23
  const summaryPrompt = [
24
- { role: 'system', content: 'Compress conversation context. Preserve goals, constraints, decisions, promised follow-ups, recurring tasks, tool outcomes, errors, and unresolved work. Keep concrete facts (dates/times/names/status) and avoid vague wording.' },
24
+ { role: 'system', content: 'Compress this conversation into a dense context block. Preserve: active goals and constraints, decisions made, promised actions (sent/created/changed/deleted), tool outcomes and errors, unresolved blockers, task configs, and concrete facts (names, IDs, dates, statuses, file paths). Omit greetings, filler, and tool-call narration. Write in past tense. Be specific — "email sent to alice@example.com at 3pm" beats "a message was sent".' },
25
25
  { role: 'user', content: `Summarize this conversation:\n\n${compactionText}` }
26
26
  ];
27
27
 
@@ -0,0 +1,190 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { normalizeArtifactContract } = require('./contracts');
6
+
7
+ const FILE_EXTENSION_TO_KIND = {
8
+ '.ppt': 'slides',
9
+ '.pptx': 'slides',
10
+ '.key': 'slides',
11
+ '.pdf': 'document',
12
+ '.doc': 'document',
13
+ '.docx': 'document',
14
+ '.md': 'document',
15
+ '.txt': 'document',
16
+ '.html': 'document',
17
+ '.htm': 'document',
18
+ '.csv': 'data',
19
+ '.tsv': 'data',
20
+ '.xlsx': 'data',
21
+ '.xls': 'data',
22
+ '.json': 'data',
23
+ '.png': 'image',
24
+ '.jpg': 'image',
25
+ '.jpeg': 'image',
26
+ '.gif': 'image',
27
+ '.webp': 'image',
28
+ '.svg': 'image',
29
+ '.mp4': 'video',
30
+ '.mov': 'video',
31
+ '.m4v': 'video',
32
+ '.webm': 'video',
33
+ };
34
+
35
+ const FILE_EXTENSION_TO_MIME = {
36
+ '.ppt': 'application/vnd.ms-powerpoint',
37
+ '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
38
+ '.pdf': 'application/pdf',
39
+ '.doc': 'application/msword',
40
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
41
+ '.md': 'text/markdown',
42
+ '.txt': 'text/plain',
43
+ '.html': 'text/html',
44
+ '.htm': 'text/html',
45
+ '.csv': 'text/csv',
46
+ '.tsv': 'text/tab-separated-values',
47
+ '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
48
+ '.xls': 'application/vnd.ms-excel',
49
+ '.json': 'application/json',
50
+ '.png': 'image/png',
51
+ '.jpg': 'image/jpeg',
52
+ '.jpeg': 'image/jpeg',
53
+ '.gif': 'image/gif',
54
+ '.webp': 'image/webp',
55
+ '.svg': 'image/svg+xml',
56
+ '.mp4': 'video/mp4',
57
+ '.mov': 'video/quicktime',
58
+ '.m4v': 'video/x-m4v',
59
+ '.webm': 'video/webm',
60
+ };
61
+
62
+ const CANDIDATE_KEYS = [
63
+ 'path',
64
+ 'paths',
65
+ 'file',
66
+ 'files',
67
+ 'filePath',
68
+ 'filePaths',
69
+ 'fullPath',
70
+ 'fullPaths',
71
+ 'mediaPath',
72
+ 'mediaPaths',
73
+ 'screenshotPath',
74
+ 'uiDumpPath',
75
+ 'url',
76
+ 'urls',
77
+ ];
78
+
79
+ function inferExtension(candidate = '') {
80
+ return path.extname(String(candidate || '').split('?')[0]).toLowerCase();
81
+ }
82
+
83
+ function inferArtifactKind(candidate = '', fallback = 'artifact') {
84
+ const extension = inferExtension(candidate);
85
+ if (FILE_EXTENSION_TO_KIND[extension]) return FILE_EXTENSION_TO_KIND[extension];
86
+ const normalized = String(candidate || '').toLowerCase();
87
+ if (normalized.includes('image')) return 'image';
88
+ if (normalized.includes('video')) return 'video';
89
+ if (normalized.includes('slide') || normalized.includes('ppt')) return 'slides';
90
+ if (normalized.includes('doc') || normalized.includes('pdf')) return 'document';
91
+ if (normalized.includes('data') || normalized.includes('chart') || normalized.includes('csv')) return 'data';
92
+ return fallback;
93
+ }
94
+
95
+ function inferMimeType(candidate = '') {
96
+ const extension = inferExtension(candidate);
97
+ return FILE_EXTENSION_TO_MIME[extension] || null;
98
+ }
99
+
100
+ function normalizePathOrUri(value) {
101
+ const text = String(value || '').trim();
102
+ if (!text) return null;
103
+ if (text.startsWith('/api/artifacts/')) return { uri: text, path: null };
104
+ if (/^https?:\/\//i.test(text)) return { uri: text, path: null };
105
+ if (/^[A-Za-z]:\\/.test(text)) return { path: text, uri: null };
106
+ if (path.isAbsolute(text)) return { path: text, uri: null };
107
+ return null;
108
+ }
109
+
110
+ async function buildArtifactFromCandidate(candidate, fallbackKind = 'artifact') {
111
+ const normalized = normalizePathOrUri(candidate);
112
+ if (!normalized) return null;
113
+ const source = normalized.path || normalized.uri || '';
114
+ const artifact = normalizeArtifactContract({
115
+ kind: inferArtifactKind(source, fallbackKind),
116
+ path: normalized.path,
117
+ uri: normalized.uri,
118
+ label: path.basename(String(source).split('?')[0]) || null,
119
+ mimeType: inferMimeType(source),
120
+ });
121
+ if (artifact.path) {
122
+ try {
123
+ artifact.size = (await fs.promises.stat(artifact.path)).size;
124
+ } catch (error) {
125
+ console.warn('[deliverables] Failed to stat artifact candidate:', artifact.path, error?.message || error);
126
+ }
127
+ }
128
+ return artifact.path || artifact.uri ? artifact : null;
129
+ }
130
+
131
+ function scanStringForCandidates(text) {
132
+ const input = String(text || '');
133
+ const matches = [];
134
+ const regexes = [
135
+ /\/api\/artifacts\/[A-Za-z0-9%_-]+\/content/g,
136
+ /\/[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
137
+ /[A-Za-z]:\\[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
138
+ /https?:\/\/[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
139
+ ];
140
+ for (const regex of regexes) {
141
+ const found = input.match(regex);
142
+ if (found) matches.push(...found);
143
+ }
144
+ return matches;
145
+ }
146
+
147
+ async function extractArtifactsFromResult(toolName, result) {
148
+ const artifacts = [];
149
+ const seen = new Set();
150
+ const fallbackKind = inferArtifactKind(toolName, 'artifact');
151
+
152
+ async function pushCandidate(candidate) {
153
+ const artifact = await buildArtifactFromCandidate(candidate, fallbackKind);
154
+ if (!artifact) return;
155
+ const key = `${artifact.kind}:${artifact.path || artifact.uri}`;
156
+ if (seen.has(key)) return;
157
+ seen.add(key);
158
+ artifacts.push(artifact);
159
+ }
160
+
161
+ async function visit(value, keyHint = '') {
162
+ if (value == null) return;
163
+ if (typeof value === 'string') {
164
+ if (CANDIDATE_KEYS.includes(keyHint)) await pushCandidate(value);
165
+ for (const candidate of scanStringForCandidates(value)) {
166
+ await pushCandidate(candidate);
167
+ }
168
+ return;
169
+ }
170
+ if (Array.isArray(value)) {
171
+ for (const item of value) await visit(item, keyHint);
172
+ return;
173
+ }
174
+ if (typeof value === 'object') {
175
+ for (const [key, nested] of Object.entries(value)) {
176
+ await visit(nested, key);
177
+ }
178
+ }
179
+ }
180
+
181
+ await visit(result);
182
+ return artifacts;
183
+ }
184
+
185
+ module.exports = {
186
+ extractArtifactsFromResult,
187
+ inferArtifactKind,
188
+ inferMimeType,
189
+ normalizePathOrUri,
190
+ };
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ const DELIVERABLE_TYPES = [
4
+ 'slides',
5
+ 'document',
6
+ 'research_report',
7
+ 'data_analysis',
8
+ 'image',
9
+ 'video',
10
+ ];
11
+
12
+ const DELIVERABLE_SELECTION_STATUSES = ['selected', 'standard'];
13
+ const DELIVERABLE_VALIDATION_STATUSES = ['passed', 'failed'];
14
+
15
+ function clampText(value, maxLength = 240) {
16
+ return String(value || '').trim().slice(0, maxLength);
17
+ }
18
+
19
+ function normalizeDeliverableType(value) {
20
+ const normalized = clampText(value, 48).toLowerCase();
21
+ return DELIVERABLE_TYPES.includes(normalized) ? normalized : null;
22
+ }
23
+
24
+ function normalizeStringList(value, limit = 8, maxLength = 120) {
25
+ if (!Array.isArray(value)) return [];
26
+ return value
27
+ .map((item) => clampText(item, maxLength))
28
+ .filter(Boolean)
29
+ .slice(0, limit);
30
+ }
31
+
32
+ function normalizeArtifactContract(raw = {}) {
33
+ const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
34
+ return {
35
+ kind: clampText(source.kind, 48) || 'artifact',
36
+ path: clampText(source.path || source.fullPath, 500) || null,
37
+ uri: clampText(source.uri || source.url, 500) || null,
38
+ label: clampText(source.label, 120) || null,
39
+ mimeType: clampText(source.mimeType || source.contentType, 120) || null,
40
+ size: Number.isFinite(Number(source.size ?? source.byteSize))
41
+ ? Number(source.size ?? source.byteSize)
42
+ : null,
43
+ preview: source.preview && typeof source.preview === 'object' && !Array.isArray(source.preview)
44
+ ? { ...source.preview }
45
+ : {},
46
+ };
47
+ }
48
+
49
+ function normalizeDeliverableSelection(raw = {}) {
50
+ const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
51
+ const type = normalizeDeliverableType(source.type);
52
+ const confidence = Math.max(0, Math.min(1, Number(source.confidence) || 0));
53
+ const status = DELIVERABLE_SELECTION_STATUSES.includes(String(source.status || '').trim().toLowerCase())
54
+ ? String(source.status).trim().toLowerCase()
55
+ : (type ? 'selected' : 'standard');
56
+
57
+ return {
58
+ status,
59
+ type,
60
+ confidence,
61
+ goal: clampText(source.goal, 240),
62
+ requestedOutputs: normalizeStringList(source.requested_outputs || source.requestedOutputs, 8, 120),
63
+ supportingCapabilities: normalizeStringList(source.supporting_capabilities || source.supportingCapabilities, 8, 64),
64
+ };
65
+ }
66
+
67
+ function normalizeDeliverableValidationResult(raw = {}) {
68
+ const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
69
+ const status = DELIVERABLE_VALIDATION_STATUSES.includes(String(source.status || '').trim().toLowerCase())
70
+ ? String(source.status).trim().toLowerCase()
71
+ : 'failed';
72
+ const artifacts = Array.isArray(source.artifacts)
73
+ ? source.artifacts.map(normalizeArtifactContract).filter((artifact) => artifact.path || artifact.uri)
74
+ : [];
75
+
76
+ return {
77
+ status,
78
+ summary: clampText(source.summary, 320),
79
+ errors: normalizeStringList(source.errors, 8, 220),
80
+ warnings: normalizeStringList(source.warnings, 8, 220),
81
+ artifacts,
82
+ metrics: source.metrics && typeof source.metrics === 'object' && !Array.isArray(source.metrics)
83
+ ? { ...source.metrics }
84
+ : {},
85
+ };
86
+ }
87
+
88
+ function normalizeDeliverableResult(raw = {}) {
89
+ const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
90
+ return {
91
+ type: normalizeDeliverableType(source.type),
92
+ status: clampText(source.status, 32) || 'unknown',
93
+ summary: clampText(source.summary, 320),
94
+ artifacts: Array.isArray(source.artifacts)
95
+ ? source.artifacts.map(normalizeArtifactContract).filter((artifact) => artifact.path || artifact.uri)
96
+ : [],
97
+ validation: normalizeDeliverableValidationResult(source.validation),
98
+ metadata: source.metadata && typeof source.metadata === 'object' && !Array.isArray(source.metadata)
99
+ ? { ...source.metadata }
100
+ : {},
101
+ };
102
+ }
103
+
104
+ module.exports = {
105
+ DELIVERABLE_TYPES,
106
+ clampText,
107
+ normalizeArtifactContract,
108
+ normalizeDeliverableResult,
109
+ normalizeDeliverableSelection,
110
+ normalizeDeliverableType,
111
+ normalizeDeliverableValidationResult,
112
+ normalizeStringList,
113
+ };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const { selectDeliverableWorkflow } = require('./selector');
4
+ const {
5
+ buildDeliverableWorkflowGuidance,
6
+ getDeliverableWorkflow,
7
+ listDeliverableWorkflows,
8
+ } = require('./workflows');
9
+ const { extractArtifactsFromResult } = require('./artifact_helpers');
10
+ const { DeliverableValidationError, validateDeliverableExecution } = require('./validator');
11
+
12
+ module.exports = {
13
+ buildDeliverableWorkflowGuidance,
14
+ DeliverableValidationError,
15
+ extractArtifactsFromResult,
16
+ getDeliverableWorkflow,
17
+ listDeliverableWorkflows,
18
+ selectDeliverableWorkflow,
19
+ validateDeliverableExecution,
20
+ };