@mindexec/cli 0.2.208 → 0.2.210

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +152 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindexec/cli",
3
- "version": "0.2.208",
3
+ "version": "0.2.210",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
package/server.js CHANGED
@@ -3610,13 +3610,14 @@ function createRemoteAgentIdleState(overrides = {}) {
3610
3610
  stderrTail: '',
3611
3611
  launcher: '',
3612
3612
  usingNpx: false,
3613
+ pairToken: '',
3613
3614
  proc: null,
3614
3615
  ...overrides
3615
3616
  };
3616
3617
  }
3617
3618
 
3618
3619
  function serializeRemoteAgentState() {
3619
- const { proc, ...publicState } = remoteAgentState;
3620
+ const { proc, pairToken, ...publicState } = remoteAgentState;
3620
3621
  return {
3621
3622
  ...publicState,
3622
3623
  registrySync: remoteAgentSyncReportState,
@@ -3757,6 +3758,32 @@ function markRemoteAgentReconnectNeededFromReport(report) {
3757
3758
  return markRemoteAgentReconnectNeeded(reason, 'agent-sync-report-disconnected');
3758
3759
  }
3759
3760
 
3761
+ function isRecentRemoteRegistryFollowerAuthenticated(maxAgeMs = 120000) {
3762
+ if (remoteRegistryFollowerState?.authenticated !== true) {
3763
+ return false;
3764
+ }
3765
+
3766
+ const lastSuccessAt = Date.parse(remoteRegistryFollowerState.lastSuccessAt || remoteRegistryFollowerState.lastAttemptAt || '');
3767
+ return Number.isFinite(lastSuccessAt) && Date.now() - lastSuccessAt <= maxAgeMs;
3768
+ }
3769
+
3770
+ function shouldIgnoreBrowserUnauthRemoteAgentSyncReport(report) {
3771
+ if (!report
3772
+ || report.authenticated === true
3773
+ || !/^(sync|browser-sync|web-sync)$/i.test(String(report.trigger || ''))) {
3774
+ return false;
3775
+ }
3776
+
3777
+ const reason = String(report.reason || report.error || '').trim();
3778
+ if (!/^(registry-not-authenticated|registry-auth-pending|session-expired|registry-auth-pending-agent-kept|registry-not-authenticated-agent-kept|session-expired-agent-kept)$/i.test(reason)) {
3779
+ return false;
3780
+ }
3781
+
3782
+ return report.localHostTargetActive === true
3783
+ || isLocalRemoteHostTargetActive()
3784
+ || isRecentRemoteRegistryFollowerAuthenticated();
3785
+ }
3786
+
3760
3787
  function isRemoteAgentOutputReconnectSignal(text) {
3761
3788
  const normalized = String(text || '').toLowerCase();
3762
3789
  if (!normalized) {
@@ -3771,6 +3798,22 @@ function isRemoteAgentOutputReconnectSignal(text) {
3771
3798
  }
3772
3799
 
3773
3800
  function rememberRemoteAgentSyncReport(report) {
3801
+ if (shouldIgnoreBrowserUnauthRemoteAgentSyncReport(report)) {
3802
+ const now = Date.now();
3803
+ const key = `ignored-browser-unauth|${report.reason || report.error || ''}|${remoteRegistryFollowerState.reason || ''}|${isLocalRemoteHostTargetActive() ? 'local-host' : 'follower-auth'}`;
3804
+ if (key !== remoteAgentSyncReportLogKey
3805
+ || now - remoteAgentSyncReportLogAt >= REMOTE_AGENT_SYNC_REPORT_LOG_REPEAT_MS) {
3806
+ remoteAgentSyncReportLogKey = key;
3807
+ remoteAgentSyncReportLogAt = now;
3808
+ logEvent(
3809
+ 'remote',
3810
+ `registry sync ignored browser unauth report ${formatKeyValue('reason', report.reason || report.error || '-')} ${formatKeyValue('bridgeAuth', remoteRegistryFollowerState?.authenticated ? 'yes' : 'no')} ${formatKeyValue('localHost', isLocalRemoteHostTargetActive() ? 'yes' : 'no')}`,
3811
+ 'remote');
3812
+ }
3813
+ scheduleRemoteHostTargetRenewWake('ignored-browser-unauth-report', { throttleMs: REMOTE_HOST_TARGET_WAKE_RENEW_MS });
3814
+ return false;
3815
+ }
3816
+
3774
3817
  if (report?.authenticated !== true
3775
3818
  && isRemoteAgentRegistryOwned()
3776
3819
  && isRemoteAgentProcessRunning()
@@ -4266,6 +4309,39 @@ function rememberRemoteRegistryInactiveTarget(reason = 'no-active-target') {
4266
4309
  };
4267
4310
  }
4268
4311
 
4312
+ async function maybeRestartKeptRemoteAgentForMissingRegistryTarget(reason = 'no-active-target') {
4313
+ if (!isRemoteAgentRegistryOwned()
4314
+ || !isRemoteAgentProcessRunning()
4315
+ || isRemoteAgentReadyDataPlaneAlive()
4316
+ || !isRemoteAgentRunningButNotReadyStale()) {
4317
+ return null;
4318
+ }
4319
+
4320
+ const managerCandidates = normalizeRemoteManagerEndpointList(remoteAgentState.managerCandidates, remoteAgentState.manager);
4321
+ const manager = managerCandidates[0] || normalizeRemoteManagerEndpoint(remoteAgentState.manager);
4322
+ const pairToken = safeRemoteAgentField(remoteAgentState.pairToken, 512);
4323
+ if (!manager || !pairToken) {
4324
+ markRemoteAgentReconnectNeeded(`${reason}-missing-target-agent-stale`, 'missing-target-agent-stale');
4325
+ return {
4326
+ ok: false,
4327
+ error: pairToken ? 'missing-manager' : 'missing-pair-token'
4328
+ };
4329
+ }
4330
+
4331
+ logWarn(
4332
+ 'remote',
4333
+ `registry target missing but managed RemoteAgent is stale; reconnecting previous manager ${formatKeyValue('reason', reason)} ${formatKeyValue('manager', manager)}`);
4334
+ return await startRemoteAgentConnection({
4335
+ manager,
4336
+ managerCandidates,
4337
+ pairToken,
4338
+ leaseId: remoteAgentState.leaseId,
4339
+ nodeId: remoteAgentState.nodeId,
4340
+ engine: remoteAgentState.engine || 'auto',
4341
+ source: remoteAgentState.source || 'local-bridge-registry-recovery'
4342
+ });
4343
+ }
4344
+
4269
4345
  function isLocalRemoteHostTargetActive() {
4270
4346
  const status = remoteHub.getStatus({ includeSecrets: false });
4271
4347
  return status?.hostTargetActive === true
@@ -4704,6 +4780,7 @@ function createRemoteAgentAttempt(options = {}) {
4704
4780
  managerCandidates,
4705
4781
  leaseId,
4706
4782
  nodeId,
4783
+ pairToken,
4707
4784
  engine,
4708
4785
  source,
4709
4786
  connectionKey,
@@ -4718,6 +4795,7 @@ function createRemoteAgentAttempt(options = {}) {
4718
4795
  managerCandidates,
4719
4796
  leaseId,
4720
4797
  nodeId,
4798
+ pairToken,
4721
4799
  engine,
4722
4800
  source,
4723
4801
  connectionKey,
@@ -4855,6 +4933,7 @@ async function startRemoteAgentConnectionRace(options = {}) {
4855
4933
  managerCandidates: managers,
4856
4934
  leaseId,
4857
4935
  nodeId,
4936
+ pairToken,
4858
4937
  engine,
4859
4938
  source,
4860
4939
  startedAt: new Date().toISOString(),
@@ -4992,6 +5071,7 @@ async function startRemoteAgentConnectionAttempt(options = {}) {
4992
5071
  managerCandidates,
4993
5072
  leaseId,
4994
5073
  nodeId,
5074
+ pairToken,
4995
5075
  engine,
4996
5076
  source,
4997
5077
  connectionKey,
@@ -5632,6 +5712,39 @@ function readSupabaseSessionField(source, ...keys) {
5632
5712
  return '';
5633
5713
  }
5634
5714
 
5715
+ function unwrapSupabaseSessionCandidate(value, depth = 0) {
5716
+ if (!value || typeof value !== 'object' || depth > 4) {
5717
+ return value;
5718
+ }
5719
+
5720
+ const directAccessToken = readSupabaseSessionField(value, 'access_token', 'accessToken', 'AccessToken');
5721
+ const directUser = value.user || value.User;
5722
+ if (directAccessToken && directUser) {
5723
+ return value;
5724
+ }
5725
+
5726
+ const candidates = [
5727
+ value.session,
5728
+ value.Session,
5729
+ value.currentSession,
5730
+ value.CurrentSession,
5731
+ value.supabaseSession,
5732
+ value.SupabaseSession,
5733
+ value.authSession,
5734
+ value.AuthSession
5735
+ ];
5736
+ for (const candidate of candidates) {
5737
+ if (candidate && typeof candidate === 'object') {
5738
+ const unwrapped = unwrapSupabaseSessionCandidate(candidate, depth + 1);
5739
+ if (unwrapped && typeof unwrapped === 'object') {
5740
+ return unwrapped;
5741
+ }
5742
+ }
5743
+ }
5744
+
5745
+ return value;
5746
+ }
5747
+
5635
5748
  function parseSupabaseSessionExpiresAtMs(value) {
5636
5749
  if (value === undefined || value === null || String(value).trim() === '') {
5637
5750
  return 0;
@@ -5662,10 +5775,14 @@ function setSupabaseSessionKnownField(session, value, fallbackKey, ...keys) {
5662
5775
 
5663
5776
  function buildRefreshedSupabaseSessionPayload(content, refreshedSession) {
5664
5777
  const existing = JSON.parse(String(content || '{}'));
5778
+ const targetSession = unwrapSupabaseSessionCandidate(existing);
5779
+ const sessionToUpdate = targetSession && typeof targetSession === 'object' ? targetSession : existing;
5665
5780
  const accessToken = String(readSupabaseSessionField(refreshedSession, 'access_token', 'accessToken', 'AccessToken')).trim();
5666
5781
  const refreshToken = String(readSupabaseSessionField(refreshedSession, 'refresh_token', 'refreshToken', 'RefreshToken')).trim()
5782
+ || String(readSupabaseSessionField(sessionToUpdate, 'refresh_token', 'refreshToken', 'RefreshToken')).trim()
5667
5783
  || String(readSupabaseSessionField(existing, 'refresh_token', 'refreshToken', 'RefreshToken')).trim();
5668
5784
  const tokenType = String(readSupabaseSessionField(refreshedSession, 'token_type', 'tokenType', 'TokenType')).trim()
5785
+ || String(readSupabaseSessionField(sessionToUpdate, 'token_type', 'tokenType', 'TokenType')).trim()
5669
5786
  || String(readSupabaseSessionField(existing, 'token_type', 'tokenType', 'TokenType')).trim()
5670
5787
  || 'bearer';
5671
5788
  const expiresInRaw = Number(readSupabaseSessionField(refreshedSession, 'expires_in', 'expiresIn', 'ExpiresIn') || 0);
@@ -5680,21 +5797,21 @@ function buildRefreshedSupabaseSessionPayload(content, refreshedSession) {
5680
5797
  throw error;
5681
5798
  }
5682
5799
 
5683
- setSupabaseSessionKnownField(existing, accessToken, 'access_token', 'access_token', 'accessToken', 'AccessToken');
5684
- setSupabaseSessionKnownField(existing, refreshToken, 'refresh_token', 'refresh_token', 'refreshToken', 'RefreshToken');
5685
- setSupabaseSessionKnownField(existing, tokenType, 'token_type', 'token_type', 'tokenType', 'TokenType');
5686
- setSupabaseSessionKnownField(existing, expiresAtSeconds, 'expires_at', 'expires_at', 'expiresAt', 'ExpiresAt');
5800
+ setSupabaseSessionKnownField(sessionToUpdate, accessToken, 'access_token', 'access_token', 'accessToken', 'AccessToken');
5801
+ setSupabaseSessionKnownField(sessionToUpdate, refreshToken, 'refresh_token', 'refresh_token', 'refreshToken', 'RefreshToken');
5802
+ setSupabaseSessionKnownField(sessionToUpdate, tokenType, 'token_type', 'token_type', 'tokenType', 'TokenType');
5803
+ setSupabaseSessionKnownField(sessionToUpdate, expiresAtSeconds, 'expires_at', 'expires_at', 'expiresAt', 'ExpiresAt');
5687
5804
 
5688
5805
  if (Number.isFinite(expiresInRaw) && expiresInRaw > 0) {
5689
- setSupabaseSessionKnownField(existing, Math.floor(expiresInRaw), 'expires_in', 'expires_in', 'expiresIn', 'ExpiresIn');
5806
+ setSupabaseSessionKnownField(sessionToUpdate, Math.floor(expiresInRaw), 'expires_in', 'expires_in', 'expiresIn', 'ExpiresIn');
5690
5807
  }
5691
5808
 
5692
5809
  const user = refreshedSession?.user || refreshedSession?.User;
5693
5810
  if (user && typeof user === 'object') {
5694
- if (Object.prototype.hasOwnProperty.call(existing, 'User')) {
5695
- existing.User = user;
5811
+ if (Object.prototype.hasOwnProperty.call(sessionToUpdate, 'User')) {
5812
+ sessionToUpdate.User = user;
5696
5813
  } else {
5697
- existing.user = user;
5814
+ sessionToUpdate.user = user;
5698
5815
  }
5699
5816
  }
5700
5817
 
@@ -5704,18 +5821,27 @@ function buildRefreshedSupabaseSessionPayload(content, refreshedSession) {
5704
5821
  function parseSupabaseSessionForRegistry(content) {
5705
5822
  let session = null;
5706
5823
  try {
5707
- session = JSON.parse(String(content || ''));
5824
+ session = unwrapSupabaseSessionCandidate(JSON.parse(String(content || '')));
5708
5825
  } catch {
5709
5826
  return null;
5710
5827
  }
5711
5828
 
5712
5829
  const user = session?.user || session?.User || {};
5713
- const accessToken = String(readSupabaseSessionField(session, 'access_token', 'accessToken', 'AccessToken')).trim();
5830
+ const accessToken = String(readSupabaseSessionField(session, 'access_token', 'accessToken', 'AccessToken', 'token', 'Token')).trim();
5714
5831
  const refreshToken = String(readSupabaseSessionField(session, 'refresh_token', 'refreshToken', 'RefreshToken')).trim();
5715
5832
  const userId = String(
5716
5833
  readSupabaseSessionField(user, 'id', 'Id')
5717
5834
  || readSupabaseSessionField(session, 'user_id', 'userId', 'UserId')).trim();
5718
- const expiresAtMs = parseSupabaseSessionExpiresAtMs(readSupabaseSessionField(session, 'expires_at', 'expiresAt', 'ExpiresAt'));
5835
+ const expiresAtMs = parseSupabaseSessionExpiresAtMs(readSupabaseSessionField(
5836
+ session,
5837
+ 'expires_at',
5838
+ 'expiresAt',
5839
+ 'ExpiresAt',
5840
+ 'expires_at_ms',
5841
+ 'expiresAtMs',
5842
+ 'ExpiresAtMs',
5843
+ 'expiresAtUnixTime',
5844
+ 'ExpiresAtUnixTime'));
5719
5845
 
5720
5846
  if (!accessToken || !userId) {
5721
5847
  return null;
@@ -6864,6 +6990,9 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
6864
6990
  ? 'registry-inactive'
6865
6991
  : 'no-active-target';
6866
6992
  const inactive = rememberRemoteRegistryInactiveTarget(inactiveReason);
6993
+ const recovery = inactive.agentKept
6994
+ ? await maybeRestartKeptRemoteAgentForMissingRegistryTarget(inactiveReason)
6995
+ : null;
6867
6996
  if (inactive.confirmedInactive && isRemoteAgentRegistryOwned()) {
6868
6997
  await stopRemoteAgentConnection('registry-inactive');
6869
6998
  }
@@ -6883,12 +7012,15 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
6883
7012
  inactiveElapsedMs: inactive.elapsedMs,
6884
7013
  agentKept: inactive.agentKept,
6885
7014
  dataPlaneReady: inactive.dataPlaneReady,
6886
- lastError: ''
7015
+ lastError: recovery?.ok === false ? (recovery.error || 'missing-target-agent-recovery-failed') : ''
6887
7016
  });
6888
7017
  await reportRemoteRegistryFollowerSync({
6889
- ok: true,
7018
+ ok: recovery?.ok === false ? false : true,
6890
7019
  skipped: true,
6891
- reason: inactive.agentKept ? `${inactiveReason}-agent-kept` : inactiveReason,
7020
+ reason: recovery?.ok === true
7021
+ ? `${inactiveReason}-agent-recovered`
7022
+ : (inactive.agentKept ? `${inactiveReason}-agent-kept` : inactiveReason),
7023
+ error: recovery?.ok === false ? recovery.error : '',
6892
7024
  trigger,
6893
7025
  authenticated: true,
6894
7026
  targetEndpoint: keptManager,
@@ -6900,7 +7032,11 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
6900
7032
  agentKept: inactive.agentKept,
6901
7033
  dataPlaneReady: inactive.dataPlaneReady
6902
7034
  });
6903
- scheduleRemoteRegistryFollower(REMOTE_REGISTRY_FOLLOWER_POLL_MS, 'no-target');
7035
+ scheduleRemoteRegistryFollower(
7036
+ inactive.agentKept && !inactive.dataPlaneReady
7037
+ ? REMOTE_REGISTRY_FOLLOWER_FAST_RETRY_MS
7038
+ : REMOTE_REGISTRY_FOLLOWER_POLL_MS,
7039
+ recovery?.ok === true ? 'missing-target-agent-recovered' : 'no-target');
6904
7040
  return serializeRemoteRegistryFollowerState();
6905
7041
  }
6906
7042