@mindexec/cli 0.2.7 → 0.2.8

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.8",
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,10 @@
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
+
12151
12170
  function getRemoteFleetTimestampMs(value) {
12152
12171
  const timestamp = Date.parse(String(value || ''));
12153
12172
  return Number.isFinite(timestamp) ? timestamp : 0;
@@ -12221,10 +12240,7 @@
12221
12240
 
12222
12241
  function renderRemoteFleetMonitor(bodyView, nodeModel) {
12223
12242
  if (!bodyView) return;
12224
- if (bodyView._remoteFleetLiveRefreshTimer) {
12225
- clearInterval(bodyView._remoteFleetLiveRefreshTimer);
12226
- bodyView._remoteFleetLiveRefreshTimer = null;
12227
- }
12243
+ clearRemoteFleetTimers(bodyView);
12228
12244
 
12229
12245
  const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
12230
12246
  const searchState = bodyView.dataset.remoteFleetSearch || '';
@@ -12232,10 +12248,13 @@
12232
12248
  const sortState = bodyView.dataset.remoteFleetSort || 'status';
12233
12249
  const densityState = bodyView.dataset.remoteFleetDensity || 'cards';
12234
12250
  const aiAssistState = bodyView.dataset.remoteFleetAiAssist === 'true';
12251
+ const autoMonitorState = bodyView.dataset.remoteFleetAutoMonitor !== 'false';
12235
12252
  const focusState = bodyView.dataset.remoteFleetFocusDeviceId || '';
12236
12253
  const devices = [...parseRemoteFleetDevices(nodeModel)]
12237
12254
  .sort((left, right) => compareRemoteFleetDevices(left, right, sortState));
12238
12255
  const hasActiveLiveStream = devices.some(isRemoteFleetLiveActive);
12256
+ const hasMonitorTargets = devices.some(device =>
12257
+ isRemoteFleetDeviceConnected(device) && isRemoteFleetThumbnailCapable(device));
12239
12258
  const focusedDevice = devices.find(device => getRemoteFleetDeviceId(device) === focusState)
12240
12259
  || devices.find(device => isRemoteFleetLiveActive(device))
12241
12260
  || null;
@@ -12289,7 +12308,7 @@
12289
12308
  const commandRow = document.createElement('div');
12290
12309
  commandRow.style.cssText = `
12291
12310
  display: grid;
12292
- grid-template-columns: minmax(0, 1fr) auto auto;
12311
+ grid-template-columns: minmax(0, 1fr) auto auto auto;
12293
12312
  gap: 8px;
12294
12313
  align-items: center;
12295
12314
  flex: 0 0 auto;
@@ -12314,7 +12333,42 @@
12314
12333
 
12315
12334
  const copyButton = createRemoteFleetButton('Copy', 'Copy agent command', 'copy-command');
12316
12335
  const refreshButton = createRemoteFleetButton('Refresh', 'Refresh remote devices', 'refresh');
12336
+ const autoMonitorLabel = document.createElement('label');
12337
+ autoMonitorLabel.title = 'Refresh stale thumbnails on a bounded timer';
12338
+ autoMonitorLabel.style.cssText = `
12339
+ display: inline-flex;
12340
+ align-items: center;
12341
+ justify-content: center;
12342
+ gap: 6px;
12343
+ height: 34px;
12344
+ padding: 0 9px;
12345
+ border-radius: 7px;
12346
+ border: 1px solid rgba(14, 165, 233, 0.28);
12347
+ background: ${autoMonitorState ? 'rgba(240, 249, 255, 0.92)' : 'rgba(248, 250, 252, 0.92)'};
12348
+ color: ${autoMonitorState ? '#0369a1' : '#475569'};
12349
+ font-size: 11px;
12350
+ font-weight: 900;
12351
+ letter-spacing: 0;
12352
+ cursor: pointer;
12353
+ pointer-events: auto;
12354
+ user-select: none;
12355
+ `;
12356
+ const autoMonitorToggle = document.createElement('input');
12357
+ autoMonitorToggle.type = 'checkbox';
12358
+ autoMonitorToggle.checked = autoMonitorState;
12359
+ autoMonitorToggle.dataset.remoteFleetAutoToggle = 'true';
12360
+ autoMonitorToggle.style.cssText = `
12361
+ width: 14px;
12362
+ height: 14px;
12363
+ margin: 0;
12364
+ accent-color: #0284c7;
12365
+ `;
12366
+ const autoMonitorText = document.createElement('span');
12367
+ autoMonitorText.textContent = 'Auto';
12368
+ autoMonitorLabel.appendChild(autoMonitorToggle);
12369
+ autoMonitorLabel.appendChild(autoMonitorText);
12317
12370
  commandRow.appendChild(commandText);
12371
+ commandRow.appendChild(autoMonitorLabel);
12318
12372
  commandRow.appendChild(copyButton);
12319
12373
  commandRow.appendChild(refreshButton);
12320
12374
  bodyView.appendChild(commandRow);
@@ -13010,8 +13064,7 @@
13010
13064
  bodyView.appendChild(grid);
13011
13065
 
13012
13066
  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)}`;
13067
+ footer.textContent = `Endpoint ${endpoint} - all devices, no paging - ${autoMonitorState ? 'auto monitor' : 'manual'} - refreshed ${formatRemoteFleetAge(refreshedAt)}`;
13015
13068
  footer.style.cssText = `
13016
13069
  flex: 0 0 auto;
13017
13070
  color: #64748b;
@@ -13048,6 +13101,20 @@
13048
13101
  const readTaskInstruction = () => String(taskInput.value || '').trim();
13049
13102
  const useAiAssist = () => aiToggle.checked === true;
13050
13103
  const getDeviceCards = () => Array.from(grid.querySelectorAll('article[data-device-id]'));
13104
+ const refreshRemoteFleetNode = async () => {
13105
+ if (bodyView._remoteFleetRefreshInFlight === true) {
13106
+ return null;
13107
+ }
13108
+
13109
+ bodyView._remoteFleetRefreshInFlight = true;
13110
+ try {
13111
+ const result = await invokeDotNetAsync('RefreshRemoteFleetMonitorNodeFromJs', nodeId);
13112
+ await syncRemoteFleetNodeStateFromResult(result);
13113
+ return result;
13114
+ } finally {
13115
+ bodyView._remoteFleetRefreshInFlight = false;
13116
+ }
13117
+ };
13051
13118
  const getVisibleEligibleDeviceIds = () => {
13052
13119
  const wantsAi = useAiAssist();
13053
13120
  return getDeviceCards()
@@ -13124,10 +13191,19 @@
13124
13191
  control.addEventListener(eventName, event => event.stopPropagation());
13125
13192
  });
13126
13193
  });
13194
+ [autoMonitorLabel, autoMonitorToggle].forEach(control => {
13195
+ ['mousedown', 'mouseup', 'click', 'dblclick', 'keydown'].forEach(eventName => {
13196
+ control.addEventListener(eventName, event => event.stopPropagation());
13197
+ });
13198
+ });
13127
13199
 
13128
13200
  searchInput.addEventListener('input', applyRemoteFleetFilters);
13129
13201
  filterSelect.addEventListener('change', applyRemoteFleetFilters);
13130
13202
  aiToggle.addEventListener('change', applyRemoteFleetFilters);
13203
+ autoMonitorToggle.addEventListener('change', () => {
13204
+ bodyView.dataset.remoteFleetAutoMonitor = autoMonitorToggle.checked ? 'true' : 'false';
13205
+ renderRemoteFleetMonitor(bodyView, nodeModel);
13206
+ });
13131
13207
  sortSelect.addEventListener('change', () => {
13132
13208
  bodyView.dataset.remoteFleetSort = String(sortSelect.value || 'status');
13133
13209
  renderRemoteFleetMonitor(bodyView, nodeModel);
@@ -13200,9 +13276,11 @@
13200
13276
  event.preventDefault();
13201
13277
  event.stopPropagation();
13202
13278
  refreshButton.disabled = true;
13203
- const result = await invokeDotNetAsync('RefreshRemoteFleetMonitorNodeFromJs', nodeId);
13204
- await syncRemoteFleetNodeStateFromResult(result);
13205
- refreshButton.disabled = false;
13279
+ try {
13280
+ await refreshRemoteFleetNode();
13281
+ } finally {
13282
+ refreshButton.disabled = false;
13283
+ }
13206
13284
  });
13207
13285
 
13208
13286
  bodyView.querySelectorAll('[data-remote-fleet-action="live-focus"]').forEach(button => {
@@ -13314,19 +13392,29 @@
13314
13392
  if (hasActiveLiveStream) {
13315
13393
  bodyView._remoteFleetLiveRefreshTimer = setInterval(async () => {
13316
13394
  if (!document.body.contains(bodyView)) {
13317
- clearInterval(bodyView._remoteFleetLiveRefreshTimer);
13318
- bodyView._remoteFleetLiveRefreshTimer = null;
13395
+ clearRemoteFleetTimers(bodyView);
13319
13396
  return;
13320
13397
  }
13321
13398
 
13322
13399
  try {
13323
- const result = await invokeDotNetAsync('RefreshRemoteFleetMonitorNodeFromJs', nodeId);
13324
- await syncRemoteFleetNodeStateFromResult(result);
13400
+ await refreshRemoteFleetNode();
13401
+ } catch {
13402
+ clearRemoteFleetTimers(bodyView);
13403
+ }
13404
+ }, REMOTE_FLEET_LIVE_REFRESH_MS);
13405
+ } else if (autoMonitorState && hasMonitorTargets) {
13406
+ bodyView._remoteFleetMonitorRefreshTimer = setInterval(async () => {
13407
+ if (!document.body.contains(bodyView)) {
13408
+ clearRemoteFleetTimers(bodyView);
13409
+ return;
13410
+ }
13411
+
13412
+ try {
13413
+ await refreshRemoteFleetNode();
13325
13414
  } catch {
13326
- clearInterval(bodyView._remoteFleetLiveRefreshTimer);
13327
- bodyView._remoteFleetLiveRefreshTimer = null;
13415
+ clearRemoteFleetTimers(bodyView);
13328
13416
  }
13329
- }, 1000);
13417
+ }, REMOTE_FLEET_MONITOR_REFRESH_MS);
13330
13418
  }
13331
13419
  }
13332
13420
 
@@ -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-auto-monitor-v468';
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": "ok6mf/2a",
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-9f7DLlG6ShPyYhu/Db97YKVoFr+RhJC2Ko9E4NsL9Lc=",
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-e/vzCKU0rJNUBs7+YbA+jxOZd53T9CbUxhBAJ0yi6oM=",
838
838
  "url": "index.html"
839
839
  },
840
840
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: VGenANrx */
1
+ /* Manifest version: ok6mf/2a */
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