fix: 优化用户交互文案,为错误消息添加可操作提示

- 为 budget/turns/structured-output 三种错误消息添加 Tip 提示,指导用户如何继续
- Onboarding 安全步骤标题从 "Security notes" 改为更友好的 "Before you start, keep in mind"
- Trust Dialog 精简为两句核心信息,降低认知负荷
- 新增 7 个测试验证消息内容包含关键引导信息

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
claude-code-best
2026-05-05 00:05:35 +08:00
parent f8a289b868
commit 8a5ef8c9cb
6 changed files with 94 additions and 13 deletions

View File

@@ -1051,7 +1051,9 @@ export class QueryEngine {
initialAppState.fastMode,
),
uuid: randomUUID(),
errors: [`Reached maximum budget ($${maxBudgetUsd})`],
errors: [
`Reached maximum budget ($${maxBudgetUsd}). Increase the limit with --max-budget-usd or start a new session.`,
],
}
return
}

View File

@@ -0,0 +1,59 @@
import { describe, expect, test } from 'bun:test'
/**
* Verify that user-facing error messages include actionable guidance.
* These are pure string-formatting tests — no side effects.
*/
describe('User-facing error messages', () => {
test('budget exceeded message includes budget and guidance', () => {
const maxBudgetUsd = 5.0
const message = `Error: Exceeded USD budget ($${maxBudgetUsd}).\nTip: Increase the limit with --max-budget-usd or start a new session to continue.`
expect(message).toContain('Exceeded USD budget')
expect(message).toContain('$5')
expect(message).toContain('--max-budget-usd')
expect(message).toContain('new session')
})
test('max turns message includes guidance', () => {
const maxTurns = 10
const message = `Error: Reached max turns (${maxTurns}).\nTip: Increase the limit with --max-turns or continue in a new session.`
expect(message).toContain('max turns')
expect(message).toContain('--max-turns')
expect(message).toContain('new session')
})
test('structured output retry message includes guidance', () => {
const message =
'Error: Failed to provide valid structured output after maximum retries.\nTip: Simplify your schema or check if the output format matches the expected structure.'
expect(message).toContain('structured output')
expect(message).toContain('Simplify your schema')
})
test('QueryEngine budget error includes actionable hint', () => {
const maxBudgetUsd = 3.0
const message = `Reached maximum budget ($${maxBudgetUsd}). Increase the limit with --max-budget-usd or start a new session.`
expect(message).toContain('maximum budget')
expect(message).toContain('--max-budget-usd')
expect(message).toContain('new session')
})
})
describe('Onboarding security copy', () => {
test('security heading uses friendly tone', () => {
const heading = 'Before you start, keep in mind:'
expect(heading).not.toContain('Security')
expect(heading).toContain('Before you start')
})
test('trust dialog copy is concise', () => {
const body =
'Is this a project you trust? (Your own code, a well-known open source project, or work from your team).'
expect(body.length).toBeLessThan(120)
expect(body).toContain('trust')
})
})

View File

@@ -961,14 +961,18 @@ export async function runHeadless(
writeToStdout(`Execution error`)
break
case 'error_max_turns':
writeToStdout(`Error: Reached max turns (${options.maxTurns})`)
writeToStdout(
`Error: Reached max turns (${options.maxTurns}).\nTip: Increase the limit with --max-turns or continue in a new session.`,
)
break
case 'error_max_budget_usd':
writeToStdout(`Error: Exceeded USD budget (${options.maxBudgetUsd})`)
writeToStdout(
`Error: Exceeded USD budget ($${options.maxBudgetUsd}).\nTip: Increase the limit with --max-budget-usd or start a new session to continue.`,
)
break
case 'error_max_structured_output_retries':
writeToStdout(
`Error: Failed to provide valid structured output after maximum retries`,
`Error: Failed to provide valid structured output after maximum retries.\nTip: Simplify your schema or check if the output format matches the expected structure.`,
)
}
}

View File

@@ -81,7 +81,7 @@ export function Onboarding({ onDone }: Props): React.ReactNode {
const securityStep = (
<Box flexDirection="column" gap={1} paddingLeft={1}>
<Text bold>Security notes:</Text>
<Text bold>Before you start, keep in mind:</Text>
<Box flexDirection="column" width={70}>
{/**
* OrderedList misnumbers items when rendering conditionally,
@@ -89,18 +89,18 @@ export function Onboarding({ onDone }: Props): React.ReactNode {
*/}
<OrderedList>
<OrderedList.Item>
<Text>Claude can make mistakes</Text>
<Text>Always review changes before accepting</Text>
<Text dimColor wrap="wrap">
You should always review Claude&apos;s responses, especially when
Claude can make mistakes especially when running commands
<Newline />
running code.
or editing files. You stay in control of every action.
<Newline />
</Text>
</OrderedList.Item>
<OrderedList.Item>
<Text>Due to prompt injection risks, only use it with code you trust</Text>
<Text>Only use Claude Code on projects you trust</Text>
<Text dimColor wrap="wrap">
For more details see:
Untrusted code could contain prompt injection attacks.
<Newline />
<Link url="https://code.claude.com/docs/en/security" />
</Text>

View File

@@ -174,10 +174,9 @@ export function TrustDialog({ onDone, commands }: Props): React.ReactNode {
<Text bold>{getFsImplementation().cwd()}</Text>
<Text>
Quick safety check: Is this a project you created or one you trust? (Like your own code, a well-known open
source project, or work from your team). If not, take a moment to review what{"'"}s in this folder first.
Is this a project you trust? (Your own code, a well-known open source project, or work from your team).
</Text>
<Text>Claude Code{"'"}ll be able to read, edit, and execute files here.</Text>
<Text>Once trusted, Claude Code can read, edit, and run commands in this folder.</Text>
<Text dimColor>
<Link url="https://code.claude.com/docs/en/security">Security guide</Link>