mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 20:17:45 +00:00
fix(websearch): detect Gemini CLI auth status before showing Ready
Previously, WebSearch status showed "Ready (Gemini)" when the CLI binary was installed, misleading users who hadn't authenticated yet. Changes: - Add isGeminiAuthenticated() to check ~/.gemini/oauth_creds.json - Add 'needs_auth' state to WebSearchReadiness type - Show warning "[!] Gemini: run 'gemini' to login" when not authenticated - Fix incorrect 'gemini auth login' references (no such command exists) - Update docs with correct npm install and authentication instructions
This commit is contained in:
+7
-9
@@ -57,21 +57,19 @@ The **ultimate solution** for third-party WebSearch. Uses `gemini` CLI with OAut
|
||||
|
||||
### Requirements
|
||||
|
||||
- `gemini` CLI installed and authenticated (`gemini auth login`)
|
||||
- `gemini` CLI installed and authenticated (run `gemini` to authenticate via browser)
|
||||
- OAuth authentication (no GEMINI_API_KEY needed)
|
||||
|
||||
### Installation
|
||||
|
||||
The Gemini CLI is typically installed via:
|
||||
The Gemini CLI is installed via npm:
|
||||
```bash
|
||||
pip install google-generativeai
|
||||
# or
|
||||
pipx install google-generativeai
|
||||
npm install -g @google/gemini-cli
|
||||
```
|
||||
|
||||
Then authenticate:
|
||||
Then authenticate by running gemini once (opens browser):
|
||||
```bash
|
||||
gemini auth login
|
||||
gemini
|
||||
```
|
||||
|
||||
## MCP Providers
|
||||
@@ -176,8 +174,8 @@ CCS writes MCP configuration to `~/.claude/.mcp.json`. Example:
|
||||
|
||||
### Gemini CLI Issues
|
||||
|
||||
1. **Not installed**: Install with `pip install google-generativeai`
|
||||
2. **Not authenticated**: Run `gemini auth login`
|
||||
1. **Not installed**: Install with `npm install -g @google/gemini-cli`
|
||||
2. **Not authenticated**: Run `gemini` to open browser for OAuth login
|
||||
3. **Timeout**: Increase timeout in config or via `CCS_GEMINI_TIMEOUT=90`
|
||||
4. **Skip Gemini**: Set `CCS_GEMINI_SKIP=1` to use MCP fallback only
|
||||
|
||||
|
||||
@@ -513,8 +513,8 @@ function outputError(query, error, providerName) {
|
||||
`Query: "${query}"`,
|
||||
'',
|
||||
'Troubleshooting:',
|
||||
' - Check if Gemini CLI is authenticated: gemini auth status',
|
||||
' - Re-authenticate if needed: gemini auth login',
|
||||
' - Check ~/.gemini/oauth_creds.json exists',
|
||||
' - Re-authenticate: run `gemini` (opens browser)',
|
||||
].join('\n');
|
||||
|
||||
const output = {
|
||||
@@ -546,7 +546,7 @@ function outputNoProvidersEnabled(query) {
|
||||
'',
|
||||
'1. Gemini CLI (FREE, 1000 req/day):',
|
||||
' npm install -g @google/gemini-cli',
|
||||
' gemini auth login',
|
||||
' gemini # opens browser to authenticate',
|
||||
'',
|
||||
'2. OpenCode (FREE via Zen):',
|
||||
' curl -fsSL https://opencode.ai/install | bash',
|
||||
@@ -595,7 +595,7 @@ function outputAllFailedMessage(query, errors) {
|
||||
`Query: "${query}"`,
|
||||
'',
|
||||
'Troubleshooting:',
|
||||
' - Gemini: gemini auth status / gemini auth login',
|
||||
' - Gemini: run `gemini` to authenticate (opens browser)',
|
||||
' - OpenCode: opencode --version',
|
||||
' - Grok: Check XAI_API_KEY environment variable',
|
||||
].join('\n');
|
||||
|
||||
@@ -114,6 +114,32 @@ export function hasGeminiCli(): boolean {
|
||||
return getGeminiCliStatus().installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Gemini CLI is authenticated
|
||||
*
|
||||
* Gemini CLI stores OAuth credentials in ~/.gemini/oauth_creds.json
|
||||
* Authentication is done by running `gemini` which opens browser for OAuth.
|
||||
* Note: There is NO `gemini auth login` command - just run `gemini` to authenticate.
|
||||
*
|
||||
* @returns true if oauth_creds.json exists with access_token
|
||||
*/
|
||||
export function isGeminiAuthenticated(): boolean {
|
||||
const oauthPath = path.join(os.homedir(), '.gemini', 'oauth_creds.json');
|
||||
|
||||
if (!fs.existsSync(oauthPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(oauthPath, 'utf8');
|
||||
const creds = JSON.parse(content);
|
||||
// Check if access_token exists (doesn't validate expiry - Gemini CLI handles refresh)
|
||||
return !!creds.access_token;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Gemini CLI cache (for testing or after installation)
|
||||
*/
|
||||
@@ -692,7 +718,7 @@ export function getWebSearchHookEnv(): Record<string, string> {
|
||||
/**
|
||||
* WebSearch availability status for third-party profiles
|
||||
*/
|
||||
export type WebSearchReadiness = 'ready' | 'unavailable';
|
||||
export type WebSearchReadiness = 'ready' | 'needs_auth' | 'unavailable';
|
||||
|
||||
/**
|
||||
* WebSearch status for display
|
||||
@@ -700,6 +726,7 @@ export type WebSearchReadiness = 'ready' | 'unavailable';
|
||||
export interface WebSearchStatus {
|
||||
readiness: WebSearchReadiness;
|
||||
geminiCli: boolean;
|
||||
geminiAuthenticated: boolean;
|
||||
grokCli: boolean;
|
||||
opencodeCli: boolean;
|
||||
message: string;
|
||||
@@ -709,6 +736,7 @@ export interface WebSearchStatus {
|
||||
* Get WebSearch readiness status for display
|
||||
*
|
||||
* Called on third-party profile startup to inform user.
|
||||
* Checks both installation AND authentication status for Gemini CLI.
|
||||
*/
|
||||
export function getWebSearchReadiness(): WebSearchStatus {
|
||||
const wsConfig = getWebSearchConfig();
|
||||
@@ -718,6 +746,7 @@ export function getWebSearchReadiness(): WebSearchStatus {
|
||||
return {
|
||||
readiness: 'unavailable',
|
||||
geminiCli: false,
|
||||
geminiAuthenticated: false,
|
||||
grokCli: false,
|
||||
opencodeCli: false,
|
||||
message: 'Disabled in config',
|
||||
@@ -726,28 +755,56 @@ export function getWebSearchReadiness(): WebSearchStatus {
|
||||
|
||||
// Check all CLIs
|
||||
const geminiInstalled = hasGeminiCli();
|
||||
const geminiAuthed = geminiInstalled && isGeminiAuthenticated();
|
||||
const grokInstalled = hasGrokCli();
|
||||
const opencodeInstalled = hasOpenCodeCli();
|
||||
|
||||
// Build message based on installed CLIs
|
||||
const installedClis: string[] = [];
|
||||
if (geminiInstalled) installedClis.push('Gemini');
|
||||
if (grokInstalled) installedClis.push('Grok');
|
||||
if (opencodeInstalled) installedClis.push('OpenCode');
|
||||
// Build message based on installed + authenticated CLIs
|
||||
const readyClis: string[] = [];
|
||||
const needsAuthClis: string[] = [];
|
||||
|
||||
if (installedClis.length > 0) {
|
||||
// Gemini requires auth check
|
||||
if (geminiInstalled) {
|
||||
if (geminiAuthed) {
|
||||
readyClis.push('Gemini');
|
||||
} else {
|
||||
needsAuthClis.push('Gemini');
|
||||
}
|
||||
}
|
||||
|
||||
// Other CLIs don't require auth check (for now)
|
||||
if (grokInstalled) readyClis.push('Grok');
|
||||
if (opencodeInstalled) readyClis.push('OpenCode');
|
||||
|
||||
// Determine overall status
|
||||
if (readyClis.length > 0) {
|
||||
// At least one CLI is ready
|
||||
return {
|
||||
readiness: 'ready',
|
||||
geminiCli: geminiInstalled,
|
||||
geminiAuthenticated: geminiAuthed,
|
||||
grokCli: grokInstalled,
|
||||
opencodeCli: opencodeInstalled,
|
||||
message: `Ready (${installedClis.join(' + ')})`,
|
||||
message: `Ready (${readyClis.join(' + ')})`,
|
||||
};
|
||||
}
|
||||
|
||||
if (needsAuthClis.length > 0) {
|
||||
// CLIs installed but need auth
|
||||
return {
|
||||
readiness: 'needs_auth',
|
||||
geminiCli: geminiInstalled,
|
||||
geminiAuthenticated: false,
|
||||
grokCli: grokInstalled,
|
||||
opencodeCli: opencodeInstalled,
|
||||
message: `Gemini: run 'gemini' to login`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
readiness: 'unavailable',
|
||||
geminiCli: false,
|
||||
geminiAuthenticated: false,
|
||||
grokCli: false,
|
||||
opencodeCli: false,
|
||||
message: 'Install: npm i -g @google/gemini-cli',
|
||||
@@ -767,6 +824,10 @@ export function displayWebSearchStatus(): void {
|
||||
case 'ready':
|
||||
console.error(ok(`WebSearch: ${status.message}`));
|
||||
break;
|
||||
case 'needs_auth':
|
||||
// CLI installed but not authenticated - show warning
|
||||
console.error(warn(`WebSearch: ${status.message}`));
|
||||
break;
|
||||
case 'unavailable':
|
||||
console.error(fail(`WebSearch: ${status.message}`));
|
||||
// Show install hints for CLI-only users
|
||||
|
||||
Reference in New Issue
Block a user