diff --git a/desktop/src/agents/local-agent-readiness.cjs b/desktop/src/agents/local-agent-readiness.cjs index a4f00d8..8322e57 100644 --- a/desktop/src/agents/local-agent-readiness.cjs +++ b/desktop/src/agents/local-agent-readiness.cjs @@ -115,8 +115,12 @@ function geminiOAuthCredentialsPresent(filename) { const contents = readCredentialFile(filename) if (!contents) return false const credentials = JSON.parse(contents) - return Boolean(credentials && typeof credentials === 'object' && !Array.isArray(credentials) - && (credentialLiteral(credentials.access_token) || credentialLiteral(credentials.refresh_token))) + if (!credentials || typeof credentials !== 'object' || Array.isArray(credentials)) return false + if (credentialLiteral(credentials.refresh_token)) return true + if (!credentialLiteral(credentials.access_token)) return false + if (credentials.expiry_date == null || credentials.expiry_date === 0) return true + return typeof credentials.expiry_date === 'number' && Number.isFinite(credentials.expiry_date) + && credentials.expiry_date > Date.now() + 5 * 60 * 1000 } catch { return false } } diff --git a/desktop/test/agents/cli/gemini-native-config.test.cjs b/desktop/test/agents/cli/gemini-native-config.test.cjs index 4f711df..3c9aed6 100644 --- a/desktop/test/agents/cli/gemini-native-config.test.cjs +++ b/desktop/test/agents/cli/gemini-native-config.test.cjs @@ -42,6 +42,12 @@ test('Gemini readiness checks credentials for its selected auth mode', t => { assert.deepEqual(nativeCredentialState('gemini', { home, env }), { state: 'unknown', source: 'unverified' }) fs.writeFileSync(path.join(root, 'oauth_creds.json'), JSON.stringify({ refresh_token: 'oauth-token' })) assert.deepEqual(nativeCredentialState('gemini', { home, env }), { state: 'ready', source: 'native-credential' }) + fs.writeFileSync(path.join(root, 'oauth_creds.json'), JSON.stringify({ access_token: 'expired', expiry_date: Date.now() - 1000 })) + assert.deepEqual(nativeCredentialState('gemini', { home, env }), { state: 'unknown', source: 'unverified' }) + fs.writeFileSync(path.join(root, 'oauth_creds.json'), JSON.stringify({ access_token: 'fresh', expiry_date: Date.now() + 10 * 60 * 1000 })) + assert.deepEqual(nativeCredentialState('gemini', { home, env }), { state: 'ready', source: 'native-credential' }) + fs.writeFileSync(path.join(root, 'oauth_creds.json'), JSON.stringify({ access_token: 'expired', refresh_token: 'refresh', expiry_date: Date.now() - 1000 })) + assert.deepEqual(nativeCredentialState('gemini', { home, env }), { state: 'ready', source: 'native-credential' }) env.GEMINI_CLI_AUTH_OVERRIDE = 'gemini-api-key' assert.deepEqual(nativeCredentialState('gemini', { home, env }), { state: 'ready', source: 'native-credential' }) env.GEMINI_CLI_AUTH_OVERRIDE = 'vertex-ai'