neoagent 2.4.1-beta.8 → 2.4.1-beta.9

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 (35) hide show
  1. package/extensions/chrome-browser/background.mjs +9 -3
  2. package/extensions/chrome-browser/manifest.json +2 -1
  3. package/extensions/chrome-browser/popup.js +2 -2
  4. package/flutter_app/lib/main.dart +1 -0
  5. package/flutter_app/lib/main_controller.dart +141 -4
  6. package/flutter_app/lib/main_devices.dart +416 -119
  7. package/flutter_app/lib/main_settings.dart +89 -14
  8. package/flutter_app/lib/src/backend_client.dart +33 -0
  9. package/flutter_app/lib/src/desktop_companion_actions.dart +26 -0
  10. package/flutter_app/lib/src/desktop_companion_io.dart +6 -0
  11. package/flutter_app/lib/src/desktop_native_bridge.dart +13 -0
  12. package/flutter_app/lib/src/stream_renderer.dart +166 -35
  13. package/flutter_app/macos/Runner/AppDelegate.swift +44 -0
  14. package/package.json +1 -1
  15. package/server/public/.last_build_id +1 -1
  16. package/server/public/flutter_bootstrap.js +1 -1
  17. package/server/public/main.dart.js +67339 -66716
  18. package/server/routes/browser.js +14 -0
  19. package/server/routes/browser_extension.js +21 -4
  20. package/server/routes/desktop.js +10 -0
  21. package/server/routes/settings.js +4 -0
  22. package/server/routes/stream.js +11 -2
  23. package/server/services/ai/tools.js +2 -2
  24. package/server/services/android/controller.js +36 -1
  25. package/server/services/browser/controller.js +18 -0
  26. package/server/services/browser/extension/manifest.js +33 -0
  27. package/server/services/browser/extension/provider.js +12 -6
  28. package/server/services/browser/extension/registry.js +144 -18
  29. package/server/services/desktop/protocol.js +1 -0
  30. package/server/services/desktop/provider.js +4 -0
  31. package/server/services/manager.js +8 -2
  32. package/server/services/runtime/manager.js +7 -3
  33. package/server/services/runtime/settings.js +17 -0
  34. package/server/services/streaming/android-stream.js +18 -7
  35. package/server/services/streaming/stream-hub.js +1 -1
@@ -250,12 +250,18 @@ async function checkForUpdates(preferredServerUrl) {
250
250
  const response = await fetchWithTimeout(`${serverUrl}/api/browser-extension/latest`);
251
251
  const latest = await response.json().catch(() => ({}));
252
252
  if (!response.ok) throw new Error(latest.error || `Update check failed: ${response.status}`);
253
- const currentVersion = chrome.runtime.getManifest().version;
253
+ const manifest = chrome.runtime.getManifest();
254
+ const currentVersion = manifest.version;
255
+ const currentVersionName = manifest.version_name || currentVersion;
256
+ const latestVersion = latest.version || currentVersion;
257
+ const latestVersionName = latest.versionName || latestVersion;
254
258
  return {
255
259
  currentVersion,
256
- latestVersion: latest.version || currentVersion,
260
+ currentVersionName,
261
+ latestVersion,
262
+ latestVersionName,
257
263
  downloadUrl: latest.downloadUrl || `${serverUrl}/api/browser-extension/download`,
258
- updateAvailable: compareVersions(latest.version, currentVersion) > 0,
264
+ updateAvailable: compareVersions(latestVersion, currentVersion) > 0,
259
265
  };
260
266
  }
261
267
 
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "NeoAgent Browser",
4
- "version": "1.0.0",
4
+ "version": "2.4.1.7",
5
+ "version_name": "2.4.1-beta.7",
5
6
  "description": "Connect this Chrome browser to NeoAgent for browser automation.",
6
7
  "minimum_chrome_version": "118",
7
8
  "permissions": ["debugger", "storage", "tabs"],
@@ -249,8 +249,8 @@ bindAsyncClick(checkUpdateEl, async () => {
249
249
  const result = await send('checkForUpdates', { serverUrl: effectiveServerUrl() });
250
250
  setMessage(
251
251
  result.updateAvailable
252
- ? `Update available: ${result.currentVersion} -> ${result.latestVersion}.`
253
- : `Current version ${result.currentVersion} is up to date.`,
252
+ ? `Update available: ${result.currentVersionName || result.currentVersion} -> ${result.latestVersionName || result.latestVersion}.`
253
+ : `Current version ${result.currentVersionName || result.currentVersion} is up to date.`,
254
254
  result.updateAvailable ? '' : 'success',
255
255
  );
256
256
  });
