()
| 1425 | * Get OpenCode authentication status by checking auth file indicators |
| 1426 | */ |
| 1427 | export async function getOpenCodeAuthIndicators(): Promise<OpenCodeAuthIndicators> { |
| 1428 | const result: OpenCodeAuthIndicators = { |
| 1429 | hasAuthFile: false, |
| 1430 | hasOAuthToken: false, |
| 1431 | hasApiKey: false, |
| 1432 | }; |
| 1433 | |
| 1434 | try { |
| 1435 | const authContent = await systemPathReadFile(getOpenCodeAuthPath()); |
| 1436 | result.hasAuthFile = true; |
| 1437 | |
| 1438 | try { |
| 1439 | const authJson = JSON.parse(authContent) as Record<string, unknown>; |
| 1440 | |
| 1441 | // Check for legacy top-level keys |
| 1442 | result.hasOAuthToken = hasNonEmptyStringField(authJson, OPENCODE_OAUTH_KEYS); |
| 1443 | result.hasApiKey = hasNonEmptyStringField(authJson, OPENCODE_API_KEY_KEYS); |
| 1444 | |
| 1445 | // Check for nested tokens object (legacy format) |
| 1446 | const nestedTokens = getOpenCodeNestedTokens(authJson); |
| 1447 | if (nestedTokens) { |
| 1448 | result.hasOAuthToken = |
| 1449 | result.hasOAuthToken || hasNonEmptyStringField(nestedTokens, OPENCODE_OAUTH_KEYS); |
| 1450 | result.hasApiKey = |
| 1451 | result.hasApiKey || hasNonEmptyStringField(nestedTokens, OPENCODE_API_KEY_KEYS); |
| 1452 | } |
| 1453 | |
| 1454 | // Check for provider-specific auth entries (current OpenCode format) |
| 1455 | // Format: { "anthropic": { "type": "oauth", "access": "...", "refresh": "..." } } |
| 1456 | result.hasOAuthToken = result.hasOAuthToken || hasProviderOAuth(authJson); |
| 1457 | result.hasApiKey = result.hasApiKey || hasProviderApiKey(authJson); |
| 1458 | } catch { |
| 1459 | // Ignore parse errors; file exists but contents are unreadable |
| 1460 | } |
| 1461 | } catch { |
| 1462 | // Auth file not found or inaccessible |
| 1463 | } |
| 1464 | |
| 1465 | return result; |
| 1466 | } |
no test coverage detected