neoagent 2.4.1-beta.26 → 2.4.1-beta.28

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.
@@ -1893,9 +1893,17 @@ class _MessagingCard extends StatelessWidget {
1893
1893
  Widget build(BuildContext context) {
1894
1894
  final connected = status?.isConnected ?? false;
1895
1895
  final configured = status != null && status!.status != 'not_configured';
1896
+ final disabled = status?.status == 'disabled';
1897
+ final canDisconnect = configured && !connected && !disabled;
1898
+ final isDisconnecting = controller.isMessagingPlatformBusy(
1899
+ platform.id,
1900
+ 'disconnect',
1901
+ );
1896
1902
  final accent = platform.accent;
1897
1903
  final actionLabel = connected
1898
1904
  ? 'Connected'
1905
+ : disabled
1906
+ ? 'Disabled'
1899
1907
  : configured
1900
1908
  ? 'Reconnect'
1901
1909
  : 'Connect';
@@ -1960,11 +1968,15 @@ class _MessagingCard extends StatelessWidget {
1960
1968
  _StatusPill(
1961
1969
  label: connected
1962
1970
  ? 'Live'
1971
+ : disabled
1972
+ ? 'Disabled'
1963
1973
  : configured
1964
1974
  ? 'Ready'
1965
1975
  : 'Setup',
1966
1976
  color: connected
1967
1977
  ? _success
1978
+ : disabled
1979
+ ? _textMuted
1968
1980
  : configured
1969
1981
  ? _warning
1970
1982
  : _textMuted,
@@ -2005,15 +2017,24 @@ class _MessagingCard extends StatelessWidget {
2005
2017
  Expanded(
2006
2018
  child: connected
2007
2019
  ? OutlinedButton.icon(
2008
- onPressed: onDisconnect,
2009
- icon: Icon(Icons.link_off_rounded, size: 18),
2020
+ onPressed: isDisconnecting ? null : onDisconnect,
2021
+ icon: isDisconnecting
2022
+ ? SizedBox.square(
2023
+ dimension: 18,
2024
+ child: CircularProgressIndicator(
2025
+ strokeWidth: 2,
2026
+ ),
2027
+ )
2028
+ : Icon(Icons.link_off_rounded, size: 18),
2010
2029
  label: Text(
2011
2030
  'Disconnect',
2012
2031
  overflow: TextOverflow.ellipsis,
2013
2032
  ),
2014
2033
  )
2015
2034
  : FilledButton.icon(
2016
- onPressed: onConnect,
2035
+ onPressed: disabled || isDisconnecting
2036
+ ? null
2037
+ : onConnect,
2017
2038
  icon: Icon(Icons.power_settings_new_rounded, size: 18),
2018
2039
  label: Text(
2019
2040
  actionLabel,
@@ -2022,6 +2043,19 @@ class _MessagingCard extends StatelessWidget {
2022
2043
  style: FilledButton.styleFrom(backgroundColor: accent),
2023
2044
  ),
2024
2045
  ),
2046
+ if (canDisconnect) ...[
2047
+ const SizedBox(width: 8),
2048
+ IconButton.outlined(
2049
+ tooltip: 'Disconnect platform',
2050
+ onPressed: isDisconnecting ? null : onDisconnect,
2051
+ icon: isDisconnecting
2052
+ ? SizedBox.square(
2053
+ dimension: 18,
2054
+ child: CircularProgressIndicator(strokeWidth: 2),
2055
+ )
2056
+ : Icon(Icons.link_off_rounded),
2057
+ ),
2058
+ ],
2025
2059
  const SizedBox(width: 8),
2026
2060
  IconButton.outlined(
2027
2061
  tooltip: 'Access policy',
@@ -63,6 +63,7 @@ class NeoAgentController extends ChangeNotifier {
63
63
  final Set<String> _backgroundRunIds = <String>{};
64
64
  final Set<String> _voiceRunIds = <String>{};
65
65
  final Set<String> _busyOfficialIntegrationKeys = <String>{};
66
+ final Set<String> _busyMessagingPlatformKeys = <String>{};
66
67
  final Map<String, DateTime> _manualRunCooldowns = <String, DateTime>{};
67
68
  static const Duration _manualRunCooldownDuration = Duration(seconds: 10);
68
69
  static const Duration _homeWidgetSyncCooldown = Duration(seconds: 5);
@@ -70,6 +71,7 @@ class NeoAgentController extends ChangeNotifier {
70
71
  int _authCycle = 0;
71
72
  bool _isPollingQrLogin = false;
72
73
  bool _socketHasConnectedOnce = false;
74
+ bool _onboardingManuallyReopened = false;
73
75
  List<LogEntry> _serverLogs = const <LogEntry>[];
74
76
  List<LogEntry> _clientLogs = const <LogEntry>[];
75
77
 
@@ -236,6 +238,8 @@ class NeoAgentController extends ChangeNotifier {
236
238
 
237
239
  bool isOfficialIntegrationBusy(String key) =>
238
240
  _busyOfficialIntegrationKeys.contains(key);
241
+ bool isMessagingPlatformBusy(String platform, String action) =>
242
+ _busyMessagingPlatformKeys.contains('$platform:$action');
239
243
 
240
244
  String get chatComposerHint => hasLiveRun
241
245
  ? 'Send a steering update or next-up note for the current run...'
@@ -812,6 +816,7 @@ class NeoAgentController extends ChangeNotifier {
812
816
  status['user'] as Map<String, dynamic>,
813
817
  );
814
818
  isAuthenticated = true;
819
+ _syncOnboardingFromAccount();
815
820
  }
816
821
  if (isAuthenticated) {
817
822
  unawaited(refresh());
@@ -1350,9 +1355,7 @@ class NeoAgentController extends ChangeNotifier {
1350
1355
  pendingTwoFactorUsername = '';
1351
1356
  password = '';
1352
1357
 
1353
- final bool backendCompletedOnboarding =
1354
- user?['hasCompletedOnboarding'] == true;
1355
- showOnboarding = isRegistration || !backendCompletedOnboarding;
1358
+ _syncOnboardingFromAccount();
1356
1359
 
1357
1360
  _clearQrLoginChallenge();
1358
1361
  await _persistCredentials();
@@ -1596,6 +1599,7 @@ class NeoAgentController extends ChangeNotifier {
1596
1599
  }
1597
1600
 
1598
1601
  Future<void> dismissOnboarding() async {
1602
+ _onboardingManuallyReopened = false;
1599
1603
  showOnboarding = false;
1600
1604
  notifyListeners();
1601
1605
  try {
@@ -1612,10 +1616,23 @@ class NeoAgentController extends ChangeNotifier {
1612
1616
  }
1613
1617
 
1614
1618
  void reopenOnboarding() {
1619
+ _onboardingManuallyReopened = true;
1615
1620
  showOnboarding = true;
1616
1621
  notifyListeners();
1617
1622
  }
1618
1623
 
1624
+ void _syncOnboardingFromAccount() {
1625
+ final hasCompletedOnboarding = user?['hasCompletedOnboarding'] == true;
1626
+ if (hasCompletedOnboarding) {
1627
+ if (!_onboardingManuallyReopened) {
1628
+ showOnboarding = false;
1629
+ }
1630
+ return;
1631
+ }
1632
+ _onboardingManuallyReopened = false;
1633
+ showOnboarding = true;
1634
+ }
1635
+
1619
1636
  void _clearAuthenticatedState() {
1620
1637
  _disconnectSocket();
1621
1638
  _updatePollTimer?.cancel();
@@ -1623,6 +1640,8 @@ class NeoAgentController extends ChangeNotifier {
1623
1640
  _clearQrLoginChallenge();
1624
1641
  isAuthenticated = false;
1625
1642
  isRefreshing = false;
1643
+ _onboardingManuallyReopened = false;
1644
+ _busyMessagingPlatformKeys.clear();
1626
1645
  isAwaitingTwoFactor = false;
1627
1646
  pendingTwoFactorUsername = '';
1628
1647
  errorMessage = null;
@@ -2080,6 +2099,7 @@ class NeoAgentController extends ChangeNotifier {
2080
2099
  user = Map<String, dynamic>.from(
2081
2100
  authStatus['user'] as Map<String, dynamic>,
2082
2101
  );
2102
+ _syncOnboardingFromAccount();
2083
2103
 
2084
2104
  final profilesResponse = await _backendClient.fetchAgentProfiles(
2085
2105
  backendUrl,
@@ -5499,12 +5519,28 @@ class NeoAgentController extends ChangeNotifier {
5499
5519
  }
5500
5520
 
5501
5521
  Future<void> disconnectMessagingPlatform(String platform) async {
5502
- await _backendClient.disconnectMessagingPlatform(
5503
- backendUrl,
5504
- platform: platform,
5505
- agentId: _scopedAgentId,
5506
- );
5507
- await refreshMessaging();
5522
+ final busyKey = '$platform:disconnect';
5523
+ if (_busyMessagingPlatformKeys.contains(busyKey)) {
5524
+ return;
5525
+ }
5526
+
5527
+ _busyMessagingPlatformKeys.add(busyKey);
5528
+ errorMessage = null;
5529
+ notifyListeners();
5530
+
5531
+ try {
5532
+ await _backendClient.disconnectMessagingPlatform(
5533
+ backendUrl,
5534
+ platform: platform,
5535
+ agentId: _scopedAgentId,
5536
+ );
5537
+ await refreshMessaging();
5538
+ } catch (error) {
5539
+ errorMessage = _friendlyErrorMessage(error);
5540
+ } finally {
5541
+ _busyMessagingPlatformKeys.remove(busyKey);
5542
+ notifyListeners();
5543
+ }
5508
5544
  }
5509
5545
 
5510
5546
  Future<void> logoutMessagingPlatform(String platform) async {
@@ -1345,8 +1345,8 @@ class _LogoBadgeState extends State<_LogoBadge> {
1345
1345
  ),
1346
1346
  child: Image.asset(
1347
1347
  isDark
1348
- ? 'assets/branding/app_icon_512.png'
1349
- : 'assets/branding/app_icon_light_512.png',
1348
+ ? 'assets/branding/app_icon_1024.png'
1349
+ : 'assets/branding/app_icon_light_1024.png',
1350
1350
  width: widget.size,
1351
1351
  height: widget.size,
1352
1352
  filterQuality: FilterQuality.high,
@@ -56,8 +56,10 @@ flutter:
56
56
  - web/icons/Icon-192.png
57
57
  - assets/branding/app_icon_256.png
58
58
  - assets/branding/app_icon_512.png
59
+ - assets/branding/app_icon_1024.png
59
60
  - assets/branding/app_icon_light_256.png
60
61
  - assets/branding/app_icon_light_512.png
62
+ - assets/branding/app_icon_light_1024.png
61
63
  - assets/branding/tray_icon_template.png
62
64
  - assets/branding/tray_icon_light_template.png
63
65
  - assets/branding/onboarding_intro.mp4
@@ -28,6 +28,7 @@ SOURCE_PNG_SIZES = (16, 32, 48, 64, 128, 180, 192, 256, 512, 1024)
28
28
  TRANSPARENT = (0, 0, 0, 0)
29
29
  WHITE = (255, 255, 255, 255)
30
30
  BLACK = (0, 0, 0, 255)
31
+ TRAY_TEMPLATE_SIZE = 256
31
32
 
32
33
 
33
34
  def ensure_dirs() -> None:
@@ -141,7 +142,8 @@ def make_tray_template(
141
142
  )
142
143
 
143
144
  # Keep the symbol optically centered inside the menu-bar bounds.
144
- return img.crop((0, 2, size, size + 2))
145
+ vertical_offset = round(size * 0.03125)
146
+ return img.crop((0, vertical_offset, size, size + vertical_offset))
145
147
 
146
148
 
147
149
  def main() -> None:
@@ -151,8 +153,14 @@ def main() -> None:
151
153
  save_icon(BRANDING_DIR / f"app_icon_{size}.png", size)
152
154
  save_icon(BRANDING_DIR / f"app_icon_light_{size}.png", size)
153
155
 
154
- make_tray_template(64).save(BRANDING_DIR / "tray_icon_template.png", format="PNG")
155
- make_tray_template(64, WHITE).save(BRANDING_DIR / "tray_icon_light_template.png", format="PNG")
156
+ make_tray_template(TRAY_TEMPLATE_SIZE).save(
157
+ BRANDING_DIR / "tray_icon_template.png",
158
+ format="PNG",
159
+ )
160
+ make_tray_template(TRAY_TEMPLATE_SIZE, WHITE).save(
161
+ BRANDING_DIR / "tray_icon_light_template.png",
162
+ format="PNG",
163
+ )
156
164
 
157
165
  for size in (16, 32, 64, 128, 256, 512, 1024):
158
166
  save_icon(MAC_ICON_DIR / f"app_icon_{size}.png", size)
@@ -192,7 +200,7 @@ def main() -> None:
192
200
  save_icon(STATIC_IMG_DIR / "app_icon.png", 512)
193
201
  save_icon(STATIC_IMG_DIR / "app_icon_light.png", 512)
194
202
  save_icon(SERVER_PUBLIC_DIR / "assets" / "assets" / "branding" / "app_icon_256.png", 256)
195
- make_tray_template(64).save(
203
+ make_tray_template(TRAY_TEMPLATE_SIZE).save(
196
204
  SERVER_PUBLIC_DIR / "assets" / "assets" / "branding" / "tray_icon_template.png",
197
205
  format="PNG",
198
206
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.4.1-beta.26",
3
+ "version": "2.4.1-beta.28",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "server/index.js",
@@ -1 +1 @@
1
- 1d4acb4ab8222124f88b6c18b5b8e9e3
1
+ 8b538b57a9cbb726db27657b5066489d
@@ -1 +1 @@
1
-
1
+
@@ -1 +1 @@
1
- "DQwHIGFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8yNTYucG5nDAENAQcFYXNzZXQHIGFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8yNTYucG5nByBhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fNTEyLnBuZwwBDQEHBWFzc2V0ByBhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fNTEyLnBuZwcmYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzI1Ni5wbmcMAQ0BBwVhc3NldAcmYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzI1Ni5wbmcHJmFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF81MTIucG5nDAENAQcFYXNzZXQHJmFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF81MTIucG5nByRhc3NldHMvYnJhbmRpbmcvb25ib2FyZGluZ19pbnRyby5tcDQMAQ0BBwVhc3NldAckYXNzZXRzL2JyYW5kaW5nL29uYm9hcmRpbmdfaW50cm8ubXA0Byxhc3NldHMvYnJhbmRpbmcvdHJheV9pY29uX2xpZ2h0X3RlbXBsYXRlLnBuZwwBDQEHBWFzc2V0Byxhc3NldHMvYnJhbmRpbmcvdHJheV9pY29uX2xpZ2h0X3RlbXBsYXRlLnBuZwcmYXNzZXRzL2JyYW5kaW5nL3RyYXlfaWNvbl90ZW1wbGF0ZS5wbmcMAQ0BBwVhc3NldAcmYXNzZXRzL2JyYW5kaW5nL3RyYXlfaWNvbl90ZW1wbGF0ZS5wbmcHMnBhY2thZ2VzL2N1cGVydGlub19pY29ucy9hc3NldHMvQ3VwZXJ0aW5vSWNvbnMudHRmDAENAQcFYXNzZXQHMnBhY2thZ2VzL2N1cGVydGlub19pY29ucy9hc3NldHMvQ3VwZXJ0aW5vSWNvbnMudHRmByxwYWNrYWdlcy9taXhwYW5lbF9mbHV0dGVyL2Fzc2V0cy9taXhwYW5lbC5qcwwBDQEHBWFzc2V0ByxwYWNrYWdlcy9taXhwYW5lbF9mbHV0dGVyL2Fzc2V0cy9taXhwYW5lbC5qcwc3cGFja2FnZXMvcmVjb3JkX3dlYi9hc3NldHMvanMvcmVjb3JkLmZpeHdlYm1kdXJhdGlvbi5qcwwBDQEHBWFzc2V0BzdwYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQuZml4d2VibWR1cmF0aW9uLmpzBy9wYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQud29ya2xldC5qcwwBDQEHBWFzc2V0By9wYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQud29ya2xldC5qcwcWd2ViL2ljb25zL0ljb24tMTkyLnBuZwwBDQEHBWFzc2V0BxZ3ZWIvaWNvbnMvSWNvbi0xOTIucG5n"
1
+ "DQ4HIWFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8xMDI0LnBuZwwBDQEHBWFzc2V0ByFhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fMTAyNC5wbmcHIGFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8yNTYucG5nDAENAQcFYXNzZXQHIGFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl8yNTYucG5nByBhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fNTEyLnBuZwwBDQEHBWFzc2V0ByBhc3NldHMvYnJhbmRpbmcvYXBwX2ljb25fNTEyLnBuZwcnYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzEwMjQucG5nDAENAQcFYXNzZXQHJ2Fzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF8xMDI0LnBuZwcmYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzI1Ni5wbmcMAQ0BBwVhc3NldAcmYXNzZXRzL2JyYW5kaW5nL2FwcF9pY29uX2xpZ2h0XzI1Ni5wbmcHJmFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF81MTIucG5nDAENAQcFYXNzZXQHJmFzc2V0cy9icmFuZGluZy9hcHBfaWNvbl9saWdodF81MTIucG5nByRhc3NldHMvYnJhbmRpbmcvb25ib2FyZGluZ19pbnRyby5tcDQMAQ0BBwVhc3NldAckYXNzZXRzL2JyYW5kaW5nL29uYm9hcmRpbmdfaW50cm8ubXA0Byxhc3NldHMvYnJhbmRpbmcvdHJheV9pY29uX2xpZ2h0X3RlbXBsYXRlLnBuZwwBDQEHBWFzc2V0Byxhc3NldHMvYnJhbmRpbmcvdHJheV9pY29uX2xpZ2h0X3RlbXBsYXRlLnBuZwcmYXNzZXRzL2JyYW5kaW5nL3RyYXlfaWNvbl90ZW1wbGF0ZS5wbmcMAQ0BBwVhc3NldAcmYXNzZXRzL2JyYW5kaW5nL3RyYXlfaWNvbl90ZW1wbGF0ZS5wbmcHMnBhY2thZ2VzL2N1cGVydGlub19pY29ucy9hc3NldHMvQ3VwZXJ0aW5vSWNvbnMudHRmDAENAQcFYXNzZXQHMnBhY2thZ2VzL2N1cGVydGlub19pY29ucy9hc3NldHMvQ3VwZXJ0aW5vSWNvbnMudHRmByxwYWNrYWdlcy9taXhwYW5lbF9mbHV0dGVyL2Fzc2V0cy9taXhwYW5lbC5qcwwBDQEHBWFzc2V0ByxwYWNrYWdlcy9taXhwYW5lbF9mbHV0dGVyL2Fzc2V0cy9taXhwYW5lbC5qcwc3cGFja2FnZXMvcmVjb3JkX3dlYi9hc3NldHMvanMvcmVjb3JkLmZpeHdlYm1kdXJhdGlvbi5qcwwBDQEHBWFzc2V0BzdwYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQuZml4d2VibWR1cmF0aW9uLmpzBy9wYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQud29ya2xldC5qcwwBDQEHBWFzc2V0By9wYWNrYWdlcy9yZWNvcmRfd2ViL2Fzc2V0cy9qcy9yZWNvcmQud29ya2xldC5qcwcWd2ViL2ljb25zL0ljb24tMTkyLnBuZwwBDQEHBWFzc2V0BxZ3ZWIvaWNvbnMvSWNvbi0xOTIucG5n"
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"c416acfeb8126e097f758c664aaa3da929e27d
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "1380510725" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "4255884063" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });