@mindexec/cli 0.2.5 → 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 +6 -6
- 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 +722 -78
- package/wwwroot/_framework/MindExecution.Core.pnw79cgqjx.dll +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.9wfplilp5l.dll → MindExecution.Kernel.dt3w864bqn.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.sb1vkmct0w.dll → MindExecution.Plugins.Admin.z93cu32xru.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.zr7rkofx44.dll → MindExecution.Plugins.Business.b6da8sg85t.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.g6wd36v92i.dll → MindExecution.Plugins.Concept.mjooiqft9j.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.bb5flwt0u7.dll → MindExecution.Plugins.Directory.rjod6rdmly.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.me8v9fpgwc.dll → MindExecution.Plugins.PlanMaster.1dcrzhsegj.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.l811fqx9e0.dll → MindExecution.Plugins.YouTube.k75qxhbpp8.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.oseamdg577.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.27f2blpou6.dll +0 -0
- package/wwwroot/_framework/MindExecution.Web.96r3nnp9is.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.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "MindExec local runtime and bridge CLI",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"start-bridge.bat",
|
|
9
9
|
"start-bridge.sh",
|
|
10
10
|
"launch-bridge.cjs",
|
|
11
|
-
"server.js",
|
|
12
|
-
"remote-hub.js",
|
|
13
|
-
"codex-runtime.js",
|
|
11
|
+
"server.js",
|
|
12
|
+
"remote-hub.js",
|
|
13
|
+
"codex-runtime.js",
|
|
14
14
|
"port-guard.cjs",
|
|
15
15
|
"wwwroot/",
|
|
16
16
|
"scripts/",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"start": "node launch-bridge.cjs",
|
|
22
22
|
"dev": "node launch-bridge.cjs --watch",
|
|
23
|
-
"test:syntax": "node --check server.js && node --check remote-hub.js && node --check codex-runtime.js && node --check launch-bridge.cjs && node --check port-guard.cjs && node --check scripts/setup-tree-sitter-grammars.mjs && node --check scripts/remote-hub-smoke.mjs",
|
|
24
|
-
"test:remote": "node scripts/remote-hub-smoke.mjs",
|
|
23
|
+
"test:syntax": "node --check server.js && node --check remote-hub.js && node --check codex-runtime.js && node --check launch-bridge.cjs && node --check port-guard.cjs && node --check scripts/setup-tree-sitter-grammars.mjs && node --check scripts/remote-hub-smoke.mjs",
|
|
24
|
+
"test:remote": "node scripts/remote-hub-smoke.mjs",
|
|
25
25
|
"pack:dry": "npm pack --dry-run",
|
|
26
26
|
"setup:grammars": "node scripts/setup-tree-sitter-grammars.mjs",
|
|
27
27
|
"postinstall": "npm run setup:grammars"
|
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());
|