feat: add copy action to AI responses
Completed AI responses now expose a bottom copy action that copies their Markdown source without reasoning, tool logs, or citation metadata. Clipboard writes use a validated Preload/Main bridge so sandboxed Electron sessions no longer fail with a renderer clipboard permission error; full-conversation copy uses the same path. Release note: AI 回复底部现在可以直接复制 Markdown 原文,并修复了沙箱环境下回复和完整会话可能无法写入剪贴板的问题。
This commit is contained in:
+28
-1
@@ -242,6 +242,29 @@ describe('terminal IPC boundary', () => {
|
||||
snapshot.sessionId
|
||||
)
|
||||
|
||||
electronMocks.handlers.get(ipcChannels.clipboardWriteText)?.(
|
||||
event,
|
||||
'## Copied response'
|
||||
)
|
||||
expect(electronMocks.writeClipboardText).toHaveBeenCalledWith(
|
||||
'## Copied response'
|
||||
)
|
||||
expect(() =>
|
||||
electronMocks.handlers.get(ipcChannels.clipboardWriteText)?.(
|
||||
event,
|
||||
{ text: 'invalid' }
|
||||
)
|
||||
).toThrow()
|
||||
expect(() =>
|
||||
electronMocks.handlers.get(ipcChannels.clipboardWriteText)?.(
|
||||
{
|
||||
sender: { ...webContents, id: 99 },
|
||||
senderFrame: webContents.mainFrame
|
||||
},
|
||||
'untrusted'
|
||||
)
|
||||
).toThrow('拒绝来自未知窗口的 IPC 请求')
|
||||
|
||||
expect(() =>
|
||||
electronMocks.handlers.get(ipcChannels.terminalWrite)?.(
|
||||
{
|
||||
@@ -295,7 +318,8 @@ const electronMocks = vi.hoisted(() => {
|
||||
})),
|
||||
openPath: vi.fn(async () => ''),
|
||||
showItemInFolder: vi.fn(),
|
||||
openExternal: vi.fn(async () => undefined)
|
||||
openExternal: vi.fn(async () => undefined),
|
||||
writeClipboardText: vi.fn()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1106,6 +1130,9 @@ vi.mock('electron', () => ({
|
||||
getVersion: vi.fn(() => '0.1.0')
|
||||
},
|
||||
BrowserWindow: class {},
|
||||
clipboard: {
|
||||
writeText: electronMocks.writeClipboardText
|
||||
},
|
||||
dialog: {
|
||||
showOpenDialog: electronMocks.showOpenDialog,
|
||||
showSaveDialog: electronMocks.showSaveDialog
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
clipboard,
|
||||
dialog,
|
||||
ipcMain,
|
||||
shell
|
||||
@@ -31,6 +32,7 @@ import {
|
||||
browserReloadRequestSchema,
|
||||
browserStopLoadingRequestSchema,
|
||||
browserStopRequestSchema,
|
||||
clipboardTextSchema,
|
||||
conversationQueueUserInputSchema,
|
||||
defaultRuntimeSettings,
|
||||
knowledgeCreateSchema,
|
||||
@@ -3298,6 +3300,11 @@ export function registerIpcHandlers(
|
||||
}
|
||||
})
|
||||
|
||||
registerHandler(ipcChannels.clipboardWriteText, (event, input) => {
|
||||
assertTrustedSender(event, window)
|
||||
clipboard.writeText(clipboardTextSchema.parse(input))
|
||||
})
|
||||
|
||||
registerHandler(
|
||||
ipcChannels.appRendererPersistenceReady,
|
||||
(event) => {
|
||||
|
||||
Reference in New Issue
Block a user