@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.
- package/README.md +12 -0
- package/package.json +1 -1
- package/remote-hub.js +167 -0
- package/scripts/remote-hub-smoke.mjs +54 -0
- package/server.js +28 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +272 -9
- package/wwwroot/_framework/MindExecution.Core.pnw79cgqjx.dll +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.79mgmkpsy1.dll → MindExecution.Kernel.dt3w864bqn.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.8ey1m70q79.dll → MindExecution.Plugins.Admin.z93cu32xru.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.8rvwgqzxaz.dll → MindExecution.Plugins.Business.b6da8sg85t.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.ynnk3bqf03.dll → MindExecution.Plugins.Concept.mjooiqft9j.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.vi24rmnuyq.dll → MindExecution.Plugins.Directory.rjod6rdmly.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.9r08m5atjr.dll → MindExecution.Plugins.PlanMaster.1dcrzhsegj.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.fjkbniwa4o.dll → MindExecution.Plugins.YouTube.k75qxhbpp8.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.e0qnm5vtax.dll → MindExecution.Shared.y3eqxd3mvo.dll} +0 -0
- package/wwwroot/_framework/MindExecution.Web.wou9x6mn2f.dll +0 -0
- package/wwwroot/_framework/blazor.boot.json +21 -21
- package/wwwroot/index.html +1 -1
- package/wwwroot/service-worker-assets.js +24 -24
- package/wwwroot/service-worker.js +1 -1
- package/wwwroot/_framework/MindExecution.Core.kf4752v5yl.dll +0 -0
- 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
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 =
|
|
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 (
|
|
12767
|
+
if (previewAt) {
|
|
12599
12768
|
const badge = document.createElement('span');
|
|
12600
|
-
badge.textContent =
|
|
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) {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"mainAssemblyName": "MindExecution.Web",
|
|
3
3
|
"resources": {
|
|
4
|
-
"hash": "sha256
|
|
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.
|
|
127
|
-
"MindExecution.Kernel.
|
|
128
|
-
"MindExecution.Plugins.Admin.
|
|
129
|
-
"MindExecution.Plugins.Business.
|
|
130
|
-
"MindExecution.Plugins.Concept.
|
|
131
|
-
"MindExecution.Plugins.Directory.
|
|
132
|
-
"MindExecution.Plugins.PlanMaster.
|
|
133
|
-
"MindExecution.Plugins.YouTube.
|
|
134
|
-
"MindExecution.Shared.
|
|
135
|
-
"MindExecution.Web.
|
|
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.
|
|
282
|
-
"MindExecution.Kernel.
|
|
283
|
-
"MindExecution.Plugins.Concept.
|
|
284
|
-
"MindExecution.Plugins.PlanMaster.
|
|
285
|
-
"MindExecution.Shared.
|
|
286
|
-
"MindExecution.Web.
|
|
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.
|
|
290
|
-
"MindExecution.Plugins.Business.
|
|
291
|
-
"MindExecution.Plugins.Directory.
|
|
292
|
-
"MindExecution.Plugins.YouTube.
|
|
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,
|
package/wwwroot/index.html
CHANGED
|
@@ -558,7 +558,7 @@
|
|
|
558
558
|
}
|
|
559
559
|
|
|
560
560
|
const base = '_content/MindExecution.Shared/js/';
|
|
561
|
-
const scriptVersion = '20260612-remote-
|
|
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": "
|
|
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-
|
|
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-
|
|
414
|
-
"url": "_framework/MindExecution.Core.
|
|
413
|
+
"hash": "sha256-64VJ+VCnq+r7lgfYzm99hPX3yo5u2QCC4guGqsrVTus=",
|
|
414
|
+
"url": "_framework/MindExecution.Core.pnw79cgqjx.dll"
|
|
415
415
|
},
|
|
416
416
|
{
|
|
417
|
-
"hash": "sha256-
|
|
418
|
-
"url": "_framework/MindExecution.Kernel.
|
|
417
|
+
"hash": "sha256-r0Q9mY7CB+L/3j7KlKlNiyLBlXcwBkPRtjGh0RBZOFs=",
|
|
418
|
+
"url": "_framework/MindExecution.Kernel.dt3w864bqn.dll"
|
|
419
419
|
},
|
|
420
420
|
{
|
|
421
|
-
"hash": "sha256-
|
|
422
|
-
"url": "_framework/MindExecution.Plugins.Admin.
|
|
421
|
+
"hash": "sha256-aToPZeovhBXkB0URHkzYdYDAmg1+HxsvojgiefL4pkY=",
|
|
422
|
+
"url": "_framework/MindExecution.Plugins.Admin.z93cu32xru.dll"
|
|
423
423
|
},
|
|
424
424
|
{
|
|
425
|
-
"hash": "sha256-
|
|
426
|
-
"url": "_framework/MindExecution.Plugins.Business.
|
|
425
|
+
"hash": "sha256-M1macJ1ZqfBCrj/1WPw2JQxnFtFX31HxydBxQKa3Cgw=",
|
|
426
|
+
"url": "_framework/MindExecution.Plugins.Business.b6da8sg85t.dll"
|
|
427
427
|
},
|
|
428
428
|
{
|
|
429
|
-
"hash": "sha256-
|
|
430
|
-
"url": "_framework/MindExecution.Plugins.Concept.
|
|
429
|
+
"hash": "sha256-Qrz35qwSLDAaugzQMJ6YLfWI+jld56cCo+9wOwVobgw=",
|
|
430
|
+
"url": "_framework/MindExecution.Plugins.Concept.mjooiqft9j.dll"
|
|
431
431
|
},
|
|
432
432
|
{
|
|
433
|
-
"hash": "sha256-
|
|
434
|
-
"url": "_framework/MindExecution.Plugins.Directory.
|
|
433
|
+
"hash": "sha256-hx8N04/7sIYB8PdHSyVTLhPfPb7ZkmqM1RPBB1J0iuw=",
|
|
434
|
+
"url": "_framework/MindExecution.Plugins.Directory.rjod6rdmly.dll"
|
|
435
435
|
},
|
|
436
436
|
{
|
|
437
|
-
"hash": "sha256-
|
|
438
|
-
"url": "_framework/MindExecution.Plugins.PlanMaster.
|
|
437
|
+
"hash": "sha256-VZ7SUoDTHQ9MdwII/dBqeaVFpDt6UEFDV5xJHAlskgM=",
|
|
438
|
+
"url": "_framework/MindExecution.Plugins.PlanMaster.1dcrzhsegj.dll"
|
|
439
439
|
},
|
|
440
440
|
{
|
|
441
|
-
"hash": "sha256-
|
|
442
|
-
"url": "_framework/MindExecution.Plugins.YouTube.
|
|
441
|
+
"hash": "sha256-IM43bEjZvj6SqvBrKl8JmAN5NfN6IW8VPi3Z/HarwlQ=",
|
|
442
|
+
"url": "_framework/MindExecution.Plugins.YouTube.k75qxhbpp8.dll"
|
|
443
443
|
},
|
|
444
444
|
{
|
|
445
|
-
"hash": "sha256-
|
|
446
|
-
"url": "_framework/MindExecution.Shared.
|
|
445
|
+
"hash": "sha256-EnE/FEgfwb2Trt9cyLvVEeHE8iSRWYhaftVJUOKLAZI=",
|
|
446
|
+
"url": "_framework/MindExecution.Shared.y3eqxd3mvo.dll"
|
|
447
447
|
},
|
|
448
448
|
{
|
|
449
|
-
"hash": "sha256-
|
|
450
|
-
"url": "_framework/MindExecution.Web.
|
|
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-
|
|
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-
|
|
837
|
+
"hash": "sha256-XjrBWCpqleqLE2sqmht7oUg24vRCkU/O+yj7TszO43g=",
|
|
838
838
|
"url": "index.html"
|
|
839
839
|
},
|
|
840
840
|
{
|
|
Binary file
|
|
Binary file
|