@mindexec/cli 0.2.106 → 0.2.108
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 +1 -1
- package/remote-hub.js +170 -16
- package/scripts/remote-hub-smoke.mjs +20 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +1 -1
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +15 -8
- package/wwwroot/index.html +3 -3
- package/wwwroot/service-worker-assets.js +4 -4
- package/wwwroot/service-worker.js +1 -1
package/package.json
CHANGED
package/remote-hub.js
CHANGED
|
@@ -15,6 +15,11 @@ const MAX_AGENT_TASK_CHARS = 4000;
|
|
|
15
15
|
const MAX_AGENT_TASK_RESULT_CHARS = 3000;
|
|
16
16
|
const RECENT_TASK_LIMIT = 12;
|
|
17
17
|
const RECENT_TASK_BATCH_LIMIT = 16;
|
|
18
|
+
const RECENT_FRAME_CACHE_TTL_MS = 5000;
|
|
19
|
+
const RECENT_THUMBNAIL_FRAME_CACHE_LIMIT = 4;
|
|
20
|
+
const RECENT_LIVE_FRAME_CACHE_LIMIT = 24;
|
|
21
|
+
const RECENT_THUMBNAIL_FRAME_CACHE_MAX_BYTES = 3 * 1024 * 1024;
|
|
22
|
+
const RECENT_LIVE_FRAME_CACHE_MAX_BYTES = 8 * 1024 * 1024;
|
|
18
23
|
const REMOTE_PROTOCOL_VERSION = 1;
|
|
19
24
|
const MAX_SYNTHETIC_DEVICES = 1000;
|
|
20
25
|
const DEFAULT_HOST_TARGET_LEASE_MS = 30000;
|
|
@@ -374,6 +379,153 @@ function serializeRemoteFrame(frame, deviceId, frameKind, options = {}) {
|
|
|
374
379
|
return serialized;
|
|
375
380
|
}
|
|
376
381
|
|
|
382
|
+
function getRecentFrameCache(device, frameKind) {
|
|
383
|
+
if (!device) {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (!device.recentFramePayloads) {
|
|
388
|
+
device.recentFramePayloads = {
|
|
389
|
+
thumbnail: [],
|
|
390
|
+
live: []
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const kind = frameKind === 'thumbnail' ? 'thumbnail' : 'live';
|
|
395
|
+
if (!Array.isArray(device.recentFramePayloads[kind])) {
|
|
396
|
+
device.recentFramePayloads[kind] = [];
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return device.recentFramePayloads[kind];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function getRecentFrameCacheLimit(frameKind) {
|
|
403
|
+
return frameKind === 'thumbnail'
|
|
404
|
+
? RECENT_THUMBNAIL_FRAME_CACHE_LIMIT
|
|
405
|
+
: RECENT_LIVE_FRAME_CACHE_LIMIT;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function getRecentFrameCacheMaxBytes(frameKind) {
|
|
409
|
+
return frameKind === 'thumbnail'
|
|
410
|
+
? RECENT_THUMBNAIL_FRAME_CACHE_MAX_BYTES
|
|
411
|
+
: RECENT_LIVE_FRAME_CACHE_MAX_BYTES;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function pruneRecentFrameCache(cache, frameKind, nowMs = Date.now()) {
|
|
415
|
+
if (!Array.isArray(cache)) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const limit = getRecentFrameCacheLimit(frameKind);
|
|
420
|
+
const maxBytes = getRecentFrameCacheMaxBytes(frameKind);
|
|
421
|
+
let byteTotal = 0;
|
|
422
|
+
for (let index = cache.length - 1; index >= 0; index -= 1) {
|
|
423
|
+
const entry = cache[index];
|
|
424
|
+
const frame = entry?.frame;
|
|
425
|
+
if (!entry
|
|
426
|
+
|| entry.expiresAt <= nowMs
|
|
427
|
+
|| !frame
|
|
428
|
+
|| !Buffer.isBuffer(frame.payload)
|
|
429
|
+
|| !Number.isFinite(Number(frame.frameSeq))
|
|
430
|
+
|| !safeString(frame.accessToken, 128)) {
|
|
431
|
+
cache.splice(index, 1);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
for (let index = 0; index < cache.length; index += 1) {
|
|
436
|
+
const entry = cache[index];
|
|
437
|
+
const byteLength = Number(entry?.byteLength || entry?.frame?.payload?.length || 0) || 0;
|
|
438
|
+
byteTotal += byteLength;
|
|
439
|
+
if (index >= limit || byteTotal > maxBytes) {
|
|
440
|
+
cache.splice(index);
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function rememberRecentFramePayload(device, frameKind, frame) {
|
|
447
|
+
if (!device || !frame || !Buffer.isBuffer(frame.payload)) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const frameSeq = Number(frame.frameSeq);
|
|
452
|
+
const accessToken = safeString(frame.accessToken, 128);
|
|
453
|
+
if (!Number.isFinite(frameSeq) || !accessToken) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const kind = frameKind === 'thumbnail' ? 'thumbnail' : 'live';
|
|
458
|
+
const cache = getRecentFrameCache(device, kind);
|
|
459
|
+
if (!cache) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const nowMs = Date.now();
|
|
464
|
+
const normalizedSeq = Math.floor(frameSeq);
|
|
465
|
+
for (let index = cache.length - 1; index >= 0; index -= 1) {
|
|
466
|
+
const existing = cache[index]?.frame;
|
|
467
|
+
if (Number(existing?.frameSeq) === normalizedSeq
|
|
468
|
+
|| safeString(existing?.accessToken, 128) === accessToken) {
|
|
469
|
+
cache.splice(index, 1);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
cache.unshift({
|
|
474
|
+
frame,
|
|
475
|
+
byteLength: frame.payload.length,
|
|
476
|
+
cachedAt: nowMs,
|
|
477
|
+
expiresAt: nowMs + RECENT_FRAME_CACHE_TTL_MS
|
|
478
|
+
});
|
|
479
|
+
pruneRecentFrameCache(cache, kind, nowMs);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function isFramePayloadRequestMatch(frame, options = {}) {
|
|
483
|
+
if (!frame || !Buffer.isBuffer(frame.payload)) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const requestedSeq = Number(options.frameSeq);
|
|
488
|
+
if (Number.isFinite(requestedSeq) && Math.floor(requestedSeq) !== Number(frame.frameSeq)) {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const token = safeString(options.token, 128);
|
|
493
|
+
if (token && !timingSafeStringEqual(token, frame.accessToken)) {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (options.requireToken === true && !token) {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function findRecentFramePayload(device, frameKind, options = {}) {
|
|
505
|
+
const kind = frameKind === 'thumbnail' ? 'thumbnail' : 'live';
|
|
506
|
+
const latest = kind === 'thumbnail'
|
|
507
|
+
? device?.latestThumbnail
|
|
508
|
+
: device?.latestLiveFrame;
|
|
509
|
+
if (isFramePayloadRequestMatch(latest, options)) {
|
|
510
|
+
return latest;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const token = safeString(options.token, 128);
|
|
514
|
+
const requestedSeq = Number(options.frameSeq);
|
|
515
|
+
if (!token && !Number.isFinite(requestedSeq)) {
|
|
516
|
+
return null;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const cache = getRecentFrameCache(device, kind);
|
|
520
|
+
if (!cache) {
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
pruneRecentFrameCache(cache, kind);
|
|
525
|
+
const entry = cache.find(item => isFramePayloadRequestMatch(item?.frame, options));
|
|
526
|
+
return entry?.frame || null;
|
|
527
|
+
}
|
|
528
|
+
|
|
377
529
|
function serializeDevice(device, options = {}) {
|
|
378
530
|
if (!device) {
|
|
379
531
|
return null;
|
|
@@ -809,6 +961,7 @@ export function createRemoteHub(options = {}) {
|
|
|
809
961
|
delete frame.mode;
|
|
810
962
|
delete frame.fps;
|
|
811
963
|
device.latestThumbnail = frame;
|
|
964
|
+
rememberRecentFramePayload(device, 'thumbnail', frame);
|
|
812
965
|
device.lastSeenAt = frame.receivedAt;
|
|
813
966
|
device.counters.thumbnailFramesReceived += 1;
|
|
814
967
|
emitRemoteEvent('RemoteFrameReceived', device, {
|
|
@@ -831,6 +984,7 @@ export function createRemoteHub(options = {}) {
|
|
|
831
984
|
fps: options.fps || device.activeLiveStream.fps
|
|
832
985
|
});
|
|
833
986
|
device.latestLiveFrame = frame;
|
|
987
|
+
rememberRecentFramePayload(device, 'live', frame);
|
|
834
988
|
device.activeLiveStream.lastFrameAt = frame.receivedAt;
|
|
835
989
|
device.activeLiveStream.lastFrameSeq = frame.frameSeq;
|
|
836
990
|
device.activeLiveStream.framesReceived = (device.activeLiveStream.framesReceived || 0) + 1;
|
|
@@ -968,6 +1122,10 @@ export function createRemoteHub(options = {}) {
|
|
|
968
1122
|
},
|
|
969
1123
|
latestThumbnail: null,
|
|
970
1124
|
latestLiveFrame: null,
|
|
1125
|
+
recentFramePayloads: {
|
|
1126
|
+
thumbnail: [],
|
|
1127
|
+
live: []
|
|
1128
|
+
},
|
|
971
1129
|
activeLiveStream: null,
|
|
972
1130
|
latestTask,
|
|
973
1131
|
recentTasks: latestTask ? [latestTask] : [],
|
|
@@ -992,6 +1150,7 @@ export function createRemoteHub(options = {}) {
|
|
|
992
1150
|
frame.receivedAt = seenAt;
|
|
993
1151
|
frame.capturedAt = seenAt;
|
|
994
1152
|
device.latestThumbnail = frame;
|
|
1153
|
+
rememberRecentFramePayload(device, 'thumbnail', frame);
|
|
995
1154
|
device.counters.thumbnailFramesReceived = 1;
|
|
996
1155
|
}
|
|
997
1156
|
|
|
@@ -1074,6 +1233,10 @@ export function createRemoteHub(options = {}) {
|
|
|
1074
1233
|
status: {},
|
|
1075
1234
|
latestThumbnail: null,
|
|
1076
1235
|
latestLiveFrame: null,
|
|
1236
|
+
recentFramePayloads: {
|
|
1237
|
+
thumbnail: [],
|
|
1238
|
+
live: []
|
|
1239
|
+
},
|
|
1077
1240
|
activeLiveStream: null,
|
|
1078
1241
|
latestTask: null,
|
|
1079
1242
|
recentTasks: [],
|
|
@@ -1545,6 +1708,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1545
1708
|
payload,
|
|
1546
1709
|
accessToken: createFrameAccessToken()
|
|
1547
1710
|
};
|
|
1711
|
+
rememberRecentFramePayload(device, 'thumbnail', device.latestThumbnail);
|
|
1548
1712
|
device.counters.thumbnailFramesReceived += 1;
|
|
1549
1713
|
emitRemoteEvent('RemoteFrameReceived', device, {
|
|
1550
1714
|
streamId: device.latestThumbnail.streamId,
|
|
@@ -1615,6 +1779,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1615
1779
|
payload,
|
|
1616
1780
|
accessToken: createFrameAccessToken()
|
|
1617
1781
|
};
|
|
1782
|
+
rememberRecentFramePayload(device, 'live', device.latestLiveFrame);
|
|
1618
1783
|
device.activeLiveStream.lastFrameAt = device.lastSeenAt;
|
|
1619
1784
|
device.activeLiveStream.lastFrameSeq = frameSeq;
|
|
1620
1785
|
device.activeLiveStream.framesReceived = (device.activeLiveStream.framesReceived || 0) + 1;
|
|
@@ -2376,29 +2541,18 @@ export function createRemoteHub(options = {}) {
|
|
|
2376
2541
|
|
|
2377
2542
|
function getFramePayload(deviceId, frameKind, options = {}) {
|
|
2378
2543
|
const device = devices.get(String(deviceId || ''));
|
|
2379
|
-
|
|
2380
|
-
? device?.latestThumbnail
|
|
2381
|
-
: device?.latestLiveFrame;
|
|
2382
|
-
if (!frame || !Buffer.isBuffer(frame.payload)) {
|
|
2383
|
-
return null;
|
|
2384
|
-
}
|
|
2385
|
-
|
|
2386
|
-
const requestedSeq = Number(options.frameSeq);
|
|
2387
|
-
if (Number.isFinite(requestedSeq) && Math.floor(requestedSeq) !== frame.frameSeq) {
|
|
2388
|
-
return null;
|
|
2389
|
-
}
|
|
2390
|
-
|
|
2391
|
-
const token = safeString(options.token, 128);
|
|
2392
|
-
if (token && !timingSafeStringEqual(token, frame.accessToken)) {
|
|
2544
|
+
if (!device) {
|
|
2393
2545
|
return null;
|
|
2394
2546
|
}
|
|
2395
2547
|
|
|
2396
|
-
|
|
2548
|
+
const kind = frameKind === 'thumbnail' ? 'thumbnail' : 'live';
|
|
2549
|
+
const frame = findRecentFramePayload(device, kind, options);
|
|
2550
|
+
if (!frame) {
|
|
2397
2551
|
return null;
|
|
2398
2552
|
}
|
|
2399
2553
|
|
|
2400
2554
|
return {
|
|
2401
|
-
frame: serializeRemoteFrame(frame, device.deviceId,
|
|
2555
|
+
frame: serializeRemoteFrame(frame, device.deviceId, kind, { includeDataUrl: false }),
|
|
2402
2556
|
payload: frame.payload,
|
|
2403
2557
|
mimeType: safeString(frame.mimeType || frame.format || 'application/octet-stream', 120) || 'application/octet-stream',
|
|
2404
2558
|
byteLength: frame.payload.length
|
|
@@ -143,6 +143,8 @@ try {
|
|
|
143
143
|
});
|
|
144
144
|
assert.equal(thumbnailDevice.latestThumbnail.streamId, 'smoke-thumb');
|
|
145
145
|
assert.equal(thumbnailDevice.counters.thumbnailFramesReceived, 1);
|
|
146
|
+
const serializedFirstThumbnail = hub.getDeviceThumbnail('smoke-device', { includeDataUrl: false });
|
|
147
|
+
const serializedFirstThumbnailUrl = new URL(serializedFirstThumbnail.framePath, 'http://127.0.0.1');
|
|
146
148
|
|
|
147
149
|
const binaryThumbnailCommand = hub.requestThumbnail('smoke-device', {
|
|
148
150
|
streamId: 'smoke-thumb-binary',
|
|
@@ -190,6 +192,14 @@ try {
|
|
|
190
192
|
assert.equal(thumbnailPayload?.mimeType, 'image/png');
|
|
191
193
|
assert.equal(thumbnailPayload?.byteLength, smokePngFrame.length);
|
|
192
194
|
assert.equal(Buffer.compare(thumbnailPayload.payload, smokePngFrame), 0);
|
|
195
|
+
const retainedThumbnailPayload = hub.getFramePayload('smoke-device', 'thumbnail', {
|
|
196
|
+
token: serializedFirstThumbnailUrl.searchParams.get('token'),
|
|
197
|
+
frameSeq: serializedFirstThumbnailUrl.searchParams.get('seq'),
|
|
198
|
+
requireToken: true
|
|
199
|
+
});
|
|
200
|
+
assert.equal(retainedThumbnailPayload?.frame?.frameSeq, 1);
|
|
201
|
+
assert.equal(retainedThumbnailPayload?.byteLength, smokePngFrame.length);
|
|
202
|
+
assert.equal(Buffer.compare(retainedThumbnailPayload.payload, smokePngFrame), 0);
|
|
193
203
|
assert.equal(hub.getFramePayload('smoke-device', 'thumbnail', {
|
|
194
204
|
token: 'wrong-token',
|
|
195
205
|
frameSeq: 4,
|
|
@@ -225,6 +235,8 @@ try {
|
|
|
225
235
|
assert.equal(liveDevice.activeLiveStream.active, true);
|
|
226
236
|
assert.equal(liveDevice.latestLiveFrame.mode, 'remote-fast');
|
|
227
237
|
assert.equal(liveDevice.counters.liveFramesReceived, 1);
|
|
238
|
+
const serializedFirstLiveFrame = hub.getDeviceLiveFrame('smoke-device', { includeDataUrl: false });
|
|
239
|
+
const serializedFirstLiveUrl = new URL(serializedFirstLiveFrame.framePath, 'http://127.0.0.1');
|
|
228
240
|
|
|
229
241
|
writeBinaryFrame(socket, {
|
|
230
242
|
frameKind: 'stream',
|
|
@@ -267,6 +279,14 @@ try {
|
|
|
267
279
|
assert.equal(livePayload?.mimeType, 'image/png');
|
|
268
280
|
assert.equal(livePayload?.byteLength, smokePngFrame.length);
|
|
269
281
|
assert.equal(Buffer.compare(livePayload.payload, smokePngFrame), 0);
|
|
282
|
+
const retainedLivePayload = hub.getFramePayload('smoke-device', 'live', {
|
|
283
|
+
token: serializedFirstLiveUrl.searchParams.get('token'),
|
|
284
|
+
frameSeq: serializedFirstLiveUrl.searchParams.get('seq'),
|
|
285
|
+
requireToken: true
|
|
286
|
+
});
|
|
287
|
+
assert.equal(retainedLivePayload?.frame?.frameSeq, 2);
|
|
288
|
+
assert.equal(retainedLivePayload?.byteLength, smokePngFrame.length);
|
|
289
|
+
assert.equal(Buffer.compare(retainedLivePayload.payload, smokePngFrame), 0);
|
|
270
290
|
assert.equal(hub.getFramePayload('smoke-device', 'live', {
|
|
271
291
|
token: serializedLiveUrl.searchParams.get('token'),
|
|
272
292
|
frameSeq: 4,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const DEBUG = false;
|
|
6
6
|
const FPS_DEBUG = false;
|
|
7
7
|
const FRAME_PERF_DEBUG = false;
|
|
8
|
-
const MINDMAP_CORE_BUILD_ID = '20260616-
|
|
8
|
+
const MINDMAP_CORE_BUILD_ID = '20260616-mdm-simple-monitor-border-v567';
|
|
9
9
|
const CanvasPhase = Object.freeze({
|
|
10
10
|
Booting: 'booting',
|
|
11
11
|
BoardFileLoading: 'board-file-loading',
|
|
@@ -13336,9 +13336,9 @@
|
|
|
13336
13336
|
min-height: ${metrics.emptyMinHeight}px;
|
|
13337
13337
|
box-sizing: border-box;
|
|
13338
13338
|
border-radius: 8px;
|
|
13339
|
-
border: 1px solid rgba(203, 213, 225, 0.
|
|
13339
|
+
border: 1px solid rgba(203, 213, 225, 0.66);
|
|
13340
13340
|
background: #ffffff;
|
|
13341
|
-
box-shadow:
|
|
13341
|
+
box-shadow: none;
|
|
13342
13342
|
`;
|
|
13343
13343
|
shell.appendChild(screen);
|
|
13344
13344
|
}
|
|
@@ -16084,7 +16084,8 @@
|
|
|
16084
16084
|
overflow: hidden;
|
|
16085
16085
|
border-radius: ${isDetail ? '8px' : '6px'};
|
|
16086
16086
|
background: ${(hasLiveFrame || hasThumbnail) ? 'linear-gradient(135deg, #0f172a 0%, #1e293b 100%)' : '#ffffff'};
|
|
16087
|
-
border: 1px solid rgba(
|
|
16087
|
+
border: 1px solid rgba(148, 163, 184, ${isDetail ? '0.34' : '0.24'});
|
|
16088
|
+
box-shadow: none;
|
|
16088
16089
|
`;
|
|
16089
16090
|
|
|
16090
16091
|
if (hasLiveFrame || hasThumbnail) {
|
|
@@ -16254,16 +16255,22 @@
|
|
|
16254
16255
|
aspect-ratio: 16 / 9;
|
|
16255
16256
|
box-sizing: border-box;
|
|
16256
16257
|
overflow: hidden;
|
|
16257
|
-
padding:
|
|
16258
|
+
padding: 0;
|
|
16258
16259
|
border-radius: 8px;
|
|
16259
|
-
background:
|
|
16260
|
-
border:
|
|
16261
|
-
box-shadow:
|
|
16260
|
+
background: transparent;
|
|
16261
|
+
border: 0;
|
|
16262
|
+
box-shadow: none;
|
|
16263
|
+
outline: 0;
|
|
16262
16264
|
cursor: pointer;
|
|
16263
16265
|
pointer-events: auto;
|
|
16264
16266
|
user-select: none;
|
|
16265
16267
|
`;
|
|
16266
|
-
|
|
16268
|
+
const preview = createDevicePreview(device, 'tile');
|
|
16269
|
+
if (isSelected) {
|
|
16270
|
+
preview.style.borderColor = 'rgba(37, 99, 235, 0.86)';
|
|
16271
|
+
preview.style.boxShadow = '0 0 0 1px rgba(37, 99, 235, 0.20)';
|
|
16272
|
+
}
|
|
16273
|
+
card.appendChild(preview);
|
|
16267
16274
|
grid.appendChild(card);
|
|
16268
16275
|
});
|
|
16269
16276
|
|
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=20260616-
|
|
11
|
-
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260616-
|
|
10
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/app.css?v=20260616-mdm-simple-monitor-border-v567" />
|
|
11
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260616-mdm-simple-monitor-border-v567" />
|
|
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-
|
|
582
|
+
const scriptVersion = '20260616-mdm-simple-monitor-border-v567';
|
|
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": "lm4IaYy/",
|
|
3
3
|
"assets": [
|
|
4
4
|
{
|
|
5
5
|
"hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"url": "_content/MindExecution.Shared/js/marked.min.js"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
|
-
"hash": "sha256-
|
|
81
|
+
"hash": "sha256-xoC/V6bym09C2/PSsXrMNa7JA6xWQTFq5RNRA+nojVs=",
|
|
82
82
|
"url": "_content/MindExecution.Shared/js/mind-map-core.js"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
@@ -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-3PsDD8j+YZE2SU7MQscT9DHl+zbP9r2NCCW6p8DzvOA=",
|
|
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-dsplZ/RaSr9+idAqCQA85yTQKyHFVw9MkMndOJpXrAQ=",
|
|
838
838
|
"url": "index.html"
|
|
839
839
|
},
|
|
840
840
|
{
|