@mindexec/cli 0.2.7 → 0.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -12105,6 +12105,21 @@
12105
12105
  return select;
12106
12106
  }
12107
12107
 
12108
+ const REMOTE_FLEET_MONITOR_REFRESH_MS = 5000;
12109
+ const REMOTE_FLEET_LIVE_REFRESH_MS = 1000;
12110
+
12111
+ function clearRemoteFleetTimers(bodyView) {
12112
+ if (!bodyView) return;
12113
+ if (bodyView._remoteFleetLiveRefreshTimer) {
12114
+ clearInterval(bodyView._remoteFleetLiveRefreshTimer);
12115
+ bodyView._remoteFleetLiveRefreshTimer = null;
12116
+ }
12117
+ if (bodyView._remoteFleetMonitorRefreshTimer) {
12118
+ clearInterval(bodyView._remoteFleetMonitorRefreshTimer);
12119
+ bodyView._remoteFleetMonitorRefreshTimer = null;
12120
+ }
12121
+ }
12122
+
12108
12123
  function getRemoteFleetDeviceField(device, camelKey, pascalKey, fallback = '') {
12109
12124
  const value = device?.[camelKey] ?? device?.[pascalKey] ?? fallback;
12110
12125
  return value === undefined || value === null ? fallback : value;
@@ -12148,6 +12163,72 @@
12148
12163
  return getRemoteFleetDeviceField(device, 'liveStreamActive', 'LiveStreamActive', false) === true;
12149
12164
  }
12150
12165
 
