mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-28 19:52:02 +00:00
Merge remote-tracking branch 'origin/main' into fix/pr2371-btw-complete
# Conflicts: # packages/cli/src/ui/AppContainer.tsx # packages/cli/src/ui/hooks/useGeminiStream.ts # packages/cli/src/ui/layouts/DefaultAppLayout.tsx # packages/cli/src/ui/types.ts # packages/core/src/core/client.test.ts
This commit is contained in:
commit
bd77eef46f
406 changed files with 55514 additions and 6431 deletions
|
|
@ -75,7 +75,7 @@ export const SuccessMessage: React.FC<StatusTextProps> = ({ text }) => (
|
|||
export const WarningMessage: React.FC<StatusTextProps> = ({ text }) => (
|
||||
<StatusMessage
|
||||
text={text}
|
||||
prefix="⚠"
|
||||
prefix="△"
|
||||
prefixColor={theme.status.warning}
|
||||
textColor={theme.status.warning}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -138,17 +138,17 @@ describe('ToolConfirmationMessage', () => {
|
|||
{
|
||||
description: 'for exec confirmations',
|
||||
details: execConfirmationDetails,
|
||||
alwaysAllowText: 'Yes, allow always',
|
||||
alwaysAllowText: 'Always allow in this project',
|
||||
},
|
||||
{
|
||||
description: 'for info confirmations',
|
||||
details: infoConfirmationDetails,
|
||||
alwaysAllowText: 'Yes, allow always',
|
||||
alwaysAllowText: 'Always allow in this project',
|
||||
},
|
||||
{
|
||||
description: 'for mcp confirmations',
|
||||
details: mcpConfirmationDetails,
|
||||
alwaysAllowText: 'always allow',
|
||||
alwaysAllowText: 'Always allow in this project',
|
||||
},
|
||||
])('$description', ({ details, alwaysAllowText }) => {
|
||||
it('should show "allow always" when folder is trusted', () => {
|
||||
|
|
|
|||
|
|
@ -242,11 +242,19 @@ export const ToolConfirmationMessage: React.FC<
|
|||
value: ToolConfirmationOutcome.ProceedOnce,
|
||||
key: 'Yes, allow once',
|
||||
});
|
||||
if (isTrustedFolder) {
|
||||
if (isTrustedFolder && !confirmationDetails.hideAlwaysAllow) {
|
||||
const rulesLabel = executionProps.permissionRules?.length
|
||||
? ` [${executionProps.permissionRules.join(', ')}]`
|
||||
: '';
|
||||
options.push({
|
||||
label: t('Yes, allow always ...'),
|
||||
value: ToolConfirmationOutcome.ProceedAlways,
|
||||
key: 'Yes, allow always ...',
|
||||
label: t('Always allow in this project') + rulesLabel,
|
||||
value: ToolConfirmationOutcome.ProceedAlwaysProject,
|
||||
key: 'Always allow in this project',
|
||||
});
|
||||
options.push({
|
||||
label: t('Always allow for this user') + rulesLabel,
|
||||
value: ToolConfirmationOutcome.ProceedAlwaysUser,
|
||||
key: 'Always allow for this user',
|
||||
});
|
||||
}
|
||||
options.push({
|
||||
|
|
@ -315,11 +323,21 @@ export const ToolConfirmationMessage: React.FC<
|
|||
value: ToolConfirmationOutcome.ProceedOnce,
|
||||
key: 'Yes, allow once',
|
||||
});
|
||||
if (isTrustedFolder) {
|
||||
if (isTrustedFolder && !confirmationDetails.hideAlwaysAllow) {
|
||||
const rulesLabel =
|
||||
'permissionRules' in infoProps &&
|
||||
(infoProps as { permissionRules?: string[] }).permissionRules?.length
|
||||
? ` [${(infoProps as { permissionRules?: string[] }).permissionRules!.join(', ')}]`
|
||||
: '';
|
||||
options.push({
|
||||
label: t('Yes, allow always'),
|
||||
value: ToolConfirmationOutcome.ProceedAlways,
|
||||
key: 'Yes, allow always',
|
||||
label: t('Always allow in this project') + rulesLabel,
|
||||
value: ToolConfirmationOutcome.ProceedAlwaysProject,
|
||||
key: 'Always allow in this project',
|
||||
});
|
||||
options.push({
|
||||
label: t('Always allow for this user') + rulesLabel,
|
||||
value: ToolConfirmationOutcome.ProceedAlwaysUser,
|
||||
key: 'Always allow for this user',
|
||||
});
|
||||
}
|
||||
options.push({
|
||||
|
|
@ -382,21 +400,19 @@ export const ToolConfirmationMessage: React.FC<
|
|||
value: ToolConfirmationOutcome.ProceedOnce,
|
||||
key: 'Yes, allow once',
|
||||
});
|
||||
if (isTrustedFolder) {
|
||||
if (isTrustedFolder && !confirmationDetails.hideAlwaysAllow) {
|
||||
const rulesLabel = mcpProps.permissionRules?.length
|
||||
? ` [${mcpProps.permissionRules.join(', ')}]`
|
||||
: '';
|
||||
options.push({
|
||||
label: t('Yes, always allow tool "{{tool}}" from server "{{server}}"', {
|
||||
tool: mcpProps.toolName,
|
||||
server: mcpProps.serverName,
|
||||
}),
|
||||
value: ToolConfirmationOutcome.ProceedAlwaysTool, // Cast until types are updated
|
||||
key: `Yes, always allow tool "${mcpProps.toolName}" from server "${mcpProps.serverName}"`,
|
||||
label: t('Always allow in this project') + rulesLabel,
|
||||
value: ToolConfirmationOutcome.ProceedAlwaysProject,
|
||||
key: 'Always allow in this project',
|
||||
});
|
||||
options.push({
|
||||
label: t('Yes, always allow all tools from server "{{server}}"', {
|
||||
server: mcpProps.serverName,
|
||||
}),
|
||||
value: ToolConfirmationOutcome.ProceedAlwaysServer,
|
||||
key: `Yes, always allow all tools from server "${mcpProps.serverName}"`,
|
||||
label: t('Always allow for this user') + rulesLabel,
|
||||
value: ToolConfirmationOutcome.ProceedAlwaysUser,
|
||||
key: 'Always allow for this user',
|
||||
});
|
||||
}
|
||||
options.push({
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import type React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { Box } from 'ink';
|
||||
import type { IndividualToolCallDisplay } from '../../types.js';
|
||||
import { ToolCallStatus } from '../../types.js';
|
||||
import { ToolMessage } from './ToolMessage.js';
|
||||
|
|
@ -136,13 +136,6 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
|
|||
contentWidth={innerWidth}
|
||||
/>
|
||||
)}
|
||||
{tool.outputFile && (
|
||||
<Box marginX={1}>
|
||||
<Text color={theme.text.primary}>
|
||||
Output too long and was saved to: {tool.outputFile}
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -300,4 +300,55 @@ describe('<ToolMessage />', () => {
|
|||
);
|
||||
expect(lastFrame()).toContain('MockAnsiOutput:hello');
|
||||
});
|
||||
|
||||
it('renders rejected plan content with plan text still visible', () => {
|
||||
const planResultDisplay = {
|
||||
type: 'plan_summary' as const,
|
||||
message: 'Plan was rejected. Remaining in plan mode.',
|
||||
plan: '# My Plan\n- Step 1: Do something\n- Step 2: Do another thing',
|
||||
rejected: true,
|
||||
};
|
||||
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage
|
||||
{...baseProps}
|
||||
name="ExitPlanMode"
|
||||
description="Plan:"
|
||||
status={ToolCallStatus.Canceled}
|
||||
resultDisplay={planResultDisplay}
|
||||
/>,
|
||||
StreamingState.Idle,
|
||||
);
|
||||
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('Plan was rejected. Remaining in plan mode.');
|
||||
expect(output).toContain('MockMarkdown:# My Plan');
|
||||
expect(output).toContain('- Step 1: Do something');
|
||||
expect(output).toContain('- Step 2: Do another thing');
|
||||
});
|
||||
|
||||
it('renders approved plan content with approval message', () => {
|
||||
const planResultDisplay = {
|
||||
type: 'plan_summary' as const,
|
||||
message: 'User approved the plan.',
|
||||
plan: '# My Plan\n- Step 1\n- Step 2',
|
||||
};
|
||||
|
||||
const { lastFrame } = renderWithContext(
|
||||
<ToolMessage
|
||||
{...baseProps}
|
||||
name="ExitPlanMode"
|
||||
description="Plan:"
|
||||
status={ToolCallStatus.Success}
|
||||
resultDisplay={planResultDisplay}
|
||||
/>,
|
||||
StreamingState.Idle,
|
||||
);
|
||||
|
||||
const output = lastFrame();
|
||||
expect(output).toContain('User approved the plan.');
|
||||
expect(output).toContain('MockMarkdown:# My Plan');
|
||||
expect(output).toContain('- Step 1');
|
||||
expect(output).toContain('- Step 2');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue