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:
mesalogo
2026-09-02 16:35:51 +08:00
parent 4d9ab72778
commit 42cbfa43f1
15 changed files with 243 additions and 19 deletions
+5
View File
@@ -254,6 +254,11 @@ const desktopApi: DesktopApi = {
return () => ipcRenderer.removeListener(ipcChannels.settingsOpen, handler)
}
},
clipboard: {
writeText: async (text: string) => {
await ipcRenderer.invoke(ipcChannels.clipboardWriteText, text)
}
},
agent: {
getStatus: (selection) =>
ipcRenderer.invoke(
+14
View File
@@ -21,6 +21,20 @@ describe('sandboxed preload', () => {
expect(source).not.toMatch(/\bfrom\s+['"]zod['"]/u)
})
it('exposes only explicit clipboard text writing', () => {
const source = readFileSync(
join(process.cwd(), 'src', 'preload', 'index.ts'),
'utf8'
)
const clipboard =
source.match(
/clipboard: \{(?<body>[\s\S]*?)\r?\n {2}\},\r?\n {2}agent:/u
)?.groups?.body ?? ''
expect(clipboard).toContain('writeText: async (text: string)')
expect(clipboard).toContain('ipcChannels.clipboardWriteText')
expect(clipboard).not.toMatch(/\b(?:read|image|html|rtf|bookmark)\b/iu)
})
it('exposes only narrow browser-control methods', () => {
const source = readFileSync(
join(process.cwd(), 'src', 'preload', 'index.ts'),