diff --git a/desktop/scripts/e2e-rewind-agent-browser.sh b/desktop/scripts/e2e-rewind-agent-browser.sh
index 7b2ba1ab..3b8c6e66 100755
--- a/desktop/scripts/e2e-rewind-agent-browser.sh
+++ b/desktop/scripts/e2e-rewind-agent-browser.sh
@@ -137,10 +137,10 @@ fi
${AB} screenshot "${ARTIFACT_DIR}/03-after-edit.png" >/dev/null
-${AB} eval "const button = [...document.querySelectorAll('button')].find((node) => node.getAttribute('aria-label') === 'Rewind to here'); if (!button) throw new Error('Rewind button not found'); button.click();"
+${AB} find role button click --name "Undo current turn changes"
${AB} wait 1500
-${AB} screenshot "${ARTIFACT_DIR}/04-rewind-modal.png" >/dev/null
-${AB} find role button click --name "Rewind here"
+${AB} screenshot "${ARTIFACT_DIR}/04-undo-current-turn-confirm.png" >/dev/null
+${AB} find role button click --name "Undo current turn"
for _ in $(seq 1 120); do
if grep -q "before-rewind" "${TARGET_FILE}" && ! grep -q "after-rewind" "${TARGET_FILE}"; then
diff --git a/desktop/scripts/e2e-rewind-complex-agent-browser.sh b/desktop/scripts/e2e-rewind-complex-agent-browser.sh
index 1739f0f0..265d8c02 100755
--- a/desktop/scripts/e2e-rewind-complex-agent-browser.sh
+++ b/desktop/scripts/e2e-rewind-complex-agent-browser.sh
@@ -171,10 +171,10 @@ wait_for_file_contains "${README_FILE}" "Second turn touched README" 60
wait_for_file_contains "${GENERATED_FILE}" "second-turn" 60
${AB} screenshot "${ARTIFACT_DIR}/04-after-second-turn.png" >/dev/null
-${AB} eval "const buttons = [...document.querySelectorAll('button')].filter((node) => node.getAttribute('aria-label') === 'Rewind to here'); if (buttons.length < 2) throw new Error('Expected at least two Rewind buttons, found ' + buttons.length); buttons[buttons.length - 1].click();"
+${AB} find role button click --name "Undo current turn changes"
${AB} wait 1500
-${AB} screenshot "${ARTIFACT_DIR}/05-rewind-second-turn-modal.png" >/dev/null
-${AB} find role button click --name "Rewind here"
+${AB} screenshot "${ARTIFACT_DIR}/05-undo-second-turn-confirm.png" >/dev/null
+${AB} find role button click --name "Undo current turn"
for _ in $(seq 1 120); do
if grep -q "turn-one" "${APP_FILE}" \
diff --git a/desktop/src/__tests__/pages.test.tsx b/desktop/src/__tests__/pages.test.tsx
index a711ca3a..01beb273 100644
--- a/desktop/src/__tests__/pages.test.tsx
+++ b/desktop/src/__tests__/pages.test.tsx
@@ -1,4 +1,4 @@
-import { describe, it, expect, vi } from 'vitest'
+import { beforeEach, describe, it, expect, vi } from 'vitest'
import { fireEvent, render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
@@ -46,9 +46,14 @@ import { ToolInspection } from '../pages/ToolInspection'
import { Sidebar } from '../components/layout/Sidebar'
import { UserMessage } from '../components/chat/UserMessage'
import { useChatStore } from '../stores/chatStore'
+import { useSettingsStore } from '../stores/settingsStore'
import { useSessionStore } from '../stores/sessionStore'
import { useTabStore } from '../stores/tabStore'
+beforeEach(() => {
+ useSettingsStore.setState({ locale: 'en' })
+})
+
/**
* Core rendering tests: content-only pages must render without crashing
* and contain key structural elements from the prototype.
@@ -576,7 +581,8 @@ describe('Design system compliance', () => {
html.includes('C47A5A') ||
html.includes('8F482F') ||
html.includes('var(--color-brand)') ||
- html.includes('bg-[var(--color-brand)]'),
+ html.includes('bg-[var(--color-brand)]') ||
+ html.includes('var(--gradient-btn-primary)'),
).toBe(true)
unmount()
}
diff --git a/desktop/src/components/chat/AskUserQuestion.test.tsx b/desktop/src/components/chat/AskUserQuestion.test.tsx
index 4a8686f1..b6d15d85 100644
--- a/desktop/src/components/chat/AskUserQuestion.test.tsx
+++ b/desktop/src/components/chat/AskUserQuestion.test.tsx
@@ -24,6 +24,7 @@ vi.mock('../../api/sessions', () => ({
import { AskUserQuestion } from './AskUserQuestion'
import { useChatStore } from '../../stores/chatStore'
+import { useSettingsStore } from '../../stores/settingsStore'
import { useTabStore } from '../../stores/tabStore'
const ACTIVE_TAB = 'active-tab'
@@ -31,6 +32,7 @@ const ACTIVE_TAB = 'active-tab'
describe('AskUserQuestion', () => {
beforeEach(() => {
sendMock.mockReset()
+ useSettingsStore.setState({ locale: 'en' })
useTabStore.setState({
activeTabId: ACTIVE_TAB,
tabs: [{ sessionId: ACTIVE_TAB, title: 'Test', type: 'session', status: 'idle' }],
diff --git a/desktop/src/components/chat/ComputerUsePermissionModal.test.tsx b/desktop/src/components/chat/ComputerUsePermissionModal.test.tsx
index c8e372f2..409cef44 100644
--- a/desktop/src/components/chat/ComputerUsePermissionModal.test.tsx
+++ b/desktop/src/components/chat/ComputerUsePermissionModal.test.tsx
@@ -73,12 +73,14 @@ vi.mock('../../api/computerUse', () => ({
}))
import { useChatStore } from '../../stores/chatStore'
+import { useSettingsStore } from '../../stores/settingsStore'
import { ComputerUsePermissionModal } from './ComputerUsePermissionModal'
describe('ComputerUsePermissionModal', () => {
beforeEach(() => {
sendMock.mockReset()
openSettingsMock.mockReset()
+ useSettingsStore.setState({ locale: 'en' })
useChatStore.setState({ sessions: {} })
})
diff --git a/desktop/src/components/chat/FileSearchMenu.test.tsx b/desktop/src/components/chat/FileSearchMenu.test.tsx
index 45ba72c2..ba6cd561 100644
--- a/desktop/src/components/chat/FileSearchMenu.test.tsx
+++ b/desktop/src/components/chat/FileSearchMenu.test.tsx
@@ -4,6 +4,7 @@ import '@testing-library/jest-dom'
import { FileSearchMenu } from './FileSearchMenu'
import { ApiError } from '../../api/client'
import { filesystemApi } from '../../api/filesystem'
+import { useSettingsStore } from '../../stores/settingsStore'
vi.mock('../../api/filesystem', () => ({
filesystemApi: {
@@ -15,6 +16,7 @@ vi.mock('../../api/filesystem', () => ({
describe('FileSearchMenu', () => {
beforeEach(() => {
vi.clearAllMocks()
+ useSettingsStore.setState({ locale: 'en' })
})
it('shows an explicit error when directory browsing is denied', async () => {
diff --git a/desktop/src/components/chat/MessageActionBar.tsx b/desktop/src/components/chat/MessageActionBar.tsx
index 34070cae..3861bd40 100644
--- a/desktop/src/components/chat/MessageActionBar.tsx
+++ b/desktop/src/components/chat/MessageActionBar.tsx
@@ -3,22 +3,17 @@ import { CopyButton } from '../shared/CopyButton'
type Props = {
copyText?: string
copyLabel: string
- onRewind?: () => void
- rewindLabel?: string
align?: 'start' | 'end'
}
export function MessageActionBar({
copyText,
copyLabel,
- onRewind,
- rewindLabel = 'Rewind to here',
align = 'start',
}: Props) {
const hasCopy = Boolean(copyText?.trim())
- const hasRewind = Boolean(onRewind)
- if (!hasCopy && !hasRewind) return null
+ if (!hasCopy) return null
return (
- {hasRewind && (
-
- )}
- {hasCopy && (
-
- )}
+
)
diff --git a/desktop/src/components/chat/MessageList.test.tsx b/desktop/src/components/chat/MessageList.test.tsx
index af05d42a..c24749d2 100644
--- a/desktop/src/components/chat/MessageList.test.tsx
+++ b/desktop/src/components/chat/MessageList.test.tsx
@@ -563,7 +563,7 @@ describe('MessageList nested tool calls', () => {
expect(assistantShell?.className).not.toContain('ml-10')
})
- it('opens a rewind preview modal for user messages', async () => {
+ it('does not expose the old message-level rewind action', async () => {
vi.spyOn(sessionsApi, 'rewind').mockResolvedValue({
target: {
targetUserMessageId: 'user-1',
@@ -575,11 +575,19 @@ describe('MessageList nested tool calls', () => {
},
code: {
available: true,
- filesChanged: ['src/example.ts'],
- insertions: 6,
- deletions: 2,
+ filesChanged: ['src/App.tsx'],
+ insertions: 4,
+ deletions: 1,
},
})
+ vi.spyOn(sessionsApi, 'getWorkspaceStatus').mockResolvedValue({
+ state: 'ok',
+ workDir: '/tmp/example-project',
+ repoName: 'example-project',
+ branch: null,
+ isGitRepo: false,
+ changedFiles: [],
+ })
useChatStore.setState({
sessions: {
@@ -588,74 +596,15 @@ describe('MessageList nested tool calls', () => {
{
id: 'user-1',
type: 'user_text',
- content: '回到这一步重做',
- timestamp: 1,
- },
- ],
- }),
- },
- })
-
- render()
-
- fireEvent.click(screen.getByRole('button', { name: 'Rewind to here' }))
-
- const dialog = await screen.findByRole('dialog')
- expect(within(dialog).getByText('Rewind Conversation')).toBeTruthy()
- expect(within(dialog).getByText('回到这一步重做')).toBeTruthy()
- expect(within(dialog).getByText('src/example.ts')).toBeTruthy()
- expect(sessionsApi.rewind).toHaveBeenCalledWith(ACTIVE_TAB, {
- targetUserMessageId: 'user-1',
- userMessageIndex: 0,
- expectedContent: '回到这一步重做',
- dryRun: true,
- })
- })
-
- it('confirms rewind with the selected message id and prompt guard', async () => {
- vi.spyOn(sessionsApi, 'rewind').mockResolvedValue({
- target: {
- targetUserMessageId: 'user-2',
- userMessageIndex: 1,
- userMessageCount: 2,
- },
- conversation: {
- messagesRemoved: 2,
- },
- code: {
- available: false,
- filesChanged: [],
- insertions: 0,
- deletions: 0,
- },
- })
- const reloadHistory = vi.fn().mockResolvedValue(undefined)
- const queueComposerPrefill = vi.fn()
-
- useChatStore.setState({
- reloadHistory,
- queueComposerPrefill,
- sessions: {
- [ACTIVE_TAB]: makeSessionState({
- messages: [
- {
- id: 'user-1',
- type: 'user_text',
- content: '第一段',
+ content: '做一个页面',
timestamp: 1,
},
{
id: 'assistant-1',
type: 'assistant_text',
- content: 'ok',
+ content: 'done',
timestamp: 2,
},
- {
- id: 'user-2',
- type: 'user_text',
- content: '第二段',
- timestamp: 3,
- },
],
}),
},
@@ -663,23 +612,8 @@ describe('MessageList nested tool calls', () => {
render()
- const buttons = screen.getAllByRole('button', { name: 'Rewind to here' })
- fireEvent.click(buttons[1]!)
- const dialog = await screen.findByRole('dialog')
- fireEvent.click(within(dialog).getByRole('button', { name: /Rewind here/ }))
-
- await waitFor(() => {
- expect(sessionsApi.rewind).toHaveBeenLastCalledWith(ACTIVE_TAB, {
- targetUserMessageId: 'user-2',
- userMessageIndex: 1,
- expectedContent: '第二段',
- })
- })
- expect(reloadHistory).toHaveBeenCalledWith(ACTIVE_TAB)
- expect(queueComposerPrefill).toHaveBeenCalledWith(ACTIVE_TAB, {
- text: '第二段',
- attachments: undefined,
- })
+ expect(await screen.findByRole('button', { name: 'Undo current turn changes' })).toBeTruthy()
+ expect(screen.queryByRole('button', { name: 'Rewind to here' })).toBeNull()
})
it('shows a current-turn change card from checkpoint preview', async () => {
diff --git a/desktop/src/components/chat/MessageList.tsx b/desktop/src/components/chat/MessageList.tsx
index 278e12fe..f299a782 100644
--- a/desktop/src/components/chat/MessageList.tsx
+++ b/desktop/src/components/chat/MessageList.tsx
@@ -19,8 +19,6 @@ import { StreamingIndicator } from './StreamingIndicator'
import { InlineTaskSummary } from './InlineTaskSummary'
import { CurrentTurnChangeCard } from './CurrentTurnChangeCard'
import type { AgentTaskNotification, UIMessage } from '../../types/chat'
-import { Modal } from '../shared/Modal'
-import { Button } from '../shared/Button'
import { ConfirmDialog } from '../shared/ConfirmDialog'
type ToolCall = Extract
@@ -191,16 +189,6 @@ export function MessageList({ sessionId, compact = false }: MessageListProps = {
const shouldAutoScrollRef = useRef(true)
const lastSessionIdRef = useRef(resolvedSessionId)
const t = useTranslation()
- const [rewindTarget, setRewindTarget] = useState<{
- messageId: string
- userMessageIndex: number
- content: string
- attachments?: Extract['attachments']
- } | null>(null)
- const [rewindPreview, setRewindPreview] = useState(null)
- const [rewindError, setRewindError] = useState(null)
- const [isLoadingPreview, setIsLoadingPreview] = useState(false)
- const [isExecutingRewind, setIsExecutingRewind] = useState(false)
const [currentTurnPreview, setCurrentTurnPreview] = useState(null)
const [currentTurnError, setCurrentTurnError] = useState(null)
const [isLoadingCurrentTurnPreview, setIsLoadingCurrentTurnPreview] = useState(false)
@@ -224,49 +212,6 @@ export function MessageList({ sessionId, compact = false }: MessageListProps = {
bottomRef.current?.scrollIntoView?.({ behavior: 'smooth' })
}, [messages.length, resolvedSessionId, streamingText])
- useEffect(() => {
- if (!resolvedSessionId || !rewindTarget) return
-
- let cancelled = false
- setIsLoadingPreview(true)
- setRewindPreview(null)
- setRewindError(null)
-
- void sessionsApi
- .rewind(resolvedSessionId, {
- targetUserMessageId: rewindTarget.messageId,
- userMessageIndex: rewindTarget.userMessageIndex,
- expectedContent: rewindTarget.content,
- dryRun: true,
- })
- .then((preview) => {
- if (!cancelled) {
- setRewindPreview(preview)
- }
- })
- .catch((error) => {
- if (cancelled) return
- const message =
- error instanceof ApiError
- ? typeof error.body === 'object' && error.body && 'message' in error.body
- ? String((error.body as { message: unknown }).message)
- : error.message
- : error instanceof Error
- ? error.message
- : String(error)
- setRewindError(message)
- })
- .finally(() => {
- if (!cancelled) {
- setIsLoadingPreview(false)
- }
- })
-
- return () => {
- cancelled = true
- }
- }, [resolvedSessionId, rewindTarget])
-
const { toolResultMap, childToolCallsByParent, renderItems } = useMemo(
() => buildRenderModel(messages),
[messages],
@@ -335,75 +280,6 @@ export function MessageList({ sessionId, compact = false }: MessageListProps = {
}
}, [chatState, isMemberSession, latestTurnTarget, resolvedSessionId])
- const closeRewindModal = useCallback(() => {
- if (isExecutingRewind) return
- setRewindTarget(null)
- setRewindPreview(null)
- setRewindError(null)
- setIsLoadingPreview(false)
- }, [isExecutingRewind])
-
- const handleConfirmRewind = useCallback(async () => {
- if (!resolvedSessionId || !rewindTarget || isExecutingRewind) return
-
- setIsExecutingRewind(true)
- setRewindError(null)
-
- try {
- if (chatState !== 'idle') {
- stopGeneration(resolvedSessionId)
- }
-
- const result = await sessionsApi.rewind(resolvedSessionId, {
- targetUserMessageId: rewindTarget.messageId,
- userMessageIndex: rewindTarget.userMessageIndex,
- expectedContent: rewindTarget.content,
- })
-
- await reloadHistory(resolvedSessionId)
- queueComposerPrefill(resolvedSessionId, {
- text: rewindTarget.content,
- attachments: rewindTarget.attachments,
- })
-
- addToast({
- type: 'success',
- message: result.code.available
- ? t('chat.rewindSuccessWithCode', {
- count: result.conversation.messagesRemoved,
- })
- : t('chat.rewindSuccessConversationOnly', {
- count: result.conversation.messagesRemoved,
- }),
- })
-
- setRewindTarget(null)
- setRewindPreview(null)
- } catch (error) {
- const message =
- error instanceof ApiError
- ? typeof error.body === 'object' && error.body && 'message' in error.body
- ? String((error.body as { message: unknown }).message)
- : error.message
- : error instanceof Error
- ? error.message
- : String(error)
- setRewindError(message)
- } finally {
- setIsExecutingRewind(false)
- }
- }, [
- addToast,
- chatState,
- isExecutingRewind,
- queueComposerPrefill,
- reloadHistory,
- resolvedSessionId,
- rewindTarget,
- stopGeneration,
- t,
- ])
-
const handleUndoCurrentTurn = useCallback(async () => {
if (!resolvedSessionId || !currentTurnPreview || isUndoingCurrentTurn) return
@@ -467,8 +343,6 @@ export function MessageList({ sessionId, compact = false }: MessageListProps = {
t,
])
- let visibleUserMessageIndex = -1
-
return (
{
- setRewindTarget({
- messageId: message.id,
- userMessageIndex,
- content: message.content,
- attachments: message.attachments,
- })
- }
- : undefined
- }
/>
)
})}
@@ -563,119 +420,6 @@ export function MessageList({ sessionId, compact = false }: MessageListProps = {
-
-
-
- >
- }
- >
-
-
-
- {t('chat.rewindPromptLabel')}
-
-
- {rewindTarget?.content || t('chat.rewindAttachmentOnly')}
-
-
-
- {isLoadingPreview && (
-
- {t('chat.rewindLoading')}
-
- )}
-
- {!isLoadingPreview && rewindPreview && (
-
-
-
- history
- {t('chat.rewindConversationCardTitle')}
-
-
- {t('chat.rewindConversationCardBody', {
- count: rewindPreview.conversation.messagesRemoved,
- })}
-
-
-
-
-
- code
- {t('chat.rewindCodeCardTitle')}
-
- {rewindPreview.code.available ? (
-
-
{t('chat.rewindCodeFiles', { count: rewindPreview.code.filesChanged.length })}
-
{t('chat.rewindCodeInsertions', { count: rewindPreview.code.insertions })}
-
{t('chat.rewindCodeDeletions', { count: rewindPreview.code.deletions })}
-
- ) : (
-
- {rewindPreview.code.reason || t('chat.rewindCodeUnavailable')}
-
- )}
-
-
- )}
-
- {!isLoadingPreview && rewindPreview?.code.available && rewindPreview.code.filesChanged.length > 0 && (
-
-
- {t('chat.rewindFilesLabel')}
-
-
- {rewindPreview.code.filesChanged.slice(0, 8).map((filePath) => (
-
- {filePath}
-
- ))}
- {rewindPreview.code.filesChanged.length > 8 && (
-
- {t('chat.rewindFilesMore', {
- count: rewindPreview.code.filesChanged.length - 8,
- })}
-
- )}
-
-
- )}
-
- {rewindError && (
-
- {rewindError}
-
- )}
-
-
-
{
@@ -700,18 +444,11 @@ export const MessageBlock = memo(function MessageBlock({
activeThinkingId,
agentTaskNotifications,
toolResult,
- rewindableUserIndex,
- onRequestRewind,
}: {
message: UIMessage
activeThinkingId: string | null
agentTaskNotifications: Record
toolResult?: { content: unknown; isError: boolean } | null
- rewindableUserIndex?: number | null
- onRequestRewind?: (
- message: Extract,
- userMessageIndex: number,
- ) => void
}) {
const t = useTranslation()
@@ -721,12 +458,6 @@ export const MessageBlock = memo(function MessageBlock({
onRequestRewind(message, rewindableUserIndex)
- : undefined
- }
- rewindLabel={t('chat.rewindAction')}
/>
)
case 'assistant_text':
diff --git a/desktop/src/components/chat/UserMessage.tsx b/desktop/src/components/chat/UserMessage.tsx
index 729ed489..9162384e 100644
--- a/desktop/src/components/chat/UserMessage.tsx
+++ b/desktop/src/components/chat/UserMessage.tsx
@@ -5,11 +5,9 @@ import { MessageActionBar } from './MessageActionBar'
type Props = {
content: string
attachments?: UIAttachment[]
- onRewind?: () => void
- rewindLabel?: string
}
-export function UserMessage({ content, attachments, onRewind, rewindLabel }: Props) {
+export function UserMessage({ content, attachments }: Props) {
const hasText = content.trim().length > 0
return (
@@ -35,8 +33,6 @@ export function UserMessage({ content, attachments, onRewind, rewindLabel }: Pro
)}
diff --git a/desktop/src/components/chat/chatBlocks.test.tsx b/desktop/src/components/chat/chatBlocks.test.tsx
index 270144e2..de59a471 100644
--- a/desktop/src/components/chat/chatBlocks.test.tsx
+++ b/desktop/src/components/chat/chatBlocks.test.tsx
@@ -4,10 +4,12 @@ import { ThinkingBlock } from './ThinkingBlock'
import { ToolCallBlock } from './ToolCallBlock'
import { PermissionDialog } from './PermissionDialog'
import { useChatStore } from '../../stores/chatStore'
+import { useSettingsStore } from '../../stores/settingsStore'
import { useTabStore } from '../../stores/tabStore'
describe('chat blocks', () => {
beforeEach(() => {
+ useSettingsStore.setState({ locale: 'en' })
useTabStore.setState({ activeTabId: 'active-tab', tabs: [{ sessionId: 'active-tab', title: 'Test', type: 'session' as const, status: 'idle' }] })
useChatStore.setState({ sessions: {} })
})
diff --git a/desktop/src/components/shared/UpdateChecker.test.tsx b/desktop/src/components/shared/UpdateChecker.test.tsx
index da1b0c60..e29e2785 100644
--- a/desktop/src/components/shared/UpdateChecker.test.tsx
+++ b/desktop/src/components/shared/UpdateChecker.test.tsx
@@ -3,10 +3,12 @@ import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import { UpdateChecker } from './UpdateChecker'
+import { useSettingsStore } from '../../stores/settingsStore'
import { useUpdateStore } from '../../stores/updateStore'
describe('UpdateChecker', () => {
beforeEach(() => {
+ useSettingsStore.setState({ locale: 'en' })
Object.defineProperty(window, '__TAURI__', {
value: {},
configurable: true,
diff --git a/desktop/src/i18n/locales/en.ts b/desktop/src/i18n/locales/en.ts
index bd40377b..f19d0eda 100644
--- a/desktop/src/i18n/locales/en.ts
+++ b/desktop/src/i18n/locales/en.ts
@@ -617,21 +617,6 @@ export const en = {
'chat.select': 'select',
'chat.dismiss': 'dismiss',
'chat.stopTitle': 'Stop generation (Cmd+.)',
- 'chat.rewindAction': 'Rewind to here',
- 'chat.rewindModalTitle': 'Rewind Conversation',
- 'chat.rewindConfirm': 'Rewind here',
- 'chat.rewindPromptLabel': 'Selected prompt',
- 'chat.rewindAttachmentOnly': 'This message only contains attachments.',
- 'chat.rewindLoading': 'Inspecting file checkpoints for this turn...',
- 'chat.rewindConversationCardTitle': 'Conversation rollback',
- 'chat.rewindConversationCardBody': 'Remove this prompt and the {count} active messages that follow it, then reopen the composer at that point.',
- 'chat.rewindCodeCardTitle': 'Code rollback',
- 'chat.rewindCodeFiles': '{count} files will be restored',
- 'chat.rewindCodeInsertions': '{count} insertions will be removed',
- 'chat.rewindCodeDeletions': '{count} deletions will be restored',
- 'chat.rewindCodeUnavailable': 'No file checkpoint is available for this prompt. The conversation can still be rewound.',
- 'chat.rewindFilesLabel': 'Affected files',
- 'chat.rewindFilesMore': '+{count} more',
'chat.rewindSuccessWithCode': 'Rewound {count} messages and restored tracked files.',
'chat.rewindSuccessConversationOnly': 'Rewound {count} messages. No file checkpoint was available for this turn.',
'chat.turnChangesCardLabel': 'Current turn changed files',
diff --git a/desktop/src/i18n/locales/zh.ts b/desktop/src/i18n/locales/zh.ts
index ad985b15..3e721154 100644
--- a/desktop/src/i18n/locales/zh.ts
+++ b/desktop/src/i18n/locales/zh.ts
@@ -619,21 +619,6 @@ export const zh: Record = {
'chat.select': '选择',
'chat.dismiss': '关闭',
'chat.stopTitle': '停止生成 (Cmd+.)',
- 'chat.rewindAction': '回滚到这里',
- 'chat.rewindModalTitle': '回滚对话',
- 'chat.rewindConfirm': '执行回滚',
- 'chat.rewindPromptLabel': '目标提示词',
- 'chat.rewindAttachmentOnly': '这条消息只包含附件。',
- 'chat.rewindLoading': '正在检查这一轮的文件检查点...',
- 'chat.rewindConversationCardTitle': '对话回滚',
- 'chat.rewindConversationCardBody': '移除这条提示词以及其后的 {count} 条活跃消息,并把输入框恢复到这个位置。',
- 'chat.rewindCodeCardTitle': '代码回滚',
- 'chat.rewindCodeFiles': '将恢复 {count} 个文件',
- 'chat.rewindCodeInsertions': '将移除 {count} 行新增',
- 'chat.rewindCodeDeletions': '将恢复 {count} 行删除',
- 'chat.rewindCodeUnavailable': '这条提示词没有可用的文件检查点,仍然可以只回滚对话。',
- 'chat.rewindFilesLabel': '受影响文件',
- 'chat.rewindFilesMore': '另有 {count} 个',
'chat.rewindSuccessWithCode': '已回滚 {count} 条消息,并恢复相关文件。',
'chat.rewindSuccessConversationOnly': '已回滚 {count} 条消息。这一轮没有可用的文件检查点。',
'chat.turnChangesCardLabel': '当前轮次已更改文件',