@mindexec/cli 0.2.142 → 0.2.144
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
|
@@ -442,6 +442,7 @@ async function loadCss3DManager() {
|
|
|
442
442
|
this.readyState = MiniWebSocket.CONNECTING;
|
|
443
443
|
this.binaryType = '';
|
|
444
444
|
this.sent = [];
|
|
445
|
+
this.closeCount = 0;
|
|
445
446
|
webSocketConnections.push(this);
|
|
446
447
|
setTimeout(() => {
|
|
447
448
|
if (this.readyState !== MiniWebSocket.CONNECTING) return;
|
|
@@ -458,6 +459,7 @@ async function loadCss3DManager() {
|
|
|
458
459
|
|
|
459
460
|
close() {
|
|
460
461
|
if (this.readyState === MiniWebSocket.CLOSED) return;
|
|
462
|
+
this.closeCount += 1;
|
|
461
463
|
this.readyState = MiniWebSocket.CLOSED;
|
|
462
464
|
this.onclose?.({ type: 'close' });
|
|
463
465
|
}
|
|
@@ -490,6 +492,8 @@ async function loadCss3DManager() {
|
|
|
490
492
|
Set,
|
|
491
493
|
WeakMap,
|
|
492
494
|
Blob,
|
|
495
|
+
TextDecoder,
|
|
496
|
+
TextEncoder,
|
|
493
497
|
requestAnimationFrame: callback => setTimeout(() => callback(Date.now()), 0),
|
|
494
498
|
cancelAnimationFrame: id => clearTimeout(id),
|
|
495
499
|
createImageBitmap: async blob => {
|
|
@@ -546,6 +550,18 @@ function wait(ms = 0) {
|
|
|
546
550
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
547
551
|
}
|
|
548
552
|
|
|
553
|
+
function encodeRemoteBinaryFrame(metadata, payload = new Uint8Array([0xff, 0xd8, 0xff, 0xd9])) {
|
|
554
|
+
const metaBytes = new TextEncoder().encode(JSON.stringify(metadata));
|
|
555
|
+
const payloadBytes = payload instanceof Uint8Array ? payload : new Uint8Array(payload);
|
|
556
|
+
const buffer = new ArrayBuffer(4 + metaBytes.byteLength + payloadBytes.byteLength);
|
|
557
|
+
const view = new DataView(buffer);
|
|
558
|
+
view.setUint32(0, metaBytes.byteLength);
|
|
559
|
+
const bytes = new Uint8Array(buffer);
|
|
560
|
+
bytes.set(metaBytes, 4);
|
|
561
|
+
bytes.set(payloadBytes, 4 + metaBytes.byteLength);
|
|
562
|
+
return buffer;
|
|
563
|
+
}
|
|
564
|
+
|
|
549
565
|
function buildMonitorNode(devices, hubStatus, latestTaskBatch = null, recentTaskBatches = [], lastError = '') {
|
|
550
566
|
const connected = devices.filter(device => device.Connected).length;
|
|
551
567
|
const endpoint = hubStatus.agentEndpoint || '127.0.0.1:5197';
|
|
@@ -935,6 +951,52 @@ try {
|
|
|
935
951
|
binaryDrawCalls.some(call => call.op === 'clearRect' || call.op === 'fillRect'),
|
|
936
952
|
false,
|
|
937
953
|
'binary Blob frame paint must not clear/fill the canvas before drawing');
|
|
954
|
+
|
|
955
|
+
await wait(20);
|
|
956
|
+
const liveWs = diagnostics.webSocketConnections[0];
|
|
957
|
+
assert.ok(liveWs, 'expected MDM render to open the binary frame WebSocket');
|
|
958
|
+
assert.equal(liveWs.readyState, 1, 'binary frame WebSocket should be open before rerender');
|
|
959
|
+
const wsCountBeforeRerender = diagnostics.webSocketConnections.length;
|
|
960
|
+
const wsCloseCountBeforeRerender = liveWs.closeCount;
|
|
961
|
+
const websocketFrameSeq = 10001;
|
|
962
|
+
liveWs.onmessage?.({
|
|
963
|
+
data: new Blob([encodeRemoteBinaryFrame({
|
|
964
|
+
type: 'remote.frame.binary',
|
|
965
|
+
deviceId: patchTarget.DeviceId,
|
|
966
|
+
kind: 'live',
|
|
967
|
+
frameSeq: websocketFrameSeq,
|
|
968
|
+
streamId: 'render-smoke-ws-live',
|
|
969
|
+
contentHash: `render-smoke-ws-live-${websocketFrameSeq}`,
|
|
970
|
+
mimeType: 'image/jpeg',
|
|
971
|
+
width: 64,
|
|
972
|
+
height: 36,
|
|
973
|
+
capturedAt: new Date().toISOString(),
|
|
974
|
+
receivedAt: new Date().toISOString()
|
|
975
|
+
})])
|
|
976
|
+
});
|
|
977
|
+
await wait(30);
|
|
978
|
+
assert.equal(
|
|
979
|
+
patchPreview.dataset.remoteFleetFrameSeq,
|
|
980
|
+
String(websocketFrameSeq),
|
|
981
|
+
JSON.stringify(diagnostics.runtimeTrace.slice(-12)));
|
|
982
|
+
|
|
983
|
+
manager.renderRemoteFleetMonitorForTest(bodyView, buildMonitorNode(devices, hub.getStatus({ includeSecrets: true }), latestTaskBatch, recentTaskBatches));
|
|
984
|
+
await wait(30);
|
|
985
|
+
assert.equal(
|
|
986
|
+
liveWs.closeCount,
|
|
987
|
+
wsCloseCountBeforeRerender,
|
|
988
|
+
'MDM rerender must not close the active binary frame WebSocket');
|
|
989
|
+
assert.equal(
|
|
990
|
+
diagnostics.webSocketConnections.length,
|
|
991
|
+
wsCountBeforeRerender,
|
|
992
|
+
'MDM rerender must reuse the active binary frame WebSocket instead of opening a replacement');
|
|
993
|
+
const rerenderedPatchPreview = bodyView
|
|
994
|
+
.querySelector(`article[data-device-id="${patchTarget.DeviceId}"]`)
|
|
995
|
+
?.querySelector('[data-remote-fleet-device-preview="tile"]');
|
|
996
|
+
assert.ok(rerenderedPatchPreview);
|
|
997
|
+
assert.equal(rerenderedPatchPreview.dataset.remoteFleetFrameSeq, String(websocketFrameSeq));
|
|
998
|
+
assert.equal(rerenderedPatchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]')?.style.display, 'block');
|
|
999
|
+
|
|
938
1000
|
const alternateDevice = devices.find(device =>
|
|
939
1001
|
device.Connected === true
|
|
940
1002
|
&& device.DeviceId !== focusedDevice.DeviceId);
|
|
@@ -13459,13 +13459,15 @@
|
|
|
13459
13459
|
const REMOTE_FLEET_FRAME_CANVAS_MAX_DPR = 2;
|
|
13460
13460
|
const REMOTE_FLEET_FRAME_BLOB_CACHE_MS = 10000;
|
|
13461
13461
|
const REMOTE_FLEET_FRAME_BLOB_CACHE_LIMIT = 96;
|
|
13462
|
-
const REMOTE_FLEET_LIVE_FRAME_DECODE_TIMEOUT_MS =
|
|
13462
|
+
const REMOTE_FLEET_LIVE_FRAME_DECODE_TIMEOUT_MS = 700;
|
|
13463
13463
|
const REMOTE_FLEET_THUMBNAIL_FRAME_DECODE_TIMEOUT_MS = 1200;
|
|
13464
13464
|
const REMOTE_FLEET_BINARY_FRAME_MAX_DECODE_IN_FLIGHT = 1;
|
|
13465
13465
|
const REMOTE_FLEET_BINARY_FRAME_WS_RECONNECT_MS = 1500;
|
|
13466
13466
|
const REMOTE_FLEET_BINARY_FRAME_SUBSCRIBE_MS = 1000;
|
|
13467
13467
|
const REMOTE_FLEET_BINARY_FRAME_STALE_FALLBACK_MS = 1400;
|
|
13468
13468
|
const REMOTE_FLEET_BINARY_FRAME_CONNECT_GRACE_MS = 1600;
|
|
13469
|
+
const REMOTE_FLEET_BINARY_FRAME_CACHE_MS = 10000;
|
|
13470
|
+
const REMOTE_FLEET_BINARY_FRAME_CACHE_LIMIT = 240;
|
|
13469
13471
|
const REMOTE_FLEET_AUTO_LIVE_START_MAX_PARALLEL = 8;
|
|
13470
13472
|
const REMOTE_FLEET_AUTO_LIVE_START_COOLDOWN_MS = 3000;
|
|
13471
13473
|
const REMOTE_FLEET_TASK_FOLLOW_INITIAL_MS = 250;
|
|
@@ -13639,9 +13641,11 @@
|
|
|
13639
13641
|
return nodeState;
|
|
13640
13642
|
}
|
|
13641
13643
|
|
|
13642
|
-
function clearRemoteFleetTimers(bodyView) {
|
|
13644
|
+
function clearRemoteFleetTimers(bodyView, options = {}) {
|
|
13643
13645
|
if (!bodyView) return;
|
|
13644
|
-
|
|
13646
|
+
if (options.keepBinaryFrameSocket !== true) {
|
|
13647
|
+
releaseRemoteFleetBinaryFrameSocket(bodyView);
|
|
13648
|
+
}
|
|
13645
13649
|
if (bodyView._remoteFleetLiveRefreshTimer) {
|
|
13646
13650
|
clearInterval(bodyView._remoteFleetLiveRefreshTimer);
|
|
13647
13651
|
bodyView._remoteFleetLiveRefreshTimer = null;
|
|
@@ -13822,6 +13826,57 @@
|
|
|
13822
13826
|
.slice(0, 240);
|
|
13823
13827
|
}
|
|
13824
13828
|
|
|
13829
|
+
function pruneRemoteFleetBinaryFrameCache(session) {
|
|
13830
|
+
if (!session?.latestBinaryFrames) {
|
|
13831
|
+
return;
|
|
13832
|
+
}
|
|
13833
|
+
|
|
13834
|
+
const now = getRemoteFleetFrameNow();
|
|
13835
|
+
for (const [deviceId, entry] of session.latestBinaryFrames) {
|
|
13836
|
+
if (!entry
|
|
13837
|
+
|| !entry.frame
|
|
13838
|
+
|| now - Number(entry.seenAt || 0) > REMOTE_FLEET_BINARY_FRAME_CACHE_MS
|
|
13839
|
+
|| session.latestBinaryFrames.size > REMOTE_FLEET_BINARY_FRAME_CACHE_LIMIT) {
|
|
13840
|
+
session.latestBinaryFrames.delete(deviceId);
|
|
13841
|
+
}
|
|
13842
|
+
}
|
|
13843
|
+
}
|
|
13844
|
+
|
|
13845
|
+
function rememberRemoteFleetBinaryFrame(session, frame) {
|
|
13846
|
+
const deviceId = String(frame?.deviceId || '').trim();
|
|
13847
|
+
if (!session || !deviceId || !frame?._remoteFleetPayloadBlob) {
|
|
13848
|
+
return;
|
|
13849
|
+
}
|
|
13850
|
+
|
|
13851
|
+
if (!(session.latestBinaryFrames instanceof Map)) {
|
|
13852
|
+
session.latestBinaryFrames = new Map();
|
|
13853
|
+
}
|
|
13854
|
+
|
|
13855
|
+
pruneRemoteFleetBinaryFrameCache(session);
|
|
13856
|
+
session.latestBinaryFrames.set(deviceId, {
|
|
13857
|
+
seenAt: getRemoteFleetFrameNow(),
|
|
13858
|
+
frame: cloneRemoteFleetFramePatch(frame)
|
|
13859
|
+
});
|
|
13860
|
+
}
|
|
13861
|
+
|
|
13862
|
+
function applyRemoteFleetBinaryFrameCacheToBody(bodyView, session) {
|
|
13863
|
+
if (!bodyView || !(session?.latestBinaryFrames instanceof Map) || session.latestBinaryFrames.size === 0) {
|
|
13864
|
+
return 0;
|
|
13865
|
+
}
|
|
13866
|
+
|
|
13867
|
+
pruneRemoteFleetBinaryFrameCache(session);
|
|
13868
|
+
const patches = [];
|
|
13869
|
+
for (const entry of session.latestBinaryFrames.values()) {
|
|
13870
|
+
if (entry?.frame) {
|
|
13871
|
+
patches.push(cloneRemoteFleetFramePatch(entry.frame));
|
|
13872
|
+
}
|
|
13873
|
+
}
|
|
13874
|
+
|
|
13875
|
+
return patches.length > 0
|
|
13876
|
+
? applyRemoteFleetFramePatches(bodyView, patches)
|
|
13877
|
+
: 0;
|
|
13878
|
+
}
|
|
13879
|
+
|
|
13825
13880
|
function refreshRemoteFleetBinaryFrameSubscription(session, force = false) {
|
|
13826
13881
|
if (!session?.ws || session.ws.readyState !== WebSocket.OPEN) {
|
|
13827
13882
|
return false;
|
|
@@ -13877,7 +13932,11 @@
|
|
|
13877
13932
|
refreshRemoteFleetBinaryFrameSubscription(session);
|
|
13878
13933
|
return true;
|
|
13879
13934
|
}
|
|
13935
|
+
if (session.wsOpening === true) {
|
|
13936
|
+
return true;
|
|
13937
|
+
}
|
|
13880
13938
|
|
|
13939
|
+
session.wsOpening = true;
|
|
13881
13940
|
try {
|
|
13882
13941
|
const status = await getRemoteFleetBridgeStatusForFrames();
|
|
13883
13942
|
const wsUrl = buildRemoteFleetBinaryFrameWsUrl(status);
|
|
@@ -13891,6 +13950,7 @@
|
|
|
13891
13950
|
session.subscriptionKey = '';
|
|
13892
13951
|
ws.binaryType = 'arraybuffer';
|
|
13893
13952
|
ws.onopen = () => {
|
|
13953
|
+
session.wsOpening = false;
|
|
13894
13954
|
session.wsOpenedAt = getRemoteFleetFrameNow();
|
|
13895
13955
|
window.RuntimeTrace?.emit?.('remote.frame.wsOpen', { nodeId: session.nodeId });
|
|
13896
13956
|
refreshRemoteFleetBinaryFrameSubscription(session, true);
|
|
@@ -13922,6 +13982,7 @@
|
|
|
13922
13982
|
let applied = 0;
|
|
13923
13983
|
const frameAt = getRemoteFleetFrameNow();
|
|
13924
13984
|
session.lastBinaryFrameAt = frameAt;
|
|
13985
|
+
rememberRemoteFleetBinaryFrame(session, frame);
|
|
13925
13986
|
session.bodies.forEach(body => {
|
|
13926
13987
|
if (document.body.contains(body)) {
|
|
13927
13988
|
const bodyApplied = applyRemoteFleetFramePatches(body, [frame]);
|
|
@@ -13975,6 +14036,7 @@
|
|
|
13975
14036
|
});
|
|
13976
14037
|
};
|
|
13977
14038
|
ws.onclose = () => {
|
|
14039
|
+
session.wsOpening = false;
|
|
13978
14040
|
if (session.ws === ws) {
|
|
13979
14041
|
session.ws = null;
|
|
13980
14042
|
}
|
|
@@ -13990,6 +14052,7 @@
|
|
|
13990
14052
|
};
|
|
13991
14053
|
return true;
|
|
13992
14054
|
} catch (error) {
|
|
14055
|
+
session.wsOpening = false;
|
|
13993
14056
|
window.RuntimeTrace?.emit?.('remote.frame.wsOpenFailed', {
|
|
13994
14057
|
nodeId: session.nodeId,
|
|
13995
14058
|
error: error?.message || String(error || '')
|
|
@@ -14014,6 +14077,7 @@
|
|
|
14014
14077
|
reconnectTimer: null,
|
|
14015
14078
|
subscriptionTimer: null,
|
|
14016
14079
|
subscriptionKey: '',
|
|
14080
|
+
latestBinaryFrames: new Map(),
|
|
14017
14081
|
controlSessions: new Set(),
|
|
14018
14082
|
getDeviceIds: null
|
|
14019
14083
|
};
|
|
@@ -14031,6 +14095,7 @@
|
|
|
14031
14095
|
mode: String(options.mode || 'remote-fast')
|
|
14032
14096
|
};
|
|
14033
14097
|
bodyView._remoteFleetBinaryFrameSession = session;
|
|
14098
|
+
applyRemoteFleetBinaryFrameCacheToBody(bodyView, session);
|
|
14034
14099
|
openRemoteFleetBinaryFrameSocket(session).catch(() => undefined);
|
|
14035
14100
|
return true;
|
|
14036
14101
|
}
|
|
@@ -16043,7 +16108,7 @@
|
|
|
16043
16108
|
|
|
16044
16109
|
function renderRemoteFleetDevice(bodyView, nodeModel) {
|
|
16045
16110
|
if (!bodyView) return;
|
|
16046
|
-
clearRemoteFleetTimers(bodyView);
|
|
16111
|
+
clearRemoteFleetTimers(bodyView, { keepBinaryFrameSocket: true });
|
|
16047
16112
|
|
|
16048
16113
|
const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
|
|
16049
16114
|
const device = parseRemoteFleetPinnedDevice(nodeModel);
|
|
@@ -16541,7 +16606,7 @@
|
|
|
16541
16606
|
|
|
16542
16607
|
function renderRemoteFleetMonitor(bodyView, nodeModel) {
|
|
16543
16608
|
if (!bodyView) return;
|
|
16544
|
-
clearRemoteFleetTimers(bodyView);
|
|
16609
|
+
clearRemoteFleetTimers(bodyView, { keepBinaryFrameSocket: true });
|
|
16545
16610
|
|
|
16546
16611
|
const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
|
|
16547
16612
|
const searchState = bodyView.dataset.remoteFleetSearch || '';
|
|
@@ -18038,11 +18103,14 @@
|
|
|
18038
18103
|
clearRemoteFleetTimers(bodyView);
|
|
18039
18104
|
}
|
|
18040
18105
|
}, REMOTE_FLEET_LIVE_REFRESH_MS);
|
|
18041
|
-
} else
|
|
18042
|
-
|
|
18043
|
-
|
|
18044
|
-
|
|
18045
|
-
|
|
18106
|
+
} else {
|
|
18107
|
+
releaseRemoteFleetBinaryFrameSocket(bodyView);
|
|
18108
|
+
if (autoMonitorState && hasMonitorTargets) {
|
|
18109
|
+
startRemoteFleetFrameLoop(bodyView, REMOTE_FLEET_THUMBNAIL_FRAME_REFRESH_MS, () => refreshRemoteFleetVisibleFrames(true));
|
|
18110
|
+
startRemoteFleetMonitorRefreshTimer(REMOTE_FLEET_MONITOR_REFRESH_MS, 'visible-devices');
|
|
18111
|
+
} else if (autoMonitorState) {
|
|
18112
|
+
startRemoteFleetMonitorRefreshTimer(REMOTE_FLEET_EMPTY_MONITOR_REFRESH_MS, 'empty-discovery');
|
|
18113
|
+
}
|
|
18046
18114
|
}
|
|
18047
18115
|
}
|
|
18048
18116
|
|
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=
|
|
11
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=
|
|
10
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260617-mdm-ws-rerender-v580" />
|
|
11
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260617-mdm-ws-rerender-v580" />
|
|
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 = '
|
|
582
|
+
const scriptVersion = '20260617-mdm-ws-rerender-v580';
|
|
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": "caOR4cJE",
|
|
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-ct4yGB6E/ViQSpNNn3fHtt3v+usCW9LYQEbpOmzuRdk=",
|
|
90
90
|
"url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
@@ -834,7 +834,7 @@
|
|
|
834
834
|
"url": "image-manifest.json"
|
|
835
835
|
},
|
|
836
836
|
{
|
|
837
|
-
"hash": "sha256-
|
|
837
|
+
"hash": "sha256-zI55TuKnPpHEJMEolp25Zk/P6dkZEOtbMSHObMgR84A=",
|
|
838
838
|
"url": "index.html"
|
|
839
839
|
},
|
|
840
840
|
{
|