@mindexec/cli 0.2.160 → 0.2.162
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
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -291,6 +291,8 @@ function spawnBridge({ bridgePort, remoteHubPort, workspacePath, authRoot, label
|
|
|
291
291
|
MINDEXEC_REMOTE_REGISTRY_FOLLOWER: follower ? '1' : '0',
|
|
292
292
|
MINDEXEC_REMOTE_REGISTRY_POLL_MS: '10000',
|
|
293
293
|
MINDEXEC_REMOTE_REGISTRY_FAST_RETRY_MS: '250',
|
|
294
|
+
MINDEXEC_REMOTE_REGISTRY_INACTIVE_STOP_COUNT: '2',
|
|
295
|
+
MINDEXEC_REMOTE_REGISTRY_INACTIVE_GRACE_MS: '500',
|
|
294
296
|
MINDEXEC_REMOTE_REGISTRY_REALTIME_RECONNECT_MS: '250',
|
|
295
297
|
MINDEXEC_REMOTE_REGISTRY_REALTIME_DEBOUNCE_MS: '100',
|
|
296
298
|
MINDEXEC_REMOTE_HOST_TARGET_RENEW_MS: '5000',
|
|
@@ -575,6 +577,28 @@ async function main() {
|
|
|
575
577
|
assert.equal(secondAgent.leaseId, 'lease-b');
|
|
576
578
|
await waitForConnectedDevice(hostB, 'host-b');
|
|
577
579
|
|
|
580
|
+
await wait(250);
|
|
581
|
+
currentTarget = null;
|
|
582
|
+
fakeSupabase.broadcastChange('DELETE');
|
|
583
|
+
await waitFor(async () => {
|
|
584
|
+
const status = await fetchJson(`${client.baseUrl}/api/status`);
|
|
585
|
+
const agent = await fetchJson(`${client.baseUrl}/api/remote/agent/status`);
|
|
586
|
+
return status.payload?.remoteRegistryFollower?.reason === 'no-active-target-agent-kept'
|
|
587
|
+
&& agent.payload?.running === true
|
|
588
|
+
&& String(agent.payload?.manager || '') === hostBEndpoint
|
|
589
|
+
? { status: status.payload.remoteRegistryFollower, agent: agent.payload }
|
|
590
|
+
: null;
|
|
591
|
+
}, 4000, `transient no-active-target keeps managed agent\n${client.details()}`);
|
|
592
|
+
|
|
593
|
+
currentTarget = createRegistryTarget({
|
|
594
|
+
endpoint: hostBEndpoint,
|
|
595
|
+
endpointCandidates: [hostBEndpoint],
|
|
596
|
+
leaseId: 'lease-b'
|
|
597
|
+
});
|
|
598
|
+
fakeSupabase.broadcastChange('INSERT');
|
|
599
|
+
const restoredAgent = await waitForManagedAgent(client, hostBEndpoint, 'host-b after transient missing target', 9000);
|
|
600
|
+
assert.equal(Number(restoredAgent.pid || 0), Number(secondAgent.pid || 0), JSON.stringify(restoredAgent));
|
|
601
|
+
|
|
578
602
|
const secondPid = Number(secondAgent.pid || 0);
|
|
579
603
|
killProcess(secondPid);
|
|
580
604
|
const restartedAgent = await waitForManagedAgentRestart(client, hostBEndpoint, secondPid, 'host-b', 12000);
|
|
@@ -589,6 +613,8 @@ async function main() {
|
|
|
589
613
|
expires_at: new Date(Date.now() - 1000).toISOString()
|
|
590
614
|
};
|
|
591
615
|
fakeSupabase.broadcastChange('UPDATE');
|
|
616
|
+
await wait(700);
|
|
617
|
+
fakeSupabase.broadcastChange('UPDATE');
|
|
592
618
|
|
|
593
619
|
await waitFor(async () => {
|
|
594
620
|
const result = await fetchJson(`${client.baseUrl}/api/remote/agent/status`);
|
package/server.js
CHANGED
|
@@ -3360,6 +3360,8 @@ const REMOTE_REGISTRY_FOLLOWER_ENABLED = !/^(0|false|no|off)$/i.test(String(proc
|
|
|
3360
3360
|
const REMOTE_REGISTRY_FOLLOWER_POLL_MS = Math.max(1500, Number(process.env.MINDEXEC_REMOTE_REGISTRY_POLL_MS || 5000) || 5000);
|
|
3361
3361
|
const REMOTE_REGISTRY_FOLLOWER_FAST_RETRY_MS = Math.max(500, Number(process.env.MINDEXEC_REMOTE_REGISTRY_FAST_RETRY_MS || 1200) || 1200);
|
|
3362
3362
|
const REMOTE_REGISTRY_FOLLOWER_MISSING_SESSION_STOP_COUNT = 3;
|
|
3363
|
+
const REMOTE_REGISTRY_FOLLOWER_INACTIVE_STOP_COUNT = Math.max(2, Number(process.env.MINDEXEC_REMOTE_REGISTRY_INACTIVE_STOP_COUNT || 8) || 8);
|
|
3364
|
+
const REMOTE_REGISTRY_FOLLOWER_INACTIVE_GRACE_MS = Math.max(500, Number(process.env.MINDEXEC_REMOTE_REGISTRY_INACTIVE_GRACE_MS || 60000) || 60000);
|
|
3363
3365
|
const REMOTE_REGISTRY_REALTIME_ENABLED = REMOTE_REGISTRY_FOLLOWER_ENABLED
|
|
3364
3366
|
&& !/^(0|false|no|off)$/i.test(String(process.env.MINDEXEC_REMOTE_REGISTRY_REALTIME || 'true'));
|
|
3365
3367
|
const REMOTE_REGISTRY_REALTIME_HEARTBEAT_MS = Math.max(10000, Number(process.env.MINDEXEC_REMOTE_REGISTRY_REALTIME_HEARTBEAT_MS || 25000) || 25000);
|
|
@@ -3391,6 +3393,8 @@ let remoteRegistryFollowerTimer = null;
|
|
|
3391
3393
|
let remoteRegistryFollowerInFlight = false;
|
|
3392
3394
|
let remoteRegistryFollowerStarted = false;
|
|
3393
3395
|
let remoteRegistryFollowerConsecutiveMissingSession = 0;
|
|
3396
|
+
let remoteRegistryFollowerConsecutiveInactiveTarget = 0;
|
|
3397
|
+
let remoteRegistryFollowerInactiveTargetFirstAt = 0;
|
|
3394
3398
|
let remoteRegistryRealtimeSocket = null;
|
|
3395
3399
|
let remoteRegistryRealtimeSessionKey = '';
|
|
3396
3400
|
let remoteRegistryRealtimeTopic = '';
|
|
@@ -3532,6 +3536,9 @@ function createRemoteAgentSyncReport(body = {}) {
|
|
|
3532
3536
|
targetLeaseId: safeRemoteAgentField(body.targetLeaseId || body.TargetLeaseId, 128),
|
|
3533
3537
|
targetNodeId: safeRemoteAgentField(body.targetNodeId || body.TargetNodeId, 128),
|
|
3534
3538
|
targetExpiresAt: safeRemoteAgentField(body.targetExpiresAt || body.TargetExpiresAt, 80),
|
|
3539
|
+
inactiveCount: Number(body.inactiveCount ?? body.InactiveCount ?? 0) || 0,
|
|
3540
|
+
inactiveElapsedMs: Number(body.inactiveElapsedMs ?? body.InactiveElapsedMs ?? 0) || 0,
|
|
3541
|
+
agentKept: body.agentKept === true || body.AgentKept === true,
|
|
3535
3542
|
updatedAt: new Date().toISOString()
|
|
3536
3543
|
};
|
|
3537
3544
|
}
|
|
@@ -3954,6 +3961,39 @@ function maybeRetryRemoteAgentAfterExit(state, reason = 'agent-exited') {
|
|
|
3954
3961
|
scheduleRemoteRegistryFollower(0, reason);
|
|
3955
3962
|
}
|
|
3956
3963
|
|
|
3964
|
+
function resetRemoteRegistryInactiveTargetGrace() {
|
|
3965
|
+
remoteRegistryFollowerConsecutiveInactiveTarget = 0;
|
|
3966
|
+
remoteRegistryFollowerInactiveTargetFirstAt = 0;
|
|
3967
|
+
}
|
|
3968
|
+
|
|
3969
|
+
function rememberRemoteRegistryInactiveTarget(reason = 'no-active-target') {
|
|
3970
|
+
const now = Date.now();
|
|
3971
|
+
remoteRegistryFollowerConsecutiveInactiveTarget += 1;
|
|
3972
|
+
if (!remoteRegistryFollowerInactiveTargetFirstAt) {
|
|
3973
|
+
remoteRegistryFollowerInactiveTargetFirstAt = now;
|
|
3974
|
+
}
|
|
3975
|
+
|
|
3976
|
+
const elapsedMs = Math.max(0, now - remoteRegistryFollowerInactiveTargetFirstAt);
|
|
3977
|
+
const agentRunning = isRemoteAgentRegistryOwned();
|
|
3978
|
+
const confirmedInactive = remoteRegistryFollowerConsecutiveInactiveTarget >= REMOTE_REGISTRY_FOLLOWER_INACTIVE_STOP_COUNT
|
|
3979
|
+
&& elapsedMs >= REMOTE_REGISTRY_FOLLOWER_INACTIVE_GRACE_MS;
|
|
3980
|
+
|
|
3981
|
+
if (agentRunning && !confirmedInactive) {
|
|
3982
|
+
logEvent(
|
|
3983
|
+
'remote',
|
|
3984
|
+
`registry target temporarily inactive; keeping managed RemoteAgent ${formatKeyValue('reason', reason)} ${formatKeyValue('count', remoteRegistryFollowerConsecutiveInactiveTarget)} ${formatKeyValue('elapsedMs', elapsedMs)}`,
|
|
3985
|
+
'remote');
|
|
3986
|
+
}
|
|
3987
|
+
|
|
3988
|
+
return {
|
|
3989
|
+
count: remoteRegistryFollowerConsecutiveInactiveTarget,
|
|
3990
|
+
elapsedMs,
|
|
3991
|
+
agentRunning,
|
|
3992
|
+
confirmedInactive,
|
|
3993
|
+
agentKept: agentRunning && !confirmedInactive
|
|
3994
|
+
};
|
|
3995
|
+
}
|
|
3996
|
+
|
|
3957
3997
|
function isLocalRemoteHostTargetActive() {
|
|
3958
3998
|
const status = remoteHub.getStatus({ includeSecrets: false });
|
|
3959
3999
|
return status?.hostTargetActive === true
|
|
@@ -4208,9 +4248,11 @@ function resolveNpxCliLauncher() {
|
|
|
4208
4248
|
return '';
|
|
4209
4249
|
}
|
|
4210
4250
|
|
|
4211
|
-
async function stopRemoteAgentConnection(reason = 'stopped') {
|
|
4251
|
+
async function stopRemoteAgentConnection(reason = 'stopped', options = {}) {
|
|
4212
4252
|
const previous = remoteAgentState;
|
|
4213
|
-
|
|
4253
|
+
if (options.suppressRetry !== false) {
|
|
4254
|
+
suppressRemoteAgentAutoRetry(previous.connectionKey);
|
|
4255
|
+
}
|
|
4214
4256
|
if (previous.proc) {
|
|
4215
4257
|
try {
|
|
4216
4258
|
await terminateProcessTree(previous.proc);
|
|
@@ -4753,7 +4795,13 @@ function serializeRemoteRegistryFollowerState() {
|
|
|
4753
4795
|
return {
|
|
4754
4796
|
...remoteRegistryFollowerState,
|
|
4755
4797
|
pollMs: REMOTE_REGISTRY_FOLLOWER_POLL_MS,
|
|
4756
|
-
fastRetryMs: REMOTE_REGISTRY_FOLLOWER_FAST_RETRY_MS
|
|
4798
|
+
fastRetryMs: REMOTE_REGISTRY_FOLLOWER_FAST_RETRY_MS,
|
|
4799
|
+
inactiveStopCount: REMOTE_REGISTRY_FOLLOWER_INACTIVE_STOP_COUNT,
|
|
4800
|
+
inactiveGraceMs: REMOTE_REGISTRY_FOLLOWER_INACTIVE_GRACE_MS,
|
|
4801
|
+
inactiveCount: remoteRegistryFollowerConsecutiveInactiveTarget,
|
|
4802
|
+
inactiveElapsedMs: remoteRegistryFollowerInactiveTargetFirstAt
|
|
4803
|
+
? Math.max(0, Date.now() - remoteRegistryFollowerInactiveTargetFirstAt)
|
|
4804
|
+
: 0
|
|
4757
4805
|
};
|
|
4758
4806
|
}
|
|
4759
4807
|
|
|
@@ -5499,7 +5547,11 @@ function buildRemoteHostTargetRegistryPayload(hub) {
|
|
|
5499
5547
|
const hostInstanceId = safeRemoteAgentField(hub?.hostTargetHostInstanceId || hub?.hostInstanceId, 128);
|
|
5500
5548
|
const nodeId = safeRemoteAgentField(hub?.hostTargetNodeId, 128);
|
|
5501
5549
|
const activatedAt = safeRemoteAgentField(hub?.hostTargetActivatedAt, 80) || new Date().toISOString();
|
|
5502
|
-
const
|
|
5550
|
+
const rawExpiresAt = safeRemoteAgentField(hub?.hostTargetExpiresAt, 80);
|
|
5551
|
+
const rawExpiresAtMs = Date.parse(rawExpiresAt || '');
|
|
5552
|
+
const expiresAt = Number.isFinite(rawExpiresAtMs) && rawExpiresAtMs > Date.now() + 5000
|
|
5553
|
+
? rawExpiresAt
|
|
5554
|
+
: new Date(Date.now() + REMOTE_HOST_TARGET_LEASE_MS).toISOString();
|
|
5503
5555
|
|
|
5504
5556
|
if (!pairToken || !leaseId || !hostInstanceId || !nodeId) {
|
|
5505
5557
|
return {
|
|
@@ -5710,7 +5762,7 @@ async function reconcileRemoteAfterSystemResume(trigger = 'timer-drift', driftMs
|
|
|
5710
5762
|
closeRemoteRegistryRealtime('system-resume');
|
|
5711
5763
|
|
|
5712
5764
|
if (wasRegistryAgentRunning) {
|
|
5713
|
-
await stopRemoteAgentConnection('system-resume-reconnect');
|
|
5765
|
+
await stopRemoteAgentConnection('system-resume-reconnect', { suppressRetry: false });
|
|
5714
5766
|
}
|
|
5715
5767
|
|
|
5716
5768
|
if (isLocalHost) {
|
|
@@ -6001,6 +6053,7 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
|
|
|
6001
6053
|
const target = await fetchRemoteRegistryTarget(config, session);
|
|
6002
6054
|
|
|
6003
6055
|
if (localHub?.hostTargetActive === true) {
|
|
6056
|
+
resetRemoteRegistryInactiveTargetGrace();
|
|
6004
6057
|
if (target?.active === true
|
|
6005
6058
|
&& !isRemoteRegistryTargetExpired(target)
|
|
6006
6059
|
&& !isRemoteRegistryTargetSameAsLocalHost(localHub, target)) {
|
|
@@ -6064,32 +6117,50 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
|
|
|
6064
6117
|
}
|
|
6065
6118
|
|
|
6066
6119
|
if (!target?.active || isRemoteRegistryTargetExpired(target)) {
|
|
6067
|
-
|
|
6120
|
+
const inactiveReason = target
|
|
6121
|
+
? 'registry-inactive'
|
|
6122
|
+
: 'no-active-target';
|
|
6123
|
+
const inactive = rememberRemoteRegistryInactiveTarget(inactiveReason);
|
|
6124
|
+
if (inactive.confirmedInactive && isRemoteAgentRegistryOwned()) {
|
|
6068
6125
|
await stopRemoteAgentConnection('registry-inactive');
|
|
6069
6126
|
}
|
|
6127
|
+
const keptManager = inactive.agentKept ? safeRemoteAgentField(remoteAgentState.manager, 160) : '';
|
|
6128
|
+
const keptCandidates = inactive.agentKept ? normalizeRemoteManagerEndpointList(remoteAgentState.managerCandidates, remoteAgentState.manager) : [];
|
|
6070
6129
|
updateRemoteRegistryFollowerState({
|
|
6071
|
-
status: 'idle',
|
|
6072
|
-
reason:
|
|
6130
|
+
status: inactive.agentKept ? 'waiting' : 'idle',
|
|
6131
|
+
reason: inactive.agentKept ? `${inactiveReason}-agent-kept` : inactiveReason,
|
|
6073
6132
|
authenticated: true,
|
|
6074
6133
|
lastAttemptAt: attemptedAt,
|
|
6075
6134
|
lastSuccessAt: attemptedAt,
|
|
6076
|
-
targetEndpoint:
|
|
6077
|
-
targetEndpointCandidates:
|
|
6078
|
-
targetLeaseId: '',
|
|
6079
|
-
targetNodeId: '',
|
|
6135
|
+
targetEndpoint: keptManager,
|
|
6136
|
+
targetEndpointCandidates: keptCandidates,
|
|
6137
|
+
targetLeaseId: inactive.agentKept ? safeRemoteAgentField(remoteAgentState.leaseId, 128) : '',
|
|
6138
|
+
targetNodeId: inactive.agentKept ? safeRemoteAgentField(remoteAgentState.nodeId, 128) : '',
|
|
6139
|
+
inactiveCount: inactive.count,
|
|
6140
|
+
inactiveElapsedMs: inactive.elapsedMs,
|
|
6141
|
+
agentKept: inactive.agentKept,
|
|
6080
6142
|
lastError: ''
|
|
6081
6143
|
});
|
|
6082
6144
|
await reportRemoteRegistryFollowerSync({
|
|
6083
6145
|
ok: true,
|
|
6084
6146
|
skipped: true,
|
|
6085
|
-
reason:
|
|
6147
|
+
reason: inactive.agentKept ? `${inactiveReason}-agent-kept` : inactiveReason,
|
|
6086
6148
|
trigger,
|
|
6087
|
-
authenticated: true
|
|
6149
|
+
authenticated: true,
|
|
6150
|
+
targetEndpoint: keptManager,
|
|
6151
|
+
targetEndpointCandidates: keptCandidates,
|
|
6152
|
+
targetLeaseId: inactive.agentKept ? remoteAgentState.leaseId : '',
|
|
6153
|
+
targetNodeId: inactive.agentKept ? remoteAgentState.nodeId : '',
|
|
6154
|
+
inactiveCount: inactive.count,
|
|
6155
|
+
inactiveElapsedMs: inactive.elapsedMs,
|
|
6156
|
+
agentKept: inactive.agentKept
|
|
6088
6157
|
});
|
|
6089
6158
|
scheduleRemoteRegistryFollower(REMOTE_REGISTRY_FOLLOWER_POLL_MS, 'no-target');
|
|
6090
6159
|
return serializeRemoteRegistryFollowerState();
|
|
6091
6160
|
}
|
|
6092
6161
|
|
|
6162
|
+
resetRemoteRegistryInactiveTargetGrace();
|
|
6163
|
+
|
|
6093
6164
|
if (isRemoteRegistryTargetSameAsLocalHost(localHub, target)) {
|
|
6094
6165
|
updateRemoteRegistryFollowerState({
|
|
6095
6166
|
status: 'skipped',
|