@mindexec/cli 0.2.6 → 0.2.7

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/README.md +12 -0
  2. package/package.json +1 -1
  3. package/remote-hub.js +167 -0
  4. package/scripts/remote-hub-smoke.mjs +54 -0
  5. package/server.js +28 -0
  6. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +272 -9
  7. package/wwwroot/_framework/MindExecution.Core.pnw79cgqjx.dll +0 -0
  8. package/wwwroot/_framework/{MindExecution.Kernel.79mgmkpsy1.dll → MindExecution.Kernel.dt3w864bqn.dll} +0 -0
  9. package/wwwroot/_framework/{MindExecution.Plugins.Admin.8ey1m70q79.dll → MindExecution.Plugins.Admin.z93cu32xru.dll} +0 -0
  10. package/wwwroot/_framework/{MindExecution.Plugins.Business.8rvwgqzxaz.dll → MindExecution.Plugins.Business.b6da8sg85t.dll} +0 -0
  11. package/wwwroot/_framework/{MindExecution.Plugins.Concept.ynnk3bqf03.dll → MindExecution.Plugins.Concept.mjooiqft9j.dll} +0 -0
  12. package/wwwroot/_framework/{MindExecution.Plugins.Directory.vi24rmnuyq.dll → MindExecution.Plugins.Directory.rjod6rdmly.dll} +0 -0
  13. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.9r08m5atjr.dll → MindExecution.Plugins.PlanMaster.1dcrzhsegj.dll} +0 -0
  14. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.fjkbniwa4o.dll → MindExecution.Plugins.YouTube.k75qxhbpp8.dll} +0 -0
  15. package/wwwroot/_framework/{MindExecution.Shared.e0qnm5vtax.dll → MindExecution.Shared.y3eqxd3mvo.dll} +0 -0
  16. package/wwwroot/_framework/MindExecution.Web.wou9x6mn2f.dll +0 -0
  17. package/wwwroot/_framework/blazor.boot.json +21 -21
  18. package/wwwroot/index.html +1 -1
  19. package/wwwroot/service-worker-assets.js +24 -24
  20. package/wwwroot/service-worker.js +1 -1
  21. package/wwwroot/_framework/MindExecution.Core.kf4752v5yl.dll +0 -0
  22. package/wwwroot/_framework/MindExecution.Web.wk9yv02eva.dll +0 -0
package/README.md CHANGED
@@ -83,6 +83,18 @@ curl -X POST -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5147/api/remot
83
83
  curl -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5147/api/remote/devices/<device-id>/thumbnail
