Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 60 additions & 3 deletions apps/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,57 @@ const BOX_CONTENT_WIDTH = 67;
// The Claude Agent SDK can use either ANTHROPIC_API_KEY or Claude Code CLI authentication
(async () => {
const hasAnthropicKey = !!process.env.ANTHROPIC_API_KEY;
const hasEnvOAuthToken = !!process.env.CLAUDE_CODE_OAUTH_TOKEN;

logger.debug('[CREDENTIAL_CHECK] Starting credential detection...');
logger.debug('[CREDENTIAL_CHECK] Environment variables:', {
hasAnthropicKey,
hasEnvOAuthToken,
});

if (hasAnthropicKey) {
logger.info('✓ ANTHROPIC_API_KEY detected');
return;
}

if (hasEnvOAuthToken) {
logger.info('✓ CLAUDE_CODE_OAUTH_TOKEN detected');
return;
}

// Check for Claude Code CLI authentication
// Store indicators outside the try block so we can use them in the warning message
let cliAuthIndicators: Awaited<ReturnType<typeof getClaudeAuthIndicators>> | null = null;

try {
const indicators = await getClaudeAuthIndicators();
cliAuthIndicators = await getClaudeAuthIndicators();
const indicators = cliAuthIndicators;

// Log detailed credential detection results
const { checks, ...indicatorSummary } = indicators;
logger.debug('[CREDENTIAL_CHECK] Claude CLI auth indicators:', indicatorSummary);

logger.debug('[CREDENTIAL_CHECK] File check details:', checks);

const hasCliAuth =
indicators.hasStatsCacheWithActivity ||
(indicators.hasSettingsFile && indicators.hasProjectsSessions) ||
(indicators.hasCredentialsFile &&
(indicators.credentials?.hasOAuthToken || indicators.credentials?.hasApiKey));

logger.debug('[CREDENTIAL_CHECK] Auth determination:', {
hasCliAuth,
reason: hasCliAuth
? indicators.hasStatsCacheWithActivity
? 'stats cache with activity'
: indicators.hasSettingsFile && indicators.hasProjectsSessions
? 'settings file + project sessions'
: indicators.credentials?.hasOAuthToken
? 'credentials file with OAuth token'
: 'credentials file with API key'
: 'no valid credentials found',
});

if (hasCliAuth) {
logger.info('✓ Claude Code CLI authentication detected');
return;
Expand All @@ -145,7 +181,7 @@ const BOX_CONTENT_WIDTH = 67;
logger.warn('Error checking for Claude Code CLI authentication:', error);
}

// No authentication found - show warning
// No authentication found - show warning with paths that were checked
const wHeader = '⚠️ WARNING: No Claude authentication configured'.padEnd(BOX_CONTENT_WIDTH);
const w1 = 'The Claude Agent SDK requires authentication to function.'.padEnd(BOX_CONTENT_WIDTH);
const w2 = 'Options:'.padEnd(BOX_CONTENT_WIDTH);
Expand All @@ -158,6 +194,27 @@ const BOX_CONTENT_WIDTH = 67;
BOX_CONTENT_WIDTH
);

// Build paths checked summary from the indicators (if available)
let pathsCheckedInfo = '';
if (cliAuthIndicators) {
const pathsChecked: string[] = [];

// Collect paths that were checked (paths are always populated strings)
pathsChecked.push(`Settings: ${cliAuthIndicators.checks.settingsFile.path}`);
pathsChecked.push(`Stats cache: ${cliAuthIndicators.checks.statsCache.path}`);
pathsChecked.push(`Projects dir: ${cliAuthIndicators.checks.projectsDir.path}`);
for (const credFile of cliAuthIndicators.checks.credentialFiles) {
pathsChecked.push(`Credentials: ${credFile.path}`);
}

if (pathsChecked.length > 0) {
pathsCheckedInfo = `
║ ║
║ ${'Paths checked:'.padEnd(BOX_CONTENT_WIDTH)}║
${pathsChecked.map((p) => `║ ${p.substring(0, BOX_CONTENT_WIDTH - 4).padEnd(BOX_CONTENT_WIDTH - 4)} ║`).join('\n')}`;
}
}

logger.warn(`
╔═════════════════════════════════════════════════════════════════════╗
║ ${wHeader}║
Expand All @@ -169,7 +226,7 @@ const BOX_CONTENT_WIDTH = 67;
║ ${w3}║
║ ${w4}║
║ ${w5}║
║ ${w6}║
║ ${w6}║${pathsCheckedInfo}
║ ║
╚═════════════════════════════════════════════════════════════════════╝
`);
Expand Down
19 changes: 19 additions & 0 deletions apps/server/src/routes/setup/routes/verify-claude-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import type { Request, Response } from 'express';
import { query } from '@anthropic-ai/claude-agent-sdk';
import { createLogger } from '@automaker/utils';
import { getClaudeAuthIndicators } from '@automaker/platform';
import { getApiKey } from '../common.js';
import {
createSecureAuthEnv,
Expand Down Expand Up @@ -320,9 +321,27 @@ export function createVerifyClaudeAuthHandler() {
authMethod,
});

// Determine specific auth type for success messages
let authType: 'oauth' | 'api_key' | 'cli' | undefined;
if (authenticated) {
if (authMethod === 'api_key') {
authType = 'api_key';
} else if (authMethod === 'cli') {
// Check if CLI auth is via OAuth (Claude Code subscription) or generic CLI
try {
const indicators = await getClaudeAuthIndicators();
authType = indicators.credentials?.hasOAuthToken ? 'oauth' : 'cli';
} catch {
// Fall back to generic CLI if credential check fails
authType = 'cli';
}
}
}
Comment on lines +324 to +339
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how the UI consumes authType from the verify-claude-auth response
rg -n -C5 'authType' --type=ts --type=tsx -g '!node_modules/**' -g '!dist/**'

Repository: AutoMaker-Org/automaker

Length of output: 94


🏁 Script executed:

#!/bin/bash
# Search for authType usage with correct rg syntax
rg -n -C5 'authType' --type=ts -g '!node_modules/**' -g '!dist/**'

Repository: AutoMaker-Org/automaker

Length of output: 13252


🏁 Script executed:

#!/bin/bash
# Get the full context of the verify-claude-auth route to understand authMethod handling
cat -n apps/server/src/routes/setup/routes/verify-claude-auth.ts | head -200

Repository: AutoMaker-Org/automaker

Length of output: 8378


🏁 Script executed:

#!/bin/bash
# Continue reading the verify-claude-auth.ts file to see the rest of the logic
cat -n apps/server/src/routes/setup/routes/verify-claude-auth.ts | tail -n +200

Repository: AutoMaker-Org/automaker

Length of output: 7518


When authMethod is omitted (auto-detect mode), authType remains undefined in the success response, causing the UI to incorrectly default to 'cli' and display the wrong success message.

In auto-detect mode (no authMethod provided), authentication can succeed with OAuth credentials (line 157), but the code on lines 327-338 only sets authType when authMethod === 'api_key' or authMethod === 'cli'. When authMethod is undefined, authType stays undefined and is returned to the UI.

The UI handler in claude-setup-step.tsx (line 144) treats undefined as 'cli': const authType = result.authType === 'oauth' ? 'oauth' : 'cli';. If a user authenticates via auto-detect using OAuth, they'll see "Claude CLI authentication verified!" instead of "Claude Code subscription detected and verified!"

Consider checking credentials in auto-detect mode similarly to how it's done for the 'cli' branch (lines 331-333), or returning a sensible default instead of undefined.

🤖 Prompt for AI Agents
In `@apps/server/src/routes/setup/routes/verify-claude-auth.ts` around lines 324 -
339, When computing authType after authentication, handle the auto-detect case
by invoking getClaudeAuthIndicators whenever authenticated is true and
authMethod is not 'api_key' (i.e., when authMethod is undefined/auto-detect) so
you can set authType to 'oauth' if indicators.credentials?.hasOAuthToken is
true, or to 'cli' if not (and fall back to 'cli' on errors); keep the existing
branch that sets authType = 'api_key' when authMethod === 'api_key' and
otherwise perform the credential check (using getClaudeAuthIndicators) to ensure
authType is never left undefined.


res.json({
success: true,
authenticated,
authType,
error: errorMessage || undefined,
});
} catch (error) {
Expand Down
23 changes: 23 additions & 0 deletions apps/ui/src/components/dialogs/sandbox-risk-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,29 @@ export function SandboxRiskDialog({ open, onConfirm, onDeny }: SandboxRiskDialog
For safer operation, consider running Automaker in Docker. See the README for
instructions.
</p>

<div className="bg-muted/50 border border-border rounded-lg p-4 space-y-2">
<p className="text-sm font-medium text-foreground">
Already running in Docker? Try these troubleshooting steps:
</p>
<ul className="text-sm text-muted-foreground list-disc list-inside space-y-1">
<li>
Ensure <code className="bg-muted px-1 rounded">IS_CONTAINERIZED=true</code> is
set in your docker-compose environment
</li>
<li>
Verify the server container has the environment variable:{' '}
<code className="bg-muted px-1 rounded">
docker exec automaker-server printenv IS_CONTAINERIZED
</code>
</li>
<li>Rebuild and restart containers if you recently changed the configuration</li>
<li>
Check the server logs for startup messages:{' '}
<code className="bg-muted px-1 rounded">docker-compose logs server</code>
</li>
</ul>
</div>
</div>
</DialogDescription>
</DialogHeader>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
// CLI Verification state
const [cliVerificationStatus, setCliVerificationStatus] = useState<VerificationStatus>('idle');
const [cliVerificationError, setCliVerificationError] = useState<string | null>(null);
const [cliAuthType, setCliAuthType] = useState<'oauth' | 'cli' | null>(null);

// API Key Verification state
const [apiKeyVerificationStatus, setApiKeyVerificationStatus] =
Expand Down Expand Up @@ -119,6 +120,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
const verifyCliAuth = useCallback(async () => {
setCliVerificationStatus('verifying');
setCliVerificationError(null);
setCliAuthType(null);

try {
const api = getElectronAPI();
Expand All @@ -138,12 +140,21 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps

if (result.authenticated && !hasLimitReachedError) {
setCliVerificationStatus('verified');
// Store the auth type for displaying specific success message
const authType = result.authType === 'oauth' ? 'oauth' : 'cli';
setCliAuthType(authType);
setClaudeAuthStatus({
authenticated: true,
method: 'cli_authenticated',
method: authType === 'oauth' ? 'oauth_token' : 'cli_authenticated',
hasCredentialsFile: claudeAuthStatus?.hasCredentialsFile || false,
oauthTokenValid: authType === 'oauth',
});
toast.success('Claude CLI authentication verified!');
// Show specific success message based on auth type
if (authType === 'oauth') {
toast.success('Claude Code subscription detected and verified!');
} else {
toast.success('Claude CLI authentication verified!');
}
} else {
setCliVerificationStatus('error');
setCliVerificationError(
Expand Down Expand Up @@ -436,9 +447,15 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps
<div className="flex items-center gap-3 p-4 rounded-lg bg-green-500/10 border border-green-500/20">
<CheckCircle2 className="w-5 h-5 text-green-500" />
<div>
<p className="font-medium text-foreground">CLI Authentication verified!</p>
<p className="font-medium text-foreground">
{cliAuthType === 'oauth'
? 'Claude Code subscription verified!'
: 'CLI Authentication verified!'}
</p>
<p className="text-sm text-muted-foreground">
Your Claude CLI is working correctly.
{cliAuthType === 'oauth'
? 'Your Claude Code subscription is active and ready to use.'
: 'Your Claude CLI is working correctly.'}
</p>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions apps/ui/src/lib/electron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1442,6 +1442,7 @@ interface SetupAPI {
verifyClaudeAuth: (authMethod?: 'cli' | 'api_key') => Promise<{
success: boolean;
authenticated: boolean;
authType?: 'oauth' | 'api_key' | 'cli';
error?: string;
}>;
getGhStatus?: () => Promise<{
Expand Down
1 change: 1 addition & 0 deletions apps/ui/src/lib/http-api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1350,6 +1350,7 @@ export class HttpApiClient implements ElectronAPI {
): Promise<{
success: boolean;
authenticated: boolean;
authType?: 'oauth' | 'api_key' | 'cli';
error?: string;
}> => this.post('/api/setup/verify-claude-auth', { authMethod, apiKey }),

Expand Down
2 changes: 2 additions & 0 deletions libs/platform/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ export {
findClaudeCliPath,
getClaudeAuthIndicators,
type ClaudeAuthIndicators,
type FileCheckResult,
type DirectoryCheckResult,
findCodexCliPath,
getCodexAuthIndicators,
type CodexAuthIndicators,
Expand Down
Loading