12166
+ function isRemoteFleetThumbnailCapable(device) {
12167
+ return getRemoteFleetDeviceField(device, 'thumbnailEnabled', 'ThumbnailEnabled', false) === true;
12168
+ }
12169
+
12170
+ function getRemoteFleetGroupInfo(device, groupMode) {
12171
+ const mode = String(groupMode || 'none');
12172
+ const connected = isRemoteFleetDeviceConnected(device);
12173
+ const latestTaskStatus = String(getRemoteFleetDeviceField(device, 'latestTaskStatus', 'LatestTaskStatus', '')).toLowerCase();
12174
+ const latestTaskError = String(getRemoteFleetDeviceField(device, 'latestTaskError', 'LatestTaskError', ''));
12175
+ const platform = String(getRemoteFleetDeviceField(device, 'platform', 'Platform', '') || 'unknown').toLowerCase();
12176
+
12177
+ switch (mode) {
12178
+ case 'status':
12179
+ return connected
12180
+ ? { key: 'status-online', label: 'Online', order: 0 }
12181
+ : { key: 'status-offline', label: 'Offline', order: 9 };
12182
+ case 'activity':
12183
+ if (isRemoteFleetLiveActive(device)) {
12184
+ return { key: 'activity-live', label: 'Live streams', order: 0 };
12185
+ }
12186
+ if (latestTaskError || latestTaskStatus === 'failed') {
12187
+ return { key: 'activity-issues', label: 'Needs attention', order: 1 };
12188
+ }
12189
+ if (latestTaskStatus && latestTaskStatus !== 'completed') {
12190
+ return { key: 'activity-working', label: 'Task in progress', order: 2 };
12191
+ }
12192
+ if (hasRemoteFleetThumbnail(device) || hasRemoteFleetLiveFrame(device)) {
12193
+ return { key: 'activity-frames', label: 'Recent frames', order: 3 };
12194
+ }
12195
+ return connected
12196
+ ? { key: 'activity-idle', label: 'Online idle', order: 4 }
12197
+ : { key: 'activity-offline', label: 'Offline', order: 9 };
12198
+ case 'platform':
12199
+ return {
12200
+ key: `platform-${platform || 'unknown'}`,
12201
+ label: platform ? platform.toUpperCase() : 'Unknown platform',
12202
+ order: connected ? 0 : 8
12203
+ };
12204
+ case 'capability':
12205
+ if (!connected) {
12206
+ return { key: 'capability-offline', label: 'Offline', order: 9 };
12207
+ }
12208
+ if (isRemoteFleetDeviceAiCapable(device)) {
12209
+ return { key: 'capability-ai', label: 'AI assist ready', order: 0 };
12210
+ }
12211
+ if (isRemoteFleetDeviceTaskCapable(device)) {
12212
+ return { key: 'capability-task', label: 'Task capable', order: 1 };
12213
+ }
12214
+ if (isRemoteFleetThumbnailCapable(device)) {
12215
+ return { key: 'capability-monitor', label: 'Monitor only', order: 2 };
12216
+ }
12217
+ return { key: 'capability-status', label: 'Status only', order: 3 };
12218
+ case 'none':
12219
+ default:
12220
+ return { key: '', label: '', order: 0 };
12221
+ }
12222
+ }
12223
+
12224
+ function compareRemoteFleetGroups(left, right, groupMode) {
12225
+ const leftGroup = getRemoteFleetGroupInfo(left, groupMode);
12226
+ const rightGroup = getRemoteFleetGroupInfo(right, groupMode);
12227
+ return (leftGroup.order - rightGroup.order)
12228
+ || leftGroup.label.localeCompare(rightGroup.label)
12229
+ || leftGroup.key.localeCompare(rightGroup.key);
12230
+ }
12231
+
12151
12232
  function getRemoteFleetTimestampMs(value) {
12152
12233
  const timestamp = Date.parse(String(value || ''));
12153
12234
  return Number.isFinite(timestamp) ? timestamp : 0;
@@ -12221,21 +12302,27 @@
12221
12302
 
12222
12303
  function renderRemoteFleetMonitor(bodyView, nodeModel) {
12223
12304
  if (!bodyView) return;
12224
- if (bodyView._remoteFleetLiveRefreshTimer) {
12225
- clearInterval(bodyView._remoteFleetLiveRefreshTimer);
12226
- bodyView._remoteFleetLiveRefreshTimer = null;
12227
- }
12305
+ clearRemoteFleetTimers(bodyView);
12228
12306
 
12229
12307
  const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
12230
12308
  const searchState = bodyView.dataset.remoteFleetSearch || '';
12231
12309
  const filterState = bodyView.dataset.remoteFleetFilter || 'all';
12232
12310
  const sortState = bodyView.dataset.remoteFleetSort || 'status';
12311
+ const groupState = bodyView.dataset.remoteFleetGroup || 'none';
12233
12312
  const densityState = bodyView.dataset.remoteFleetDensity || 'cards';
12234
12313
  const aiAssistState = bodyView.dataset.remoteFleetAiAssist === 'true';
12314
+ const autoMonitorState = bodyView.dataset.remoteFleetAutoMonitor !== 'false';
12235
12315
  const focusState = bodyView.dataset.remoteFleetFocusDeviceId || '';
12236
- const devices = [...parseRemoteFleetDevices(nodeModel)]
12316
+ const sortedDevices = [...parseRemoteFleetDevices(nodeModel)]
12237
12317
  .sort((left, right) => compareRemoteFleetDevices(left, right, sortState));
12318
+ const devices = groupState === 'none'
12319
+ ? sortedDevices
12320
+ : [...sortedDevices].sort((left, right) =>
12321
+ compareRemoteFleetGroups(left, right, groupState)
12322
+ || compareRemoteFleetDevices(left, right, sortState));
12238
12323
  const hasActiveLiveStream = devices.some(isRemoteFleetLiveActive);
12324
+ const hasMonitorTargets = devices.some(device =>
12325
+ isRemoteFleetDeviceConnected(device) && isRemoteFleetThumbnailCapable(device));
12239
12326
  const focusedDevice = devices.find(device => getRemoteFleetDeviceId(device) === focusState)
12240
12327
  || devices.find(device => isRemoteFleetLiveActive(device))
12241
12328
  || null;
@@ -12289,7 +12376,7 @@
12289
12376
  const commandRow = document.createElement('div');
12290
12377
  commandRow.style.cssText = `
12291
12378
  display: grid;
12292
- grid-template-columns: minmax(0, 1fr) auto auto;
12379
+ grid-template-columns: minmax(0, 1fr) auto auto auto;
12293
12380
  gap: 8px;
12294
12381
  align-items: center;
12295
12382
  flex: 0 0 auto;
@@ -12314,7 +12401,42 @@
12314
12401
 
12315
12402
  const copyButton = createRemoteFleetButton('Copy', 'Copy agent command', 'copy-command');
12316
12403
  const refreshButton = createRemoteFleetButton('Refresh', 'Refresh remote devices', 'refresh');
12404
+ const autoMonitorLabel = document.createElement('label');
12405
+ autoMonitorLabel.title = 'Refresh stale thumbnails on a bounded timer';
12406
+ autoMonitorLabel.style.cssText = `
12407
+ display: inline-flex;
12408
+ align-items: center;
12409
+ justify-content: center;
12410
+ gap: 6px;
12411
+ height: 34px;
12412
+ padding: 0 9px;
12413
+ border-radius: 7px;
12414
+ border: 1px solid rgba(14, 165, 233, 0.28);
12415
+ background: ${autoMonitorState ? 'rgba(240, 249, 255, 0.92)' : 'rgba(248, 250, 252, 0.92)'};
12416
+ color: ${autoMonitorState ? '#0369a1' : '#475569'};
12417
+ font-size: 11px;
12418
+ font-weight: 900;
12419
+ letter-spacing: 0;
12420
+ cursor: pointer;
12421
+ pointer-events: auto;
12422
+ user-select: none;
12423
+ `;
12424
+ const autoMonitorToggle = document.createElement('input');
12425
+ autoMonitorToggle.type = 'checkbox';
12426
+ autoMonitorToggle.checked = autoMonitorState;
12427
+ autoMonitorToggle.dataset.remoteFleetAutoToggle = 'true';
12428
+ autoMonitorToggle.style.cssText = `
12429
+ width: 14px;
12430
+ height: 14px;
12431
+ margin: 0;
12432
+ accent-color: #0284c7;
12433
+ `;
12434
+ const autoMonitorText = document.createElement('span');
12435
+ autoMonitorText.textContent = 'Auto';
12436
+ autoMonitorLabel.appendChild(autoMonitorToggle);
12437
+ autoMonitorLabel.appendChild(autoMonitorText);
12317
12438
  commandRow.appendChild(commandText);
12439
+ commandRow.appendChild(autoMonitorLabel);
12318
12440
  commandRow.appendChild(copyButton);
12319
12441
  commandRow.appendChild(refreshButton);
12320
12442
  bodyView.appendChild(commandRow);
@@ -12322,7 +12444,7 @@
12322
12444
  const filterRow = document.createElement('div');
12323
12445
  filterRow.style.cssText = `
12324
12446
  display: grid;
12325
- grid-template-columns: minmax(150px, 1.2fr) minmax(96px, 0.7fr) minmax(96px, 0.7fr) minmax(84px, 0.55fr) auto;
12447
+ grid-template-columns: minmax(140px, 1.25fr) minmax(86px, 0.62fr) minmax(86px, 0.62fr) minmax(98px, 0.7fr) minmax(78px, 0.5fr) auto;
12326
12448
  gap: 8px;
12327
12449
  align-items: center;
12328
12450
  flex: 0 0 auto;
@@ -12370,6 +12492,14 @@
12370
12492
  { value: 'task', label: 'Task' }
12371
12493
  ], sortState, 'Device sort');
