@mindexec/cli 0.2.177 → 0.2.179

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.177",
3
+ "version": "0.2.179",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -185,6 +185,28 @@ async function main() {
185
185
  assert.equal(frame.metadata.mimeType, 'image/png');
186
186
  assert.ok(frame.payload.length > 0, 'payload should be non-empty');
187
187
 
188
+ const afterFirstAutoStart = await fetchJson(`${bridge.baseUrl}/api/remote/devices`);
189
+ const firstDeviceState = afterFirstAutoStart.payload?.devices?.find(item => item.deviceId === device.deviceId);
190
+ assert.equal(firstDeviceState?.activeLiveStream?.active, true, 'auto-start should mark the synthetic device live');
191
+ assert.equal(firstDeviceState?.counters?.liveStreamsStarted, 1, 'first subscribe should start one live stream');
192
+
193
+ ws.send(JSON.stringify({
194
+ type: 'subscribe',
195
+ deviceIds: [device.deviceId],
196
+ autoStartLive: true,
197
+ fps: 12,
198
+ maxWidth: 960,
199
+ maxHeight: 540,
200
+ quality: 60
201
+ }));
202
+ await wait(120);
203
+ const afterDuplicateSubscribe = await fetchJson(`${bridge.baseUrl}/api/remote/devices`);
204
+ const duplicateDeviceState = afterDuplicateSubscribe.payload?.devices?.find(item => item.deviceId === device.deviceId);
205
+ assert.equal(
206
+ duplicateDeviceState?.counters?.liveStreamsStarted,
207
+ 1,
208
+ 'duplicate keep-live subscribe must not restart a fresh live stream');
209
+
188
210
  const frameStatus = await fetchJson(`${bridge.baseUrl}/api/status?remoteFrames=ws`);
189
211
  assert.equal(frameStatus.ok, true);
190
212
  assert.ok(frameStatus.payload?.remoteFrameWs?.clientCount >= 1, JSON.stringify(frameStatus.payload?.remoteFrameWs));
package/server.js CHANGED
@@ -2185,6 +2185,7 @@ const REMOTE_FRAME_WS_DEFAULT_FPS = 12;
2185
2185
  const REMOTE_FRAME_WS_DEFAULT_MAX_WIDTH = 960;
2186
2186
  const REMOTE_FRAME_WS_DEFAULT_MAX_HEIGHT = 540;
2187
2187
  const REMOTE_FRAME_WS_DEFAULT_QUALITY = 60;
2188
+ const REMOTE_FRAME_WS_LIVE_STALE_RESTART_MS = 6000;
2188
2189
 
2189
2190
  httpServer.on('upgrade', (req, socket, head) => {
2190
2191
  try {
@@ -2327,6 +2328,7 @@ function maybeAutoStartRemoteFrameLiveStreams(ws, deviceIds = []) {
2327
2328
  const lookup = getRemoteFrameWsDeviceLookup();
2328
2329
  const started = [];
2329
2330
  const skipped = [];
2331
+ const nowMs = Date.now();
2330
2332
  for (const deviceId of deviceIds.slice(0, REMOTE_FRAME_WS_AUTO_START_LIMIT)) {
2331
2333
  const device = lookup.get(String(deviceId || '').trim());
2332
2334
  if (!device?.connected) {
@@ -2334,7 +2336,24 @@ function maybeAutoStartRemoteFrameLiveStreams(ws, deviceIds = []) {
2334
2336
  continue;
2335
2337
  }
2336
2338
 
2337
- if (device.liveStreamActive === true) {
2339
+ const activeLiveStream = device.activeLiveStream && typeof device.activeLiveStream === 'object'
2340
+ ? device.activeLiveStream
2341
+ : null;
2342
+ const liveActive = device.liveStreamActive === true || activeLiveStream?.active === true;
2343
+ const liveStartedAtMs = Date.parse(activeLiveStream?.startedAt || device.liveStreamStartedAt || '');
2344
+ const liveLastFrameAtMs = Date.parse(
2345
+ activeLiveStream?.lastFrameAt
2346
+ || device.liveStreamLastFrameAt
2347
+ || device.latestLiveFrame?.receivedAt
2348
+ || device.latestLiveFrame?.capturedAt
2349
+ || '');
2350
+ const liveHasStartupGrace = liveActive
2351
+ && Number.isFinite(liveStartedAtMs)
2352
+ && nowMs - liveStartedAtMs < REMOTE_FRAME_WS_LIVE_STALE_RESTART_MS;
2353
+ const liveIsFresh = liveActive
2354
+ && Number.isFinite(liveLastFrameAtMs)
2355
+ && nowMs - liveLastFrameAtMs < REMOTE_FRAME_WS_LIVE_STALE_RESTART_MS;
2356
+ if (liveActive && (liveIsFresh || liveHasStartupGrace)) {
2338
2357
  skipped.push({ deviceId, reason: 'already-live' });
2339
2358
  continue;
2340
2359
  }
@@ -12591,6 +12591,8 @@
12591
12591
 
12592
12592
  handle.dataset.nodeId = nodeId;
12593
12593
  handle.dataset.corner = handleInfo.corner;
12594
+ handle.dataset.remoteFleetResizeHandle = 'true';
12595
+ handle.draggable = false;
12594
12596
  handle.style.cursor = getRemoteFleetResizeCursor(handleInfo.corner);
12595
12597
  });
12596
12598
  }
@@ -13583,6 +13585,7 @@
13583
13585
  const REMOTE_FLEET_BINARY_FRAME_MAX_DECODE_IN_FLIGHT = 1;
13584
13586
  const REMOTE_FLEET_BINARY_FRAME_WS_RECONNECT_MS = 1500;
13585
13587
  const REMOTE_FLEET_BINARY_FRAME_SUBSCRIBE_MS = 1000;
13588
+ const REMOTE_FLEET_BINARY_FRAME_AUTOSTART_REFRESH_MS = 2500;
13586
13589
  const REMOTE_FLEET_BINARY_FRAME_STALE_FALLBACK_MS = 1400;
13587
13590
  const REMOTE_FLEET_BINARY_FRAME_CONNECT_GRACE_MS = 1600;
13588
13591
  const REMOTE_FLEET_BINARY_FRAME_CACHE_MS = 10000;
@@ -14346,11 +14349,19 @@
14346
14349
  String(liveOptions.mode || '')
14347
14350
  ].join('|');
14348
14351
  const key = `${deviceIds.join('\n')}::${optionKey}`;
14349
- if (!force && session.subscriptionKey === key) {
14352
+ const now = getRemoteFleetFrameNow();
14353
+ const shouldRefreshAutoStart =
14354
+ liveOptions.autoStartLive === true
14355
+ && deviceIds.length > 0
14356
+ && now - Number(session.lastAutoStartSubscribeAt || 0) >= REMOTE_FLEET_BINARY_FRAME_AUTOSTART_REFRESH_MS;
14357
+ if (!force && session.subscriptionKey === key && !shouldRefreshAutoStart) {
14350
14358
  return true;
14351
14359
  }
14352
14360
 
14353
14361
  session.subscriptionKey = key;
14362
+ if (liveOptions.autoStartLive === true) {
14363
+ session.lastAutoStartSubscribeAt = now;
14364
+ }
14354
14365
  session.ws.send(JSON.stringify({
14355
14366
  type: 'subscribe',
14356
14367
  nodeId: session.nodeId,
@@ -22302,11 +22313,12 @@
22302
22313
  const handle = document.createElement('div');
22303
22314
  const remoteFleetClass = remoteFleetSurface ? ' remote-fleet-resize-handle' : '';
22304
22315
  handle.className = `resize-handle css3d-resize-handle${remoteFleetClass} ${zone.className}`.trim();
22305
- handle.dataset.nodeId = nodeModel.id;
22316
+ handle.dataset.nodeId = String(nodeModel?.id ?? nodeModel?.Id ?? '').trim();
22306
22317
  handle.dataset.corner = zone.corner;
22307
22318
  if (remoteFleetSurface) {
22308
22319
  handle.dataset.remoteFleetResizeHandle = 'true';
22309
22320
  }
22321
+ handle.draggable = false;
22310
22322
  handle.style.cssText = `
22311
22323
  position: absolute;
22312
22324
  left: auto;
@@ -21,6 +21,8 @@
21
21
  const CSV_TABLE_MIN_WIDTH = 320;
22
22
  const CSV_TABLE_MIN_HEIGHT = 180;
23
23
  const REMOTE_FLEET_SEMANTIC_TYPE = 'RemoteFleetMonitor';
24
+ const REMOTE_FLEET_DISPLAY_NAME = 'Multi Desktop Monitor';
25
+ const REMOTE_FLEET_LEGACY_DISPLAY_NAME = 'Remote Fleet Monitor';
24
26
  const REMOTE_FLEET_MONITOR_MIN_WIDTH = 520;
25
27
  const REMOTE_FLEET_MONITOR_MIN_HEIGHT = 320;
26
28
 
@@ -28,13 +30,25 @@
28
30
  return nodeModel?.metadata || nodeModel?.Metadata || null;
29
31
  }
30
32
 
33
+ function getNodeContentType(nodeModel) {
34
+ return String(nodeModel?.contentType ?? nodeModel?.ContentType ?? '').trim().toLowerCase();
35
+ }
36
+
31
37
  function isRemoteFleetMonitorNodeModel(nodeModel) {
32
38
  const metadata = getNodeMetadata(nodeModel);
33
- return String(metadata?.SemanticType || metadata?.semanticType || '').trim() === REMOTE_FLEET_SEMANTIC_TYPE;
39
+ const semanticType = String(metadata?.SemanticType || metadata?.semanticType || '').trim();
40
+ if (semanticType === REMOTE_FLEET_SEMANTIC_TYPE) {
41
+ return true;
42
+ }
43
+
44
+ const contentType = getNodeContentType(nodeModel);
45
+ const title = String(nodeModel?.prompt ?? nodeModel?.Prompt ?? '').trim();
46
+ return contentType === 'templatelauncher'
47
+ && (title === REMOTE_FLEET_DISPLAY_NAME || title === REMOTE_FLEET_LEGACY_DISPLAY_NAME);
34
48
  }
35
49
 
36
50
  function isCsvTableNodeModel(nodeModel) {
37
- return String(nodeModel?.contentType ?? nodeModel?.ContentType ?? '').trim().toLowerCase() === CSV_TABLE_CONTENT_TYPE;
51
+ return getNodeContentType(nodeModel) === CSV_TABLE_CONTENT_TYPE;
38
52
  }
39
53
 
40
54
  function clampRemoteFleetResizeDimensions(
@@ -1036,9 +1050,10 @@
1036
1050
  module.resizingNodeId = nodeId;
1037
1051
  module.resizeCorner = corner; // TL, TR, BL, BR
1038
1052
  const cssRendererEnabled = module?.renderDebugFlags?.enableCss3d !== false;
1053
+ const isCssOnlyInteractiveSurface = isRemoteFleetMonitorNodeModel(nodeEntry.model);
1039
1054
  const shouldResizeCssObject = !!nodeEntry.cssObject &&
1040
1055
  cssRendererEnabled &&
1041
- (nodeEntry.currentType === 'CSS' || nodeEntry.cssObject.visible === true);
1056
+ (isCssOnlyInteractiveSurface || nodeEntry.currentType === 'CSS' || nodeEntry.cssObject.visible === true);
1042
1057
  const activeResizeType = shouldResizeCssObject ? 'CSS' : 'GL';
1043
1058
  module.resizeNodeObject = activeResizeType === 'CSS' ? nodeEntry.cssObject : nodeEntry.glObject;
1044
1059
  if (!module.resizeNodeObject && nodeEntry.cssObject) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mainAssemblyName": "MindExecution.Web",
3
3
  "resources": {
4
- "hash": "sha256-J42cMyhEPDUI5FMrpZaxLnKM8dAvsG124jdCZIbo40o=",
4
+ "hash": "sha256-mXalTzongUarYIKdGkRZyBj737QEkHT+ja+nioqtve4=",
5
5
  "fingerprinting": {
6
6
  "Google.Protobuf.9h59ukbel7.dll": "Google.Protobuf.dll",
7
7
  "Markdig.d1j7v41cl1.dll": "Markdig.dll",
@@ -132,7 +132,7 @@
132
132
  "MindExecution.Plugins.PlanMaster.cbsobbckk1.dll": "MindExecution.Plugins.PlanMaster.dll",
133
133
  "MindExecution.Plugins.YouTube.vlwj5eytol.dll": "MindExecution.Plugins.YouTube.dll",
134
134
  "MindExecution.Shared.bi3agtnwsf.dll": "MindExecution.Shared.dll",
135
- "MindExecution.Web.nev8fm9057.dll": "MindExecution.Web.dll",
135
+ "MindExecution.Web.ok8fq2ssq9.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",
@@ -284,7 +284,7 @@
284
284
  "MindExecution.Plugins.Concept.u70zp9qbvo.dll": "sha256-2shsnRsIbEhl8nk8mJIzUgV/oXmvxNKoe/xcxaZ3s0c=",
285
285
  "MindExecution.Plugins.PlanMaster.cbsobbckk1.dll": "sha256-WFyqQ9i6a7lHkp1gJEF8/ZYcRaGkqf64FmlLPD3AJZ8=",
286
286
  "MindExecution.Shared.bi3agtnwsf.dll": "sha256-vbsv8/SRhBHipHJYwc1X4lnat8FSgTR2OIP+Nfdx/4Q=",
287
- "MindExecution.Web.nev8fm9057.dll": "sha256-AZhG5e+nE5LC2BKQHBTDdqUUdHddruUQp4hR/WvOKUo="
287
+ "MindExecution.Web.ok8fq2ssq9.dll": "sha256-KDud/vhCxgleWllp53ps36qbAtqjOvzYuXVpdZv1ybQ="
288
288
  },
289
289
  "lazyAssembly": {
290
290
  "MindExecution.Plugins.Admin.kylq0fxv8c.dll": "sha256-VKLartecp6S319WtR/dhvYXB4gCAkjaYx/mnIYe2VmY=",
@@ -7,8 +7,8 @@
7
7
  <title>MindExec | Business Execution OS for solo builders</title>
8
8
  <meta name="description" content="MindExec is an AI business execution OS for solo builders who want to turn notes, research, assets, and repeatable execution Skills into revenue-producing work." />
9
9
  <base href="/" />
10
- <link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260617-smart-managed-margin-v606" />
11
- <link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260617-smart-managed-margin-v606" />
10
+ <link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260617-mdm-resize-reconnect-v607" />
11
+ <link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260617-mdm-resize-reconnect-v607" />
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-smart-managed-margin-v606';
582
+ const scriptVersion = '20260617-mdm-resize-reconnect-v607';
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": "TyBXbpiz",
2
+ "version": "PM6aErcF",
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-WpXggA1xE6EanQSVrS+OrYIqTiqlGtC1P8MXgK1bUzM=",
89
+ "hash": "sha256-gBI36z4Y7+AjUkFA/hGi8vAMGy8n+P5UbYry3YiMhCw=",
90
90
  "url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
91
91
  },
92
92
  {
@@ -146,7 +146,7 @@
146
146
  "url": "_content/MindExecution.Shared/js/mind-map-object-manager.js.backup"
147
147
  },
148
148
  {
149
- "hash": "sha256-CbH7IH0gNoo/R/o1pBkuBcU753K+twxK2mCqkjO6zjI=",
149
+ "hash": "sha256-U1ZZffxZdhXwwCRY4VLUKXOFUMGllD7/Wsno/iXNC2E=",
150
150
  "url": "_content/MindExecution.Shared/js/mind-map-pipeline.js"
151
151
  },
152
152
  {
@@ -446,8 +446,8 @@
446
446
  "url": "_framework/MindExecution.Shared.bi3agtnwsf.dll"
447
447
  },
448
448
  {
449
- "hash": "sha256-AZhG5e+nE5LC2BKQHBTDdqUUdHddruUQp4hR/WvOKUo=",
450
- "url": "_framework/MindExecution.Web.nev8fm9057.dll"
449
+ "hash": "sha256-KDud/vhCxgleWllp53ps36qbAtqjOvzYuXVpdZv1ybQ=",
450
+ "url": "_framework/MindExecution.Web.ok8fq2ssq9.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-VzTy0MB++MzxH8769g4kft9KyFol6O8mnCgOtY9xtn0=",
773
+ "hash": "sha256-Wx/uNtUK80xm/cJaYZuB+GHTGCz1Vxzx0065VwVwxEw=",
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-zsAmcmUA5PZaoEXBiRqzPPmopDpFc+Hkz2Lq+vMpk3U=",
837
+ "hash": "sha256-En9zl1UbLcPA629rVN6zjIjavRORX4w86sx+o0/XEuQ=",
838
838
  "url": "index.html"
839
839
  },
840
840
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: TyBXbpiz */
1
+ /* Manifest version: PM6aErcF */
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