@mindexec/cli 0.2.123 → 0.2.125
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindexec/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.125",
|
|
4
4
|
"description": "MindExec local runtime and bridge CLI",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -20,12 +20,13 @@
|
|
|
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/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",
|
|
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/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",
|
|
24
24
|
"test:auth": "node scripts/auth-session-smoke.mjs",
|
|
25
25
|
"test:remote": "node scripts/remote-hub-smoke.mjs",
|
|
26
26
|
"test:remote:scale": "node scripts/remote-hub-scale-smoke.mjs",
|
|
27
27
|
"test:remote:render": "node scripts/remote-fleet-render-smoke.mjs",
|
|
28
28
|
"test:remote:http": "node scripts/remote-http-smoke.mjs",
|
|
29
|
+
"test:remote:managed": "node scripts/remote-agent-managed-smoke.mjs",
|
|
29
30
|
"pack:dry": "npm pack --dry-run",
|
|
30
31
|
"setup:grammars": "node scripts/setup-tree-sitter-grammars.mjs",
|
|
31
32
|
"postinstall": "npm run setup:grammars"
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { mkdtemp, readFile, 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 } from 'node:url';
|
|
10
|
+
|
|
11
|
+
const BRIDGE_TOKEN = 'remote-agent-managed-smoke-token';
|
|
12
|
+
const PAIR_TOKEN = 'remote-agent-managed-pair-token';
|
|
13
|
+
const LEASE_ID = 'remote-agent-managed-smoke-lease';
|
|
14
|
+
const LOCAL_BRIDGE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
15
|
+
|
|
16
|
+
function wait(ms) {
|
|
17
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function findFreePort() {
|
|
21
|
+
return await new Promise((resolve, reject) => {
|
|
22
|
+
const server = net.createServer();
|
|
23
|
+
server.unref();
|
|
24
|
+
server.once('error', reject);
|
|
25
|
+
server.listen(0, '127.0.0.1', () => {
|
|
26
|
+
const address = server.address();
|
|
27
|
+
const port = typeof address === 'object' && address ? address.port : 0;
|
|
28
|
+
server.close(() => resolve(port));
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function fetchJson(url, options = {}) {
|
|
34
|
+
const response = await fetch(url, {
|
|
35
|
+
...options,
|
|
36
|
+
headers: {
|
|
37
|
+
...(options.body ? { 'Content-Type': 'application/json' } : {}),
|
|
38
|
+
'X-Bridge-Token': options.token || BRIDGE_TOKEN,
|
|
39
|
+
...(options.headers || {})
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
let payload = null;
|
|
44
|
+
try {
|
|
45
|
+
payload = await response.json();
|
|
46
|
+
} catch {
|
|
47
|
+
// Some failure responses may be empty.
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
status: response.status,
|
|
52
|
+
ok: response.ok,
|
|
53
|
+
payload
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function waitFor(predicate, timeoutMs = 30000, label = 'condition') {
|
|
58
|
+
const startedAt = Date.now();
|
|
59
|
+
let lastError = null;
|
|
60
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
61
|
+
try {
|
|
62
|
+
const value = await predicate();
|
|
63
|
+
if (value) {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
} catch (err) {
|
|
67
|
+
lastError = err;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
await wait(100);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
throw new Error(`Timed out waiting for ${label}${lastError ? `: ${lastError.message}` : ''}.`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function spawnBridge({ bridgePort, remoteHubPort, workspacePath, label }) {
|
|
77
|
+
const child = spawn(process.execPath, ['server.js'], {
|
|
78
|
+
cwd: LOCAL_BRIDGE_DIR,
|
|
79
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
80
|
+
windowsHide: true,
|
|
81
|
+
env: {
|
|
82
|
+
...process.env,
|
|
83
|
+
BRIDGE_PORT: String(bridgePort),
|
|
84
|
+
BRIDGE_TOKEN,
|
|
85
|
+
BRIDGE_REQUIRE_TOKEN: '1',
|
|
86
|
+
MINDEXEC_REMOTE_HUB: '1',
|
|
87
|
+
REMOTE_HUB_HOST: '127.0.0.1',
|
|
88
|
+
REMOTE_HUB_PORT: String(remoteHubPort),
|
|
89
|
+
REMOTE_HUB_PAIR_TOKEN: PAIR_TOKEN,
|
|
90
|
+
WORKSPACE_PATH: workspacePath,
|
|
91
|
+
NO_COLOR: '1'
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
let stdout = '';
|
|
96
|
+
let stderr = '';
|
|
97
|
+
child.stdout.on('data', chunk => {
|
|
98
|
+
stdout += chunk.toString();
|
|
99
|
+
});
|
|
100
|
+
child.stderr.on('data', chunk => {
|
|
101
|
+
stderr += chunk.toString();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const exitPromise = new Promise(resolve => child.once('exit', resolve));
|
|
105
|
+
const details = () => `${label} stdout=${stdout}\n${label} stderr=${stderr}`;
|
|
106
|
+
const stop = async () => {
|
|
107
|
+
if (child.exitCode === null && !child.killed) {
|
|
108
|
+
child.kill('SIGTERM');
|
|
109
|
+
await Promise.race([
|
|
110
|
+
exitPromise,
|
|
111
|
+
wait(5000)
|
|
112
|
+
]);
|
|
113
|
+
if (child.exitCode === null && !child.killed) {
|
|
114
|
+
child.kill('SIGKILL');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
baseUrl: `http://127.0.0.1:${bridgePort}`,
|
|
121
|
+
child,
|
|
122
|
+
details,
|
|
123
|
+
stop
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function waitForBridge(bridge) {
|
|
128
|
+
return await waitFor(async () => {
|
|
129
|
+
const result = await fetchJson(`${bridge.baseUrl}/api/status`);
|
|
130
|
+
return result.ok && result.payload?.status === 'ok' ? result.payload : null;
|
|
131
|
+
}, 30000, `bridge startup\n${bridge.details()}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function connectManagedAgent(clientBridge, managerEndpoint, staleEndpoint) {
|
|
135
|
+
const result = await fetchJson(`${clientBridge.baseUrl}/api/remote/agent/connect`, {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
body: JSON.stringify({
|
|
138
|
+
managerCandidates: [staleEndpoint, managerEndpoint],
|
|
139
|
+
pairToken: PAIR_TOKEN,
|
|
140
|
+
leaseId: LEASE_ID,
|
|
141
|
+
nodeId: 'remote-agent-managed-smoke-node',
|
|
142
|
+
engine: 'auto',
|
|
143
|
+
source: 'smoke'
|
|
144
|
+
})
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
assert.equal(result.ok, true, JSON.stringify(result.payload));
|
|
148
|
+
assert.equal(result.payload?.ok, true, JSON.stringify(result.payload));
|
|
149
|
+
return result.payload.agent;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function main() {
|
|
153
|
+
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'mindexec-remote-managed-smoke-'));
|
|
154
|
+
const hostWorkspace = path.join(tempRoot, 'host');
|
|
155
|
+
const clientWorkspace = path.join(tempRoot, 'client');
|
|
156
|
+
const hostBridgePort = await findFreePort();
|
|
157
|
+
const hostRemotePort = await findFreePort();
|
|
158
|
+
const clientBridgePort = await findFreePort();
|
|
159
|
+
const clientRemotePort = await findFreePort();
|
|
160
|
+
const stalePort = await findFreePort();
|
|
161
|
+
const managerEndpoint = `127.0.0.1:${hostRemotePort}`;
|
|
162
|
+
const staleEndpoint = `127.0.0.1:${stalePort}`;
|
|
163
|
+
|
|
164
|
+
let hostBridge = null;
|
|
165
|
+
let clientBridge = null;
|
|
166
|
+
try {
|
|
167
|
+
hostBridge = spawnBridge({
|
|
168
|
+
bridgePort: hostBridgePort,
|
|
169
|
+
remoteHubPort: hostRemotePort,
|
|
170
|
+
workspacePath: hostWorkspace,
|
|
171
|
+
label: 'host'
|
|
172
|
+
});
|
|
173
|
+
await waitForBridge(hostBridge);
|
|
174
|
+
|
|
175
|
+
clientBridge = spawnBridge({
|
|
176
|
+
bridgePort: clientBridgePort,
|
|
177
|
+
remoteHubPort: clientRemotePort,
|
|
178
|
+
workspacePath: clientWorkspace,
|
|
179
|
+
label: 'client-1'
|
|
180
|
+
});
|
|
181
|
+
await waitForBridge(clientBridge);
|
|
182
|
+
|
|
183
|
+
const firstAgent = await connectManagedAgent(clientBridge, managerEndpoint, staleEndpoint);
|
|
184
|
+
assert.equal(firstAgent.running, true, JSON.stringify(firstAgent));
|
|
185
|
+
assert.equal(firstAgent.ready, true, JSON.stringify(firstAgent));
|
|
186
|
+
assert.equal(firstAgent.usingNpx, false, JSON.stringify(firstAgent));
|
|
187
|
+
assert.match(String(firstAgent.launcher || ''), /mindexec-remote-fast/i);
|
|
188
|
+
|
|
189
|
+
const connectedDevice = await waitFor(async () => {
|
|
190
|
+
const result = await fetchJson(`${hostBridge.baseUrl}/api/remote/devices`);
|
|
191
|
+
return result.payload?.devices?.find(device => device.connected === true) || null;
|
|
192
|
+
}, 10000, `host device registration\n${hostBridge.details()}\n${clientBridge.details()}`);
|
|
193
|
+
assert.equal(connectedDevice.capabilities?.binaryFrames, true);
|
|
194
|
+
|
|
195
|
+
await clientBridge.stop();
|
|
196
|
+
clientBridge = null;
|
|
197
|
+
|
|
198
|
+
const cachePath = path.join(clientWorkspace, '.mindexec', 'cache', 'remote-agent-recent-managers.json');
|
|
199
|
+
const cache = JSON.parse(await readFile(cachePath, 'utf8'));
|
|
200
|
+
assert.equal(cache.version, 1);
|
|
201
|
+
assert.equal(cache.entries?.[0]?.endpoint, managerEndpoint, JSON.stringify(cache));
|
|
202
|
+
|
|
203
|
+
clientBridge = spawnBridge({
|
|
204
|
+
bridgePort: clientBridgePort,
|
|
205
|
+
remoteHubPort: clientRemotePort,
|
|
206
|
+
workspacePath: clientWorkspace,
|
|
207
|
+
label: 'client-2'
|
|
208
|
+
});
|
|
209
|
+
await waitForBridge(clientBridge);
|
|
210
|
+
|
|
211
|
+
const secondAgent = await connectManagedAgent(clientBridge, managerEndpoint, staleEndpoint);
|
|
212
|
+
assert.equal(secondAgent.running, true, JSON.stringify(secondAgent));
|
|
213
|
+
assert.equal(secondAgent.ready, true, JSON.stringify(secondAgent));
|
|
214
|
+
assert.equal(secondAgent.usingNpx, false, JSON.stringify(secondAgent));
|
|
215
|
+
assert.match(String(secondAgent.launcher || ''), /mindexec-remote-fast/i);
|
|
216
|
+
assert.equal(secondAgent.managerCandidates?.[0], managerEndpoint, JSON.stringify(secondAgent.managerCandidates));
|
|
217
|
+
assert.equal(secondAgent.managerCandidates?.[1], staleEndpoint, JSON.stringify(secondAgent.managerCandidates));
|
|
218
|
+
|
|
219
|
+
console.log('RemoteAgent managed supervisor smoke OK');
|
|
220
|
+
} finally {
|
|
221
|
+
if (clientBridge) {
|
|
222
|
+
await clientBridge.stop();
|
|
223
|
+
}
|
|
224
|
+
if (hostBridge) {
|
|
225
|
+
await hostBridge.stop();
|
|
226
|
+
}
|
|
227
|
+
await rm(tempRoot, { recursive: true, force: true });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
await main();
|
|
@@ -13461,6 +13461,7 @@
|
|
|
13461
13461
|
const REMOTE_FLEET_FRAME_BLOB_CACHE_LIMIT = 96;
|
|
13462
13462
|
const REMOTE_FLEET_LIVE_FRAME_DECODE_TIMEOUT_MS = 180;
|
|
13463
13463
|
const REMOTE_FLEET_THUMBNAIL_FRAME_DECODE_TIMEOUT_MS = 1200;
|
|
13464
|
+
const REMOTE_FLEET_BINARY_FRAME_MAX_DECODE_IN_FLIGHT = 2;
|
|
13464
13465
|
const REMOTE_FLEET_BINARY_FRAME_WS_RECONNECT_MS = 1500;
|
|
13465
13466
|
const REMOTE_FLEET_BINARY_FRAME_SUBSCRIBE_MS = 1000;
|
|
13466
13467
|
const REMOTE_FLEET_BINARY_FRAME_STALE_FALLBACK_MS = 1400;
|
|
@@ -14506,13 +14507,14 @@
|
|
|
14506
14507
|
}
|
|
14507
14508
|
|
|
14508
14509
|
if (comparePending) {
|
|
14509
|
-
const pendingUrl = String(preview.dataset.remoteFleetPendingImageUrl || preview.dataset.remoteFleetPendingFrameUrl || '');
|
|
14510
|
-
const pendingKind = String(preview.dataset.remoteFleetPendingImageKind || preview.dataset.remoteFleetPendingFrameKind || '').toLowerCase();
|
|
14511
|
-
const pendingSeq = Number(preview.dataset.remoteFleetPendingImageSeq || preview.dataset.remoteFleetPendingFrameSeq || '0');
|
|
14512
|
-
|
|
14510
|
+
const pendingUrl = String(preview.dataset.remoteFleetPendingBinaryUrl || preview.dataset.remoteFleetPendingImageUrl || preview.dataset.remoteFleetPendingFrameUrl || '');
|
|
14511
|
+
const pendingKind = String(preview.dataset.remoteFleetPendingBinaryKind || preview.dataset.remoteFleetPendingImageKind || preview.dataset.remoteFleetPendingFrameKind || '').toLowerCase();
|
|
14512
|
+
const pendingSeq = Number(preview.dataset.remoteFleetPendingBinarySeq || preview.dataset.remoteFleetPendingImageSeq || preview.dataset.remoteFleetPendingFrameSeq || '0');
|
|
14513
|
+
const hasPendingFrame = !!pendingUrl || !!pendingKind || (Number.isFinite(pendingSeq) && pendingSeq > 0);
|
|
14514
|
+
if (hasPendingFrame) {
|
|
14513
14515
|
const samePending = pendingKind === frame.kind
|
|
14514
14516
|
&& pendingSeq === nextSeq
|
|
14515
|
-
&& pendingUrl === frame.frameUrl;
|
|
14517
|
+
&& (pendingUrl === frame.frameUrl || (!pendingUrl && !frame.frameUrl));
|
|
14516
14518
|
if (samePending) {
|
|
14517
14519
|
return false;
|
|
14518
14520
|
}
|
|
@@ -14652,6 +14654,165 @@
|
|
|
14652
14654
|
}
|
|
14653
14655
|
}
|
|
14654
14656
|
|
|
14657
|
+
function clearRemoteFleetPendingBinaryDataset(preview, frame) {
|
|
14658
|
+
if (!preview || preview._remoteFleetPendingBinaryFrame) {
|
|
14659
|
+
return;
|
|
14660
|
+
}
|
|
14661
|
+
|
|
14662
|
+
const pendingKind = String(preview.dataset.remoteFleetPendingBinaryKind || '').toLowerCase();
|
|
14663
|
+
const pendingSeq = Number(preview.dataset.remoteFleetPendingBinarySeq || '0');
|
|
14664
|
+
const pendingUrl = String(preview.dataset.remoteFleetPendingBinaryUrl || '');
|
|
14665
|
+
const frameKind = String(frame?.kind || '').toLowerCase();
|
|
14666
|
+
const frameSeq = Number(frame?.frameSeq || 0);
|
|
14667
|
+
const frameUrl = String(frame?.frameUrl || '');
|
|
14668
|
+
const sameFrame = !frame
|
|
14669
|
+
|| (pendingKind === frameKind
|
|
14670
|
+
&& pendingSeq === frameSeq
|
|
14671
|
+
&& (pendingUrl === frameUrl || (!pendingUrl && !frameUrl)));
|
|
14672
|
+
|
|
14673
|
+
if (!sameFrame) {
|
|
14674
|
+
return;
|
|
14675
|
+
}
|
|
14676
|
+
|
|
14677
|
+
delete preview.dataset.remoteFleetPendingBinaryKind;
|
|
14678
|
+
delete preview.dataset.remoteFleetPendingBinarySeq;
|
|
14679
|
+
delete preview.dataset.remoteFleetPendingBinaryUrl;
|
|
14680
|
+
}
|
|
14681
|
+
|
|
14682
|
+
function hasRemoteFleetSupersedingBinaryFrame(preview, frame) {
|
|
14683
|
+
const pending = preview?._remoteFleetPendingBinaryFrame;
|
|
14684
|
+
if (!pending || !frame) {
|
|
14685
|
+
return false;
|
|
14686
|
+
}
|
|
14687
|
+
|
|
14688
|
+
const pendingKind = String(pending.kind || '').toLowerCase();
|
|
14689
|
+
const frameKind = String(frame.kind || '').toLowerCase();
|
|
14690
|
+
if (pendingKind === 'live' && frameKind !== 'live') {
|
|
14691
|
+
return true;
|
|
14692
|
+
}
|
|
14693
|
+
|
|
14694
|
+
const pendingSeq = Number(pending.frameSeq || 0);
|
|
14695
|
+
const frameSeq = Number(frame.frameSeq || 0);
|
|
14696
|
+
if (Number.isFinite(pendingSeq)
|
|
14697
|
+
&& Number.isFinite(frameSeq)
|
|
14698
|
+
&& pendingSeq > 0
|
|
14699
|
+
&& frameSeq > 0) {
|
|
14700
|
+
return pendingSeq > frameSeq;
|
|
14701
|
+
}
|
|
14702
|
+
|
|
14703
|
+
return getRemoteFleetFrameIdentity(pending) !== getRemoteFleetFrameIdentity(frame);
|
|
14704
|
+
}
|
|
14705
|
+
|
|
14706
|
+
function drainRemoteFleetBinaryCanvasPaint(preview) {
|
|
14707
|
+
if (!preview
|
|
14708
|
+
|| !document.body.contains(preview)
|
|
14709
|
+
|| Number(preview._remoteFleetBinaryPaintInFlight || 0) >= REMOTE_FLEET_BINARY_FRAME_MAX_DECODE_IN_FLIGHT) {
|
|
14710
|
+
return;
|
|
14711
|
+
}
|
|
14712
|
+
|
|
14713
|
+
const frame = preview._remoteFleetPendingBinaryFrame;
|
|
14714
|
+
if (!frame || !frame._remoteFleetPayloadBlob || typeof createImageBitmap !== 'function') {
|
|
14715
|
+
preview._remoteFleetPendingBinaryFrame = null;
|
|
14716
|
+
clearRemoteFleetPendingBinaryDataset(preview, frame);
|
|
14717
|
+
return;
|
|
14718
|
+
}
|
|
14719
|
+
|
|
14720
|
+
if (!isRemoteFleetFrameNewerForPreview(preview, frame, false)) {
|
|
14721
|
+
preview._remoteFleetPendingBinaryFrame = null;
|
|
14722
|
+
clearRemoteFleetPendingBinaryDataset(preview, frame);
|
|
14723
|
+
return;
|
|
14724
|
+
}
|
|
14725
|
+
|
|
14726
|
+
preview._remoteFleetPendingBinaryFrame = null;
|
|
14727
|
+
preview._remoteFleetBinaryPaintInFlight = Number(preview._remoteFleetBinaryPaintInFlight || 0) + 1;
|
|
14728
|
+
const token = Number(preview._remoteFleetBinaryPaintToken || 0) + 1;
|
|
14729
|
+
preview._remoteFleetBinaryPaintToken = token;
|
|
14730
|
+
|
|
14731
|
+
loadRemoteFleetFrameBitmap(frame)
|
|
14732
|
+
.then(bitmap => new Promise(resolve => {
|
|
14733
|
+
if (!bitmap) {
|
|
14734
|
+
resolve(false);
|
|
14735
|
+
return;
|
|
14736
|
+
}
|
|
14737
|
+
|
|
14738
|
+
requestRemoteFleetFrameLoopFrame(() => {
|
|
14739
|
+
let committed = false;
|
|
14740
|
+
try {
|
|
14741
|
+
const isLatestToken = Number(preview._remoteFleetBinaryPaintToken || 0) === token;
|
|
14742
|
+
const superseded = hasRemoteFleetSupersedingBinaryFrame(preview, frame);
|
|
14743
|
+
if (document.body.contains(preview) && isLatestToken && !superseded) {
|
|
14744
|
+
const canvas = ensureRemoteFleetFrameCanvas(preview);
|
|
14745
|
+
const image = preview.querySelector?.('img[data-remote-fleet-frame-image="true"]') || null;
|
|
14746
|
+
committed = commitRemoteFleetFrameToCanvas(preview, canvas, image, bitmap, frame);
|
|
14747
|
+
}
|
|
14748
|
+
} finally {
|
|
14749
|
+
if (typeof bitmap.close === 'function') {
|
|
14750
|
+
bitmap.close();
|
|
14751
|
+
}
|
|
14752
|
+
}
|
|
14753
|
+
|
|
14754
|
+
if (committed) {
|
|
14755
|
+
window.RuntimeTrace?.emit?.('remote.frame.binaryPatched', {
|
|
14756
|
+
count: 1,
|
|
14757
|
+
kind: frame.kind,
|
|
14758
|
+
seq: frame.frameSeq,
|
|
14759
|
+
surface: 'binary-canvas',
|
|
14760
|
+
contentHash: frame.contentHash || '',
|
|
14761
|
+
sameContentStreak: Number(frame.sameContentStreak || 0) || 0,
|
|
14762
|
+
captureMs: Number(frame.captureMs || 0) || 0
|
|
14763
|
+
});
|
|
14764
|
+
} else {
|
|
14765
|
+
window.RuntimeTrace?.emit?.('remote.frame.binarySkipped', {
|
|
14766
|
+
kind: frame.kind,
|
|
14767
|
+
seq: frame.frameSeq,
|
|
14768
|
+
reason: hasRemoteFleetSupersedingBinaryFrame(preview, frame) ? 'superseded' : 'stale'
|
|
14769
|
+
});
|
|
14770
|
+
}
|
|
14771
|
+
|
|
14772
|
+
resolve(committed);
|
|
14773
|
+
});
|
|
14774
|
+
}))
|
|
14775
|
+
.catch(error => {
|
|
14776
|
+
window.RuntimeTrace?.emit?.('remote.frame.binaryDecodeFailed', {
|
|
14777
|
+
kind: frame.kind,
|
|
14778
|
+
seq: frame.frameSeq,
|
|
14779
|
+
error: error?.message || String(error || '')
|
|
14780
|
+
});
|
|
14781
|
+
})
|
|
14782
|
+
.finally(() => {
|
|
14783
|
+
preview._remoteFleetBinaryPaintInFlight = Math.max(0, Number(preview._remoteFleetBinaryPaintInFlight || 0) - 1);
|
|
14784
|
+
if (!preview._remoteFleetPendingBinaryFrame) {
|
|
14785
|
+
clearRemoteFleetPendingBinaryDataset(preview, frame);
|
|
14786
|
+
}
|
|
14787
|
+
if (preview._remoteFleetPendingBinaryFrame) {
|
|
14788
|
+
drainRemoteFleetBinaryCanvasPaint(preview);
|
|
14789
|
+
}
|
|
14790
|
+
});
|
|
14791
|
+
}
|
|
14792
|
+
|
|
14793
|
+
function queueRemoteFleetBinaryCanvasPaint(preview, frame) {
|
|
14794
|
+
if (!preview
|
|
14795
|
+
|| !frame
|
|
14796
|
+
|| frame._remoteFleetBinaryFrame !== true
|
|
14797
|
+
|| !frame._remoteFleetPayloadBlob
|
|
14798
|
+
|| typeof createImageBitmap !== 'function'
|
|
14799
|
+
|| !isRemoteFleetFrameNewerForPreview(preview, frame, true)) {
|
|
14800
|
+
return false;
|
|
14801
|
+
}
|
|
14802
|
+
|
|
14803
|
+
const nextFrame = cloneRemoteFleetFramePatch(frame);
|
|
14804
|
+
preview._remoteFleetPendingBinaryFrame = nextFrame;
|
|
14805
|
+
preview.dataset.remoteFleetPendingBinaryKind = nextFrame.kind;
|
|
14806
|
+
preview.dataset.remoteFleetPendingBinarySeq = String(nextFrame.frameSeq || 0);
|
|
14807
|
+
preview.dataset.remoteFleetPendingBinaryUrl = nextFrame.frameUrl || '';
|
|
14808
|
+
window.RuntimeTrace?.emit?.('remote.frame.binaryQueued', {
|
|
14809
|
+
kind: nextFrame.kind,
|
|
14810
|
+
seq: nextFrame.frameSeq
|
|
14811
|
+
});
|
|
14812
|
+
drainRemoteFleetBinaryCanvasPaint(preview);
|
|
14813
|
+
return true;
|
|
14814
|
+
}
|
|
14815
|
+
|
|
14655
14816
|
function processRemoteFleetFramePaintQueue(preview, image) {
|
|
14656
14817
|
if (!preview || !image || preview._remoteFleetFrameLoaderActive === true) {
|
|
14657
14818
|
return;
|
|
@@ -14925,6 +15086,16 @@
|
|
|
14925
15086
|
}
|
|
14926
15087
|
|
|
14927
15088
|
function applyRemoteFleetFramePatchToPreview(preview, frame) {
|
|
15089
|
+
if (frame?._remoteFleetBinaryFrame === true && frame?._remoteFleetPayloadBlob) {
|
|
15090
|
+
preview._remoteFleetPendingImageFrame = null;
|
|
15091
|
+
delete preview.dataset.remoteFleetPendingImageKind;
|
|
15092
|
+
delete preview.dataset.remoteFleetPendingImageSeq;
|
|
15093
|
+
delete preview.dataset.remoteFleetPendingImageUrl;
|
|
15094
|
+
if (queueRemoteFleetBinaryCanvasPaint(preview, frame)) {
|
|
15095
|
+
return true;
|
|
15096
|
+
}
|
|
15097
|
+
}
|
|
15098
|
+
|
|
14928
15099
|
if (String(frame?.kind || '').toLowerCase() === 'live') {
|
|
14929
15100
|
preview._remoteFleetPendingImageFrame = null;
|
|
14930
15101
|
delete preview.dataset.remoteFleetPendingImageKind;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
self.assetsManifest = {
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "MEKEGiqN",
|
|
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-g1BhxjO7bWZgkU1pMxOmGH/Z3n7XsZQYBIx31/Ptsu0=",
|
|
90
90
|
"url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
|
|
91
91
|
},
|
|
92
92
|
{
|