@@ -39,6 +39,7 @@ import 'src/messaging_access_summary.dart';
39
39
  import 'src/oauth_launcher.dart';
40
40
  import 'src/recording_bridge.dart';
41
41
  import 'src/recording_payloads.dart';
42
+ import 'src/stream_renderer.dart';
42
43
  import 'src/theme/palette.dart';
43
44
  import 'src/web_app_update_monitor.dart';
44
45
  import 'src/widget_bridge.dart';
@@ -105,6 +105,8 @@ class NeoAgentController extends ChangeNotifier {
105
105
  bool _analyticsConsentResolved = false;
106
106
  bool _analyticsConsentGranted = false;
107
107
 
108
+ io.Socket? get streamSocket => socketConnected ? _socket : null;
109
+
108
110
  bool hasUser = true;
109
111
  bool registrationOpen = false;
110
112
  bool serviceEmailConfigured = false;
@@ -168,6 +170,8 @@ class NeoAgentController extends ChangeNotifier {
168
170
  List<McpServerItem> mcpServers = const <McpServerItem>[];
169
171
  Map<String, dynamic> browserRuntime = const <String, dynamic>{};
170
172
  Map<String, dynamic> browserExtensionStatus = const <String, dynamic>{};
173
+ List<Map<String, dynamic>> browserExtensionTokens =
174
+ const <Map<String, dynamic>>[];
171
175
  Map<String, dynamic> androidRuntime = const <String, dynamic>{};
172
176
  Map<String, dynamic> desktopRuntime = const <String, dynamic>{};
173
177
  List<String> androidInstalledApps = const <String>[];
@@ -176,6 +180,7 @@ class NeoAgentController extends ChangeNotifier {
176
180
  List<Map<String, dynamic>> desktopDisplays = const <Map<String, dynamic>>[];
177
181
  Map<String, dynamic> desktopPermissions = const <String, dynamic>{};
178
182
  String? selectedDesktopDeviceId;
183
+ String? selectedBrowserExtensionTokenId;
179
184
  String? browserScreenshotPath;
180
185
  String? androidScreenshotPath;
181
186
  String? desktopScreenshotPath;
@@ -893,8 +898,9 @@ class NeoAgentController extends ChangeNotifier {
893
898
  // On web, require explicit opt-in (GDPR). On native, consent is implicit
894
899
  // unless the user has previously declined.
895
900
  _analyticsConsentResolved = consentState != null || !kIsWeb;
896
- _analyticsConsentGranted =
897
- kIsWeb ? consentState == true : consentState != false;
901
+ _analyticsConsentGranted = kIsWeb
902
+ ? consentState == true
903
+ : consentState != false;
898
904
  await _analytics.initialize(
899
905
  token: token,
900
906
  consentGranted: _analyticsConsentGranted,
@@ -1653,6 +1659,7 @@ class NeoAgentController extends ChangeNotifier {
1653
1659
  mcpServers = const <McpServerItem>[];
1654
1660
  browserRuntime = const <String, dynamic>{};
1655
1661
  browserExtensionStatus = const <String, dynamic>{};
1662
+ browserExtensionTokens = const <Map<String, dynamic>>[];
1656
1663
  androidRuntime = const <String, dynamic>{};
1657
1664
  desktopRuntime = const <String, dynamic>{};
1658
1665
  androidInstalledApps = const <String>[];
@@ -1661,6 +1668,7 @@ class NeoAgentController extends ChangeNotifier {
1661
1668
  desktopDisplays = const <Map<String, dynamic>>[];
1662
1669
  desktopPermissions = const <String, dynamic>{};
1663
1670
  selectedDesktopDeviceId = null;
1671
+ selectedBrowserExtensionTokenId = null;
1664
1672
  browserScreenshotPath = null;
1665
1673
  androidScreenshotPath = null;
1666
1674
  desktopScreenshotPath = null;
@@ -2342,6 +2350,13 @@ class NeoAgentController extends ChangeNotifier {
2342
2350
  browserExtensionStatus = Map<String, dynamic>.from(
2343
2351
  browserExtensionResponse,
2344
2352
  );
2353
+ browserExtensionTokens = _jsonMapList(
2354
+ browserExtensionStatus['tokens'],
2355
+ fallbackToMapValues: true,
2356
+ );
2357
+ selectedBrowserExtensionTokenId = _optionalIdFrom(
2358
+ browserExtensionStatus['selectedTokenId'],
2359
+ );
2345
2360
  androidRuntime = Map<String, dynamic>.from(androidResponse);
2346
2361
  desktopRuntime = Map<String, dynamic>.from(desktopResponse);
2347
2362
  selectedDesktopDeviceId =
@@ -2437,6 +2452,11 @@ class NeoAgentController extends ChangeNotifier {
2437
2452
  return parsed;
2438
2453
  }
2439
2454
 
2455
+ String? _optionalIdFrom(dynamic value) {
2456
+ final normalized = value?.toString().trim() ?? '';
2457
+ return normalized.isEmpty || normalized == 'null' ? null : normalized;
2458
+ }
2459
+
2440
2460
  Future<void> refreshRunsOnly() async {
2441
2461
  try {
2442
2462
  final runsResponse = await _backendClient.fetchRuns(
@@ -2740,6 +2760,13 @@ class NeoAgentController extends ChangeNotifier {
2740
2760
  browserExtensionStatus = Map<String, dynamic>.from(
2741
2761
  browserExtensionResponse,
2742
2762
  );
2763
+ browserExtensionTokens = _jsonMapList(
2764
+ browserExtensionStatus['tokens'],
2765
+ fallbackToMapValues: true,
2766
+ );
2767
+ selectedBrowserExtensionTokenId = _optionalIdFrom(
2768
+ browserExtensionStatus['selectedTokenId'],
2769
+ );
2743
2770
  androidRuntime = Map<String, dynamic>.from(androidResponse);
2744
2771
  desktopRuntime = Map<String, dynamic>.from(desktopResponse);
2745
2772
  selectedDesktopDeviceId =
@@ -2767,6 +2794,13 @@ class NeoAgentController extends ChangeNotifier {
2767
2794
  backendUrl,
2768
2795
  );
2769
2796
  browserExtensionStatus = Map<String, dynamic>.from(response);
2797
+ browserExtensionTokens = _jsonMapList(
2798
+ browserExtensionStatus['tokens'],
2799
+ fallbackToMapValues: true,
2800
+ );
2801
+ selectedBrowserExtensionTokenId = _optionalIdFrom(
2802
+ browserExtensionStatus['selectedTokenId'],
2803
+ );
2770
2804
  notifyListeners();
2771
2805
  } catch (error) {
2772
2806
  errorMessage = _friendlyErrorMessage(error);
@@ -2911,6 +2945,15 @@ class NeoAgentController extends ChangeNotifier {
2911
2945
  );
2912
2946
  }
2913
2947
 
2948
+ Future<void> hoverBrowserPointRuntime({
2949
+ required int x,
2950
+ required int y,
2951
+ }) async {
2952
+ try {
2953
+ await _backendClient.hoverBrowserPoint(backendUrl, x: x, y: y);
2954
+ } catch (_) {}
2955
+ }
2956
+
2914
2957
  Future<void> fillBrowserRuntime({
2915
2958
  required String selector,
2916
2959
  required String value,
@@ -3036,6 +3079,40 @@ class NeoAgentController extends ChangeNotifier {
3036
3079
  } catch (_) {}
3037
3080
  }
3038
3081
 
3082
+ Future<void> startStreamRuntime({
3083
+ required String platform,
3084
+ required String deviceId,
3085
+ int fps = 10,
3086
+ int quality = 70,
3087
+ }) async {
3088
+ final normalizedDeviceId = deviceId.trim();
3089
+ if (normalizedDeviceId.isEmpty) {
3090
+ return;
3091
+ }
3092
+ await _backendClient.startStream(
3093
+ backendUrl,
3094
+ platform: platform,
3095
+ deviceId: normalizedDeviceId,
3096
+ fps: fps,
3097
+ quality: quality,
3098
+ );
3099
+ }
3100
+
3101
+ Future<void> stopStreamRuntime({
3102
+ required String platform,
3103
+ required String deviceId,
3104
+ }) async {
3105
+ final normalizedDeviceId = deviceId.trim();
3106
+ if (normalizedDeviceId.isEmpty) {
3107
+ return;
3108
+ }
3109
+ await _backendClient.stopStream(
3110
+ backendUrl,
3111
+ platform: platform,
3112
+ deviceId: normalizedDeviceId,
3113
+ );
3114
+ }
3115
+
3039
3116
  Future<void> dumpAndroidUiRuntime() async {
3040
3117
  await _runDeviceAction(
3041
3118
  () => _backendClient.dumpAndroidUi(backendUrl),
@@ -3203,6 +3280,44 @@ class NeoAgentController extends ChangeNotifier {
3203
3280
  await refreshDesktopFrameRuntime();
3204
3281
  }
3205
3282
 
3283
+ Future<void> selectBrowserExtensionRuntime(String tokenId) async {
3284
+ isRunningDeviceAction = true;
3285
+ errorMessage = null;
3286
+ notifyListeners();
3287
+ try {
3288
+ final response = await _backendClient.selectBrowserExtensionToken(
3289
+ backendUrl,
3290
+ tokenId: tokenId,
3291
+ );
3292
+ final status = response['status'] is Map
3293
+ ? Map<String, dynamic>.from(response['status'] as Map)
3294
+ : await _backendClient.fetchBrowserExtensionStatus(backendUrl);
3295
+ browserExtensionStatus = Map<String, dynamic>.from(status);
3296
+ browserExtensionTokens = _jsonMapList(
3297
+ browserExtensionStatus['tokens'],
3298
+ fallbackToMapValues: true,
3299
+ );
3300
+ selectedBrowserExtensionTokenId = _optionalIdFrom(
3301
+ browserExtensionStatus['selectedTokenId'],
3302
+ );
3303
+ if (selectedBrowserExtensionTokenId != null) {
3304
+ settings = <String, dynamic>{
3305
+ ...settings,
3306
+ 'browser_extension_token_id': selectedBrowserExtensionTokenId,
3307
+ 'selected_browser_extension_token_id':
3308
+ selectedBrowserExtensionTokenId,
3309
+ };
3310
+ }
3311
+ browserScreenshotPath = null;
3312
+ await refreshBrowserFrameRuntime();
3313
+ } catch (error) {
3314
+ errorMessage = _friendlyErrorMessage(error);
3315
+ } finally {
3316
+ isRunningDeviceAction = false;
3317
+ notifyListeners();
3318
+ }
3319
+ }
3320
+
3206
3321
  Future<void> openDesktopSelectionRuntime() async {
3207
3322
  await refreshDevices();
3208
3323
  errorMessage =
@@ -3281,6 +3396,17 @@ class NeoAgentController extends ChangeNotifier {
3281
3396
  );
3282
3397
  }
3283
3398
 
3399
+ Future<void> hoverDesktopRuntime({required int x, required int y}) async {
3400
+ try {
3401
+ await _backendClient.hoverDesktop(
3402
+ backendUrl,
3403
+ deviceId: selectedDesktopDeviceId,
3404
+ x: x,
3405
+ y: y,
3406
+ );
3407
+ } catch (_) {}
3408
+ }
3409
+
3284
3410
  Future<void> dragDesktopRuntime({
3285
3411
  required int x1,
3286
3412
  required int y1,
@@ -4573,6 +4699,7 @@ class NeoAgentController extends ChangeNotifier {
4573
4699
 
4574
4700
  Future<void> saveSettings({
4575
4701
  required String browserBackend,
4702
+ String? browserExtensionTokenId,
4576
4703
  required String cliBackend,
4577
4704
  String? cliDesktopDeviceId,
4578
4705
  required bool smarterSelector,
@@ -4603,8 +4730,11 @@ class NeoAgentController extends ChangeNotifier {
4603
4730
  final payload = <String, dynamic>{
4604
4731
  'headless_browser': true,
4605
4732
  'browser_backend': browserBackend,
4733
+ if (browserExtensionTokenId != null)
4734
+ 'browser_extension_token_id': browserExtensionTokenId,
4606
4735
  'cli_backend': cliBackend,
4607
- if (cliDesktopDeviceId != null) 'cli_desktop_device_id': cliDesktopDeviceId,
4736
+ if (cliDesktopDeviceId != null)
4737
+ 'cli_desktop_device_id': cliDesktopDeviceId,
4608
4738
  'smarter_model_selector': smarterSelector,
4609
4739
  'enabled_models': enabledModels,
4610
4740
  'default_chat_model': defaultChatModel,
@@ -6170,6 +6300,11 @@ class NeoAgentController extends ChangeNotifier {
6170
6300
  bool get browserExtensionConnected =>
6171
6301
  browserExtensionStatus['connected'] == true;
6172
6302
 
6303
+ String? get browserExtensionTokenId {
6304
+ final v = settings['browser_extension_token_id']?.toString().trim();
6305
+ return (v == null || v.isEmpty || v == 'null') ? null : v;
6306
+ }
6307
+
6173
6308
  bool get smarterSelector => settings['smarter_model_selector'] != false;
6174
6309
 
6175
6310
  Map<String, AiProviderConfig> get aiProviderConfigs {
@@ -6352,7 +6487,9 @@ class NeoAgentController extends ChangeNotifier {
6352
6487
 
6353
6488
  List<ChatEntry> get visibleChatMessages {
6354
6489
  final entries = <ChatEntry>[...chatMessages];
6355
- if (isSendingMessage && activeRun != null && streamingAssistant.trim().isEmpty) {
6490
+ if (isSendingMessage &&
6491
+ activeRun != null &&
6492
+ streamingAssistant.trim().isEmpty) {
6356
6493
  entries.add(
6357
6494
  ChatEntry(
6358
6495
  id: '',