@mindexec/cli 0.2.118 → 0.2.120
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 +5 -7
- package/scripts/remote-http-smoke.mjs +14 -2
- package/scripts/remote-hub-scale-smoke.mjs +6 -1
- package/server.js +531 -50
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +171 -50
- package/wwwroot/_framework/{MindExecution.Shared.e8lipb57xv.dll → MindExecution.Shared.uwkrc41o75.dll} +0 -0
- package/wwwroot/_framework/blazor.boot.json +3 -3
- package/wwwroot/index.html +3 -3
- package/wwwroot/service-worker-assets.js +6 -6
- package/wwwroot/service-worker.js +1 -1
package/package.json
CHANGED
package/remote-hub.js
CHANGED
|
@@ -372,8 +372,8 @@ function serializeRemoteFrame(frame, deviceId, frameKind, options = {}) {
|
|
|
372
372
|
framePath,
|
|
373
373
|
frameUrl: framePath
|
|
374
374
|
};
|
|
375
|
-
if (options.includeDataUrl
|
|
376
|
-
serialized.dataUrl = dataUrl;
|
|
375
|
+
if (options.includeDataUrl === true) {
|
|
376
|
+
serialized.dataUrl = dataUrl || buildFrameDataUrl(payload, '', publicFrame.mimeType || publicFrame.format || 'image/jpeg');
|
|
377
377
|
}
|
|
378
378
|
|
|
379
379
|
return serialized;
|
|
@@ -1114,7 +1114,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1114
1114
|
|
|
1115
1115
|
function listDevices(options = {}) {
|
|
1116
1116
|
const serializeOptions = {
|
|
1117
|
-
includeDataUrl: options.includeDataUrl
|
|
1117
|
+
includeDataUrl: options.includeDataUrl === true
|
|
1118
1118
|
};
|
|
1119
1119
|
return [...devices.values()]
|
|
1120
1120
|
.map(device => serializeDevice(device, serializeOptions))
|
|
@@ -1969,7 +1969,6 @@ export function createRemoteHub(options = {}) {
|
|
|
1969
1969
|
contentHash,
|
|
1970
1970
|
captureMs: readFrameCaptureMs(message),
|
|
1971
1971
|
sameContentStreak,
|
|
1972
|
-
dataUrl: buildFrameDataUrl(framePayload, frameData, mimeType),
|
|
1973
1972
|
payload,
|
|
1974
1973
|
accessToken: createFrameAccessToken()
|
|
1975
1974
|
};
|
|
@@ -2040,7 +2039,6 @@ export function createRemoteHub(options = {}) {
|
|
|
2040
2039
|
contentHash,
|
|
2041
2040
|
captureMs: readFrameCaptureMs(message),
|
|
2042
2041
|
sameContentStreak,
|
|
2043
|
-
dataUrl: buildFrameDataUrl(framePayload, frameData, mimeType),
|
|
2044
2042
|
payload,
|
|
2045
2043
|
accessToken: createFrameAccessToken()
|
|
2046
2044
|
};
|
|
@@ -2961,14 +2959,14 @@ export function createRemoteHub(options = {}) {
|
|
|
2961
2959
|
function getDeviceLiveFrame(deviceId, options = {}) {
|
|
2962
2960
|
const device = devices.get(String(deviceId || ''));
|
|
2963
2961
|
return serializeRemoteFrame(device?.latestLiveFrame, device?.deviceId, 'live', {
|
|
2964
|
-
includeDataUrl: options.includeDataUrl
|
|
2962
|
+
includeDataUrl: options.includeDataUrl === true
|
|
2965
2963
|
});
|
|
2966
2964
|
}
|
|
2967
2965
|
|
|
2968
2966
|
function getDeviceThumbnail(deviceId, options = {}) {
|
|
2969
2967
|
const device = devices.get(String(deviceId || ''));
|
|
2970
2968
|
return serializeRemoteFrame(device?.latestThumbnail, device?.deviceId, 'thumbnail', {
|
|
2971
|
-
includeDataUrl: options.includeDataUrl
|
|
2969
|
+
includeDataUrl: options.includeDataUrl === true
|
|
2972
2970
|
});
|
|
2973
2971
|
}
|
|
2974
2972
|
|
|
@@ -373,10 +373,16 @@ async function runSyntheticEnabledSmoke() {
|
|
|
373
373
|
});
|
|
374
374
|
assert.equal(thumbnail.ok, true, JSON.stringify(thumbnail.payload));
|
|
375
375
|
assert.equal(thumbnail.payload?.thumbnail?.streamId, 'http-smoke-thumb');
|
|
376
|
-
assert.ok(
|
|
376
|
+
assert.ok(!('dataUrl' in thumbnail.payload.thumbnail));
|
|
377
377
|
assert.ok(String(thumbnail.payload?.thumbnail?.framePath || '').includes(`/api/remote/devices/${encodeURIComponent(thumbnailTarget.deviceId)}/thumbnail?`));
|
|
378
378
|
assert.equal(thumbnail.payload?.thumbnail?.frameUrl, thumbnail.payload?.thumbnail?.framePath);
|
|
379
379
|
|
|
380
|
+
const thumbnailWithData = await fetchJson(`${baseUrl}/api/remote/devices/${encodeURIComponent(thumbnailTarget.deviceId)}/thumbnail?includeDataUrl=true`, {
|
|
381
|
+
token: BRIDGE_TOKEN
|
|
382
|
+
});
|
|
383
|
+
assert.equal(thumbnailWithData.ok, true, JSON.stringify(thumbnailWithData.payload));
|
|
384
|
+
assert.ok(String(thumbnailWithData.payload?.thumbnail?.dataUrl || '').startsWith('data:image/png;base64,'));
|
|
385
|
+
|
|
380
386
|
const thumbnailBinary = await fetchBinary(`${baseUrl}${thumbnail.payload.thumbnail.framePath}`);
|
|
381
387
|
assert.equal(thumbnailBinary.ok, true, `${thumbnailBinary.status} ${thumbnailBinary.contentType}`);
|
|
382
388
|
assert.equal(thumbnailBinary.contentType, 'image/png');
|
|
@@ -433,9 +439,15 @@ async function runSyntheticEnabledSmoke() {
|
|
|
433
439
|
assert.equal(liveFrame.payload?.frame?.streamId, 'http-smoke-live');
|
|
434
440
|
assert.equal(liveFrame.payload?.frame?.mode, 'remote-fast');
|
|
435
441
|
assert.equal(liveFrame.payload?.frame?.fps, 20);
|
|
436
|
-
assert.ok(
|
|
442
|
+
assert.ok(!('dataUrl' in liveFrame.payload.frame));
|
|
437
443
|
assert.ok(String(liveFrame.payload?.frame?.framePath || '').includes(`/api/remote/devices/${encodeURIComponent(liveTarget.deviceId)}/live/frame?`));
|
|
438
444
|
|
|
445
|
+
const liveFrameWithData = await fetchJson(`${baseUrl}/api/remote/devices/${encodeURIComponent(liveTarget.deviceId)}/live/frame?includeDataUrl=true`, {
|
|
446
|
+
token: BRIDGE_TOKEN
|
|
447
|
+
});
|
|
448
|
+
assert.equal(liveFrameWithData.ok, true, JSON.stringify(liveFrameWithData.payload));
|
|
449
|
+
assert.ok(String(liveFrameWithData.payload?.frame?.dataUrl || '').startsWith('data:image/png;base64,'));
|
|
450
|
+
|
|
439
451
|
const liveBinary = await fetchBinary(`${baseUrl}${liveFrame.payload.frame.framePath}`);
|
|
440
452
|
assert.equal(liveBinary.ok, true, `${liveBinary.status} ${liveBinary.contentType}`);
|
|
441
453
|
assert.equal(liveBinary.contentType, 'image/png');
|
|
@@ -37,9 +37,12 @@ try {
|
|
|
37
37
|
assert.equal(devices.length, SYNTHETIC_COUNT);
|
|
38
38
|
assert.equal(devices.filter(device => device.synthetic === true).length, SYNTHETIC_COUNT);
|
|
39
39
|
assert.equal(devices.some(device => device.connected === false), true);
|
|
40
|
-
assert.equal(devices.some(device => device.latestThumbnail
|
|
40
|
+
assert.equal(devices.some(device => device.latestThumbnail && 'dataUrl' in device.latestThumbnail), false);
|
|
41
41
|
assert.equal(devices.some(device => device.activeLiveStream?.active === true), true);
|
|
42
42
|
|
|
43
|
+
const devicesWithDataUrl = hub.listDevices({ includeDataUrl: true });
|
|
44
|
+
assert.equal(devicesWithDataUrl.some(device => device.latestThumbnail?.dataUrl), true);
|
|
45
|
+
|
|
43
46
|
const deviceListPayload = {
|
|
44
47
|
total: devices.length,
|
|
45
48
|
pagination: 'none',
|
|
@@ -58,6 +61,8 @@ try {
|
|
|
58
61
|
});
|
|
59
62
|
assert.equal(thumbnailResult.ok, true);
|
|
60
63
|
assert.equal(hub.getDeviceThumbnail(thumbnailTarget.deviceId).streamId, 'scale-thumb');
|
|
64
|
+
assert.equal('dataUrl' in hub.getDeviceThumbnail(thumbnailTarget.deviceId), false);
|
|
65
|
+
assert.ok(hub.getDeviceThumbnail(thumbnailTarget.deviceId, { includeDataUrl: true }).dataUrl);
|
|
61
66
|
|
|
62
67
|
const liveTarget = devices.find(device => device.connected && device.capabilities?.liveStream);
|
|
63
68
|
assert.ok(liveTarget);
|
package/server.js
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
import express from 'express';
|
|
10
10
|
import cors from 'cors';
|
|
11
|
-
import { promises as fs, readFileSync, statSync, createReadStream } from 'fs';
|
|
11
|
+
import { promises as fs, readFileSync, statSync, createReadStream, chmodSync } from 'fs';
|
|
12
12
|
import path from 'path';
|
|
13
|
-
import { exec, spawn, execFile } from 'child_process';
|
|
13
|
+
import { exec, spawn, spawnSync, execFile } from 'child_process';
|
|
14
14
|
import { promisify } from 'util';
|
|
15
15
|
import os from 'os';
|
|
16
16
|
import multer from 'multer';
|
|
@@ -2907,10 +2907,14 @@ const REMOTE_AGENT_EARLY_EXIT_MS = 1200;
|
|
|
2907
2907
|
const REMOTE_AGENT_READY_TIMEOUT_MS = 5000;
|
|
2908
2908
|
const REMOTE_AGENT_DEFAULT_ENGINE = 'auto';
|
|
2909
2909
|
const REMOTE_AGENT_SYNC_REPORT_LOG_REPEAT_MS = 30000;
|
|
2910
|
+
const REMOTE_AGENT_RACE_START_STAGGER_MS = 120;
|
|
2911
|
+
const REMOTE_AGENT_MAX_PARALLEL_CANDIDATES = 6;
|
|
2910
2912
|
let remoteAgentState = createRemoteAgentIdleState();
|
|
2911
2913
|
let remoteAgentSyncReportState = null;
|
|
2912
2914
|
let remoteAgentSyncReportLogKey = '';
|
|
2913
2915
|
let remoteAgentSyncReportLogAt = 0;
|
|
2916
|
+
let remoteAgentConnectPromise = null;
|
|
2917
|
+
const remoteAgentRecentSuccessfulManagers = new Map();
|
|
2914
2918
|
|
|
2915
2919
|
function createRemoteAgentIdleState(overrides = {}) {
|
|
2916
2920
|
return {
|
|
@@ -3211,6 +3215,46 @@ function createRemoteAgentConnectionKey(manager, leaseId) {
|
|
|
3211
3215
|
.slice(0, 24);
|
|
3212
3216
|
}
|
|
3213
3217
|
|
|
3218
|
+
function getRemoteAgentRecentManagerKey(leaseId = '') {
|
|
3219
|
+
return safeRemoteAgentField(leaseId || 'default', 128) || 'default';
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
function rememberRemoteAgentSuccessfulManager(manager, leaseId = '') {
|
|
3223
|
+
const endpoint = normalizeRemoteManagerEndpoint(manager);
|
|
3224
|
+
if (!endpoint) {
|
|
3225
|
+
return;
|
|
3226
|
+
}
|
|
3227
|
+
|
|
3228
|
+
remoteAgentRecentSuccessfulManagers.set(getRemoteAgentRecentManagerKey(leaseId), {
|
|
3229
|
+
endpoint,
|
|
3230
|
+
updatedAt: Date.now()
|
|
3231
|
+
});
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
function prioritizeRemoteAgentManagers(managers, leaseId = '') {
|
|
3235
|
+
const normalized = normalizeRemoteManagerEndpointList(managers);
|
|
3236
|
+
if (normalized.length <= 1) {
|
|
3237
|
+
return normalized;
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
const recent = remoteAgentRecentSuccessfulManagers.get(getRemoteAgentRecentManagerKey(leaseId));
|
|
3241
|
+
const recentEndpoint = normalizeRemoteManagerEndpoint(recent?.endpoint);
|
|
3242
|
+
if (!recentEndpoint) {
|
|
3243
|
+
return normalized;
|
|
3244
|
+
}
|
|
3245
|
+
|
|
3246
|
+
const recentIndex = normalized.findIndex(item => item.toLowerCase() === recentEndpoint.toLowerCase());
|
|
3247
|
+
if (recentIndex <= 0) {
|
|
3248
|
+
return normalized;
|
|
3249
|
+
}
|
|
3250
|
+
|
|
3251
|
+
return [
|
|
3252
|
+
normalized[recentIndex],
|
|
3253
|
+
...normalized.slice(0, recentIndex),
|
|
3254
|
+
...normalized.slice(recentIndex + 1)
|
|
3255
|
+
];
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3214
3258
|
function isRemoteAgentProcessRunning() {
|
|
3215
3259
|
const proc = remoteAgentState.proc;
|
|
3216
3260
|
return remoteAgentState.status === 'running'
|
|
@@ -3225,19 +3269,183 @@ function isLocalRemoteHostTargetActive() {
|
|
|
3225
3269
|
&& (!status.hostTargetHostInstanceId || status.hostTargetHostInstanceId === BRIDGE_INSTANCE_ID);
|
|
3226
3270
|
}
|
|
3227
3271
|
|
|
3228
|
-
function
|
|
3229
|
-
const
|
|
3230
|
-
|
|
3231
|
-
|
|
3272
|
+
function getRemoteFastRuntimeId() {
|
|
3273
|
+
const platform = process.platform;
|
|
3274
|
+
const arch = process.arch;
|
|
3275
|
+
if (platform === 'win32' && arch === 'x64') {
|
|
3276
|
+
return 'win-x64';
|
|
3277
|
+
}
|
|
3278
|
+
if (platform === 'darwin' && arch === 'arm64') {
|
|
3279
|
+
return 'osx-arm64';
|
|
3280
|
+
}
|
|
3281
|
+
if (platform === 'darwin' && arch === 'x64') {
|
|
3282
|
+
return 'osx-x64';
|
|
3283
|
+
}
|
|
3284
|
+
return '';
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
function getRemoteFastRuntimeExecutableName() {
|
|
3288
|
+
return process.platform === 'win32'
|
|
3289
|
+
? 'mindexec-remote-fast.exe'
|
|
3290
|
+
: 'mindexec-remote-fast';
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
function getBundledRemoteFastRuntimeDirs() {
|
|
3294
|
+
const rid = getRemoteFastRuntimeId();
|
|
3295
|
+
if (!rid) {
|
|
3296
|
+
return [];
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
return [
|
|
3300
|
+
path.join(BRIDGE_ROOT, 'remote-fast', rid),
|
|
3301
|
+
path.join(BRIDGE_ROOT, 'remote', 'fast', rid),
|
|
3302
|
+
path.join(BRIDGE_ROOT, 'node_modules', '@mindexec', 'remote', 'fast', rid),
|
|
3303
|
+
path.resolve(BRIDGE_ROOT, '..', 'remote', 'fast', rid),
|
|
3304
|
+
path.resolve(BRIDGE_ROOT, '..', 'RemoteAgent', 'fast', rid)
|
|
3305
|
+
];
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3308
|
+
function resolveRemoteFastLauncher() {
|
|
3309
|
+
const rid = getRemoteFastRuntimeId();
|
|
3310
|
+
if (!rid) {
|
|
3311
|
+
return {
|
|
3312
|
+
ok: false,
|
|
3313
|
+
error: `remote-fast-not-packaged:${process.platform}-${process.arch}`
|
|
3314
|
+
};
|
|
3315
|
+
}
|
|
3316
|
+
|
|
3317
|
+
const failures = [];
|
|
3318
|
+
const seen = new Set();
|
|
3319
|
+
for (const dir of getBundledRemoteFastRuntimeDirs()) {
|
|
3320
|
+
const resolvedDir = path.resolve(dir);
|
|
3321
|
+
const key = resolvedDir.toLowerCase();
|
|
3322
|
+
if (seen.has(key)) {
|
|
3323
|
+
continue;
|
|
3324
|
+
}
|
|
3325
|
+
seen.add(key);
|
|
3326
|
+
|
|
3327
|
+
const executable = path.join(resolvedDir, getRemoteFastRuntimeExecutableName());
|
|
3328
|
+
try {
|
|
3329
|
+
if (statSync(executable).isFile()) {
|
|
3330
|
+
if (process.platform !== 'win32') {
|
|
3331
|
+
try {
|
|
3332
|
+
const currentMode = statSync(executable).mode;
|
|
3333
|
+
chmodSync(executable, currentMode | 0o755);
|
|
3334
|
+
} catch {
|
|
3335
|
+
// best effort only
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
const preflight = spawnSync(executable, ['--version'], {
|
|
3340
|
+
encoding: 'utf8',
|
|
3341
|
+
windowsHide: true,
|
|
3342
|
+
timeout: 2500
|
|
3343
|
+
});
|
|
3344
|
+
if (preflight.status === 0) {
|
|
3345
|
+
return {
|
|
3346
|
+
ok: true,
|
|
3347
|
+
command: executable,
|
|
3348
|
+
argsPrefix: [],
|
|
3349
|
+
launcher: executable,
|
|
3350
|
+
usingNpx: false,
|
|
3351
|
+
directFast: true,
|
|
3352
|
+
rid
|
|
3353
|
+
};
|
|
3354
|
+
}
|
|
3355
|
+
failures.push(`${executable}:exit:${preflight.status}`);
|
|
3356
|
+
}
|
|
3357
|
+
} catch {
|
|
3358
|
+
// Try DLL or next directory.
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
const dll = path.join(resolvedDir, 'mindexec-remote-fast.dll');
|
|
3362
|
+
try {
|
|
3363
|
+
if (statSync(dll).isFile()) {
|
|
3364
|
+
const preflight = spawnSync('dotnet', [dll, '--version'], {
|
|
3365
|
+
encoding: 'utf8',
|
|
3366
|
+
windowsHide: true,
|
|
3367
|
+
timeout: 2500
|
|
3368
|
+
});
|
|
3369
|
+
if (preflight.status === 0) {
|
|
3370
|
+
return {
|
|
3371
|
+
ok: true,
|
|
3372
|
+
command: 'dotnet',
|
|
3373
|
+
argsPrefix: [dll],
|
|
3374
|
+
launcher: dll,
|
|
3375
|
+
usingNpx: false,
|
|
3376
|
+
directFast: true,
|
|
3377
|
+
rid
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
failures.push(`${dll}:exit:${preflight.status}`);
|
|
3381
|
+
}
|
|
3382
|
+
} catch {
|
|
3383
|
+
// Try next directory.
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
|
|
3387
|
+
return {
|
|
3388
|
+
ok: false,
|
|
3389
|
+
error: failures.length > 0
|
|
3390
|
+
? failures.join('; ')
|
|
3391
|
+
: `remote-fast-runtime-missing:${rid}`
|
|
3392
|
+
};
|
|
3393
|
+
}
|
|
3394
|
+
|
|
3395
|
+
function resolveLocalRemotePackageLaunchers() {
|
|
3396
|
+
return [
|
|
3397
|
+
path.join(BRIDGE_ROOT, 'remote', 'bin', 'mindexec-remote.js'),
|
|
3398
|
+
path.join(BRIDGE_ROOT, 'node_modules', '@mindexec', 'remote', 'bin', 'mindexec-remote.js'),
|
|
3399
|
+
path.resolve(BRIDGE_ROOT, '..', 'remote', 'bin', 'mindexec-remote.js'),
|
|
3400
|
+
path.resolve(BRIDGE_ROOT, '..', 'RemoteAgent', 'bin', 'mindexec-remote.js')
|
|
3401
|
+
];
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3404
|
+
function resolveRemotePackageLauncher() {
|
|
3405
|
+
const seen = new Set();
|
|
3406
|
+
for (const candidate of resolveLocalRemotePackageLaunchers()) {
|
|
3407
|
+
const resolved = path.resolve(candidate);
|
|
3408
|
+
const key = resolved.toLowerCase();
|
|
3409
|
+
if (seen.has(key)) {
|
|
3410
|
+
continue;
|
|
3411
|
+
}
|
|
3412
|
+
seen.add(key);
|
|
3413
|
+
try {
|
|
3414
|
+
if (statSync(resolved).isFile()) {
|
|
3415
|
+
return {
|
|
3416
|
+
command: process.execPath,
|
|
3417
|
+
argsPrefix: [resolved],
|
|
3418
|
+
launcher: resolved,
|
|
3419
|
+
usingNpx: false,
|
|
3420
|
+
directFast: false
|
|
3421
|
+
};
|
|
3422
|
+
}
|
|
3423
|
+
} catch {
|
|
3424
|
+
// Try next package layout.
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
return null;
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3430
|
+
function resolveRemoteAgentLauncher(engine = REMOTE_AGENT_DEFAULT_ENGINE) {
|
|
3431
|
+
const normalizedEngine = normalizeRemoteAgentEngine(engine);
|
|
3432
|
+
if (normalizedEngine !== 'node') {
|
|
3433
|
+
const fast = resolveRemoteFastLauncher();
|
|
3434
|
+
if (fast.ok) {
|
|
3435
|
+
return fast;
|
|
3436
|
+
}
|
|
3437
|
+
|
|
3438
|
+
if (normalizedEngine === 'fast') {
|
|
3232
3439
|
return {
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
launcher: localLauncher,
|
|
3236
|
-
usingNpx: false
|
|
3440
|
+
ok: false,
|
|
3441
|
+
error: fast.error || 'remote-fast-unavailable'
|
|
3237
3442
|
};
|
|
3238
3443
|
}
|
|
3239
|
-
}
|
|
3240
|
-
|
|
3444
|
+
}
|
|
3445
|
+
|
|
3446
|
+
const localPackage = resolveRemotePackageLauncher();
|
|
3447
|
+
if (localPackage) {
|
|
3448
|
+
return localPackage;
|
|
3241
3449
|
}
|
|
3242
3450
|
|
|
3243
3451
|
const npxCli = resolveNpxCliLauncher();
|
|
@@ -3246,7 +3454,8 @@ function resolveRemoteAgentLauncher() {
|
|
|
3246
3454
|
command: process.execPath,
|
|
3247
3455
|
argsPrefix: [npxCli, '-y', '@mindexec/remote@latest'],
|
|
3248
3456
|
launcher: npxCli,
|
|
3249
|
-
usingNpx: true
|
|
3457
|
+
usingNpx: true,
|
|
3458
|
+
directFast: false
|
|
3250
3459
|
};
|
|
3251
3460
|
}
|
|
3252
3461
|
|
|
@@ -3255,7 +3464,8 @@ function resolveRemoteAgentLauncher() {
|
|
|
3255
3464
|
command: process.env.ComSpec || 'cmd.exe',
|
|
3256
3465
|
argsPrefix: ['/d', '/s', '/c', 'npx.cmd', '-y', '@mindexec/remote@latest'],
|
|
3257
3466
|
launcher: 'cmd.exe /c npx.cmd',
|
|
3258
|
-
usingNpx: true
|
|
3467
|
+
usingNpx: true,
|
|
3468
|
+
directFast: false
|
|
3259
3469
|
};
|
|
3260
3470
|
}
|
|
3261
3471
|
|
|
@@ -3263,7 +3473,8 @@ function resolveRemoteAgentLauncher() {
|
|
|
3263
3473
|
command: 'npx',
|
|
3264
3474
|
argsPrefix: ['-y', '@mindexec/remote@latest'],
|
|
3265
3475
|
launcher: 'npx',
|
|
3266
|
-
usingNpx: true
|
|
3476
|
+
usingNpx: true,
|
|
3477
|
+
directFast: false
|
|
3267
3478
|
};
|
|
3268
3479
|
}
|
|
3269
3480
|
|
|
@@ -3343,11 +3554,11 @@ async function startRemoteAgentConnection(options = {}) {
|
|
|
3343
3554
|
const nodeId = safeRemoteAgentField(options.nodeId, 128);
|
|
3344
3555
|
const source = safeRemoteAgentField(options.source || 'registry', 64);
|
|
3345
3556
|
const engine = normalizeRemoteAgentEngine(options.engine);
|
|
3346
|
-
const managers = normalizeRemoteManagerEndpointList(
|
|
3557
|
+
const managers = prioritizeRemoteAgentManagers(normalizeRemoteManagerEndpointList(
|
|
3347
3558
|
options.manager || options.managerEndpoint || options.endpoint,
|
|
3348
3559
|
options.managerCandidates,
|
|
3349
3560
|
options.endpointCandidates,
|
|
3350
|
-
options.candidates);
|
|
3561
|
+
options.candidates), leaseId);
|
|
3351
3562
|
|
|
3352
3563
|
if (managers.length === 0) {
|
|
3353
3564
|
logWarn('remote', 'managed RemoteAgent connect rejected: invalid manager endpoint');
|
|
@@ -3385,45 +3596,321 @@ async function startRemoteAgentConnection(options = {}) {
|
|
|
3385
3596
|
await stopRemoteAgentConnection('replaced-by-new-target');
|
|
3386
3597
|
}
|
|
3387
3598
|
|
|
3388
|
-
|
|
3599
|
+
if (remoteAgentConnectPromise) {
|
|
3600
|
+
return await remoteAgentConnectPromise;
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3603
|
+
remoteAgentConnectPromise = startRemoteAgentConnectionRace({
|
|
3604
|
+
managers,
|
|
3605
|
+
pairToken,
|
|
3606
|
+
leaseId,
|
|
3607
|
+
nodeId,
|
|
3608
|
+
source,
|
|
3609
|
+
engine
|
|
3610
|
+
}).finally(() => {
|
|
3611
|
+
remoteAgentConnectPromise = null;
|
|
3612
|
+
});
|
|
3613
|
+
return await remoteAgentConnectPromise;
|
|
3614
|
+
}
|
|
3615
|
+
|
|
3616
|
+
function buildRemoteAgentLaunchArgs(launcher, manager, pairToken, engine) {
|
|
3617
|
+
const args = [
|
|
3618
|
+
...launcher.argsPrefix,
|
|
3619
|
+
'connect',
|
|
3620
|
+
'--manager',
|
|
3621
|
+
manager,
|
|
3622
|
+
'--pair',
|
|
3623
|
+
pairToken
|
|
3624
|
+
];
|
|
3625
|
+
|
|
3626
|
+
if (launcher.directFast === true) {
|
|
3627
|
+
args.push('--transport', 'ws');
|
|
3628
|
+
return args;
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
args.push('--engine', engine);
|
|
3632
|
+
return args;
|
|
3633
|
+
}
|
|
3634
|
+
|
|
3635
|
+
function appendRemoteAgentAttemptOutput(attempt, stream, chunk) {
|
|
3636
|
+
const text = chunk.toString();
|
|
3637
|
+
const key = stream === 'stderr' ? 'stderrTail' : 'stdoutTail';
|
|
3638
|
+
attempt.state[key] = String((attempt.state[key] || '') + text).slice(-REMOTE_AGENT_STDIO_TAIL_CHARS);
|
|
3639
|
+
if (/Connected to RemoteHub/i.test(text)) {
|
|
3640
|
+
attempt.state.ready = true;
|
|
3641
|
+
attempt.state.connectedAt = new Date().toISOString();
|
|
3642
|
+
}
|
|
3643
|
+
attempt.state.updatedAt = new Date().toISOString();
|
|
3644
|
+
}
|
|
3645
|
+
|
|
3646
|
+
function summarizeRemoteAgentAttempt(attempt) {
|
|
3647
|
+
return formatRemoteAgentFailureSummary(attempt?.state || {});
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3650
|
+
function createRemoteAgentAttempt(options = {}) {
|
|
3651
|
+
const manager = normalizeRemoteManagerEndpoint(options.manager);
|
|
3652
|
+
const pairToken = safeRemoteAgentField(options.pairToken || options.pair, 512);
|
|
3653
|
+
const leaseId = safeRemoteAgentField(options.leaseId, 128);
|
|
3654
|
+
const nodeId = safeRemoteAgentField(options.nodeId, 128);
|
|
3655
|
+
const source = safeRemoteAgentField(options.source || 'registry', 64);
|
|
3656
|
+
const engine = normalizeRemoteAgentEngine(options.engine);
|
|
3657
|
+
const managerCandidates = normalizeRemoteManagerEndpointList(options.managerCandidates, manager);
|
|
3658
|
+
|
|
3659
|
+
const connectionKey = createRemoteAgentConnectionKey(manager, leaseId);
|
|
3660
|
+
const launcher = options.launcher || resolveRemoteAgentLauncher(engine);
|
|
3661
|
+
if (launcher?.ok === false) {
|
|
3662
|
+
return {
|
|
3663
|
+
manager,
|
|
3664
|
+
failed: true,
|
|
3665
|
+
error: launcher.error || 'remote-agent-launcher-unavailable',
|
|
3666
|
+
state: createRemoteAgentIdleState({
|
|
3667
|
+
status: 'failed',
|
|
3668
|
+
manager,
|
|
3669
|
+
managerCandidates,
|
|
3670
|
+
leaseId,
|
|
3671
|
+
nodeId,
|
|
3672
|
+
engine,
|
|
3673
|
+
source,
|
|
3674
|
+
connectionKey,
|
|
3675
|
+
lastError: launcher.error || 'remote-agent-launcher-unavailable'
|
|
3676
|
+
})
|
|
3677
|
+
};
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3680
|
+
const state = createRemoteAgentIdleState({
|
|
3681
|
+
status: 'starting',
|
|
3682
|
+
manager,
|
|
3683
|
+
managerCandidates,
|
|
3684
|
+
leaseId,
|
|
3685
|
+
nodeId,
|
|
3686
|
+
engine,
|
|
3687
|
+
source,
|
|
3688
|
+
connectionKey,
|
|
3689
|
+
startedAt: new Date().toISOString(),
|
|
3690
|
+
ready: false,
|
|
3691
|
+
connectedAt: '',
|
|
3692
|
+
launcher: launcher.launcher,
|
|
3693
|
+
usingNpx: launcher.usingNpx
|
|
3694
|
+
});
|
|
3695
|
+
|
|
3696
|
+
const args = buildRemoteAgentLaunchArgs(launcher, manager, pairToken, engine);
|
|
3697
|
+
const attempt = {
|
|
3698
|
+
manager,
|
|
3699
|
+
pairToken,
|
|
3700
|
+
leaseId,
|
|
3701
|
+
nodeId,
|
|
3702
|
+
source,
|
|
3703
|
+
engine,
|
|
3704
|
+
launcher,
|
|
3705
|
+
args,
|
|
3706
|
+
state,
|
|
3707
|
+
child: null,
|
|
3708
|
+
failed: false,
|
|
3709
|
+
error: ''
|
|
3710
|
+
};
|
|
3711
|
+
|
|
3712
|
+
try {
|
|
3713
|
+
const child = spawn(launcher.command, args, {
|
|
3714
|
+
cwd: BRIDGE_ROOT,
|
|
3715
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
3716
|
+
windowsHide: true,
|
|
3717
|
+
env: {
|
|
3718
|
+
...process.env,
|
|
3719
|
+
MINDEXEC_REMOTE_AGENT_MANAGED: '1'
|
|
3720
|
+
}
|
|
3721
|
+
});
|
|
3722
|
+
|
|
3723
|
+
attempt.child = child;
|
|
3724
|
+
state.proc = child;
|
|
3725
|
+
state.pid = Number(child.pid || 0);
|
|
3726
|
+
state.status = 'running';
|
|
3727
|
+
state.updatedAt = new Date().toISOString();
|
|
3728
|
+
|
|
3729
|
+
child.stdout.on('data', chunk => appendRemoteAgentAttemptOutput(attempt, 'stdout', chunk));
|
|
3730
|
+
child.stderr.on('data', chunk => appendRemoteAgentAttemptOutput(attempt, 'stderr', chunk));
|
|
3731
|
+
child.once('error', err => {
|
|
3732
|
+
attempt.failed = true;
|
|
3733
|
+
attempt.error = err?.message || String(err);
|
|
3734
|
+
state.status = 'failed';
|
|
3735
|
+
state.lastError = attempt.error;
|
|
3736
|
+
state.updatedAt = new Date().toISOString();
|
|
3737
|
+
});
|
|
3738
|
+
child.once('exit', (code, signal) => {
|
|
3739
|
+
if (state.status === 'running' && state.ready === true) {
|
|
3740
|
+
state.status = code === 0 ? 'exited' : 'failed';
|
|
3741
|
+
} else {
|
|
3742
|
+
attempt.failed = true;
|
|
3743
|
+
state.status = code === 0 ? 'exited' : 'failed';
|
|
3744
|
+
}
|
|
3745
|
+
state.exitCode = Number.isFinite(code) ? code : null;
|
|
3746
|
+
state.signal = signal || '';
|
|
3747
|
+
state.exitedAt = new Date().toISOString();
|
|
3748
|
+
state.updatedAt = state.exitedAt;
|
|
3749
|
+
if (code !== 0 && !state.lastError) {
|
|
3750
|
+
state.lastError = signal ? `signal:${signal}` : `exit:${code}`;
|
|
3751
|
+
}
|
|
3752
|
+
attempt.error = attempt.error || state.lastError || `exit:${code ?? 'unknown'}`;
|
|
3753
|
+
});
|
|
3754
|
+
} catch (err) {
|
|
3755
|
+
attempt.failed = true;
|
|
3756
|
+
attempt.error = err?.message || String(err);
|
|
3757
|
+
state.status = 'failed';
|
|
3758
|
+
state.lastError = attempt.error;
|
|
3759
|
+
state.updatedAt = new Date().toISOString();
|
|
3760
|
+
}
|
|
3761
|
+
|
|
3762
|
+
return attempt;
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
async function stopRemoteAgentAttempt(attempt, reason = 'race-lost') {
|
|
3766
|
+
if (!attempt?.child) {
|
|
3767
|
+
return;
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3770
|
+
if (attempt.child.exitCode !== null || attempt.child.killed) {
|
|
3771
|
+
return;
|
|
3772
|
+
}
|
|
3773
|
+
|
|
3774
|
+
try {
|
|
3775
|
+
await terminateProcessTree(attempt.child);
|
|
3776
|
+
} catch (err) {
|
|
3777
|
+
logWarn('remote', `managed RemoteAgent cleanup failed ${formatKeyValue('manager', attempt.manager || '-')} ${formatKeyValue('reason', reason)} ${formatKeyValue('error', err?.message || err)}`);
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
|
|
3781
|
+
async function startRemoteAgentConnectionRace(options = {}) {
|
|
3782
|
+
const managers = normalizeRemoteManagerEndpointList(options.managers).slice(0, REMOTE_AGENT_MAX_PARALLEL_CANDIDATES);
|
|
3783
|
+
const pairToken = safeRemoteAgentField(options.pairToken || options.pair, 512);
|
|
3784
|
+
const leaseId = safeRemoteAgentField(options.leaseId, 128);
|
|
3785
|
+
const nodeId = safeRemoteAgentField(options.nodeId, 128);
|
|
3786
|
+
const source = safeRemoteAgentField(options.source || 'registry', 64);
|
|
3787
|
+
const engine = normalizeRemoteAgentEngine(options.engine);
|
|
3788
|
+
const launcher = resolveRemoteAgentLauncher(engine);
|
|
3789
|
+
if (launcher?.ok === false) {
|
|
3790
|
+
const error = launcher.error || 'remote-agent-launcher-unavailable';
|
|
3791
|
+
remoteAgentState = createRemoteAgentIdleState({
|
|
3792
|
+
status: 'failed',
|
|
3793
|
+
manager: managers[0] || '',
|
|
3794
|
+
managerCandidates: managers,
|
|
3795
|
+
leaseId,
|
|
3796
|
+
nodeId,
|
|
3797
|
+
engine,
|
|
3798
|
+
source,
|
|
3799
|
+
lastError: error,
|
|
3800
|
+
updatedAt: new Date().toISOString()
|
|
3801
|
+
});
|
|
3802
|
+
emitBridgeEvent('RemoteAgentFailed', serializeRemoteAgentState());
|
|
3803
|
+
return { ok: false, error, agent: serializeRemoteAgentState() };
|
|
3804
|
+
}
|
|
3805
|
+
|
|
3806
|
+
remoteAgentState = createRemoteAgentIdleState({
|
|
3807
|
+
status: 'starting',
|
|
3808
|
+
manager: managers[0] || '',
|
|
3809
|
+
managerCandidates: managers,
|
|
3810
|
+
leaseId,
|
|
3811
|
+
nodeId,
|
|
3812
|
+
engine,
|
|
3813
|
+
source,
|
|
3814
|
+
startedAt: new Date().toISOString(),
|
|
3815
|
+
launcher: 'race',
|
|
3816
|
+
usingNpx: false
|
|
3817
|
+
});
|
|
3818
|
+
|
|
3819
|
+
const attempts = [];
|
|
3389
3820
|
for (let index = 0; index < managers.length; index += 1) {
|
|
3390
3821
|
const manager = managers[index];
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
'remote');
|
|
3396
|
-
}
|
|
3822
|
+
logEvent(
|
|
3823
|
+
'remote',
|
|
3824
|
+
`managed RemoteAgent race ${index + 1}/${managers.length} ${formatKeyValue('manager', manager)}`,
|
|
3825
|
+
'remote');
|
|
3397
3826
|
|
|
3398
|
-
const
|
|
3827
|
+
const attempt = createRemoteAgentAttempt({
|
|
3399
3828
|
manager,
|
|
3400
3829
|
managerCandidates: managers,
|
|
3401
3830
|
pairToken,
|
|
3402
3831
|
leaseId,
|
|
3403
3832
|
nodeId,
|
|
3404
3833
|
source,
|
|
3405
|
-
engine
|
|
3834
|
+
engine,
|
|
3835
|
+
launcher
|
|
3406
3836
|
});
|
|
3407
|
-
|
|
3408
|
-
|
|
3837
|
+
attempts.push(attempt);
|
|
3838
|
+
|
|
3839
|
+
if (index + 1 < managers.length && REMOTE_AGENT_RACE_START_STAGGER_MS > 0) {
|
|
3840
|
+
await new Promise(resolve => setTimeout(resolve, REMOTE_AGENT_RACE_START_STAGGER_MS));
|
|
3409
3841
|
}
|
|
3842
|
+
}
|
|
3410
3843
|
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3844
|
+
const startedAt = Date.now();
|
|
3845
|
+
let winner = null;
|
|
3846
|
+
while (Date.now() - startedAt < REMOTE_AGENT_READY_TIMEOUT_MS) {
|
|
3847
|
+
winner = attempts.find(attempt =>
|
|
3848
|
+
attempt?.state?.ready === true
|
|
3849
|
+
&& attempt?.child
|
|
3850
|
+
&& attempt.child.exitCode === null
|
|
3851
|
+
&& !attempt.child.killed);
|
|
3852
|
+
if (winner) {
|
|
3853
|
+
break;
|
|
3414
3854
|
}
|
|
3415
3855
|
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3856
|
+
const allFinished = attempts.every(attempt =>
|
|
3857
|
+
attempt.failed === true
|
|
3858
|
+
|| !attempt.child
|
|
3859
|
+
|| attempt.child.exitCode !== null
|
|
3860
|
+
|| attempt.child.killed);
|
|
3861
|
+
if (allFinished) {
|
|
3862
|
+
break;
|
|
3420
3863
|
}
|
|
3864
|
+
|
|
3865
|
+
await new Promise(resolve => setTimeout(resolve, 60));
|
|
3421
3866
|
}
|
|
3422
3867
|
|
|
3868
|
+
if (winner) {
|
|
3869
|
+
for (const attempt of attempts) {
|
|
3870
|
+
if (attempt !== winner) {
|
|
3871
|
+
await stopRemoteAgentAttempt(attempt, 'race-lost');
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
remoteAgentState = winner.state;
|
|
3876
|
+
remoteAgentState.status = 'running';
|
|
3877
|
+
remoteAgentState.proc = winner.child;
|
|
3878
|
+
remoteAgentState.updatedAt = new Date().toISOString();
|
|
3879
|
+
rememberRemoteAgentSuccessfulManager(winner.manager, leaseId);
|
|
3880
|
+
emitBridgeEvent('RemoteAgentStarted', serializeRemoteAgentState());
|
|
3881
|
+
logEvent(
|
|
3882
|
+
'remote',
|
|
3883
|
+
`managed RemoteAgent connected ${formatKeyValue('manager', winner.manager)} ${formatKeyValue('launcher', winner.launcher?.launcher || '-')}`,
|
|
3884
|
+
'remote');
|
|
3885
|
+
return { ok: true, alreadyRunning: false, agent: serializeRemoteAgentState() };
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
const lastAttempt = attempts.findLast?.(attempt => attempt?.error || attempt?.state?.lastError)
|
|
3889
|
+
|| attempts[attempts.length - 1]
|
|
3890
|
+
|| null;
|
|
3891
|
+
for (const attempt of attempts) {
|
|
3892
|
+
await stopRemoteAgentAttempt(attempt, 'race-failed');
|
|
3893
|
+
}
|
|
3894
|
+
|
|
3895
|
+
const error = lastAttempt
|
|
3896
|
+
? summarizeRemoteAgentAttempt(lastAttempt)
|
|
3897
|
+
: 'all-manager-candidates-failed';
|
|
3898
|
+
remoteAgentState = createRemoteAgentIdleState({
|
|
3899
|
+
status: 'failed',
|
|
3900
|
+
manager: managers[0] || '',
|
|
3901
|
+
managerCandidates: managers,
|
|
3902
|
+
leaseId,
|
|
3903
|
+
nodeId,
|
|
3904
|
+
engine,
|
|
3905
|
+
source,
|
|
3906
|
+
lastError: error,
|
|
3907
|
+
updatedAt: new Date().toISOString()
|
|
3908
|
+
});
|
|
3909
|
+
emitBridgeEvent('RemoteAgentFailed', serializeRemoteAgentState());
|
|
3423
3910
|
return {
|
|
3424
3911
|
ok: false,
|
|
3425
|
-
error
|
|
3426
|
-
agent:
|
|
3912
|
+
error,
|
|
3913
|
+
agent: serializeRemoteAgentState()
|
|
3427
3914
|
};
|
|
3428
3915
|
}
|
|
3429
3916
|
|
|
@@ -3445,17 +3932,11 @@ async function startRemoteAgentConnectionAttempt(options = {}) {
|
|
|
3445
3932
|
}
|
|
3446
3933
|
|
|
3447
3934
|
const connectionKey = createRemoteAgentConnectionKey(manager, leaseId);
|
|
3448
|
-
const launcher = resolveRemoteAgentLauncher();
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
manager,
|
|
3454
|
-
'--pair',
|
|
3455
|
-
pairToken,
|
|
3456
|
-
'--engine',
|
|
3457
|
-
engine
|
|
3458
|
-
];
|
|
3935
|
+
const launcher = resolveRemoteAgentLauncher(engine);
|
|
3936
|
+
if (launcher?.ok === false) {
|
|
3937
|
+
return { ok: false, error: launcher.error || 'remote-agent-launcher-unavailable', agent: serializeRemoteAgentState() };
|
|
3938
|
+
}
|
|
3939
|
+
const args = buildRemoteAgentLaunchArgs(launcher, manager, pairToken, engine);
|
|
3459
3940
|
|
|
3460
3941
|
remoteAgentState = createRemoteAgentIdleState({
|
|
3461
3942
|
status: 'starting',
|
|
@@ -8065,7 +8546,7 @@ app.get('/api/remote/status', (req, res) => {
|
|
|
8065
8546
|
|
|
8066
8547
|
app.get('/api/remote/devices', (req, res) => {
|
|
8067
8548
|
res.setHeader('Cache-Control', 'no-store');
|
|
8068
|
-
const includeDataUrl =
|
|
8549
|
+
const includeDataUrl = /^(1|true|yes|on|data|base64)$/i.test(String(req.query?.includeDataUrl ?? req.query?.frameData ?? ''));
|
|
8069
8550
|
const devices = remoteHub.listDevices({ includeDataUrl });
|
|
8070
8551
|
res.json({
|
|
8071
8552
|
total: devices.length,
|
|
@@ -8285,7 +8766,7 @@ function isRemoteCapabilityEnabled(device, key) {
|
|
|
8285
8766
|
}
|
|
8286
8767
|
|
|
8287
8768
|
function includeRemoteFrameDataUrl(req) {
|
|
8288
|
-
return
|
|
8769
|
+
return /^(1|true|yes|on|data|base64)$/i.test(String(req.query?.includeDataUrl ?? req.query?.frameData ?? ''));
|
|
8289
8770
|
}
|
|
8290
8771
|
|
|
8291
8772
|
function sendRemoteFrameBinary(req, res, frameKind) {
|
|
@@ -12221,11 +12221,119 @@
|
|
|
12221
12221
|
}
|
|
12222
12222
|
}
|
|
12223
12223
|
|
|
12224
|
+
function isTemplateCardCanvasControlTarget(target) {
|
|
12225
|
+
return !!target?.closest?.([
|
|
12226
|
+
'button',
|
|
12227
|
+
'a',
|
|
12228
|
+
'input',
|
|
12229
|
+
'textarea',
|
|
12230
|
+
'select',
|
|
12231
|
+
'[contenteditable="true"]',
|
|
12232
|
+
'[data-template-card-interactive="true"]',
|
|
12233
|
+
'[data-template-card-action]',
|
|
12234
|
+
'[data-template-option-id]',
|
|
12235
|
+
'[data-remote-fleet-action]',
|
|
12236
|
+
'[data-remote-fleet-control-popup]',
|
|
12237
|
+
'[data-remote-fleet-task-input]',
|
|
12238
|
+
'[data-remote-fleet-ai-toggle]',
|
|
12239
|
+
'[data-remote-fleet-search]',
|
|
12240
|
+
'.csv-table-scroll',
|
|
12241
|
+
'.csv-table-header-button',
|
|
12242
|
+
'.csv-table-cell'
|
|
12243
|
+
].join(', '));
|
|
12244
|
+
}
|
|
12245
|
+
|
|
12246
|
+
function routeTemplateCardWheelToCanvas(event) {
|
|
12247
|
+
if (!_module || !event) {
|
|
12248
|
+
return false;
|
|
12249
|
+
}
|
|
12250
|
+
|
|
12251
|
+
if (typeof window.MindMapInteractions?.routeCanvasWheelEvent === 'function') {
|
|
12252
|
+
window.MindMapInteractions.routeCanvasWheelEvent(_module, event);
|
|
12253
|
+
return true;
|
|
12254
|
+
}
|
|
12255
|
+
|
|
12256
|
+
if (window.MindMapInteractions?.shouldTreatWheelAsZoom?.(_module, event) === true) {
|
|
12257
|
+
window.MindMapInteractions?.routeWheelEventToZoom?.(_module, event);
|
|
12258
|
+
} else {
|
|
12259
|
+
window.MindMapInteractions?.routeCtrlWheelEventToVerticalScroll?.(_module, event);
|
|
12260
|
+
}
|
|
12261
|
+
return true;
|
|
12262
|
+
}
|
|
12263
|
+
|
|
12264
|
+
function bindTemplateCardCanvasNavigation(container, nodeModel) {
|
|
12265
|
+
const card = container?.classList?.contains?.('map-node-template-card')
|
|
12266
|
+
? container
|
|
12267
|
+
: container?.querySelector?.('.map-node-template-card');
|
|
12268
|
+
if (!card || typeof card.addEventListener !== 'function') {
|
|
12269
|
+
return;
|
|
12270
|
+
}
|
|
12271
|
+
|
|
12272
|
+
if (card._templateCardCanvasNavigationModule === _module
|
|
12273
|
+
&& card._templateCardWheelNavigationHandler
|
|
12274
|
+
&& card._templateCardPanNavigationHandler) {
|
|
12275
|
+
return;
|
|
12276
|
+
}
|
|
12277
|
+
|
|
12278
|
+
if (card._templateCardWheelNavigationHandler) {
|
|
12279
|
+
card.removeEventListener('wheel', card._templateCardWheelNavigationHandler, true);
|
|
12280
|
+
}
|
|
12281
|
+
if (card._templateCardPanNavigationHandler) {
|
|
12282
|
+
card.removeEventListener('mousedown', card._templateCardPanNavigationHandler, true);
|
|
12283
|
+
}
|
|
12284
|
+
|
|
12285
|
+
const nodeId = String(getNodeId(nodeModel) || card.dataset?.nodeId || '').trim();
|
|
12286
|
+
const isRemoteFleetCard = isRemoteFleetMonitorNode(nodeModel);
|
|
12287
|
+
|
|
12288
|
+
const wheelHandler = event => {
|
|
12289
|
+
routeTemplateCardWheelToCanvas(event);
|
|
12290
|
+
};
|
|
12291
|
+
|
|
12292
|
+
const panHandler = event => {
|
|
12293
|
+
const button = Number(event?.button);
|
|
12294
|
+
if (button === 1 || button === 2) {
|
|
12295
|
+
const started = window.MindMapInteractions?.beginPanFromMouseEvent?.(
|
|
12296
|
+
_module,
|
|
12297
|
+
event,
|
|
12298
|
+
card
|
|
12299
|
+
) === true;
|
|
12300
|
+
if (started) {
|
|
12301
|
+
event.stopImmediatePropagation?.();
|
|
12302
|
+
}
|
|
12303
|
+
return;
|
|
12304
|
+
}
|
|
12305
|
+
|
|
12306
|
+
if (button !== 0 || isRemoteFleetCard || !nodeId || isTemplateCardCanvasControlTarget(event.target)) {
|
|
12307
|
+
return;
|
|
12308
|
+
}
|
|
12309
|
+
|
|
12310
|
+
const started = window.MindMapInteractions?.startNodeDragFromDom?.(
|
|
12311
|
+
_module,
|
|
12312
|
+
event,
|
|
12313
|
+
nodeId,
|
|
12314
|
+
{ source: 'template-card' }
|
|
12315
|
+
) === true;
|
|
12316
|
+
if (started) {
|
|
12317
|
+
event.stopImmediatePropagation?.();
|
|
12318
|
+
}
|
|
12319
|
+
};
|
|
12320
|
+
|
|
12321
|
+
card._templateCardCanvasNavigationModule = _module;
|
|
12322
|
+
card._templateCardWheelNavigationHandler = wheelHandler;
|
|
12323
|
+
card._templateCardPanNavigationHandler = panHandler;
|
|
12324
|
+
card.addEventListener('wheel', wheelHandler, { passive: false, capture: true });
|
|
12325
|
+
card.addEventListener('mousedown', panHandler, { passive: false, capture: true });
|
|
12326
|
+
}
|
|
12327
|
+
|
|
12224
12328
|
function bindTemplateLauncherNodeEvents(container, nodeModel) {
|
|
12225
12329
|
const card = container?.classList?.contains?.('map-node-template-card')
|
|
12226
12330
|
? container
|
|
12227
12331
|
: container?.querySelector?.('.map-node-template-card');
|
|
12228
|
-
if (!card
|
|
12332
|
+
if (!card) return;
|
|
12333
|
+
|
|
12334
|
+
bindTemplateCardCanvasNavigation(card, nodeModel);
|
|
12335
|
+
|
|
12336
|
+
if (card.dataset.templateCardEventsBound === 'true') return;
|
|
12229
12337
|
|
|
12230
12338
|
card.dataset.templateCardEventsBound = 'true';
|
|
12231
12339
|
card._templateCardConfig = getTemplateCardConfig(nodeModel);
|
|
@@ -13995,6 +14103,7 @@
|
|
|
13995
14103
|
function isRemoteFleetFrameSource(value) {
|
|
13996
14104
|
const source = String(value || '').trim();
|
|
13997
14105
|
if (/^data:image\/(png|jpe?g|webp|svg\+xml);base64,/i.test(source)
|
|
14106
|
+
|| /^blob:/i.test(source)
|
|
13998
14107
|
|| /^\/api\/remote\//i.test(source)) {
|
|
13999
14108
|
return true;
|
|
14000
14109
|
}
|
|
@@ -14266,7 +14375,18 @@
|
|
|
14266
14375
|
return null;
|
|
14267
14376
|
}
|
|
14268
14377
|
|
|
14269
|
-
if (typeof
|
|
14378
|
+
if (typeof createImageBitmap !== 'function') {
|
|
14379
|
+
return null;
|
|
14380
|
+
}
|
|
14381
|
+
|
|
14382
|
+
const timeoutMs = getRemoteFleetFrameDecodeTimeoutMs(frame);
|
|
14383
|
+
if (frame._remoteFleetPayloadBlob) {
|
|
14384
|
+
return await withRemoteFleetFrameTimeout(
|
|
14385
|
+
createImageBitmap(frame._remoteFleetPayloadBlob),
|
|
14386
|
+
timeoutMs);
|
|
14387
|
+
}
|
|
14388
|
+
|
|
14389
|
+
if (typeof fetch !== 'function') {
|
|
14270
14390
|
return null;
|
|
14271
14391
|
}
|
|
14272
14392
|
|
|
@@ -14304,7 +14424,6 @@
|
|
|
14304
14424
|
entry.expiresAt = now + REMOTE_FLEET_FRAME_BLOB_CACHE_MS;
|
|
14305
14425
|
}
|
|
14306
14426
|
|
|
14307
|
-
const timeoutMs = getRemoteFleetFrameDecodeTimeoutMs(frame);
|
|
14308
14427
|
const blob = await withRemoteFleetFrameTimeout(
|
|
14309
14428
|
entry.promise,
|
|
14310
14429
|
timeoutMs,
|
|
@@ -14323,7 +14442,7 @@
|
|
|
14323
14442
|
}
|
|
14324
14443
|
|
|
14325
14444
|
function cloneRemoteFleetFramePatch(frame) {
|
|
14326
|
-
|
|
14445
|
+
const patch = {
|
|
14327
14446
|
deviceId: String(frame?.deviceId || '').trim(),
|
|
14328
14447
|
kind: String(frame?.kind || 'thumbnail').trim().toLowerCase(),
|
|
14329
14448
|
frameSeq: Number.isFinite(Number(frame?.frameSeq)) ? Math.floor(Number(frame.frameSeq)) : 0,
|
|
@@ -14335,6 +14454,16 @@
|
|
|
14335
14454
|
captureMs: Number(frame?.captureMs || 0) || 0,
|
|
14336
14455
|
sameContentStreak: Number(frame?.sameContentStreak || 0) || 0
|
|
14337
14456
|
};
|
|
14457
|
+
if (frame?._remoteFleetPayloadBlob) {
|
|
14458
|
+
patch._remoteFleetPayloadBlob = frame._remoteFleetPayloadBlob;
|
|
14459
|
+
}
|
|
14460
|
+
if (frame?._remoteFleetObjectUrl) {
|
|
14461
|
+
patch._remoteFleetObjectUrl = frame._remoteFleetObjectUrl;
|
|
14462
|
+
}
|
|
14463
|
+
if (frame?._remoteFleetBinaryFrame === true) {
|
|
14464
|
+
patch._remoteFleetBinaryFrame = true;
|
|
14465
|
+
}
|
|
14466
|
+
return patch;
|
|
14338
14467
|
}
|
|
14339
14468
|
|
|
14340
14469
|
function isRemoteFleetFrameNewerForPreview(preview, frame, comparePending = false) {
|
|
@@ -14435,23 +14564,7 @@
|
|
|
14435
14564
|
placeholder.remove();
|
|
14436
14565
|
}
|
|
14437
14566
|
|
|
14438
|
-
|
|
14439
|
-
if (previewMode === 'tile') {
|
|
14440
|
-
preview.querySelector?.('[data-remote-fleet-frame-badge="true"]')?.remove();
|
|
14441
|
-
return true;
|
|
14442
|
-
}
|
|
14443
|
-
|
|
14444
|
-
const badge = ensureRemoteFleetFrameBadge(preview, frame);
|
|
14445
|
-
if (badge) {
|
|
14446
|
-
const at = frame.receivedAt || frame.capturedAt || '';
|
|
14447
|
-
badge.textContent = frame.kind === 'live'
|
|
14448
|
-
? `LIVE ${at ? formatRemoteFleetAge(at) : ''}`.trim()
|
|
14449
|
-
: (at ? formatRemoteFleetAge(at) : 'Screen');
|
|
14450
|
-
badge.style.display = 'inline-flex';
|
|
14451
|
-
badge.style.background = frame.kind === 'live'
|
|
14452
|
-
? 'rgba(220, 38, 38, 0.84)'
|
|
14453
|
-
: 'rgba(15, 23, 42, 0.72)';
|
|
14454
|
-
}
|
|
14567
|
+
preview.querySelector?.('[data-remote-fleet-frame-badge="true"]')?.remove();
|
|
14455
14568
|
|
|
14456
14569
|
return true;
|
|
14457
14570
|
}
|
|
@@ -14772,11 +14885,10 @@
|
|
|
14772
14885
|
|
|
14773
14886
|
function applyRemoteFleetFramePatchToPreview(preview, frame) {
|
|
14774
14887
|
if (String(frame?.kind || '').toLowerCase() === 'live') {
|
|
14775
|
-
preview.
|
|
14776
|
-
delete preview.dataset.
|
|
14777
|
-
delete preview.dataset.
|
|
14778
|
-
delete preview.dataset.
|
|
14779
|
-
return queueRemoteFleetImageSwap(preview, frame);
|
|
14888
|
+
preview._remoteFleetPendingImageFrame = null;
|
|
14889
|
+
delete preview.dataset.remoteFleetPendingImageKind;
|
|
14890
|
+
delete preview.dataset.remoteFleetPendingImageSeq;
|
|
14891
|
+
delete preview.dataset.remoteFleetPendingImageUrl;
|
|
14780
14892
|
}
|
|
14781
14893
|
|
|
14782
14894
|
return queueRemoteFleetFramePaint(preview, frame);
|
|
@@ -14856,6 +14968,16 @@
|
|
|
14856
14968
|
return;
|
|
14857
14969
|
}
|
|
14858
14970
|
|
|
14971
|
+
const binarySession = bodyView._remoteFleetBinaryFrameSession;
|
|
14972
|
+
const binarySocket = binarySession?.ws || null;
|
|
14973
|
+
if (binarySocket
|
|
14974
|
+
&& typeof WebSocket !== 'undefined'
|
|
14975
|
+
&& (binarySocket.readyState === WebSocket.OPEN || binarySocket.readyState === WebSocket.CONNECTING)) {
|
|
14976
|
+
lastTick = timestamp;
|
|
14977
|
+
bodyView._remoteFleetFrameLoopRaf = requestRemoteFleetFrameLoopFrame(loop);
|
|
14978
|
+
return;
|
|
14979
|
+
}
|
|
14980
|
+
|
|
14859
14981
|
if (timestamp - lastTick >= intervalMs && bodyView._remoteFleetFrameRefreshInFlight !== true) {
|
|
14860
14982
|
lastTick = timestamp;
|
|
14861
14983
|
bodyView._remoteFleetFrameRefreshInFlight = true;
|
|
@@ -15885,29 +16007,6 @@
|
|
|
15885
16007
|
`;
|
|
15886
16008
|
preview.appendChild(placeholder);
|
|
15887
16009
|
}
|
|
15888
|
-
const previewBadge = document.createElement('span');
|
|
15889
|
-
previewBadge.dataset.remoteFleetFrameBadge = 'true';
|
|
15890
|
-
previewBadge.textContent = hasLiveFrame
|
|
15891
|
-
? `LIVE ${previewAt ? formatRemoteFleetAge(previewAt) : ''}`.trim()
|
|
15892
|
-
: (previewAt ? formatRemoteFleetAge(previewAt) : (hubStatus === 'online' ? 'Pinned' : 'Hub offline'));
|
|
15893
|
-
previewBadge.style.cssText = `
|
|
15894
|
-
position: absolute;
|
|
15895
|
-
left: 7px;
|
|
15896
|
-
bottom: 7px;
|
|
15897
|
-
max-width: calc(100% - 14px);
|
|
15898
|
-
padding: 4px 7px;
|
|
15899
|
-
border-radius: 999px;
|
|
15900
|
-
background: ${hasLiveFrame ? 'rgba(220, 38, 38, 0.84)' : 'rgba(15, 23, 42, 0.74)'};
|
|
15901
|
-
color: #e2e8f0;
|
|
15902
|
-
font-size: 9px;
|
|
15903
|
-
font-weight: 950;
|
|
15904
|
-
line-height: 1;
|
|
15905
|
-
overflow: hidden;
|
|
15906
|
-
text-overflow: ellipsis;
|
|
15907
|
-
white-space: nowrap;
|
|
15908
|
-
letter-spacing: 0;
|
|
15909
|
-
`;
|
|
15910
|
-
preview.appendChild(previewBadge);
|
|
15911
16010
|
bodyView.appendChild(preview);
|
|
15912
16011
|
|
|
15913
16012
|
const stats = document.createElement('div');
|
|
@@ -16256,6 +16355,15 @@
|
|
|
16256
16355
|
if (bodyView._remoteFleetNodeSelectionBound !== true) {
|
|
16257
16356
|
bodyView._remoteFleetNodeSelectionBound = true;
|
|
16258
16357
|
bodyView.addEventListener('mousedown', event => {
|
|
16358
|
+
if (event.button === 1 || event.button === 2) {
|
|
16359
|
+
window.MindMapInteractions?.beginPanFromMouseEvent?.(_module, event, bodyView);
|
|
16360
|
+
return;
|
|
16361
|
+
}
|
|
16362
|
+
|
|
16363
|
+
if (event.button !== 0) {
|
|
16364
|
+
return;
|
|
16365
|
+
}
|
|
16366
|
+
|
|
16259
16367
|
const controlTarget = event.target?.closest?.('button, input, textarea, select, [contenteditable="true"]');
|
|
16260
16368
|
if (controlTarget) {
|
|
16261
16369
|
return;
|
|
@@ -17297,7 +17405,16 @@
|
|
|
17297
17405
|
});
|
|
17298
17406
|
getDeviceCards().forEach(card => {
|
|
17299
17407
|
['mousedown', 'mouseup', 'dblclick'].forEach(eventName => {
|
|
17300
|
-
card.addEventListener(eventName, event =>
|
|
17408
|
+
card.addEventListener(eventName, event => {
|
|
17409
|
+
if (event.button === 1 || event.button === 2) {
|
|
17410
|
+
if (eventName === 'mousedown') {
|
|
17411
|
+
window.MindMapInteractions?.beginPanFromMouseEvent?.(_module, event, card);
|
|
17412
|
+
}
|
|
17413
|
+
return;
|
|
17414
|
+
}
|
|
17415
|
+
|
|
17416
|
+
event.stopPropagation();
|
|
17417
|
+
});
|
|
17301
17418
|
});
|
|
17302
17419
|
card.addEventListener('dblclick', event => {
|
|
17303
17420
|
event.preventDefault();
|
|
@@ -20882,6 +20999,9 @@
|
|
|
20882
20999
|
&& !isRemoteFleetMonitorNode(nodeModel)) {
|
|
20883
21000
|
bindTemplateLauncherNodeEvents(clonedElement, nodeModel);
|
|
20884
21001
|
}
|
|
21002
|
+
if (String(nodeModel.contentType ?? nodeModel.ContentType ?? '').toLowerCase() === 'templatelauncher') {
|
|
21003
|
+
bindTemplateCardCanvasNavigation(clonedElement, nodeModel);
|
|
21004
|
+
}
|
|
20885
21005
|
wrapper.appendChild(clonedElement);
|
|
20886
21006
|
if (String(nodeModel.contentType ?? nodeModel.ContentType ?? '').toLowerCase() !== 'templatelauncher'
|
|
20887
21007
|
|| isRemoteFleetMonitorNode(nodeModel)) {
|
|
@@ -21115,6 +21235,7 @@
|
|
|
21115
21235
|
|
|
21116
21236
|
const bodyView = card.querySelector('.template-card__remote-fleet-body');
|
|
21117
21237
|
renderRemoteFleetMonitor(bodyView, nodeModel);
|
|
21238
|
+
bindTemplateCardCanvasNavigation(card, nodeModel);
|
|
21118
21239
|
return;
|
|
21119
21240
|
}
|
|
21120
21241
|
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"mainAssemblyName": "MindExecution.Web",
|
|
3
3
|
"resources": {
|
|
4
|
-
"hash": "sha256-
|
|
4
|
+
"hash": "sha256-o8W1U0lBmrbs5unXcwG+/IEh2KogSA7Rk3MqjQnNfGU=",
|
|
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.
|
|
134
|
+
"MindExecution.Shared.uwkrc41o75.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.
|
|
285
|
+
"MindExecution.Shared.uwkrc41o75.dll": "sha256-YjF+7VcGo3+nB0fsa2nh3AiaRyrHS1AL6d6Mq4RWKqo=",
|
|
286
286
|
"MindExecution.Web.994sb3nzuy.dll": "sha256-jQshtLmhEC4xenzdD9PqHjaCuKvJf/frzaKBi2weDAg="
|
|
287
287
|
},
|
|
288
288
|
"lazyAssembly": {
|
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-ws-fast-v575" />
|
|
11
|
+
<link rel="stylesheet" href="_content/MindExecution.Shared/css/mind-map-overrides.css?v=20260616-mdm-ws-fast-v575" />
|
|
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-ws-fast-v575';
|
|
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": "vnLn5hRl",
|
|
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-
|
|
89
|
+
"hash": "sha256-eGHfAJwh8N3LmDZTr3/anW3CVrYCEYowGfK4N8KPzik=",
|
|
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-
|
|
446
|
-
"url": "_framework/MindExecution.Shared.
|
|
445
|
+
"hash": "sha256-YjF+7VcGo3+nB0fsa2nh3AiaRyrHS1AL6d6Mq4RWKqo=",
|
|
446
|
+
"url": "_framework/MindExecution.Shared.uwkrc41o75.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-
|
|
773
|
+
"hash": "sha256-lL/HCjpHZ3+EWJkTvNj72sH8NLl/eSU2UZDTr6bP99c=",
|
|
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-
|
|
837
|
+
"hash": "sha256-IYebw41Eytj+5xl0lRltZ9R7wOwuHg0mlcgar2MiudE=",
|
|
838
838
|
"url": "index.html"
|
|
839
839
|
},
|
|
840
840
|
{
|