12372
12494
 
12495
+ const groupSelect = createRemoteFleetSelect([
12496
+ { value: 'none', label: 'No group' },
12497
+ { value: 'status', label: 'Status' },
12498
+ { value: 'activity', label: 'Activity' },
12499
+ { value: 'platform', label: 'Platform' },
12500
+ { value: 'capability', label: 'Capability' }
12501
+ ], groupState, 'Device grouping');
12502
+
12373
12503
  const densitySelect = createRemoteFleetSelect([
12374
12504
  { value: 'cards', label: 'Cards' },
12375
12505
  { value: 'dense', label: 'Dense' }
@@ -12392,6 +12522,7 @@
12392
12522
  filterRow.appendChild(searchInput);
12393
12523
  filterRow.appendChild(filterSelect);
12394
12524
  filterRow.appendChild(sortSelect);
12525
+ filterRow.appendChild(groupSelect);
12395
12526
  filterRow.appendChild(densitySelect);
12396
12527
  filterRow.appendChild(matchCount);
12397
12528
  bodyView.appendChild(filterRow);
@@ -12672,6 +12803,25 @@
12672
12803
  `;
12673
12804
  grid.appendChild(empty);
12674
12805
  } else {
12806
+ const groupStats = new Map();
12807
+ if (groupState !== 'none') {
12808
+ devices.forEach(device => {
12809
+ const group = getRemoteFleetGroupInfo(device, groupState);
12810
+ if (!group.key) return;
12811
+ const stat = groupStats.get(group.key) || {
12812
+ label: group.label,
12813
+ total: 0,
12814
+ connected: 0
12815
+ };
12816
+ stat.total += 1;
12817
+ if (isRemoteFleetDeviceConnected(device)) {
12818
+ stat.connected += 1;
12819
+ }
12820
+ groupStats.set(group.key, stat);
12821
+ });
12822
+ }
12823
+
12824
+ let lastGroupKey = '';
12675
12825
  devices.forEach(device => {
12676
12826
  const connectedDevice = isRemoteFleetDeviceConnected(device);
12677
12827
  const name = getRemoteFleetDeviceName(device);
@@ -12699,9 +12849,44 @@
12699
12849
  const latestTaskUpdatedAt = String(device?.latestTaskUpdatedAt || device?.LatestTaskUpdatedAt || '');
12700
12850
  const latestTaskError = String(device?.latestTaskError || device?.LatestTaskError || '');
12701
12851
  const latestTaskResult = String(device?.latestTaskResultSummary || device?.LatestTaskResultSummary || '');
12852
+ const groupInfo = getRemoteFleetGroupInfo(device, groupState);
12853
+ if (groupState !== 'none' && groupInfo.key && groupInfo.key !== lastGroupKey) {
12854
+ const stat = groupStats.get(groupInfo.key) || { label: groupInfo.label, total: 0, connected: 0 };
12855
+ const groupHeader = document.createElement('div');
12856
+ groupHeader.dataset.remoteFleetGroupHeader = 'true';
12857
+ groupHeader.dataset.remoteFleetGroupKey = groupInfo.key;
12858
+ groupHeader.style.cssText = `
12859
+ grid-column: 1 / -1;
12860
+ display: flex;
12861
+ align-items: center;
12862
+ justify-content: space-between;
12863
+ gap: 10px;
12864
+ min-height: 30px;
12865
+ padding: 6px 9px;
12866
+ border-radius: 7px;
12867
+ border: 1px solid rgba(148, 163, 184, 0.22);
12868
+ background: rgba(226, 232, 240, 0.58);
12869
+ color: #334155;
12870
+ font-size: 11px;
12871
+ font-weight: 950;
12872
+ letter-spacing: 0;
12873
+ `;
12874
+ const groupLabel = document.createElement('span');
12875
+ groupLabel.textContent = stat.label || groupInfo.label;
12876
+ groupLabel.style.cssText = 'min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
12877
+ const groupCount = document.createElement('span');
12878
+ groupCount.dataset.remoteFleetGroupCount = 'true';
12879
+ groupCount.textContent = `${stat.total} device${stat.total === 1 ? '' : 's'}${stat.connected !== stat.total ? ` - ${stat.connected} online` : ''}`;
12880
+ groupCount.style.cssText = 'flex:0 0 auto;color:#64748b;font-size:10px;font-weight:900;white-space:nowrap;';
12881
+ groupHeader.appendChild(groupLabel);
12882
+ groupHeader.appendChild(groupCount);
12883
+ grid.appendChild(groupHeader);
12884
+ lastGroupKey = groupInfo.key;
12885
+ }
12702
12886
  const card = document.createElement('article');
12703
12887
  card.dataset.deviceId = deviceId;
12704
12888
  card.dataset.remoteFleetSearchText = buildRemoteFleetSearchText(device);
12889
+ card.dataset.remoteFleetGroupKey = groupInfo.key || '';
12705
12890
  card.dataset.remoteFleetConnected = connectedDevice ? 'true' : 'false';
12706
12891
  card.dataset.remoteFleetTaskCapable = taskEnabled ? 'true' : 'false';
12707
12892
  card.dataset.remoteFleetAiCapable = aiAssistEnabled ? 'true' : 'false';
@@ -13010,8 +13195,7 @@
13010
13195
  bodyView.appendChild(grid);
13011
13196
 
13012
13197
  const footer = document.createElement('div');
13013
- footer.textContent = `Endpoint ${endpoint} · refreshed ${formatRemoteFleetAge(refreshedAt)}`;
13014
- footer.textContent = `Endpoint ${endpoint} - all devices, no paging - refreshed ${formatRemoteFleetAge(refreshedAt)}`;
13198
+ footer.textContent = `Endpoint ${endpoint} - all devices, no paging - group ${groupState} - ${autoMonitorState ? 'auto monitor' : 'manual'} - refreshed ${formatRemoteFleetAge(refreshedAt)}`;
13015
13199
  footer.style.cssText = `
13016
13200
  flex: 0 0 auto;
13017
13201
  color: #64748b;
@@ -13048,6 +13232,20 @@
13048
13232
  const readTaskInstruction = () => String(taskInput.value || '').trim();
13049
13233
  const useAiAssist = () => aiToggle.checked === true;
13050
13234
  const getDeviceCards = () => Array.from(grid.querySelectorAll('article[data-device-id]'));
13235
+ const refreshRemoteFleetNode = async () => {
13236
+ if (bodyView._remoteFleetRefreshInFlight === true) {
13237
+ return null;
13238
+ }
13239
+
13240
+ bodyView._remoteFleetRefreshInFlight = true;
13241
+ try {
13242
+ const result = await invokeDotNetAsync('RefreshRemoteFleetMonitorNodeFromJs', nodeId);
13243
+ await syncRemoteFleetNodeStateFromResult(result);
13244
+ return result;
13245
+ } finally {
13246
+ bodyView._remoteFleetRefreshInFlight = false;
13247
+ }
13248
+ };
13051
13249
  const getVisibleEligibleDeviceIds = () => {
13052
13250
  const wantsAi = useAiAssist();
13053
13251
  return getDeviceCards()
@@ -13090,6 +13288,18 @@
13090
13288
  }
13091
13289
  });
