更新大量 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,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
}