@mindexec/cli 0.2.52 → 0.2.54

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 (22) hide show
  1. package/package.json +1 -1
  2. package/remote-hub.js +29 -0
  3. package/scripts/remote-fleet-render-smoke.mjs +19 -0
  4. package/scripts/remote-http-smoke.mjs +34 -0
  5. package/server.js +17 -0
  6. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +224 -12
  7. package/wwwroot/_framework/MindExecution.Core.fu1rl67yt3.dll +0 -0
  8. package/wwwroot/_framework/{MindExecution.Kernel.jgfwunsvz4.dll → MindExecution.Kernel.cqcbagjpqb.dll} +0 -0
  9. package/wwwroot/_framework/{MindExecution.Plugins.Admin.uz1ws5p7x5.dll → MindExecution.Plugins.Admin.tsn0j478un.dll} +0 -0
  10. package/wwwroot/_framework/{MindExecution.Plugins.Business.yeedyl4etv.dll → MindExecution.Plugins.Business.xg74dmn0vz.dll} +0 -0
  11. package/wwwroot/_framework/{MindExecution.Plugins.Concept.i8wxwseow8.dll → MindExecution.Plugins.Concept.j0zntvuecv.dll} +0 -0
  12. package/wwwroot/_framework/{MindExecution.Plugins.Directory.mbuksx1hqq.dll → MindExecution.Plugins.Directory.9i4bd043ia.dll} +0 -0
  13. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.vp3cl6bvxb.dll → MindExecution.Plugins.PlanMaster.vml3qie2ji.dll} +0 -0
  14. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.snkp6shzuk.dll → MindExecution.Plugins.YouTube.0gfbwq1jfg.dll} +0 -0
  15. package/wwwroot/_framework/{MindExecution.Shared.irzb0k7hye.dll → MindExecution.Shared.f3bclzo6k4.dll} +0 -0
  16. package/wwwroot/_framework/MindExecution.Web.4jhsxoiqgz.dll +0 -0
  17. package/wwwroot/_framework/blazor.boot.json +21 -21
  18. package/wwwroot/index.html +3 -3
  19. package/wwwroot/service-worker-assets.js +24 -24
  20. package/wwwroot/service-worker.js +1 -1
  21. package/wwwroot/_framework/MindExecution.Core.07ktly047n.dll +0 -0
  22. package/wwwroot/_framework/MindExecution.Web.td6ps8xw4t.dll +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.52",
3
+ "version": "0.2.54",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
package/remote-hub.js CHANGED
@@ -512,6 +512,34 @@ export function createRemoteHub(options = {}) {
512
512
  });
513
513
  }
514
514
 
