feat: complete WorkBuddy parity and Windows release workflow
This commit is contained in:
1 parent
143516b3a8
commit
d5512df549
434 files changed
+54977
-1854
No files matched your search
@@ -45,6 +45,7 @@ if (!process.versions.electron) {
|
||||
] }, { id: crypto.randomUUID(), title: 'Edit Other', cwd, createdAt: now - 9000, updatedAt: now - 8000, messages: [
|
||||
{ id: crypto.randomUUID(), role: 'user', content: '另一个会话', createdAt: now - 9000, status: 'done' }
|
||||
] }]
|
||||
for (const message of sessions[0].messages) if (message.role === 'user') message.nativeEntryId = 'qa-native-' + message.id
|
||||
await fs.writeFile(path.join(data, 'sessions.json'), JSON.stringify({ sessions }))
|
||||
await fs.writeFile(path.join(directory, 'expected.json'), JSON.stringify({ crossYearUserId, sameYearUserId, firstUserId, secondUserId, editedFilePath, editedFileBefore, editedFileAfter,
|
||||
sameYearDay, otherYear, userTimes: [otherYear, sameYearDay, now - 4000, now - 2000] }))
|
||||
@@ -123,8 +124,8 @@ if (!process.versions.electron) {
|
||||
// 回退走真实渲染链路与真实 preload/IPC;主进程侧换成记录器,
|
||||
// 真实文件与历史语义由 npm run test:conversation-ipc 覆盖。
|
||||
ipcMain.removeHandler('chat:revert')
|
||||
ipcMain.handle('chat:revert', async (_event, sessionId, messageId) => {
|
||||
revertCalls.push({ sessionId, messageId })
|
||||
ipcMain.handle('chat:revert', async (_event, sessionId, messageId, options) => {
|
||||
revertCalls.push({ sessionId, messageId, options })
|
||||
return { messages: [] }
|
||||
})
|
||||
ipcMain.removeHandler('chat:send')
|
||||
@@ -132,7 +133,7 @@ if (!process.versions.electron) {
|
||||
if (sendDelayMs) await pause(sendDelayMs)
|
||||
sentPayloads.push(payload)
|
||||
const runId = 'edit-run-' + sentPayloads.length
|
||||
const userMessage = { id: 'edit-user-' + sentPayloads.length, role: 'user', content: payload.text, createdAt: Date.now(), status: 'done', requestId: runId }
|
||||
const userMessage = { id: payload.fromMessageId, nativeEntryId: 'qa-replacement', role: 'user', content: payload.text, createdAt: Date.now(), status: 'done', requestId: runId }
|
||||
const assistant = { id: 'edit-assistant-' + sentPayloads.length, role: 'assistant', content: '已重新开始。', createdAt: Date.now(), status: 'done', requestId: runId, tools: [], parts: [] }
|
||||
// ChatEvent 的 done 形状:{ runId, type:'done', content, tools }。
|
||||
setTimeout(() => { try { main?.webContents.send('chat:event', { sessionId: payload.sessionId, runId, type: 'done', content: assistant.content, tools: [] }) } catch { /* window closed */ } }, 60)
|
||||
@@ -194,6 +195,10 @@ if (!process.versions.electron) {
|
||||
await read(`(()=>{const rows=[...document.querySelectorAll('[data-session-id]')];const row=rows.find(item=>item.textContent.includes('Edit Other'));if(!row)return false;row.click();return true})()`)
|
||||
await pause(500)
|
||||
check('switching sessions shows the other session time only', await read(`document.querySelectorAll('.cr-frame--right .cr-toolbar__time').length`), 1)
|
||||
await read(`document.querySelector('.cr-frame--right [data-action="edit"]').click()`)
|
||||
await wait(`!!document.querySelector('.chat-pane [role="alert"]')`, 'legacy edit preflight error')
|
||||
check('legacy messages fail preflight before opening an editor', await read(`!!document.querySelector('.cr-user-message-editor')`), false)
|
||||
check('legacy preflight explains the missing branch', await read(`document.querySelector('.chat-pane [role="alert"]').textContent.includes('原生分支')`), true)
|
||||
await read(`(()=>{const rows=[...document.querySelectorAll('[data-session-id]')];const row=rows.find(item=>item.textContent.includes('Edit Live'));if(!row)return false;row.click();return true})()`)
|
||||
await pause(600)
|
||||
check('history reload keeps the three-tier hover times', await read(timesSource), expected.userTimes.map(expectedTimeText))
|
||||
@@ -260,6 +265,15 @@ if (!process.versions.electron) {
|
||||
await read(setEditable('workbuddy 有目标模式吗'))
|
||||
await pause(120)
|
||||
await read(`document.querySelector('.cr-user-message-editor__send').click()`)
|
||||
await wait(`document.querySelector('.dialog[role="dialog"]')?.getAttribute('aria-label') === '是否回退产物历史版本?'`, 'edit artifact choice')
|
||||
check('artifact edits ask before sending', sentPayloads.length, 0)
|
||||
await read(`document.querySelector('.dialog[role="dialog"] .dialog__actions button').click()`)
|
||||
await wait(`!document.querySelector('.dialog[role="dialog"]')`, 'cancel edit artifact choice')
|
||||
check('cancelling the artifact choice retains the edited draft', await read(`document.querySelector('.cr-user-message-editor [data-slate-editor]').innerText`), 'workbuddy 有目标模式吗')
|
||||
check('cancelling the artifact choice does not send', sentPayloads.length, 0)
|
||||
await read(`document.querySelector('.cr-user-message-editor__send').click()`)
|
||||
await wait(`!!document.querySelector('.dialog[role="dialog"]')`, 'edit artifact choice reopened')
|
||||
await read(`(()=>{const button=[...document.querySelectorAll('.dialog__actions button')].find(item=>item.textContent==='不回退');button.click()})()`)
|
||||
await pause(250)
|
||||
const submitting = await read(editorSource)
|
||||
snapshots.submitting = submitting
|
||||
@@ -273,6 +287,7 @@ if (!process.versions.electron) {
|
||||
check('edit submit reaches chat:send through IPC', !!editPayload, true)
|
||||
check('edit payload carries action=edit with the original message id', editPayload.action === 'edit' && editPayload.fromMessageId === expected.secondUserId, true)
|
||||
check('edit payload sends the modified text', editPayload.text, 'workbuddy 有目标模式吗')
|
||||
check('edit payload records the explicit choice to preserve current artifacts', editPayload.rollbackArtifacts, false)
|
||||
await wait(`!document.querySelector('.cr-user-message-editor')`, 'editor closed after submit')
|
||||
check('submit closes the editor', await read(`!!document.querySelector('.cr-user-message-editor')`), false)
|
||||
// 产物回退由真实主进程语义覆盖:npm run test:conversation-ipc 的 testEditArtifactRollback
|
||||
@@ -322,7 +337,7 @@ if (!process.versions.electron) {
|
||||
snapshots.rewindDialog = dialog
|
||||
check('rewind dialog uses the recovered artifacts variant title', dialog.title, '将对话及以下产物版本回退到此消息前?')
|
||||
check('rewind dialog carries the recovered description', dialog.description, '回退暂不支持部分类型文件')
|
||||
check('rewind dialog actions are 取消/回退', dialog.labels.join(','), '取消,回退')
|
||||
check('rewind dialog offers cancel, keep-artifacts and rewind', dialog.labels.join(','), '取消,不回退,回退')
|
||||
check('rewind dialog lists the pending artifact with its status', dialog.rows.length === 1 && dialog.rows[0].name === 'edited-artifact.txt' && dialog.rows[0].status === '回退至历史版本' && dialog.rows[0].title === expected.editedFilePath, true)
|
||||
await shot('rewind-dialog')
|
||||
await read(`document.querySelector('.dialog[role="dialog"] .dialog__actions button').click()`)
|
||||
@@ -336,6 +351,14 @@ if (!process.versions.electron) {
|
||||
check('confirm reaches chat:revert with the session and message id', revertCalls.length === 1 && revertCalls[0].messageId === expected.secondUserId && typeof revertCalls[0].sessionId === 'string', true)
|
||||
await wait(`!document.querySelector('.dialog[role="dialog"]')`, 'rewind dialog closed after confirm')
|
||||
check('rewind replaces the conversation with the rewound prefix', await read(`document.querySelectorAll('.cr-frame--right').length`), 0)
|
||||
await read(`window.location.reload()`)
|
||||
await wait(`!!document.querySelector('[data-session-id]')`, 'reload for conversation-only rewind')
|
||||
await read(`(()=>{const row=[...document.querySelectorAll('[data-session-id]')].find(item=>item.textContent.includes('Edit Live'));row.click()})()`)
|
||||
await wait(`document.querySelectorAll('.cr-frame--right').length === 4`, 'conversation-only fixture')
|
||||
await openRewind()
|
||||
await read(`(()=>{const button=[...document.querySelectorAll('.dialog__actions button')].find(item=>item.textContent==='不回退');button.click()})()`)
|
||||
await wait(`!document.querySelector('.dialog[role="dialog"]')`, 'conversation-only rewind closed')
|
||||
check('conversation-only rewind sends the artifact option through preload', revertCalls[1]?.options?.rollbackArtifacts, false)
|
||||
check('no renderer error logs', rendererErrors, [])
|
||||
|
||||
const report = { result: checks.every(item => item.pass) ? 'PASS' : 'FAIL',
|
||||
|
||||
Reference in new issue
Block a user