feat(desktop): add library clipboardWrite PNG bitmap op - #3923
Conversation
Plugins already send library-request clipboardWrite; the host whitelist rejected it as PATH_INVALID. Add the op as a PNG bitmap write via nativeImage + clipboard.writeImage, not saveAs/reveal or the media:copy-to-clipboard file-reference path. Signed-off-by: PraiseZhu <zhuzan@xd.com>
|
| Filename | Overview |
|---|---|
| apps/desktop/src/shared/ghost.ts | 扩展 library 协议和响应类型,但新增剪贴板能力复用了不含逐操作授权的既有 library 权限。 |
| apps/desktop/src/main/cindy-brain/librarySlot.ts | 实现输入校验、限流、会话检查和依赖调用,但会将生产依赖的“不支持”异常统一映射为内部故障。 |
| apps/desktop/src/main/cindy-brain/index.ts | 接入 Electron 位图剪贴板,并在没有可见主壳窗口时抛错,导致实际错误码偏离协议。 |
| apps/desktop/src/main/cindy-brain/tests/librarySlot.test.ts | 覆盖主要成功、校验、限流和会话失效路径,但未覆盖生产接线的无窗口错误映射。 |
| apps/desktop/src/main/cindy-brain/forge.ts | 记录新增协议及失败语义,其中无主壳窗口的 UNSUPPORTED 承诺与实现不一致。 |
Sequence Diagram
sequenceDiagram
participant P as 插件
participant H as Library 管道
participant S as GhostLibrarySlot
participant E as Electron 主进程
participant C as 系统剪贴板
P->>H: library-request clipboardWrite
H->>H: 校验整体 library 权限
H->>S: handleLibraryRequest
S->>S: 校验 Base64、大小、PNG 签名与限流
S->>E: writeClipboardPng(bytes)
E->>E: nativeImage.createFromBuffer
E->>C: clipboard.writeImage
C-->>P: "{ok:true, bytes}"
Prompt To Fix All With AI
### Issue 1
apps/desktop/src/shared/ghost.ts:8251
**既有插件静默扩权**
将 `clipboardWrite` 加入通用 library 操作白名单后,任何已安装且已获 `library: true` 批准的插件都会自动获得写系统剪贴板的能力。library 请求只检查整体权限和操作白名单,而批准指纹与权限说明都不记录具体操作,因此升级后不会触发重新确认,用户也不会得知这项新增权限。应将剪贴板写入设为独立权限,或让这次权限变化使既有批准失效。
**How this was verified:** library 请求只检查整体 `manifest.library` 权限和操作白名单,而批准指纹不记录 library 内的具体操作。
### Issue 2
apps/desktop/src/main/cindy-brain/index.ts:5281-5283
**无窗口错误码不符**
当所有主壳窗口均隐藏或最小化时,这里会抛出普通异常,随后被 `librarySlot` 统一转换为 `INTERNAL`。但新增协议明确承诺无主壳窗口时返回 `UNSUPPORTED`,因此插件无法按文档区分宿主当前不支持写入与真正的内部故障。请让该条件返回 `UNSUPPORTED`,或同步修正协议并覆盖生产接线的这一分支。
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "feat(desktop): add library clipboardWrit..." | Re-trigger Greptile
v1 review: Buffer.from accepted bad padding, and isPngBuffer only checked the 8-byte magic, so truncated PNG still reached writeClipboardPng. Decode strictly and require a full IHDR header. Signed-off-by: PraiseZhu <zhuzan@xd.com>
v1 follow-up: a 24-byte signature+IHDR prefix is still truncated. Accept only a full IHDR chunk plus IEND, and use a real 1x1 PNG fixture. Signed-off-by: PraiseZhu <zhuzan@xd.com>
includes('IEND') accepted truncated images with the ASCII marker
embedded mid-file. Parse length+type+data+crc, CRC-check IHDR, and
require IEND as the final chunk with no trailing bytes.
Signed-off-by: PraiseZhu <zhuzan@xd.com>
|
@PraiseZhu 👋 这个 PR 还有 2 条 review conversation 没 resolve(apps/desktop/src/shared/ghost.ts / apps/desktop/src/main/cindy-brain/index.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。 如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。 |
|
这条 PR 改到了插件基座(Library 确认方式:维护者直接在本 PR 上 Approve;若要改,请 Request Changes,作者改完后再 Approve 即放行。 讨论 issue:#3924 |
7bfdd94 to
922ce17
Compare
MagicLizi
left a comment
There was a problem hiding this comment.
审查发现 P1 ×1,请在当前 head 上修复后再请求 review。
- [P1] apps/desktop/src/main/cindy-brain/librarySlot.ts:746 / apps/desktop/src/main/cindy-brain/index.ts:5281 — 协议与实现不一致:FORGE_GUIDE 承诺无主壳窗 / 宿主不能写剪贴板返回
UNSUPPORTED,生产接线在无可见主壳窗时抛没有可挂靠的宿主窗口,clipboardWrite的catch一律折成INTERNAL。Desktop 生产始终注入writeClipboardPng,因此真实无窗路径永远是INTERNAL。issue #3924 第 2 条明确要求统一错误码并补生产注入测试。请把该窗口条件(及可识别的不支持)映射为UNSUPPORTED,仅真正异常走INTERNAL;加一条覆盖生产注入函数的测试(无可见主壳窗 →UNSUPPORTED)。
FORGE_GUIDE promises UNSUPPORTED when no main shell window can host clipboardWrite. Catch the production '没有可挂靠的宿主窗口' error instead of collapsing it into INTERNAL. Signed-off-by: PraiseZhu <zhuzan@xd.com>
|
@MagicLizi P1 已在当前 head 生产接线仍在无可见主壳窗时抛 |
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
审查未通过(P1×1)。Library 新增无对话框的系统剪贴板写入,插件详情能力文案未同步。
- [P1] apps/desktop/src/shared/ghost.ts:2087 — Host 给
library: true新增无确认框的系统剪贴板写入(librarySlot.tsclipboardWrite),但详情能力文案libraryPersistDetail仍只写「系统文件夹显示 / 另存为」,五语均未改。ghost.ts已要求详情页讲清 Library 的系统侧副作用;plugin-security-and-authoring.md§3 要求能力在详情如实展示;plugin-library-storage.mdReview 清单第 4 条要求 i18n 五语同步。已声明 Library 的存量插件升级后会自动获得覆盖系统剪贴板的能力,用户在插件详情看不到。请五语libraryPersistDetail补上 PNG 位图写剪贴板(无确认框、会覆盖当前剪贴板),并同步ghost.ts注释。改完跑pnpm check:i18n与pnpm check:i18n-glossary。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
P1:Host 给已声明 library: true 的插件新增无确认框的系统剪贴板 PNG 写入(librarySlot.ts 的 clipboardWrite → clipboard.writeImage),但用户可见的插件详情能力文案未同步。
ghost.ts 仍走 detailKey: 'libraryPersistDetail';五语 libraryPersistDetail 只写系统文件夹显示与另存为,没有「可把 PNG 写入系统剪贴板、无确认框、会覆盖当前剪贴板」。plugin-security-and-authoring.md §3 与 plugin-library-storage.md Review 清单要求详情如实展示。FORGE_GUIDE 已写该 op,详情页没有。
请五语补上该副作用,并改 ghost.ts 对应注释。不要求拆独立权限或让旧批准失效(那会违反存量兼容红线)。
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
Plugin details for library:true only mentioned Finder/Explorer and Save As. Host already writes PNG bitmaps to the system clipboard without a confirm dialog, so the five-locale copy and ghost.ts comment now say so. Signed-off-by: PraiseZhu <zhuzan@xd.com>
MagicLizi
left a comment
There was a problem hiding this comment.
独立审查未通过(P1×1)。
- apps/desktop/src/shared/ghost.ts:2087 — Host 给已声明
library: true的插件新增无确认框的系统剪贴板 PNG 写入(clipboardWrite→clipboard.writeImage),但插件详情仍走detailKey: 'libraryPersistDetail'。五语文案只写系统文件夹显示与另存为,没有「可把 PNG 写入系统剪贴板、无确认框、会覆盖当前剪贴板」。注释也未覆盖新副作用。按 plugin-security-and-authoring.md §3 与 plugin-library-storage.md Review 清单第 4 条,五语libraryPersistDetail必须补上该副作用(不要拆独立权限,以免违反存量兼容红线)。改完跑pnpm check:i18n与pnpm check:i18n-glossary。
|
@MagicLizi P1 已在当前 head
对应 CHANGES_REQUESTED:#3923 (review) (以及先前同口径的 5120398435)。请再审;本条不 merge。 |
这些问题已在当前 head 的后续 commit 中修复(格式门/安全门已通过),自动 dismiss 旧的 CHANGES_REQUESTED 以解除合并阻塞。
MagicLizi
left a comment
There was a problem hiding this comment.
代码重审通过:当前 head 未发现 P0/P1。PNG 位图写入系统剪贴板走 library 管子,无主壳窗映射为 UNSUPPORTED,插件详情已写明会覆盖剪贴板。全部 conversation 已 resolve。
|
合了。插件把 PNG 写进系统剪贴板这条管子现在能走通,详情页也说清楚了会覆盖当前剪贴板。 |
这次改了什么
摘要
插件已经在发
library-requestop=clipboardWrite,宿主白名单没有这个 op,一律PATH_INVALID。本 PR 在 Cindy 宿主加上 PNG 位图写口:只收encoding:'base64'的 PNG 字节,经nativeImage.createFromBuffer+clipboard.writeImage写入系统剪贴板,成功回{ok:true, op:'clipboardWrite', bytes}。不是 saveAs/reveal,也不复用media:copy-to-clipboard的文件引用通道。#3626 是另存为/显示,不是本 PR。变更类型
feat新功能fix缺陷修复refactor/perf重构或性能优化docs/test/chore文档、测试或工程维护范围
GHOST_LIBRARY_OPS增加clipboardWrite;GhostLibrarySlot分派与校验;getGhostLibrarySlot注入 PNG 位图写剪贴板;FORGE_GUIDE 协议说明;librarySlot 单测media:copy-to-clipboard文件引用粘贴UI 变化
怎么验证的
自动验证
手工验证
不涉及本机外部应用粘贴实测(e2e worker 按源码与单测验收)。外部粘贴仍由操作系统与目标应用决定。
未执行的验证
无主壳窗时的实机剪贴板失败路径未在本机 GUI 复现,由单测与接线覆盖。
风险
风险分类
影响与回滚
clipboardWrite;空字节 / 非 base64 / 非 PNG / 超限结构化失败;无主壳窗失败关闭;账号切换后旧会话不得继续写。存量未声明该 op 的插件不受影响。PATH_INVALID。提交前检查
git commit -s,见 DCO)