@mindexec/cli 0.2.120 → 0.2.122

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.120",
3
+ "version": "0.2.122",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -95,6 +95,10 @@ class MiniElement {
95
95
  this.value = '';
96
96
  this.checked = false;
97
97
  this.disabled = false;
98
+ this.clientWidth = 320;
99
+ this.clientHeight = 180;
100
+ this.width = 0;
101
+ this.height = 0;
98
102
  }
99
103
 
100
104
  get textContent() {
@@ -182,6 +186,44 @@ class MiniElement {
182
186
  return true;
183
187
  }
184
188
 
189
+ getBoundingClientRect() {
190
+ return {
191
+ left: 0,
192
+ top: 0,
193
+ right: this.clientWidth,
194
+ bottom: this.clientHeight,
195
+ width: this.clientWidth,
196
+ height: this.clientHeight
197
+ };
198
+ }
199
+
200
+ getContext(type) {
201
+ if (this.tagName !== 'CANVAS' || String(type || '').toLowerCase() !== '2d') {
202
+ return null;
203
+ }
204
+
205
+ if (this._canvasContext) {
206
+ return this._canvasContext;
207
+ }
208
+
209
+ const owner = this.ownerDocument;
210
+ this._canvasContext = {
211
+ imageSmoothingEnabled: false,
212
+ imageSmoothingQuality: 'low',
213
+ fillStyle: '#000',
214
+ clearRect: (...args) => {
215
+ owner.canvasDrawCalls.push({ canvas: this, op: 'clearRect', args });
216
+ },
217
+ fillRect: (...args) => {
218
+ owner.canvasDrawCalls.push({ canvas: this, op: 'fillRect', args });
219
+ },
220
+ drawImage: (...args) => {
221
+ owner.canvasDrawCalls.push({ canvas: this, op: 'drawImage', args });
222
+ }
223
+ };
224
+ return this._canvasContext;
225
+ }
226
+
185
227
  querySelector(selector) {
186
228
  return this.querySelectorAll(selector)[0] || null;
187
229
  }
@@ -225,6 +267,7 @@ class MiniDocument {
225
267
  constructor() {
226
268
  this.body = new MiniElement('body', this);
227
269
  this.head = new MiniElement('head', this);
270
+ this.canvasDrawCalls = [];
228
271
  }
229
272
 
230
273
  createElement(tagName) {
@@ -373,6 +416,17 @@ async function loadCss3DManager() {
373
416
  const managerPath = path.resolve(__dirname, '../../MindExecution.Shared/wwwroot/js/mind-map-css3d-manager.js');
374
417
  const source = await fs.readFile(managerPath, 'utf8');
375
418
  const document = new MiniDocument();
419
+ const objectUrlCalls = [];
420
+ const revokedObjectUrls = [];
421
+ const imageBitmapCalls = [];
422
+ class SmokeURL extends URL {}
423
+ SmokeURL.createObjectURL = blob => {
424
+ objectUrlCalls.push(blob);
425
+ return `blob:remote-fleet-smoke-${objectUrlCalls.length}`;
426
+ };
427
+ SmokeURL.revokeObjectURL = value => {
428
+ revokedObjectUrls.push(String(value || ''));
429
+ };
376
430
  const context = {
377
431
  console,
378
432
  document,
@@ -397,15 +451,36 @@ async function loadCss3DManager() {
397
451
  Map,
398
452
  Set,
399
453
  WeakMap,
454
+ Blob,
455
+ requestAnimationFrame: callback => setTimeout(() => callback(Date.now()), 0),
456
+ cancelAnimationFrame: id => clearTimeout(id),
457
+ createImageBitmap: async blob => {
458
+ imageBitmapCalls.push(blob);
459
+ return {
460
+ width: 64,
461
+ height: 36,
462
+ close() {
463
+ this.closed = true;
464
+ }
465
+ };
466
+ },
400
467
  THREE: createThreeStub(),
401
- URL,
468
+ URL: SmokeURL,
402
469
  Promise
403
470
  };
404
471
  context.window = context;
405
472
  context.self = context;
406
473
 
407
474
  vm.runInNewContext(source, context, { filename: managerPath });
408
- return { manager: context.window.MindMapCss3DManager, document };
475
+ return {
476
+ manager: context.window.MindMapCss3DManager,
477
+ document,
478
+ diagnostics: {
479
+ objectUrlCalls,
480
+ revokedObjectUrls,
481
+ imageBitmapCalls
482
+ }
483
+ };
409
484
  }
410
485
 
411
486
  function wait(ms = 0) {
@@ -646,7 +721,7 @@ try {
646
721
  }
647
722
  ];
648
723
 
649
- const { manager, document } = await loadCss3DManager();
724
+ const { manager, document, diagnostics } = await loadCss3DManager();
650
725
  assert.equal(typeof manager?.renderRemoteFleetMonitorForTest, 'function');
651
726
  assert.equal(typeof manager?.renderRemoteFleetDeviceForTest, 'function');
652
727
  assert.equal(typeof manager?.applyRemoteFleetFramePatchesForTest, 'function');
@@ -765,6 +840,35 @@ try {
765
840
  assert.ok(patchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]'));
766
841
  assert.equal(patchPreview.querySelector('img[data-remote-fleet-frame-image="true"]')?.dataset.remoteFleetFrameUrl, patchUrl);
767
842
  assert.equal(patchPreview.querySelector('[data-remote-fleet-frame-badge="true"]'), null);
843
+
844
+ const objectUrlCountBeforeBinary = diagnostics.objectUrlCalls.length;
845
+ const imageBitmapCountBeforeBinary = diagnostics.imageBitmapCalls.length;
846
+ const drawCountBeforeBinary = document.canvasDrawCalls.length;
847
+ const binaryPatchCount = manager.applyRemoteFleetFramePatchesForTest(bodyView, [{
848
+ deviceId: patchTarget.DeviceId,
849
+ kind: 'live',
850
+ frameSeq: 10000,
851
+ frameUrl: '',
852
+ streamId: 'render-smoke-binary-live',
853
+ contentHash: 'render-smoke-binary-live-10000',
854
+ receivedAt: new Date().toISOString(),
855
+ _remoteFleetPayloadBlob: new Blob([new Uint8Array([0xff, 0xd8, 0xff, 0xd9])], { type: 'image/jpeg' }),
856
+ _remoteFleetBinaryFrame: true
857
+ }]);
858
+ assert.equal(binaryPatchCount, 1);
859
+ await wait(20);
860
+ const binaryCanvas = patchPreview.querySelector('canvas[data-remote-fleet-frame-canvas="true"]');
861
+ const binaryImage = patchPreview.querySelector('img[data-remote-fleet-frame-image="true"]');
862
+ assert.equal(patchPreview.dataset.remoteFleetFrameKind, 'live');
863
+ assert.equal(patchPreview.dataset.remoteFleetFrameSeq, '10000');
864
+ assert.equal(binaryCanvas?.dataset.remoteFleetFrameSeq, '10000');
865
+ assert.equal(binaryCanvas?.style.display, 'block');
866
+ assert.equal(binaryImage?.style.display, 'none');
867
+ assert.equal(diagnostics.imageBitmapCalls.length, imageBitmapCountBeforeBinary + 1);
868
+ assert.equal(diagnostics.objectUrlCalls.length, objectUrlCountBeforeBinary);
869
+ assert.ok(
870
+ document.canvasDrawCalls.slice(drawCountBeforeBinary).some(call => call.op === 'drawImage'),
871
+ 'expected binary Blob frame to draw directly to canvas');
768
872
  const alternateDevice = devices.find(device =>
769
873
  device.Connected === true
770
874
  && device.DeviceId !== focusedDevice.DeviceId);
@@ -13463,6 +13463,10 @@
13463
13463
  const REMOTE_FLEET_THUMBNAIL_FRAME_DECODE_TIMEOUT_MS = 1200;
13464
13464
  const REMOTE_FLEET_BINARY_FRAME_WS_RECONNECT_MS = 1500;
13465
13465
  const REMOTE_FLEET_BINARY_FRAME_SUBSCRIBE_MS = 1000;
13466
+ const REMOTE_FLEET_BINARY_FRAME_STALE_FALLBACK_MS = 1400;
13467
+ const REMOTE_FLEET_BINARY_FRAME_CONNECT_GRACE_MS = 1600;
13468
+ const REMOTE_FLEET_AUTO_LIVE_START_MAX_PARALLEL = 8;
13469
+ const REMOTE_FLEET_AUTO_LIVE_START_COOLDOWN_MS = 3000;
13466
13470
  const REMOTE_FLEET_TASK_FOLLOW_INITIAL_MS = 250;
13467
13471
  const REMOTE_FLEET_TASK_FOLLOW_REFRESH_MS = 2000;
13468
13472
  const REMOTE_FLEET_TASK_FOLLOW_MAX_TICKS = 60;
@@ -13675,6 +13679,12 @@
13675
13679
  return candidates;
13676
13680
  }
13677
13681
 
13682
+ function getRemoteFleetFrameNow() {
13683
+ return typeof performance !== 'undefined' && typeof performance.now === 'function'
13684
+ ? performance.now()
13685
+ : Date.now();
13686
+ }
13687
+
13678
13688
  async function getRemoteFleetBridgeStatusForFrames() {
13679
13689
  if (remoteFleetBridgeStatusPromise) {
13680
13690
  return remoteFleetBridgeStatusPromise;
@@ -13760,15 +13770,13 @@
13760
13770
  const payload = buffer.slice(4 + metaLength);
13761
13771
  const mimeType = String(metadata.mimeType || metadata.format || 'image/jpeg').trim() || 'image/jpeg';
13762
13772
  const payloadBlob = new Blob([payload], { type: mimeType });
13763
- const objectUrl = URL.createObjectURL(payloadBlob);
13764
13773
  return {
13765
13774
  ...metadata,
13766
13775
  kind: String(metadata.kind || 'live').toLowerCase() === 'thumbnail' ? 'thumbnail' : 'live',
13767
13776
  mimeType,
13768
- frameUrl: objectUrl,
13769
- framePath: objectUrl,
13777
+ frameUrl: '',
13778
+ framePath: '',
13770
13779
  dataUrl: '',
13771
- _remoteFleetObjectUrl: objectUrl,
13772
13780
  _remoteFleetPayloadBlob: payloadBlob,
13773
13781
  _remoteFleetBinaryFrame: true
13774
13782
  };
@@ -13863,9 +13871,11 @@
13863
13871
 
13864
13872
  const ws = new WebSocket(wsUrl);
13865
13873
  session.ws = ws;
13874
+ session.wsOpeningAt = getRemoteFleetFrameNow();
13866
13875
  session.subscriptionKey = '';
13867
13876
  ws.binaryType = 'arraybuffer';
13868
13877
  ws.onopen = () => {
13878
+ session.wsOpenedAt = getRemoteFleetFrameNow();
13869
13879
  window.RuntimeTrace?.emit?.('remote.frame.wsOpen', { nodeId: session.nodeId });
13870
13880
  refreshRemoteFleetBinaryFrameSubscription(session, true);
13871
13881
  if (!session.subscriptionTimer) {
@@ -13894,9 +13904,15 @@
13894
13904
  }
13895
13905
 
13896
13906
  let applied = 0;
13907
+ const frameAt = getRemoteFleetFrameNow();
13908
+ session.lastBinaryFrameAt = frameAt;
13897
13909
  session.bodies.forEach(body => {
13898
13910
  if (document.body.contains(body)) {
13899
- applied += applyRemoteFleetFramePatches(body, [frame]);
13911
+ const bodyApplied = applyRemoteFleetFramePatches(body, [frame]);
13912
+ if (bodyApplied > 0) {
13913
+ body._remoteFleetLastBinaryFrameAt = frameAt;
13914
+ }
13915
+ applied += bodyApplied;
13900
13916
  }
13901
13917
  });
13902
13918
 
@@ -14371,7 +14387,7 @@
14371
14387
  }
14372
14388
 
14373
14389
  async function loadRemoteFleetFrameBitmap(frame) {
14374
- if (!frame || !isRemoteFleetFrameSource(frame.frameUrl)) {
14390
+ if (!frame) {
14375
14391
  return null;
14376
14392
  }
14377
14393
 
@@ -14386,6 +14402,10 @@
14386
14402
  timeoutMs);
14387
14403
  }
14388
14404
 
14405
+ if (!isRemoteFleetFrameSource(frame.frameUrl)) {
14406
+ return null;
14407
+ }
14408
+
14389
14409
  if (typeof fetch !== 'function') {
14390
14410
  return null;
14391
14411
  }
@@ -14437,7 +14457,7 @@
14437
14457
  String(frame?.kind || '').trim().toLowerCase(),
14438
14458
  String(frame?.streamId || '').trim(),
14439
14459
  String(Number(frame?.frameSeq || 0) || 0),
14440
- String(frame?.frameUrl || '').trim()
14460
+ String(frame?.contentHash || frame?.frameUrl || '').trim()
14441
14461
  ].join('|');
14442
14462
  }
14443
14463
 
@@ -14467,7 +14487,9 @@
14467
14487
  }
14468
14488
 
14469
14489
  function isRemoteFleetFrameNewerForPreview(preview, frame, comparePending = false) {
14470
- if (!preview || !frame || !isRemoteFleetFrameSource(frame.frameUrl)) {
14490
+ const hasPayloadBlob = !!frame?._remoteFleetPayloadBlob;
14491
+ const hasFrameSource = isRemoteFleetFrameSource(frame?.frameUrl);
14492
+ if (!preview || !frame || (!hasPayloadBlob && !hasFrameSource)) {
14471
14493
  return false;
14472
14494
  }
14473
14495
 
@@ -14636,7 +14658,7 @@
14636
14658
  }
14637
14659
 
14638
14660
  const frame = preview._remoteFleetPendingFrame;
14639
- if (!frame || !isRemoteFleetFrameSource(frame.frameUrl)) {
14661
+ if (!frame || (!frame._remoteFleetPayloadBlob && !isRemoteFleetFrameSource(frame.frameUrl))) {
14640
14662
  clearRemoteFleetPendingFrameDataset(preview, frame);
14641
14663
  return;
14642
14664
  }
@@ -14673,6 +14695,25 @@
14673
14695
  return;
14674
14696
  }
14675
14697
 
14698
+ let fallbackUrl = String(frame.frameUrl || '').trim();
14699
+ if (!isRemoteFleetFrameSource(fallbackUrl)
14700
+ && frame._remoteFleetPayloadBlob
14701
+ && typeof URL !== 'undefined'
14702
+ && typeof URL.createObjectURL === 'function') {
14703
+ try {
14704
+ fallbackUrl = URL.createObjectURL(frame._remoteFleetPayloadBlob);
14705
+ frame.frameUrl = fallbackUrl;
14706
+ frame._remoteFleetObjectUrl = fallbackUrl;
14707
+ } catch {
14708
+ fallbackUrl = '';
14709
+ }
14710
+ }
14711
+
14712
+ if (!isRemoteFleetFrameSource(fallbackUrl)) {
14713
+ finish(false, 'img-unavailable');
14714
+ return;
14715
+ }
14716
+
14676
14717
  const timeoutMs = getRemoteFleetFrameDecodeTimeoutMs(frame);
14677
14718
  let settled = false;
14678
14719
  const complete = (loaded, surface = 'img') => {
@@ -14691,7 +14732,7 @@
14691
14732
  decoded.then(() => complete(true, 'img'));
14692
14733
  };
14693
14734
  loader.onerror = () => complete(false, 'img');
14694
- loader.src = frame.frameUrl;
14735
+ loader.src = fallbackUrl;
14695
14736
  };
14696
14737
 
14697
14738
  const canvas = ensureRemoteFleetFrameCanvas(preview);
@@ -14753,7 +14794,7 @@
14753
14794
  seq: frame.frameSeq,
14754
14795
  error: error?.message || String(error || '')
14755
14796
  });
14756
- finish(false, 'canvas-timeout');
14797
+ loadFallbackImage();
14757
14798
  return;
14758
14799
  }
