img-share Skill
把浏览器截图或本地图片变成聊天框内的可点大图(缩略图+点击看原图),并且手机/其他设备也能访问。跨平台(Linux/macOS/WSL/Windows 原生均可用)。
whenToUse(何时触发)
- 用户要"打开某个网站/页面截图给我";
- 把某张图贴到聊天框,且希望"手机也能看、能点开放大看细节";
- 想把工作区图片做成可点大图的聊天内嵌图。
依赖
| 依赖 | 用途 | 获取 |
|---|---|---|
| web-access skill | 截图(CDP 驱动浏览器) | 需装:https://github.com/eze-is/web-access |
| python3/python | 编排器(serve.py) | 系统自带 |
| cloudflared | 兜底公网隧道 | mac: brew install cloudflared;win: winget install Cloudflare.cloudflared;linux: 见其官方 README;或设 CLOUDFLARED=/路径 |
| ffmpeg(可选) | 多图拼网格 | 系统安装(scripts/montage.sh 用) |
执行步骤
-
宿主可达性判定(必选,最先做) —— 决定图片 URL 的基址,以及是否需要另开公网隧道。图片地址必须跟随宿主地址,不要为了"能跑通"就擅自另开一条与宿主不同源的隧道:
判定 结论(行动) 宿主已被隧道化/公网可达(用户手机正是通过该地址访问本会话),且宿主暴露了静态图片路径(如 /img/*)图片放进宿主静态目录,内嵌用 宿主公网地址,不开新隧道 宿主公网可达,但未暴露静态图片路径 不静默兜底:先告诉用户"需给宿主配置静态图片映射";仅当用户知情同意后才走"显式独立隧道兜底" 宿主仅 localhost(如 DSH_WEB_URL=http://127.0.0.1:*,未开公网)图片只有本机/局域网地址,手机本来也到不了本会话 —— 先提示用户把 DSH 开成公网,或经用户同意走显式兜底;禁止把 localhost/127.0.0.1 地址内嵌并宣称手机可看 探测不到 / 不确定 不猜测,先问用户:"你手机访问本会话用的是哪个地址(公网域名还是 localhost)?" 再按上表执行 探测方式:读环境变量(
DSH_WEB_URL、DSH_PUBLIC_BASE、DSH_IMG_BASE等)、查宿主静态路由配置;取不到即视为"宿主未提供",按上表走"问用户/提示",不得静默降级为另开隧道。宿主契约(前瞻约定,当前 DSH 宿主尚未提供):宿主若暴露
DSH_PUBLIC_BASE/DSH_IMG_BASE或等价的静态路径声明,agent 必须优先把图片挂到宿主域名下;未提供时不要假设存在。 -
截图(如需):用 web-access skill,
/screenshot渲染页面成 PNG。- 若 CDP/Chromium 在受限环境跑不起来(禁联网/进程崩溃),降级到云端截图:用 thum.io / mshots / microlink 等,带
?wait=N&width=W,返回后校验"非白像素占比>阈值、色簇数>N",不是空白才可用。
- 若 CDP/Chromium 在受限环境跑不起来(禁联网/进程崩溃),降级到云端截图:用 thum.io / mshots / microlink 等,带
-
存图:放到工作区(如
img/x.png,文件名用 ASCII/无空格)。 -
分享(按第 0 步结论,二选一):
- 宿主路径(第 0 步判定为可复用宿主时):把图片放到宿主暴露的静态目录,内嵌
https://<宿主域名>/img/x.png;不要开独立隧道。 - 显式兜底(第 0 步判定为需兜底且用户同意时):只分享这一个文件,不开整个目录;起图库[仅回环]+公网隧道,端到端校验,输出 PUBLIC_BASE:
bash <skill>/scripts/setup.sh <img>/x.png # Unix/WSL python <skill>/scripts/serve.py --share <img>/x.png # Windows 原生
- 宿主路径(第 0 步判定为可复用宿主时):把图片放到宿主暴露的静态目录,内嵌
-
回复里内嵌(缩略图=原图 URL,点击开原图全屏):
[](https://<基址>/x.png)基址必须是第 0 步判定的结果(宿主公网地址,或用户知情同意的显式隧道地址);禁止 embed localhost/127.0.0.1 并声称手机可看。告知用户:聊天框显缩略图,点击开原图;手机用同一公网地址也可访问(已验证 DSH 能渲染公网 markdown 图片)。
-
分享完毕→撤隧道(显式兜底场景,避免长期公开):
bash <skill>/scripts/teardown.sh # 停图库+隧道+清理
失败处理
- 宿主可达性无法判定:不猜、不静默另开隧道;先问用户手机访问本会话所用的地址(见第 0 步)。
- 宿主公网但无静态图片路径:提示用户配置静态映射,或征得同意后走显式兜底,并说明该隧道与宿主不同源。
- 缺依赖:serve.py 报"缺 cloudflared/python",按提示装或设
CLOUDFLARED;截图缺 web-access 则走云端截图(见上)或让用户传图。 - 端口被占:serve.py 自动选空闲端口。
- 隧道域名取不到(网络慢/断连 Cloudflare):serve.py 轮询重试;仍失败则告知"网络无法建隧道",回退为仅本机/局域网(给本机地址,并说明手机场景需先让宿主/服务公网可达)。
- 端到端校验失败:serve.py 会 curl 真实文件名校验(200 才成功),失败即撤,避免"看似 live 实则 404"。
- 域名漂移:快捷隧道重启换域名,旧内嵌 URL 失效;宿主路径无此问题;兜底场景长期稳定用命名隧道/固定域名。
环境自检(Agent 先做)
开始前先探测:能否出网(curl 一个公网地址)、能否spawn 浏览器进程(CDP)、宿主是否为公网可达(见第 0 步)。出网/CDP 都不行 → 走云端截图 + 提示需要更高权限,不要直接给用户一个"看起来能但实际裂"的图。
安全(默认动作,非提醒)
- 只分享指定文件:serve.py 把要分享的文件拷进随机命名子目录再起服务,绝不开整个 img/ 目录(否则隧道 URL 能列出/下载该目录所有文件);宿主静态目录同理只放要分享的文件。
- 图库仅绑定 127.0.0.1(局域网不能直连);公网隧道 URL 无鉴权——分享完立即 teardown。
- 想更严:给 URL 加随机 token / 用短时隧道;别放敏感图。
- 别把所有图都放公网:只让"本次要分享的那一张/几张"出现在可公开访问的目录/隧道中。
宿主隧道优先(判定见执行步骤第 0 步)
- 图地址跟随宿主地址:宿主已被隧道化/公网化时,图片应挂在宿主同一域名(如静态
/img/*路径)下——用户手机上打开会话即能加载,无需、也不应另开一条与宿主不同源的临时隧道。 - 若宿主通过 dsh-trust-proxy 等暴露了
/img/静态规则,图片 URL 形如https://<DSH域名>/img/x.png,跨设备、免多开隧道。 - serve.py 的独立 cloudflared 隧道只是可移植兜底(任何机器都能跑):仅在第 0 步判定"宿主不可公网复用"且用户知情同意后使用,并明确告知其局限(与宿主不同源、快捷隧道重启即换域名)。
边界
- 进程要常驻/可撤:serve.py 记录 PID 供 teardown;DSH 会话里服务需跨会话(可用托管后台 + teardown 明确清理)。
- 文件名:用 ASCII、无空格;脚本对文件存在做校验,中文/空格由 URL 编码处理,但建议避免。
- 工作区不同:不同会话工作区不同,按该会话路径分享;serve.py 用系统临时目录,不依赖工作区。