515
+ function listDeviceFrames(options = {}) {
516
+ const ids = Array.isArray(options.deviceIds)
517
+ ? options.deviceIds.map(value => safeString(value, 160)).filter(Boolean)
518
+ : [];
519
+ const idSet = ids.length > 0 ? new Set(ids) : null;
520
+ const includeThumbnail = options.includeThumbnail !== false;
521
+ const includeLive = options.includeLive !== false;
522
+
523
+ return [...devices.values()]
524
+ .filter(device => !idSet || idSet.has(device.deviceId))
525
+ .map(device => ({
526
+ deviceId: device.deviceId,
527
+ connected: device.connected === true,
528
+ thumbnailEnabled: readCapabilityFlag(device.capabilities, 'thumbnail'),
529
+ liveStreamActive: device.activeLiveStream?.active === true,
530
+ liveStreamId: device.activeLiveStream?.streamId || '',
531
+ liveStreamFps: Number(device.activeLiveStream?.fps || 0),
532
+ liveStreamLastFrameAt: device.activeLiveStream?.lastFrameAt || '',
533
+ thumbnail: includeThumbnail
534
+ ? serializeRemoteFrame(device.latestThumbnail, device.deviceId, 'thumbnail', { includeDataUrl: false })
535
+ : null,
536
+ live: includeLive
537
+ ? serializeRemoteFrame(device.latestLiveFrame, device.deviceId, 'live', { includeDataUrl: false })
538
+ : null
539
+ }))
540
+ .sort((a, b) => String(a.deviceId).localeCompare(String(b.deviceId)));
541
+ }
542
+
515
543
  function listTaskBatches() {
516
544
  return [...taskBatches.values()]
517
545
  .map(serializeTaskBatch)
@@ -2100,6 +2128,7 @@ export function createRemoteHub(options = {}) {
2100
2128
  listDevices,
2101
2129
  listTaskBatches,
2102
2130
  getLatestTaskBatch,
2131
+ listDeviceFrames,
2103
2132
  disconnectDevice,
2104
2133
  sendCommand,
2105
2134
  requestAgentTask,
@@ -649,6 +649,7 @@ try {
649
649
  const { manager, document } = await loadCss3DManager();
650
650
  assert.equal(typeof manager?.renderRemoteFleetMonitorForTest, 'function');
651
651
  assert.equal(typeof manager?.renderRemoteFleetDeviceForTest, 'function');
652
+ assert.equal(typeof manager?.applyRemoteFleetFramePatchesForTest, 'function');
652
653
  assert.equal(typeof manager?.setModuleForTest, 'function');
653
654
 
654
655
  const dotNetCalls = [];
@@ -724,6 +725,24 @@ try {
724
725
  assert.ok(initialDetailPanel?.textContent.includes('Load'));
725
726
  assert.ok(cards[0]?.querySelector('[data-remote-fleet-device-preview="tile"]'));
726
727
  assert.equal(/\b(Seen|Uptime|Mem|Load)\b/.test(cards[0]?.textContent || ''), false);
728
+ const patchTarget = devices.find(device => device.ThumbnailEnabled === true && device.LiveStreamActive !== true);
729
+ assert.ok(patchTarget);
730
+ const patchCard = Array.from(cards).find(card => card.dataset.deviceId === patchTarget.DeviceId);
731
+ const patchPreview = patchCard?.querySelector('[data-remote-fleet-device-preview="tile"]');
732
+ assert.ok(patchPreview);
733
+ const patchUrl = `/api/remote/devices/${encodeURIComponent(patchTarget.DeviceId)}/thumbnail?token=render-smoke-frame&seq=9999`;
734
+ const patchCount = manager.applyRemoteFleetFramePatchesForTest(bodyView, [{
735
+ deviceId: patchTarget.DeviceId,
736
+ kind: 'thumbnail',
737
+ frameSeq: 9999,
738
+ frameUrl: patchUrl,
739
+ receivedAt: new Date().toISOString()
740
+ }]);
741
+ assert.equal(patchCount, 1);
742
+ assert.equal(patchPreview.dataset.remoteFleetFrameSeq, '9999');
743
+ assert.equal(patchPreview.dataset.remoteFleetFrameUrl, patchUrl);
744
+ assert.equal(patchPreview.dataset.remoteFleetPendingFrameUrl || '', '');
745
+ assert.equal(patchPreview.querySelector('img[data-remote-fleet-frame-image="true"]')?.dataset.remoteFleetFrameUrl, patchUrl);
727
746
  const alternateDevice = devices.find(device => device.DeviceId !== focusedDevice.DeviceId);
728
747
  assert.ok(alternateDevice);
729
748
  const alternateCard = Array.from(cards).find(card => card.dataset.deviceId === alternateDevice.DeviceId);
@@ -377,6 +377,23 @@ async function runSyntheticEnabledSmoke() {
377
377
  assert.ok(urlOnlyThumbnailDevice?.latestThumbnail?.framePath);
378
378
  assert.ok(!('dataUrl' in urlOnlyThumbnailDevice.latestThumbnail));
379
379
 
380
+ const thumbnailFramesOnly = await fetchJson(`${baseUrl}/api/remote/frames`, {
381
+ method: 'POST',
382
+ token: BRIDGE_TOKEN,
383
+ body: JSON.stringify({
384
+ deviceIds: [thumbnailTarget.deviceId],
385
+ includeThumbnail: true,
386
+ includeLive: true
387
+ })
388
+ });
389
+ assert.equal(thumbnailFramesOnly.ok, true, JSON.stringify(thumbnailFramesOnly.payload));
390
+ assert.equal(thumbnailFramesOnly.payload?.ok, true);
391
+ assert.equal(thumbnailFramesOnly.payload?.frames?.length, 1);
392
+ assert.equal(thumbnailFramesOnly.payload.frames[0].deviceId, thumbnailTarget.deviceId);
393
+ assert.equal(thumbnailFramesOnly.payload.frames[0].thumbnailEnabled, true);
394
+ assert.ok(String(thumbnailFramesOnly.payload.frames[0].thumbnail?.framePath || '').includes(`/api/remote/devices/${encodeURIComponent(thumbnailTarget.deviceId)}/thumbnail?`));
395
+ assert.ok(!('dataUrl' in thumbnailFramesOnly.payload.frames[0].thumbnail));
396
+
380
397
  const liveTarget = devicesResult.payload.devices.find(device =>
381
398
  device.connected && device.capabilities?.liveStream);
382
399
  assert.ok(liveTarget);
@@ -419,6 +436,23 @@ async function runSyntheticEnabledSmoke() {
419
436
  const badLiveSeq = await fetchBinary(`${baseUrl}${liveFrame.payload.frame.framePath.replace(/seq=\d+/, 'seq=999999')}`);
420
437
  assert.equal(badLiveSeq.status, 401);
421
438
 
439
+ const liveFramesOnly = await fetchJson(`${baseUrl}/api/remote/frames`, {
440
+ method: 'POST',
441
+ token: BRIDGE_TOKEN,
442
+ body: JSON.stringify({
443
+ deviceIds: [liveTarget.deviceId],
444
+ includeThumbnail: true,
445
+ includeLive: true
446
+ })
447
+ });
448
+ assert.equal(liveFramesOnly.ok, true, JSON.stringify(liveFramesOnly.payload));
449
+ assert.equal(liveFramesOnly.payload?.ok, true);
450
+ assert.equal(liveFramesOnly.payload?.frames?.length, 1);
451
+ assert.equal(liveFramesOnly.payload.frames[0].deviceId, liveTarget.deviceId);
452
+ assert.equal(liveFramesOnly.payload.frames[0].liveStreamActive, true);
453
+ assert.ok(String(liveFramesOnly.payload.frames[0].live?.framePath || '').includes(`/api/remote/devices/${encodeURIComponent(liveTarget.deviceId)}/live/frame?`));
454
+ assert.ok(!('dataUrl' in liveFramesOnly.payload.frames[0].live));
455
+
422
456
  const liveStop = await fetchJson(`${baseUrl}/api/remote/devices/${encodeURIComponent(liveTarget.deviceId)}/live/stop`, {
423
457
  method: 'POST',
424
458
  token: BRIDGE_TOKEN,
package/server.js CHANGED
@@ -7284,6 +7284,23 @@ app.get('/api/remote/devices', (req, res) => {
7284
7284
  });
7285
7285
  });
7286
7286
 
7287
+ app.post('/api/remote/frames', (req, res) => {
7288
+ res.setHeader('Cache-Control', 'no-store');
7289
+ const deviceIds = Array.isArray(req.body?.deviceIds)
7290
+ ? req.body.deviceIds.map(value => String(value || '').trim()).filter(Boolean).slice(0, 120)
7291
+ : [];
7292
+ const frames = remoteHub.listDeviceFrames({
7293
+ deviceIds,
7294
+ includeThumbnail: req.body?.includeThumbnail !== false,
7295
+ includeLive: req.body?.includeLive !== false
7296
+ });
7297
+ res.json({
7298
+ ok: true,
7299
+ total: frames.length,
7300
+ frames
7301
+ });
7302
+ });
7303
+
7287
7304
  app.post('/api/remote/host-target', (req, res) => {
7288
7305
  res.setHeader('Cache-Control', 'no-store');
7289
7306
  res.json(remoteHub.setHostTarget({
@@ -12920,7 +12920,7 @@
12920
12920
  bodyView._remoteFleetMonitorRefreshTimer = null;
12921
12921
  }
12922
12922
  if (bodyView._remoteFleetFrameLoopRaf) {
12923
- cancelAnimationFrame(bodyView._remoteFleetFrameLoopRaf);
12923
+ cancelRemoteFleetFrameLoopFrame(bodyView._remoteFleetFrameLoopRaf);
12924
12924
  bodyView._remoteFleetFrameLoopRaf = null;
12925
12925
  }
12926
12926
  bodyView._remoteFleetFrameLoopActive = false;
@@ -12935,6 +12935,38 @@
12935
12935
  }
12936
12936
  }
12937
12937
 
12938
+ function requestRemoteFleetFrameLoopFrame(callback) {
12939
+ if (typeof requestAnimationFrame === 'function') {
12940
+ return {
12941
+ kind: 'raf',
12942
+ id: requestAnimationFrame(callback)
12943
+ };
12944
+ }
12945
+
12946
+ return {
12947
+ kind: 'timeout',
12948
+ id: setTimeout(
12949
+ () => callback(typeof performance !== 'undefined' ? performance.now() : Date.now()),
12950
+ 33
12951
+ )
12952
+ };
12953
+ }
12954
+
12955
+ function cancelRemoteFleetFrameLoopFrame(handle) {
12956
+ if (!handle) {
12957
+ return;
12958
+ }
12959
+
12960
+ if (handle.kind === 'timeout') {
12961
+ clearTimeout(handle.id);
12962
+ return;
12963
+ }
12964
+
12965
+ if (typeof cancelAnimationFrame === 'function') {
12966
+ cancelAnimationFrame(handle.id);
12967
+ }
12968
+ }
12969
+
12938
12970
  function getRemoteFleetDeviceField(device, camelKey, pascalKey, fallback = '') {
12939
12971
  const value = device?.[camelKey] ?? device?.[pascalKey] ?? fallback;
12940
12972
  return value === undefined || value === null ? fallback : value;
@@ -13061,15 +13093,37 @@
13061
13093
  image.loading = frame.kind === 'thumbnail' ? 'lazy' : 'eager';
13062
13094
  image.decoding = 'async';
13063
13095
  image.style.cssText = 'width:100%;height:100%;object-fit:cover;display:block;';
13064
- const placeholder = preview?.querySelector?.('[data-remote-fleet-screen-placeholder="true"]');
13065
- if (placeholder) {
13066
- placeholder.remove();
13096
+ if (typeof preview?.insertBefore === 'function') {
13097
+ preview.insertBefore(image, preview.firstChild || null);
13098
+ } else {
13099
+ preview?.appendChild?.(image);
13067
13100
  }
13068
- preview?.insertBefore?.(image, preview.firstChild || null);
13069
13101
  return image;
13070
13102
  }
13071
13103
 
13072
- function applyRemoteFleetFramePatchToPreview(preview, frame) {
13104
+ function getRemoteFleetFrameIdentity(frame) {
13105
+ return [
13106
+ String(frame?.deviceId || '').trim(),
13107
+ String(frame?.kind || '').trim().toLowerCase(),
13108
+ String(frame?.streamId || '').trim(),
13109
+ String(Number(frame?.frameSeq || 0) || 0),
13110
+ String(frame?.frameUrl || '').trim()
13111
+ ].join('|');
13112
+ }
13113
+
13114
+ function cloneRemoteFleetFramePatch(frame) {
13115
+ return {
13116
+ deviceId: String(frame?.deviceId || '').trim(),
13117
+ kind: String(frame?.kind || 'thumbnail').trim().toLowerCase(),
13118
+ frameSeq: Number.isFinite(Number(frame?.frameSeq)) ? Math.floor(Number(frame.frameSeq)) : 0,
13119
+ frameUrl: String(frame?.frameUrl || '').trim(),
13120
+ receivedAt: String(frame?.receivedAt || '').trim(),
13121
+ capturedAt: String(frame?.capturedAt || '').trim(),
13122
+ streamId: String(frame?.streamId || '').trim()
13123
+ };
13124
+ }
13125
+
13126
+ function isRemoteFleetFrameNewerForPreview(preview, frame, comparePending = false) {
13073
13127
  if (!preview || !frame || !isRemoteFleetFrameSource(frame.frameUrl)) {
13074
13128
  return false;
13075
13129
  }
@@ -13086,11 +13140,73 @@
13086
13140
  return false;
13087
13141
  }
13088
13142
 
13089
- const image = ensureRemoteFleetFrameImage(preview, frame);
13090
- if (!image) {
13143
+ if (comparePending) {
13144
+ const pendingUrl = String(preview.dataset.remoteFleetPendingFrameUrl || '');
13145
+ const pendingKind = String(preview.dataset.remoteFleetPendingFrameKind || '').toLowerCase();
13146
+ const pendingSeq = Number(preview.dataset.remoteFleetPendingFrameSeq || '0');
13147
+ if (pendingUrl) {
13148
+ const samePending = pendingKind === frame.kind
13149
+ && pendingSeq === nextSeq
13150
+ && pendingUrl === frame.frameUrl;
13151
+ if (samePending) {
13152
+ return false;
13153
+ }
13154
+
13155
+ if (pendingKind === 'live' && frame.kind !== 'live') {
13156
+ return false;
13157
+ }
13158
+
13159
+ if (pendingKind === frame.kind
13160
+ && Number.isFinite(pendingSeq)
13161
+ && pendingSeq > 0
13162
+ && Number.isFinite(nextSeq)
13163
+ && nextSeq > 0
13164
+ && nextSeq < pendingSeq) {
13165
+ return false;
13166
+ }
13167
+ }
13168
+ }
13169
+
13170
+ return true;
13171
+ }
13172
+
13173
+ function ensureRemoteFleetFrameBadge(preview, frame) {
13174
+ let badge = preview?.querySelector?.('[data-remote-fleet-frame-badge="true"]');
13175
+ if (badge) {
13176
+ return badge;
13177
+ }
13178
+
13179
+ badge = document.createElement('span');
13180
+ badge.dataset.remoteFleetFrameBadge = 'true';
13181
+ const previewMode = String(preview?.dataset?.remoteFleetDevicePreview || '');
13182
+ const isDetail = previewMode === 'detail';
13183
+ badge.style.cssText = `
13184
+ position: absolute;
13185
+ right: ${isDetail ? '9px' : '6px'};
13186
+ bottom: ${isDetail ? '9px' : '6px'};
13187
+ max-width: calc(100% - ${isDetail ? '18px' : '12px'});
13188
+ padding: ${isDetail ? '4px 7px' : '3px 6px'};
13189
+ border-radius: 999px;
13190
+ background: ${frame?.kind === 'live' ? 'rgba(220, 38, 38, 0.84)' : 'rgba(15, 23, 42, 0.72)'};
13191
+ color: #e2e8f0;
13192
+ font-size: ${isDetail ? '9px' : '8px'};
13193
+ font-weight: 950;
13194
+ line-height: 1;
13195
+ overflow: hidden;
13196
+ text-overflow: ellipsis;
13197
+ white-space: nowrap;
13198
+ letter-spacing: 0;
13199
+ `;
13200
+ preview?.appendChild?.(badge);
13201
+ return badge;
13202
+ }
13203
+
13204
+ function commitRemoteFleetFrameToPreview(preview, image, frame) {
13205
+ if (!preview || !image || !isRemoteFleetFrameNewerForPreview(preview, frame, false)) {
13091
13206
  return false;
13092
13207
  }
13093
13208
 
13209
+ const nextSeq = Number(frame.frameSeq || 0);
13094
13210
  image.dataset.remoteFleetFrameKind = frame.kind;
13095
13211
  image.dataset.remoteFleetFrameSeq = String(nextSeq || 0);
13096
13212
  image.dataset.remoteFleetFrameUrl = frame.frameUrl;
@@ -13104,7 +13220,12 @@
13104
13220
  preview.dataset.remoteFleetFrameUrl = frame.frameUrl;
13105
13221
  preview.dataset.remoteFleetFrameAt = frame.receivedAt || frame.capturedAt || '';
13106
13222
 
13107
- const badge = preview.querySelector('[data-remote-fleet-frame-badge="true"]');
13223
+ const placeholder = preview.querySelector('[data-remote-fleet-screen-placeholder="true"]');
13224
+ if (placeholder) {
13225
+ placeholder.remove();
13226
+ }
13227
+
13228
+ const badge = ensureRemoteFleetFrameBadge(preview, frame);
13108
13229
  if (badge) {
13109
13230
  const at = frame.receivedAt || frame.capturedAt || '';
13110
13231
  badge.textContent = frame.kind === 'live'
@@ -13119,6 +13240,96 @@
13119
13240
  return true;
13120
13241
  }
13121
13242
 
13243
+ function clearRemoteFleetPendingFrameDataset(preview, frame) {
13244
+ if (!preview) {
13245
+ return;
13246
+ }
13247
+
13248
+ if (!frame
13249
+ || getRemoteFleetFrameIdentity(preview._remoteFleetPendingFrame) === getRemoteFleetFrameIdentity(frame)) {
13250
+ delete preview.dataset.remoteFleetPendingFrameKind;
13251
+ delete preview.dataset.remoteFleetPendingFrameSeq;
13252
+ delete preview.dataset.remoteFleetPendingFrameUrl;
13253
+ preview._remoteFleetPendingFrame = null;
13254
+ }
13255
+ }
13256
+
13257
+ function processRemoteFleetFrameQueue(preview, image) {
13258
+ if (!preview || !image || preview._remoteFleetFrameLoaderActive === true) {
13259
+ return;
13260
+ }
13261
+
13262
+ const frame = preview._remoteFleetPendingFrame;
13263
+ if (!frame || !isRemoteFleetFrameSource(frame.frameUrl)) {
13264
+ clearRemoteFleetPendingFrameDataset(preview, frame);
13265
+ return;
13266
+ }
13267
+
13268
+ preview._remoteFleetFrameLoaderActive = true;
13269
+ const frameIdentity = getRemoteFleetFrameIdentity(frame);
13270
+ const finish = loaded => {
13271
+ const currentPending = preview._remoteFleetPendingFrame;
13272
+ const stillLatest = getRemoteFleetFrameIdentity(currentPending) === frameIdentity;
13273
+ let committed = false;
13274
+ if (loaded && stillLatest) {
13275
+ committed = commitRemoteFleetFrameToPreview(preview, image, frame);
13276
+ window.RuntimeTrace?.emit?.('remote.frame.uiPatched', {
13277
+ count: committed ? 1 : 0,
13278
+ kind: frame.kind,
13279
+ seq: frame.frameSeq
13280
+ });
13281
+ }
13282
+
13283
+ if (stillLatest) {
13284
+ clearRemoteFleetPendingFrameDataset(preview, frame);
13285
+ }
13286
+
13287
+ preview._remoteFleetFrameLoaderActive = false;
13288
+ if (preview._remoteFleetPendingFrame) {
13289
+ processRemoteFleetFrameQueue(preview, image);
13290
+ }
13291
+ };
13292
+
13293
+ if (typeof Image !== 'function') {
13294
+ finish(true);
13295
+ return;
13296
+ }
13297
+
13298
+ const loader = new Image();
13299
+ loader.decoding = 'async';
13300
+ loader.onload = () => {
13301
+ const decoded = typeof loader.decode === 'function'
13302
+ ? loader.decode().catch(() => undefined)
13303
+ : Promise.resolve();
13304
+ decoded.then(() => finish(true));
13305
+ };
13306
+ loader.onerror = () => finish(false);
13307
+ loader.src = frame.frameUrl;
13308
+ }
13309
+
13310
+ function queueRemoteFleetFrameImageSwap(preview, frame) {
13311
+ if (!preview || !frame || !isRemoteFleetFrameNewerForPreview(preview, frame, true)) {
13312
+ return false;
13313
+ }
13314
+
13315
+ const image = ensureRemoteFleetFrameImage(preview, frame);
13316
+ if (!image) {
13317
+ return false;
13318
+ }
13319
+
13320
+ const nextFrame = cloneRemoteFleetFramePatch(frame);
13321
+ preview._remoteFleetPendingFrame = nextFrame;
13322
+ preview.dataset.remoteFleetPendingFrameKind = nextFrame.kind;
13323
+ preview.dataset.remoteFleetPendingFrameSeq = String(nextFrame.frameSeq || 0);
13324
+ preview.dataset.remoteFleetPendingFrameUrl = nextFrame.frameUrl;
13325
+ processRemoteFleetFrameQueue(preview, image);
13326
+ return true;
13327
+ }
13328
+
13329
+ function applyRemoteFleetFramePatchToPreview(preview, frame) {
13330
+ return queueRemoteFleetFrameImageSwap(preview, frame);
13331
+ }
13332
+
13122
13333
  function applyRemoteFleetFramePatches(bodyView, patches) {
13123
13334
  if (!bodyView || !Array.isArray(patches) || patches.length === 0) {
13124
13335
  return 0;
@@ -13146,7 +13357,7 @@
13146
13357
  });
13147
13358
 
13148
13359
  if (applied > 0) {
13149
- window.RuntimeTrace?.emit?.('remote.frame.uiPatched', {
13360
+ window.RuntimeTrace?.emit?.('remote.frame.uiQueued', {
13150
13361
  count: applied
13151
13362
  });
13152
13363
  }
@@ -13179,10 +13390,10 @@
13179
13390
  });
13180
13391
  }
13181
13392
 
13182
- bodyView._remoteFleetFrameLoopRaf = requestAnimationFrame(loop);
13393
+ bodyView._remoteFleetFrameLoopRaf = requestRemoteFleetFrameLoopFrame(loop);
13183
13394
  };
13184
13395
 
13185
- bodyView._remoteFleetFrameLoopRaf = requestAnimationFrame(loop);
13396
+ bodyView._remoteFleetFrameLoopRaf = requestRemoteFleetFrameLoopFrame(loop);
13186
13397
  }
13187
13398
 
13188
13399
  function isRemoteFleetLiveActive(device) {
@@ -19533,6 +19744,7 @@
19533
19744
  setModuleForTest: setModuleForTest,
19534
19745
  renderRemoteFleetMonitorForTest: renderRemoteFleetMonitor,
19535
19746
  renderRemoteFleetDeviceForTest: renderRemoteFleetDevice,
19747
+ applyRemoteFleetFramePatchesForTest: applyRemoteFleetFramePatches,
19536
19748
  renderBusinessAutomationEdges: renderBusinessAutomationEdges,
19537
19749
  scheduleBusinessAutomationEdgeRender: scheduleBusinessAutomationEdgeRender,
19538
19750
  syncBusinessAutomationSelectionContext: syncBusinessAutomationSelectionContext,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mainAssemblyName": "MindExecution.Web",
3
3
  "resources": {
4
- "hash": "sha256-9JUxLgIdet6zJ56ZG7ShauqiLsfwURY2wj+UzGbhN6o=",
4
+ "hash": "sha256-FI1aVvJXZHMtJ4l634osWbTe8sQ5rfdCKfSBgDnqQ70=",
5
5
  "fingerprinting": {
6
6
  "Google.Protobuf.9h59ukbel7.dll": "Google.Protobuf.dll",
7
7
  "Markdig.d1j7v41cl1.dll": "Markdig.dll",
@@ -123,16 +123,16 @@
123
123
  "System.brmz7yk5qh.dll": "System.dll",
124
124
  "netstandard.yvr3prsx0x.dll": "netstandard.dll",
125
125
  "System.Private.CoreLib.ns29bor93l.dll": "System.Private.CoreLib.dll",
126
- "MindExecution.Core.07ktly047n.dll": "MindExecution.Core.dll",
127
- "MindExecution.Kernel.jgfwunsvz4.dll": "MindExecution.Kernel.dll",
128
- "MindExecution.Plugins.Admin.uz1ws5p7x5.dll": "MindExecution.Plugins.Admin.dll",
129
- "MindExecution.Plugins.Business.yeedyl4etv.dll": "MindExecution.Plugins.Business.dll",
130
- "MindExecution.Plugins.Concept.i8wxwseow8.dll": "MindExecution.Plugins.Concept.dll",
131
- "MindExecution.Plugins.Directory.mbuksx1hqq.dll": "MindExecution.Plugins.Directory.dll",
132
- "MindExecution.Plugins.PlanMaster.vp3cl6bvxb.dll": "MindExecution.Plugins.PlanMaster.dll",
133
- "MindExecution.Plugins.YouTube.snkp6shzuk.dll": "MindExecution.Plugins.YouTube.dll",
134
- "MindExecution.Shared.irzb0k7hye.dll": "MindExecution.Shared.dll",
135
- "MindExecution.Web.td6ps8xw4t.dll": "MindExecution.Web.dll",
126
+ "MindExecution.Core.fu1rl67yt3.dll": "MindExecution.Core.dll",
127
+ "MindExecution.Kernel.cqcbagjpqb.dll": "MindExecution.Kernel.dll",
128
+ "MindExecution.Plugins.Admin.tsn0j478un.dll": "MindExecution.Plugins.Admin.dll",
129
+ "MindExecution.Plugins.Business.xg74dmn0vz.dll": "MindExecution.Plugins.Business.dll",
130
+ "MindExecution.Plugins.Concept.j0zntvuecv.dll": "MindExecution.Plugins.Concept.dll",
131
+ "MindExecution.Plugins.Directory.9i4bd043ia.dll": "MindExecution.Plugins.Directory.dll",
132
+ "MindExecution.Plugins.PlanMaster.vml3qie2ji.dll": "MindExecution.Plugins.PlanMaster.dll",
133
+ "MindExecution.Plugins.YouTube.0gfbwq1jfg.dll": "MindExecution.Plugins.YouTube.dll",
134
+ "MindExecution.Shared.f3bclzo6k4.dll": "MindExecution.Shared.dll",
135
+ "MindExecution.Web.4jhsxoiqgz.dll": "MindExecution.Web.dll",
136
136
  "dotnet.js": "dotnet.js",
137
137
  "dotnet.native.qc8g39g30v.js": "dotnet.native.js",
138
138
  "dotnet.native.boem75ye5i.wasm": "dotnet.native.wasm",
@@ -278,18 +278,18 @@
278
278
  "System.Xml.XDocument.sn51jas17n.dll": "sha256-GNI2kFgFmPTwzuzwUn8gxK+AzGLUWRJFdg9JzIbrybQ=",
279
279
  "System.brmz7yk5qh.dll": "sha256-CfM2miyj1KHApFmqMdLYWio3S/jrdON2pW9Xr2nTwlo=",
280
280
  "netstandard.yvr3prsx0x.dll": "sha256-EksNn8Luo4bOWqJ6X7dIe9qG9oOqwOVzjH2xYyMNi+E=",
281
- "MindExecution.Core.07ktly047n.dll": "sha256-hPd6g1aLjuHKYrK39vB2e2zNIT03JHDIOogVdJisxpg=",
282
- "MindExecution.Kernel.jgfwunsvz4.dll": "sha256-QzAvoq5JLTdZZjwWkIuHVhCHFMjw92dGhzrYo0NM978=",
283
- "MindExecution.Plugins.Concept.i8wxwseow8.dll": "sha256-chFP/WITGF1EPbkmHMqQmY90WQwsNG7jI+gjohLg744=",
284
- "MindExecution.Plugins.PlanMaster.vp3cl6bvxb.dll": "sha256-0xofgEHFyL96OcvSI34znXAL5ruOaGdGsci5Sh5T+mI=",
285
- "MindExecution.Shared.irzb0k7hye.dll": "sha256-MvbceH+10w3Ss5amK8K4BC4Hx6trEMyXe1vAXQSdDyA=",
286
- "MindExecution.Web.td6ps8xw4t.dll": "sha256-b0daeUMZRom6Z1kV+P0QhVWDaovg0QbC91vQIvA2ClQ="
281
+ "MindExecution.Core.fu1rl67yt3.dll": "sha256-6cDbehKdjX71zeL9Ro5GNupn7wqRYfb7yLW2w3Wp05g=",
282
+ "MindExecution.Kernel.cqcbagjpqb.dll": "sha256-zPB0tmwi/UKdJ//g0xMH1Y02ahDX5ii6ZKdB3yiQQz4=",
283
+ "MindExecution.Plugins.Concept.j0zntvuecv.dll": "sha256-/XUaopvgQk71o+jBdb3ljhCAQkXrda6XxCzS0242pIo=",
284
+ "MindExecution.Plugins.PlanMaster.vml3qie2ji.dll": "sha256-uS3p/j4Kq171sz/xkiEn08DZni3X6HLbq2OHsYcxIjg=",
285
+ "MindExecution.Shared.f3bclzo6k4.dll": "sha256-1ZuF0eTN8dm8o0BzDJX+lyuKB1Wlc8MO2+kPJx/TYec=",
286
+ "MindExecution.Web.4jhsxoiqgz.dll": "sha256-QPegscpX6rm9Fp7lPqHdeKDVUFshfip6frFo62NWuss="
287
287
  },
288
288
  "lazyAssembly": {
289
- "MindExecution.Plugins.Admin.uz1ws5p7x5.dll": "sha256-5g1F71Jv0PP/HXccx2jBR5k8bgq2d2dK8XDYyObESnc=",
290
- "MindExecution.Plugins.Business.yeedyl4etv.dll": "sha256-OiBtEdBJooJG9IAH2Zuhfh2NsJEtpbLoJ+jnC3a9VPU=",
291
- "MindExecution.Plugins.Directory.mbuksx1hqq.dll": "sha256-fhmxuuTKS1ndouHTj3FSu+KwUqWILi9nJAN1WJabAIs=",
292
- "MindExecution.Plugins.YouTube.snkp6shzuk.dll": "sha256-KEV5qk5uwybBSFgCjGFWSO07ZObjBSXhi6iP41dyxt0="
289
+ "MindExecution.Plugins.Admin.tsn0j478un.dll": "sha256-g5Q4Ihy2PJKx6EFB6k78dIszLgK4hZ3Xintjvso/zmw=",
290
+ "MindExecution.Plugins.Business.xg74dmn0vz.dll": "sha256-0bP/QgMyXSk9IlQVun63rnWvkwqqZmJcRe90QoPC6jw=",
291
+ "MindExecution.Plugins.Directory.9i4bd043ia.dll": "sha256-b+fpVz2RkQC8uL4dIvN6wMWWefoII84Jyfe85EU/URk=",
292
+ "MindExecution.Plugins.YouTube.0gfbwq1jfg.dll": "sha256-EEXiqTRw/mDzke0TaI/QAlp2DRCQCfL4lzGSH0pRZ4c="
293
293
  }
294
294
  },
295
295
  "cacheBootResources": true,
@@ -7,8 +7,8 @@
7
7
  <title>MindExec | Run your ideas as AI task graphs</title>
8
8
  <meta name="description" content="MindExec is an AI execution canvas for solo builders, researchers, developers, and creators. Start with free browser tools, then move serious work into saved MindCanvas projects." />
9
9
  <base href="/" />
10
- <link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260614-remote-realtime-frame-v512" />
11
- <link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260614-remote-realtime-frame-v512" />
10
+ <link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260614-remote-frame-queue-v514" />
11
+ <link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260614-remote-frame-queue-v514" />
12
12
  <!-- ?쇄뼹??Font Awesome (local) ?쇄뼹??-->
13
13
  <link rel="stylesheet" href="_content/MindExecution.Shared/lib/font-awesome/css/all.min.css" />
14
14
  <!-- ?꿎뼯??-->
@@ -558,7 +558,7 @@
558
558
  }
559
559
 
560
560
  const base = '_content/MindExecution.Shared/js/';
561
- const scriptVersion = '20260614-remote-realtime-frame-v512';
561
+ const scriptVersion = '20260614-remote-frame-queue-v514';
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": "kgm0PdX0",
2
+ "version": "AbrqsGjG",
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-V1OuXmwqGhSExZg1kWPPENZLaSPZWu/q/PgBwC3cQwg=",
89
+ "hash": "sha256-Ha83zpDlwJT6nxD2wgO3rL3uPBHZvZFxzpnKKHMZhd0=",
90
90
  "url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
91
91
  },
92
92
  {
@@ -410,44 +410,44 @@
410
410
  "url": "_framework/MimeMapping.og9ys58ylm.dll"
411
411
  },
412
412
  {
413
- "hash": "sha256-hPd6g1aLjuHKYrK39vB2e2zNIT03JHDIOogVdJisxpg=",
414
- "url": "_framework/MindExecution.Core.07ktly047n.dll"
413
+ "hash": "sha256-6cDbehKdjX71zeL9Ro5GNupn7wqRYfb7yLW2w3Wp05g=",
414
+ "url": "_framework/MindExecution.Core.fu1rl67yt3.dll"
415
415
  },
416
416
  {
417
- "hash": "sha256-QzAvoq5JLTdZZjwWkIuHVhCHFMjw92dGhzrYo0NM978=",
418
- "url": "_framework/MindExecution.Kernel.jgfwunsvz4.dll"
417
+ "hash": "sha256-zPB0tmwi/UKdJ//g0xMH1Y02ahDX5ii6ZKdB3yiQQz4=",
418
+ "url": "_framework/MindExecution.Kernel.cqcbagjpqb.dll"
419
419
  },
420
420
  {
421
- "hash": "sha256-5g1F71Jv0PP/HXccx2jBR5k8bgq2d2dK8XDYyObESnc=",
422
- "url": "_framework/MindExecution.Plugins.Admin.uz1ws5p7x5.dll"
421
+ "hash": "sha256-g5Q4Ihy2PJKx6EFB6k78dIszLgK4hZ3Xintjvso/zmw=",
422
+ "url": "_framework/MindExecution.Plugins.Admin.tsn0j478un.dll"
423
423
  },
424
424
  {
425
- "hash": "sha256-OiBtEdBJooJG9IAH2Zuhfh2NsJEtpbLoJ+jnC3a9VPU=",
426
- "url": "_framework/MindExecution.Plugins.Business.yeedyl4etv.dll"
425
+ "hash": "sha256-0bP/QgMyXSk9IlQVun63rnWvkwqqZmJcRe90QoPC6jw=",
426
+ "url": "_framework/MindExecution.Plugins.Business.xg74dmn0vz.dll"
427
427
  },
428
428
  {
429
- "hash": "sha256-chFP/WITGF1EPbkmHMqQmY90WQwsNG7jI+gjohLg744=",
430
- "url": "_framework/MindExecution.Plugins.Concept.i8wxwseow8.dll"
429
+ "hash": "sha256-/XUaopvgQk71o+jBdb3ljhCAQkXrda6XxCzS0242pIo=",
430
+ "url": "_framework/MindExecution.Plugins.Concept.j0zntvuecv.dll"
431
431
  },
432
432
  {
433
- "hash": "sha256-fhmxuuTKS1ndouHTj3FSu+KwUqWILi9nJAN1WJabAIs=",
434
- "url": "_framework/MindExecution.Plugins.Directory.mbuksx1hqq.dll"
433
+ "hash": "sha256-b+fpVz2RkQC8uL4dIvN6wMWWefoII84Jyfe85EU/URk=",
434
+ "url": "_framework/MindExecution.Plugins.Directory.9i4bd043ia.dll"
435
435
  },
436
436
  {
437
- "hash": "sha256-0xofgEHFyL96OcvSI34znXAL5ruOaGdGsci5Sh5T+mI=",
438
- "url": "_framework/MindExecution.Plugins.PlanMaster.vp3cl6bvxb.dll"
437
+ "hash": "sha256-uS3p/j4Kq171sz/xkiEn08DZni3X6HLbq2OHsYcxIjg=",
438
+ "url": "_framework/MindExecution.Plugins.PlanMaster.vml3qie2ji.dll"
439
439
  },
440
440
  {
441
- "hash": "sha256-KEV5qk5uwybBSFgCjGFWSO07ZObjBSXhi6iP41dyxt0=",
442
- "url": "_framework/MindExecution.Plugins.YouTube.snkp6shzuk.dll"
441
+ "hash": "sha256-EEXiqTRw/mDzke0TaI/QAlp2DRCQCfL4lzGSH0pRZ4c=",
442
+ "url": "_framework/MindExecution.Plugins.YouTube.0gfbwq1jfg.dll"
443
443
  },
444
444
  {
445
- "hash": "sha256-MvbceH+10w3Ss5amK8K4BC4Hx6trEMyXe1vAXQSdDyA=",
446
- "url": "_framework/MindExecution.Shared.irzb0k7hye.dll"
445
+ "hash": "sha256-1ZuF0eTN8dm8o0BzDJX+lyuKB1Wlc8MO2+kPJx/TYec=",
446
+ "url": "_framework/MindExecution.Shared.f3bclzo6k4.dll"
447
447
  },
448
448
  {
449
- "hash": "sha256-b0daeUMZRom6Z1kV+P0QhVWDaovg0QbC91vQIvA2ClQ=",
450
- "url": "_framework/MindExecution.Web.td6ps8xw4t.dll"
449
+ "hash": "sha256-QPegscpX6rm9Fp7lPqHdeKDVUFshfip6frFo62NWuss=",
450
+ "url": "_framework/MindExecution.Web.4jhsxoiqgz.dll"
451
451
  },
452
452
  {
453
453
  "hash": "sha256-IsZJ91/OW+fHzNqIgEc7Y072ns8z9dGritiSyvR9Wgc=",
@@ -770,7 +770,7 @@
770
770
  "url": "_framework/Websocket.Client.vapounvmnl.dll"
771
771
  },
772
772
  {
773
- "hash": "sha256-wGyB8Myog0UDbOOCHb4dhxOV/v55f4CdT7ZvxeRk7Z4=",
773
+ "hash": "sha256-XdUGtIDw1SDDWXPLtg2RaeuvCW6T6yjMxok5H9KUFaE=",
774
774
  "url": "_framework/blazor.boot.json"
775
775
  },
776
776
  {
@@ -834,7 +834,7 @@
834
834
  "url": "image-manifest.json"
835
835
  },
836
836
  {
837
- "hash": "sha256-9BW4+BDrFuEuMemTbJ1oaH74zwmzsmqIe1JmRtmlqEg=",
837
+ "hash": "sha256-CSvUcpq/bag2h6q/jhgdebJ5n7IE9rrAbielPCFI5jk=",
838
838
  "url": "index.html"
839
839
  },
840
840
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: kgm0PdX0 */
1
+ /* Manifest version: AbrqsGjG */
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