更新大量 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,40 +1,46 @@
import React from 'react';
import { stringWidth } from '../ink/stringWidth.js';
import { Box, Text } from '../ink.js';
import { truncateToWidth } from '../utils/format.js';
import React from 'react'
import { stringWidth } from '../ink/stringWidth.js'
import { Box, Text } from '../ink.js'
import { truncateToWidth } from '../utils/format.js'
// Constants for width calculations - derived from actual rendered strings
const ALL_TAB_LABEL = 'All';
const TAB_PADDING = 2; // Space before and after tab text: " {tab} "
const HASH_PREFIX_LENGTH = 1; // "#" prefix for non-All tabs
const LEFT_ARROW_PREFIX = '← ';
const RIGHT_HINT_WITH_COUNT_PREFIX = '→';
const RIGHT_HINT_SUFFIX = ' (tab to cycle)';
const RIGHT_HINT_NO_COUNT = '(tab to cycle)';
const MAX_OVERFLOW_DIGITS = 2; // Assume max 99 hidden tabs for width calculation
const ALL_TAB_LABEL = 'All'
const TAB_PADDING = 2 // Space before and after tab text: " {tab} "
const HASH_PREFIX_LENGTH = 1 // "#" prefix for non-All tabs
const LEFT_ARROW_PREFIX = '← '
const RIGHT_HINT_WITH_COUNT_PREFIX = '→'
const RIGHT_HINT_SUFFIX = ' (tab to cycle)'
const RIGHT_HINT_NO_COUNT = '(tab to cycle)'
const MAX_OVERFLOW_DIGITS = 2 // Assume max 99 hidden tabs for width calculation
// Computed widths
const LEFT_ARROW_WIDTH = LEFT_ARROW_PREFIX.length + MAX_OVERFLOW_DIGITS + 1; // "← NN " with gap
const RIGHT_HINT_WIDTH_WITH_COUNT = RIGHT_HINT_WITH_COUNT_PREFIX.length + MAX_OVERFLOW_DIGITS + RIGHT_HINT_SUFFIX.length; // "→NN (tab to cycle)"
const RIGHT_HINT_WIDTH_NO_COUNT = RIGHT_HINT_NO_COUNT.length;
const LEFT_ARROW_WIDTH = LEFT_ARROW_PREFIX.length + MAX_OVERFLOW_DIGITS + 1 // "← NN " with gap
const RIGHT_HINT_WIDTH_WITH_COUNT =
RIGHT_HINT_WITH_COUNT_PREFIX.length +
MAX_OVERFLOW_DIGITS +
RIGHT_HINT_SUFFIX.length // "→NN (tab to cycle)"
const RIGHT_HINT_WIDTH_NO_COUNT = RIGHT_HINT_NO_COUNT.length
type Props = {
tabs: string[];
selectedIndex: number;
availableWidth: number;
showAllProjects?: boolean;
};
tabs: string[]
selectedIndex: number
availableWidth: number
showAllProjects?: boolean
}
/**
* Calculate the display width of a tab
*/
function getTabWidth(tab: string, maxWidth?: number): number {
if (tab === ALL_TAB_LABEL) {
return ALL_TAB_LABEL.length + TAB_PADDING;
return ALL_TAB_LABEL.length + TAB_PADDING
}
// For non-All tabs: " #{tag} " but truncate tag if needed
const tagWidth = stringWidth(tab);
const effectiveTagWidth = maxWidth ? Math.min(tagWidth, maxWidth - TAB_PADDING - HASH_PREFIX_LENGTH) : tagWidth;
return Math.max(0, effectiveTagWidth) + TAB_PADDING + HASH_PREFIX_LENGTH;
const tagWidth = stringWidth(tab)
const effectiveTagWidth = maxWidth
? Math.min(tagWidth, maxWidth - TAB_PADDING - HASH_PREFIX_LENGTH)
: tagWidth
return Math.max(0, effectiveTagWidth) + TAB_PADDING + HASH_PREFIX_LENGTH
}
/**
@@ -42,97 +48,130 @@ function getTabWidth(tab: string, maxWidth?: number): number {
*/
function truncateTag(tag: string, maxWidth: number): string {
// Available space for the tag text itself: maxWidth - " #" - " "
const availableForTag = maxWidth - TAB_PADDING - HASH_PREFIX_LENGTH;
const availableForTag = maxWidth - TAB_PADDING - HASH_PREFIX_LENGTH
if (stringWidth(tag) <= availableForTag) {
return tag;
return tag
}
if (availableForTag <= 1) {
return tag.charAt(0);
return tag.charAt(0)
}
return truncateToWidth(tag, availableForTag);
return truncateToWidth(tag, availableForTag)
}
export function TagTabs({
tabs,
selectedIndex,
availableWidth,
showAllProjects = false
showAllProjects = false,
}: Props): React.ReactNode {
const resumeLabel = showAllProjects ? 'Resume (All Projects)' : 'Resume';
const resumeLabelWidth = resumeLabel.length + 1; // +1 for gap
const resumeLabel = showAllProjects ? 'Resume (All Projects)' : 'Resume'
const resumeLabelWidth = resumeLabel.length + 1 // +1 for gap
// Calculate how much space we have for tabs (use worst-case hint width)
const rightHintWidth = Math.max(RIGHT_HINT_WIDTH_WITH_COUNT, RIGHT_HINT_WIDTH_NO_COUNT);
const maxTabsWidth = availableWidth - resumeLabelWidth - rightHintWidth - 2; // 2 for gaps
const rightHintWidth = Math.max(
RIGHT_HINT_WIDTH_WITH_COUNT,
RIGHT_HINT_WIDTH_NO_COUNT,
)
const maxTabsWidth = availableWidth - resumeLabelWidth - rightHintWidth - 2 // 2 for gaps
// Clamp selectedIndex to valid range
const safeSelectedIndex = Math.max(0, Math.min(selectedIndex, tabs.length - 1));
const safeSelectedIndex = Math.max(
0,
Math.min(selectedIndex, tabs.length - 1),
)
// Calculate width of each tab, with truncation for very long tags
const maxSingleTabWidth = Math.max(20, Math.floor(maxTabsWidth / 2)); // At least show half the space for one tab
const tabWidths = tabs.map(tab => getTabWidth(tab, maxSingleTabWidth));
const maxSingleTabWidth = Math.max(20, Math.floor(maxTabsWidth / 2)) // At least show half the space for one tab
const tabWidths = tabs.map(tab => getTabWidth(tab, maxSingleTabWidth))
// Find a window of tabs that fits, centered around selectedIndex
let startIndex = 0;
let endIndex = tabs.length;
let startIndex = 0
let endIndex = tabs.length
// Calculate total width of all tabs
const totalTabsWidth = tabWidths.reduce((sum, w, i) => sum + w + (i < tabWidths.length - 1 ? 1 : 0), 0); // +1 for gaps between tabs
const totalTabsWidth = tabWidths.reduce(
(sum, w, i) => sum + w + (i < tabWidths.length - 1 ? 1 : 0),
0,
) // +1 for gaps between tabs
if (totalTabsWidth > maxTabsWidth) {
// Need to show a subset - account for left arrow when not at start
const effectiveMaxWidth = maxTabsWidth - LEFT_ARROW_WIDTH;
const effectiveMaxWidth = maxTabsWidth - LEFT_ARROW_WIDTH
// Start with the selected tab
let windowWidth = tabWidths[safeSelectedIndex] ?? 0;
startIndex = safeSelectedIndex;
endIndex = safeSelectedIndex + 1;
let windowWidth = tabWidths[safeSelectedIndex] ?? 0
startIndex = safeSelectedIndex
endIndex = safeSelectedIndex + 1
// Expand window to include more tabs
while (startIndex > 0 || endIndex < tabs.length) {
const canExpandLeft = startIndex > 0;
const canExpandRight = endIndex < tabs.length;
const canExpandLeft = startIndex > 0
const canExpandRight = endIndex < tabs.length
if (canExpandLeft) {
const leftWidth = (tabWidths[startIndex - 1] ?? 0) + 1; // +1 for gap
const leftWidth = (tabWidths[startIndex - 1] ?? 0) + 1 // +1 for gap
if (windowWidth + leftWidth <= effectiveMaxWidth) {
startIndex--;
windowWidth += leftWidth;
continue;
startIndex--
windowWidth += leftWidth
continue
}
}
if (canExpandRight) {
const rightWidth = (tabWidths[endIndex] ?? 0) + 1; // +1 for gap
const rightWidth = (tabWidths[endIndex] ?? 0) + 1 // +1 for gap
if (windowWidth + rightWidth <= effectiveMaxWidth) {
endIndex++;
windowWidth += rightWidth;
continue;
endIndex++
windowWidth += rightWidth
continue
}
}
break;
break
}
}
const hiddenLeft = startIndex;
const hiddenRight = tabs.length - endIndex;
const visibleTabs = tabs.slice(startIndex, endIndex);
const visibleIndices = visibleTabs.map((_, i_0) => startIndex + i_0);
return <Box flexDirection="row" gap={1}>
const hiddenLeft = startIndex
const hiddenRight = tabs.length - endIndex
const visibleTabs = tabs.slice(startIndex, endIndex)
const visibleIndices = visibleTabs.map((_, i) => startIndex + i)
return (
<Box flexDirection="row" gap={1}>
<Text color="suggestion">{resumeLabel}</Text>
{hiddenLeft > 0 && <Text dimColor>
{hiddenLeft > 0 && (
<Text dimColor>
{LEFT_ARROW_PREFIX}
{hiddenLeft}
</Text>}
{visibleTabs.map((tab_0, i_1) => {
const actualIndex = visibleIndices[i_1]!;
const isSelected = actualIndex === safeSelectedIndex;
const displayText = tab_0 === ALL_TAB_LABEL ? tab_0 : `#${truncateTag(tab_0, maxSingleTabWidth - TAB_PADDING)}`;
return <Text key={tab_0} backgroundColor={isSelected ? 'suggestion' : undefined} color={isSelected ? 'inverseText' : undefined} bold={isSelected}>
</Text>
)}
{visibleTabs.map((tab, i) => {
const actualIndex = visibleIndices[i]!
const isSelected = actualIndex === safeSelectedIndex
const displayText =
tab === ALL_TAB_LABEL
? tab
: `#${truncateTag(tab, maxSingleTabWidth - TAB_PADDING)}`
return (
<Text
key={tab}
backgroundColor={isSelected ? 'suggestion' : undefined}
color={isSelected ? 'inverseText' : undefined}
bold={isSelected}
>
{' '}
{displayText}{' '}
</Text>;
})}
{hiddenRight > 0 ? <Text dimColor>
</Text>
)
})}
{hiddenRight > 0 ? (
<Text dimColor>
{RIGHT_HINT_WITH_COUNT_PREFIX}
{hiddenRight}
{RIGHT_HINT_SUFFIX}
</Text> : <Text dimColor>{RIGHT_HINT_NO_COUNT}</Text>}
</Box>;
</Text>
) : (
<Text dimColor>{RIGHT_HINT_NO_COUNT}</Text>
)}
</Box>
)
}