84
84
  ```
85
85
 
86
+ Start, read, and stop the focused view-only RemoteFast live stream:
87
+
88
+ ```bash
89
+ curl -X POST -H "X-Bridge-Token: <bridge-token>" -H "Content-Type: application/json" \
90
+ -d "{\"fps\":12,\"maxWidth\":960,\"maxHeight\":540,\"quality\":60}" \
91
+ http://127.0.0.1:5147/api/remote/devices/<device-id>/live/start
92
+
93
+ curl -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5147/api/remote/devices/<device-id>/live/frame
94
+
95
+ curl -X POST -H "X-Bridge-Token: <bridge-token>" http://127.0.0.1:5147/api/remote/devices/<device-id>/live/stop
96
+ ```
97
+
86
98
  Queue a safe task-only instruction for one device or all connected devices:
87
99
 
88
100
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
package/remote-hub.js CHANGED
@@ -7,6 +7,7 @@ const DEFAULT_REMOTE_HUB_HOST = '127.0.0.1';
7
7
  const DEFAULT_HEARTBEAT_MS = 5000;
8
8
  const MAX_LINE_CHARS = 4 * 1024 * 1024;
9
9
  const MAX_THUMBNAIL_BASE64_CHARS = 3 * 1024 * 1024;
10
+ const MAX_STREAM_BASE64_CHARS = 3 * 1024 * 1024;
10
11
  const MAX_AGENT_TASK_CHARS = 4000;
11
12
  const MAX_AGENT_TASK_RESULT_CHARS = 3000;
12
13
  const RECENT_TASK_LIMIT = 12;
@@ -118,6 +119,8 @@ function serializeDevice(device) {
118
119
  remoteAddress: device.remoteAddress,
119
120
  remotePort: device.remotePort,
120
121
  latestThumbnail: device.latestThumbnail ? { ...device.latestThumbnail } : null,
122
+ latestLiveFrame: device.latestLiveFrame ? { ...device.latestLiveFrame } : null,
123
+ activeLiveStream: device.activeLiveStream ? { ...device.activeLiveStream } : null,
121
124
  latestTask: device.latestTask ? { ...device.latestTask } : null,
122
125
  recentTasks: Array.isArray(device.recentTasks)
123
126
  ? device.recentTasks.map(task => ({ ...task }))
@@ -249,6 +252,8 @@ export function createRemoteHub(options = {}) {
249
252
  remotePort: socket.remotePort || 0,
250
253
  status: {},
251
254
  latestThumbnail: null,
255
+ latestLiveFrame: null,
256
+ activeLiveStream: null,
252
257
  latestTask: null,
253
258
  recentTasks: [],
254
259
  pendingTaskCommands: new Map(),
@@ -259,6 +264,10 @@ export function createRemoteHub(options = {}) {
259
264
  commandResultsReceived: 0,
260
265
  thumbnailFramesReceived: 0,
261
266
  thumbnailFramesDropped: 0,
267
+ liveFramesReceived: 0,
268
+ liveFramesDropped: 0,
269
+ liveStreamsStarted: 0,
270
+ liveStreamsStopped: 0,
262
271
  tasksQueued: 0,
263
272
  taskResultsReceived: 0,
264
273
  taskResultsFailed: 0
@@ -297,6 +306,11 @@ export function createRemoteHub(options = {}) {
297
306
  device.socket = null;
298
307
  device.disconnectedAt = new Date().toISOString();
299
308
  device.lastDisconnectReason = reason;
309
+ if (device.activeLiveStream) {
310
+ device.activeLiveStream.active = false;
311
+ device.activeLiveStream.stoppedAt = device.disconnectedAt;
312
+ device.activeLiveStream.stopReason = reason;
313
+ }
300
314
  logWarn('remote', `device disconnected ${device.deviceName} (${deviceId}): ${reason}`);
301
315
  emitRemoteEvent('RemoteDeviceDisconnected', device, { reason });
302
316
  }
@@ -475,6 +489,62 @@ export function createRemoteHub(options = {}) {
475
489
  });
476
490
  break;
477
491
  }
492
+ case 'stream.frame': {
493
+ const frameData = safeString(message.data, MAX_STREAM_BASE64_CHARS + 1);
494
+ const frameSeq = Number(message.frameSeq);
495
+ const streamId = safeString(message.streamId, 128) || 'live';
496
+ if (!device.activeLiveStream?.active || device.activeLiveStream.streamId !== streamId) {
497
+ device.counters.liveFramesDropped += 1;
498
+ emitRemoteEvent('RemoteFrameDropped', device, {
499
+ reason: 'stale-live-stream-frame',
500
+ streamId,
501
+ frameSeq: Number.isFinite(frameSeq) ? frameSeq : null
502
+ });
503
+ break;
504
+ }
505
+
506
+ if (!frameData || frameData.length > MAX_STREAM_BASE64_CHARS || !Number.isFinite(frameSeq)) {
507
+ device.counters.liveFramesDropped += 1;
508
+ emitRemoteEvent('RemoteFrameDropped', device, {
509
+ reason: 'invalid-live-frame',
510
+ streamId,
511
+ frameSeq: Number.isFinite(frameSeq) ? frameSeq : null
512
+ });
513
+ break;
514
+ }
515
+
516
+ const mimeType = safeString(message.mimeType || message.format || 'image/jpeg', 80) || 'image/jpeg';
517
+ const capturedAt = safeString(message.capturedAt, 80) || device.lastSeenAt;
518
+ device.latestLiveFrame = {
519
+ streamId,
520
+ frameSeq,
521
+ commandId: safeString(message.commandId, 128),
522
+ width: Number.isFinite(Number(message.width)) ? Number(message.width) : 0,
523
+ height: Number.isFinite(Number(message.height)) ? Number(message.height) : 0,
524
+ mimeType,
525
+ format: mimeType,
526
+ mode: safeString(message.mode || device.activeLiveStream.mode || 'remote-fast', 80),
527
+ fps: Number.isFinite(Number(message.fps)) ? Number(message.fps) : device.activeLiveStream.fps,
528
+ capturedAt,
529
+ receivedAt: device.lastSeenAt,
530
+ byteLength: Math.floor(frameData.length * 3 / 4),
531
+ dataUrl: frameData.startsWith('data:')
532
+ ? frameData
533
+ : `data:${mimeType};base64,${frameData}`
534
+ };
535
+ device.activeLiveStream.lastFrameAt = device.lastSeenAt;
536
+ device.activeLiveStream.lastFrameSeq = frameSeq;
537
+ device.activeLiveStream.framesReceived = (device.activeLiveStream.framesReceived || 0) + 1;
538
+ device.counters.liveFramesReceived += 1;
539
+ emitRemoteEvent('RemoteFrameReceived', device, {
540
+ streamId,
541
+ frameSeq,
542
+ width: device.latestLiveFrame.width,
543
+ height: device.latestLiveFrame.height,
544
+ mode: device.latestLiveFrame.mode
545
+ });
546
+ break;
547
+ }
478
548
  default:
479
549
  emitRemoteEvent('RemoteAgentMessageIgnored', device, {
480
550
  messageType: safeString(message.type, 80)
@@ -731,6 +801,100 @@ export function createRemoteHub(options = {}) {
731
801
  });
732
802
  }
733
803
 
804
+ function startLiveStream(deviceId, options = {}) {
805
+ const device = devices.get(String(deviceId || ''));
806
+ if (!device?.socket || device.socket.destroyed || !device.connected) {
807
+ return { ok: false, error: 'device-not-connected' };
808
+ }
809
+ if (!readCapabilityFlag(device.capabilities, 'liveStream')) {
810
+ return { ok: false, error: 'device-live-stream-unavailable' };
811
+ }
812
+
813
+ const now = new Date().toISOString();
814
+ const streamId = safeString(options.streamId, 128) || `live-${Date.now()}`;
815
+ const fps = clampNumber(options.fps, 1, 24, 12);
816
+ const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
817
+ const result = sendCommand(deviceId, {
818
+ command: 'stream.start',
819
+ commandId,
820
+ payload: {
821
+ streamId,
822
+ mode: safeString(options.mode, 80) || 'remote-fast',
823
+ fps,
824
+ maxWidth: clampNumber(options.maxWidth, 320, 2560, 960),
825
+ maxHeight: clampNumber(options.maxHeight, 180, 1440, 540),
826
+ quality: clampNumber(options.quality, 20, 95, 60),
827
+ requestedAt: now
828
+ }
829
+ });
830
+
831
+ if (!result.ok) {
832
+ return result;
833
+ }
834
+
835
+ device.activeLiveStream = {
836
+ streamId,
837
+ commandId,
838
+ active: true,
839
+ mode: 'remote-fast',
840
+ fps,
841
+ startedAt: now,
842
+ stoppedAt: '',
843
+ stopReason: '',
844
+ lastFrameAt: '',
845
+ lastFrameSeq: 0,
846
+ framesReceived: 0
847
+ };
848
+ device.counters.liveStreamsStarted += 1;
849
+ emitRemoteEvent('RemoteLiveStreamStarted', device, {
850
+ streamId,
851
+ commandId,
852
+ fps
853
+ });
854
+
855
+ return { ok: true, commandId, streamId, fps };
856
+ }
857
+
858
+ function stopLiveStream(deviceId, options = {}) {
859
+ const device = devices.get(String(deviceId || ''));
860
+ if (!device?.socket || device.socket.destroyed || !device.connected) {
861
+ return { ok: false, error: 'device-not-connected' };
862
+ }
863
+
864
+ const streamId = safeString(options.streamId, 128) || device.activeLiveStream?.streamId || '';
865
+ const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
866
+ const result = sendCommand(deviceId, {
867
+ command: 'stream.stop',
868
+ commandId,
869
+ payload: {
870
+ streamId,
871
+ requestedAt: new Date().toISOString()
872
+ }
873
+ });
874
+
875
+ if (!result.ok) {
876
+ return result;
877
+ }
878
+
879
+ if (device.activeLiveStream && (!streamId || device.activeLiveStream.streamId === streamId)) {
880
+ device.activeLiveStream.active = false;
881
+ device.activeLiveStream.stoppedAt = new Date().toISOString();
882
+ device.activeLiveStream.stopReason = 'manager-request';
883
+ }
884
+ device.counters.liveStreamsStopped += 1;
885
+ emitRemoteEvent('RemoteLiveStreamStopped', device, {
886
+ streamId,
887
+ commandId
888
+ });
889
+
890
+ return { ok: true, commandId, streamId };
891
+ }
892
+
893
+ function getDeviceLiveFrame(deviceId) {
894
+ const device = devices.get(String(deviceId || ''));
895
+ return device?.latestLiveFrame ? { ...device.latestLiveFrame } : null;
896
+ }
897
+
734
898
  function getDeviceThumbnail(deviceId) {
735
899
  const device = devices.get(String(deviceId || ''));
736
900
  return device?.latestThumbnail ? { ...device.latestThumbnail } : null;
@@ -745,6 +909,9 @@ export function createRemoteHub(options = {}) {
745
909
  sendCommand,
746
910
  requestAgentTask,
747
911
  requestThumbnail,
912
+ startLiveStream,
913
+ stopLiveStream,
914
+ getDeviceLiveFrame,
748
915
  getDeviceThumbnail,
749
916
  getPairToken: () => pairToken
750
917
  };
@@ -61,6 +61,7 @@ try {
61
61
  status: true,
62
62
  thumbnail: false,
63
63
  control: false,
64
+ liveStream: true,
64
65
  computerAgent: true,
65
66
  taskDispatch: true,
66
67
  aiAssist: true,
@@ -112,6 +113,59 @@ try {
112
113
  assert.equal(thumbnailDevice.latestThumbnail.streamId, 'smoke-thumb');
113
114
  assert.equal(thumbnailDevice.counters.thumbnailFramesReceived, 1);
114
115
 
116
+ const liveCommand = hub.startLiveStream('smoke-device', {
117
+ streamId: 'smoke-live',
118
+ fps: 5,
119
+ maxWidth: 320,
120
+ maxHeight: 180,
121
+ quality: 50
122
+ });
123
+ assert.equal(liveCommand.ok, true);
124
+ writeJsonLine(socket, {
125
+ type: 'stream.frame',
126
+ commandId: liveCommand.commandId,
127
+ streamId: 'smoke-live',
128
+ frameSeq: 2,
129
+ width: 2,
130
+ height: 1,
131
+ mimeType: 'image/png',
132
+ mode: 'remote-fast',
133
+ fps: 5,
134
+ capturedAt: new Date().toISOString(),
135
+ data: 'iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAYAAAD0In+KAAAADElEQVR42mP8z8AAAAMBAQDJ/pLvAAAAAElFTkSuQmCC'
136
+ });
137
+
138
+ const liveDevice = await waitFor(() => {
139
+ const current = hub.listDevices();
140
+ return current[0]?.latestLiveFrame?.streamId === 'smoke-live' ? current[0] : null;
141
+ });
142
+ assert.equal(liveDevice.activeLiveStream.active, true);
143
+ assert.equal(liveDevice.latestLiveFrame.mode, 'remote-fast');
144
+ assert.equal(liveDevice.counters.liveFramesReceived, 1);
145
+
146
+ const staleFrameBefore = liveDevice.counters.liveFramesDropped;
147
+ writeJsonLine(socket, {
148
+ type: 'stream.frame',
149
+ streamId: 'stale-live',
150
+ frameSeq: 3,
151
+ width: 2,
152
+ height: 1,
153
+ mimeType: 'image/png',
154
+ capturedAt: new Date().toISOString(),
155
+ data: 'iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAYAAAD0In+KAAAADElEQVR42mP8z8AAAAMBAQDJ/pLvAAAAAElFTkSuQmCC'
156
+ });
157
+ const staleDropDevice = await waitFor(() => {
158
+ const current = hub.listDevices();
159
+ return current[0]?.counters?.liveFramesDropped > staleFrameBefore ? current[0] : null;
160
+ });
161
+ assert.equal(staleDropDevice.latestLiveFrame.streamId, 'smoke-live');
162
+
163
+ const stopLiveCommand = hub.stopLiveStream('smoke-device', {
164
+ streamId: 'smoke-live'
165
+ });
166
+ assert.equal(stopLiveCommand.ok, true);
167
+ assert.equal(hub.listDevices()[0].activeLiveStream.active, false);
168
+
115
169
  const taskCommand = hub.requestAgentTask('smoke-device', {
116
170
  instruction: 'Summarize current desktop status for the manager.',
117
171
  title: 'Smoke task'
package/server.js CHANGED
@@ -7048,6 +7048,34 @@ app.post('/api/remote/devices/:deviceId/thumbnail/request', (req, res) => {
7048
7048
  }));
7049
7049
  });
7050
7050
 
7051
+ app.get('/api/remote/devices/:deviceId/live/frame', (req, res) => {
7052
+ res.setHeader('Cache-Control', 'no-store');
7053
+ const frame = remoteHub.getDeviceLiveFrame(req.params.deviceId);
7054
+ if (!frame) {
7055
+ res.status(404).json({ ok: false, error: 'live-frame-not-available' });
7056
+ return;
7057
+ }
7058
+
7059
+ res.json({ ok: true, frame });
7060
+ });
7061
+
7062
+ app.post('/api/remote/devices/:deviceId/live/start', (req, res) => {
7063
+ res.json(remoteHub.startLiveStream(req.params.deviceId, {
7064
+ streamId: req.body?.streamId,
7065
+ mode: req.body?.mode,
7066
+ fps: req.body?.fps,
7067
+ maxWidth: req.body?.maxWidth,
7068
+ maxHeight: req.body?.maxHeight,
7069
+ quality: req.body?.quality
7070
+ }));
7071
+ });
7072
+
7073
+ app.post('/api/remote/devices/:deviceId/live/stop', (req, res) => {
7074
+ res.json(remoteHub.stopLiveStream(req.params.deviceId, {
7075
+ streamId: req.body?.streamId
7076
+ }));
7077
+ });
7078
+
7051
7079
  app.get('/api/codex/capabilities', async (req, res) => {
7052
7080
  try {
7053
7081
  res.json(await getCodexRuntime().getCapabilities());
@@ -12139,6 +12139,15 @@
12139
12139
  return /^data:image\/(png|jpe?g|webp|svg\+xml);base64,/i.test(dataUrl);
12140
12140
  }
12141
12141
 
12142
+ function hasRemoteFleetLiveFrame(device) {
12143
+ const dataUrl = String(getRemoteFleetDeviceField(device, 'liveFrameDataUrl', 'LiveFrameDataUrl', ''));
12144
+ return /^data:image\/(png|jpe?g|webp|svg\+xml);base64,/i.test(dataUrl);
12145
+ }
12146
+
12147
+ function isRemoteFleetLiveActive(device) {
12148
+ return getRemoteFleetDeviceField(device, 'liveStreamActive', 'LiveStreamActive', false) === true;
12149
+ }
12150
+
12142
12151
  function getRemoteFleetTimestampMs(value) {
12143
12152
  const timestamp = Date.parse(String(value || ''));
12144
12153
  return Number.isFinite(timestamp) ? timestamp : 0;
@@ -12165,6 +12174,8 @@
12165
12174
  getRemoteFleetDeviceField(device, 'release', 'Release', ''),
12166
12175
  getRemoteFleetDeviceField(device, 'arch', 'Arch', ''),
12167
12176
  getRemoteFleetDeviceField(device, 'agentVersion', 'AgentVersion', ''),
12177
+ getRemoteFleetDeviceField(device, 'liveStreamMode', 'LiveStreamMode', ''),
12178
+ isRemoteFleetLiveActive(device) ? 'live active remote-fast' : '',
12168
12179
  getRemoteFleetDeviceField(device, 'latestTaskTitle', 'LatestTaskTitle', ''),
12169
12180
  getRemoteFleetDeviceField(device, 'latestTaskStatus', 'LatestTaskStatus', ''),
12170
12181
  getRemoteFleetDeviceField(device, 'latestTaskResultSummary', 'LatestTaskResultSummary', ''),
@@ -12210,6 +12221,10 @@
12210
12221
 
12211
12222
  function renderRemoteFleetMonitor(bodyView, nodeModel) {
12212
12223
  if (!bodyView) return;
12224
+ if (bodyView._remoteFleetLiveRefreshTimer) {
12225
+ clearInterval(bodyView._remoteFleetLiveRefreshTimer);
12226
+ bodyView._remoteFleetLiveRefreshTimer = null;
12227
+ }
12213
12228
 
12214
12229
  const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
12215
12230
  const searchState = bodyView.dataset.remoteFleetSearch || '';
@@ -12217,8 +12232,16 @@
12217
12232
  const sortState = bodyView.dataset.remoteFleetSort || 'status';
12218
12233
  const densityState = bodyView.dataset.remoteFleetDensity || 'cards';
12219
12234
  const aiAssistState = bodyView.dataset.remoteFleetAiAssist === 'true';
12235
+ const focusState = bodyView.dataset.remoteFleetFocusDeviceId || '';
12220
12236
  const devices = [...parseRemoteFleetDevices(nodeModel)]
12221
12237
  .sort((left, right) => compareRemoteFleetDevices(left, right, sortState));
12238
+ const hasActiveLiveStream = devices.some(isRemoteFleetLiveActive);
12239
+ const focusedDevice = devices.find(device => getRemoteFleetDeviceId(device) === focusState)
12240
+ || devices.find(device => isRemoteFleetLiveActive(device))
12241
+ || null;
12242
+ if (focusedDevice) {
12243
+ bodyView.dataset.remoteFleetFocusDeviceId = getRemoteFleetDeviceId(focusedDevice);
12244
+ }
12222
12245
  const total = Number(getRemoteFleetMetadataValue(nodeModel, 'RemoteFleetDeviceCount', devices.length));
12223
12246
  const connected = Number(getRemoteFleetMetadataValue(
12224
12247
  nodeModel,
@@ -12333,6 +12356,7 @@
12333
12356
  { value: 'offline', label: 'Offline' },
12334
12357
  { value: 'task', label: 'Task' },
12335
12358
  { value: 'ai', label: 'AI' },
12359
+ { value: 'live', label: 'Live' },
12336
12360
  { value: 'frames', label: 'Frames' },
12337
12361
  { value: 'issues', label: 'Issues' }
12338
12362
  ], filterState, 'Device filter');
@@ -12465,6 +12489,141 @@
12465
12489
  `;
