mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +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,31 +1,49 @@
|
||||
// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
|
||||
import { Box, Text } from '../ink.js';
|
||||
import * as React from 'react';
|
||||
import { getLargeMemoryFiles, MAX_MEMORY_CHARACTER_COUNT, type MemoryFileInfo } from './claudemd.js';
|
||||
import figures from 'figures';
|
||||
import { getCwd } from './cwd.js';
|
||||
import { relative } from 'path';
|
||||
import { formatNumber } from './format.js';
|
||||
import type { getGlobalConfig } from './config.js';
|
||||
import { getAnthropicApiKeyWithSource, getApiKeyFromConfigOrMacOSKeychain, getAuthTokenSource, isClaudeAISubscriber } from './auth.js';
|
||||
import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js';
|
||||
import { getAgentDescriptionsTotalTokens, AGENT_DESCRIPTIONS_THRESHOLD } from './statusNoticeHelpers.js';
|
||||
import { isSupportedJetBrainsTerminal, toIDEDisplayName, getTerminalIdeType } from './ide.js';
|
||||
import { isJetBrainsPluginInstalledCachedSync } from './jetbrains.js';
|
||||
import { Box, Text } from '../ink.js'
|
||||
import * as React from 'react'
|
||||
import {
|
||||
getLargeMemoryFiles,
|
||||
MAX_MEMORY_CHARACTER_COUNT,
|
||||
type MemoryFileInfo,
|
||||
} from './claudemd.js'
|
||||
import figures from 'figures'
|
||||
import { getCwd } from './cwd.js'
|
||||
import { relative } from 'path'
|
||||
import { formatNumber } from './format.js'
|
||||
import type { getGlobalConfig } from './config.js'
|
||||
import {
|
||||
getAnthropicApiKeyWithSource,
|
||||
getApiKeyFromConfigOrMacOSKeychain,
|
||||
getAuthTokenSource,
|
||||
isClaudeAISubscriber,
|
||||
} from './auth.js'
|
||||
import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js'
|
||||
import {
|
||||
getAgentDescriptionsTotalTokens,
|
||||
AGENT_DESCRIPTIONS_THRESHOLD,
|
||||
} from './statusNoticeHelpers.js'
|
||||
import {
|
||||
isSupportedJetBrainsTerminal,
|
||||
toIDEDisplayName,
|
||||
getTerminalIdeType,
|
||||
} from './ide.js'
|
||||
import { isJetBrainsPluginInstalledCachedSync } from './jetbrains.js'
|
||||
|
||||
// Types
|
||||
export type StatusNoticeType = 'warning' | 'info';
|
||||
export type StatusNoticeType = 'warning' | 'info'
|
||||
|
||||
export type StatusNoticeContext = {
|
||||
config: ReturnType<typeof getGlobalConfig>;
|
||||
agentDefinitions?: AgentDefinitionsResult;
|
||||
memoryFiles: MemoryFileInfo[];
|
||||
};
|
||||
config: ReturnType<typeof getGlobalConfig>
|
||||
agentDefinitions?: AgentDefinitionsResult
|
||||
memoryFiles: MemoryFileInfo[]
|
||||
}
|
||||
|
||||
export type StatusNoticeDefinition = {
|
||||
id: string;
|
||||
type: StatusNoticeType;
|
||||
isActive: (context: StatusNoticeContext) => boolean;
|
||||
render: (context: StatusNoticeContext) => React.ReactNode;
|
||||
};
|
||||
id: string
|
||||
type: StatusNoticeType
|
||||
isActive: (context: StatusNoticeContext) => boolean
|
||||
render: (context: StatusNoticeContext) => React.ReactNode
|
||||
}
|
||||
|
||||
// Individual notice definitions
|
||||
const largeMemoryFilesNotice: StatusNoticeDefinition = {
|
||||
@@ -33,11 +51,16 @@ const largeMemoryFilesNotice: StatusNoticeDefinition = {
|
||||
type: 'warning',
|
||||
isActive: ctx => getLargeMemoryFiles(ctx.memoryFiles).length > 0,
|
||||
render: ctx => {
|
||||
const largeMemoryFiles = getLargeMemoryFiles(ctx.memoryFiles);
|
||||
return <>
|
||||
const largeMemoryFiles = getLargeMemoryFiles(ctx.memoryFiles)
|
||||
return (
|
||||
<>
|
||||
{largeMemoryFiles.map(file => {
|
||||
const displayPath = file.path.startsWith(getCwd()) ? relative(getCwd(), file.path) : file.path;
|
||||
return <Box key={file.path} flexDirection="row">
|
||||
const displayPath = file.path.startsWith(getCwd())
|
||||
? relative(getCwd(), file.path)
|
||||
: file.path
|
||||
|
||||
return (
|
||||
<Box key={file.path} flexDirection="row">
|
||||
<Text color="warning">{figures.warning}</Text>
|
||||
<Text color="warning">
|
||||
Large <Text bold>{displayPath}</Text> will impact performance (
|
||||
@@ -45,76 +68,92 @@ const largeMemoryFilesNotice: StatusNoticeDefinition = {
|
||||
{formatNumber(MAX_MEMORY_CHARACTER_COUNT)})
|
||||
<Text dimColor> · /memory to edit</Text>
|
||||
</Text>
|
||||
</Box>;
|
||||
})}
|
||||
</>;
|
||||
}
|
||||
};
|
||||
</Box>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
const claudeAiSubscriberExternalTokenNotice: StatusNoticeDefinition = {
|
||||
id: 'claude-ai-external-token',
|
||||
type: 'warning',
|
||||
isActive: () => {
|
||||
const authTokenInfo = getAuthTokenSource();
|
||||
return isClaudeAISubscriber() && (authTokenInfo.source === 'ANTHROPIC_AUTH_TOKEN' || authTokenInfo.source === 'apiKeyHelper');
|
||||
const authTokenInfo = getAuthTokenSource()
|
||||
return (
|
||||
isClaudeAISubscriber() &&
|
||||
(authTokenInfo.source === 'ANTHROPIC_AUTH_TOKEN' ||
|
||||
authTokenInfo.source === 'apiKeyHelper')
|
||||
)
|
||||
},
|
||||
render: () => {
|
||||
const authTokenInfo = getAuthTokenSource();
|
||||
return <Box flexDirection="row" marginTop={1}>
|
||||
const authTokenInfo = getAuthTokenSource()
|
||||
return (
|
||||
<Box flexDirection="row" marginTop={1}>
|
||||
<Text color="warning">{figures.warning}</Text>
|
||||
<Text color="warning">
|
||||
Auth conflict: Using {authTokenInfo.source} instead of Claude account
|
||||
subscription token. Either unset {authTokenInfo.source}, or run
|
||||
`claude /logout`.
|
||||
</Text>
|
||||
</Box>;
|
||||
}
|
||||
};
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
const apiKeyConflictNotice: StatusNoticeDefinition = {
|
||||
id: 'api-key-conflict',
|
||||
type: 'warning',
|
||||
isActive: () => {
|
||||
const {
|
||||
source: apiKeySource
|
||||
} = getAnthropicApiKeyWithSource({
|
||||
skipRetrievingKeyFromApiKeyHelper: true
|
||||
});
|
||||
return !!getApiKeyFromConfigOrMacOSKeychain() && (apiKeySource === 'ANTHROPIC_API_KEY' || apiKeySource === 'apiKeyHelper');
|
||||
const { source: apiKeySource } = getAnthropicApiKeyWithSource({
|
||||
skipRetrievingKeyFromApiKeyHelper: true,
|
||||
})
|
||||
return (
|
||||
!!getApiKeyFromConfigOrMacOSKeychain() &&
|
||||
(apiKeySource === 'ANTHROPIC_API_KEY' || apiKeySource === 'apiKeyHelper')
|
||||
)
|
||||
},
|
||||
render: () => {
|
||||
const {
|
||||
source: apiKeySource
|
||||
} = getAnthropicApiKeyWithSource({
|
||||
skipRetrievingKeyFromApiKeyHelper: true
|
||||
});
|
||||
return <Box flexDirection="row" marginTop={1}>
|
||||
const { source: apiKeySource } = getAnthropicApiKeyWithSource({
|
||||
skipRetrievingKeyFromApiKeyHelper: true,
|
||||
})
|
||||
return (
|
||||
<Box flexDirection="row" marginTop={1}>
|
||||
<Text color="warning">{figures.warning}</Text>
|
||||
<Text color="warning">
|
||||
Auth conflict: Using {apiKeySource} instead of Anthropic Console key.
|
||||
Either unset {apiKeySource}, or run `claude /logout`.
|
||||
</Text>
|
||||
</Box>;
|
||||
}
|
||||
};
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
const bothAuthMethodsNotice: StatusNoticeDefinition = {
|
||||
id: 'both-auth-methods',
|
||||
type: 'warning',
|
||||
isActive: () => {
|
||||
const {
|
||||
source: apiKeySource
|
||||
} = getAnthropicApiKeyWithSource({
|
||||
skipRetrievingKeyFromApiKeyHelper: true
|
||||
});
|
||||
const authTokenInfo = getAuthTokenSource();
|
||||
return apiKeySource !== 'none' && authTokenInfo.source !== 'none' && !(apiKeySource === 'apiKeyHelper' && authTokenInfo.source === 'apiKeyHelper');
|
||||
const { source: apiKeySource } = getAnthropicApiKeyWithSource({
|
||||
skipRetrievingKeyFromApiKeyHelper: true,
|
||||
})
|
||||
const authTokenInfo = getAuthTokenSource()
|
||||
return (
|
||||
apiKeySource !== 'none' &&
|
||||
authTokenInfo.source !== 'none' &&
|
||||
!(
|
||||
apiKeySource === 'apiKeyHelper' &&
|
||||
authTokenInfo.source === 'apiKeyHelper'
|
||||
)
|
||||
)
|
||||
},
|
||||
render: () => {
|
||||
const {
|
||||
source: apiKeySource
|
||||
} = getAnthropicApiKeyWithSource({
|
||||
skipRetrievingKeyFromApiKeyHelper: true
|
||||
});
|
||||
const authTokenInfo = getAuthTokenSource();
|
||||
return <Box flexDirection="column" marginTop={1}>
|
||||
const { source: apiKeySource } = getAnthropicApiKeyWithSource({
|
||||
skipRetrievingKeyFromApiKeyHelper: true,
|
||||
})
|
||||
const authTokenInfo = getAuthTokenSource()
|
||||
return (
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
<Box flexDirection="row">
|
||||
<Text color="warning">{figures.warning}</Text>
|
||||
<Text color="warning">
|
||||
@@ -125,28 +164,43 @@ const bothAuthMethodsNotice: StatusNoticeDefinition = {
|
||||
<Box flexDirection="column" marginLeft={3}>
|
||||
<Text color="warning">
|
||||
· Trying to use{' '}
|
||||
{authTokenInfo.source === 'claude.ai' ? 'claude.ai' : authTokenInfo.source}
|
||||
{authTokenInfo.source === 'claude.ai'
|
||||
? 'claude.ai'
|
||||
: authTokenInfo.source}
|
||||
?{' '}
|
||||
{apiKeySource === 'ANTHROPIC_API_KEY' ? 'Unset the ANTHROPIC_API_KEY environment variable, or claude /logout then say "No" to the API key approval before login.' : apiKeySource === 'apiKeyHelper' ? 'Unset the apiKeyHelper setting.' : 'claude /logout'}
|
||||
{apiKeySource === 'ANTHROPIC_API_KEY'
|
||||
? 'Unset the ANTHROPIC_API_KEY environment variable, or claude /logout then say "No" to the API key approval before login.'
|
||||
: apiKeySource === 'apiKeyHelper'
|
||||
? 'Unset the apiKeyHelper setting.'
|
||||
: 'claude /logout'}
|
||||
</Text>
|
||||
<Text color="warning">
|
||||
· Trying to use {apiKeySource}?{' '}
|
||||
{authTokenInfo.source === 'claude.ai' ? 'claude /logout to sign out of claude.ai.' : `Unset the ${authTokenInfo.source} environment variable.`}
|
||||
{authTokenInfo.source === 'claude.ai'
|
||||
? 'claude /logout to sign out of claude.ai.'
|
||||
: `Unset the ${authTokenInfo.source} environment variable.`}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>;
|
||||
}
|
||||
};
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
const largeAgentDescriptionsNotice: StatusNoticeDefinition = {
|
||||
id: 'large-agent-descriptions',
|
||||
type: 'warning',
|
||||
isActive: context => {
|
||||
const totalTokens = getAgentDescriptionsTotalTokens(context.agentDefinitions);
|
||||
return totalTokens > AGENT_DESCRIPTIONS_THRESHOLD;
|
||||
const totalTokens = getAgentDescriptionsTotalTokens(
|
||||
context.agentDefinitions,
|
||||
)
|
||||
return totalTokens > AGENT_DESCRIPTIONS_THRESHOLD
|
||||
},
|
||||
render: context => {
|
||||
const totalTokens = getAgentDescriptionsTotalTokens(context.agentDefinitions);
|
||||
return <Box flexDirection="row">
|
||||
const totalTokens = getAgentDescriptionsTotalTokens(
|
||||
context.agentDefinitions,
|
||||
)
|
||||
return (
|
||||
<Box flexDirection="row">
|
||||
<Text color="warning">{figures.warning}</Text>
|
||||
<Text color="warning">
|
||||
Large cumulative agent descriptions will impact performance (~
|
||||
@@ -154,44 +208,58 @@ const largeAgentDescriptionsNotice: StatusNoticeDefinition = {
|
||||
{formatNumber(AGENT_DESCRIPTIONS_THRESHOLD)})
|
||||
<Text dimColor> · /agents to manage</Text>
|
||||
</Text>
|
||||
</Box>;
|
||||
}
|
||||
};
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
const jetbrainsPluginNotice: StatusNoticeDefinition = {
|
||||
id: 'jetbrains-plugin-install',
|
||||
type: 'info',
|
||||
isActive: context => {
|
||||
// Only show if running in JetBrains built-in terminal
|
||||
if (!isSupportedJetBrainsTerminal()) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
// Don't show if auto-install is disabled
|
||||
const shouldAutoInstall = context.config.autoInstallIdeExtension ?? true;
|
||||
const shouldAutoInstall = context.config.autoInstallIdeExtension ?? true
|
||||
if (!shouldAutoInstall) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
// Check if plugin is already installed (cached to avoid repeated filesystem checks)
|
||||
const ideType = getTerminalIdeType();
|
||||
return ideType !== null && !isJetBrainsPluginInstalledCachedSync(ideType);
|
||||
const ideType = getTerminalIdeType()
|
||||
return ideType !== null && !isJetBrainsPluginInstalledCachedSync(ideType)
|
||||
},
|
||||
render: () => {
|
||||
const ideType = getTerminalIdeType();
|
||||
const ideName = toIDEDisplayName(ideType);
|
||||
return <Box flexDirection="row" gap={1} marginLeft={1}>
|
||||
const ideType = getTerminalIdeType()
|
||||
const ideName = toIDEDisplayName(ideType)
|
||||
return (
|
||||
<Box flexDirection="row" gap={1} marginLeft={1}>
|
||||
<Text color="ide">{figures.arrowUp}</Text>
|
||||
<Text>
|
||||
Install the <Text color="ide">{ideName}</Text> plugin from the
|
||||
JetBrains Marketplace:{' '}
|
||||
<Text bold>https://docs.claude.com/s/claude-code-jetbrains</Text>
|
||||
</Text>
|
||||
</Box>;
|
||||
}
|
||||
};
|
||||
</Box>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
// All notice definitions
|
||||
export const statusNoticeDefinitions: StatusNoticeDefinition[] = [largeMemoryFilesNotice, largeAgentDescriptionsNotice, claudeAiSubscriberExternalTokenNotice, apiKeyConflictNotice, bothAuthMethodsNotice, jetbrainsPluginNotice];
|
||||
export const statusNoticeDefinitions: StatusNoticeDefinition[] = [
|
||||
largeMemoryFilesNotice,
|
||||
largeAgentDescriptionsNotice,
|
||||
claudeAiSubscriberExternalTokenNotice,
|
||||
apiKeyConflictNotice,
|
||||
bothAuthMethodsNotice,
|
||||
jetbrainsPluginNotice,
|
||||
]
|
||||
|
||||
// Helper functions for external use
|
||||
export function getActiveNotices(context: StatusNoticeContext): StatusNoticeDefinition[] {
|
||||
return statusNoticeDefinitions.filter(notice => notice.isActive(context));
|
||||
export function getActiveNotices(
|
||||
context: StatusNoticeContext,
|
||||
): StatusNoticeDefinition[] {
|
||||
return statusNoticeDefinitions.filter(notice => notice.isActive(context))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user