mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 00:05: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,59 +1,73 @@
|
||||
import { basename, sep } from 'path';
|
||||
import React, { type ReactNode } from 'react';
|
||||
import { getOriginalCwd } from '../../bootstrap/state.js';
|
||||
import { Text } from '../../ink.js';
|
||||
import type { PermissionUpdate } from '../../utils/permissions/PermissionUpdateSchema.js';
|
||||
import { permissionRuleExtractPrefix } from '../../utils/permissions/shellRuleMatching.js';
|
||||
import { basename, sep } from 'path'
|
||||
import React, { type ReactNode } from 'react'
|
||||
import { getOriginalCwd } from '../../bootstrap/state.js'
|
||||
import { Text } from '../../ink.js'
|
||||
import type { PermissionUpdate } from '../../utils/permissions/PermissionUpdateSchema.js'
|
||||
import { permissionRuleExtractPrefix } from '../../utils/permissions/shellRuleMatching.js'
|
||||
|
||||
function commandListDisplay(commands: string[]): ReactNode {
|
||||
switch (commands.length) {
|
||||
case 0:
|
||||
return '';
|
||||
return ''
|
||||
case 1:
|
||||
return <Text bold>{commands[0]}</Text>;
|
||||
return <Text bold>{commands[0]}</Text>
|
||||
case 2:
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
<Text bold>{commands[0]}</Text> and <Text bold>{commands[1]}</Text>
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
default:
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
<Text bold>{commands.slice(0, -1).join(', ')}</Text>, and{' '}
|
||||
<Text bold>{commands.slice(-1)[0]}</Text>
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function commandListDisplayTruncated(commands: string[]): ReactNode {
|
||||
// Check if the plain text representation would be too long
|
||||
const plainText = commands.join(', ');
|
||||
const plainText = commands.join(', ')
|
||||
if (plainText.length > 50) {
|
||||
return 'similar';
|
||||
return 'similar'
|
||||
}
|
||||
return commandListDisplay(commands);
|
||||
return commandListDisplay(commands)
|
||||
}
|
||||
|
||||
function formatPathList(paths: string[]): ReactNode {
|
||||
if (paths.length === 0) return '';
|
||||
if (paths.length === 0) return ''
|
||||
|
||||
// Extract directory names from paths
|
||||
const names = paths.map(p => basename(p) || p);
|
||||
const names = paths.map(p => basename(p) || p)
|
||||
|
||||
if (names.length === 1) {
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
<Text bold>{names[0]}</Text>
|
||||
{sep}
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
if (names.length === 2) {
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
<Text bold>{names[0]}</Text>
|
||||
{sep} and <Text bold>{names[1]}</Text>
|
||||
{sep}
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
// For 3+, show first two with "and N more"
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
<Text bold>{names[0]}</Text>
|
||||
{sep}, <Text bold>{names[1]}</Text>
|
||||
{sep} and {paths.length - 2} more
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,102 +76,138 @@ function formatPathList(paths: string[]): ReactNode {
|
||||
* and an optional command transform (e.g., Bash strips output redirections so
|
||||
* filenames don't show as commands).
|
||||
*/
|
||||
export function generateShellSuggestionsLabel(suggestions: PermissionUpdate[], shellToolName: string, commandTransform?: (command: string) => string): ReactNode | null {
|
||||
export function generateShellSuggestionsLabel(
|
||||
suggestions: PermissionUpdate[],
|
||||
shellToolName: string,
|
||||
commandTransform?: (command: string) => string,
|
||||
): ReactNode | null {
|
||||
// Collect all rules for display
|
||||
const allRules = suggestions.filter(s => s.type === 'addRules').flatMap(s => s.rules || []);
|
||||
const allRules = suggestions
|
||||
.filter(s => s.type === 'addRules')
|
||||
.flatMap(s => s.rules || [])
|
||||
|
||||
// Separate Read rules from shell rules
|
||||
const readRules = allRules.filter(r => r.toolName === 'Read');
|
||||
const shellRules = allRules.filter(r => r.toolName === shellToolName);
|
||||
const readRules = allRules.filter(r => r.toolName === 'Read')
|
||||
const shellRules = allRules.filter(r => r.toolName === shellToolName)
|
||||
|
||||
// Get directory info
|
||||
const directories = suggestions.filter(s => s.type === 'addDirectories').flatMap(s => s.directories || []);
|
||||
const directories = suggestions
|
||||
.filter(s => s.type === 'addDirectories')
|
||||
.flatMap(s => s.directories || [])
|
||||
|
||||
// Extract paths from Read rules (keep separate from directories)
|
||||
const readPaths = readRules.map(r => r.ruleContent?.replace('/**', '') || '').filter(p => p);
|
||||
const readPaths = readRules
|
||||
.map(r => r.ruleContent?.replace('/**', '') || '')
|
||||
.filter(p => p)
|
||||
|
||||
// Extract shell command prefixes, optionally transforming for display
|
||||
const shellCommands = [...new Set(shellRules.flatMap(rule => {
|
||||
if (!rule.ruleContent) return [];
|
||||
const command = permissionRuleExtractPrefix(rule.ruleContent) ?? rule.ruleContent;
|
||||
return commandTransform ? commandTransform(command) : command;
|
||||
}))];
|
||||
const shellCommands = [
|
||||
...new Set(
|
||||
shellRules.flatMap(rule => {
|
||||
if (!rule.ruleContent) return []
|
||||
const command =
|
||||
permissionRuleExtractPrefix(rule.ruleContent) ?? rule.ruleContent
|
||||
return commandTransform ? commandTransform(command) : command
|
||||
}),
|
||||
),
|
||||
]
|
||||
|
||||
// Check what we have
|
||||
const hasDirectories = directories.length > 0;
|
||||
const hasReadPaths = readPaths.length > 0;
|
||||
const hasCommands = shellCommands.length > 0;
|
||||
const hasDirectories = directories.length > 0
|
||||
const hasReadPaths = readPaths.length > 0
|
||||
const hasCommands = shellCommands.length > 0
|
||||
|
||||
// Handle single type cases
|
||||
if (hasReadPaths && !hasDirectories && !hasCommands) {
|
||||
// Only Read rules - use "reading from" language
|
||||
if (readPaths.length === 1) {
|
||||
const firstPath = readPaths[0]!;
|
||||
const dirName = basename(firstPath) || firstPath;
|
||||
return <Text>
|
||||
const firstPath = readPaths[0]!
|
||||
const dirName = basename(firstPath) || firstPath
|
||||
return (
|
||||
<Text>
|
||||
Yes, allow reading from <Text bold>{dirName}</Text>
|
||||
{sep} from this project
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
// Multiple read paths
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
Yes, allow reading from {formatPathList(readPaths)} from this project
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
if (hasDirectories && !hasReadPaths && !hasCommands) {
|
||||
// Only directory permissions - use "access to" language
|
||||
if (directories.length === 1) {
|
||||
const firstDir = directories[0]!;
|
||||
const dirName = basename(firstDir) || firstDir;
|
||||
return <Text>
|
||||
const firstDir = directories[0]!
|
||||
const dirName = basename(firstDir) || firstDir
|
||||
return (
|
||||
<Text>
|
||||
Yes, and always allow access to <Text bold>{dirName}</Text>
|
||||
{sep} from this project
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
// Multiple directories
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
Yes, and always allow access to {formatPathList(directories)} from this
|
||||
project
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
if (hasCommands && !hasDirectories && !hasReadPaths) {
|
||||
// Only shell command permissions
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
{"Yes, and don't ask again for "}
|
||||
{commandListDisplayTruncated(shellCommands)} commands in{' '}
|
||||
<Text bold>{getOriginalCwd()}</Text>
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
// Handle mixed cases
|
||||
if ((hasDirectories || hasReadPaths) && !hasCommands) {
|
||||
// Combine directories and read paths since they're both path access
|
||||
const allPaths = [...directories, ...readPaths];
|
||||
const allPaths = [...directories, ...readPaths]
|
||||
if (hasDirectories && hasReadPaths) {
|
||||
// Mixed - use generic "access to"
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
Yes, and always allow access to {formatPathList(allPaths)} from this
|
||||
project
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if ((hasDirectories || hasReadPaths) && hasCommands) {
|
||||
// Build descriptive message for both types
|
||||
const allPaths = [...directories, ...readPaths];
|
||||
const allPaths = [...directories, ...readPaths]
|
||||
|
||||
// Keep it concise but informative
|
||||
if (allPaths.length === 1 && shellCommands.length === 1) {
|
||||
return <Text>
|
||||
return (
|
||||
<Text>
|
||||
Yes, and allow access to {formatPathList(allPaths)} and{' '}
|
||||
{commandListDisplayTruncated(shellCommands)} commands
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
return <Text>
|
||||
|
||||
return (
|
||||
<Text>
|
||||
Yes, and allow {formatPathList(allPaths)} access and{' '}
|
||||
{commandListDisplayTruncated(shellCommands)} commands
|
||||
</Text>;
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
return null;
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user