@mindexec/cli 0.2.188 → 0.2.189

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.188",
3
+ "version": "0.2.189",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
package/remote-hub.js CHANGED
@@ -875,7 +875,7 @@ export function createRemoteHub(options = {}) {
875
875
  const publicEndpoint = safeString(env.MINDEXEC_REMOTE_PUBLIC_ENDPOINT || env.REMOTE_HUB_PUBLIC_ENDPOINT, 256);
876
876
  const publicHost = safeString(env.MINDEXEC_REMOTE_PUBLIC_HOST || env.REMOTE_HUB_PUBLIC_HOST, 128);
877
877
  const pairToken = safeString(
878
- env.REMOTE_HUB_PAIR_TOKEN || env.MINDEXEC_REMOTE_PAIR_TOKEN || crypto.randomBytes(6).toString('hex'),
878
+ options.pairToken || env.REMOTE_HUB_PAIR_TOKEN || env.MINDEXEC_REMOTE_PAIR_TOKEN || crypto.randomBytes(6).toString('hex'),
879
879
  256);
880
880
 
881
881
  const devices = new Map();
@@ -1043,7 +1043,9 @@ export function createRemoteHub(options = {}) {
1043
1043
  const routeInfo = getAgentEndpointRouteInfo();
1044
1044
  hostTarget = {
1045
1045
  nodeId,
1046
- leaseId: activeSameNode && previous?.leaseId ? previous.leaseId : crypto.randomUUID(),
1046
+ leaseId: activeSameNode && previous?.leaseId
1047
+ ? previous.leaseId
1048
+ : (safeString(options.leaseId, 128) || crypto.randomUUID()),
1047
1049
  hostInstanceId,
1048
1050
  endpoint: routeInfo.endpoint,
1049
1051
  endpointCandidates: routeInfo.candidates,
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+
3
+ import assert from 'node:assert/strict';
4
+ import { spawn } from 'node:child_process';
5
+ import { mkdtemp, mkdir, rm } from 'node:fs/promises';
6
+ import net from 'node:net';
7
+ import os from 'node:os';
8
+ import path from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+
11
+ const BRIDGE_TOKEN = 'remote-hub-identity-smoke-token';
12
+ const LOCAL_BRIDGE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
13
+
14
+ function wait(ms) {
15
+ return new Promise(resolve => setTimeout(resolve, ms));
16
+ }
17
+
18
+ async function findFreePort() {
19
+ return await new Promise((resolve, reject) => {
20
+ const server = net.createServer();
21
+ server.unref();
22
+ server.once('error', reject);
23
+ server.listen(0, '127.0.0.1', () => {
24
+ const address = server.address();
25
+ const port = typeof address === 'object' && address ? address.port : 0;
26
+ server.close(() => resolve(port));
27
+ });
28
+ });
29
+ }
30
+
31
+ async function fetchJson(url, options = {}) {
32
+ const response = await fetch(url, {
33
+ ...options,
34
+ headers: {
35
+ 'X-Bridge-Token': BRIDGE_TOKEN,
36
+ ...(options.headers || {})
37
+ }
38
+ });
39
+ let payload = null;
40
+ try {
41
+ payload = await response.json();
42
+ } catch {
43
+ // Ignore non-JSON diagnostics.
44
+ }
45
+ return { ok: response.ok, status: response.status, payload };
46
+ }
47
+
48
+ function spawnBridge({ bridgePort, remoteHubPort, workspacePath, authDataRoot, label }) {
49
+ const child = spawn(process.execPath, ['server.js'], {
50
+ cwd: LOCAL_BRIDGE_DIR,
51
+ stdio: ['ignore', 'pipe', 'pipe'],
52
+ windowsHide: true,
53
+ env: {
54
+ ...process.env,
55
+ BRIDGE_PORT: String(bridgePort),
56
+ BRIDGE_TOKEN,
57
+ BRIDGE_REQUIRE_TOKEN: '1',
58
+ MINDEXEC_REMOTE_HUB: '1',
59
+ MINDEXEC_REMOTE_REGISTRY_FOLLOWER: '0',
60
+ REMOTE_HUB_HOST: '127.0.0.1',
61
+ REMOTE_HUB_PORT: String(remoteHubPort),
62
+ WORKSPACE_PATH: workspacePath,
63
+ MINDEXEC_AUTH_DATA_ROOT: authDataRoot,
64
+ REMOTE_HUB_PAIR_TOKEN: '',
65
+ MINDEXEC_REMOTE_PAIR_TOKEN: '',
66
+ MINDEXEC_BRIDGE_INSTANCE_ID: '',
67
+ NO_COLOR: '1'
68
+ }
69
+ });
70
+
71
+ let stdout = '';
72
+ let stderr = '';
73
+ child.stdout.on('data', chunk => {
74
+ stdout += chunk.toString();
75
+ });
76
+ child.stderr.on('data', chunk => {
77
+ stderr += chunk.toString();
78
+ });
79
+
80
+ const exitPromise = new Promise(resolve => child.once('exit', resolve));
81
+ const details = () => `${label} stdout=${stdout}\n${label} stderr=${stderr}`;
82
+ const stop = async () => {
83
+ if (child.exitCode === null && !child.killed) {
84
+ child.kill('SIGTERM');
85
+ await Promise.race([exitPromise, wait(3000)]);
86
+ if (child.exitCode === null && !child.killed) {
87
+ child.kill('SIGKILL');
88
+ }
89
+ }
90
+ };
91
+
92
+ return {
93
+ baseUrl: `http://127.0.0.1:${bridgePort}`,
94
+ details,
95
+ stop
96
+ };
97
+ }
98
+
99
+ async function waitForStatus(bridge) {
100
+ const startedAt = Date.now();
101
+ while (Date.now() - startedAt < 30000) {
102
+ try {
103
+ const result = await fetchJson(`${bridge.baseUrl}/api/remote/status`);
104
+ if (result.ok && result.payload?.started === true) {
105
+ return result.payload;
106
+ }
107
+ } catch {
108
+ // Bridge still starting.
109
+ }
110
+ await wait(100);
111
+ }
112
+
113
+ throw new Error(`Timed out waiting for bridge status.\n${bridge.details()}`);
114
+ }
115
+
116
+ async function runOnce({ workspacePath, authDataRoot, label }) {
117
+ const bridgePort = await findFreePort();
118
+ const remoteHubPort = await findFreePort();
119
+ const bridge = spawnBridge({ bridgePort, remoteHubPort, workspacePath, authDataRoot, label });
120
+ try {
121
+ return await waitForStatus(bridge);
122
+ } finally {
123
+ await bridge.stop();
124
+ }
125
+ }
126
+
127
+ const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'mindexec-remote-hub-identity-smoke-'));
128
+ try {
129
+ const workspacePath = path.join(tempRoot, 'workspace');
130
+ const authDataRoot = path.join(tempRoot, 'auth');
131
+ await mkdir(workspacePath, { recursive: true });
132
+ await mkdir(authDataRoot, { recursive: true });
133
+
134
+ const first = await runOnce({ workspacePath, authDataRoot, label: 'first' });
135
+ const second = await runOnce({ workspacePath, authDataRoot, label: 'second' });
136
+
137
+ assert.ok(first.pairToken, JSON.stringify(first));
138
+ assert.ok(first.hostInstanceId, JSON.stringify(first));
139
+ assert.equal(second.pairToken, first.pairToken);
140
+ assert.equal(second.hostInstanceId, first.hostInstanceId);
141
+ assert.match(first.hostInstanceId, /^bridge-[a-f0-9]{32}$/);
142
+
143
+ console.log('RemoteHub identity persistence smoke OK');
144
+ } finally {
145
+ await rm(tempRoot, { recursive: true, force: true });
146
+ }
@@ -72,13 +72,13 @@ async function waitFor(predicate, timeoutMs, label) {
72
72
  throw new Error(`Timed out waiting for ${label}${lastError ? `: ${lastError.message}` : ''}.`);
73
73
  }
74
74
 
75
- function createRegistryTarget({ endpoint, endpointCandidates, leaseId, active = true }) {
75
+ function createRegistryTarget({ endpoint, endpointCandidates, leaseId, active = true, pairToken = PAIR_TOKEN }) {
76
76
  return {
77
77
  user_id: USER_ID,
78
78
  active,
79
79
  endpoint,
80
80
  endpoint_candidates: endpointCandidates,
81
- pair_token: PAIR_TOKEN,
81
+ pair_token: pairToken,
82
82
  lease_id: leaseId,
83
83
  node_id: 'remote-registry-follower-node',
84
84
  host_instance_id: `host-${leaseId}`,
package/server.js CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  import express from 'express';
10
10
  import cors from 'cors';
11
- import { promises as fs, readFileSync, statSync, createReadStream, chmodSync } from 'fs';
11
+ import { promises as fs, readFileSync, statSync, createReadStream, chmodSync, mkdirSync, writeFileSync } from 'fs';
12
12
  import path from 'path';
13
13
  import { exec, spawn, spawnSync, execFile } from 'child_process';
14
14
  import { promisify } from 'util';
@@ -32,10 +32,14 @@ const { normalizePort, releaseBridgePort } = portGuard;
32
32
  const app = express();
33
33
  const PORT = normalizePort(process.env.BRIDGE_PORT);
34
34
  const BRIDGE_ROOT = path.dirname(fileURLToPath(import.meta.url));
35
- const PACKAGE_INFO = JSON.parse(readFileSync(path.join(BRIDGE_ROOT, 'package.json'), 'utf8'));
35
+ const PACKAGE_INFO = JSON.parse(readFileSync(path.join(BRIDGE_ROOT, 'package.json'), 'utf8'));
36
36
  const BRIDGE_PACKAGE_NAME = String(PACKAGE_INFO.name || '@mindexec/cli');
37
37
  const BRIDGE_VERSION = String(PACKAGE_INFO.version || '0.1.0');
38
- const BRIDGE_INSTANCE_ID = String(process.env.MINDEXEC_BRIDGE_INSTANCE_ID || crypto.randomUUID()).trim() || crypto.randomUUID();
38
+ const REMOTE_HUB_IDENTITY_FILE_PREFIX = 'remote-hub-identity';
39
+ const REMOTE_HUB_IDENTITY_SCOPE = createRemoteHubIdentityScope();
40
+ const REMOTE_HUB_IDENTITY = loadOrCreateRemoteHubIdentity(REMOTE_HUB_IDENTITY_SCOPE);
41
+ const BRIDGE_INSTANCE_ID = String(process.env.MINDEXEC_BRIDGE_INSTANCE_ID || REMOTE_HUB_IDENTITY.hostInstanceId || crypto.randomUUID()).trim() || crypto.randomUUID();
42
+ const REMOTE_HUB_PAIR_TOKEN = String(process.env.REMOTE_HUB_PAIR_TOKEN || process.env.MINDEXEC_REMOTE_PAIR_TOKEN || REMOTE_HUB_IDENTITY.pairToken || crypto.randomBytes(18).toString('hex')).trim() || crypto.randomBytes(18).toString('hex');
39
43
  const TREE_SITTER_GRAMMAR_DIR = path.join(BRIDGE_ROOT, 'tree-sitter-grammars');
40
44
  const VERBOSE_CODEX_TRACE = /^(1|true|yes|on)$/i.test(String(process.env.BRIDGE_VERBOSE_CODEX || ''));
41
45
  const COLOR_LOGS_ENABLED = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
@@ -404,22 +408,95 @@ function looksLikeWorkspaceRoot(candidatePath) {
404
408
  || pathExistsSync(path.join(normalizedPath, 'MindExecution.Shared'));
405
409
  }
406
410
 
407
- function resolveInitialWorkspacePath() {
408
- const envWorkspacePath = String(process.env.WORKSPACE_PATH || '').trim();
409
- if (envWorkspacePath) {
410
- return envWorkspacePath;
411
- }
411
+ function resolveInitialWorkspacePath() {
412
+ const envWorkspacePath = String(process.env.WORKSPACE_PATH || '').trim();
413
+ if (envWorkspacePath) {
414
+ return envWorkspacePath;
415
+ }
412
416
 
413
417
  const bridgeSiblingWorkspace = path.resolve(BRIDGE_ROOT, '..');
414
418
  if (looksLikeWorkspaceRoot(bridgeSiblingWorkspace)) {
415
419
  return bridgeSiblingWorkspace;
416
420
  }
417
-
418
- return path.join(os.homedir(), 'Documents', 'MindExecution');
419
- }
420
-
421
- // Default workspace path
422
- const DEFAULT_WORKSPACE = resolveInitialWorkspacePath();
421
+
422
+ return path.join(os.homedir(), 'Documents', 'MindExecution');
423
+ }
424
+
425
+ function createRemoteHubIdentityScope() {
426
+ const initialWorkspace = path.resolve(resolveInitialWorkspacePath());
427
+ const user = (() => {
428
+ try {
429
+ return os.userInfo().username || '';
430
+ } catch {
431
+ return '';
432
+ }
433
+ })();
434
+ return [
435
+ initialWorkspace.toLowerCase(),
436
+ os.hostname().toLowerCase(),
437
+ user.toLowerCase()
438
+ ].join('\n');
439
+ }
440
+
441
+ function createRemoteHubIdentityHash(scope) {
442
+ return crypto
443
+ .createHash('sha256')
444
+ .update(String(scope || 'mindexec-remote-hub'))
445
+ .digest('hex');
446
+ }
447
+
448
+ function getStableRemoteHubIdentityPath(scope) {
449
+ const scopeHash = createRemoteHubIdentityHash(scope).slice(0, 16);
450
+ return path.join(resolveAuthDataRoot(), `${REMOTE_HUB_IDENTITY_FILE_PREFIX}-${scopeHash}.json`);
451
+ }
452
+
453
+ function createStableRemoteHubInstanceId(scope) {
454
+ return `bridge-${createRemoteHubIdentityHash(scope).slice(0, 32)}`;
455
+ }
456
+
457
+ function loadOrCreateRemoteHubIdentity(scope) {
458
+ const identityPath = getStableRemoteHubIdentityPath(scope);
459
+ let existing = null;
460
+ try {
461
+ existing = JSON.parse(readFileSync(identityPath, 'utf8'));
462
+ } catch (err) {
463
+ if (err?.code !== 'ENOENT') {
464
+ // Ignore corrupt identity files and replace them with a fresh stable shape.
465
+ }
466
+ }
467
+
468
+ const hostInstanceId = String(existing?.hostInstanceId || '').trim()
469
+ || createStableRemoteHubInstanceId(scope);
470
+ const pairToken = String(existing?.pairToken || '').trim()
471
+ || crypto.randomBytes(18).toString('hex');
472
+ const next = {
473
+ version: 1,
474
+ scopeHash: createRemoteHubIdentityHash(scope).slice(0, 16),
475
+ hostInstanceId,
476
+ pairToken
477
+ };
478
+ const changed = existing?.version !== next.version
479
+ || existing?.scopeHash !== next.scopeHash
480
+ || existing?.hostInstanceId !== next.hostInstanceId
481
+ || existing?.pairToken !== next.pairToken;
482
+
483
+ if (changed) {
484
+ try {
485
+ mkdirSync(path.dirname(identityPath), { recursive: true });
486
+ writeFileSync(identityPath, `${JSON.stringify(next, null, 2)}\n`, {
487
+ encoding: 'utf8',
488
+ mode: 0o600
489
+ });
490
+ } catch (err) {
491
+ console.warn(`[RemoteHubIdentity] Failed to persist identity: ${err?.message || err}`);
492
+ }
493
+ }
494
+
495
+ return next;
496
+ }
497
+
498
+ // Default workspace path
499
+ const DEFAULT_WORKSPACE = resolveInitialWorkspacePath();
423
500
  let workspacePath = DEFAULT_WORKSPACE;
424
501
  const browserSessions = new Map();
425
502
  let currentBrowserSessionId = null;
@@ -3363,7 +3440,8 @@ const remoteHub = createRemoteHub({
3363
3440
  emitFrame: broadcastRemoteBinaryFrame,
3364
3441
  managerPackage: BRIDGE_PACKAGE_NAME,
3365
3442
  managerVersion: BRIDGE_VERSION,
3366
- hostInstanceId: BRIDGE_INSTANCE_ID
3443
+ hostInstanceId: BRIDGE_INSTANCE_ID,
3444
+ pairToken: REMOTE_HUB_PAIR_TOKEN
3367
3445
  });
3368
3446
 
3369
3447
  const REMOTE_AGENT_STDIO_TAIL_CHARS = 12000;
@@ -5841,6 +5919,23 @@ function isRemoteRegistryTargetSameAsLocalHost(localHub, target) {
5841
5919
  && localHostInstanceId.toLowerCase() === String(target.hostInstanceId).toLowerCase();
5842
5920
  }
5843
5921
 
5922
+ function isRemoteRegistryTargetEndpointLocal(localHub, target) {
5923
+ const localEndpoints = normalizeRemoteManagerEndpointList(
5924
+ localHub?.agentEndpointCandidates,
5925
+ localHub?.agentEndpoint,
5926
+ localHub?.hostTargetEndpointCandidates,
5927
+ localHub?.hostTargetEndpoint);
5928
+ const targetEndpoints = normalizeRemoteManagerEndpointList(
5929
+ target?.endpointCandidates,
5930
+ target?.endpoint);
5931
+ if (localEndpoints.length === 0 || targetEndpoints.length === 0) {
5932
+ return false;
5933
+ }
5934
+
5935
+ const localSet = new Set(localEndpoints.map(endpoint => endpoint.toLowerCase()));
5936
+ return targetEndpoints.some(endpoint => localSet.has(endpoint.toLowerCase()));
5937
+ }
5938
+
5844
5939
  async function fetchRemoteRegistryTarget(config, session) {
5845
5940
  const url = new URL('/rest/v1/remote_host_targets', config.url);
5846
5941
  url.searchParams.set('select', '*');
@@ -6609,6 +6704,54 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
6609
6704
  await ensureRemoteRegistryRealtimeSubscription(config, session, trigger);
6610
6705
  const target = await fetchRemoteRegistryTarget(config, session);
6611
6706
 
6707
+ if (localHub?.hostTargetActive !== true
6708
+ && target?.active === true
6709
+ && !isRemoteRegistryTargetExpired(target)
6710
+ && isRemoteRegistryTargetEndpointLocal(localHub, target)) {
6711
+ const revived = remoteHub.setHostTarget({
6712
+ enabled: true,
6713
+ nodeId: target.nodeId,
6714
+ leaseId: target.leaseId,
6715
+ leaseMs: REMOTE_HOST_TARGET_LEASE_MS
6716
+ });
6717
+ if (revived?.ok === true) {
6718
+ if (isRemoteAgentProcessRunning()) {
6719
+ await stopRemoteAgentConnection('local-host-target-revived');
6720
+ }
6721
+ const revivedHub = remoteHub.getStatus({ includeSecrets: true });
6722
+ const registry = await publishLocalRemoteHostTargetToRegistry(revivedHub, { takeover: true });
6723
+ updateRemoteRegistryFollowerState({
6724
+ status: 'skipped',
6725
+ reason: 'local-monitor-host-revived',
6726
+ authenticated: true,
6727
+ lastAttemptAt: attemptedAt,
6728
+ lastSuccessAt: attemptedAt,
6729
+ targetEndpoint: registry.endpoint || target.endpoint,
6730
+ targetEndpointCandidates: registry.endpointCandidates?.length ? registry.endpointCandidates : target.endpointCandidates,
6731
+ targetLeaseId: revivedHub.hostTargetLeaseId,
6732
+ targetNodeId: revivedHub.hostTargetNodeId,
6733
+ lastError: registry.ok || isRemoteHostTargetRenewSoftSkipReason(registry.reason) ? '' : (registry.reason || 'host-target-republish-failed')
6734
+ });
6735
+ await reportRemoteRegistryFollowerSync({
6736
+ ok: registry.ok !== false,
6737
+ skipped: true,
6738
+ reason: registry.ok ? 'local-monitor-host-revived' : `local-monitor-host-revived-${registry.reason || 'registry-publish-failed'}`,
6739
+ trigger,
6740
+ authenticated: true,
6741
+ localHostTargetActive: true,
6742
+ targetActive: true,
6743
+ targetEndpoint: registry.endpoint || target.endpoint,
6744
+ targetEndpointCandidates: registry.endpointCandidates?.length ? registry.endpointCandidates : target.endpointCandidates,
6745
+ targetLeaseId: revivedHub.hostTargetLeaseId,
6746
+ targetNodeId: revivedHub.hostTargetNodeId,
6747
+ targetExpiresAt: revivedHub.hostTargetExpiresAt
6748
+ });
6749
+ scheduleRemoteHostTargetRenewWake('local-host-revived');
6750
+ scheduleRemoteRegistryFollower(REMOTE_REGISTRY_FOLLOWER_POLL_MS, 'local-host-revived');
6751
+ return serializeRemoteRegistryFollowerState();
6752
+ }
6753
+ }
6754
+
6612
6755
  if (localHub?.hostTargetActive === true) {
6613
6756
  resetRemoteRegistryInactiveTargetGrace();
6614
6757
  if (target?.active === true
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mainAssemblyName": "MindExecution.Web",
3
3
  "resources": {
4
- "hash": "sha256-wO/y6PhLVnM+OKb9a+DZH6St+JWnCdBxHFafo2120Dc=",
4
+ "hash": "sha256-e0n1RLLtx0J+Ffwaa005iSuhZrI+q9OH/azLs6RFJdE=",
5
5
  "fingerprinting": {
6
6
  "Google.Protobuf.9h59ukbel7.dll": "Google.Protobuf.dll",
7
7
  "Markdig.d1j7v41cl1.dll": "Markdig.dll",
@@ -132,7 +132,7 @@
132
132
  "MindExecution.Plugins.PlanMaster.xt4y5gj8yw.dll": "MindExecution.Plugins.PlanMaster.dll",
133
133
  "MindExecution.Plugins.YouTube.kz0lju94md.dll": "MindExecution.Plugins.YouTube.dll",
134
134
  "MindExecution.Shared.7rwzquw93z.dll": "MindExecution.Shared.dll",
135
- "MindExecution.Web.hsle161c7m.dll": "MindExecution.Web.dll",
135
+ "MindExecution.Web.7on7otq3do.dll": "MindExecution.Web.dll",
136
136
  "dotnet.js": "dotnet.js",
137
137
  "dotnet.native.qc8g39g30v.js": "dotnet.native.js",
138
138
  "dotnet.native.boem75ye5i.wasm": "dotnet.native.wasm",
@@ -284,7 +284,7 @@
284
284
  "MindExecution.Plugins.Concept.3mpew6v5hz.dll": "sha256-K6GVU9mkcEQatq6shNKDO9xtahvaLBOhrIOzYda8lAI=",
285
285
  "MindExecution.Plugins.PlanMaster.xt4y5gj8yw.dll": "sha256-Cx47VicQk4brENQ4Y/9SMJ81sawy9AkvnrxuDnqoAYI=",
286
286
  "MindExecution.Shared.7rwzquw93z.dll": "sha256-bZ2rx8V2aQu7Ff4nl/mgbEOg3P/3YNjMmFpIXWcu3cQ=",
287
- "MindExecution.Web.hsle161c7m.dll": "sha256-0e786DmgqKdqucNj3NloG//KBor6Wqoeci7UHtgdyaA="
287
+ "MindExecution.Web.7on7otq3do.dll": "sha256-l3+AdCxkmuRdpmgy+hg5tQBsNft43p/QZ1jFKlJAz2A="
288
288
  },
289
289
  "lazyAssembly": {
290
290
  "MindExecution.Plugins.Admin.29mytzdaun.dll": "sha256-2mHPbTPcHCi1xPuk3dNMVWxn42xZFUZ3QFhm3xIV/6E=",
@@ -1,5 +1,5 @@
1
1
  self.assetsManifest = {
2
- "version": "gYWza81R",
2
+ "version": "2A2jXlS/",
3
3
  "assets": [
4
4
  {
5
5
  "hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
@@ -446,8 +446,8 @@
446
446
  "url": "_framework/MindExecution.Shared.7rwzquw93z.dll"
447
447
  },
448
448
  {
449
- "hash": "sha256-0e786DmgqKdqucNj3NloG//KBor6Wqoeci7UHtgdyaA=",
450
- "url": "_framework/MindExecution.Web.hsle161c7m.dll"
449
+ "hash": "sha256-l3+AdCxkmuRdpmgy+hg5tQBsNft43p/QZ1jFKlJAz2A=",
450
+ "url": "_framework/MindExecution.Web.7on7otq3do.dll"
451
451
  },
452
452
  {
453
453
  "hash": "sha256-IsZJ91/OW+fHzNqIgEc7Y072ns8z9dGritiSyvR9Wgc=",
@@ -770,7 +770,7 @@
770
770
  "url": "_framework/Websocket.Client.vapounvmnl.dll"
771
771
  },
772
772
  {
773
- "hash": "sha256-qmh1kbyeNhh7PgQWPBUrFh5bC+YayDSQBAYA92Yo4VA=",
773
+ "hash": "sha256-/VqlSl0soIWMyeyUaHS8719wDwRJJLAk6Wh9TJo4PVU=",
774
774
  "url": "_framework/blazor.boot.json"
775
775
  },
776
776
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: gYWza81R */
1
+ /* Manifest version: 2A2jXlS/ */
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