14759
14800
 
@@ -14973,9 +15014,20 @@
14973
15014
  if (binarySocket
14974
15015
  && typeof WebSocket !== 'undefined'
14975
15016
  && (binarySocket.readyState === WebSocket.OPEN || binarySocket.readyState === WebSocket.CONNECTING)) {
14976
- lastTick = timestamp;
14977
- bodyView._remoteFleetFrameLoopRaf = requestRemoteFleetFrameLoopFrame(loop);
14978
- return;
15017
+ const lastBinaryFrameAt = Number(bodyView._remoteFleetLastBinaryFrameAt || binarySession?.lastBinaryFrameAt || 0);
15018
+ const wsStartedAt = Number(binarySession?.wsOpenedAt || binarySession?.wsOpeningAt || 0);
15019
+ const hasRecentBinaryFrame =
15020
+ lastBinaryFrameAt > 0
15021
+ && timestamp - lastBinaryFrameAt <= REMOTE_FLEET_BINARY_FRAME_STALE_FALLBACK_MS;
15022
+ const stillWithinConnectGrace =
15023
+ wsStartedAt > 0
15024
+ && lastBinaryFrameAt <= 0
15025
+ && timestamp - wsStartedAt <= REMOTE_FLEET_BINARY_FRAME_CONNECT_GRACE_MS;
15026
+ if (hasRecentBinaryFrame || stillWithinConnectGrace) {
15027
+ lastTick = timestamp;
15028
+ bodyView._remoteFleetFrameLoopRaf = requestRemoteFleetFrameLoopFrame(loop);
15029
+ return;
15030
+ }
14979
15031
  }