13092
13290
 
13291
+ grid.querySelectorAll('[data-remote-fleet-group-header="true"]').forEach(header => {
13292
+ const key = String(header.dataset.remoteFleetGroupKey || '');
13293
+ const groupCards = getDeviceCards().filter(card => String(card.dataset.remoteFleetGroupKey || '') === key);
13294
+ const visibleCards = groupCards.filter(card => card.style.display !== 'none').length;
13295
+ header.style.display = visibleCards > 0 ? 'flex' : 'none';
13296
+ const countEl = header.querySelector('[data-remote-fleet-group-count="true"]');
13297
+ if (countEl) {
13298
+ countEl.textContent = `${visibleCards}/${groupCards.length}`;
13299
+ countEl.title = `${visibleCards} visible in this group, ${groupCards.length} total`;
13300
+ }
13301
+ });
13302
+
13093
13303
  const noMatch = grid.querySelector('[data-remote-fleet-no-match="true"]');
13094
13304
  if (noMatch) {
13095
13305
  noMatch.style.display = devices.length > 0 && visible === 0 ? 'flex' : 'none';
@@ -13115,11 +13325,17 @@
13115
13325
  bodyView.dataset.remoteFleetSearch = searchText;
13116
13326
  bodyView.dataset.remoteFleetFilter = filterMode;
13117
13327
  bodyView.dataset.remoteFleetSort = String(sortSelect.value || 'status');
13328
+ bodyView.dataset.remoteFleetGroup = String(groupSelect.value || 'none');
13118
13329
  bodyView.dataset.remoteFleetDensity = String(densitySelect.value || 'cards');
13119
13330
  bodyView.dataset.remoteFleetAiAssist = wantsAi ? 'true' : 'false';
13120
13331
  };
