@mindexec/cli 0.2.285 → 0.2.286
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/scripts/remote-registry-follower-smoke.mjs +20 -0
- package/server.js +67 -24
- package/wwwroot/_framework/MindExecution.Web.f4nix6qubf.dll +0 -0
- package/wwwroot/_framework/blazor.boot.json +3 -3
- package/wwwroot/service-worker-assets.js +4 -4
- package/wwwroot/service-worker.js +1 -1
- package/wwwroot/_framework/MindExecution.Web.1otc7eb4qb.dll +0 -0
package/package.json
CHANGED
|
@@ -713,6 +713,26 @@ async function main() {
|
|
|
713
713
|
? { status: status.payload.remoteRegistryFollower, agent: agent.payload }
|
|
714
714
|
: null;
|
|
715
715
|
}, 9000, `registry inactive keeps ready data-plane agent\n${client.details()}`);
|
|
716
|
+
|
|
717
|
+
const inactivePid = Number(restartedAgent.pid || 0);
|
|
718
|
+
killProcess(inactivePid);
|
|
719
|
+
const recoveredInactiveAgent = await waitForManagedAgentRestart(
|
|
720
|
+
client,
|
|
721
|
+
hostBEndpoint,
|
|
722
|
+
inactivePid,
|
|
723
|
+
'host-b after inactive target recovery',
|
|
724
|
+
12000);
|
|
725
|
+
assert.equal(recoveredInactiveAgent.usingNpx, false, JSON.stringify(recoveredInactiveAgent));
|
|
726
|
+
assert.match(String(recoveredInactiveAgent.launcher || ''), /mindexec-remote-fast/i);
|
|
727
|
+
assert.equal(recoveredInactiveAgent.leaseId, 'lease-b');
|
|
728
|
+
await waitForConnectedDevice(hostB, 'host-b after inactive target recovery');
|
|
729
|
+
await waitFor(async () => {
|
|
730
|
+
const status = await fetchJson(`${client.baseUrl}/api/status`);
|
|
731
|
+
return status.payload?.remoteRegistryFollower?.reason === 'registry-inactive-agent-recovered'
|
|
732
|
+
&& String(status.payload?.remoteRegistryFollower?.targetEndpoint || '') === hostBEndpoint
|
|
733
|
+
? status.payload.remoteRegistryFollower
|
|
734
|
+
: null;
|
|
735
|
+
}, 4000, `inactive target recovered managed agent\n${client.details()}`);
|
|
716
736
|
const finalStatus = await fetchJson(`${client.baseUrl}/api/status`);
|
|
717
737
|
assert.ok(finalStatus.payload?.remoteRegistryRealtime?.changes >= 2, JSON.stringify(finalStatus.payload?.remoteRegistryRealtime));
|
|
718
738
|
assert.ok(finalStatus.payload?.remoteRegistryRealtime?.wakeups >= 2, JSON.stringify(finalStatus.payload?.remoteRegistryRealtime));
|
package/server.js
CHANGED
|
@@ -3505,6 +3505,9 @@ const REMOTE_REGISTRY_FOLLOWER_MISSING_SESSION_FAST_RETRY_COUNT = Math.max(
|
|
|
3505
3505
|
Number(process.env.MINDEXEC_REMOTE_REGISTRY_MISSING_SESSION_FAST_RETRY_COUNT || 5) || 5);
|
|
3506
3506
|
const REMOTE_REGISTRY_FOLLOWER_INACTIVE_STOP_COUNT = Math.max(2, Number(process.env.MINDEXEC_REMOTE_REGISTRY_INACTIVE_STOP_COUNT || 8) || 8);
|
|
3507
3507
|
const REMOTE_REGISTRY_FOLLOWER_INACTIVE_GRACE_MS = Math.max(500, Number(process.env.MINDEXEC_REMOTE_REGISTRY_INACTIVE_GRACE_MS || 60000) || 60000);
|
|
3508
|
+
const REMOTE_REGISTRY_INACTIVE_TARGET_RECOVERY_MS = Math.max(
|
|
3509
|
+
REMOTE_REGISTRY_FOLLOWER_INACTIVE_GRACE_MS,
|
|
3510
|
+
Number(process.env.MINDEXEC_REMOTE_REGISTRY_INACTIVE_TARGET_RECOVERY_MS || (10 * 60 * 1000)) || (10 * 60 * 1000));
|
|
3508
3511
|
const REMOTE_REGISTRY_SESSION_REFRESH_LEAD_MS = Math.max(15_000, Number(process.env.MINDEXEC_REMOTE_REGISTRY_SESSION_REFRESH_LEAD_MS || 120_000) || 120_000);
|
|
3509
3512
|
const REMOTE_REGISTRY_REALTIME_ENABLED = REMOTE_REGISTRY_FOLLOWER_ENABLED
|
|
3510
3513
|
&& !/^(0|false|no|off)$/i.test(String(process.env.MINDEXEC_REMOTE_REGISTRY_REALTIME || 'true'));
|
|
@@ -6096,6 +6099,8 @@ function normalizeRemoteRegistryTarget(row) {
|
|
|
6096
6099
|
const hostInstanceId = String(readRegistryTargetField(row, 'host_instance_id', 'hostInstanceId', 'HostInstanceId') || '').trim();
|
|
6097
6100
|
const expiresAt = String(readRegistryTargetField(row, 'expires_at', 'expiresAt', 'ExpiresAt') || '').trim();
|
|
6098
6101
|
const expiresAtMs = Date.parse(expiresAt);
|
|
6102
|
+
const updatedAt = String(readRegistryTargetField(row, 'updated_at', 'updatedAt', 'UpdatedAt') || '').trim();
|
|
6103
|
+
const updatedAtMs = Date.parse(updatedAt);
|
|
6099
6104
|
|
|
6100
6105
|
return {
|
|
6101
6106
|
active,
|
|
@@ -6106,7 +6111,9 @@ function normalizeRemoteRegistryTarget(row) {
|
|
|
6106
6111
|
nodeId,
|
|
6107
6112
|
hostInstanceId,
|
|
6108
6113
|
expiresAt,
|
|
6109
|
-
expiresAtMs: Number.isFinite(expiresAtMs) ? expiresAtMs : 0
|
|
6114
|
+
expiresAtMs: Number.isFinite(expiresAtMs) ? expiresAtMs : 0,
|
|
6115
|
+
updatedAt,
|
|
6116
|
+
updatedAtMs: Number.isFinite(updatedAtMs) ? updatedAtMs : 0
|
|
6110
6117
|
};
|
|
6111
6118
|
}
|
|
6112
6119
|
|
|
@@ -6114,6 +6121,20 @@ function isRemoteRegistryTargetExpired(target) {
|
|
|
6114
6121
|
return !target?.expiresAtMs || target.expiresAtMs <= Date.now();
|
|
6115
6122
|
}
|
|
6116
6123
|
|
|
6124
|
+
function isRecoverableInactiveRemoteRegistryTarget(target) {
|
|
6125
|
+
if (!target || target.active === true || !isRemoteRegistryTargetExpired(target)) {
|
|
6126
|
+
return false;
|
|
6127
|
+
}
|
|
6128
|
+
|
|
6129
|
+
const managers = normalizeRemoteManagerEndpointList(target.endpointCandidates, target.endpoint);
|
|
6130
|
+
if (managers.length === 0 || !target.pairToken || !target.leaseId || !target.nodeId) {
|
|
6131
|
+
return false;
|
|
6132
|
+
}
|
|
6133
|
+
|
|
6134
|
+
const anchorMs = Math.max(Number(target.expiresAtMs || 0), Number(target.updatedAtMs || 0));
|
|
6135
|
+
return anchorMs > 0 && Date.now() - anchorMs <= REMOTE_REGISTRY_INACTIVE_TARGET_RECOVERY_MS;
|
|
6136
|
+
}
|
|
6137
|
+
|
|
6117
6138
|
function isRemoteRegistryTargetSameAsLocalHost(localHub, target) {
|
|
6118
6139
|
const localLeaseId = safeRemoteAgentField(localHub?.hostTargetLeaseId, 128);
|
|
6119
6140
|
const localHostInstanceId = safeRemoteAgentField(localHub?.hostTargetHostInstanceId || localHub?.hostInstanceId, 128);
|
|
@@ -6405,15 +6426,17 @@ function stopRemoteHostTargetRenew(reason = 'stopped') {
|
|
|
6405
6426
|
clearTimeout(remoteHostTargetRenewTimer);
|
|
6406
6427
|
remoteHostTargetRenewTimer = null;
|
|
6407
6428
|
}
|
|
6429
|
+
const keepRecoverableLease = /^(no-local-host-target|expired-local-host-target)$/i.test(String(reason || ''))
|
|
6430
|
+
&& !!remoteHostTargetRenewState.nodeId;
|
|
6408
6431
|
updateRemoteHostTargetRenewState({
|
|
6409
6432
|
status: REMOTE_HOST_TARGET_AUTO_RENEW_ENABLED ? 'idle' : 'disabled',
|
|
6410
6433
|
reason,
|
|
6411
|
-
nodeId: '',
|
|
6412
|
-
leaseId: '',
|
|
6413
|
-
hostInstanceId: '',
|
|
6414
|
-
endpoint: '',
|
|
6415
|
-
endpointCandidates: [],
|
|
6416
|
-
expiresAt: '',
|
|
6434
|
+
nodeId: keepRecoverableLease ? remoteHostTargetRenewState.nodeId : '',
|
|
6435
|
+
leaseId: keepRecoverableLease ? remoteHostTargetRenewState.leaseId : '',
|
|
6436
|
+
hostInstanceId: keepRecoverableLease ? remoteHostTargetRenewState.hostInstanceId : '',
|
|
6437
|
+
endpoint: keepRecoverableLease ? remoteHostTargetRenewState.endpoint : '',
|
|
6438
|
+
endpointCandidates: keepRecoverableLease ? remoteHostTargetRenewState.endpointCandidates : [],
|
|
6439
|
+
expiresAt: keepRecoverableLease ? remoteHostTargetRenewState.expiresAt : '',
|
|
6417
6440
|
lastError: ''
|
|
6418
6441
|
});
|
|
6419
6442
|
}
|
|
@@ -7029,28 +7052,48 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
|
|
|
7029
7052
|
? 'registry-inactive'
|
|
7030
7053
|
: 'no-active-target';
|
|
7031
7054
|
const inactive = rememberRemoteRegistryInactiveTarget(inactiveReason);
|
|
7032
|
-
|
|
7055
|
+
let recovery = inactive.agentKept
|
|
7033
7056
|
? await maybeRestartKeptRemoteAgentForMissingRegistryTarget(inactiveReason)
|
|
7034
7057
|
: null;
|
|
7035
|
-
if (inactive.
|
|
7058
|
+
if (!inactive.agentKept && isRecoverableInactiveRemoteRegistryTarget(target)) {
|
|
7059
|
+
const recoveryManagers = normalizeRemoteManagerEndpointList(target.endpointCandidates, target.endpoint);
|
|
7060
|
+
logWarn(
|
|
7061
|
+
'remote',
|
|
7062
|
+
`registry target inactive but recently recoverable; reconnecting previous manager ${formatKeyValue('reason', inactiveReason)} ${formatKeyValue('manager', recoveryManagers[0] || '-')}`);
|
|
7063
|
+
recovery = await startRemoteAgentConnection({
|
|
7064
|
+
manager: recoveryManagers[0],
|
|
7065
|
+
managerCandidates: recoveryManagers,
|
|
7066
|
+
pairToken: target.pairToken,
|
|
7067
|
+
leaseId: target.leaseId,
|
|
7068
|
+
nodeId: target.nodeId,
|
|
7069
|
+
engine: 'auto',
|
|
7070
|
+
source: 'local-bridge-registry-inactive-recovery'
|
|
7071
|
+
});
|
|
7072
|
+
}
|
|
7073
|
+
if (inactive.confirmedInactive && recovery?.ok !== true && isRemoteAgentRegistryOwned()) {
|
|
7036
7074
|
await stopRemoteAgentConnection('registry-inactive');
|
|
7037
7075
|
}
|
|
7038
|
-
const
|
|
7039
|
-
const
|
|
7076
|
+
const recoveredAgent = recovery?.ok === true && isRemoteAgentRegistryOwned() && isRemoteAgentProcessRunning();
|
|
7077
|
+
const agentKept = inactive.agentKept || recoveredAgent;
|
|
7078
|
+
const dataPlaneReady = recoveredAgent ? isRemoteAgentReadyDataPlaneAlive() : inactive.dataPlaneReady;
|
|
7079
|
+
const keptManager = agentKept ? safeRemoteAgentField(remoteAgentState.manager, 160) : '';
|
|
7080
|
+
const keptCandidates = agentKept ? normalizeRemoteManagerEndpointList(remoteAgentState.managerCandidates, remoteAgentState.manager) : [];
|
|
7040
7081
|
updateRemoteRegistryFollowerState({
|
|
7041
|
-
status:
|
|
7042
|
-
reason:
|
|
7082
|
+
status: recoveredAgent ? 'connected' : (agentKept ? 'waiting' : 'idle'),
|
|
7083
|
+
reason: recovery?.ok === true
|
|
7084
|
+
? `${inactiveReason}-agent-recovered`
|
|
7085
|
+
: (agentKept ? `${inactiveReason}-agent-kept` : inactiveReason),
|
|
7043
7086
|
authenticated: true,
|
|
7044
7087
|
lastAttemptAt: attemptedAt,
|
|
7045
|
-
lastSuccessAt: attemptedAt,
|
|
7088
|
+
lastSuccessAt: recoveredAgent ? new Date().toISOString() : attemptedAt,
|
|
7046
7089
|
targetEndpoint: keptManager,
|
|
7047
7090
|
targetEndpointCandidates: keptCandidates,
|
|
7048
|
-
targetLeaseId:
|
|
7049
|
-
targetNodeId:
|
|
7091
|
+
targetLeaseId: agentKept ? safeRemoteAgentField(remoteAgentState.leaseId, 128) : '',
|
|
7092
|
+
targetNodeId: agentKept ? safeRemoteAgentField(remoteAgentState.nodeId, 128) : '',
|
|
7050
7093
|
inactiveCount: inactive.count,
|
|
7051
7094
|
inactiveElapsedMs: inactive.elapsedMs,
|
|
7052
|
-
agentKept
|
|
7053
|
-
dataPlaneReady
|
|
7095
|
+
agentKept,
|
|
7096
|
+
dataPlaneReady,
|
|
7054
7097
|
lastError: recovery?.ok === false ? (recovery.error || 'missing-target-agent-recovery-failed') : ''
|
|
7055
7098
|
});
|
|
7056
7099
|
await reportRemoteRegistryFollowerSync({
|
|
@@ -7058,21 +7101,21 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
|
|
|
7058
7101
|
skipped: true,
|
|
7059
7102
|
reason: recovery?.ok === true
|
|
7060
7103
|
? `${inactiveReason}-agent-recovered`
|
|
7061
|
-
: (
|
|
7104
|
+
: (agentKept ? `${inactiveReason}-agent-kept` : inactiveReason),
|
|
7062
7105
|
error: recovery?.ok === false ? recovery.error : '',
|
|
7063
7106
|
trigger,
|
|
7064
7107
|
authenticated: true,
|
|
7065
7108
|
targetEndpoint: keptManager,
|
|
7066
7109
|
targetEndpointCandidates: keptCandidates,
|
|
7067
|
-
targetLeaseId:
|
|
7068
|
-
targetNodeId:
|
|
7110
|
+
targetLeaseId: agentKept ? remoteAgentState.leaseId : '',
|
|
7111
|
+
targetNodeId: agentKept ? remoteAgentState.nodeId : '',
|
|
7069
7112
|
inactiveCount: inactive.count,
|
|
7070
7113
|
inactiveElapsedMs: inactive.elapsedMs,
|
|
7071
|
-
agentKept
|
|
7072
|
-
dataPlaneReady
|
|
7114
|
+
agentKept,
|
|
7115
|
+
dataPlaneReady
|
|
7073
7116
|
});
|
|
7074
7117
|
scheduleRemoteRegistryFollower(
|
|
7075
|
-
|
|
7118
|
+
(agentKept && !dataPlaneReady) || recovery?.ok === false
|
|
7076
7119
|
? REMOTE_REGISTRY_FOLLOWER_FAST_RETRY_MS
|
|
7077
7120
|
: REMOTE_REGISTRY_FOLLOWER_POLL_MS,
|
|
7078
7121
|
recovery?.ok === true ? 'missing-target-agent-recovered' : 'no-target');
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"mainAssemblyName": "MindExecution.Web",
|
|
3
3
|
"resources": {
|
|
4
|
-
"hash": "sha256-
|
|
4
|
+
"hash": "sha256-qAJZS2gJhj1UEBPo3ENSQdIHVUddkYUsKaosccaB7nY=",
|
|
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.w9msy01tp9.dll": "MindExecution.Plugins.PlanMaster.dll",
|
|
133
133
|
"MindExecution.Plugins.YouTube.iob4817wtf.dll": "MindExecution.Plugins.YouTube.dll",
|
|
134
134
|
"MindExecution.Shared.lvqhaceogf.dll": "MindExecution.Shared.dll",
|
|
135
|
-
"MindExecution.Web.
|
|
135
|
+
"MindExecution.Web.f4nix6qubf.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.cjp3ty08t0.dll": "sha256-+FZtYvFT7aqaThaaATz4C7YmMZEDy3z8i2JcplL+fJs=",
|
|
285
285
|
"MindExecution.Plugins.PlanMaster.w9msy01tp9.dll": "sha256-xBGl/hx1xJ1XCAy1wfZJv0/LSsm825PrufniNvTFpdk=",
|
|
286
286
|
"MindExecution.Shared.lvqhaceogf.dll": "sha256-UXxhTxZwmtsqxr4Tf3DmjWKLbihsP91u88dZhsubRQU=",
|
|
287
|
-
"MindExecution.Web.
|
|
287
|
+
"MindExecution.Web.f4nix6qubf.dll": "sha256-j/4kL30Kb8VYCRXGcr0Ireb4S3IDzFuKmP9oZxdmMVI="
|
|
288
288
|
},
|
|
289
289
|
"lazyAssembly": {
|
|
290
290
|
"MindExecution.Plugins.Admin.m5d94977um.dll": "sha256-Jt1vsUZkolnZk+PcV3ysNyL99SfPUVcUHwvBQ/Y+pR8=",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
self.assetsManifest = {
|
|
2
|
-
"version": "/
|
|
2
|
+
"version": "Xn/pulp5",
|
|
3
3
|
"assets": [
|
|
4
4
|
{
|
|
5
5
|
"hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
|
|
@@ -446,8 +446,8 @@
|
|
|
446
446
|
"url": "_framework/MindExecution.Shared.lvqhaceogf.dll"
|
|
447
447
|
},
|
|
448
448
|
{
|
|
449
|
-
"hash": "sha256-
|
|
450
|
-
"url": "_framework/MindExecution.Web.
|
|
449
|
+
"hash": "sha256-j/4kL30Kb8VYCRXGcr0Ireb4S3IDzFuKmP9oZxdmMVI=",
|
|
450
|
+
"url": "_framework/MindExecution.Web.f4nix6qubf.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-
|
|
773
|
+
"hash": "sha256-YBSr20c7qRbSof/FmV2prtF/F52GFhVGyW27i1MjBis=",
|
|
774
774
|
"url": "_framework/blazor.boot.json"
|
|
775
775
|
},
|
|
776
776
|
{
|
|
Binary file
|