@mindexec/cli 0.2.151 → 0.2.153

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.
@@ -13494,6 +13494,8 @@
13494
13494
  const REMOTE_FLEET_LIVE_FRAME_REFRESH_MS = Math.round(1000 / REMOTE_FLEET_MONITOR_LIVE_FPS);
13495
13495
  const REMOTE_FLEET_CONTROL_LIVE_FPS = 20;
13496
13496
  const REMOTE_FLEET_CONTROL_FRAME_REFRESH_MS = Math.round(1000 / REMOTE_FLEET_CONTROL_LIVE_FPS);
13497
+ const REMOTE_FLEET_CONTROL_INPUT_MOVE_MS = 16;
13498
+ const REMOTE_FLEET_CONTROL_INPUT_QUEUE_LIMIT = 64;
13497
13499
  const REMOTE_FLEET_THUMBNAIL_FRAME_REFRESH_MS = 2000;
13498
13500
  const REMOTE_FLEET_FRAME_CANVAS_MAX_DPR = 2;
13499
13501
  const REMOTE_FLEET_FRAME_BLOB_CACHE_MS = 10000;
@@ -13829,6 +13831,22 @@
13829
13831
  return url.toString();
13830
13832
  }
13831
13833
 
13834
+ function buildRemoteFleetInputWsUrl(status) {
13835
+ const baseUrl = String(status?.__remoteFleetBridgeBaseUrl || window.location?.origin || '').trim();
13836
+ const path = String(status?.remoteInputWsPath || '/api/remote/input/ws').trim() || '/api/remote/input/ws';
13837
+ if (!baseUrl) {
13838
+ return '';
13839
+ }
13840
+
13841
+ const url = new URL(path, baseUrl);
13842
+ url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
13843
+ const bridgeToken = String(status?.bridgeToken || '').trim();
13844
+ if (bridgeToken) {
13845
+ url.searchParams.set('token', bridgeToken);
13846
+ }
13847
+ return url.toString();
13848
+ }
13849
+
13832
13850
  async function parseRemoteFleetBinaryFrameMessage(data) {
13833
13851
  let buffer = null;
13834
13852
  if (data instanceof ArrayBuffer) {
@@ -15729,6 +15747,8 @@
15729
15747
  activeRemoteFleetControlPopup = null;
15730
15748
  session.active = false;
15731
15749
  detachRemoteFleetControlBinaryFrameSession(session);
15750
+ closeRemoteFleetControlInputSocket(session, 'close');
15751
+ session.inputCleanup?.();
15732
15752
  if (session.timer) {
15733
15753
  clearTimeout(session.timer);
15734
15754
  session.timer = null;
@@ -15910,34 +15930,268 @@
15910
15930
  }
15911
15931
  }
15912
15932
 
15913
- function sendRemoteFleetControlInput(session, payload, throttleMove = false) {
15914
- if (!session?.active || !payload?.type) {
15933
+ function closeRemoteFleetControlInputSocket(session, reason = 'close') {
15934
+ if (!session) {
15915
15935
  return;
15916
15936
  }
15917
15937
 
15918
- const send = next => {
15919
- if (!session.active) {
15920
- return;
15938
+ if (session.inputWsOpenTimer) {
15939
+ clearTimeout(session.inputWsOpenTimer);
15940
+ session.inputWsOpenTimer = null;
15941
+ }
15942
+
15943
+ const ws = session.inputWs;
15944
+ session.inputWs = null;
15945
+ session.inputWsConnecting = false;
15946
+ if (ws && ws.readyState !== 3) {
15947
+ try {
15948
+ ws.close();
15949
+ } catch {
15950
+ // Best-effort input socket cleanup.
15921
15951
  }
15922
- invokeDotNetAsync('SendRemoteFleetInputFromJs', session.nodeId, session.deviceId, {
15923
- ...next,
15924
- controlLeaseId: session.controlLeaseId,
15925
- issuedAt: new Date().toISOString()
15926
- }).catch(error => {
15952
+ }
15953
+
15954
+ if (reason === 'close') {
15955
+ session.inputQueue = [];
15956
+ }
15957
+ }
15958
+
15959
+ function createRemoteFleetControlInput(session, payload) {
15960
+ return {
15961
+ ...payload,
15962
+ controlLeaseId: session.controlLeaseId,
15963
+ issuedAt: new Date().toISOString()
15964
+ };
15965
+ }
15966
+
15967
+ function sendRemoteFleetControlInputFallback(session, input) {
15968
+ if (!session?.active || !input?.type) {
15969
+ return;
15970
+ }
15971
+
15972
+ invokeDotNetAsync('SendRemoteFleetInputFromJs', session.nodeId, session.deviceId, {
15973
+ ...input,
15974
+ controlLeaseId: input.controlLeaseId || session.controlLeaseId,
15975
+ issuedAt: input.issuedAt || new Date().toISOString()
15976
+ }).catch(error => {
15977
+ if (session.active) {
15927
15978
  session.status.textContent = error?.message || 'Input failed';
15979
+ }
15980
+ });
15981
+ }
15982
+
15983
+ function drainRemoteFleetControlInputQueueToFallback(session) {
15984
+ if (!session?.inputQueue?.length) {
15985
+ return;
15986
+ }
15987
+
15988
+ const queued = session.inputQueue.splice(0);
15989
+ queued.forEach(envelope => sendRemoteFleetControlInputFallback(session, envelope.input));
15990
+ }
15991
+
15992
+ function enqueueRemoteFleetControlInput(session, envelope) {
15993
+ if (!session) {
15994
+ return;
15995
+ }
15996
+
15997
+ if (!Array.isArray(session.inputQueue)) {
15998
+ session.inputQueue = [];
15999
+ }
16000
+
16001
+ const inputType = String(envelope?.input?.type || '').toLowerCase();
16002
+ if (inputType === 'pointermove') {
16003
+ for (let i = session.inputQueue.length - 1; i >= 0; i -= 1) {
16004
+ if (String(session.inputQueue[i]?.input?.type || '').toLowerCase() === 'pointermove') {
16005
+ session.inputQueue.splice(i, 1);
16006
+ }
16007
+ }
16008
+ }
16009
+
16010
+ session.inputQueue.push(envelope);
16011
+ while (session.inputQueue.length > REMOTE_FLEET_CONTROL_INPUT_QUEUE_LIMIT) {
16012
+ const moveIndex = session.inputQueue.findIndex(item =>
16013
+ String(item?.input?.type || '').toLowerCase() === 'pointermove');
16014
+ session.inputQueue.splice(moveIndex >= 0 ? moveIndex : 0, 1);
16015
+ }
16016
+ }
16017
+
16018
+ function flushRemoteFleetControlInputQueue(session) {
16019
+ const ws = session?.inputWs;
16020
+ if (!session?.active || !ws || ws.readyState !== 1 || !session.inputQueue?.length) {
16021
+ return;
16022
+ }
16023
+
16024
+ const queued = session.inputQueue.splice(0);
16025
+ for (const envelope of queued) {
16026
+ if (!sendRemoteFleetControlInputEnvelope(session, envelope)) {
16027
+ enqueueRemoteFleetControlInput(session, envelope);
16028
+ break;
16029
+ }
16030
+ }
16031
+ }
16032
+
16033
+ function sendRemoteFleetControlInputEnvelope(session, envelope) {
16034
+ const ws = session?.inputWs;
16035
+ if (!session?.active || !ws || ws.readyState !== 1) {
16036
+ return false;
16037
+ }
16038
+
16039
+ const inputType = String(envelope?.input?.type || '').toLowerCase();
16040
+ if (inputType === 'pointermove' && Number(ws.bufferedAmount || 0) > 256 * 1024) {
16041
+ window.RuntimeTrace?.emit?.('remote.control.input.drop', {
16042
+ reason: 'ws-buffered',
16043
+ deviceId: session.deviceId,
16044
+ bufferedAmount: Number(ws.bufferedAmount || 0)
15928
16045
  });
16046
+ return true;
16047
+ }
16048
+
16049
+ try {
16050
+ ws.send(JSON.stringify(envelope));
16051
+ return true;
16052
+ } catch {
16053
+ return false;
16054
+ }
16055
+ }
16056
+
16057
+ function handleRemoteFleetControlInputSocketFailure(session) {
16058
+ if (!session?.active) {
16059
+ return;
16060
+ }
16061
+
16062
+ closeRemoteFleetControlInputSocket(session, 'failed');
16063
+ session.inputWsUnavailableUntil = Date.now() + 1000;
16064
+ drainRemoteFleetControlInputQueueToFallback(session);
16065
+ }
16066
+
16067
+ function ensureRemoteFleetControlInputSocket(session) {
16068
+ if (!session?.active || typeof WebSocket !== 'function') {
16069
+ return false;
16070
+ }
16071
+
16072
+ const ws = session.inputWs;
16073
+ if (ws && (ws.readyState === 0 || ws.readyState === 1)) {
16074
+ return true;
16075
+ }
16076
+
16077
+ if (session.inputWsConnecting === true) {
16078
+ return true;
16079
+ }
16080
+
16081
+ if ((session.inputWsUnavailableUntil || 0) > Date.now()) {
16082
+ return false;
16083
+ }
16084
+
16085
+ const connectToken = `input-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
16086
+ session.inputWsConnecting = true;
16087
+ session.inputWsConnectToken = connectToken;
16088
+ getRemoteFleetBridgeStatusForFrames()
16089
+ .then(status => {
16090
+ if (!session.active || session.inputWsConnectToken !== connectToken) {
16091
+ return;
16092
+ }
16093
+
16094
+ const wsUrl = buildRemoteFleetInputWsUrl(status);
16095
+ if (!wsUrl) {
16096
+ throw new Error('input-ws-url-unavailable');
16097
+ }
16098
+
16099
+ const inputWs = new WebSocket(wsUrl);
16100
+ session.inputWs = inputWs;
16101
+ inputWs.onopen = () => {
16102
+ if (!session.active || session.inputWs !== inputWs) {
16103
+ return;
16104
+ }
16105
+
16106
+ session.inputWsConnecting = false;
16107
+ session.inputWsUnavailableUntil = 0;
16108
+ if (session.inputWsOpenTimer) {
16109
+ clearTimeout(session.inputWsOpenTimer);
16110
+ session.inputWsOpenTimer = null;
16111
+ }
16112
+ flushRemoteFleetControlInputQueue(session);
16113
+ };
16114
+ inputWs.onmessage = event => {
16115
+ try {
16116
+ const message = JSON.parse(String(event?.data || ''));
16117
+ if (message?.ok === false && session.active) {
16118
+ session.status.textContent = message.error || 'Input failed';
16119
+ }
16120
+ } catch {
16121
+ // Ignore input ack parse errors.
16122
+ }
16123
+ };
16124
+ inputWs.onerror = () => {
16125
+ if (session.inputWs === inputWs) {
16126
+ handleRemoteFleetControlInputSocketFailure(session);
16127
+ }
16128
+ };
16129
+ inputWs.onclose = () => {
16130
+ if (session.inputWs === inputWs) {
16131
+ handleRemoteFleetControlInputSocketFailure(session);
16132
+ }
16133
+ };
16134
+ session.inputWsOpenTimer = setTimeout(() => {
16135
+ if (session.active && session.inputWs === inputWs && inputWs.readyState === 0) {
16136
+ handleRemoteFleetControlInputSocketFailure(session);
16137
+ }
16138
+ }, 900);
16139
+ })
16140
+ .catch(() => {
16141
+ if (!session.active || session.inputWsConnectToken !== connectToken) {
16142
+ return;
16143
+ }
16144
+
16145
+ session.inputWsConnecting = false;
16146
+ session.inputWsUnavailableUntil = Date.now() + 1000;
16147
+ drainRemoteFleetControlInputQueueToFallback(session);
16148
+ });
16149
+
16150
+ return true;
16151
+ }
16152
+
16153
+ function sendRemoteFleetControlInputNow(session, payload) {
16154
+ if (!session?.active || !payload?.type) {
16155
+ return;
16156
+ }
16157
+
16158
+ const input = createRemoteFleetControlInput(session, payload);
16159
+ const envelope = {
16160
+ type: 'input',
16161
+ nodeId: session.nodeId,
16162
+ deviceId: session.deviceId,
16163
+ requestId: `input-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
16164
+ input
15929
16165
  };
15930
16166
 
16167
+ const wsReady = ensureRemoteFleetControlInputSocket(session);
16168
+ if (wsReady && sendRemoteFleetControlInputEnvelope(session, envelope)) {
16169
+ return;
16170
+ }
16171
+
16172
+ if (wsReady) {
16173
+ enqueueRemoteFleetControlInput(session, envelope);
16174
+ return;
16175
+ }
16176
+
16177
+ sendRemoteFleetControlInputFallback(session, input);
16178
+ }
16179
+
16180
+ function sendRemoteFleetControlInput(session, payload, throttleMove = false) {
16181
+ if (!session?.active || !payload?.type) {
16182
+ return;
16183
+ }
16184
+
15931
16185
  if (!throttleMove) {
15932
- send(payload);
16186
+ sendRemoteFleetControlInputNow(session, payload);
15933
16187
  return;
15934
16188
  }
15935
16189
 
15936
16190
  const now = performance.now();
15937
16191
  const elapsed = now - (session.lastMoveSentAt || 0);
15938
- if (elapsed >= 32) {
16192
+ if (elapsed >= REMOTE_FLEET_CONTROL_INPUT_MOVE_MS) {
15939
16193
  session.lastMoveSentAt = now;
15940
- send(payload);
16194
+ sendRemoteFleetControlInputNow(session, payload);
15941
16195
  return;
15942
16196
  }
15943
16197
 
@@ -15952,9 +16206,9 @@
15952
16206
  session.pendingMove = null;
15953
16207
  if (next) {
15954
16208
  session.lastMoveSentAt = performance.now();
15955
- send(next);
16209
+ sendRemoteFleetControlInputNow(session, next);
15956
16210
  }
15957
- }, Math.max(1, 32 - elapsed));
16211
+ }, Math.max(1, REMOTE_FLEET_CONTROL_INPUT_MOVE_MS - elapsed));
15958
16212
  }
15959
16213
 
15960
16214
  function bindRemoteFleetControlInput(session) {
@@ -15965,6 +16219,40 @@
15965
16219
  overlay.addEventListener(eventName, event => event.stopPropagation(), true);
15966
16220
  });
15967
16221
 
16222
+ const shouldIgnoreKeyboardEvent = event =>
16223
+ event?.target?.closest?.('[data-remote-fleet-control-close="true"]');
16224
+
16225
+ const handleKeyboardEvent = (event, type) => {
16226
+ if (!session.active || shouldIgnoreKeyboardEvent(event) || event.__remoteFleetControlHandled === true) {
16227
+ return;
16228
+ }
16229
+
16230
+ event.__remoteFleetControlHandled = true;
16231
+ event.preventDefault();
16232
+ event.stopPropagation();
16233
+ shell.focus({ preventScroll: true });
16234
+ sendRemoteFleetControlInput(session, {
16235
+ type,
16236
+ key: event.key,
16237
+ code: event.code,
16238
+ repeat: event.repeat === true
16239
+ });
16240
+ };
16241
+
16242
+ const handleWindowKeyDown = event => handleKeyboardEvent(event, 'keyDown');
16243
+ const handleWindowKeyUp = event => handleKeyboardEvent(event, 'keyUp');
16244
+ if (typeof window.addEventListener === 'function') {
16245
+ window.addEventListener('keydown', handleWindowKeyDown, true);
16246
+ window.addEventListener('keyup', handleWindowKeyUp, true);
16247
+ }
16248
+ session.inputCleanup = () => {
16249
+ if (typeof window.removeEventListener === 'function') {
16250
+ window.removeEventListener('keydown', handleWindowKeyDown, true);
16251
+ window.removeEventListener('keyup', handleWindowKeyUp, true);
16252
+ }
16253
+ session.inputCleanup = null;
16254
+ };
16255
+
15968
16256
  stage.addEventListener('pointerdown', event => {
15969
16257
  const point = getRemoteFleetControlPoint(event, canvas, false);
15970
16258
  if (!point) {
@@ -16041,35 +16329,8 @@
16041
16329
  event.stopPropagation();
16042
16330
  });
16043
16331
 
16044
- shell.addEventListener('keydown', event => {
16045
- if (event.target?.closest?.('[data-remote-fleet-control-close="true"]')) {
16046
- return;
16047
- }
16048
-
16049
- event.preventDefault();
16050
- event.stopPropagation();
16051
- sendRemoteFleetControlInput(session, {
16052
- type: 'keyDown',
16053
- key: event.key,
16054
- code: event.code,
16055
- repeat: event.repeat === true
16056
- });
16057
- });
16058
-
16059
- shell.addEventListener('keyup', event => {
16060
- if (event.target?.closest?.('[data-remote-fleet-control-close="true"]')) {
16061
- return;
16062
- }
16063
-
16064
- event.preventDefault();
16065
- event.stopPropagation();
16066
- sendRemoteFleetControlInput(session, {
16067
- type: 'keyUp',
16068
- key: event.key,
16069
- code: event.code,
16070
- repeat: event.repeat === true
16071
- });
16072
- });
16332
+ shell.addEventListener('keydown', event => handleKeyboardEvent(event, 'keyDown'));
16333
+ shell.addEventListener('keyup', event => handleKeyboardEvent(event, 'keyUp'));
16073
16334
  }
16074
16335
 
16075
16336
  function openRemoteFleetControlPopup(bodyView, nodeModel, deviceId) {
@@ -16233,10 +16494,18 @@
16233
16494
  lastMoveSentAt: 0,
16234
16495
  lastControlFrameAt: 0,
16235
16496
  lastControlFrameSeq: 0,
16236
- binaryFramePreferred: false
16497
+ binaryFramePreferred: false,
16498
+ inputWs: null,
16499
+ inputWsConnecting: false,
16500
+ inputWsConnectToken: '',
16501
+ inputWsOpenTimer: null,
16502
+ inputWsUnavailableUntil: 0,
16503
+ inputQueue: [],
16504
+ inputCleanup: null
16237
16505
  };
16238
16506
  activeRemoteFleetControlPopup = session;
16239
16507
  bindRemoteFleetControlInput(session);
16508
+ ensureRemoteFleetControlInputSocket(session);
16240
16509
  attachRemoteFleetControlBinaryFrameSession(session, bodyView);
16241
16510
 
16242
16511
  const refresh = async () => {
@@ -1,5 +1,5 @@
1
1
  self.assetsManifest = {
2
- "version": "20SB8UIp",
2
+ "version": "uSz5Xt0z",
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-CXwos9ge49EzJij/kELHzhWSDGBSR3fbqqW7hBxARCI=",
89
+ "hash": "sha256-4BdT/RnBOnh3Mm/hTZilg3zo9az6W9oYf8h3br2aDko=",
90
90
  "url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
91
91
  },
92
92
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: 20SB8UIp */
1
+ /* Manifest version: uSz5Xt0z */
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