feat: 完成大部分操作

This commit is contained in:
claude-code-best
2026-03-31 21:40:37 +08:00
parent 3d4cb096d1
commit c4d92178b7
22 changed files with 561 additions and 98 deletions

View File

@@ -294,8 +294,8 @@ function PromptInput({
// otherwise bridge becomes an invisible selection stop.
const bridgeFooterVisible = replBridgeConnected && (replBridgeExplicit || replBridgeReconnecting);
// Tmux pill (ant-only) — visible when there's an active tungsten session
const hasTungstenSession = useAppState(s => "external" === 'ant' && s.tungstenActiveSession !== undefined);
const tmuxFooterVisible = "external" === 'ant' && hasTungstenSession;
const hasTungstenSession = useAppState(s => ("external" as string) === 'ant' && s.tungstenActiveSession !== undefined);
const tmuxFooterVisible = ("external" as string) === 'ant' && hasTungstenSession;
// WebBrowser pill — visible when a browser is open
const bagelFooterVisible = useAppState(s => false);
const teamContext = useAppState(s => s.teamContext);
@@ -391,7 +391,7 @@ function PromptInput({
// exist. When only local_agent tasks are running (coordinator/fork mode), the
// pill is absent, so the -1 sentinel would leave nothing visually selected.
// In that case, skip -1 and treat 0 as the minimum selectable index.
const hasBgTaskPill = useMemo(() => Object.values(tasks).some(t => isBackgroundTask(t) && !("external" === 'ant' && isPanelAgentTask(t))), [tasks]);
const hasBgTaskPill = useMemo(() => Object.values(tasks).some(t => isBackgroundTask(t) && !(("external" as string) === 'ant' && isPanelAgentTask(t))), [tasks]);
const minCoordinatorIndex = hasBgTaskPill ? -1 : 0;
// Clamp index when tasks complete and the list shrinks beneath the cursor
useEffect(() => {
@@ -455,7 +455,7 @@ function PromptInput({
// Panel shows retained-completed agents too (getVisibleAgentTasks), so the
// pill must stay navigable whenever the panel has rows — not just when
// something is running.
const tasksFooterVisible = (runningTaskCount > 0 || "external" === 'ant' && coordinatorTaskCount > 0) && !shouldHideTasksFooter(tasks, showSpinnerTree);
const tasksFooterVisible = (runningTaskCount > 0 || ("external" as string) === 'ant' && coordinatorTaskCount > 0) && !shouldHideTasksFooter(tasks, showSpinnerTree);
const teamsFooterVisible = cachedTeams.length > 0;
const footerItems = useMemo(() => [tasksFooterVisible && 'tasks', tmuxFooterVisible && 'tmux', bagelFooterVisible && 'bagel', teamsFooterVisible && 'teams', bridgeFooterVisible && 'bridge', companionFooterVisible && 'companion'].filter(Boolean) as FooterItem[], [tasksFooterVisible, tmuxFooterVisible, bagelFooterVisible, teamsFooterVisible, bridgeFooterVisible, companionFooterVisible]);
@@ -1054,7 +1054,7 @@ function PromptInput({
clearBuffer();
resetHistory();
return;
} else if (result.error === 'no_team_context') {
} else if ('error' in result && result.error === 'no_team_context') {
// No team context - fall through to normal prompt submission
} else {
// Unknown recipient - fall through to normal prompt submission
@@ -1742,7 +1742,7 @@ function PromptInput({
useKeybindings({
'footer:up': () => {
// ↑ scrolls within the coordinator task list before leaving the pill
if (tasksSelected && "external" === 'ant' && coordinatorTaskCount > 0 && coordinatorTaskIndex > minCoordinatorIndex) {
if (tasksSelected && ("external" as string) === 'ant' && coordinatorTaskCount > 0 && coordinatorTaskIndex > minCoordinatorIndex) {
setCoordinatorTaskIndex(prev => prev - 1);
return;
}
@@ -1750,7 +1750,7 @@ function PromptInput({
},
'footer:down': () => {
// ↓ scrolls within the coordinator task list, never leaves the pill
if (tasksSelected && "external" === 'ant' && coordinatorTaskCount > 0) {
if (tasksSelected && ("external" as string) === 'ant' && coordinatorTaskCount > 0) {
if (coordinatorTaskIndex < coordinatorTaskCount - 1) {
setCoordinatorTaskIndex(prev => prev + 1);
}
@@ -1813,7 +1813,7 @@ function PromptInput({
}
break;
case 'tmux':
if ("external" === 'ant') {
if (("external" as string) === 'ant') {
setAppState(prev => prev.tungstenPanelAutoHidden ? {
...prev,
tungstenPanelAutoHidden: false
@@ -2306,7 +2306,7 @@ function getInitialPasteId(messages: Message[]): number {
if (message.type === 'user') {
// Check image paste IDs
if (message.imagePasteIds) {
for (const id of message.imagePasteIds) {
for (const id of message.imagePasteIds as number[]) {
if (id > maxId) maxId = id;
}
}

View File

@@ -143,11 +143,11 @@ function PromptInputFooter({
</Box>
<Box flexShrink={1} gap={1}>
{isFullscreen ? null : <Notifications apiKeyStatus={apiKeyStatus} autoUpdaterResult={autoUpdaterResult} debug={debug} isAutoUpdating={isAutoUpdating} verbose={verbose} messages={messages} onAutoUpdaterResult={onAutoUpdaterResult} onChangeIsUpdating={onChangeIsUpdating} ideSelection={ideSelection} mcpClients={mcpClients} isInputWrapped={isInputWrapped} isNarrow={isNarrow} />}
{"external" === 'ant' && isUndercover() && <Text dimColor>undercover</Text>}
{("external" as string) === 'ant' && isUndercover() && <Text dimColor>undercover</Text>}
<BridgeStatusIndicator bridgeSelected={bridgeSelected} />
</Box>
</Box>
{"external" === 'ant' && <CoordinatorTaskPanel />}
{("external" as string) === 'ant' && <CoordinatorTaskPanel />}
</>;
}
export default memo(PromptInputFooter);

View File

@@ -260,7 +260,7 @@ function ModeIndicator({
const expandedView = useAppState(s_3 => s_3.expandedView);
const showSpinnerTree = expandedView === 'teammates';
const prStatus = usePrStatus(isLoading, isPrStatusEnabled());
const hasTmuxSession = useAppState(s_4 => "external" === 'ant' && s_4.tungstenActiveSession !== undefined);
const hasTmuxSession = useAppState(s_4 => ("external" as string) === 'ant' && s_4.tungstenActiveSession !== undefined);
const nextTickAt = useSyncExternalStore(proactiveModule?.subscribeToProactiveChanges ?? NO_OP_SUBSCRIBE, proactiveModule?.getNextTickAt ?? NULL, NULL);
// biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
const voiceEnabled = feature('VOICE_MODE') ? useVoiceEnabled() : false;
@@ -274,7 +274,7 @@ function ModeIndicator({
const selGetState = useSelection().getState;
const hasNextTick = nextTickAt !== null;
const isCoordinator = feature('COORDINATOR_MODE') ? coordinatorModule?.isCoordinatorMode() === true : false;
const runningTaskCount = useMemo(() => count(Object.values(tasks), t => isBackgroundTask(t) && !("external" === 'ant' && isPanelAgentTask(t))), [tasks]);
const runningTaskCount = useMemo(() => count(Object.values(tasks), t => isBackgroundTask(t) && !(("external" as string) === 'ant' && isPanelAgentTask(t))), [tasks]);
const tasksV2 = useTasksV2();
const hasTaskItems = tasksV2 !== undefined && tasksV2.length > 0;
const escShortcut = useShortcutDisplay('chat:cancel', 'Chat', 'esc').toLowerCase();
@@ -365,7 +365,7 @@ function ModeIndicator({
// its click-target Box isn't nested inside the <Text wrap="truncate">
// wrapper (reconciler throws on Box-in-Text).
// Tmux pill (ant-only) — appears right after tasks in nav order
...("external" === 'ant' && hasTmuxSession ? [<TungstenPill key="tmux" selected={tmuxSelected} />] : []), ...(isAgentSwarmsEnabled() && hasTeams ? [<TeamStatus key="teams" teamsSelected={teamsSelected} showHint={showHint && !hasBackgroundTasks} />] : []), ...(shouldShowPrStatus ? [<PrBadge key="pr-status" number={prStatus.number!} url={prStatus.url!} reviewState={prStatus.reviewState!} />] : [])];
...(("external" as string) === 'ant' && hasTmuxSession ? [<TungstenPill key="tmux" selected={tmuxSelected} />] : []), ...(isAgentSwarmsEnabled() && hasTeams ? [<TeamStatus key="teams" teamsSelected={teamsSelected} showHint={showHint && !hasBackgroundTasks} />] : []), ...(shouldShowPrStatus ? [<PrBadge key="pr-status" number={prStatus.number!} url={prStatus.url!} reviewState={prStatus.reviewState!} />] : [])];
// Check if any in-process teammates exist (for hint text cycling)
const hasAnyInProcessTeammates = Object.values(tasks).some(t_2 => t_2.type === 'in_process_teammate' && t_2.status === 'running');
@@ -399,7 +399,7 @@ function ModeIndicator({
}
// Add "↓ to manage tasks" hint when panel has visible rows
const hasCoordinatorTasks = "external" === 'ant' && getVisibleAgentTasks(tasks).length > 0;
const hasCoordinatorTasks = ("external" as string) === 'ant' && getVisibleAgentTasks(tasks).length > 0;
// Tasks pill renders as a Box sibling (not a parts entry) so its
// click-target Box isn't nested inside <Text wrap="truncate"> — the

View File

@@ -34,7 +34,7 @@ function getIcon(itemId: string): string {
function isUnifiedSuggestion(itemId: string): boolean {
return itemId.startsWith('file-') || itemId.startsWith('mcp-resource-') || itemId.startsWith('agent-');
}
const SuggestionItemRow = memo(function SuggestionItemRow(t0) {
const SuggestionItemRow = memo(function SuggestionItemRow(t0: { item: SuggestionItem; maxColumnWidth: number; isSelected: boolean }) {
const $ = _c(36);
const {
item,

View File

@@ -74,8 +74,8 @@ export function HighlightedInput(t0) {
$[8] = lo;
$[9] = hi;
} else {
lo = $[8];
hi = $[9];
lo = $[8] as number;
hi = $[9] as number;
}
sweepStart = lo - 10;
cycleLength = hi - lo + 20;