@mindexec/cli 0.2.131 → 0.2.133
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/scripts/remote-fast-live-rate-smoke.mjs +2 -2
- package/scripts/remote-fast-mdm-browser-smoke.mjs +361 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +1 -1
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.lxunwcdjgq.dll → MindExecution.Plugins.Concept.5gltgdqyo3.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.2sugb66h95.dll → MindExecution.Plugins.PlanMaster.cn6ppe6qoz.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.vy0nsbcoo4.dll → MindExecution.Plugins.YouTube.d7nnsxrftv.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.vki6dm13ef.dll → MindExecution.Shared.mnpwk5h86c.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Web.994sb3nzuy.dll → MindExecution.Web.ygql0sg6b3.dll} +0 -0
- package/wwwroot/_framework/blazor.boot.json +11 -11
- package/wwwroot/index.html +3 -3
- package/wwwroot/service-worker-assets.js +14 -14
- package/wwwroot/service-worker.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindexec/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.133",
|
|
4
4
|
"description": "MindExec local runtime and bridge CLI",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"start": "node launch-bridge.cjs",
|
|
23
23
|
"dev": "node launch-bridge.cjs --watch",
|
|
24
|
-
"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/auth-session-smoke.mjs && node --check scripts/remote-hub-smoke.mjs && node --check scripts/remote-hub-scale-smoke.mjs && node --check scripts/remote-fleet-render-smoke.mjs && node --check scripts/remote-http-smoke.mjs && node --check scripts/remote-frame-ws-smoke.mjs && node --check scripts/remote-agent-ws-smoke.mjs && node --check scripts/remote-agent-managed-smoke.mjs && node --check scripts/remote-agent-package-smoke.mjs && node --check scripts/remote-fast-live-rate-smoke.mjs",
|
|
24
|
+
"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/auth-session-smoke.mjs && node --check scripts/remote-hub-smoke.mjs && node --check scripts/remote-hub-scale-smoke.mjs && node --check scripts/remote-fleet-render-smoke.mjs && node --check scripts/remote-http-smoke.mjs && node --check scripts/remote-frame-ws-smoke.mjs && node --check scripts/remote-agent-ws-smoke.mjs && node --check scripts/remote-agent-managed-smoke.mjs && node --check scripts/remote-agent-package-smoke.mjs && node --check scripts/remote-fast-live-rate-smoke.mjs && node --check scripts/remote-fast-mdm-browser-smoke.mjs",
|
|
25
25
|
"test:auth": "node scripts/auth-session-smoke.mjs",
|
|
26
26
|
"test:remote": "node scripts/remote-hub-smoke.mjs",
|
|
27
27
|
"test:remote:scale": "node scripts/remote-hub-scale-smoke.mjs",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"test:remote:managed": "node scripts/remote-agent-managed-smoke.mjs",
|
|
33
33
|
"test:remote:package": "node scripts/remote-agent-package-smoke.mjs",
|
|
34
34
|
"test:remote:live-rate": "node scripts/remote-fast-live-rate-smoke.mjs",
|
|
35
|
+
"test:remote:mdm-browser": "node scripts/remote-fast-mdm-browser-smoke.mjs",
|
|
35
36
|
"pack:dry": "npm pack --dry-run",
|
|
36
37
|
"setup:grammars": "node scripts/setup-tree-sitter-grammars.mjs",
|
|
37
38
|
"postinstall": "npm run setup:grammars"
|
|
@@ -13,9 +13,9 @@ const BRIDGE_TOKEN = 'remote-fast-live-rate-smoke-token';
|
|
|
13
13
|
const PAIR_TOKEN = 'remote-fast-live-rate-pair-token';
|
|
14
14
|
const LEASE_ID = 'remote-fast-live-rate-lease';
|
|
15
15
|
const LOCAL_BRIDGE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
16
|
-
const REQUESTED_FPS = Number(process.env.MINDEXEC_REMOTE_LIVE_RATE_REQUEST_FPS ||
|
|
16
|
+
const REQUESTED_FPS = Number(process.env.MINDEXEC_REMOTE_LIVE_RATE_REQUEST_FPS || 12);
|
|
17
17
|
const SAMPLE_MS = Number(process.env.MINDEXEC_REMOTE_LIVE_RATE_SAMPLE_MS || 3500);
|
|
18
|
-
const MIN_EFFECTIVE_FPS = Number(process.env.MINDEXEC_REMOTE_LIVE_RATE_MIN_FPS ||
|
|
18
|
+
const MIN_EFFECTIVE_FPS = Number(process.env.MINDEXEC_REMOTE_LIVE_RATE_MIN_FPS || 10);
|
|
19
19
|
|
|
20
20
|
function wait(ms) {
|
|
21
21
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
6
|
+
import net from 'node:net';
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
10
|
+
|
|
11
|
+
const BRIDGE_TOKEN = 'remote-fast-mdm-browser-smoke-token';
|
|
12
|
+
const PAIR_TOKEN = 'remote-fast-mdm-browser-pair-token';
|
|
13
|
+
const LEASE_ID = 'remote-fast-mdm-browser-lease';
|
|
14
|
+
const LOCAL_BRIDGE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
15
|
+
const REQUESTED_FPS = Number(process.env.MINDEXEC_REMOTE_MDM_BROWSER_REQUEST_FPS || 12);
|
|
16
|
+
|
|
17
|
+
function wait(ms) {
|
|
18
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function findFreePort() {
|
|
22
|
+
return await new Promise((resolve, reject) => {
|
|
23
|
+
const server = net.createServer();
|
|
24
|
+
server.unref();
|
|
25
|
+
server.once('error', reject);
|
|
26
|
+
server.listen(0, '127.0.0.1', () => {
|
|
27
|
+
const address = server.address();
|
|
28
|
+
const port = typeof address === 'object' && address ? address.port : 0;
|
|
29
|
+
server.close(() => resolve(port));
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function fetchJson(url, options = {}) {
|
|
35
|
+
const response = await fetch(url, {
|
|
36
|
+
...options,
|
|
37
|
+
headers: {
|
|
38
|
+
...(options.body ? { 'Content-Type': 'application/json' } : {}),
|
|
39
|
+
'X-Bridge-Token': BRIDGE_TOKEN,
|
|
40
|
+
...(options.headers || {})
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const payload = await response.json().catch(() => null);
|
|
45
|
+
return { status: response.status, ok: response.ok, payload };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function waitFor(predicate, timeoutMs = 30000, label = 'condition') {
|
|
49
|
+
const startedAt = Date.now();
|
|
50
|
+
let lastError = null;
|
|
51
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
52
|
+
try {
|
|
53
|
+
const value = await predicate();
|
|
54
|
+
if (value) {
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
lastError = error;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
await wait(100);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throw new Error(`Timed out waiting for ${label}${lastError ? `: ${lastError.message}` : ''}.`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function spawnBridge({ bridgePort, remoteHubPort, workspacePath, label, traceFrames = false }) {
|
|
68
|
+
const child = spawn(process.execPath, ['server.js'], {
|
|
69
|
+
cwd: LOCAL_BRIDGE_DIR,
|
|
70
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
71
|
+
windowsHide: true,
|
|
72
|
+
env: {
|
|
73
|
+
...process.env,
|
|
74
|
+
BRIDGE_PORT: String(bridgePort),
|
|
75
|
+
BRIDGE_TOKEN,
|
|
76
|
+
BRIDGE_REQUIRE_TOKEN: '1',
|
|
77
|
+
MINDEXEC_REMOTE_HUB: '1',
|
|
78
|
+
MINDEXEC_REMOTE_TRACE_FRAMES: traceFrames ? '1' : '',
|
|
79
|
+
REMOTE_HUB_HOST: '127.0.0.1',
|
|
80
|
+
REMOTE_HUB_PORT: String(remoteHubPort),
|
|
81
|
+
REMOTE_HUB_PAIR_TOKEN: PAIR_TOKEN,
|
|
82
|
+
WORKSPACE_PATH: workspacePath,
|
|
83
|
+
NO_COLOR: '1'
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
let stdout = '';
|
|
88
|
+
let stderr = '';
|
|
89
|
+
child.stdout.on('data', chunk => {
|
|
90
|
+
stdout += chunk.toString();
|
|
91
|
+
});
|
|
92
|
+
child.stderr.on('data', chunk => {
|
|
93
|
+
stderr += chunk.toString();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const exitPromise = new Promise(resolve => child.once('exit', resolve));
|
|
97
|
+
const details = () => `${label} stdout=${stdout}\n${label} stderr=${stderr}`;
|
|
98
|
+
const stop = async () => {
|
|
99
|
+
if (child.exitCode === null && !child.killed) {
|
|
100
|
+
child.kill('SIGTERM');
|
|
101
|
+
await Promise.race([exitPromise, wait(5000)]);
|
|
102
|
+
if (child.exitCode === null && !child.killed) {
|
|
103
|
+
child.kill('SIGKILL');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
baseUrl: `http://127.0.0.1:${bridgePort}`,
|
|
110
|
+
child,
|
|
111
|
+
details,
|
|
112
|
+
stop
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function waitForBridge(bridge) {
|
|
117
|
+
return await waitFor(async () => {
|
|
118
|
+
const result = await fetchJson(`${bridge.baseUrl}/api/status`);
|
|
119
|
+
return result.ok && result.payload?.status === 'ok' ? result.payload : null;
|
|
120
|
+
}, 30000, `bridge startup\n${bridge.details()}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function loadPlaywrightChromium() {
|
|
124
|
+
const candidates = [
|
|
125
|
+
path.join(LOCAL_BRIDGE_DIR, 'node_modules', 'playwright', 'index.js'),
|
|
126
|
+
path.join(LOCAL_BRIDGE_DIR, 'node_modules', 'playwright-core', 'index.mjs'),
|
|
127
|
+
path.join(LOCAL_BRIDGE_DIR, 'node_modules', 'playwright-core', 'index.js')
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
let lastError = null;
|
|
131
|
+
for (const candidate of candidates) {
|
|
132
|
+
try {
|
|
133
|
+
const mod = await import(pathToFileURL(candidate).href);
|
|
134
|
+
if (mod.chromium) {
|
|
135
|
+
return mod.chromium;
|
|
136
|
+
}
|
|
137
|
+
} catch (error) {
|
|
138
|
+
lastError = error;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
throw new Error(`Playwright chromium is unavailable: ${lastError?.message || 'not installed'}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function launchBrowser(chromium) {
|
|
146
|
+
const launchers = [
|
|
147
|
+
() => chromium.launch({ channel: 'chrome', headless: true }),
|
|
148
|
+
() => chromium.launch({ channel: 'msedge', headless: true }),
|
|
149
|
+
() => chromium.launch({ headless: true })
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
let lastError = null;
|
|
153
|
+
for (const launch of launchers) {
|
|
154
|
+
try {
|
|
155
|
+
return await launch();
|
|
156
|
+
} catch (error) {
|
|
157
|
+
lastError = error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
throw new Error(`Unable to launch a Chromium browser: ${lastError?.message || 'unknown error'}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function paintRemoteFrameInBrowser(page, wsUrl, deviceId) {
|
|
165
|
+
await page.setContent(`
|
|
166
|
+
<!doctype html>
|
|
167
|
+
<meta charset="utf-8">
|
|
168
|
+
<canvas id="screen" width="320" height="180"></canvas>
|
|
169
|
+
`);
|
|
170
|
+
|
|
171
|
+
return await page.evaluate(async ({ wsUrl, deviceId }) => {
|
|
172
|
+
const canvas = document.getElementById('screen');
|
|
173
|
+
const context = canvas.getContext('2d', { alpha: false, desynchronized: true }) || canvas.getContext('2d');
|
|
174
|
+
if (!context) {
|
|
175
|
+
throw new Error('canvas-2d-context-unavailable');
|
|
176
|
+
}
|
|
177
|
+
if (typeof createImageBitmap !== 'function') {
|
|
178
|
+
throw new Error('createImageBitmap-unavailable');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function parsePacket(buffer) {
|
|
182
|
+
const view = new DataView(buffer);
|
|
183
|
+
const metaLength = view.getUint32(0);
|
|
184
|
+
if (!Number.isFinite(metaLength) || metaLength <= 0 || metaLength > 64 * 1024 || 4 + metaLength >= buffer.byteLength) {
|
|
185
|
+
throw new Error('invalid-frame-packet');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const metadataBytes = new Uint8Array(buffer, 4, metaLength);
|
|
189
|
+
const metadata = JSON.parse(new TextDecoder().decode(metadataBytes));
|
|
190
|
+
const payload = buffer.slice(4 + metaLength);
|
|
191
|
+
return { metadata, payload };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return await new Promise((resolve, reject) => {
|
|
195
|
+
const timeout = setTimeout(() => {
|
|
196
|
+
try {
|
|
197
|
+
ws?.close();
|
|
198
|
+
} catch {
|
|
199
|
+
// ignore close failure
|
|
200
|
+
}
|
|
201
|
+
reject(new Error('timed-out-waiting-for-mdm-frame'));
|
|
202
|
+
}, 20000);
|
|
203
|
+
const ws = new WebSocket(wsUrl);
|
|
204
|
+
ws.binaryType = 'arraybuffer';
|
|
205
|
+
ws.onopen = () => {
|
|
206
|
+
ws.send(JSON.stringify({ type: 'subscribe', deviceIds: [deviceId] }));
|
|
207
|
+
};
|
|
208
|
+
ws.onerror = () => {
|
|
209
|
+
clearTimeout(timeout);
|
|
210
|
+
reject(new Error('remote-frame-websocket-error'));
|
|
211
|
+
};
|
|
212
|
+
ws.onclose = () => {
|
|
213
|
+
clearTimeout(timeout);
|
|
214
|
+
reject(new Error('remote-frame-websocket-closed-before-paint'));
|
|
215
|
+
};
|
|
216
|
+
ws.onmessage = async event => {
|
|
217
|
+
if (typeof event.data === 'string') {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
const { metadata, payload } = parsePacket(event.data);
|
|
223
|
+
if (String(metadata.type || '').toLowerCase() !== 'remote.frame.binary'
|
|
224
|
+
|| String(metadata.kind || '').toLowerCase() !== 'live'
|
|
225
|
+
|| String(metadata.deviceId || '') !== deviceId) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (metadata.dataUrl || metadata.framePath || metadata.frameUrl) {
|
|
230
|
+
throw new Error('binary-ws-metadata-must-not-carry-frame-url-or-data-url');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const blob = new Blob([payload], { type: metadata.mimeType || 'image/jpeg' });
|
|
234
|
+
const bitmap = await createImageBitmap(blob);
|
|
235
|
+
context.fillStyle = '#000000';
|
|
236
|
+
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
237
|
+
context.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
|
|
238
|
+
bitmap.close?.();
|
|
239
|
+
const pixel = Array.from(context.getImageData(0, 0, 1, 1).data);
|
|
240
|
+
clearTimeout(timeout);
|
|
241
|
+
ws.onclose = null;
|
|
242
|
+
ws.close();
|
|
243
|
+
resolve({
|
|
244
|
+
frameSeq: Number(metadata.frameSeq || 0),
|
|
245
|
+
fps: Number(metadata.fps || 0),
|
|
246
|
+
width: Number(metadata.width || 0),
|
|
247
|
+
height: Number(metadata.height || 0),
|
|
248
|
+
byteLength: Number(metadata.byteLength || payload.byteLength || 0),
|
|
249
|
+
mimeType: String(metadata.mimeType || ''),
|
|
250
|
+
transport: String(metadata.transport || ''),
|
|
251
|
+
payloadBytes: payload.byteLength,
|
|
252
|
+
pixel
|
|
253
|
+
});
|
|
254
|
+
} catch (error) {
|
|
255
|
+
clearTimeout(timeout);
|
|
256
|
+
try {
|
|
257
|
+
ws.close();
|
|
258
|
+
} catch {
|
|
259
|
+
// ignore close failure
|
|
260
|
+
}
|
|
261
|
+
reject(error);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
});
|
|
265
|
+
}, { wsUrl, deviceId });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function main() {
|
|
269
|
+
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'mindexec-remote-mdm-browser-'));
|
|
270
|
+
const hostWorkspace = path.join(tempRoot, 'host');
|
|
271
|
+
const clientWorkspace = path.join(tempRoot, 'client');
|
|
272
|
+
const hostBridgePort = await findFreePort();
|
|
273
|
+
const hostRemotePort = await findFreePort();
|
|
274
|
+
const clientBridgePort = await findFreePort();
|
|
275
|
+
const clientRemotePort = await findFreePort();
|
|
276
|
+
const managerEndpoint = `127.0.0.1:${hostRemotePort}`;
|
|
277
|
+
let hostBridge = null;
|
|
278
|
+
let clientBridge = null;
|
|
279
|
+
let browser = null;
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
hostBridge = spawnBridge({
|
|
283
|
+
bridgePort: hostBridgePort,
|
|
284
|
+
remoteHubPort: hostRemotePort,
|
|
285
|
+
workspacePath: hostWorkspace,
|
|
286
|
+
label: 'host'
|
|
287
|
+
});
|
|
288
|
+
await waitForBridge(hostBridge);
|
|
289
|
+
|
|
290
|
+
clientBridge = spawnBridge({
|
|
291
|
+
bridgePort: clientBridgePort,
|
|
292
|
+
remoteHubPort: clientRemotePort,
|
|
293
|
+
workspacePath: clientWorkspace,
|
|
294
|
+
label: 'client',
|
|
295
|
+
traceFrames: true
|
|
296
|
+
});
|
|
297
|
+
await waitForBridge(clientBridge);
|
|
298
|
+
|
|
299
|
+
const connectResult = await fetchJson(`${clientBridge.baseUrl}/api/remote/agent/connect`, {
|
|
300
|
+
method: 'POST',
|
|
301
|
+
body: JSON.stringify({
|
|
302
|
+
managerCandidates: [managerEndpoint],
|
|
303
|
+
pairToken: PAIR_TOKEN,
|
|
304
|
+
leaseId: LEASE_ID,
|
|
305
|
+
nodeId: 'remote-fast-mdm-browser-node',
|
|
306
|
+
engine: 'auto',
|
|
307
|
+
source: 'mdm-browser-smoke'
|
|
308
|
+
})
|
|
309
|
+
});
|
|
310
|
+
assert.equal(connectResult.ok, true, JSON.stringify(connectResult.payload));
|
|
311
|
+
assert.equal(connectResult.payload?.ok, true, JSON.stringify(connectResult.payload));
|
|
312
|
+
assert.equal(connectResult.payload?.agent?.usingNpx, false, JSON.stringify(connectResult.payload?.agent));
|
|
313
|
+
assert.match(String(connectResult.payload?.agent?.launcher || ''), /mindexec-remote-fast/i);
|
|
314
|
+
|
|
315
|
+
const device = await waitFor(async () => {
|
|
316
|
+
const result = await fetchJson(`${hostBridge.baseUrl}/api/remote/devices`);
|
|
317
|
+
return result.payload?.devices?.find(item =>
|
|
318
|
+
item.connected === true
|
|
319
|
+
&& item.capabilities?.liveStream === true
|
|
320
|
+
&& item.capabilities?.binaryFrames === true) || null;
|
|
321
|
+
}, 15000, `RemoteFast device registration\n${hostBridge.details()}\n${clientBridge.details()}`);
|
|
322
|
+
|
|
323
|
+
const live = await fetchJson(`${hostBridge.baseUrl}/api/remote/devices/${encodeURIComponent(device.deviceId)}/live/start`, {
|
|
324
|
+
method: 'POST',
|
|
325
|
+
body: JSON.stringify({
|
|
326
|
+
fps: REQUESTED_FPS,
|
|
327
|
+
maxWidth: 960,
|
|
328
|
+
maxHeight: 540,
|
|
329
|
+
quality: 60
|
|
330
|
+
})
|
|
331
|
+
});
|
|
332
|
+
assert.equal(live.ok, true, JSON.stringify(live.payload));
|
|
333
|
+
assert.equal(live.payload?.ok, true, JSON.stringify(live.payload));
|
|
334
|
+
|
|
335
|
+
const chromium = await loadPlaywrightChromium();
|
|
336
|
+
browser = await launchBrowser(chromium);
|
|
337
|
+
const page = await browser.newPage();
|
|
338
|
+
const wsUrl = `${hostBridge.baseUrl.replace(/^http:/, 'ws:')}/api/remote/frames/ws?token=${encodeURIComponent(BRIDGE_TOKEN)}`;
|
|
339
|
+
const painted = await paintRemoteFrameInBrowser(page, wsUrl, device.deviceId);
|
|
340
|
+
assert.ok(painted.frameSeq > 0, JSON.stringify(painted));
|
|
341
|
+
assert.equal(painted.fps, REQUESTED_FPS, JSON.stringify(painted));
|
|
342
|
+
assert.ok(painted.width > 0 && painted.height > 0, JSON.stringify(painted));
|
|
343
|
+
assert.ok(painted.byteLength > 0 && painted.payloadBytes > 0, JSON.stringify(painted));
|
|
344
|
+
assert.match(painted.mimeType, /^image\/(jpeg|png|webp)$/i, JSON.stringify(painted));
|
|
345
|
+
|
|
346
|
+
console.log(`RemoteFast MDM browser smoke OK (seq ${painted.frameSeq}, ${painted.width}x${painted.height}, ${painted.byteLength} bytes)`);
|
|
347
|
+
} finally {
|
|
348
|
+
if (browser) {
|
|
349
|
+
await browser.close().catch(() => undefined);
|
|
350
|
+
}
|
|
351
|
+
if (clientBridge) {
|
|
352
|
+
await clientBridge.stop();
|
|
353
|
+
}
|
|
354
|
+
if (hostBridge) {
|
|
355
|
+
await hostBridge.stop();
|
|
356
|
+
}
|
|
357
|
+
await rm(tempRoot, { recursive: true, force: true });
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
await main();
|
|
@@ -13451,7 +13451,7 @@
|
|
|
13451
13451
|
const REMOTE_FLEET_MONITOR_REFRESH_MS = 10000;
|
|
13452
13452
|
const REMOTE_FLEET_EMPTY_MONITOR_REFRESH_MS = 2500;
|
|
13453
13453
|
const REMOTE_FLEET_LIVE_REFRESH_MS = 30000;
|
|
13454
|
-
const REMOTE_FLEET_MONITOR_LIVE_FPS =
|
|
13454
|
+
const REMOTE_FLEET_MONITOR_LIVE_FPS = 12;
|
|
13455
13455
|
const REMOTE_FLEET_LIVE_FRAME_REFRESH_MS = Math.round(1000 / REMOTE_FLEET_MONITOR_LIVE_FPS);
|
|
13456
13456
|
const REMOTE_FLEET_CONTROL_LIVE_FPS = 20;
|
|
13457
13457
|
const REMOTE_FLEET_CONTROL_FRAME_REFRESH_MS = Math.round(1000 / REMOTE_FLEET_CONTROL_LIVE_FPS);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/wwwroot/_framework/{MindExecution.Web.994sb3nzuy.dll → MindExecution.Web.ygql0sg6b3.dll}
RENAMED
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"mainAssemblyName": "MindExecution.Web",
|
|
3
3
|
"resources": {
|
|
4
|
-
"hash": "sha256-
|
|
4
|
+
"hash": "sha256-exyWukcppwSmHQvoV122RgnUj4KZOvdS3LHrc3Z6BTY=",
|
|
5
5
|
"fingerprinting": {
|
|
6
6
|
"Google.Protobuf.9h59ukbel7.dll": "Google.Protobuf.dll",
|
|
7
7
|
"Markdig.d1j7v41cl1.dll": "Markdig.dll",
|
|
@@ -127,12 +127,12 @@
|
|
|
127
127
|
"MindExecution.Kernel.3zom09ir6j.dll": "MindExecution.Kernel.dll",
|
|
128
128
|
"MindExecution.Plugins.Admin.bk23zzy6wc.dll": "MindExecution.Plugins.Admin.dll",
|
|
129
129
|
"MindExecution.Plugins.Business.zwcvc8wufe.dll": "MindExecution.Plugins.Business.dll",
|
|
130
|
-
"MindExecution.Plugins.Concept.
|
|
130
|
+
"MindExecution.Plugins.Concept.5gltgdqyo3.dll": "MindExecution.Plugins.Concept.dll",
|
|
131
131
|
"MindExecution.Plugins.Directory.jc0g7fvyzv.dll": "MindExecution.Plugins.Directory.dll",
|
|
132
|
-
"MindExecution.Plugins.PlanMaster.
|
|
133
|
-
"MindExecution.Plugins.YouTube.
|
|
134
|
-
"MindExecution.Shared.
|
|
135
|
-
"MindExecution.Web.
|
|
132
|
+
"MindExecution.Plugins.PlanMaster.cn6ppe6qoz.dll": "MindExecution.Plugins.PlanMaster.dll",
|
|
133
|
+
"MindExecution.Plugins.YouTube.d7nnsxrftv.dll": "MindExecution.Plugins.YouTube.dll",
|
|
134
|
+
"MindExecution.Shared.mnpwk5h86c.dll": "MindExecution.Shared.dll",
|
|
135
|
+
"MindExecution.Web.ygql0sg6b3.dll": "MindExecution.Web.dll",
|
|
136
136
|
"dotnet.js": "dotnet.js",
|
|
137
137
|
"dotnet.native.qc8g39g30v.js": "dotnet.native.js",
|
|
138
138
|
"dotnet.native.boem75ye5i.wasm": "dotnet.native.wasm",
|
|
@@ -280,16 +280,16 @@
|
|
|
280
280
|
"netstandard.yvr3prsx0x.dll": "sha256-EksNn8Luo4bOWqJ6X7dIe9qG9oOqwOVzjH2xYyMNi+E=",
|
|
281
281
|
"MindExecution.Core.asayb4hw1o.dll": "sha256-5gla4JTR/zbvkGpneSt6S7ItE51+MjWgjW6L+B6Yevk=",
|
|
282
282
|
"MindExecution.Kernel.3zom09ir6j.dll": "sha256-78vR2SNkF9FwdQv0fEItSyz4HzgyzwGUROJAnpripPA=",
|
|
283
|
-
"MindExecution.Plugins.Concept.
|
|
284
|
-
"MindExecution.Plugins.PlanMaster.
|
|
285
|
-
"MindExecution.Shared.
|
|
286
|
-
"MindExecution.Web.
|
|
283
|
+
"MindExecution.Plugins.Concept.5gltgdqyo3.dll": "sha256-1ZVpFoyPoidSyJz38jH40AFealONt+qQpToJKgqoWW8=",
|
|
284
|
+
"MindExecution.Plugins.PlanMaster.cn6ppe6qoz.dll": "sha256-GIFH/f4ilVTFDJVEDLLiWkkI7yGeeQl/T5/iuivI87Q=",
|
|
285
|
+
"MindExecution.Shared.mnpwk5h86c.dll": "sha256-Ht4Kl9nQePXwyDEwL4jBxo2K3F9R4B2OGnSuhHmZ+eU=",
|
|
286
|
+
"MindExecution.Web.ygql0sg6b3.dll": "sha256-vhb5mjLTaEStzJ9ggN4jBqtd1Z7FAkKHp7bx6Pz33Mc="
|
|
287
287
|
},
|
|
288
288
|
"lazyAssembly": {
|
|
289
289
|
"MindExecution.Plugins.Admin.bk23zzy6wc.dll": "sha256-uz7Nz0OZ8BBESp2Nr9YocyzV0dUrn7szPuD4/m/RWL8=",
|
|
290
290
|
"MindExecution.Plugins.Business.zwcvc8wufe.dll": "sha256-3YDsB2/uNI+feWqJk+cesLHgNt8s2/8hXxGPO6CRZZE=",
|
|
291
291
|
"MindExecution.Plugins.Directory.jc0g7fvyzv.dll": "sha256-PSe7135JPpTBmu4j+rGLF0Dc/6w/wDJNPi8zlfTmSMk=",
|
|
292
|
-
"MindExecution.Plugins.YouTube.
|
|
292
|
+
"MindExecution.Plugins.YouTube.d7nnsxrftv.dll": "sha256-OQVjt1f240FGxRV8b2FpxDv4i3U4a7GGA+dBBiZBih8="
|
|
293
293
|
}
|
|
294
294
|
},
|
|
295
295
|
"cacheBootResources": true,
|
package/wwwroot/index.html
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<title>MindExec | Run your ideas as AI task graphs</title>
|
|
8
8
|
<meta name="description" content="MindExec is an AI execution canvas for solo builders, researchers, developers, and creators. Start with free browser tools, then move serious work into saved MindCanvas projects." />
|
|
9
9
|
<base href="/" />
|
|
10
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260616-mdm-binary-canvas-
|
|
11
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260616-mdm-binary-canvas-
|
|
10
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260616-mdm-binary-canvas-v579" />
|
|
11
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260616-mdm-binary-canvas-v579" />
|
|
12
12
|
<!-- ?쇄뼹??Font Awesome (local) ?쇄뼹??-->
|
|
13
13
|
<link rel="stylesheet" href="_content/MindExecution.Shared/lib/font-awesome/css/all.min.css" />
|
|
14
14
|
<!-- ?꿎뼯??-->
|
|
@@ -579,7 +579,7 @@
|
|
|
579
579
|
}
|
|
580
580
|
|
|
581
581
|
const base = '_content/MindExecution.Shared/js/';
|
|
582
|
-
const scriptVersion = '20260616-mdm-binary-canvas-
|
|
582
|
+
const scriptVersion = '20260616-mdm-binary-canvas-v579';
|
|
583
583
|
const scriptUrl = (script) => `${base}${script}?v=${scriptVersion}`;
|
|
584
584
|
console.log(`[Script Loader] Shared JS version: ${scriptVersion}`);
|
|
585
585
|
const criticalScripts = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
self.assetsManifest = {
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "yUK/iR3X",
|
|
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-RLe5Ta1um44TU9QYuOpzKHrl8t1tOWQdkL+zwH79MFA=",
|
|
90
90
|
"url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
@@ -426,28 +426,28 @@
|
|
|
426
426
|
"url": "_framework/MindExecution.Plugins.Business.zwcvc8wufe.dll"
|
|
427
427
|
},
|
|
428
428
|
{
|
|
429
|
-
"hash": "sha256-
|
|
430
|
-
"url": "_framework/MindExecution.Plugins.Concept.
|
|
429
|
+
"hash": "sha256-1ZVpFoyPoidSyJz38jH40AFealONt+qQpToJKgqoWW8=",
|
|
430
|
+
"url": "_framework/MindExecution.Plugins.Concept.5gltgdqyo3.dll"
|
|
431
431
|
},
|
|
432
432
|
{
|
|
433
433
|
"hash": "sha256-PSe7135JPpTBmu4j+rGLF0Dc/6w/wDJNPi8zlfTmSMk=",
|
|
434
434
|
"url": "_framework/MindExecution.Plugins.Directory.jc0g7fvyzv.dll"
|
|
435
435
|
},
|
|
436
436
|
{
|
|
437
|
-
"hash": "sha256-
|
|
438
|
-
"url": "_framework/MindExecution.Plugins.PlanMaster.
|
|
437
|
+
"hash": "sha256-GIFH/f4ilVTFDJVEDLLiWkkI7yGeeQl/T5/iuivI87Q=",
|
|
438
|
+
"url": "_framework/MindExecution.Plugins.PlanMaster.cn6ppe6qoz.dll"
|
|
439
439
|
},
|
|
440
440
|
{
|
|
441
|
-
"hash": "sha256-
|
|
442
|
-
"url": "_framework/MindExecution.Plugins.YouTube.
|
|
441
|
+
"hash": "sha256-OQVjt1f240FGxRV8b2FpxDv4i3U4a7GGA+dBBiZBih8=",
|
|
442
|
+
"url": "_framework/MindExecution.Plugins.YouTube.d7nnsxrftv.dll"
|
|
443
443
|
},
|
|
444
444
|
{
|
|
445
|
-
"hash": "sha256-
|
|
446
|
-
"url": "_framework/MindExecution.Shared.
|
|
445
|
+
"hash": "sha256-Ht4Kl9nQePXwyDEwL4jBxo2K3F9R4B2OGnSuhHmZ+eU=",
|
|
446
|
+
"url": "_framework/MindExecution.Shared.mnpwk5h86c.dll"
|
|
447
447
|
},
|
|
448
448
|
{
|
|
449
|
-
"hash": "sha256-
|
|
450
|
-
"url": "_framework/MindExecution.Web.
|
|
449
|
+
"hash": "sha256-vhb5mjLTaEStzJ9ggN4jBqtd1Z7FAkKHp7bx6Pz33Mc=",
|
|
450
|
+
"url": "_framework/MindExecution.Web.ygql0sg6b3.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-FgsKNE/RFoMI9OioRZ4cgImxpXXkbc2D4LpHp7W2L7A=",
|
|
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-0O54YE8cYfnYOu/2NbpFuJs/cJRKBw/OAc963M3JI6E=",
|
|
838
838
|
"url": "index.html"
|
|
839
839
|
},
|
|
840
840
|
{
|