cc-haha/desktop/src/stores/workspaceChatContextStore.test.ts
程序员阿江(Relakkes) 80aca8c176 feat: 让工作区文件引用成为可回滚的聊天上下文
桌面端的工作区文件面板现在可以把文件或局部评论加入聊天,发送给 CLI 的内容保持为原生 @文件路径引用,聊天界面则保留用户可读的文件 chip。为了让本轮变更卡片和 checkpoint 回滚继续可靠,UI 消息会同时保存用于展示的内容和实际发给模型的 modelContent;历史转录里的 @文件路径也会在重载时还原成附件 chip。

Constraint: CLI 侧最稳定的文件上下文入口仍是原生 @文件路径
Constraint: 聊天 UI 不能把绝对路径裸露成用户消息正文
Rejected: 只发送隐藏提示文本 | CLI 对 @文件路径已有稳定读取行为
Rejected: 只依赖前端展示内容做回滚校验 | 会和真实转录内容不一致
Confidence: high
Scope-risk: moderate
Directive: 修改附件展示或回滚校验时必须同时验证 modelContent 与 UI content 的分离
Tested: cd desktop && bun run test -- src/stores/chatStore.test.ts src/components/chat/MessageList.test.tsx src/stores/workspaceChatContextStore.test.ts src/components/workspace/WorkspacePanel.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: SKIP_INSTALL=1 ./desktop/scripts/build-macos-arm64.sh
Tested: codesign --verify --deep --strict --verbose=2 desktop/build-artifacts/macos-arm64/Claude\ Code\ Haha.app
Tested: hdiutil verify desktop/build-artifacts/macos-arm64/Claude\ Code\ Haha_0.1.8_aarch64.dmg
Tested: Computer Use macOS run with /private/tmp/cc-haha-computer-use-e2e verified file chip, @path model input, model sentinel response, workspace preview interactions
Not-tested: Deep unloaded-folder fuzzy search in all-files view
2026-05-01 00:00:32 +08:00

70 lines
1.9 KiB
TypeScript

import { beforeEach, describe, expect, it } from 'vitest'
import {
formatWorkspaceReferencePrompt,
useWorkspaceChatContextStore,
} from './workspaceChatContextStore'
const initialState = useWorkspaceChatContextStore.getInitialState()
describe('workspaceChatContextStore', () => {
beforeEach(() => {
useWorkspaceChatContextStore.setState(initialState, true)
})
it('deduplicates file references per session', () => {
const store = useWorkspaceChatContextStore.getState()
store.addReference('session-1', {
kind: 'file',
path: 'src/App.tsx',
absolutePath: '/repo/src/App.tsx',
name: 'App.tsx',
})
store.addReference('session-1', {
kind: 'file',
path: 'src/App.tsx',
absolutePath: '/repo/src/App.tsx',
name: 'App.tsx',
})
expect(useWorkspaceChatContextStore.getState().referencesBySession['session-1']).toHaveLength(1)
})
it('formats line comments into the request prompt', () => {
const prompt = formatWorkspaceReferencePrompt([
{
id: 'ref-1',
kind: 'code-comment',
path: 'src/App.tsx',
absolutePath: '/repo/src/App.tsx',
name: 'App.tsx',
lineStart: 12,
lineEnd: 12,
note: 'Use a clearer name',
quote: 'const value = 1',
},
])
expect(prompt).toContain('Notes for attached workspace files:')
expect(prompt).toContain('- src/App.tsx:L12')
expect(prompt).toContain('Comment: Use a clearer name')
expect(prompt).toContain('Selected code: const value = 1')
expect(prompt).not.toContain('Use the Read tool')
expect(prompt).not.toContain('Path: /repo/src/App.tsx')
})
it('does not add prompt text for plain file attachments', () => {
const prompt = formatWorkspaceReferencePrompt([
{
id: 'ref-1',
kind: 'file',
path: 'src/App.tsx',
absolutePath: '/repo/src/App.tsx',
name: 'App.tsx',
},
])
expect(prompt).toBe('')
})
})