mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-17 13:55:50 +00:00
* feat: 第一版大重构 * fix: 修复类型问题 * chore: 更新版本到 1.3.2 * Add brave as alternative WebSearchTool * fix: 修正顺序 * fix: 修复对穷鬼模式的 auto dream 和 session memory 越过 * feat: 穷鬼模式去除 session-summary * feat: 创建 builtin-tools 包,搬运所有工具实现 将 src/tools/ 下的全部 60 个工具目录迁移至 packages/builtin-tools/src/tools/, 内部导入路径已更新为 src/ alias 模式。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: 更新 src/ 中所有工具引用至 builtin-tools 包,删除 src/tools/ - src/tools.ts 及 178 个 src/ 文件的 import 路径从 ./tools/ 改为 builtin-tools/tools/ - 删除 src/tools/ 整个目录(已迁移至 packages/builtin-tools/) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: 添加 builtin-tools 路径别名至 tsconfig,更新 bun.lock - tsconfig.json 新增 builtin-tools/* 和 builtin-tools 路径映射 - 新增 packages/builtin-tools/src 至 include Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: 为 builtin-tools、mcp-client、agent-tools 添加 @claude-code-best 作用域前缀 所有包名及 import 路径统一添加 @claude-code-best/ 前缀: - builtin-tools → @claude-code-best/builtin-tools - mcp-client → @claude-code-best/mcp-client - agent-tools → @claude-code-best/agent-tools Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 修复 node 环境没有 bun 的问题 --------- Co-authored-by: Eric-Guo <eric.guocz@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
266 lines
8.3 KiB
TypeScript
266 lines
8.3 KiB
TypeScript
// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
|
|
import { Box, Text } from '@anthropic/ink'
|
|
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 '@claude-code-best/builtin-tools/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 StatusNoticeContext = {
|
|
config: ReturnType<typeof getGlobalConfig>
|
|
agentDefinitions?: AgentDefinitionsResult
|
|
memoryFiles: MemoryFileInfo[]
|
|
}
|
|
|
|
export type StatusNoticeDefinition = {
|
|
id: string
|
|
type: StatusNoticeType
|
|
isActive: (context: StatusNoticeContext) => boolean
|
|
render: (context: StatusNoticeContext) => React.ReactNode
|
|
}
|
|
|
|
// Individual notice definitions
|
|
const largeMemoryFilesNotice: StatusNoticeDefinition = {
|
|
id: 'large-memory-files',
|
|
type: 'warning',
|
|
isActive: ctx => getLargeMemoryFiles(ctx.memoryFiles).length > 0,
|
|
render: ctx => {
|
|
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">
|
|
<Text color="warning">{figures.warning}</Text>
|
|
<Text color="warning">
|
|
Large <Text bold>{displayPath}</Text> will impact performance (
|
|
{formatNumber(file.content.length)} chars >{' '}
|
|
{formatNumber(MAX_MEMORY_CHARACTER_COUNT)})
|
|
<Text dimColor> · /memory to edit</Text>
|
|
</Text>
|
|
</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')
|
|
)
|
|
},
|
|
render: () => {
|
|
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>
|
|
)
|
|
},
|
|
}
|
|
|
|
const apiKeyConflictNotice: StatusNoticeDefinition = {
|
|
id: 'api-key-conflict',
|
|
type: 'warning',
|
|
isActive: () => {
|
|
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}>
|
|
<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>
|
|
)
|
|
},
|
|
}
|
|
|
|
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'
|
|
)
|
|
)
|
|
},
|
|
render: () => {
|
|
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">
|
|
Auth conflict: Both a token ({authTokenInfo.source}) and an API key
|
|
({apiKeySource}) are set. This may lead to unexpected behavior.
|
|
</Text>
|
|
</Box>
|
|
<Box flexDirection="column" marginLeft={3}>
|
|
<Text color="warning">
|
|
· Trying to use{' '}
|
|
{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'}
|
|
</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.`}
|
|
</Text>
|
|
</Box>
|
|
</Box>
|
|
)
|
|
},
|
|
}
|
|
|
|
const largeAgentDescriptionsNotice: StatusNoticeDefinition = {
|
|
id: 'large-agent-descriptions',
|
|
type: 'warning',
|
|
isActive: context => {
|
|
const totalTokens = getAgentDescriptionsTotalTokens(
|
|
context.agentDefinitions,
|
|
)
|
|
return totalTokens > AGENT_DESCRIPTIONS_THRESHOLD
|
|
},
|
|
render: context => {
|
|
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 (~
|
|
{formatNumber(totalTokens)} tokens >{' '}
|
|
{formatNumber(AGENT_DESCRIPTIONS_THRESHOLD)})
|
|
<Text dimColor> · /agents to manage</Text>
|
|
</Text>
|
|
</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
|
|
}
|
|
// Don't show if auto-install is disabled
|
|
const shouldAutoInstall = context.config.autoInstallIdeExtension ?? true
|
|
if (!shouldAutoInstall) {
|
|
return false
|
|
}
|
|
// Check if plugin is already installed (cached to avoid repeated filesystem checks)
|
|
const ideType = getTerminalIdeType()
|
|
return ideType !== null && !isJetBrainsPluginInstalledCachedSync(ideType)
|
|
},
|
|
render: () => {
|
|
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>
|
|
)
|
|
},
|
|
}
|
|
|
|
|
|
// All notice definitions
|
|
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))
|
|
}
|