@mindexec/cli 0.2.158 → 0.2.159

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.158",
3
+ "version": "0.2.159",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -1043,6 +1043,7 @@ try {
1043
1043
  binaryDrawCalls.some(call => call.op === 'clearRect' || call.op === 'fillRect'),
1044
1044
  false,
1045
1045
  'binary Blob frame paint must not clear/fill the canvas before drawing');
1046
+ const binaryCanvasBeforeRerender = binaryCanvas;
1046
1047
 
1047
1048
  const liveOverlayCard = document.createElement('div');
1048
1049
  liveOverlayCard.dataset.nodeId = 'remote-fleet-render-smoke';
@@ -1105,7 +1106,12 @@ try {
1105
1106
  ?.querySelector('[data-remote-fleet-device-preview="tile"]');
1106
1107
  assert.ok(rerenderedPatchPreview);
1107
1108
  assert.equal(rerenderedPatchPreview.dataset.remoteFleetFrameSeq, String(websocketFrameSeq));
1108
- assert.equal(rerenderedPatchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]')?.style.display, 'block');
1109
+ const rerenderedPatchCanvas = rerenderedPatchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]');
1110
+ assert.equal(rerenderedPatchCanvas?.style.display, 'block');
1111
+ assert.equal(
1112
+ rerenderedPatchCanvas,
1113
+ binaryCanvasBeforeRerender,
1114
+ 'MDM rerender should reuse the already-painted canvas instead of flashing a blank replacement');
1109
1115
 
1110
1116
  const otherBoardNodeId = 'remote-fleet-render-smoke-other-board';
1111
1117
  const { nodeShell: otherBoardShell, bodyView: otherBoardBodyView } =
@@ -1434,6 +1440,18 @@ try {
1434
1440
  assert.ok(deviceBody.querySelector('[data-remote-fleet-action="task-device"]'));
1435
1441
  assert.ok(deviceBody.textContent.includes('Task timed out waiting for the agent response.'));
1436
1442
  assert.ok(deviceBody.textContent.includes(focusedDevice.DeviceId));
1443
+ const controlCanvasBeforeRerender = deviceControlCanvas;
1444
+ manager.renderRemoteFleetDeviceForTest(deviceBody, buildDeviceNode(focusedDevice, hub.getStatus()));
1445
+ await wait(30);
1446
+ const controlCanvasAfterRerender = deviceBody.querySelector('[data-remote-fleet-control-node-canvas="true"]');
1447
+ assert.equal(
1448
+ controlCanvasAfterRerender,
1449
+ controlCanvasBeforeRerender,
1450
+ 'RemoteFleetDevice rerender should reuse the already-painted control canvas instead of flashing black');
1451
+ assert.equal(
1452
+ deviceBody.querySelector('[data-remote-fleet-control-node-placeholder="true"]'),
1453
+ null,
1454
+ 'RemoteFleetDevice rerender should not cover a restored control canvas with a waiting placeholder');
1437
1455
 
1438
1456
  nodeShell.remove();
1439
1457
  emptyShell.remove();
@@ -14842,6 +14842,104 @@
14842
14842
  return canvas;
14843
14843
  }
14844
14844
 