13121
13332
 
13122
- [searchInput, filterSelect, sortSelect, densitySelect, aiToggle].forEach(control => {
13333
+ [searchInput, filterSelect, sortSelect, groupSelect, densitySelect, aiToggle].forEach(control => {
13334
+ ['mousedown', 'mouseup', 'click', 'dblclick', 'keydown'].forEach(eventName => {
13335
+ control.addEventListener(eventName, event => event.stopPropagation());
13336
+ });
13337
+ });
13338
+ [autoMonitorLabel, autoMonitorToggle].forEach(control => {
13123
13339
  ['mousedown', 'mouseup', 'click', 'dblclick', 'keydown'].forEach(eventName => {
13124
13340
  control.addEventListener(eventName, event => event.stopPropagation());
13125
13341
  });
@@ -13128,10 +13344,18 @@
13128
13344
  searchInput.addEventListener('input', applyRemoteFleetFilters);
13129
13345
  filterSelect.addEventListener('change', applyRemoteFleetFilters);
13130
13346
  aiToggle.addEventListener('change', applyRemoteFleetFilters);
13347
+ autoMonitorToggle.addEventListener('change', () => {
13348
+ bodyView.dataset.remoteFleetAutoMonitor = autoMonitorToggle.checked ? 'true' : 'false';
13349
+ renderRemoteFleetMonitor(bodyView, nodeModel);
13350
+ });
13131
13351
  sortSelect.addEventListener('change', () => {
13132
13352
  bodyView.dataset.remoteFleetSort = String(sortSelect.value || 'status');
13133
13353
  renderRemoteFleetMonitor(bodyView, nodeModel);
13134
13354
  });
13355
+ groupSelect.addEventListener('change', () => {
13356
+ bodyView.dataset.remoteFleetGroup = String(groupSelect.value || 'none');
13357
+ renderRemoteFleetMonitor(bodyView, nodeModel);
13358
+ });
13135
13359
  densitySelect.addEventListener('change', () => {
13136
13360
  bodyView.dataset.remoteFleetDensity = String(densitySelect.value || 'cards');
13137
13361
  renderRemoteFleetMonitor(bodyView, nodeModel);
@@ -13200,9 +13424,11 @@
13200
13424
  event.preventDefault();
13201
13425
  event.stopPropagation();
13202
13426
  refreshButton.disabled = true;
13203
- const result = await invokeDotNetAsync('RefreshRemoteFleetMonitorNodeFromJs', nodeId);
13204
- await syncRemoteFleetNodeStateFromResult(result);
13205
- refreshButton.disabled = false;
13427
+ try {
13428
+ await refreshRemoteFleetNode();
13429
+ } finally {
13430
+ refreshButton.disabled = false;
13431
+ }
13206
13432
  });
13207
13433
 
13208
13434
  bodyView.querySelectorAll('[data-remote-fleet-action="live-focus"]').forEach(button => {
@@ -13314,19 +13540,29 @@
13314
13540
  if (hasActiveLiveStream) {
13315
13541
  bodyView._remoteFleetLiveRefreshTimer = setInterval(async () => {
13316
13542
  if (!document.body.contains(bodyView)) {
13317
- clearInterval(bodyView._remoteFleetLiveRefreshTimer);
13318
- bodyView._remoteFleetLiveRefreshTimer = null;
13543
+ clearRemoteFleetTimers(bodyView);
13319
13544
  return;
13320
13545
  }
13321
13546
 
13322
13547
  try {
13323
- const result = await invokeDotNetAsync('RefreshRemoteFleetMonitorNodeFromJs', nodeId);
13324
- await syncRemoteFleetNodeStateFromResult(result);
13548
+ await refreshRemoteFleetNode();
13549
+ } catch {
13550
+ clearRemoteFleetTimers(bodyView);
13551
+ }
13552
+ }, REMOTE_FLEET_LIVE_REFRESH_MS);
13553
+ } else if (autoMonitorState && hasMonitorTargets) {
13554
+ bodyView._remoteFleetMonitorRefreshTimer = setInterval(async () => {
13555
+ if (!document.body.contains(bodyView)) {
13556
+ clearRemoteFleetTimers(bodyView);
13557
+ return;
13558
+ }
13559
+
13560
+ try {
13561
+ await refreshRemoteFleetNode();
13325
13562
  } catch {
13326
- clearInterval(bodyView._remoteFleetLiveRefreshTimer);
13327
- bodyView._remoteFleetLiveRefreshTimer = null;
13563
+ clearRemoteFleetTimers(bodyView);
13328
13564
  }
13329
- }, 1000);
13565
+ }, REMOTE_FLEET_MONITOR_REFRESH_MS);
13330
13566
  }
13331
13567
  }
13332
13568
 
@@ -558,7 +558,7 @@
558
558
  }
559
559
 
560
560
  const base = '_content/MindExecution.Shared/js/';
561
- const scriptVersion = '20260612-remote-live-v467';
561
+ const scriptVersion = '20260612-remote-grouping-v469';
562
562
  const scriptUrl = (script) => `${base}${script}?v=${scriptVersion}`;
563
563
  console.log(`[Script Loader] Shared JS version: ${scriptVersion}`);
564
564
  const criticalScripts = [
@@ -1,5 +1,5 @@
1
1
  self.assetsManifest = {
2
- "version": "VGenANrx",
2
+ "version": "f0W9Xlyj",
3
3
  "assets": [
4
4
  {
5
5
  "hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
@@ -86,7 +86,7 @@
86
86
  "url": "_content/MindExecution.Shared/js/mind-map-core.js.backup"
87
87
  },
88
88
  {
89
- "hash": "sha256-onBRk1N+CsAvVe3BVd4w9ca+0VF+NLCzDOjqBH3T2vw=",
89
+ "hash": "sha256-PUVvy0IwiS6uV3XxWr2shsyWGD3tgG9LmarQERuoboY=",
90
90
  "url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
91
91
  },
92
92
  {
@@ -834,7 +834,7 @@
834
834
  "url": "image-manifest.json"
835
835
  },
836
836
  {
837
- "hash": "sha256-XjrBWCpqleqLE2sqmht7oUg24vRCkU/O+yj7TszO43g=",
837
+ "hash": "sha256-N8LbhFnpFjOzfff/nGijpdKbc+/wg9vtlFm7ZpJtkK0=",
838
838
  "url": "index.html"
839
839
  },
840
840
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: VGenANrx */
1
+ /* Manifest version: f0W9Xlyj */
2
2
  // Hosted deployments should prefer the network over stale offline caches.
3
3
  // This service worker immediately clears old Blazor offline caches and unregisters itself.
4
4