From 944dde36079f85badefd9bc7dea39fe2c982bc84 Mon Sep 17 00:00:00 2001
From: Steven Enamakel <31011319+senamakel@users.noreply.github.com>
Date: Thu, 21 May 2026 01:26:48 -0700
Subject: [PATCH 1/7] Update Product Hunt badges in README
---
README.md | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/README.md b/README.md
index 68501bfca..f34d7a4c1 100644
--- a/README.md
+++ b/README.md
@@ -5,16 +5,26 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
OpenHuman is your Personal AI super intelligence. Private, Simple and extremely powerful.
From 182c01f3a92840c96c2ebcede2d121320ccac432 Mon Sep 17 00:00:00 2001
From: M3gA-Mind
Date: Thu, 21 May 2026 20:15:23 +0530
Subject: [PATCH 2/7] fix(auth): deliver OAuth JWT to remote core in cloud mode
Two failure paths prevented the openhuman://auth deep link from
reaching a Docker-hosted remote core:
1. oauthAuthReadiness.ts pinged the core with a stale local-core
bearer token (resolved from cache). Fix: explicitly pass the
stored cloud token to testCoreRpcConnection in cloud mode.
2. CoreStateProvider's auth-expired cascade cleared the session while
auth_store_session was in flight. Fix: dispatch a 15 s suppress-
reauth window around storeSession; CoreStateProvider skips clearSession
while the window is active.
Also busts stale RPC URL/token caches before auth_store_session in
cloud mode, and improves the core_unreachable error message to name
the cloud core specifically.
Closes #2377
---
.../__tests__/oauthAuthReadiness.test.ts | 33 +++++++++++-
.../components/oauth/oauthAuthReadiness.ts | 20 +++++--
app/src/providers/CoreStateProvider.tsx | 21 ++++++++
app/src/services/coreRpcClient.ts | 6 +++
.../__tests__/desktopDeepLinkListener.test.ts | 54 +++++++++++++++++++
app/src/utils/desktopDeepLinkListener.ts | 23 +++++++-
6 files changed, 151 insertions(+), 6 deletions(-)
diff --git a/app/src/components/oauth/__tests__/oauthAuthReadiness.test.ts b/app/src/components/oauth/__tests__/oauthAuthReadiness.test.ts
index 56bbcbeb6..53ac95982 100644
--- a/app/src/components/oauth/__tests__/oauthAuthReadiness.test.ts
+++ b/app/src/components/oauth/__tests__/oauthAuthReadiness.test.ts
@@ -4,7 +4,7 @@ import { getCoreStateSnapshot } from '../../../lib/coreState/store';
import { bootCheckTransport } from '../../../services/bootCheckService';
import { testCoreRpcConnection } from '../../../services/coreRpcClient';
import { isTauri } from '../../../services/webviewAccountService';
-import { getStoredCoreMode } from '../../../utils/configPersistence';
+import { getStoredCoreMode, getStoredCoreToken } from '../../../utils/configPersistence';
import {
oauthAuthReadinessUserMessage,
prepareOAuthLoginLaunch,
@@ -22,7 +22,10 @@ vi.mock('../../../services/bootCheckService', () => ({
bootCheckTransport: { invokeCmd: vi.fn().mockResolvedValue(undefined), callRpc: vi.fn() },
}));
-vi.mock('../../../utils/configPersistence', () => ({ getStoredCoreMode: vi.fn() }));
+vi.mock('../../../utils/configPersistence', () => ({
+ getStoredCoreMode: vi.fn(),
+ getStoredCoreToken: vi.fn().mockReturnValue(null),
+}));
vi.mock('../../../services/webviewAccountService', () => ({
isTauri: vi.fn().mockReturnValue(true),
@@ -135,4 +138,30 @@ describe('oauthAuthReadiness', () => {
vi.useRealTimers();
}
});
+
+ it('returns cloud-specific message for core_unreachable when mode is cloud', () => {
+ vi.mocked(getStoredCoreMode).mockReturnValue('cloud');
+ const msg = oauthAuthReadinessUserMessage('core_unreachable');
+ expect(msg).toMatch(/remote.*cloud/i);
+ expect(msg).toMatch(/RPC URL/i);
+ });
+
+ it('returns local-specific message for core_unreachable when mode is local', () => {
+ vi.mocked(getStoredCoreMode).mockReturnValue('local');
+ const msg = oauthAuthReadinessUserMessage('core_unreachable');
+ expect(msg).toMatch(/local runtime/i);
+ expect(msg).toMatch(/Quit and reopen/i);
+ });
+
+ it('passes cloud token to testCoreRpcConnection when mode is cloud', async () => {
+ vi.mocked(getStoredCoreMode).mockReturnValue('cloud');
+ vi.mocked(getStoredCoreToken).mockReturnValue('cloud-bearer-token');
+
+ await waitForOAuthAuthReadiness(2_000);
+
+ expect(testCoreRpcConnection).toHaveBeenCalledWith(
+ 'http://127.0.0.1:7788/rpc',
+ 'cloud-bearer-token'
+ );
+ });
});
diff --git a/app/src/components/oauth/oauthAuthReadiness.ts b/app/src/components/oauth/oauthAuthReadiness.ts
index 3d519c4eb..63ba50372 100644
--- a/app/src/components/oauth/oauthAuthReadiness.ts
+++ b/app/src/components/oauth/oauthAuthReadiness.ts
@@ -4,7 +4,7 @@ import { getCoreStateSnapshot } from '../../lib/coreState/store';
import { bootCheckTransport } from '../../services/bootCheckService';
import { getCoreRpcUrl, testCoreRpcConnection } from '../../services/coreRpcClient';
import { isTauri } from '../../services/webviewAccountService';
-import { getStoredCoreMode } from '../../utils/configPersistence';
+import { getStoredCoreMode, getStoredCoreToken } from '../../utils/configPersistence';
const logPrefix = '[oauth-auth-readiness]';
const log = debug('oauth:auth-readiness');
@@ -27,7 +27,13 @@ const delay = (ms: number): Promise =>
async function pingCoreRpc(): Promise {
try {
const rpcUrl = await getCoreRpcUrl();
- const response = await testCoreRpcConnection(rpcUrl);
+ // In cloud mode, pass the stored cloud token explicitly to avoid
+ // getCoreRpcToken() resolving to a stale local-core token. See issue #2377.
+ const cloudToken = getStoredCoreMode() === 'cloud' ? getStoredCoreToken() : null;
+ log(`${logPrefix} core.ping probe`, { rpcUrl, mode: getStoredCoreMode(), hasCloudToken: Boolean(cloudToken) });
+ const response = cloudToken
+ ? await testCoreRpcConnection(rpcUrl, cloudToken)
+ : await testCoreRpcConnection(rpcUrl);
return response.ok;
} catch (err) {
log(`${logPrefix} core.ping probe failed`, err);
@@ -112,11 +118,19 @@ export function oauthAuthReadinessUserMessage(reason: OAuthAuthReadinessFailure)
'Finish choosing how OpenHuman runs (tap Continue on the setup screen), ' +
'then try signing in again.'
);
- case 'core_unreachable':
+ case 'core_unreachable': {
+ const mode = getStoredCoreMode();
+ if (mode === 'cloud') {
+ return (
+ 'OpenHuman could not reach its remote (cloud) runtime. ' +
+ 'Check your RPC URL and token in Settings, then try signing in again.'
+ );
+ }
return (
'OpenHuman could not reach its local runtime. Quit and reopen the app, ' +
'then try signing in again.'
);
+ }
default:
return 'Sign-in is still starting up. Wait a few seconds and try again.';
}
diff --git a/app/src/providers/CoreStateProvider.tsx b/app/src/providers/CoreStateProvider.tsx
index 42ca0abca..e994909b2 100644
--- a/app/src/providers/CoreStateProvider.tsx
+++ b/app/src/providers/CoreStateProvider.tsx
@@ -617,6 +617,23 @@ export default function CoreStateProvider({ children }: { children: ReactNode })
);
const lastReauthAtRef = useRef(0);
+ const suppressReauthUntilRef = useRef(0);
+
+ // Listen for deep-link auth suppression signals so that an in-flight
+ // `auth_store_session` call (OAuth deep link) does not race with the
+ // `core-rpc-auth-expired` handler and clear the session mid-delivery.
+ // See issue #2377.
+ useEffect(() => {
+ const onSuppressReauth = (event: Event) => {
+ const until = (event as CustomEvent<{ until: number }>).detail?.until ?? 0;
+ suppressReauthUntilRef.current = until;
+ log('[CoreState] suppress-reauth updated until=%d', until);
+ };
+ window.addEventListener('core-state:suppress-reauth', onSuppressReauth as EventListener);
+ return () => {
+ window.removeEventListener('core-state:suppress-reauth', onSuppressReauth as EventListener);
+ };
+ }, []);
const clearSession = useCallback(async () => {
logoutGuardUntilRef.current = Date.now() + 5_000;
@@ -665,6 +682,10 @@ export default function CoreStateProvider({ children }: { children: ReactNode })
useEffect(() => {
const runReauth = (method: string, source: string) => {
const now = Date.now();
+ if (Date.now() < suppressReauthUntilRef.current) {
+ log('[CoreState] auth-expired suppressed during deep-link auth delivery (method=%s source=%s)', method, source);
+ return;
+ }
if (now - lastReauthAtRef.current < 10_000) {
log('auth-expired debounced (method=%s source=%s)', method, source);
return;
diff --git a/app/src/services/coreRpcClient.ts b/app/src/services/coreRpcClient.ts
index 610b3fecb..e3bf0e843 100644
--- a/app/src/services/coreRpcClient.ts
+++ b/app/src/services/coreRpcClient.ts
@@ -465,6 +465,12 @@ export async function callCoreRpc({
try {
const [rpcUrl, token] = await Promise.all([getCoreRpcUrl(), getCoreRpcToken()]);
coreRpcLog('HTTP request', { id: payload.id, method: payload.method });
+ if (normalizedMethod === 'openhuman.auth_store_session') {
+ coreRpcLog('[rpc] auth_store_session routing', {
+ rpcUrl,
+ tokenSource: getStoredCoreToken() ? 'cloud-stored' : 'local-resolved',
+ });
+ }
if (coreIsTauri() && !token) {
throw new Error('Core RPC token unavailable in Tauri; local RPC auth cannot be satisfied');
}
diff --git a/app/src/utils/__tests__/desktopDeepLinkListener.test.ts b/app/src/utils/__tests__/desktopDeepLinkListener.test.ts
index 41665241d..eb41269c9 100644
--- a/app/src/utils/__tests__/desktopDeepLinkListener.test.ts
+++ b/app/src/utils/__tests__/desktopDeepLinkListener.test.ts
@@ -2,14 +2,22 @@ import { isTauri } from '@tauri-apps/api/core';
import { getCurrent, onOpenUrl } from '@tauri-apps/plugin-deep-link';
import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { clearCoreRpcTokenCache, clearCoreRpcUrlCache } from '../../services/coreRpcClient';
import {
completeDeepLinkAuthProcessing,
getDeepLinkAuthState,
subscribeDeepLinkAuthState,
} from '../../store/deepLinkAuthState';
+import { getStoredCoreMode } from '../configPersistence';
import { setupDesktopDeepLinkListener } from '../desktopDeepLinkListener';
import { storeSession } from '../tauriCommands';
+vi.mock('../configPersistence', () => ({ getStoredCoreMode: vi.fn() }));
+vi.mock('../../services/coreRpcClient', () => ({
+ clearCoreRpcUrlCache: vi.fn(),
+ clearCoreRpcTokenCache: vi.fn(),
+}));
+
const waitForAuthSettled = (): Promise =>
new Promise(resolve => {
if (!getDeepLinkAuthState().isProcessing) {
@@ -59,6 +67,9 @@ describe('desktopDeepLinkListener', () => {
waitForOAuthAuthReadiness.mockResolvedValue({ ready: true });
vi.mocked(storeSession).mockReset();
vi.mocked(storeSession).mockResolvedValue(undefined);
+ vi.mocked(getStoredCoreMode).mockReturnValue(null);
+ vi.mocked(clearCoreRpcUrlCache).mockClear();
+ vi.mocked(clearCoreRpcTokenCache).mockClear();
windowControls.show.mockClear();
windowControls.unminimize.mockClear();
windowControls.setFocus.mockClear();
@@ -194,4 +205,47 @@ describe('desktopDeepLinkListener', () => {
'OAuth sign-in failed before OpenHuman received authorization. Check the provider app settings and try again.',
});
});
+
+ it('busts RPC caches before storeSession in cloud mode', async () => {
+ vi.mocked(getStoredCoreMode).mockReturnValue('cloud');
+ vi.mocked(getCurrent).mockResolvedValue(['openhuman://auth?token=abc&key=auth']);
+
+ await setupDesktopDeepLinkListener();
+ await waitForAuthSettled();
+
+ expect(clearCoreRpcUrlCache).toHaveBeenCalledTimes(1);
+ expect(clearCoreRpcTokenCache).toHaveBeenCalledTimes(1);
+ expect(storeSession).toHaveBeenCalledWith('abc', {});
+ });
+
+ it('does NOT bust RPC caches before storeSession in local mode', async () => {
+ vi.mocked(getStoredCoreMode).mockReturnValue('local');
+ vi.mocked(getCurrent).mockResolvedValue(['openhuman://auth?token=abc&key=auth']);
+
+ await setupDesktopDeepLinkListener();
+ await waitForAuthSettled();
+
+ expect(clearCoreRpcUrlCache).not.toHaveBeenCalled();
+ expect(clearCoreRpcTokenCache).not.toHaveBeenCalled();
+ expect(storeSession).toHaveBeenCalledWith('abc', {});
+ });
+
+ it('dispatches suppress-reauth before storeSession and clears it after in cloud mode', async () => {
+ vi.mocked(getStoredCoreMode).mockReturnValue('cloud');
+ vi.mocked(getCurrent).mockResolvedValue(['openhuman://auth?token=abc&key=auth']);
+
+ const suppressEvents: Array<{ until: number }> = [];
+ window.addEventListener('core-state:suppress-reauth', event => {
+ suppressEvents.push((event as CustomEvent<{ until: number }>).detail);
+ });
+
+ await setupDesktopDeepLinkListener();
+ await waitForAuthSettled();
+
+ // First event: non-zero until (suppress on)
+ expect(suppressEvents.length).toBeGreaterThanOrEqual(2);
+ expect(suppressEvents[0].until).toBeGreaterThan(0);
+ // Last event: until=0 (suppress cleared)
+ expect(suppressEvents[suppressEvents.length - 1].until).toBe(0);
+ });
});
diff --git a/app/src/utils/desktopDeepLinkListener.ts b/app/src/utils/desktopDeepLinkListener.ts
index 254b6f96d..b00221a4e 100644
--- a/app/src/utils/desktopDeepLinkListener.ts
+++ b/app/src/utils/desktopDeepLinkListener.ts
@@ -4,11 +4,13 @@ import { getCurrent, onOpenUrl } from '@tauri-apps/plugin-deep-link';
import { patchCoreStateSnapshot } from '../lib/coreState/store';
import { consumeLoginToken } from '../services/api/authApi';
+import { clearCoreRpcTokenCache, clearCoreRpcUrlCache } from '../services/coreRpcClient';
import {
beginDeepLinkAuthProcessing,
completeDeepLinkAuthProcessing,
failDeepLinkAuthProcessing,
} from '../store/deepLinkAuthState';
+import { getStoredCoreMode } from './configPersistence';
import { BILLING_DASHBOARD_URL } from './links';
import {
evaluateOAuthAppVersionGate,
@@ -76,7 +78,26 @@ const focusMainWindow = async () => {
};
const applySessionToken = async (sessionToken: string): Promise => {
- await storeSession(sessionToken, {});
+ // In cloud mode, bust any stale RPC URL/token caches so auth_store_session
+ // targets the user's configured remote core. See issue #2377.
+ const currentCoreMode = getStoredCoreMode();
+ if (currentCoreMode === 'cloud') {
+ console.debug('[DeepLink] cloud mode: busting RPC caches before session delivery');
+ clearCoreRpcUrlCache();
+ clearCoreRpcTokenCache();
+ }
+
+ // Signal CoreStateProvider to hold off clearing session during token delivery.
+ window.dispatchEvent(
+ new CustomEvent('core-state:suppress-reauth', { detail: { until: Date.now() + 15_000 } })
+ );
+ try {
+ await storeSession(sessionToken, {});
+ } finally {
+ window.dispatchEvent(
+ new CustomEvent('core-state:suppress-reauth', { detail: { until: 0 } })
+ );
+ }
patchCoreStateSnapshot({ snapshot: { sessionToken } });
window.dispatchEvent(new CustomEvent(SESSION_TOKEN_UPDATED_EVENT, { detail: { sessionToken } }));
};
From 265d0ac1b4c680f2bcdbebf3de830c525c1d405a Mon Sep 17 00:00:00 2001
From: M3gA-Mind
Date: Thu, 21 May 2026 22:27:26 +0530
Subject: [PATCH 3/7] chore: fix Prettier formatting on oauth readiness +
deep-link files
---
app/src/components/oauth/oauthAuthReadiness.ts | 6 +++++-
app/src/providers/CoreStateProvider.tsx | 6 +++++-
app/src/utils/desktopDeepLinkListener.ts | 4 +---
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/app/src/components/oauth/oauthAuthReadiness.ts b/app/src/components/oauth/oauthAuthReadiness.ts
index 63ba50372..154295fb0 100644
--- a/app/src/components/oauth/oauthAuthReadiness.ts
+++ b/app/src/components/oauth/oauthAuthReadiness.ts
@@ -30,7 +30,11 @@ async function pingCoreRpc(): Promise {
// In cloud mode, pass the stored cloud token explicitly to avoid
// getCoreRpcToken() resolving to a stale local-core token. See issue #2377.
const cloudToken = getStoredCoreMode() === 'cloud' ? getStoredCoreToken() : null;
- log(`${logPrefix} core.ping probe`, { rpcUrl, mode: getStoredCoreMode(), hasCloudToken: Boolean(cloudToken) });
+ log(`${logPrefix} core.ping probe`, {
+ rpcUrl,
+ mode: getStoredCoreMode(),
+ hasCloudToken: Boolean(cloudToken),
+ });
const response = cloudToken
? await testCoreRpcConnection(rpcUrl, cloudToken)
: await testCoreRpcConnection(rpcUrl);
diff --git a/app/src/providers/CoreStateProvider.tsx b/app/src/providers/CoreStateProvider.tsx
index e994909b2..cfffdcc1b 100644
--- a/app/src/providers/CoreStateProvider.tsx
+++ b/app/src/providers/CoreStateProvider.tsx
@@ -683,7 +683,11 @@ export default function CoreStateProvider({ children }: { children: ReactNode })
const runReauth = (method: string, source: string) => {
const now = Date.now();
if (Date.now() < suppressReauthUntilRef.current) {
- log('[CoreState] auth-expired suppressed during deep-link auth delivery (method=%s source=%s)', method, source);
+ log(
+ '[CoreState] auth-expired suppressed during deep-link auth delivery (method=%s source=%s)',
+ method,
+ source
+ );
return;
}
if (now - lastReauthAtRef.current < 10_000) {
diff --git a/app/src/utils/desktopDeepLinkListener.ts b/app/src/utils/desktopDeepLinkListener.ts
index b00221a4e..d346b99e9 100644
--- a/app/src/utils/desktopDeepLinkListener.ts
+++ b/app/src/utils/desktopDeepLinkListener.ts
@@ -94,9 +94,7 @@ const applySessionToken = async (sessionToken: string): Promise => {
try {
await storeSession(sessionToken, {});
} finally {
- window.dispatchEvent(
- new CustomEvent('core-state:suppress-reauth', { detail: { until: 0 } })
- );
+ window.dispatchEvent(new CustomEvent('core-state:suppress-reauth', { detail: { until: 0 } }));
}
patchCoreStateSnapshot({ snapshot: { sessionToken } });
window.dispatchEvent(new CustomEvent(SESSION_TOKEN_UPDATED_EVENT, { detail: { sessionToken } }));
From e7590148dea8c41b423f01b26465919eb9b6fcf4 Mon Sep 17 00:00:00 2001
From: M3gA-Mind
Date: Thu, 21 May 2026 22:55:20 +0530
Subject: [PATCH 4/7] test(core-state): cover suppress-reauth window from
deep-link auth delivery (#2377)
Add two targeted tests that exercise the `core-state:suppress-reauth` custom-event
handler introduced for issue #2377:
- verifies auth-expired clearSession is blocked while the suppress window is active
- verifies clearSession resumes after the window is explicitly cleared (until=0)
---
.../__tests__/CoreStateProvider.test.tsx | 73 +++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/app/src/providers/__tests__/CoreStateProvider.test.tsx b/app/src/providers/__tests__/CoreStateProvider.test.tsx
index 65b53218a..3f74572de 100644
--- a/app/src/providers/__tests__/CoreStateProvider.test.tsx
+++ b/app/src/providers/__tests__/CoreStateProvider.test.tsx
@@ -550,6 +550,79 @@ describe('CoreStateProvider — identity-change cache clearing', () => {
expect(vi.mocked(tauriCommands.logout)).toHaveBeenCalledTimes(1);
});
+ it('core-state:suppress-reauth suppresses auth-expired clearSession during deep-link delivery (#2377)', async () => {
+ fetchSnapshot.mockResolvedValue(makeSnapshot({ userId: 'u1', sessionToken: 'tok1' }));
+ listTeams.mockResolvedValue([]);
+ vi.mocked(tauriCommands.logout).mockReset();
+ vi.mocked(tauriCommands.logout).mockResolvedValue(undefined as never);
+
+ render(
+
+
+
+ );
+
+ await waitFor(() => expect(screen.getByTestId('ready').textContent).toBe('ready'));
+
+ // Arm the suppress window so core-rpc-auth-expired is silenced.
+ await act(async () => {
+ window.dispatchEvent(
+ new CustomEvent('core-state:suppress-reauth', {
+ detail: { until: Date.now() + 30_000 },
+ })
+ );
+ });
+
+ // auth-expired during the suppress window must not call logout.
+ await act(async () => {
+ window.dispatchEvent(
+ new CustomEvent('core-rpc-auth-expired', {
+ detail: { method: 'openhuman.auth_store_session', source: 'rpc' },
+ })
+ );
+ });
+
+ expect(vi.mocked(tauriCommands.logout)).not.toHaveBeenCalled();
+ });
+
+ it('core-state:suppress-reauth with until=0 re-enables auth-expired handling after deep-link delivery (#2377)', async () => {
+ fetchSnapshot.mockResolvedValue(makeSnapshot({ userId: 'u1', sessionToken: 'tok1' }));
+ listTeams.mockResolvedValue([]);
+ vi.mocked(tauriCommands.logout).mockReset();
+ vi.mocked(tauriCommands.logout).mockResolvedValue(undefined as never);
+
+ render(
+
+
+
+ );
+
+ await waitFor(() => expect(screen.getByTestId('ready').textContent).toBe('ready'));
+
+ // Arm then immediately disarm so clearSession is allowed again.
+ await act(async () => {
+ window.dispatchEvent(
+ new CustomEvent('core-state:suppress-reauth', { detail: { until: Date.now() + 30_000 } })
+ );
+ });
+ await act(async () => {
+ window.dispatchEvent(
+ new CustomEvent('core-state:suppress-reauth', { detail: { until: 0 } })
+ );
+ });
+
+ // auth-expired after suppress cleared must call logout.
+ await act(async () => {
+ window.dispatchEvent(
+ new CustomEvent('core-rpc-auth-expired', {
+ detail: { method: 'openhuman.team_get_usage', source: 'rpc' },
+ })
+ );
+ });
+
+ await waitFor(() => expect(vi.mocked(tauriCommands.logout)).toHaveBeenCalledTimes(1));
+ });
+
it('ignores forged session-token-updated events that do not match the core snapshot (#1937)', async () => {
fetchSnapshot.mockResolvedValue(makeSnapshot({ userId: 'u1', sessionToken: 'tok1' }));
listTeams.mockResolvedValue([]);
From f2a0a2f6ed35c8b7edb7acf8c5eba94a191bf028 Mon Sep 17 00:00:00 2001
From: M3gA-Mind
Date: Thu, 21 May 2026 22:57:06 +0530
Subject: [PATCH 5/7] chore(format): prettier fix for CoreStateProvider test
additions
---
app/src/providers/__tests__/CoreStateProvider.test.tsx | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/app/src/providers/__tests__/CoreStateProvider.test.tsx b/app/src/providers/__tests__/CoreStateProvider.test.tsx
index 3f74572de..ea4aae915 100644
--- a/app/src/providers/__tests__/CoreStateProvider.test.tsx
+++ b/app/src/providers/__tests__/CoreStateProvider.test.tsx
@@ -567,9 +567,7 @@ describe('CoreStateProvider — identity-change cache clearing', () => {
// Arm the suppress window so core-rpc-auth-expired is silenced.
await act(async () => {
window.dispatchEvent(
- new CustomEvent('core-state:suppress-reauth', {
- detail: { until: Date.now() + 30_000 },
- })
+ new CustomEvent('core-state:suppress-reauth', { detail: { until: Date.now() + 30_000 } })
);
});
@@ -606,9 +604,7 @@ describe('CoreStateProvider — identity-change cache clearing', () => {
);
});
await act(async () => {
- window.dispatchEvent(
- new CustomEvent('core-state:suppress-reauth', { detail: { until: 0 } })
- );
+ window.dispatchEvent(new CustomEvent('core-state:suppress-reauth', { detail: { until: 0 } }));
});
// auth-expired after suppress cleared must call logout.
From ea912f6e6e8bc1f8ee7238b6817dded7bc331571 Mon Sep 17 00:00:00 2001
From: Steven Enamakel
Date: Fri, 22 May 2026 17:53:54 -0700
Subject: [PATCH 6/7] refactor(core-state): reuse computed now in runReauth
suppression check
Trivial cleanup: the suppress-reauth check called Date.now() a second
time instead of reusing the 'now' value computed on the line above.
Functionally identical, but consistent with the debounce check below.
---
app/src/providers/CoreStateProvider.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/providers/CoreStateProvider.tsx b/app/src/providers/CoreStateProvider.tsx
index cfffdcc1b..45944dfe6 100644
--- a/app/src/providers/CoreStateProvider.tsx
+++ b/app/src/providers/CoreStateProvider.tsx
@@ -682,7 +682,7 @@ export default function CoreStateProvider({ children }: { children: ReactNode })
useEffect(() => {
const runReauth = (method: string, source: string) => {
const now = Date.now();
- if (Date.now() < suppressReauthUntilRef.current) {
+ if (now < suppressReauthUntilRef.current) {
log(
'[CoreState] auth-expired suppressed during deep-link auth delivery (method=%s source=%s)',
method,
From 868eb7bd8e9ae4a5a64417a4a3af701199840cd2 Mon Sep 17 00:00:00 2001
From: Steven Enamakel
Date: Fri, 22 May 2026 18:07:40 -0700
Subject: [PATCH 7/7] Merge upstream/main: drop duplicate de-5 mcpServer keys
---
app/src/lib/i18n/chunks/de-5.ts | 22 ----------------------
1 file changed, 22 deletions(-)
diff --git a/app/src/lib/i18n/chunks/de-5.ts b/app/src/lib/i18n/chunks/de-5.ts
index 79f041cc1..c8a26af5f 100644
--- a/app/src/lib/i18n/chunks/de-5.ts
+++ b/app/src/lib/i18n/chunks/de-5.ts
@@ -523,28 +523,6 @@ const de5: TranslationMap = {
'settings.mascot.colorYellow': 'Gelb',
'settings.mascot.libraryUnavailable': 'OpenHuman Bibliothek nicht verfügbar',
'settings.mascot.title': 'OpenHuman',
- 'settings.developerMenu.mcpServer.title': 'MCP-Server',
- 'settings.developerMenu.mcpServer.desc':
- 'Externe MCP-Clients zur Verbindung mit OpenHuman konfigurieren',
- 'settings.mcpServer.title': 'MCP-Server',
- 'settings.mcpServer.toolsSectionTitle': 'Verfügbare Tools',
- 'settings.mcpServer.toolsSectionDesc':
- 'Tools, die über den MCP-Stdio-Server bereitgestellt werden, wenn openhuman-core mcp ausgeführt wird',
- 'settings.mcpServer.configSectionTitle': 'Client-Konfiguration',
- 'settings.mcpServer.configSectionDesc':
- 'Wählen Sie Ihren MCP-Client aus, um den passenden Konfigurations-Schnipsel zu erzeugen',
- 'settings.mcpServer.copySnippet': 'In Zwischenablage kopieren',
- 'settings.mcpServer.copied': 'Kopiert!',
- 'settings.mcpServer.openConfigFile': 'Konfigurationsdatei öffnen',
- 'settings.mcpServer.binaryPathNotFound':
- 'OpenHuman-Binary nicht gefunden. Wenn Sie aus dem Quellcode arbeiten, bauen Sie mit: cargo build --bin openhuman-core',
- 'settings.mcpServer.openConfigError': 'Konfigurationsdatei konnte nicht geöffnet werden',
- 'settings.mcpServer.clientClaudeDesktop': 'Claude Desktop',
- 'settings.mcpServer.clientCursor': 'Cursor',
- 'settings.mcpServer.clientCodex': 'Codex',
- 'settings.mcpServer.clientZed': 'Zed',
- 'settings.mcpServer.configFilePath': 'Konfigurationsdatei',
- 'settings.mcpServer.clientSelectorAriaLabel': 'MCP-Client-Auswahl',
};
export default de5;