14845
+ function collectRemoteFleetPreviewFrameSurfaces(root) {
14846
+ const surfaces = new Map();
14847
+ if (!root?.querySelectorAll) {
14848
+ return surfaces;
14849
+ }
14850
+
14851
+ root.querySelectorAll('[data-remote-fleet-device-preview][data-device-id]').forEach(preview => {
14852
+ const deviceId = String(preview.dataset.deviceId || '').trim();
14853
+ if (!deviceId) {
14854
+ return;
14855
+ }
14856
+
14857
+ const canvas = preview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]');
14858
+ const image = preview.querySelector('img[data-remote-fleet-frame-image="true"]');
14859
+ surfaces.set(deviceId, {
14860
+ canvas,
14861
+ image,
14862
+ kind: String(preview.dataset.remoteFleetFrameKind || canvas?.dataset?.remoteFleetFrameKind || image?.dataset?.remoteFleetFrameKind || '').trim().toLowerCase(),
14863
+ seq: Number(preview.dataset.remoteFleetFrameSeq || canvas?.dataset?.remoteFleetFrameSeq || image?.dataset?.remoteFleetFrameSeq || 0) || 0,
14864
+ url: String(preview.dataset.remoteFleetFrameUrl || canvas?.dataset?.remoteFleetFrameUrl || image?.dataset?.remoteFleetFrameUrl || '').trim()
14865
+ });
14866
+ });
14867
+
14868
+ return surfaces;
14869
+ }
14870
+
14871
+ function restoreRemoteFleetPreviewFrameSurface(preview, surfaces, deviceId) {
14872
+ const id = String(deviceId || preview?.dataset?.deviceId || '').trim();
14873
+ const surface = id && surfaces instanceof Map ? surfaces.get(id) : null;
14874
+ if (!preview || !surface) {
14875
+ return false;
14876
+ }
14877
+
14878
+ const existingSeq = Number(surface.seq || 0) || 0;
14879
+ const nextSeq = Number(preview.dataset.remoteFleetFrameSeq || 0) || 0;
14880
+ if (existingSeq <= 0 || (nextSeq > 0 && existingSeq < nextSeq)) {
14881
+ return false;
14882
+ }
14883
+
14884
+ const currentCanvas = preview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]');
14885
+ if (surface.canvas && surface.canvas !== currentCanvas) {
14886
+ currentCanvas?.remove?.();
14887
+ surface.canvas.dataset.remoteFleetFrameKind = surface.kind || preview.dataset.remoteFleetFrameKind || 'live';
14888
+ surface.canvas.dataset.remoteFleetFrameSeq = String(existingSeq);
14889
+ surface.canvas.dataset.remoteFleetFrameUrl = surface.url || '';
14890
+ surface.canvas.style.display = 'block';
14891
+ if (typeof preview.insertBefore === 'function') {
14892
+ preview.insertBefore(surface.canvas, preview.firstChild || null);
14893
+ } else {
14894
+ preview.appendChild?.(surface.canvas);
14895
+ }
14896
+ }
14897
+
14898
+ const currentImage = preview.querySelector('img[data-remote-fleet-frame-image="true"]');
14899
+ if (surface.canvas) {
14900
+ preview.querySelector('[data-remote-fleet-screen-placeholder="true"]')?.remove?.();
14901
+ if (currentImage && currentImage !== surface.image) {
14902
+ currentImage.style.display = 'none';
14903
+ }
14904
+ if (surface.image && surface.image !== currentImage && surface.image.parentElement === preview) {
14905
+ surface.image.style.display = 'none';
14906
+ }
14907
+ } else if (surface.image && surface.image !== currentImage) {
14908
+ currentImage?.remove?.();
14909
+ surface.image.style.display = 'block';
14910
+ if (typeof preview.insertBefore === 'function') {
14911
+ preview.insertBefore(surface.image, preview.firstChild || null);
14912
+ } else {
14913
+ preview.appendChild?.(surface.image);
14914
+ }
14915
+ }
14916
+
14917
+ preview.dataset.remoteFleetFrameKind = surface.kind || preview.dataset.remoteFleetFrameKind || '';
14918
+ preview.dataset.remoteFleetFrameSeq = String(existingSeq);
14919
+ preview.dataset.remoteFleetFrameUrl = surface.url || '';
14920
+ preview.dataset.remoteFleetRestoredFrame = 'true';
14921
+ return true;
14922
+ }
14923
+
14924
+ function collectRemoteFleetControlNodeSurface(root) {
14925
+ const canvas = root?.querySelector?.('canvas[data-remote-fleet-control-node-canvas="true"]');
14926
+ if (!canvas) {
14927
+ return null;
14928
+ }
14929
+
14930
+ return {
14931
+ canvas,
14932
+ kind: String(canvas.dataset.remoteFleetFrameKind || 'live').trim().toLowerCase(),
14933
+ seq: Number(canvas.dataset.remoteFleetFrameSeq || 0) || 0,
14934
+ contentRect: canvas._remoteFleetContentRect || null
14935
+ };
14936
+ }
14937
+
14938
+ function hasRemoteFleetReusableControlSurface(surface) {
14939
+ return !!surface?.canvas
14940
+ && (Number(surface.seq || 0) > 0 || !!surface.contentRect);
14941
+ }
14942
+
14845
14943
  function syncRemoteFleetFrameCanvasSize(canvas) {
14846
14944
  if (!canvas) {
14847
14945
  return null;
@@ -14853,8 +14951,18 @@
14853
14951
  const cssWidth = Math.max(1, Math.round(rect?.width || canvas.clientWidth || 320));
14854
14952
  const cssHeight = Math.max(1, Math.round(rect?.height || canvas.clientHeight || 180));
14855
14953
  const dpr = Math.max(1, Math.min(REMOTE_FLEET_FRAME_CANVAS_MAX_DPR, Number(window.devicePixelRatio || 1) || 1));
14856
- const nextWidth = Math.max(1, Math.round(cssWidth * dpr));
14857
- const nextHeight = Math.max(1, Math.round(cssHeight * dpr));
14954
+ let nextWidth = Math.max(1, Math.round(cssWidth * dpr));
14955
+ let nextHeight = Math.max(1, Math.round(cssHeight * dpr));
14956
+ const currentWidth = Number(canvas.width || 0) || 0;
14957
+ const currentHeight = Number(canvas.height || 0) || 0;
14958
+ const widthDelta = Math.abs(currentWidth - nextWidth);
14959
+ const heightDelta = Math.abs(currentHeight - nextHeight);
14960
+ if (currentWidth > 0 && widthDelta > 0 && widthDelta <= 2) {
14961
+ nextWidth = currentWidth;
14962
+ }
14963
+ if (currentHeight > 0 && heightDelta > 0 && heightDelta <= 2) {
14964
+ nextHeight = currentHeight;
14965
+ }
14858
14966
  if (canvas.width !== nextWidth) {
14859
14967
  canvas.width = nextWidth;
14860
14968
  }
@@ -15970,7 +16078,12 @@
15970
16078
  }
15971
16079
 
15972
16080
  drawRemoteFleetFrameToCanvas(session.canvas, bitmap, 'contain');
16081
+ session.canvas.dataset.remoteFleetFrameKind = String(frame.kind || 'live').toLowerCase();
16082
+ session.canvas.dataset.remoteFleetFrameSeq = String(Number(frame.frameSeq || frame.FrameSeq || 0) || 0);
16083
+ session.canvas.dataset.remoteFleetFrameUrl = String(frame.frameUrl || '');
15973
16084
  session.canvas.style.display = 'block';
16085
+ session.lastControlFrameSeq = Number(frame.frameSeq || frame.FrameSeq || session.lastControlFrameSeq || 0) || 0;
16086
+ session.lastControlFrameAt = Date.now();
15974
16087
  session.placeholder?.remove?.();
15975
16088
  session.placeholder = null;
15976
16089
  if (typeof bitmap.close === 'function') {
@@ -16020,6 +16133,9 @@
16020
16133
  }
16021
16134
 
16022
16135
  drawRemoteFleetFrameToCanvas(session.canvas, bitmap, 'contain');
16136
+ session.canvas.dataset.remoteFleetFrameKind = String(frame.kind || 'live').toLowerCase();
16137
+ session.canvas.dataset.remoteFleetFrameSeq = String(frameSeq || 0);
16138
+ session.canvas.dataset.remoteFleetFrameUrl = String(frame.frameUrl || '');
16023
16139
  session.canvas.style.display = 'block';
16024
16140
  session.lastControlFrameAt = Date.now();
16025
16141
  session.status.textContent = `Control ${REMOTE_FLEET_CONTROL_LIVE_FPS}fps`;
@@ -16971,6 +17087,7 @@
16971
17087
  function renderRemoteFleetDevice(bodyView, nodeModel) {
16972
17088
  if (!bodyView) return;
16973
17089
  clearRemoteFleetTimers(bodyView, { keepBinaryFrameSocket: true });
17090
+ const preservedControlSurface = collectRemoteFleetControlNodeSurface(bodyView);
16974
17091
 
16975
17092
  const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
16976
17093
  const device = parseRemoteFleetPinnedDevice(nodeModel);
@@ -17166,7 +17283,7 @@
17166
17283
  touch-action: none;
17167
17284
  outline: none;
17168
17285
  `;
17169
- const controlCanvas = document.createElement('canvas');
17286
+ const controlCanvas = preservedControlSurface?.canvas || document.createElement('canvas');
17170
17287
  controlCanvas.dataset.remoteFleetControlNodeCanvas = 'true';
17171
17288
  controlCanvas.style.cssText = `
17172
17289
  position: absolute;
@@ -17226,7 +17343,10 @@
17226
17343
  controlOverlay.appendChild(controlDot);
17227
17344
  controlOverlay.appendChild(controlStatus);
17228
17345
  controlStage.appendChild(controlCanvas);
17229
- controlStage.appendChild(controlPlaceholder);
17346
+ const restoredControlSurface = hasRemoteFleetReusableControlSurface(preservedControlSurface);
17347
+ if (!restoredControlSurface) {
17348
+ controlStage.appendChild(controlPlaceholder);
17349
+ }
17230
17350
  controlStage.appendChild(controlOverlay);
17231
17351
  bodyView.appendChild(controlStage);
17232
17352
 
@@ -17238,7 +17358,17 @@
17238
17358
  controlStage,
17239
17359
  controlCanvas,
17240
17360
  controlStatus,
17241
- controlPlaceholder);
17361
+ restoredControlSurface ? null : controlPlaceholder);
17362
+ if (session && restoredControlSurface) {
17363
+ session.lastControlFrameSeq = Number(preservedControlSurface?.seq || session.lastControlFrameSeq || 0) || 0;
17364
+ session.lastControlFrameAt = Date.now();
17365
+ controlStatus.textContent = `Control ${REMOTE_FLEET_CONTROL_LIVE_FPS}fps`;
17366
+ window.RuntimeTrace?.emit?.('remote.control.surfaceRestored', {
17367
+ nodeId,
17368
+ deviceId,
17369
+ seq: session.lastControlFrameSeq
17370
+ });
17371
+ }
17242
17372
  if (session && isRemoteFleetFrameSource(previewSource)) {
17243
17373
  paintRemoteFleetControlFrame(session, {
17244
17374
  deviceId,
@@ -17526,6 +17656,7 @@
17526
17656
  function renderRemoteFleetMonitor(bodyView, nodeModel) {
17527
17657
  if (!bodyView) return;
17528
17658
  clearRemoteFleetTimers(bodyView, { keepBinaryFrameSocket: true });
17659
+ const preservedFrameSurfaces = collectRemoteFleetPreviewFrameSurfaces(bodyView);
17529
17660
 
17530
17661
  const nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '');
17531
17662
  const searchState = bodyView.dataset.remoteFleetSearch || '';
@@ -18080,6 +18211,7 @@
18080
18211
  preview.appendChild(placeholder);
18081
18212
  }
18082
18213
 
18214
+ restoreRemoteFleetPreviewFrameSurface(preview, preservedFrameSurfaces, getRemoteFleetDeviceId(device));
18083
18215
  return preview;
18084
18216
  };
18085
18217
 
@@ -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=20260617-mdm-tab-fast-v591" />
11
- <link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260617-mdm-tab-fast-v591" />
10
+ <link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260617-remote-frame-no-flash-v592" />
11
+ <link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260617-remote-frame-no-flash-v592" />
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 = '20260617-mdm-tab-fast-v591';
582
+ const scriptVersion = '20260617-remote-frame-no-flash-v592';
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": "2guH6APA",
2
+ "version": "ikaqQxI3",
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-piKsRYcnSTaqs+vd7QATTt7cGBN5hHPbY6P8Xjl2J6k=",
89
+ "hash": "sha256-yUuxzH9Fpd62pPLMU5n0HuYjsJhKvC82LO5X5Uu/1gg=",
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-hq0qYVhXCK09hkKo9EkKj84gbxqFCuf2l4XAWk1gfL0=",
837
+ "hash": "sha256-8VAYYW89mBjF45WS2vA1+Hssmo6S30PB8AW03niSE2Q=",
838
838
  "url": "index.html"
839
839
  },
840
840
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: 2guH6APA */
1
+ /* Manifest version: ikaqQxI3 */
2
2
  // Hosted deployments should prefer the network over stale offline caches.
3
3
  // This service worker immediately clears old Blazor offline caches and unregisters itself.
4
4