更新大量 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:
claude-code-best
2026-04-04 23:24:27 +08:00
committed by GitHub
parent 02694918b5
commit 5b1a52b8e0
559 changed files with 103807 additions and 101817 deletions

View File

@@ -1,24 +1,29 @@
import figures from 'figures';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import type { CommandResultDisplay } from '../../commands.js';
import { Box, color, Link, Text, useTheme } from '../../ink.js';
import { useKeybinding } from '../../keybindings/useKeybinding.js';
import { AuthenticationCancelledError, performMCPOAuthFlow } from '../../services/mcp/auth.js';
import { capitalize } from '../../utils/stringUtils.js';
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js';
import { Select } from '../CustomSelect/index.js';
import { Byline } from '../design-system/Byline.js';
import { Dialog } from '../design-system/Dialog.js';
import { KeyboardShortcutHint } from '../design-system/KeyboardShortcutHint.js';
import { Spinner } from '../Spinner.js';
import type { AgentMcpServerInfo } from './types.js';
import figures from 'figures'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import type { CommandResultDisplay } from '../../commands.js'
import { Box, color, Link, Text, useTheme } from '../../ink.js'
import { useKeybinding } from '../../keybindings/useKeybinding.js'
import {
AuthenticationCancelledError,
performMCPOAuthFlow,
} from '../../services/mcp/auth.js'
import { capitalize } from '../../utils/stringUtils.js'
import { ConfigurableShortcutHint } from '../ConfigurableShortcutHint.js'
import { Select } from '../CustomSelect/index.js'
import { Byline } from '../design-system/Byline.js'
import { Dialog } from '../design-system/Dialog.js'
import { KeyboardShortcutHint } from '../design-system/KeyboardShortcutHint.js'
import { Spinner } from '../Spinner.js'
import type { AgentMcpServerInfo } from './types.js'
type Props = {
agentServer: AgentMcpServerInfo;
onCancel: () => void;
onComplete?: (result?: string, options?: {
display?: CommandResultDisplay;
}) => void;
};
agentServer: AgentMcpServerInfo
onCancel: () => void
onComplete?: (
result?: string,
options?: { display?: CommandResultDisplay },
) => void
}
/**
* Menu for agent-specific MCP servers.
@@ -28,113 +33,165 @@ type Props = {
export function MCPAgentServerMenu({
agentServer,
onCancel,
onComplete
onComplete,
}: Props): React.ReactNode {
const [theme] = useTheme();
const [isAuthenticating, setIsAuthenticating] = useState(false);
const [error, setError] = useState<string | null>(null);
const [authorizationUrl, setAuthorizationUrl] = useState<string | null>(null);
const authAbortControllerRef = useRef<AbortController | null>(null);
const [theme] = useTheme()
const [isAuthenticating, setIsAuthenticating] = useState(false)
const [error, setError] = useState<string | null>(null)
const [authorizationUrl, setAuthorizationUrl] = useState<string | null>(null)
const authAbortControllerRef = useRef<AbortController | null>(null)
// Abort OAuth flow on unmount so the callback server is closed even if a
// parent component's Esc handler navigates away before ours fires.
useEffect(() => () => authAbortControllerRef.current?.abort(), []);
useEffect(() => () => authAbortControllerRef.current?.abort(), [])
// Handle ESC to cancel authentication flow
const handleEscCancel = useCallback(() => {
if (isAuthenticating) {
authAbortControllerRef.current?.abort();
authAbortControllerRef.current = null;
setIsAuthenticating(false);
setAuthorizationUrl(null);
authAbortControllerRef.current?.abort()
authAbortControllerRef.current = null
setIsAuthenticating(false)
setAuthorizationUrl(null)
}
}, [isAuthenticating]);
}, [isAuthenticating])
useKeybinding('confirm:no', handleEscCancel, {
context: 'Confirmation',
isActive: isAuthenticating
});
isActive: isAuthenticating,
})
const handleAuthenticate = useCallback(async () => {
if (!agentServer.needsAuth || !agentServer.url) {
return;
return
}
setIsAuthenticating(true);
setError(null);
const controller = new AbortController();
authAbortControllerRef.current = controller;
setIsAuthenticating(true)
setError(null)
const controller = new AbortController()
authAbortControllerRef.current = controller
try {
// Create a temporary config for OAuth
const tempConfig = {
type: agentServer.transport as 'http' | 'sse',
url: agentServer.url
};
await performMCPOAuthFlow(agentServer.name, tempConfig, setAuthorizationUrl, controller.signal);
onComplete?.(`Authentication successful for ${agentServer.name}. The server will connect when the agent runs.`);
url: agentServer.url,
}
await performMCPOAuthFlow(
agentServer.name,
tempConfig,
setAuthorizationUrl,
controller.signal,
)
onComplete?.(
`Authentication successful for ${agentServer.name}. The server will connect when the agent runs.`,
)
} catch (err) {
// Don't show error if it was a cancellation
if (err instanceof Error && !(err instanceof AuthenticationCancelledError)) {
setError(err.message);
if (
err instanceof Error &&
!(err instanceof AuthenticationCancelledError)
) {
setError(err.message)
}
} finally {
setIsAuthenticating(false);
authAbortControllerRef.current = null;
setIsAuthenticating(false)
authAbortControllerRef.current = null
}
}, [agentServer, onComplete]);
const capitalizedServerName = capitalize(String(agentServer.name));
}, [agentServer, onComplete])
const capitalizedServerName = capitalize(String(agentServer.name))
if (isAuthenticating) {
return <Box flexDirection="column" gap={1} padding={1}>
return (
<Box flexDirection="column" gap={1} padding={1}>
<Text color="claude">Authenticating with {agentServer.name}</Text>
<Box>
<Spinner />
<Text> A browser window will open for authentication</Text>
</Box>
{authorizationUrl && <Box flexDirection="column">
{authorizationUrl && (
<Box flexDirection="column">
<Text dimColor>
If your browser doesn&apos;t open automatically, copy this URL
manually:
</Text>
<Link url={authorizationUrl} />
</Box>}
</Box>
)}
<Box marginLeft={3}>
<Text dimColor>
Return here after authenticating in your browser.{' '}
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="go back" />
<ConfigurableShortcutHint
action="confirm:no"
context="Confirmation"
fallback="Esc"
description="go back"
/>
</Text>
</Box>
</Box>;
</Box>
)
}
const menuOptions = [];
const menuOptions = []
// Only show authenticate option for HTTP/SSE servers
if (agentServer.needsAuth) {
menuOptions.push({
label: agentServer.isAuthenticated ? 'Re-authenticate' : 'Authenticate',
value: 'auth'
});
value: 'auth',
})
}
menuOptions.push({
label: 'Back',
value: 'back'
});
return <Dialog title={`${capitalizedServerName} MCP Server`} subtitle="agent-only" onCancel={onCancel} inputGuide={exitState => exitState.pending ? <Text>Press {exitState.keyName} again to exit</Text> : <Byline>
value: 'back',
})
return (
<Dialog
title={`${capitalizedServerName} MCP Server`}
subtitle="agent-only"
onCancel={onCancel}
inputGuide={exitState =>
exitState.pending ? (
<Text>Press {exitState.keyName} again to exit</Text>
) : (
<Byline>
<KeyboardShortcutHint shortcut="↑↓" action="navigate" />
<KeyboardShortcutHint shortcut="Enter" action="confirm" />
<ConfigurableShortcutHint action="confirm:no" context="Confirmation" fallback="Esc" description="go back" />
</Byline>}>
<ConfigurableShortcutHint
action="confirm:no"
context="Confirmation"
fallback="Esc"
description="go back"
/>
</Byline>
)
}
>
<Box flexDirection="column" gap={0}>
<Box>
<Text bold>Type: </Text>
<Text dimColor>{agentServer.transport}</Text>
</Box>
{agentServer.url && <Box>
{agentServer.url && (
<Box>
<Text bold>URL: </Text>
<Text dimColor>{agentServer.url}</Text>
</Box>}
</Box>
)}
{agentServer.command && <Box>
{agentServer.command && (
<Box>
<Text bold>Command: </Text>
<Text dimColor>{agentServer.command}</Text>
</Box>}
</Box>
)}
<Box>
<Text bold>Used by: </Text>
@@ -149,34 +206,47 @@ export function MCPAgentServerMenu({
</Text>
</Box>
{agentServer.needsAuth && <Box>
{agentServer.needsAuth && (
<Box>
<Text bold>Auth: </Text>
{agentServer.isAuthenticated ? <Text>{color('success', theme)(figures.tick)} authenticated</Text> : <Text>
{agentServer.isAuthenticated ? (
<Text>{color('success', theme)(figures.tick)} authenticated</Text>
) : (
<Text>
{color('warning', theme)(figures.triangleUpOutline)} may need
authentication
</Text>}
</Box>}
</Text>
)}
</Box>
)}
</Box>
<Box>
<Text dimColor>This server connects only when running the agent.</Text>
</Box>
{error && <Box>
{error && (
<Box>
<Text color="error">Error: {error}</Text>
</Box>}
</Box>
)}
<Box>
<Select options={menuOptions} onChange={async value => {
switch (value) {
case 'auth':
await handleAuthenticate();
break;
case 'back':
onCancel();
break;
}
}} onCancel={onCancel} />
<Select
options={menuOptions}
onChange={async value => {
switch (value) {
case 'auth':
await handleAuthenticate()
break
case 'back':
onCancel()
break
}
}}
onCancel={onCancel}
/>
</Box>
</Dialog>;
</Dialog>
)
}