14980
15032
 
14981
15033
  if (timestamp - lastTick >= intervalMs && bodyView._remoteFleetFrameRefreshInFlight !== true) {
@@ -17100,35 +17152,39 @@
17100
17152
  return ids.slice(0, 120);
17101
17153
  };
17102
17154
  const ensureVisibleRemoteFleetLiveStreams = async () => {
17103
- if (!(bodyView._remoteFleetAutoLiveStartedIds instanceof Set)) {
17104
- bodyView._remoteFleetAutoLiveStartedIds = new Set();
17155
+ if (!(bodyView._remoteFleetAutoLiveStartInFlight instanceof Set)) {
17156
+ bodyView._remoteFleetAutoLiveStartInFlight = new Set();
17157
+ }
17158
+ if (!(bodyView._remoteFleetAutoLiveStartAttemptAt instanceof Map)) {
17159
+ bodyView._remoteFleetAutoLiveStartAttemptAt = new Map();
17105
17160
  }
17161
+ const now = Date.now();
17106
17162
  const targets = getVisibleLiveDevices()
17107
17163
  .filter(device => {
17108
17164
  const deviceId = getRemoteFleetDeviceId(device);
17165
+ const lastAttemptAt = Number(bodyView._remoteFleetAutoLiveStartAttemptAt.get(deviceId) || 0);
17109
17166
  return deviceId
17110
17167
  && !isRemoteFleetLiveActive(device)
17111
- && !bodyView._remoteFleetAutoLiveStartedIds.has(deviceId);
17168
+ && !bodyView._remoteFleetAutoLiveStartInFlight.has(deviceId)
17169
+ && (now - lastAttemptAt >= REMOTE_FLEET_AUTO_LIVE_START_COOLDOWN_MS);
17112
17170
  });
17113
17171
  if (targets.length === 0) {
17114
17172
  return null;
17115
17173
  }
17116
17174
 
17117
- if (!(bodyView._remoteFleetAutoLiveStartInFlight instanceof Set)) {
17118
- bodyView._remoteFleetAutoLiveStartInFlight = new Set();
17119
- }
17120
-
17121
17175
  let started = 0;
17122
17176
  let lastResult = null;
17123
- for (const target of targets) {
17177
+ const queue = targets.slice(0, 120);
17178
+ const startOne = async target => {
17124
17179
  const deviceId = getRemoteFleetDeviceId(target);
17125
17180
  if (!deviceId || bodyView._remoteFleetAutoLiveStartInFlight.has(deviceId)) {
17126
- continue;
17181
+ return;
17127
17182
  }
17128
17183
 
17129
17184
  bodyView._remoteFleetAutoLiveStartInFlight.add(deviceId);
17185
+ bodyView._remoteFleetAutoLiveStartAttemptAt.set(deviceId, Date.now());
17130
17186
  try {
17131
- const result = await invokeDotNetAsync('StartRemoteFleetLiveStreamFromJs', nodeId, deviceId);
17187
+ const result = await invokeDotNetAsync('StartRemoteFleetLiveStreamFromJs', nodeId, deviceId, REMOTE_FLEET_MONITOR_LIVE_FPS);
17132
17188
  lastResult = result;
17133
17189
  const success = isRemoteFleetResultSuccess(result);
17134
17190
  window.RuntimeTrace?.emit?.('remote.live.autoStart', {
@@ -17141,12 +17197,21 @@
17141
17197
  });
17142
17198
  if (success) {
17143
17199
  started += 1;
17144
- bodyView._remoteFleetAutoLiveStartedIds.add(deviceId);
17145
17200
  }
17146
17201
  } finally {
17147
17202
  bodyView._remoteFleetAutoLiveStartInFlight.delete(deviceId);
17148
17203
  }
17149
- }
17204
+ };
17205
+
17206
+ const workerCount = Math.min(REMOTE_FLEET_AUTO_LIVE_START_MAX_PARALLEL, queue.length);
17207
+ await Promise.all(Array.from({ length: workerCount }, async () => {
17208
+ while (queue.length > 0) {
17209
+ const target = queue.shift();
17210
+ if (target) {
17211
+ await startOne(target);
17212
+ }
17213
+ }
17214
+ }));
17150
17215
 
17151
17216
  if (started > 0) {
17152
17217
  try {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mainAssemblyName": "MindExecution.Web",
3
3
  "resources": {
4
- "hash": "sha256-o8W1U0lBmrbs5unXcwG+/IEh2KogSA7Rk3MqjQnNfGU=",
4
+ "hash": "sha256-aGxH2r2LOpixHAksGBYXRcA86Dv8rGHPIhoagHBUV2M=",
5
5
  "fingerprinting": {
6
6
  "Google.Protobuf.9h59ukbel7.dll": "Google.Protobuf.dll",
7
7
  "Markdig.d1j7v41cl1.dll": "Markdig.dll",
@@ -131,7 +131,7 @@
131
131
  "MindExecution.Plugins.Directory.jc0g7fvyzv.dll": "MindExecution.Plugins.Directory.dll",
132
132
  "MindExecution.Plugins.PlanMaster.2sugb66h95.dll": "MindExecution.Plugins.PlanMaster.dll",
133
133
  "MindExecution.Plugins.YouTube.vy0nsbcoo4.dll": "MindExecution.Plugins.YouTube.dll",
134
- "MindExecution.Shared.uwkrc41o75.dll": "MindExecution.Shared.dll",
134
+ "MindExecution.Shared.vki6dm13ef.dll": "MindExecution.Shared.dll",
135
135
  "MindExecution.Web.994sb3nzuy.dll": "MindExecution.Web.dll",
136
136
  "dotnet.js": "dotnet.js",
137
137
  "dotnet.native.qc8g39g30v.js": "dotnet.native.js",
@@ -282,7 +282,7 @@
282
282
  "MindExecution.Kernel.3zom09ir6j.dll": "sha256-78vR2SNkF9FwdQv0fEItSyz4HzgyzwGUROJAnpripPA=",
283
283
  "MindExecution.Plugins.Concept.lxunwcdjgq.dll": "sha256-WVyvjaxW6UoGQvGW0icChLsXwYVCcdn0BLTftzlkCKc=",
284
284
  "MindExecution.Plugins.PlanMaster.2sugb66h95.dll": "sha256-Lp0AieRHDo2H4Yl0Il1pPruy9nFUHJsX9t1AblXGD6Y=",
285
- "MindExecution.Shared.uwkrc41o75.dll": "sha256-YjF+7VcGo3+nB0fsa2nh3AiaRyrHS1AL6d6Mq4RWKqo=",
285
+ "MindExecution.Shared.vki6dm13ef.dll": "sha256-cUcgQfOJa1LaZuLSXdrmi1RrrueXoKuP49M/cjsbguU=",
286
286
  "MindExecution.Web.994sb3nzuy.dll": "sha256-jQshtLmhEC4xenzdD9PqHjaCuKvJf/frzaKBi2weDAg="
287
287
  },
288
288
  "lazyAssembly": {
@@ -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=20260616-mdm-ws-fast-v575" />
11
- <link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260616-mdm-ws-fast-v575" />
10
+ <link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260616-mdm-ws-watchdog-v577" />
11
+ <link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260616-mdm-ws-watchdog-v577" />
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 = '20260616-mdm-ws-fast-v575';
582
+ const scriptVersion = '20260616-mdm-ws-watchdog-v577';
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": "vnLn5hRl",
2
+ "version": "PVMqIJP0",
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-eGHfAJwh8N3LmDZTr3/anW3CVrYCEYowGfK4N8KPzik=",
89
+ "hash": "sha256-04ZcgwZFW2ICQSVXCeuy61QLIexXoiGLVAIR1UDv3UQ=",
90
90
  "url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
91
91
  },
92
92
  {
@@ -442,8 +442,8 @@
442
442
  "url": "_framework/MindExecution.Plugins.YouTube.vy0nsbcoo4.dll"
443
443
  },
444
444
  {
445
- "hash": "sha256-YjF+7VcGo3+nB0fsa2nh3AiaRyrHS1AL6d6Mq4RWKqo=",
446
- "url": "_framework/MindExecution.Shared.uwkrc41o75.dll"
445
+ "hash": "sha256-cUcgQfOJa1LaZuLSXdrmi1RrrueXoKuP49M/cjsbguU=",
446
+ "url": "_framework/MindExecution.Shared.vki6dm13ef.dll"
447
447
  },
448
448
  {
449
449
  "hash": "sha256-jQshtLmhEC4xenzdD9PqHjaCuKvJf/frzaKBi2weDAg=",
@@ -770,7 +770,7 @@
770
770
  "url": "_framework/Websocket.Client.vapounvmnl.dll"
771
771
  },
772
772
  {
773
- "hash": "sha256-lL/HCjpHZ3+EWJkTvNj72sH8NLl/eSU2UZDTr6bP99c=",
773
+ "hash": "sha256-RIddmeeu4/GO5kDBZ6kmWUv1o1+x8NzfFxWruTBtPec=",
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-IYebw41Eytj+5xl0lRltZ9R7wOwuHg0mlcgar2MiudE=",
837
+ "hash": "sha256-a13nNlTLpG4s9DEqkhUdxDJRAp9L+OnnPbRXafbvBCo=",
838
838
  "url": "index.html"
839
839
  },
840
840
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: vnLn5hRl */
1
+ /* Manifest version: PVMqIJP0 */
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