mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-19 06:45:50 +00:00
更新大量 tsx 原始文件; 已经迁移 login panel; 部分 (#121)
* style(B1-1): 格式化 ink/buddy/cli/context/screens/tasks/services/keybindings/state (43 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 修复了 Box.tsx 和 ScrollBox.tsx 中无效的 global.d.ts import。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-2): 格式化 commands (79 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-3): 格式化 components/messages,permissions,mcp,sandbox,shell (104 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-4): 格式化 components/PromptInput,FeedbackSurvey,tasks,agents,skills,design-system,wizard (73 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-5): 格式化 components其余 + hooks + tools (232 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(B1-6): 格式化 main/entrypoints/utils/moreright (21 files) 纯格式化:移除分号、React Compiler import、import 多行展开。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: 更新 README,新增 Run.ps1/TODO.md,删除 V6.md - README.md: 大幅重写,更详细版本历史和配置示例 - Run.ps1: 新增 Windows 启动脚本 - TODO.md: 新增包完成清单 - V6.md: 删除(架构重构规划已不适用) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 修复以前的问题 * fix: 修复 login 面板的问题 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,134 +1,152 @@
|
||||
import axios from 'axios';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { logEvent } from 'src/services/analytics/index.js';
|
||||
import { Spinner } from '../components/Spinner.js';
|
||||
import { getOauthConfig } from '../constants/oauth.js';
|
||||
import { useTimeout } from '../hooks/useTimeout.js';
|
||||
import { Box, Text } from '../ink.js';
|
||||
import { getSSLErrorHint } from '../services/api/errorUtils.js';
|
||||
import { getUserAgent } from './http.js';
|
||||
import { logError } from './log.js';
|
||||
import axios from 'axios'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { logEvent } from 'src/services/analytics/index.js'
|
||||
import { Spinner } from '../components/Spinner.js'
|
||||
import { getOauthConfig } from '../constants/oauth.js'
|
||||
import { useTimeout } from '../hooks/useTimeout.js'
|
||||
import { Box, Text } from '../ink.js'
|
||||
import { getSSLErrorHint } from '../services/api/errorUtils.js'
|
||||
import { getUserAgent } from './http.js'
|
||||
import { logError } from './log.js'
|
||||
|
||||
export interface PreflightCheckResult {
|
||||
success: boolean;
|
||||
error?: string;
|
||||
sslHint?: string;
|
||||
success: boolean
|
||||
error?: string
|
||||
sslHint?: string
|
||||
}
|
||||
|
||||
async function checkEndpoints(): Promise<PreflightCheckResult> {
|
||||
try {
|
||||
const oauthConfig = getOauthConfig();
|
||||
const tokenUrl = new URL(oauthConfig.TOKEN_URL);
|
||||
const endpoints = [`${oauthConfig.BASE_API_URL}/api/hello`, `${tokenUrl.origin}/v1/oauth/hello`];
|
||||
const checkEndpoint = async (url: string): Promise<PreflightCheckResult> => {
|
||||
const oauthConfig = getOauthConfig()
|
||||
const tokenUrl = new URL(oauthConfig.TOKEN_URL)
|
||||
const endpoints = [
|
||||
`${oauthConfig.BASE_API_URL}/api/hello`,
|
||||
`${tokenUrl.origin}/v1/oauth/hello`,
|
||||
]
|
||||
|
||||
const checkEndpoint = async (
|
||||
url: string,
|
||||
): Promise<PreflightCheckResult> => {
|
||||
try {
|
||||
const response = await axios.get(url, {
|
||||
headers: {
|
||||
'User-Agent': getUserAgent()
|
||||
}
|
||||
});
|
||||
headers: { 'User-Agent': getUserAgent() },
|
||||
})
|
||||
if (response.status !== 200) {
|
||||
const hostname = new URL(url).hostname;
|
||||
const hostname = new URL(url).hostname
|
||||
return {
|
||||
success: false,
|
||||
error: `Failed to connect to ${hostname}: Status ${response.status}`
|
||||
};
|
||||
error: `Failed to connect to ${hostname}: Status ${response.status}`,
|
||||
}
|
||||
}
|
||||
return {
|
||||
success: true
|
||||
};
|
||||
return { success: true }
|
||||
} catch (error) {
|
||||
const hostname = new URL(url).hostname;
|
||||
const sslHint = getSSLErrorHint(error);
|
||||
const hostname = new URL(url).hostname
|
||||
const sslHint = getSSLErrorHint(error)
|
||||
return {
|
||||
success: false,
|
||||
error: `Failed to connect to ${hostname}: ${error instanceof Error ? (error as ErrnoException).code || error.message : String(error)}`,
|
||||
sslHint: sslHint ?? undefined
|
||||
};
|
||||
sslHint: sslHint ?? undefined,
|
||||
}
|
||||
}
|
||||
};
|
||||
const results = await Promise.all(endpoints.map(checkEndpoint));
|
||||
const failedResult = results.find(result => !result.success);
|
||||
}
|
||||
|
||||
const results = await Promise.all(endpoints.map(checkEndpoint))
|
||||
const failedResult = results.find(result => !result.success)
|
||||
|
||||
if (failedResult) {
|
||||
// Log failure to Statsig
|
||||
logEvent('tengu_preflight_check_failed', {
|
||||
isConnectivityError: false,
|
||||
hasErrorMessage: !!failedResult.error,
|
||||
isSSLError: !!failedResult.sslHint
|
||||
});
|
||||
isSSLError: !!failedResult.sslHint,
|
||||
})
|
||||
}
|
||||
return failedResult || {
|
||||
success: true
|
||||
};
|
||||
|
||||
return failedResult || { success: true }
|
||||
} catch (error) {
|
||||
logError(error as Error);
|
||||
logError(error as Error)
|
||||
|
||||
// Log to Statsig
|
||||
logEvent('tengu_preflight_check_failed', {
|
||||
isConnectivityError: true
|
||||
});
|
||||
isConnectivityError: true,
|
||||
})
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: `Connectivity check error: ${error instanceof Error ? (error as ErrnoException).code || error.message : String(error)}`
|
||||
};
|
||||
error: `Connectivity check error: ${error instanceof Error ? (error as ErrnoException).code || error.message : String(error)}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface PreflightStepProps {
|
||||
onSuccess: () => void;
|
||||
onSuccess: () => void
|
||||
}
|
||||
export function PreflightStep({ onSuccess }: PreflightStepProps) {
|
||||
const [result, setResult] = useState<PreflightCheckResult | null>(null);
|
||||
const [isChecking, setIsChecking] = useState(true);
|
||||
const showSpinner = useTimeout(1000) && isChecking;
|
||||
|
||||
export function PreflightStep({
|
||||
onSuccess,
|
||||
}: PreflightStepProps): React.ReactNode {
|
||||
const [result, setResult] = useState<PreflightCheckResult | null>(null)
|
||||
const [isChecking, setIsChecking] = useState(true)
|
||||
|
||||
// delay showing the check since it's so fast that we normally
|
||||
// want to just immediately show the next step without a flash
|
||||
const showSpinner = useTimeout(1000) && isChecking
|
||||
|
||||
useEffect(() => {
|
||||
checkEndpoints().then((checkResult) => {
|
||||
setResult(checkResult);
|
||||
setIsChecking(false);
|
||||
});
|
||||
}, []);
|
||||
async function run() {
|
||||
const checkResult = await checkEndpoints()
|
||||
setResult(checkResult)
|
||||
setIsChecking(false)
|
||||
}
|
||||
void run()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (result?.success) {
|
||||
onSuccess();
|
||||
onSuccess()
|
||||
} else if (result && !result.success) {
|
||||
logError(result.error ?? 'Preflight connectivity check failed');
|
||||
onSuccess();
|
||||
const timer = setTimeout(() => process.exit(1), 100)
|
||||
return () => clearTimeout(timer)
|
||||
}
|
||||
}, [result, onSuccess]);
|
||||
|
||||
let content = null;
|
||||
if (isChecking && showSpinner) {
|
||||
content = (
|
||||
<Box paddingLeft={1}>
|
||||
<Spinner />
|
||||
<Text>Checking connectivity...</Text>
|
||||
</Box>
|
||||
);
|
||||
} else if (!result?.success && !isChecking) {
|
||||
content = (
|
||||
<Box flexDirection="column" gap={1}>
|
||||
<Text color="error">Unable to connect to Anthropic services</Text>
|
||||
<Text color="error">{result?.error}</Text>
|
||||
{result?.sslHint ? (
|
||||
<Box flexDirection="column" gap={1}>
|
||||
<Text>{result.sslHint}</Text>
|
||||
<Text color="suggestion">See https://code.claude.com/docs/en/network-config</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<Box flexDirection="column" gap={1}>
|
||||
<Text>Please check your internet connection and network settings.</Text>
|
||||
<Text>
|
||||
Note: Claude Code might not be available in your country. Check supported countries at{" "}
|
||||
<Text color="suggestion">https://anthropic.com/supported-countries</Text>
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}, [result, onSuccess])
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" gap={1} paddingLeft={1}>
|
||||
{content}
|
||||
{isChecking && showSpinner ? (
|
||||
<Box paddingLeft={1}>
|
||||
<Spinner />
|
||||
<Text>Checking connectivity...</Text>
|
||||
</Box>
|
||||
) : (
|
||||
!result?.success &&
|
||||
!isChecking && (
|
||||
<Box flexDirection="column" gap={1}>
|
||||
<Text color="error">Unable to connect to Anthropic services</Text>
|
||||
<Text color="error">{result?.error}</Text>
|
||||
{result?.sslHint ? (
|
||||
<Box flexDirection="column" gap={1}>
|
||||
<Text>{result.sslHint}</Text>
|
||||
<Text color="suggestion">
|
||||
See https://code.claude.com/docs/en/network-config
|
||||
</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<Box flexDirection="column" gap={1}>
|
||||
<Text>
|
||||
Please check your internet connection and network settings.
|
||||
</Text>
|
||||
<Text>
|
||||
Note: Claude Code might not be available in your country.
|
||||
Check supported countries at{' '}
|
||||
<Text color="suggestion">
|
||||
https://anthropic.com/supported-countries
|
||||
</Text>
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user