@mindexec/cli 0.2.209 → 0.2.211

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.209",
3
+ "version": "0.2.211",
4
4
  "description": "MindExec local runtime and bridge CLI",
5
5
  "main": "server.js",
6
6
  "type": "module",
@@ -138,11 +138,25 @@ try {
138
138
  const sessionPayload = JSON.stringify({
139
139
  access_token: 'access-token-a',
140
140
  refresh_token: 'refresh-token-a',
141
+ expires_at: Math.floor(Date.now() / 1000) + 600,
141
142
  user: {
142
143
  id: 'user-a',
143
144
  email: 'auth-smoke@example.com'
144
145
  }
145
146
  });
147
+ let expectedStablePayload = sessionPayload;
148
+
149
+ function makeTimedSessionPayload(accessToken, refreshToken, expiresInSeconds) {
150
+ return JSON.stringify({
151
+ access_token: accessToken,
152
+ refresh_token: refreshToken,
153
+ expires_at: Math.floor(Date.now() / 1000) + expiresInSeconds,
154
+ user: {
155
+ id: 'user-a',
156
+ email: 'auth-smoke@example.com'
157
+ }
158
+ });
159
+ }
146
160
 
147
161
  await withBridge({ workspacePath: workspaceA, authDataRoot }, async (baseUrl) => {
148
162
  const unauthorized = await fetchJson(`${baseUrl}/api/auth/session`);
@@ -170,12 +184,41 @@ try {
170
184
  assert.equal(loaded.status, 200);
171
185
  assert.equal(loaded.payload?.content, sessionPayload);
172
186
  assert.equal(loaded.payload?.source, 'stable');
187
+
188
+ const newerPayload = makeTimedSessionPayload('access-token-newer', 'refresh-token-newer', 3600);
189
+ const newerSaved = await fetchJson(`${baseUrl}/api/auth/session`, {
190
+ method: 'POST',
191
+ token: BRIDGE_TOKEN,
192
+ body: JSON.stringify({ content: newerPayload })
193
+ });
194
+ assert.equal(newerSaved.status, 200);
195
+
196
+ const staleBrowserPayload = makeTimedSessionPayload('access-token-stale-browser', 'refresh-token-stale-browser', 120);
197
+ const staleSaved = await fetchJson(`${baseUrl}/api/auth/session`, {
198
+ method: 'POST',
199
+ token: BRIDGE_TOKEN,
200
+ body: JSON.stringify({ content: staleBrowserPayload })
201
+ });
202
+ assert.equal(staleSaved.status, 200);
203
+
204
+ const afterStale = await fetchJson(`${baseUrl}/api/auth/session`, { token: BRIDGE_TOKEN });
205
+ assert.equal(afterStale.status, 200);
206
+ assert.equal(JSON.parse(afterStale.payload?.content || '{}').access_token, 'access-token-newer');
207
+
208
+ const newestPayload = makeTimedSessionPayload('access-token-newest', 'refresh-token-newest', 7200);
209
+ const newestSaved = await fetchJson(`${baseUrl}/api/auth/session`, {
210
+ method: 'POST',
211
+ token: BRIDGE_TOKEN,
212
+ body: JSON.stringify({ content: newestPayload })
213
+ });
214
+ assert.equal(newestSaved.status, 200);
215
+ expectedStablePayload = newestPayload;
173
216
  });
174
217
 
175
218
  await withBridge({ workspacePath: workspaceB, authDataRoot }, async (baseUrl) => {
176
219
  const loaded = await fetchJson(`${baseUrl}/api/auth/session`, { token: BRIDGE_TOKEN });
177
220
  assert.equal(loaded.status, 200);
178
- assert.equal(loaded.payload?.content, sessionPayload);
221
+ assert.equal(loaded.payload?.content, expectedStablePayload);
179
222
  assert.equal(loaded.payload?.source, 'stable');
180
223
 
181
224
  const deleted = await fetchJson(`${baseUrl}/api/auth/session`, {
package/server.js CHANGED
@@ -669,10 +669,49 @@ async function readStableAuthSessionPayload() {
669
669
  async function writeStableAuthSessionPayload(content) {
670
670
  const payload = validateAuthSessionPayload(content);
671
671
  const stablePath = getStableSupabaseSessionPath();
672
+ const existingPayload = await tryReadTextFile(stablePath);
673
+ if (shouldKeepExistingAuthSessionPayload(existingPayload, payload)) {
674
+ return stablePath;
675
+ }
676
+
672
677
  await writePrivateTextFile(stablePath, payload);
673
678
  return stablePath;
674
679
  }
675
680
 
681
+ function shouldKeepExistingAuthSessionPayload(existingContent, incomingContent) {
682
+ if (!existingContent || !String(existingContent).trim()) {
683
+ return false;
684
+ }
685
+
686
+ const existing = parseSupabaseSessionForRegistry(existingContent);
687
+ const incoming = parseSupabaseSessionForRegistry(incomingContent);
688
+ if (!existing || !incoming) {
689
+ return false;
690
+ }
691
+
692
+ if (!existing.userId || !incoming.userId || existing.userId !== incoming.userId) {
693
+ return false;
694
+ }
695
+
696
+ if (!Number.isFinite(existing.expiresAtMs) || !Number.isFinite(incoming.expiresAtMs)) {
697
+ return false;
698
+ }
699
+
700
+ const now = Date.now();
701
+ const existingRemainingMs = existing.expiresAtMs - now;
702
+ const incomingRemainingMs = incoming.expiresAtMs - now;
703
+ const staleSkewMs = 30_000;
704
+ if (existingRemainingMs <= staleSkewMs || incoming.expiresAtMs + staleSkewMs >= existing.expiresAtMs) {
705
+ return false;
706
+ }
707
+
708
+ logEvent(
709
+ 'remote',
710
+ `auth session write ignored stale payload ${formatKeyValue('existingMs', Math.max(0, existingRemainingMs))} ${formatKeyValue('incomingMs', Math.max(0, incomingRemainingMs))}`,
711
+ 'remote');
712
+ return true;
713
+ }
714
+
676
715
  async function deleteStableAuthSessionPayload() {
677
716
  const paths = [
678
717
  getStableSupabaseSessionPath(),
@@ -3610,13 +3649,14 @@ function createRemoteAgentIdleState(overrides = {}) {
3610
3649
  stderrTail: '',
3611
3650
  launcher: '',
3612
3651
  usingNpx: false,
3652
+ pairToken: '',
3613
3653
  proc: null,
3614
3654
  ...overrides
3615
3655
  };
3616
3656
  }
3617
3657
 
3618
3658
  function serializeRemoteAgentState() {
3619
- const { proc, ...publicState } = remoteAgentState;
3659
+ const { proc, pairToken, ...publicState } = remoteAgentState;
3620
3660
  return {
3621
3661
  ...publicState,
3622
3662
  registrySync: remoteAgentSyncReportState,
@@ -3757,6 +3797,32 @@ function markRemoteAgentReconnectNeededFromReport(report) {
3757
3797
  return markRemoteAgentReconnectNeeded(reason, 'agent-sync-report-disconnected');
3758
3798
  }
3759
3799
 
3800
+ function isRecentRemoteRegistryFollowerAuthenticated(maxAgeMs = 120000) {
3801
+ if (remoteRegistryFollowerState?.authenticated !== true) {
3802
+ return false;
3803
+ }
3804
+
3805
+ const lastSuccessAt = Date.parse(remoteRegistryFollowerState.lastSuccessAt || remoteRegistryFollowerState.lastAttemptAt || '');
3806
+ return Number.isFinite(lastSuccessAt) && Date.now() - lastSuccessAt <= maxAgeMs;
3807
+ }
3808
+
3809
+ function shouldIgnoreBrowserUnauthRemoteAgentSyncReport(report) {
3810
+ if (!report
3811
+ || report.authenticated === true
3812
+ || !/^(sync|browser-sync|web-sync)$/i.test(String(report.trigger || ''))) {
3813
+ return false;
3814
+ }
3815
+
3816
+ const reason = String(report.reason || report.error || '').trim();
3817
+ 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)) {
3818
+ return false;
3819
+ }
3820
+
3821
+ return report.localHostTargetActive === true
3822
+ || isLocalRemoteHostTargetActive()
3823
+ || isRecentRemoteRegistryFollowerAuthenticated();
3824
+ }
3825
+
3760
3826
  function isRemoteAgentOutputReconnectSignal(text) {
3761
3827
  const normalized = String(text || '').toLowerCase();
3762
3828
  if (!normalized) {
@@ -3771,6 +3837,22 @@ function isRemoteAgentOutputReconnectSignal(text) {
3771
3837
  }
3772
3838
 
3773
3839
  function rememberRemoteAgentSyncReport(report) {
3840
+ if (shouldIgnoreBrowserUnauthRemoteAgentSyncReport(report)) {
3841
+ const now = Date.now();
3842
+ const key = `ignored-browser-unauth|${report.reason || report.error || ''}|${remoteRegistryFollowerState.reason || ''}|${isLocalRemoteHostTargetActive() ? 'local-host' : 'follower-auth'}`;
3843
+ if (key !== remoteAgentSyncReportLogKey
3844
+ || now - remoteAgentSyncReportLogAt >= REMOTE_AGENT_SYNC_REPORT_LOG_REPEAT_MS) {
3845
+ remoteAgentSyncReportLogKey = key;
3846
+ remoteAgentSyncReportLogAt = now;
3847
+ logEvent(
3848
+ 'remote',
3849
+ `registry sync ignored browser unauth report ${formatKeyValue('reason', report.reason || report.error || '-')} ${formatKeyValue('bridgeAuth', remoteRegistryFollowerState?.authenticated ? 'yes' : 'no')} ${formatKeyValue('localHost', isLocalRemoteHostTargetActive() ? 'yes' : 'no')}`,
3850
+ 'remote');
3851
+ }
3852
+ scheduleRemoteHostTargetRenewWake('ignored-browser-unauth-report', { throttleMs: REMOTE_HOST_TARGET_WAKE_RENEW_MS });
3853
+ return false;
3854
+ }
3855
+
3774
3856
  if (report?.authenticated !== true
3775
3857
  && isRemoteAgentRegistryOwned()
3776
3858
  && isRemoteAgentProcessRunning()
@@ -4266,6 +4348,39 @@ function rememberRemoteRegistryInactiveTarget(reason = 'no-active-target') {
4266
4348
  };
4267
4349
  }
4268
4350
 
4351
+ async function maybeRestartKeptRemoteAgentForMissingRegistryTarget(reason = 'no-active-target') {
4352
+ if (!isRemoteAgentRegistryOwned()
4353
+ || !isRemoteAgentProcessRunning()
4354
+ || isRemoteAgentReadyDataPlaneAlive()
4355
+ || !isRemoteAgentRunningButNotReadyStale()) {
4356
+ return null;
4357
+ }
4358
+
4359
+ const managerCandidates = normalizeRemoteManagerEndpointList(remoteAgentState.managerCandidates, remoteAgentState.manager);
4360
+ const manager = managerCandidates[0] || normalizeRemoteManagerEndpoint(remoteAgentState.manager);
4361
+ const pairToken = safeRemoteAgentField(remoteAgentState.pairToken, 512);
4362
+ if (!manager || !pairToken) {
4363
+ markRemoteAgentReconnectNeeded(`${reason}-missing-target-agent-stale`, 'missing-target-agent-stale');
4364
+ return {
4365
+ ok: false,
4366
+ error: pairToken ? 'missing-manager' : 'missing-pair-token'
4367
+ };
4368
+ }
4369
+
4370
+ logWarn(
4371
+ 'remote',
4372
+ `registry target missing but managed RemoteAgent is stale; reconnecting previous manager ${formatKeyValue('reason', reason)} ${formatKeyValue('manager', manager)}`);
4373
+ return await startRemoteAgentConnection({
4374
+ manager,
4375
+ managerCandidates,
4376
+ pairToken,
4377
+ leaseId: remoteAgentState.leaseId,
4378
+ nodeId: remoteAgentState.nodeId,
4379
+ engine: remoteAgentState.engine || 'auto',
4380
+ source: remoteAgentState.source || 'local-bridge-registry-recovery'
4381
+ });
4382
+ }
4383
+
4269
4384
  function isLocalRemoteHostTargetActive() {
4270
4385
  const status = remoteHub.getStatus({ includeSecrets: false });
4271
4386
  return status?.hostTargetActive === true
@@ -4704,6 +4819,7 @@ function createRemoteAgentAttempt(options = {}) {
4704
4819
  managerCandidates,
4705
4820
  leaseId,
4706
4821
  nodeId,
4822
+ pairToken,
4707
4823
  engine,
4708
4824
  source,
4709
4825
  connectionKey,
@@ -4718,6 +4834,7 @@ function createRemoteAgentAttempt(options = {}) {
4718
4834
  managerCandidates,
4719
4835
  leaseId,
4720
4836
  nodeId,
4837
+ pairToken,
4721
4838
  engine,
4722
4839
  source,
4723
4840
  connectionKey,
@@ -4855,6 +4972,7 @@ async function startRemoteAgentConnectionRace(options = {}) {
4855
4972
  managerCandidates: managers,
4856
4973
  leaseId,
4857
4974
  nodeId,
4975
+ pairToken,
4858
4976
  engine,
4859
4977
  source,
4860
4978
  startedAt: new Date().toISOString(),
@@ -4992,6 +5110,7 @@ async function startRemoteAgentConnectionAttempt(options = {}) {
4992
5110
  managerCandidates,
4993
5111
  leaseId,
4994
5112
  nodeId,
5113
+ pairToken,
4995
5114
  engine,
4996
5115
  source,
4997
5116
  connectionKey,
@@ -6910,6 +7029,9 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
6910
7029
  ? 'registry-inactive'
6911
7030
  : 'no-active-target';
6912
7031
  const inactive = rememberRemoteRegistryInactiveTarget(inactiveReason);
7032
+ const recovery = inactive.agentKept
7033
+ ? await maybeRestartKeptRemoteAgentForMissingRegistryTarget(inactiveReason)
7034
+ : null;
6913
7035
  if (inactive.confirmedInactive && isRemoteAgentRegistryOwned()) {
6914
7036
  await stopRemoteAgentConnection('registry-inactive');
6915
7037
  }
@@ -6929,12 +7051,15 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
6929
7051
  inactiveElapsedMs: inactive.elapsedMs,
6930
7052
  agentKept: inactive.agentKept,
6931
7053
  dataPlaneReady: inactive.dataPlaneReady,
6932
- lastError: ''
7054
+ lastError: recovery?.ok === false ? (recovery.error || 'missing-target-agent-recovery-failed') : ''
6933
7055
  });
6934
7056
  await reportRemoteRegistryFollowerSync({
6935
- ok: true,
7057
+ ok: recovery?.ok === false ? false : true,
6936
7058
  skipped: true,
6937
- reason: inactive.agentKept ? `${inactiveReason}-agent-kept` : inactiveReason,
7059
+ reason: recovery?.ok === true
7060
+ ? `${inactiveReason}-agent-recovered`
7061
+ : (inactive.agentKept ? `${inactiveReason}-agent-kept` : inactiveReason),
7062
+ error: recovery?.ok === false ? recovery.error : '',
6938
7063
  trigger,
6939
7064
  authenticated: true,
6940
7065
  targetEndpoint: keptManager,
@@ -6946,7 +7071,11 @@ async function runRemoteRegistryFollowerOnce(trigger = 'timer') {
6946
7071
  agentKept: inactive.agentKept,
6947
7072
  dataPlaneReady: inactive.dataPlaneReady
6948
7073
  });
6949
- scheduleRemoteRegistryFollower(REMOTE_REGISTRY_FOLLOWER_POLL_MS, 'no-target');
7074
+ scheduleRemoteRegistryFollower(
7075
+ inactive.agentKept && !inactive.dataPlaneReady
7076
+ ? REMOTE_REGISTRY_FOLLOWER_FAST_RETRY_MS
7077
+ : REMOTE_REGISTRY_FOLLOWER_POLL_MS,
7078
+ recovery?.ok === true ? 'missing-target-agent-recovered' : 'no-target');
6950
7079
  return serializeRemoteRegistryFollowerState();
6951
7080
  }
6952
7081
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mainAssemblyName": "MindExecution.Web",
3
3
  "resources": {
4
- "hash": "sha256-Ny3t+3+wMEcLBIrH8PviSLxWnIKH3h8bXWdrXi8ESDY=",
4
+ "hash": "sha256-iiSeCvB5NpvqIW1+MQgzzc+UStFn80YeJUyFtdiuER8=",
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.kibqg6rvqh.dll": "MindExecution.Plugins.PlanMaster.dll",
133
133
  "MindExecution.Plugins.YouTube.089r64n2hv.dll": "MindExecution.Plugins.YouTube.dll",
134
134
  "MindExecution.Shared.p86iw1fhns.dll": "MindExecution.Shared.dll",
135
- "MindExecution.Web.aj117i28hy.dll": "MindExecution.Web.dll",
135
+ "MindExecution.Web.7axuoygrwi.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.u9kzsgf64o.dll": "sha256-Yp38m6zHe8EBxtm480N4LfcHRpzFZRhYpr1RsCgnlK8=",
285
285
  "MindExecution.Plugins.PlanMaster.kibqg6rvqh.dll": "sha256-NOtEHR8Y0rO8BguFvD1soa8jfB4YVQFydten0SzqBEg=",
286
286
  "MindExecution.Shared.p86iw1fhns.dll": "sha256-GeQGsY17FMYu6beNS1RDR7yJ/nNgfiix6rjORzhXnCY=",
287
- "MindExecution.Web.aj117i28hy.dll": "sha256-+jKjBygtNF6dsjwsyJ+O2NId2p7HeQk4rYksxd+SqPA="
287
+ "MindExecution.Web.7axuoygrwi.dll": "sha256-/6NQ8z9E7ixNwgYD71eh6M6YCGzctKodTWcZNJcNF8E="
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": "3ooTJksk",
2
+ "version": "YLV1KsFI",
3
3
  "assets": [
4
4
  {
5
5
  "hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
@@ -446,8 +446,8 @@
446
446
  "url": "_framework/MindExecution.Shared.p86iw1fhns.dll"
447
447
  },
448
448
  {
449
- "hash": "sha256-+jKjBygtNF6dsjwsyJ+O2NId2p7HeQk4rYksxd+SqPA=",
450
- "url": "_framework/MindExecution.Web.aj117i28hy.dll"
449
+ "hash": "sha256-/6NQ8z9E7ixNwgYD71eh6M6YCGzctKodTWcZNJcNF8E=",
450
+ "url": "_framework/MindExecution.Web.7axuoygrwi.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-txW3qdrqdJhTHyMMLK0IDsdhphqslC5BjXEhWNo5jpM=",
773
+ "hash": "sha256-xLiOU/vuEmRFIqaJXh1WMyuEaWcsagGwx5Uq71HsjkY=",
774
774
  "url": "_framework/blazor.boot.json"
775
775
  },
776
776
  {
@@ -1,4 +1,4 @@
1
- /* Manifest version: 3ooTJksk */
1
+ /* Manifest version: YLV1KsFI */
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