fix(desktop): reset picker state on selection + guard malformed preview payloads

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
程序员阿江(Relakkes) 2026-05-29 13:45:14 +08:00
parent b3c4f1b686
commit fcd766a5ff
2 changed files with 24 additions and 2 deletions

View File

@ -36,4 +36,20 @@ describe('subscribePreviewEvents', () => {
attachments: [expect.objectContaining({ type: 'image', data: 'data:image/png;base64,AAAA' })],
}))
})
it('selection event resets pickerActive on the session', async () => {
useBrowserPanelStore.getState().open('s1', 'http://x/a')
useBrowserPanelStore.getState().setPicker('s1', true)
await subscribePreviewEvents('s1')
listeners['preview://event']!({ payload: JSON.stringify({ v: 1, type: 'selection', payload: { pageUrl: 'http://x/', element: { selector: '#t', tag: 'h1', classes: [] }, screenshot: { dataUrl: 'data:image/png;base64,AAAA', kind: 'element' } } }) })
expect(useBrowserPanelStore.getState().bySession['s1']!.pickerActive).toBe(false)
})
it('ignores a malformed selection payload without throwing but still resets picker', async () => {
useBrowserPanelStore.getState().open('s1', 'http://x/a')
useBrowserPanelStore.getState().setPicker('s1', true)
await subscribePreviewEvents('s1')
expect(() => listeners['preview://event']!({ payload: JSON.stringify({ v: 1, type: 'selection', payload: { pageUrl: 'http://x/' } }) })).not.toThrow()
expect(useBrowserPanelStore.getState().bySession['s1']!.pickerActive).toBe(false)
})
})

View File

@ -22,8 +22,11 @@ export async function subscribePreviewEvents(sessionId: string): Promise<() => v
attachments: [{ type: 'image', name: `screenshot-${kindLabel(msg.kind)}.png`, mimeType: 'image/png', data: msg.dataUrl }],
})
}
else if (msg.type === 'selection' && msg.payload) {
const p = msg.payload as SelectionPayload & { screenshot?: { dataUrl?: string; kind?: string } }
else if (msg.type === 'selection') {
// 选区事件意味着页面侧已结束一次性拾取——同步关闭宿主侧 picker 态,避免按钮卡在按下态
store.setPicker(sessionId, false)
const p = msg.payload as (SelectionPayload & { screenshot?: { dataUrl?: string; kind?: string } }) | undefined
if (!p || typeof p !== 'object' || !p.element) return
useChatStore.getState().queueComposerPrefill(sessionId, {
text: buildSelectionComposerText(p),
attachments: p.screenshot?.dataUrl
@ -31,5 +34,8 @@ export async function subscribePreviewEvents(sessionId: string): Promise<() => v
: [],
})
}
else if (msg.type === 'error') {
console.warn('[preview-agent]', msg)
}
})
}