12466
12490
  bodyView.appendChild(taskFeedback);
12467
12491
 
12492
+ if (focusedDevice) {
12493
+ const focusedId = getRemoteFleetDeviceId(focusedDevice);
12494
+ const focusedName = getRemoteFleetDeviceName(focusedDevice);
12495
+ const liveActive = isRemoteFleetLiveActive(focusedDevice);
12496
+ const liveFrameDataUrl = String(getRemoteFleetDeviceField(focusedDevice, 'liveFrameDataUrl', 'LiveFrameDataUrl', ''));
12497
+ const liveFrameAt = String(getRemoteFleetDeviceField(focusedDevice, 'liveFrameReceivedAt', 'LiveFrameReceivedAt', ''));
12498
+ const liveStreamId = String(getRemoteFleetDeviceField(focusedDevice, 'liveStreamId', 'LiveStreamId', ''));
12499
+ const hasLiveFrame = hasRemoteFleetLiveFrame(focusedDevice);
12500
+ const livePanel = document.createElement('section');
12501
+ livePanel.dataset.remoteFleetLivePanel = 'true';
12502
+ livePanel.dataset.deviceId = focusedId;
12503
+ livePanel.style.cssText = `
12504
+ flex: 0 0 auto;
12505
+ display: grid;
12506
+ grid-template-columns: minmax(220px, 0.95fr) minmax(0, 1.25fr);
12507
+ gap: 10px;
12508
+ min-height: 170px;
12509
+ padding: 10px;
12510
+ border-radius: 8px;
12511
+ border: 1px solid rgba(14, 165, 233, 0.24);
12512
+ background: rgba(255, 255, 255, 0.82);
12513
+ `;
12514
+
12515
+ const livePreview = document.createElement('div');
12516
+ livePreview.style.cssText = `
12517
+ position: relative;
12518
+ min-width: 0;
12519
+ aspect-ratio: 16 / 9;
12520
+ overflow: hidden;
12521
+ border-radius: 7px;
12522
+ background: linear-gradient(135deg, #111827 0%, #1f2937 100%);
12523
+ border: 1px solid rgba(15, 23, 42, 0.16);
12524
+ `;
12525
+ if (hasLiveFrame) {
12526
+ const image = document.createElement('img');
12527
+ image.src = liveFrameDataUrl;
12528
+ image.alt = `${focusedName} live screen`;
12529
+ image.decoding = 'async';
12530
+ image.style.cssText = `
12531
+ width: 100%;
12532
+ height: 100%;
12533
+ object-fit: cover;
12534
+ display: block;
12535
+ `;
12536
+ livePreview.appendChild(image);
12537
+ } else {
12538
+ const placeholder = document.createElement('div');
12539
+ placeholder.textContent = liveActive ? 'Waiting for live frame' : 'Live view idle';
12540
+ placeholder.style.cssText = `
12541
+ position: absolute;
12542
+ inset: 0;
12543
+ display: flex;
12544
+ align-items: center;
12545
+ justify-content: center;
12546
+ color: rgba(226, 232, 240, 0.82);
12547
+ font-size: 12px;
12548
+ font-weight: 900;
12549
+ letter-spacing: 0;
12550
+ `;
12551
+ livePreview.appendChild(placeholder);
12552
+ }
12553
+ const liveBadge = document.createElement('span');
12554
+ liveBadge.textContent = liveActive
12555
+ ? `LIVE ${liveFrameAt ? formatRemoteFleetAge(liveFrameAt) : ''}`.trim()
12556
+ : 'FOCUS';
12557
+ liveBadge.style.cssText = `
12558
+ position: absolute;
12559
+ left: 7px;
12560
+ top: 7px;
12561
+ max-width: calc(100% - 14px);
12562
+ padding: 4px 7px;
12563
+ border-radius: 999px;
12564
+ background: ${liveActive ? 'rgba(220, 38, 38, 0.86)' : 'rgba(15, 23, 42, 0.72)'};
12565
+ color: #ffffff;
12566
+ font-size: 9px;
12567
+ font-weight: 950;
12568
+ line-height: 1;
12569
+ overflow: hidden;
12570
+ text-overflow: ellipsis;
12571
+ white-space: nowrap;
12572
+ letter-spacing: 0;
12573
+ `;
12574
+ livePreview.appendChild(liveBadge);
12575
+
12576
+ const liveInfo = document.createElement('div');
12577
+ liveInfo.style.cssText = `
12578
+ min-width: 0;
12579
+ display: flex;
12580
+ flex-direction: column;
12581
+ justify-content: space-between;
12582
+ gap: 8px;
12583
+ `;
12584
+ const liveTitle = document.createElement('div');
12585
+ liveTitle.style.cssText = 'min-width:0;display:flex;flex-direction:column;gap:3px;';
12586
+ const liveName = document.createElement('strong');
12587
+ liveName.textContent = focusedName;
12588
+ liveName.title = focusedName;
12589
+ liveName.style.cssText = 'color:#0f172a;font-size:15px;font-weight:950;line-height:1.15;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;letter-spacing:0;';
12590
+ const liveMeta = document.createElement('span');
12591
+ liveMeta.textContent = liveActive
12592
+ ? `RemoteFast ${getRemoteFleetDeviceField(focusedDevice, 'liveStreamFps', 'LiveStreamFps', 0) || 12} fps`
12593
+ : 'View-only focused screen stream';
12594
+ liveMeta.style.cssText = 'color:#475569;font-size:11px;font-weight:800;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;letter-spacing:0;';
12595
+ liveTitle.appendChild(liveName);
12596
+ liveTitle.appendChild(liveMeta);
12597
+
12598
+ const liveActions = document.createElement('div');
12599
+ liveActions.style.cssText = 'display:flex;align-items:center;gap:8px;flex-wrap:wrap;';
12600
+ if (isRemoteFleetDeviceConnected(focusedDevice) && getRemoteFleetDeviceField(focusedDevice, 'liveStreamEnabled', 'LiveStreamEnabled', false) === true) {
12601
+ const startLiveButton = createRemoteFleetButton(liveActive ? 'Restart live' : 'Start live', 'Start focused view-only live stream', 'live-start');
12602
+ startLiveButton.dataset.deviceId = focusedId;
12603
+ startLiveButton.style.height = '30px';
12604
+ liveActions.appendChild(startLiveButton);
12605
+ if (liveActive) {
12606
+ const stopLiveButton = createRemoteFleetButton('Stop live', 'Stop focused live stream', 'live-stop');
12607
+ stopLiveButton.dataset.deviceId = focusedId;
12608
+ stopLiveButton.dataset.streamId = liveStreamId;
12609
+ stopLiveButton.style.height = '30px';
12610
+ stopLiveButton.style.borderColor = 'rgba(220, 38, 38, 0.32)';
12611
+ stopLiveButton.style.color = '#b91c1c';
12612
+ liveActions.appendChild(stopLiveButton);
12613
+ }
12614
+ } else {
12615
+ const disabled = document.createElement('span');
12616
+ disabled.textContent = 'Live unavailable';
12617
+ disabled.style.cssText = 'color:#64748b;font-size:11px;font-weight:900;';
12618
+ liveActions.appendChild(disabled);
12619
+ }
12620
+ liveInfo.appendChild(liveTitle);
12621
+ liveInfo.appendChild(liveActions);
12622
+ livePanel.appendChild(livePreview);
12623
+ livePanel.appendChild(liveInfo);
12624
+ bodyView.appendChild(livePanel);
12625
+ }
12626
+
12468
12627
  if (lastError.trim()) {
12469
12628
  const errorEl = document.createElement('div');
12470
12629
  errorEl.textContent = lastError;
@@ -12524,7 +12683,13 @@
12524
12683
  const thumbnailEnabled = device?.thumbnailEnabled === true || device?.ThumbnailEnabled === true;
12525
12684
  const thumbnailDataUrl = String(device?.thumbnailDataUrl || device?.ThumbnailDataUrl || '');
12526
12685
  const thumbnailCapturedAt = String(device?.thumbnailCapturedAt || device?.ThumbnailCapturedAt || '');
12686
+ const liveStreamEnabled = device?.liveStreamEnabled === true || device?.LiveStreamEnabled === true;
12687
+ const liveStreamActive = isRemoteFleetLiveActive(device);
12688
+ const liveStreamId = String(device?.liveStreamId || device?.LiveStreamId || '');
12689
+ const liveFrameDataUrl = String(device?.liveFrameDataUrl || device?.LiveFrameDataUrl || '');
12690
+ const liveFrameReceivedAt = String(device?.liveFrameReceivedAt || device?.LiveFrameReceivedAt || '');
12527
12691
  const hasThumbnail = hasRemoteFleetThumbnail(device);
12692
+ const hasLiveFrame = hasRemoteFleetLiveFrame(device);
12528
12693
  const taskEnabled = isRemoteFleetDeviceTaskCapable(device);
12529
12694
  const aiAssistEnabled = isRemoteFleetDeviceAiCapable(device);
12530
12695
  const aiModel = String(device?.aiModel || device?.AiModel || '');
@@ -12540,7 +12705,9 @@
12540
12705
  card.dataset.remoteFleetConnected = connectedDevice ? 'true' : 'false';
12541
12706
  card.dataset.remoteFleetTaskCapable = taskEnabled ? 'true' : 'false';
12542
12707
  card.dataset.remoteFleetAiCapable = aiAssistEnabled ? 'true' : 'false';
12543
- card.dataset.remoteFleetHasFrame = hasThumbnail ? 'true' : 'false';
12708
+ card.dataset.remoteFleetHasFrame = (hasThumbnail || hasLiveFrame) ? 'true' : 'false';
12709
+ card.dataset.remoteFleetLiveCapable = liveStreamEnabled ? 'true' : 'false';
12710
+ card.dataset.remoteFleetLiveActive = liveStreamActive ? 'true' : 'false';
12544
12711
  card.dataset.remoteFleetIssue = (!connectedDevice || latestTaskStatus === 'failed' || !!latestTaskError) ? 'true' : 'false';
12545
12712
  card.style.cssText = `
12546
12713
  display: flex;
@@ -12556,6 +12723,8 @@
12556
12723
  `;
12557
12724
 
12558
12725
  if (densityState !== 'dense') {
12726
+ const previewDataUrl = hasLiveFrame ? liveFrameDataUrl : thumbnailDataUrl;
12727
+ const previewAt = hasLiveFrame ? liveFrameReceivedAt : thumbnailCapturedAt;
12559
12728
  const preview = document.createElement('div');
12560
12729
  preview.style.cssText = `
12561
12730
  position: relative;
@@ -12566,10 +12735,10 @@
12566
12735
  background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
12567
12736
  border: 1px solid rgba(15, 23, 42, 0.12);
12568
12737
  `;
12569
- if (hasThumbnail) {
12738
+ if (hasLiveFrame || hasThumbnail) {
12570
12739
  const image = document.createElement('img');
12571
- image.src = thumbnailDataUrl;
12572
- image.alt = `${name} thumbnail`;
12740
+ image.src = previewDataUrl;
12741
+ image.alt = hasLiveFrame ? `${name} live frame` : `${name} thumbnail`;
12573
12742
  image.loading = 'lazy';
12574
12743
  image.decoding = 'async';
12575
12744
  image.style.cssText = `
@@ -12595,9 +12764,11 @@
12595
12764
  `;
12596
12765
  preview.appendChild(placeholder);
12597
12766
  }
12598
- if (thumbnailCapturedAt) {
12767
+ if (previewAt) {
12599
12768
  const badge = document.createElement('span');
12600
- badge.textContent = formatRemoteFleetAge(thumbnailCapturedAt);
12769
+ badge.textContent = hasLiveFrame
12770
+ ? `LIVE ${formatRemoteFleetAge(previewAt)}`
12771
+ : formatRemoteFleetAge(previewAt);
12601
12772
  badge.style.cssText = `
12602
12773
  position: absolute;
12603
12774
  right: 6px;
@@ -12605,7 +12776,7 @@
12605
12776
  max-width: calc(100% - 12px);
12606
12777
  padding: 3px 6px;
12607
12778
  border-radius: 999px;
12608
- background: rgba(15, 23, 42, 0.74);
12779
+ background: ${hasLiveFrame ? 'rgba(220, 38, 38, 0.82)' : 'rgba(15, 23, 42, 0.74)'};
12609
12780
  color: #e2e8f0;
12610
12781
  font-size: 9px;
12611
12782
  font-weight: 900;
@@ -12763,11 +12934,11 @@
12763
12934
  actions.style.cssText = 'display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:auto;';
12764
12935
  const status = document.createElement('span');
12765
12936
  status.textContent = connectedDevice
12766
- ? (aiAssistEnabled ? `AI ${aiModel || 'ready'}` : 'Connected')
12937
+ ? (liveStreamActive ? 'Live' : (aiAssistEnabled ? `AI ${aiModel || 'ready'}` : 'Connected'))
12767
12938
  : 'Offline';
12768
12939
  status.style.cssText = `
12769
12940
  min-width: 0;
12770
- color: ${connectedDevice ? '#047857' : '#64748b'};
12941
+ color: ${liveStreamActive ? '#b91c1c' : (connectedDevice ? '#047857' : '#64748b')};
12771
12942
  font-size: 11px;
12772
12943
  font-weight: 900;
12773
12944
  overflow: hidden;
@@ -12776,6 +12947,23 @@
12776
12947
  `;
12777
12948
  actions.appendChild(status);
12778
12949
  if (connectedDevice && deviceId) {
12950
+ const focusButton = createRemoteFleetButton('Focus', 'Show this device in focused live panel', 'live-focus');
12951
+ focusButton.dataset.deviceId = deviceId;
12952
+ focusButton.style.height = '24px';
12953
+ focusButton.style.fontSize = '10px';
12954
+ actions.appendChild(focusButton);
12955
+ if (liveStreamEnabled) {
12956
+ const liveButton = createRemoteFleetButton(liveStreamActive ? 'Stop' : 'Live', liveStreamActive ? 'Stop live stream' : 'Start focused live stream', liveStreamActive ? 'live-stop' : 'live-start');
12957
+ liveButton.dataset.deviceId = deviceId;
12958
+ liveButton.dataset.streamId = liveStreamId;
12959
+ liveButton.style.height = '24px';
12960
+ liveButton.style.fontSize = '10px';
12961
+ if (liveStreamActive) {
12962
+ liveButton.style.borderColor = 'rgba(220, 38, 38, 0.32)';
12963
+ liveButton.style.color = '#b91c1c';
12964
+ }
12965
+ actions.appendChild(liveButton);
12966
+ }
12779
12967
  if (taskEnabled) {
12780
12968
  const taskButton = createRemoteFleetButton('Task', 'Dispatch task to this device', 'task-device');
12781
12969
  taskButton.dataset.deviceId = deviceId;
@@ -12887,6 +13075,7 @@
12887
13075
  || (filterMode === 'offline' && card.dataset.remoteFleetConnected !== 'true')
12888
13076
  || (filterMode === 'task' && card.dataset.remoteFleetConnected === 'true' && card.dataset.remoteFleetTaskCapable === 'true')
12889
13077
  || (filterMode === 'ai' && card.dataset.remoteFleetConnected === 'true' && card.dataset.remoteFleetAiCapable === 'true')
13078
+ || (filterMode === 'live' && card.dataset.remoteFleetLiveActive === 'true')
12890
13079
  || (filterMode === 'frames' && card.dataset.remoteFleetHasFrame === 'true')
12891
13080
  || (filterMode === 'issues' && card.dataset.remoteFleetIssue === 'true');
12892
13081
  const show = matchesSearch && matchesMode;
@@ -13016,6 +13205,62 @@
13016
13205
  refreshButton.disabled = false;
13017
13206
  });
13018
13207
 
13208
+ bodyView.querySelectorAll('[data-remote-fleet-action="live-focus"]').forEach(button => {
13209
+ button.addEventListener('click', event => {
13210
+ event.preventDefault();
13211
+ event.stopPropagation();
13212
+ const deviceId = String(button.dataset.deviceId || '').trim();
13213
+ if (!deviceId) return;
13214
+ bodyView.dataset.remoteFleetFocusDeviceId = deviceId;
13215
+ renderRemoteFleetMonitor(bodyView, nodeModel);
13216
+ });
13217
+ });
13218
+
13219
+ bodyView.querySelectorAll('[data-remote-fleet-action="live-start"]').forEach(button => {
13220
+ button.addEventListener('click', async event => {
13221
+ event.preventDefault();
13222
+ event.stopPropagation();
13223
+ const deviceId = String(button.dataset.deviceId || '').trim();
13224
+ if (!deviceId) return;
13225
+ bodyView.dataset.remoteFleetFocusDeviceId = deviceId;
13226
+ button.disabled = true;
13227
+ setTaskFeedback('Starting focused live stream...');
13228
+ try {
13229
+ const result = await invokeDotNetAsync('StartRemoteFleetLiveStreamFromJs', nodeId, deviceId);
13230
+ await syncRemoteFleetNodeStateFromResult(result);
13231
+ if (result?.success) {
13232
+ setTaskFeedback('Focused live stream started.', 'success');
13233
+ } else {
13234
+ setTaskFeedback(result?.error || 'Live stream start failed.', 'error');
13235
+ }
13236
+ } finally {
13237
+ button.disabled = false;
13238
+ }
13239
+ });
13240
+ });
13241
+
13242
+ bodyView.querySelectorAll('[data-remote-fleet-action="live-stop"]').forEach(button => {
13243
+ button.addEventListener('click', async event => {
13244
+ event.preventDefault();
13245
+ event.stopPropagation();
13246
+ const deviceId = String(button.dataset.deviceId || '').trim();
13247
+ if (!deviceId) return;
13248
+ button.disabled = true;
13249
+ setTaskFeedback('Stopping focused live stream...');
13250
+ try {
13251
+ const result = await invokeDotNetAsync('StopRemoteFleetLiveStreamFromJs', nodeId, deviceId, button.dataset.streamId || '');
13252
+ await syncRemoteFleetNodeStateFromResult(result);
13253
+ if (result?.success) {
13254
+ setTaskFeedback('Focused live stream stopped.', 'success');
13255
+ } else {
13256
+ setTaskFeedback(result?.error || 'Live stream stop failed.', 'error');
13257
+ }
13258
+ } finally {
13259
+ button.disabled = false;
13260
+ }
13261
+ });
13262
+ });
13263
+
13019
13264
  grid.querySelectorAll('[data-remote-fleet-action="ping-device"]').forEach(button => {
13020
13265
  button.addEventListener('click', async event => {
13021
13266
  event.preventDefault();
@@ -13065,6 +13310,24 @@
13065
13310
  button.disabled = false;
13066
13311
  });
13067
13312
  });
13313
+
13314
+ if (hasActiveLiveStream) {
13315
+ bodyView._remoteFleetLiveRefreshTimer = setInterval(async () => {
13316
+ if (!document.body.contains(bodyView)) {
13317
+ clearInterval(bodyView._remoteFleetLiveRefreshTimer);
13318
+ bodyView._remoteFleetLiveRefreshTimer = null;
13319
+ return;
13320
+ }
13321
+
13322
+ try {
13323
+ const result = await invokeDotNetAsync('RefreshRemoteFleetMonitorNodeFromJs', nodeId);
13324
+ await syncRemoteFleetNodeStateFromResult(result);
13325
+ } catch {
13326
+ clearInterval(bodyView._remoteFleetLiveRefreshTimer);
13327
+ bodyView._remoteFleetLiveRefreshTimer = null;
13328
+ }
13329
+ }, 1000);
13330
+ }
13068
13331
  }
13069
13332
 
13070
13333
  function bindMemoNodeEvents(container, nodeModel) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mainAssemblyName": "MindExecution.Web",
3
3
  "resources": {
4
- "hash": "sha256-/odScRNovgEc8hBO1R9VAaBYER2ZEkgcGNL8jCOVsoU=",
4
+ "hash": "sha256-XfKFSqnMBnbJmPnM+j3zriBOOdujMLDI/U8Usvww2jQ=",
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.m05i39uvk9.dll": "System.dll",
124
124
  "netstandard.0xet7jg7ky.dll": "netstandard.dll",
125
125
  "System.Private.CoreLib.rkafq04oma.dll": "System.Private.CoreLib.dll",
126
- "MindExecution.Core.kf4752v5yl.dll": "MindExecution.Core.dll",
127
- "MindExecution.Kernel.79mgmkpsy1.dll": "MindExecution.Kernel.dll",
128
- "MindExecution.Plugins.Admin.8ey1m70q79.dll": "MindExecution.Plugins.Admin.dll",
129
- "MindExecution.Plugins.Business.8rvwgqzxaz.dll": "MindExecution.Plugins.Business.dll",
130
- "MindExecution.Plugins.Concept.ynnk3bqf03.dll": "MindExecution.Plugins.Concept.dll",
131
- "MindExecution.Plugins.Directory.vi24rmnuyq.dll": "MindExecution.Plugins.Directory.dll",
132
- "MindExecution.Plugins.PlanMaster.9r08m5atjr.dll": "MindExecution.Plugins.PlanMaster.dll",
133
- "MindExecution.Plugins.YouTube.fjkbniwa4o.dll": "MindExecution.Plugins.YouTube.dll",
134
- "MindExecution.Shared.e0qnm5vtax.dll": "MindExecution.Shared.dll",
135
- "MindExecution.Web.wk9yv02eva.dll": "MindExecution.Web.dll",
126
+ "MindExecution.Core.pnw79cgqjx.dll": "MindExecution.Core.dll",
127
+ "MindExecution.Kernel.dt3w864bqn.dll": "MindExecution.Kernel.dll",
128
+ "MindExecution.Plugins.Admin.z93cu32xru.dll": "MindExecution.Plugins.Admin.dll",
129
+ "MindExecution.Plugins.Business.b6da8sg85t.dll": "MindExecution.Plugins.Business.dll",
130
+ "MindExecution.Plugins.Concept.mjooiqft9j.dll": "MindExecution.Plugins.Concept.dll",
131
+ "MindExecution.Plugins.Directory.rjod6rdmly.dll": "MindExecution.Plugins.Directory.dll",
132
+ "MindExecution.Plugins.PlanMaster.1dcrzhsegj.dll": "MindExecution.Plugins.PlanMaster.dll",
133
+ "MindExecution.Plugins.YouTube.k75qxhbpp8.dll": "MindExecution.Plugins.YouTube.dll",
134
+ "MindExecution.Shared.y3eqxd3mvo.dll": "MindExecution.Shared.dll",
135
+ "MindExecution.Web.wou9x6mn2f.dll": "MindExecution.Web.dll",
136
136
  "dotnet.js": "dotnet.js",
137
137
  "dotnet.native.xsn1d6x2kd.js": "dotnet.native.js",
138
138
  "dotnet.native.vz0adxojrz.wasm": "dotnet.native.wasm",
@@ -278,18 +278,18 @@
278
278
  "System.Xml.XDocument.c539ki6cuq.dll": "sha256-MPTRJkptrL9nGa2tl4kF46+wErNUYRPCGblX3ANoKoY=",
279
279
  "System.m05i39uvk9.dll": "sha256-5jDfIdbYAigw7/Q/lMzt5W/+cayGbW9ko9FvuaN1GsQ=",
280
280
  "netstandard.0xet7jg7ky.dll": "sha256-xENDv620uJ8fHwLJ2bdhrTHz4QPjvqXOztnk2a4wr0c=",
281
- "MindExecution.Core.kf4752v5yl.dll": "sha256-MK+6sYNYxso5bmurLtzuQOy6PiIr6jHmV0DMzHSg+sc=",
282
- "MindExecution.Kernel.79mgmkpsy1.dll": "sha256-qwoCzn5eUut0Qz0kvhUJmtlPAtoMtYtMTv9c4ekX84o=",
283
- "MindExecution.Plugins.Concept.ynnk3bqf03.dll": "sha256-Mvw1k0NexULKDOElumjmqjK4jl2MS5NNvFrTnBDZ2qc=",
284
- "MindExecution.Plugins.PlanMaster.9r08m5atjr.dll": "sha256-K2De6QooRNGCQL7zfYyZ4aeMZZE2etfT4Aj52u7y+RQ=",
285
- "MindExecution.Shared.e0qnm5vtax.dll": "sha256-bh3YoyPl9H4U9q8TO3u6hoJLMoWW0sYxJyJwj8heek0=",
286
- "MindExecution.Web.wk9yv02eva.dll": "sha256-AHwwn1rOC7uDlpCJJLndmyf97G7nM018K4WpzRuPwTg="
281
+ "MindExecution.Core.pnw79cgqjx.dll": "sha256-64VJ+VCnq+r7lgfYzm99hPX3yo5u2QCC4guGqsrVTus=",
282
+ "MindExecution.Kernel.dt3w864bqn.dll": "sha256-r0Q9mY7CB+L/3j7KlKlNiyLBlXcwBkPRtjGh0RBZOFs=",
283
+ "MindExecution.Plugins.Concept.mjooiqft9j.dll": "sha256-Qrz35qwSLDAaugzQMJ6YLfWI+jld56cCo+9wOwVobgw=",
284
+ "MindExecution.Plugins.PlanMaster.1dcrzhsegj.dll": "sha256-VZ7SUoDTHQ9MdwII/dBqeaVFpDt6UEFDV5xJHAlskgM=",
285
+ "MindExecution.Shared.y3eqxd3mvo.dll": "sha256-EnE/FEgfwb2Trt9cyLvVEeHE8iSRWYhaftVJUOKLAZI=",
286
+ "MindExecution.Web.wou9x6mn2f.dll": "sha256-YENKxQvH07LxcUCqbFITQtVD2sCcdYNAF9aX0YVtVGs="
287
287
  },
288
288
  "lazyAssembly": {
289
- "MindExecution.Plugins.Admin.8ey1m70q79.dll": "sha256-oMlSl7sNr3GfLsqVskx6UNQMyoGJANENnZIL62rfG+c=",
290
- "MindExecution.Plugins.Business.8rvwgqzxaz.dll": "sha256-xJBBAfZAEw5jQcNThJNI3vKn2rLWuCRV7Oo8onCFwOo=",
291
- "MindExecution.Plugins.Directory.vi24rmnuyq.dll": "sha256-x+iwabNhSVcOgBw2RlEp7HSQ7Eep/nvCn+lZVNGxCK8=",
292
- "MindExecution.Plugins.YouTube.fjkbniwa4o.dll": "sha256-RUR2I22IaFbLmHY/Gcw7wfwiybsIs8m+kgMfo1i78+w="
289
+ "MindExecution.Plugins.Admin.z93cu32xru.dll": "sha256-aToPZeovhBXkB0URHkzYdYDAmg1+HxsvojgiefL4pkY=",
290
+ "MindExecution.Plugins.Business.b6da8sg85t.dll": "sha256-M1macJ1ZqfBCrj/1WPw2JQxnFtFX31HxydBxQKa3Cgw=",
291
+ "MindExecution.Plugins.Directory.rjod6rdmly.dll": "sha256-hx8N04/7sIYB8PdHSyVTLhPfPb7ZkmqM1RPBB1J0iuw=",
292
+ "MindExecution.Plugins.YouTube.k75qxhbpp8.dll": "sha256-IM43bEjZvj6SqvBrKl8JmAN5NfN6IW8VPi3Z/HarwlQ="
293
293
  }
294
294
  },
295
295
  "cacheBootResources": true,
@@ -558,7 +558,7 @@
558
558
  }
559
559
 
560
560
  const base = '_content/MindExecution.Shared/js/';
561
- const scriptVersion = '20260612-remote-fleet-scale-v466';
561
+ const scriptVersion = '20260612-remote-live-v467';
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": "tyUOiEjY",
2
+ "version": "VGenANrx",
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-UIJj28RUmbRzdxZB7yxJHs88G8t0QTV1mCQOJeHywK8=",
89
+ "hash": "sha256-onBRk1N+CsAvVe3BVd4w9ca+0VF+NLCzDOjqBH3T2vw=",
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-MK+6sYNYxso5bmurLtzuQOy6PiIr6jHmV0DMzHSg+sc=",
414
- "url": "_framework/MindExecution.Core.kf4752v5yl.dll"
413
+ "hash": "sha256-64VJ+VCnq+r7lgfYzm99hPX3yo5u2QCC4guGqsrVTus=",
414
+ "url": "_framework/MindExecution.Core.pnw79cgqjx.dll"
415
415
  },
416
416
  {
417
- "hash": "sha256-qwoCzn5eUut0Qz0kvhUJmtlPAtoMtYtMTv9c4ekX84o=",
418
- "url": "_framework/MindExecution.Kernel.79mgmkpsy1.dll"
417
+ "hash": "sha256-r0Q9mY7CB+L/3j7KlKlNiyLBlXcwBkPRtjGh0RBZOFs=",
418
+ "url": "_framework/MindExecution.Kernel.dt3w864bqn.dll"
419
419
  },
420
420
  {
421
- "hash": "sha256-oMlSl7sNr3GfLsqVskx6UNQMyoGJANENnZIL62rfG+c=",
422
- "url": "_framework/MindExecution.Plugins.Admin.8ey1m70q79.dll"
421
+ "hash": "sha256-aToPZeovhBXkB0URHkzYdYDAmg1+HxsvojgiefL4pkY=",
422
+ "url": "_framework/MindExecution.Plugins.Admin.z93cu32xru.dll"
423
423
  },
424
424
  {
425
- "hash": "sha256-xJBBAfZAEw5jQcNThJNI3vKn2rLWuCRV7Oo8onCFwOo=",
426
- "url": "_framework/MindExecution.Plugins.Business.8rvwgqzxaz.dll"
425
+ "hash": "sha256-M1macJ1ZqfBCrj/1WPw2JQxnFtFX31HxydBxQKa3Cgw=",
426
+ "url": "_framework/MindExecution.Plugins.Business.b6da8sg85t.dll"
427
427
  },
428
428
  {
429
- "hash": "sha256-Mvw1k0NexULKDOElumjmqjK4jl2MS5NNvFrTnBDZ2qc=",
430
- "url": "_framework/MindExecution.Plugins.Concept.ynnk3bqf03.dll"
429
+ "hash": "sha256-Qrz35qwSLDAaugzQMJ6YLfWI+jld56cCo+9wOwVobgw=",
430
+ "url": "_framework/MindExecution.Plugins.Concept.mjooiqft9j.dll"
431
431
  },
432
432
  {
433
- "hash": "sha256-x+iwabNhSVcOgBw2RlEp7HSQ7Eep/nvCn+lZVNGxCK8=",
434
- "url": "_framework/MindExecution.Plugins.Directory.vi24rmnuyq.dll"
433
+ "hash": "sha256-hx8N04/7sIYB8PdHSyVTLhPfPb7ZkmqM1RPBB1J0iuw=",
434
+ "url": "_framework/MindExecution.Plugins.Directory.rjod6rdmly.dll"
435
435
  },
436
436
  {
437
- "hash": "sha256-K2De6QooRNGCQL7zfYyZ4aeMZZE2etfT4Aj52u7y+RQ=",
438
- "url": "_framework/MindExecution.Plugins.PlanMaster.9r08m5atjr.dll"
437
+ "hash": "sha256-VZ7SUoDTHQ9MdwII/dBqeaVFpDt6UEFDV5xJHAlskgM=",
438
+ "url": "_framework/MindExecution.Plugins.PlanMaster.1dcrzhsegj.dll"
439
439
  },
440
440
  {
441
- "hash": "sha256-RUR2I22IaFbLmHY/Gcw7wfwiybsIs8m+kgMfo1i78+w=",
442
- "url": "_framework/MindExecution.Plugins.YouTube.fjkbniwa4o.dll"
441
+ "hash": "sha256-IM43bEjZvj6SqvBrKl8JmAN5NfN6IW8VPi3Z/HarwlQ=",
442
+ "url": "_framework/MindExecution.Plugins.YouTube.k75qxhbpp8.dll"
443
443
  },
444
444
  {
445
- "hash": "sha256-bh3YoyPl9H4U9q8TO3u6hoJLMoWW0sYxJyJwj8heek0=",
446
- "url": "_framework/MindExecution.Shared.e0qnm5vtax.dll"
445
+ "hash": "sha256-EnE/FEgfwb2Trt9cyLvVEeHE8iSRWYhaftVJUOKLAZI=",
446
+ "url": "_framework/MindExecution.Shared.y3eqxd3mvo.dll"
447
447
  },
448
448
  {
449
- "hash": "sha256-AHwwn1rOC7uDlpCJJLndmyf97G7nM018K4WpzRuPwTg=",
450
- "url": "_framework/MindExecution.Web.wk9yv02eva.dll"
449
+ "hash": "sha256-YENKxQvH07LxcUCqbFITQtVD2sCcdYNAF9aX0YVtVGs=",
450
+ "url": "_framework/MindExecution.Web.wou9x6mn2f.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-v2ZTmYhjrtyEfbHSvkcdnYwoI+IoWSf/opZgluPefHA=",
773
+ "hash": "sha256-10lI3q/nXAGFdelS8ribQw72sOgD3PYExvQX6srRqWA=",
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-TU40FZ+Rzj9ZDbwOAysHnWs1F2588obb2+wwcp7Mcy4=",
837
+ "hash": "sha256-XjrBWCpqleqLE2sqmht7oUg24vRCkU/O+yj7TszO43g=",
838
838
  "url": "index.html"
839
839
  },
840
840
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: tyUOiEjY */
1
+ /* Manifest version: VGenANrx */
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