mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-28 19:52:02 +00:00
fix: address PR review feedback for verbose/compact mode toggle
- Change default verboseMode to true (preserving current UX behavior) - Fix compact mode hiding active shell output (add forceShowResult + isUserInitiated) - Fix asymmetric frozen snapshot (freeze on ANY toggle during streaming) - Fix copyright header in VerboseModeContext.tsx (Google LLC → Qwen) - Add proper translations for all 6 locales (de/ja/pt/ru/zh/en) - Rewrite CompactToolGroupDisplay with bordered box, i18n hint, shell detection - Fix Pending status color (theme.text.secondary instead of theme.status.success) - Fix description casing: ctrl+o → Ctrl+O - Add explanatory comment for useCallback settings dependency Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b9c17d13ff
commit
6fd29b698b
18 changed files with 261 additions and 27 deletions
|
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import type { IndividualToolCallDisplay } from '../../types.js';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import { GeminiRespondingSpinner } from '../GeminiRespondingSpinner.js';
|
||||
import {
|
||||
TOOL_STATUS,
|
||||
SHELL_COMMAND_NAME,
|
||||
SHELL_NAME,
|
||||
} from '../../constants.js';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { t } from '../../../i18n/index.js';
|
||||
|
||||
interface CompactToolGroupDisplayProps {
|
||||
toolCalls: IndividualToolCallDisplay[];
|
||||
contentWidth: number;
|
||||
}
|
||||
|
||||
// Priority: Confirming > Executing > Error > Canceled > Pending > Success
|
||||
function getOverallStatus(
|
||||
toolCalls: IndividualToolCallDisplay[],
|
||||
): ToolCallStatus {
|
||||
if (toolCalls.some((t) => t.status === ToolCallStatus.Confirming))
|
||||
return ToolCallStatus.Confirming;
|
||||
if (toolCalls.some((t) => t.status === ToolCallStatus.Executing))
|
||||
return ToolCallStatus.Executing;
|
||||
if (toolCalls.some((t) => t.status === ToolCallStatus.Error))
|
||||
return ToolCallStatus.Error;
|
||||
if (toolCalls.some((t) => t.status === ToolCallStatus.Canceled))
|
||||
return ToolCallStatus.Canceled;
|
||||
if (toolCalls.some((t) => t.status === ToolCallStatus.Pending))
|
||||
return ToolCallStatus.Pending;
|
||||
return ToolCallStatus.Success;
|
||||
}
|
||||
|
||||
// Active tool priority: Confirming > Executing > last in array
|
||||
function getActiveTool(
|
||||
toolCalls: IndividualToolCallDisplay[],
|
||||
): IndividualToolCallDisplay {
|
||||
return (
|
||||
toolCalls.find((t) => t.status === ToolCallStatus.Confirming) ??
|
||||
toolCalls.find((t) => t.status === ToolCallStatus.Executing) ??
|
||||
toolCalls[toolCalls.length - 1]
|
||||
);
|
||||
}
|
||||
|
||||
const STATUS_INDICATOR_WIDTH = 3;
|
||||
|
||||
export const CompactToolGroupDisplay: React.FC<
|
||||
CompactToolGroupDisplayProps
|
||||
> = ({ toolCalls, contentWidth }) => {
|
||||
if (toolCalls.length === 0) return null;
|
||||
|
||||
const overallStatus = getOverallStatus(toolCalls);
|
||||
const activeTool = getActiveTool(toolCalls);
|
||||
|
||||
const isShellCommand = toolCalls.some(
|
||||
(t) => t.name === SHELL_COMMAND_NAME || t.name === SHELL_NAME,
|
||||
);
|
||||
const hasPending = !toolCalls.every(
|
||||
(t) => t.status === ToolCallStatus.Success,
|
||||
);
|
||||
|
||||
const borderColor = isShellCommand
|
||||
? theme.ui.symbol
|
||||
: hasPending
|
||||
? theme.status.warning
|
||||
: theme.border.default;
|
||||
|
||||
// Take only the first line of description to prevent multi-line shell scripts
|
||||
// from expanding the compact view (wrap="truncate-end" only handles width overflow,
|
||||
// not literal \n characters in the content)
|
||||
const activeToolDescription = activeTool.description
|
||||
? activeTool.description.split('\n')[0]
|
||||
: '';
|
||||
|
||||
const renderStatusIcon = () => {
|
||||
switch (overallStatus) {
|
||||
case ToolCallStatus.Executing:
|
||||
return (
|
||||
<GeminiRespondingSpinner
|
||||
spinnerType="toggle"
|
||||
nonRespondingDisplay={TOOL_STATUS.EXECUTING}
|
||||
/>
|
||||
);
|
||||
case ToolCallStatus.Success:
|
||||
return <Text color={theme.status.success}>{TOOL_STATUS.SUCCESS}</Text>;
|
||||
case ToolCallStatus.Error:
|
||||
return (
|
||||
<Text color={theme.status.error} bold>
|
||||
{TOOL_STATUS.ERROR}
|
||||
</Text>
|
||||
);
|
||||
case ToolCallStatus.Confirming:
|
||||
return (
|
||||
<Text color={theme.status.warning}>{TOOL_STATUS.CONFIRMING}</Text>
|
||||
);
|
||||
case ToolCallStatus.Canceled:
|
||||
return (
|
||||
<Text color={theme.status.warning} bold>
|
||||
{TOOL_STATUS.CANCELED}
|
||||
</Text>
|
||||
);
|
||||
case ToolCallStatus.Pending:
|
||||
return <Text color={theme.text.secondary}>{TOOL_STATUS.PENDING}</Text>;
|
||||
default:
|
||||
return <Text>{TOOL_STATUS.PENDING}</Text>;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
flexDirection="column"
|
||||
borderStyle="round"
|
||||
width={contentWidth}
|
||||
borderDimColor={hasPending}
|
||||
borderColor={borderColor}
|
||||
gap={0}
|
||||
>
|
||||
{/* Status line: icon + tool name + description */}
|
||||
<Box flexDirection="row">
|
||||
<Box minWidth={STATUS_INDICATOR_WIDTH}>{renderStatusIcon()}</Box>
|
||||
<Box flexGrow={1}>
|
||||
<Text wrap="truncate-end">
|
||||
<Text bold>{activeTool.name}</Text>
|
||||
{activeToolDescription ? (
|
||||
<Text color={theme.text.secondary}>
|
||||
{' '}
|
||||
{activeToolDescription}
|
||||
</Text>
|
||||
) : null}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Hint line */}
|
||||
<Text color={theme.text.secondary}>
|
||||
{t('Press Ctrl+O to show full tool output')}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue