tabby-clipboard-image
v0.1.1
Published
Tabby plugin: paste a clipboard image into an SSH session as a native AI-client attachment or as a quoted remote path
Maintainers
Readme
tabby-clipboard-image
English · 简体中文
一个 Tabby 桌面端插件:当本地剪贴板里是图片时,显式粘贴会在当前 SSH pane 中变成 AI 客户端的原生附件 或 带引号的远程文件路径。普通文本粘贴完全保持 Tabby 原有行为。
不需要任何远端组件。 两种模式都只要求一个具备 SFTP 的 SSH 账户。
需要 Tabby 桌面版 1.0.230 或更高。不支持 Tabby 网页版:读取图片剪贴板是桌面端(Electron)能力。
两种粘贴模式
| 模式 | 做什么 | 远端 CLI 看到什么 |
| --- | --- | --- |
| 原生附件(默认) | 通过 SFTP 上传 PNG,再把它的绝对路径以 bracketed paste 送入 pane。 | 客户端自己的附件占位符,作为图片内容发送。输入框里不出现路径。 |
| 远程路径 | 通过 SFTP 上传 PNG,再把最终路径加双引号、以普通按键输入送入 pane。 | 一个带引号的绝对路径,由它自己读取 —— 这通常意味着一次 Read(image) 工具调用。 |
两者只在投递方式上不同,而这个差别就是全部机制所在。对 Claude Code 2.1.237 实测:
| 投递方式 | 输入框结果 |
| --- | --- |
| ESC [ 200 ~ "/abs/x.png" ESC [ 201 ~ | [Image #1] |
| 同一路径按普通按键输入 | 路径本身,纯文本 |
能识别「粘贴进来的图片路径」的 AI 客户端会自己读取该文件并渲染自己的占位符。它要求路径是绝对路径,且扩展名为 .png、.jpg、.jpeg、.gif 或 .webp;两端的引号由客户端自行剥除。
原生附件绝不会静默降级为远程路径。降级是显式开关,且开启时会在上传之前告知你附件语义已改变。
为什么不去拦截远端剪贴板
早先的设计是在远端为 pbpaste / xclip / wl-paste 装 shim,让 AI 客户端从假剪贴板里读到图片。这条路走不通:Claude Code 通过一个进程内读取器读剪贴板,只有该读取器不可用时才回退到调用那些命令 —— 读取器加载成功、只是报告「无图片」时会直接返回,shim 根本不会被调用。bracketed paste 没有这个依赖。
安装
从 npm 装到 Tabby 的插件目录:
# Windows
cd %APPDATA%\tabby\plugins
npm install --no-save tabby-clipboard-image
# macOS
cd ~/Library/Application\ Support/tabby/plugins
npm install --no-save tabby-clipboard-image
# Linux
cd ~/.config/tabby/plugins
npm install --no-save tabby-clipboard-image从本地构建安装:
npm install
npm run verify # 类型检查、测试、生产构建、外部依赖检查
npm pack # 产出 tabby-clipboard-image-<version>.tgz
cd <Tabby 插件目录>
npm install --no-save /path/to/tabby-clipboard-image-<version>.tgz重启 Tabby。安装后插件即为启用状态,默认选中原生附件、降级关闭、通知开启、上传目录为 /tmp —— 不需要手改配置文件。
原生附件还要求 Tabby 自身的 设置 → 终端 → Bracketed paste 保持开启(默认开启)。关闭时插件会明确拒绝,而不是送出一段前台程序会显示成乱码的转义序列。
卸载
cd <Tabby 插件目录>
npm uninstall tabby-clipboard-image
# 或直接删除 node_modules/tabby-clipboard-image 目录重启 Tabby。插件在卸载时会还原每个终端原本的 paste(),因此粘贴行为完全回到安装前。可以顺手删掉 Tabby config.yaml 里的 clipboardImage 段;留着也无妨。
已上传的文件不会在卸载时删除 —— 它们是上传目录里的普通文件,有意留下,好让前台程序有时间读取。
设置
Tabby → 设置 → 剪贴板图片:
- 启用图片粘贴 —— 关闭时,粘贴行为与未安装插件时完全一致。
- 粘贴模式 —— 原生附件 或 远程路径。
- 降级到远程路径 —— 默认关闭。
- 显示通知 —— 控制成功与失败通知。失败无论如何都会记入日志。
- 高级 → 远程上传目录 —— 两种模式都使用,必须是绝对路径。上传的文件权限为
0600,因此像/tmp这样的共享目录只会暴露文件名,不会暴露图片内容。 - 高级 → 详细诊断日志 —— 脱敏进度信息。绝不包含图片数据、Base64、剪贴板文本或凭据。
改动对下一次粘贴生效,不需要重装,重启后设置仍保留。
粘贴是怎么被接管的
插件通过 Tabby 的终端装饰扩展点,包装每个终端的 paste() 方法。所有粘贴入口 —— 快捷键、标签页右键菜单、右键、中键 —— 都汇聚到这一个方法,所以一个包装就覆盖全部入口,也只有一处实现需要推理。这里刻意不使用全局快捷键流:它无法消费 Tabby 自己的粘贴订阅者,那会导致原本的文本粘贴与图片路径并行发生。
一次图片粘贴会一次性快照当前 pane、它的 SSH 会话,以及它的 bracketed paste 能力。上传、通知和终端输入都使用这份快照,因此操作过程中切换标签页或 pane 不会把结果投递到错误的 pane;前台程序在上传途中关闭 bracketed paste 也不会改变本次判定。
限制与已知行为
- 接受最大 20 MiB 的图片;更大的在任何远端操作之前就被拒绝。
- 两种模式都要求 SSH pane。在本地终端上,原生附件会把粘贴原样交回 Tabby;远程路径则以明确的 SFTP 不可用错误失败,而不是假装上传成功。
- 原生附件要求前台程序已启用 bracketed paste。shell 提示符通常是开启的,但它只会把带引号的路径当作命令参数收下;只有能识别粘贴图片路径的 AI 客户端才会产生附件。
- 「成功」的含义是路径已上传并已粘贴,并不声称下游 Gateway 接受了由此产生的消息。
- 原生附件在 v1 只覆盖 Claude Code。不声称支持 OpenCode 或其他 AI 客户端。
- 上传的文件在粘贴后不会被删除,插件也不附带远端临时文件回收器。这里使用的 SFTP 接口没有目录列举能力,因此插件无法枚举自己留下的文件。
- Windows Tabby 端到端行为与 Gateway 请求体验证属于用户负责的验证项,见
docs/acceptance.md。
开发
npm run typecheck
npm test
npm run build
npm run verify测试在被装饰的终端 paste() 这个接缝上断言外部行为,剪贴板、终端与 SSH/SFTP 均用可注入的假实现。npm run build 还会校验 Tabby、Angular 与 Electron 模块保持为构建外部依赖,未被打进产物。
许可
MIT。
