Repository navigation
Releases: q253595422/dsh-imagegen-video
Release list
v1.10.0
v1.10.0 · 分镜:一列镜头,各出一段视频
各版本改动见 CHANGELOG.md。
本版在无限画布上加了一个分镜节点,并把「上一镜接着下一镜」做成画布上的一等操作。
它没有另起一套工作流:每一镜的成品就是一个普通的视频节点,预览、下载、收藏、重试和拼接
都还是原来那条链路。
分镜
- 一个节点就是一列镜头。 每镜一条提示词、一个时长,可以加、删、上下移动;列表顺序
就是片序。「每镜独立」一次把还没有视频的镜头全部提交;「接上一镜尾帧」一次跑一镜,
用上一镜的最后一帧当这一镜的第一帧,镜头之间才真正接得上。 - 接不上的时候会说出来。 选了「接上一镜尾帧」而上一镜还没出片时,这一镜的生成按钮
是禁用的,不会提交一个悄悄退化成纯文本生成的请求。 - 每一镜的状态来自它自己的视频节点。 已完成、生成中、失败、还没生成四种状态都读自
那张节点,所以分镜上看到的进度和画布上看到的片段永远一致;删掉片段,那一镜就回到
待生成,可以直接重来。
拼接
- 分镜自己会拼。 有两镜及以上出片后,「拼接全部镜头」把它们按镜头顺序交给现有的
compose 链路——同一张 ①②③ 顺序确认卡、同一个本机 ffmpeg。还在生成的镜头不会被塞进
去,界面会说明少了几镜,而不是提交一次注定失败的拼接。
画布
- 取尾帧续拍。 任意已完成的片段都可以一键取结尾帧:生成一张图片节点,并接好一个
新的视频配置节点,直接写下一镜的描述就能接着拍。这是分镜衔接的手动版,用的还是画布
上原有的抓帧与生成。 - 刷新不丢。 镜头列表、画布共享的画幅与分辨率、每一镜和它片段节点的对应关系都存在
画布文档里;重开画布照旧。文档里存了无法兑现的镜头数据时,保存会明确失败,而不是写进
去一份半坏的文档。 - 编辑走文档。 在分镜里改提示词、调顺序,和其他节点一样支持撤销、重做与自动保存。
已知边界
- 分镜的镜头数上限为 40。超过上限的文档会被拒绝保存。
- 「接上一镜尾帧」依赖浏览器能解码上一镜的结尾帧;片段文件被清理掉时无法续拍,会给出
明确提示。 - 分镜不生成配乐、字幕或转场,只负责把镜头跑出来并拼成一条片子。
v1.9.3
v1.9.3 · 会话图片、PPT 交付与 xAI Grok 视频
各版本改动见 CHANGELOG.md。
本版把上游 1.9.1 与 1.9.2 的 PPT 交付改动合进来,并修掉本仓库自己的两处问题:
会话里的生图结果能显示图片了,「图片转 PPT」在窄栏下不再被挤出屏幕,Grok 视频接上了官方接口。
PPT 转换
- 宿主错误不再被「未输出最终 PPTX」掩盖。 模型或执行失败时保留具体错误并脱敏,
没有回复时提示检查默认模型连接与工具配置。 - 接收上游 skill 自己 final 目录里的最终 PPTX。 只接受完成记录加通过的校验报告,
继续检查 PPTX 结构与页数;中间页文件不会被当成成功结果。 - 配置改为页内弹窗,复用生图配置里的同一组字段,不再依赖宿主设置按钮的 DOM 查找;
支持 Escape、焦点约束与返回原按钮。 - 上传后是缩略图网格加「+」卡片,可点击预览、移动顺序、删除;顺序即幻灯片顺序。
- 结果区只展示最终 PPTX。 左右两栏:左边图片与参数,右边自动打开内容预览,
支持缩略图翻页、上一页/下一页、放大与下载;窄屏改单列,图片列表独立滚动。
新增任务诊断入口,预览失败可重试且仍可下载文件。复杂版式以 PowerPoint 为准。
会话与画布
- 会话中的生图工具读取 DSH 持久化的结果 metadata,文生图、图生图与任务查询返回的
图片都能显示缩略图并打开原图;旧会话里的图片内容块与 JSON 引用仍然兼容,重复附件只显示一次。
图片只作界面展示,发给模型的内容仍是文本。 - 修复 PPT 首条消息的
format v4 message requires a producer-owned source kind:
改用plugin:dsh-imagegen,不再用被 DSH v4 拒绝的旧 plugin 包装;无限画布里的重型 skill 同样生效。
视频
- Grok 视频接入官方协议。 新增
xai家族:提交到/v1/videos/generations读request_id,
轮询/v1/videos/{request_id}读video.url与video.duration,failed与expired都按失败报告。
请求体按官方约定发送数字duration、小写resolution与image: { url }。
xai-grok预设自带grok-imagine-video-1.5与-lite两个视频模型。
其它
- 窄栏布局不再被挤出屏幕。 中间列很窄时对话区按内容收缩,工作室整体滚动,
配置栏不再撑破布局;生成按钮与画布都可达。 - Windows 桌面宿主的在线更新改走宿主安装接口,安装结果逐项核对,不接受「看起来成功」。
验证
类型检查、构建与 93 项离线检查通过,另有反向验证确认每处守卫被改回时对应检查会变红。
PPT 工作区的真实浏览器检查(pnpm run ppt:preview && pnpm run test:ppt-browser)需要 Playwright
与 Chromium,本机未安装时明确跳过并返回成功;等价的 jsdom 覆盖在 pnpm test 的 E1 里。
本环境没有用真实付费模型跑通整份多页转换,转换质量仍取决于输入图片、OCR 与模型能力。
v1.9.0
v1.9.0 · 图片转可编辑 PPT
各版本改动见 CHANGELOG.md。
新增独立的「图片转 PPT」工作区:上传图片,每张图片对应一页幻灯片,转换结果为可编辑的 PPTX。
生图、图生图和对比结果里都多了一个「生成可编辑 PPT」入口,点一下就把图带进这个工作区。
主要更新
-
图片转 PPT 是独立工作区。 上传 PNG / JPG / WebP,最多 12 张、单张 20MB;
缩略图可以排序和删除,顺序就是幻灯片顺序。转换有真实状态:进行中、可取消、
完成可下载,输入图片保留下来可以再转一次。 -
结果页与对比页都能一键带入。 文生图、图生图结果、多模型对比结果以及放大预览
都加了「生成可编辑 PPT」,点击后带着这张图切到 PPT 工作区。 -
配置区新增 PPT 专区。 在「设置 → 生图配置」里:安装或更新官方技能、
安装并检查隔离的editpptPython 环境、配置图像 API 与 PaddleOCR token。
密钥沿用设置里的脱敏存储,不进入任务提示词。 -
OCR 两种方式可选。 PaddleOCR,或本次转换自带的离线文字检测。
-
失败是失败,不是空白。 没有产出 PPTX、ZIP 无效、页数对不上,都按失败报告;
宿主重启后未完成的任务显示为中断,可以重新发起。
前提
Python 3.10+;DSH 已配置默认模型,并启用技能与长任务;Agent 预设需要提供文件与命令工具。
多页转换按技能自己的方式跑页任务,需要预设支持子 Agent。PaddleOCR token 可选;
图像后端需要有效的 Codex OAuth 或兼容图像 API。
其他
- 画布顶部导航在窄屏(≤760px)下可横向滚动,标签不再被挤出屏幕外。
- 设置区在窄屏下允许换行,不再把摘要挤成一条。
验证
类型检查、构建与全部 187 项离线检查通过。新增的 C6c4 覆盖 PPT 三个路由的请求校验
(图片数量、asset id 的路径语法、OCR 方式必填)与拒绝时的原因说明;
撤回路由里的 asset id 校验后该检查确实变红。
尚未在真实付费模型上完整跑通一份多页转换——转换质量取决于输入图片、OCR 与模型能力。
v1.8.0
v1.8.0 · 图生图多参考、模板库改成抽屉、等待状态不再骗人
本仓库自己的发布说明。相对上游 v1.6.8 的完整改动见 CHANGELOG.md。
这一版吸收了上游 v1.8.0–v1.8.3 的四项能力,按文件逐个移植进来(两边历史没有
共同祖先,所以不是 merge)。移植完就是本仓库自己的代码,版本号也是本仓库的。
主要更新
-
图生图最多可以用 5 张参考图。
第一张走image,其余放进images——只认单张的渠道看到的仍然是一张图,
所有既有的请求形状不变。上限写在reference-images.ts一处:
5 张、单张 10 MiB、合计 16 MiB,面板支持多选、拖拽、粘贴、逐张删除、
方向键翻页预览,也支持从画廊「加入编辑」。
只吃一张的模型会在提交前就被拦下,并告诉你能用几张,
而不是把请求发出去、由上游悄悄截掉;对比模式下取所有目标里最严的那个。渠道 / 模型 上限 subscription、chat-completions 族 5 grok-imagine-image、nanobanana 系列、dall-e 1 qwen / minimax 且未配 apiUrlFull(modelscope 除外)1 其余 5 -
模板库从居中的弹窗改成右侧抽屉。
默认占工作区约 75% 宽度,宽度记在localStorage(0.55–1),
可以从左边缘拖动,也可以一键铺满;手机上(≤760px)全宽。
搜索覆盖全部模板源,最近用过的 24 条留在「历史记录」里一条点击就能再用。
选中的提示词可以替换输入框内容,也可以追加在后面。
上游顺手丢掉的两件事我们留下了:favorites: null仍然是「还没读到」,
所以读取失败显示的是未知状态的星和重试,而不是一整片「未收藏」;
源标签页仍然走共享的 roving tabindex,方向键能在标签之间移动。 -
等待状态改成点阵,并且每张卡说自己的话。
475 个点(对比模式下 130 个)的 SVG 点阵,只靠 CSS 的
animation-delay走波浪——没有计时器,也没有 React 更新。
多模型对比时每张卡有自己的点阵,耗时也各自从这张任务自己的
startedAt起算,四个模型不再共用一个误导的秒表。
失败与取消只停掉自己那张卡,prefers-reduced-motion下不动画。 -
结果图不再被裁掉。
结果网格从cover改成contain,配合零基准的 flex,
竖图和横图都能完整放进它拿到的那块空间,而不是切掉两边。
电商套图卡片保留cover覆盖——那条规则正是商品图不被加黑边的理由。 -
桌面端的更新:宿主能装就在线装,装不了就把命令给出来。
updateInstallTarget()现在分cli/host/host-managed三态。
宿主暴露了安装钩子,就用 Release 里那份 tgz 直接装,
装完核对application、退出码、包名与版本;老宿主不回版本号时回读
profile 下已装的package.json再核——核不到就是失败,绝不当作成功。
宿主不提供钩子时仍然抛ManualUpdateRequiredError,面板据此渲染一条
可复制的安装命令。 -
模板详情的主按钮不再改名字。
输入框里已经有内容时,上游会把按钮从「使用此提示词」改成「替换」;
我们两种情况都叫「使用此提示词」,有内容时另外给一个「添加」按钮。
主操作的含义不会因为旁边有没有字而变化。 -
顺带修掉两处,都是 1.7.8 那次发布暴露出来的。
发布任务靠回读 registry 证明「发布成功」,而那次回读比写入晚到了
3 分 16 秒,原来的 60 秒窗口把一次成功的发布报成了失败,还把人指向凭据。
窗口现在是 5 分钟,窗口耗尽时的报错也分成「我们发布了,npm 退出码 0」
与「这次运行没发布过」两句;verify-pack.mjs断言这个窗口必须大于 4 分钟,
反向套件用旧循环证明这条断言会变红。
另一处是 jsdom 的拆卸顺序:几何观察者是在微任务里被通知的,
旧代码先删全局再close(),于是稳定打印四行
ReferenceError: window is not defined,而套件仍然报绿。
兼容性
- 不新增运行时依赖,无配置变更,无需迁移。
localStorage新增两个键(最近用过的模板、抽屉宽度),缺失时用默认值,
不会影响旧数据。- 面板里的单图状态换成列表,只是内存中的表单状态,没有落盘格式变化;
历史、画廊、收藏、画布、渠道设置与视频记录都不受影响。 - 单张上限 10 MiB 在客户端与服务端都有;张数与合计 16 MiB 只由面板把关,
服务端只会截断。绕开面板直接调/api/dsh-imagegen/*时,这两条不生效。
安装
dsh plugin --profile web add https://github.com/q253595422/dsh-imagegen-video/releases/download/v1.8.0/q253595422-dsh-imagegen-video-1.8.0.tgz从本页的 tgz 附件安装:
dsh plugin --profile web add <下载路径>/q253595422-dsh-imagegen-video-1.8.0.tgz也可以从 npm 装:@q253595422/dsh-imagegen-video@1.8.0(由 CI 通过 GitHub
OIDC 发布,带 Sigstore provenance)。
安装后重启 dsh web。DSH Desktop 用户:桌面版插件目录由应用独占,
请在终端执行上面这条 dsh plugin ... add,或在「设置 → 插件」里直接安装这个文件。
验证
pnpm run typecheck通过;pnpm test全链通过——十一道离线检查:
verify-tracked、verify-reproducible、smoke、smoke-video、
smoke-canvas-video、smoke-video-picker、smoke-compose
(真实 ffmpeg,零跳过)、verify-b-defect、verify-video-layout、
verify-frame-grab、verify-ui-contracts。pnpm run test:negative把每处修复对应的缺陷注回仓库副本,要求对应检查变红。
本版新增的两条是:jsdom 先删全局再close()(稳定复现那四行
ReferenceError),以及 read-back 窗口退回 60 秒。参考图与抽屉的改动
由verify-ui-contracts的既有契约检查覆盖,没有为它们新增变异用例。- 本版新增一条门禁:版本号没有对应的
docs/releases/v<版本>.md时,
verify-pack.mjs直接失败;该文件不在包里也算失败(files里有docs/releases)。
起因就是这一版的发布说明漏了——release.yml会用那个文件当 Release 正文,
文件不在时只回落到 GitHub 自动生成的「Full Changelog」一行链接,
而且只打印一条没人会看的 warning。两条变异用例(改版本号但不写说明、
从files里删掉docs/releases)都实测变红。 - npm 发布走 GitHub OIDC、不带任何 token。发布任务在 publish 前会用
SHA256SUMS校验下载到的 tgz,所以 npm 上那份与 Release 附件是同一批字节;
1.8.0 也带 Sigstore provenance(npm 页面可见「Built and signed on
GitHub Actions」)。
已知边界(诚实说明)
- 模板抽屉的拖拽只有静态验证。 宽度记忆、左边缘拖拽、手机全宽都有类型检查
与契约检查背书,但没有真实指针拖拽的截图或端到端证据;
smoke.mjs里的模板断言跑在 jsdom 上,不带真实指针事件。 - 图生图的张数上限只在面板里。 见上文兼容性一节:服务端只截断。
- 本版没有改画布、视频、拼接的任何行为;那些链路的上一轮成果在 1.7.5–1.7.7。
- 上游 v1.8.0–v1.8.3 之外没有并入别的东西;也没有跟随上游之后的版本。
v1.7.8
v1.7.8
一个打包归属修正,没有行为变化。它属于「安装一次就能看出差别」的那类改动:
装 1.7.7 会多拉一份宿主已经提供的包,装 1.7.8 不会。
改了什么
@deepseek-ai/schemastery 从 dependencies 移到 peerDependencies。
它不是本插件的实现细节——它的 z 构建的是宿主拿去校验的配置 schema,
所以必须用宿主那一份。把它声明成依赖,等于每次安装都在宿主的副本旁边再拉
一份 @deepseek-ai/*,既是错误的归属关系,也正是插件目录收录规则里点名
禁止的事。
devDependencies 仍然保留它,本地的构建、tsc --noEmit 与整套离线检查
解析路径与之前完全一致;变的只有发布出去的清单。
为什么要单独发一版
1.7.7 已经从 npm 装出去了,它的清单里 schemastery 仍在 dependencies。
registry 上的版本不可改写,所以这个修正只能体现为新版本,不能声称它对
1.7.7 也成立。
验证
pnpm run typecheck、pnpm test(十一项离线检查)、pnpm run test:negative
全绿;版本号两处(package.json与src/protocol.ts的PLUGIN_VERSION)
由smoke.mjs断言一致。- 打包后装入隔离的
DSH_HOME:profile 解析到宿主自带的 schemastery,
lib/index.js正常导入。 - 本版同时用来验证一件事:
release.yml里那个默认关闭的 npm job,在配好
Trusted Publisher、并把仓库变量NPM_PUBLISH设为true之后,能否只靠
GitHub OIDC 把包发出去——不依赖任何存在本机的 npm token。
已知边界
- 这一版没有用户可见的功能变化。如果你已经装好 1.7.7 且不在意多一份
schemastery,可以跳过。 - 首次发布(1.7.7)走的是人工流程:npm 的 trusted publishing 只能挂在已存在
的包上。从 1.7.8 起才由 CI 发布。
v1.7.7
v1.7.7 · 删除变成可撤销,海报编辑器到位,更新链路不再说「失败了」了事
本仓库自己的发布说明。相对上游 v1.6.8 的完整改动见 CHANGELOG.md。
这一版修掉三个用户能直接撞上的问题,补上上游 v1.7.0 的海报编辑器,
并把发布这件事从「人手动打包」挪到「CI 跑完所有门禁再打包」。
主要更新
-
画廊删除不再销毁文件,30 天内可还原。
原先删除就是unlink,于是历史记录行、画布节点、已经打开的大图预览
里所有的 URL 一起变成破图,而且没有任何退路。
现在删除是软删除:条目打上deletedAt进回收站,文件原地不动;
只有「清空回收站」或超过保留期才会真正删除。
保留期是GALLERY_TRASH_RETENTION_MS= 30 天,
清理是惰性的——在mutateGallery里顺手做,
没有定时器、没有需要在退出时收尾的东西;
一个进程哪怕再也不会被打开,下一次启动的第一次存储调用也会把它清掉。
另外,把一张旧副本还在回收站里的图片重新加入,
结果是一条看得见的新条目,而不是静默的无操作。 -
海报编辑器(移植自上游 v1.7.0):图片节点上叠文字与 Logo。
全程本地 Canvas 2D 合成,不调用模型、不消耗额度,底图不被改写。
保存时把合成结果作为新图片节点上传,并把图层配方存进这个新节点的
metadata.poster(新节点与原节点相连)。
重新打开结果节点会还原每一层,而不是只剩一张压平的图。
弹层里的Ctrl+Z/Delete只作用于海报图层,不会误删画布下面的节点。
画布的资产清扫现在会把这层配方算作引用:成品节点自己只持有压平的合成图,
底图与 Logo 图层只存在于metadata.poster里,而编辑器每次打开都要读它们。
之前清扫只认metadata.asset,于是删掉任意一个画布就会把用户做过的每张
海报的底图一并删掉,再打开时是空舞台加上几个悬空的图层。 -
更新链路终于说清楚到底发生了什么。
原先 现在 只看 --profile,Desktop 传的是路径,于是落到web依次看 DSH_PROFILE、--profile、argv 里的profiles/<名字>路径段Desktop 环境下照样 spawn,只得到「更新失败」 直接给出 update-manual-required+ 可复制的安装命令子进程 stderr 被丢弃,只剩退出码 保留末尾三行(上限 4000 字符),pnpm store 冲突、目录被锁都能看见 第一行是 Desktop 用户真正那次失败的根因:Electron 宿主把 profile 当作路径
传进来(…/.dsh/profiles/desktop),既不设DSH_PROFILE也不传--profile,
所以只按 flag 解析的实现对每个 Desktop 用户都落到web——
哪怕更新"成功"了,正在运行的宿主插件也还是旧的。Desktop 那条尤其重要:DSH Desktop 的插件目录由桌面应用独占,
命令行去写必然以退出码 1 被拒。之前的实现仍然去 spawn,
于是用户看到的是一句没有任何原因的失败——这正是上游 issue #41 描述的死胡同。
现在面板会说明原因,并把安装命令和下载地址一起给出来。 -
画布有了快捷键面板。
按?或F1呼出,工具栏新增键盘图标入口,Esc关闭(层级在所有浮层之上)。
有快捷键的控件同时把它写进自己的提示里(如「撤销 (Ctrl+Z)」),
所以不必先知道有这块面板才能发现快捷键。
键位定义集中在CANVAS_SHORTCUTS一张表里,和检查脚本用的是同一份数据,
图例不会与它记录的代码漂开。 -
损坏的海报配方会被当场拒绝。
isPosterDocument()是严格的(version === 1、边长为整数且 ≤ 4096、
64 位 hex 的assetId且带图片扩展名、url走同源资源路由、
类型字段是type而不是kind、id 唯一、颜色为#rrggbb),
并且被isNode()调用——带半合法配方的画布保存会明确失败,
而不是等到下次打开编辑器时才抛错。 -
浏览器套件不再抢调试端口。
它们原先用9900 + 随机(300)猜端口,两次运行(或一个残留进程)
撞上同一个端口时就是那个偶发的Error: CDP down,
让verify-ui-contracts报 27/28。
现在统一走scripts/lib/headless-chrome.mjs:以
--remote-debugging-port=0启动,从DevToolsActivePort读回 Chromium
真正发布的端口,检查exitCode,保留 stderr 供报错使用,每次启动用独立 profile 目录。
三个守卫共用它,并且verify-ui-contracts会扫描其他守卫的源码,
谁再写死一个端口都会让检查变红。 -
发布由 CI 完成,不再是人手动打包。
.github/workflows/release.yml依次跑
typecheck → build → ffmpeg → 全部套件 →verify-pack→pnpm pack
→SHA256SUMS→ 打 tag → 建 Release。
打包时带--ignore-scripts,确保 Release 里那串校验和对应的字节
就是测试跑过的那份,而不是重新构建出来的另一份。
重跑是幂等的:同一个 tag、替换资产、不会产生重复 Release,也不会移动已有的 tag。
npm 发布是另一个 job,由一个仓库变量控制开关;
它先探测包是否存在再探测版本——npm 对这两种情况都回 E404,
但只有后者是正常发布。 -
test:negative并没有跑它定义的全部用例。
为回收站用例新增的canvas-videorunner 没有接进test:negative的命令链,
于是那条用例手动跑是绿的、却永远不在门禁里。
现在已接上,并且verify-negative.mjs在开始跑之前会先自检:
任何一个已定义的 runner 不在那条命令里,整个反向验证直接拒绝运行。
兼容性
- 不新增运行时依赖,无配置变更,无需迁移。
- 画廊索引新增可选字段
deletedAt:旧版本的清单读进来就是「全部存活」,
不需要迁移步骤;新版本写出的清单被旧版本读取时,
回收站里的条目会被当作正常条目显示(不会丢文件)。 - 画布节点新增可选字段
metadata.poster;没有它的节点行为完全不变。 - 历史、收藏、模板、渠道设置、视频记录全部不受影响。
安装
dsh plugin --profile web add https://github.com/q253595422/dsh-imagegen-video/releases/download/v1.7.7/q253595422-dsh-imagegen-video-1.7.7.tgz从本页的 tgz 附件安装:
dsh plugin --profile web add <下载路径>/q253595422-dsh-imagegen-video-1.7.7.tgz安装后重启 dsh web。DSH Desktop 用户:桌面版插件目录由应用独占,
请用面板里给出(或上面这条)dsh plugin ... add 命令在终端执行,
或在「设置 → 插件」里直接安装这个文件。
验证
-
pnpm run typecheck通过;pnpm test全链通过——十道离线检查:
verify-tracked(pnpm test的第一步)、smoke、smoke-video、
smoke-canvas-video、smoke-video-picker、
smoke-compose(真实 ffmpeg,零跳过)、verify-b-defect、
verify-video-layout、verify-frame-grab、verify-ui-contracts。 -
verify-tracked是这次发布过程中真出事才补上的一道:.gitignore里
未锚定的lib/同时匹配了scripts/lib/,于是
scripts/lib/headless-chrome.mjs从未进过仓库,而三个浏览器守卫都
import 它——干净 clone 直接ERR_MODULE_NOT_FOUND,本地却一直是绿的,
因为文件只存在于一台机器的磁盘上。现在/lib/只匹配构建产物,
并且每个相对 import 的目标都必须是 git 跟踪的文件,src/与scripts/
下也不允许存在“既未提交也未忽略”的源码。 -
反向验证
pnpm run test:negative共 54 个变异,
分布在 contracts 31 + smoke 16 + video 4 + canvas-video 1 + pack 1 + tracked 1;
每一个都让对应检查变红,且变红的原因与注入的缺陷一致。
本版新增的用例包括:注入的缺陷 应当变红的检查 海报配方不再被校验 smoke(路由级往返 + 两种损坏形态被拒)资产清扫不认海报配方里的底图与图层 smoke(删掉别的画布后,海报底图与 Logo 仍然可读)某个守卫 import 了一个从未入库的辅助文件 tracked(scripts/verify-tracked.mjs)删除画廊条目又直接销毁字节 smoke-canvas-video更新器又去 spawn 被锁定的 desktop profile smoke?键不再打开快捷键图例smoke工具栏控件不再在提示里带上键名 smoke某个浏览器守卫又自己猜 DevTools 端口 verify-ui-contracts快捷键面板在窄屏停止折成单列 verify-ui-contracts快捷键面板不再限制高度、直接长出视口 verify-ui-contracts回收站的还原按钮不再携带各自条目的 id smoke展开的回收站又重复一遍计数标题 smoke清空回收站的确认框不再说明将删几个 smoke -
端口那一条是源码级不变量,排在所有浏览器检查之前执行:
它读取scripts/下每一个会启动浏览器的脚本,
用拼接出来的模式匹配「非 0 的--remote-debugging-port=」,
命中就直接失败——所以它不可能因为「这次运气好没撞端口」而假绿。 -
这条不变量自身也有反向用例:把固定端口写回任一守卫,
verify-ui-contracts必须变红。 -
浏览器相关检查在缺少 Chromium 时明确跳过并返回成功,
跳过与通过会分别打印,不把「没跑」说成「通过」。
已知边界(诚实说明)
- npm 包尚未发布。 包名
@q253595422/dsh-imagegen-video目前在 registry 上
是 404,而 npm 的 trusted publishing 只能挂在已存在的包上,
所以第一次npm publish --access public必须由人工在已登录的机器上执行一次。
release.yml里的 npm job 默认关闭(仓库变量NPM_PUBLISH不为true时跳过),
跳过不算失败,GitHub Release 照常产出。 - Desktop 的更新仍然是手动的,这是上游 CLI 的设计,不是本插件能绕过的;
本版做到的是不再假装能自动更新,并把可执行的命令交到用户手上。 - 海报编辑器只做文字与 Logo 两层合成,不是完整的排版工具:
不提供旋转、渐变、阴影、多行富文本。它的定位是「不花额度的一层叠加」,
复杂的成图仍应回到生成链路。 - 回收站保留期固定为 30 天,本版不提供设置项。
v1.7.6 · 模板库从 5 个源扩到 8 个,安装包降到 4 MiB
v1.7.6 · 模板库从 5 个源扩到 8 个,并修掉一个静默丢了一半条目的解析缺陷
本仓库自己的发布说明。相对上游 v1.6.8 的完整改动见 CHANGELOG.md。
这一版只有一个主题:模板库里到底有多少条。答案是原先的 2462 条其实少算了——
一个用编号做 key 的解析缺陷把 evolink 静默丢弃了近千条,
而这次又在 GitHub 上找到了三个可以合规接入的新来源。
主要更新
-
模板库:5 个源 / 2462 条 → 8 个源 / 3774 条(+1312 条,+53%)。
-
evolink 从 462 条修复到 967 条。
上游那批案例的编号在不同分类文件之间以及同一文件内部都会重复
(cases/character.md与cases/portrait.md都从### Case 1:开始,
图片还放在不同目录),而快照原先只拿编号当 key,
于是约 1420 条里只有 462 条存活,其余的没有任何报错就被覆盖了。
现在 id 按分类加作用域(portrait-53),并对同一文件内的重号去重,
967 条、id 零重复。
这不是「新增内容」而是「把本来就该在的东西修回来」,所以单列一条。 -
新增三个来源,全部按精确 commit 固定。
源 条数 许可 示例图 itgoyo/awesome-gpt-image2-prompt602 CC BY 4.0 有 songtianlun/awesome-prompts55 MIT 有 youart-open-source/awesome-gpt-image-2-5-prompts150 分层声明,见下 无 三个源都在
scripts/fetch-templates.mjs里钉死到具体 commit
(ITGOYO_COMMIT/SONGTIANLUN_COMMIT/YOUART_COMMIT),
运行时不可刷新——否则上游一改,我们审核过的那一版就漂了。 -
来源标签行现在可以滚动。
八行标签在窄面板里放不下,而原先的 flex 行既不换行也不滚动:
右边缘之后的所有来源不可见、不可点,且屏幕上没有任何提示说它们存在。
现在行可横向滚动、标签不参与收缩(收缩会把标签文字和计数徽章一起截断)。
这条用真实浏览器验证,而不是读 CSS 声明。 -
youart 的 150 条卡片没有缩略图,这是设计而非缺陷。
该语料不发自己的图片,只在每一行署名到原作者与原始帖子。
卡片显示占位缩略图,提示词、标题与原作者链接都完整——
它是这批来源里合规溯源最干净的一个。 -
「检测模型」不再丢掉
nanobanana2和nanobanana2-lite。
这两个 id 就在出厂默认列表DEFAULT_IMAGE_MODELS里,但
describeModel()认它们、isLikelyImageModelId()不认:
后者要求关键词后面跟分隔符,而nanobanana2里nanobanana和2
之间什么都没有。于是网关/models只返回 id、不带能力元数据时,
面板的「检测模型」静默少两项,用户看到的是一个比目录更短的列表。
谓词现在接受无分隔符的数字后缀(flux2、wanx2同理),
而gpt-4o、text-embedding-3-small仍然被正确排除。
许可
新增来源的许可与署名已逐条写入 THIRD_PARTY_NOTICES.md。
其中 youart 的许可不是一句话能说完的:该仓库按路径分层声明
(构建脚本 MIT,提示词文本不是那个项目能许可的东西——每一行都写明作者与首次出现的帖子,
仓库还用 provenance/ 保留了各上游集合自己声明的条款)。
本版收录的行来自声明为 CC0-1.0 或 CC BY 4.0 的集合。
prompt-signal 里 6 条无许可图片已清除(上一版挂起的待定项,本版定案)。
那 6 条的 image 原本指向一个不声明任何许可的仓库
(songguoxs/gpt4o-image-prompts)。这些 URL 是随包分发的数据,
所以要不要提供它们由本仓库负责,而不是上游聚合器。
现在 image 置空,卡片显示占位缩略图;提示词、标题、原作者链接全部保留,
因为这些提示词本来就逐条来自原作者自己的帖子,聚合器只提供了预览图。
生成器与检查脚本两侧都加了守卫,重新生成若忘记过滤会让构建失败。
包体
安装包从 24 MiB 降到 4 MiB。 docs/images/ 是 README 里那批截图(其中一个
13 MiB 的演示 GIF,合计约 20 MiB),运行时从不读取,GitHub 直接从仓库渲染。
它和 docs/videos/ 一样留在仓库里、不再进安装包。CI 现在会检查这两条——
打包后用真实 pnpm pack 的产物核对,而不是靠人记得。
兼容性
- 不新增运行时依赖,无配置变更,无需迁移。
- 画布数据、历史记录、素材库、渠道设置全部不变。
- 模板收藏按
源id:条目id保存。evolink 的 id 换了形态
(case-12→portrait-12),因此上一版对 evolink 条目的收藏会失效;
其余来源的 id 未变,收藏不受影响。这是修 id 冲突不可避免的代价。
安装
dsh plugin --profile web add https://github.com/q253595422/dsh-imagegen-video/releases/download/v1.7.6/q253595422-dsh-imagegen-video-1.7.6.tgz从本页的 tgz 附件安装:
dsh plugin --profile web add <下载路径>/q253595422-dsh-imagegen-video-1.7.6.tgz验证
pnpm run typecheck通过;pnpm test全链通过(含smoke、
smoke-video、smoke-canvas-video、smoke-video-picker、smoke-compose、
verify-b-defect、verify-video-layout、verify-frame-grab、
verify-ui-contracts)。- 来源标签行在真实浏览器里实测:420px 宽下渲真实样式表与全部 8 个来源标签
(标签从TEMPLATE_SOURCES注册表生成,不是手写死列表,避免加第 9 个源时
测试悄悄失效),内容溢出 855px,滚轮把它从 0 滚到 855,
末位标签经elementFromPoint命中自身。 - 反向验证
pnpm run test:negative共 41 个变异
(contracts 28 + smoke 8 + video 4 + pack 1)全部让对应检查变红,
本轮新增的包括「标签行不再滚动转而裁切后续标签」「标签允许收缩」
「行高比标签还矮导致纵向切一半」「标签行不再从注册表生成」
「注册的来源失去宿主侧抓取定义」「快照引用了来源白名单之外的主机」
「evolink 因编号冲突再次丢条目」「快照把图片指向无许可仓库」
「发布的归档又带上了 README 截图」「模型检测丢掉带数字后缀的族名」。 pack这一段跑的是真实的pnpm pack产物,不是模拟:
在仓库副本里放一个一字节占位文件代表docs/images,
再把docs/images加回files,检查必须失败。
没有这个占位文件,缺陷会因为「副本里本来就没东西可打包」而假装通过。- 图片主机白名单是从真实的
SOURCE_DEFS读取再校验快照的,
不是在测试里复制一份主机前缀——复制的那份会永远与自己一致,
而真实网关拒绝了图片。这一条本身也有反向用例。 - 每个内置快照都断言 id 唯一,且每个非空图片引用要么是裸文件名
(靠imageBaseUrl提供)、要么是无凭据的绝对 URL。
URL 用解析器判断而不是正则匹配——jsdelivr 的固定 URL 路径里合法地带着
@commit,把裸@当作用户信息会把 handraw 快照整个误判掉。
已知边界(诚实说明)
- 模板库仍然是打包随发布分发的,不在运行时抓取——
这是刻意的:离线可用、审核过的内容不会漂。 - 新增来源里
songtianlun的图片主机白名单包含cdn.openai.com,
该主机在部分网络下不可达;不可达时卡片退化为占位缩略图,不影响提示词使用。 prompt-signal里清空图片的 6 条卡片只有占位缩略图,与youart的 150 条同类。- evolink 的收藏会失效:见「兼容性」一节。
v1.7.5 · UI 全部模块过一遍,并把失败诊断做到视频链
v1.7.5 · UI 全部模块过一遍,并把失败诊断做到视频链
本仓库自己的发布说明。相对上游 v1.6.8 的完整改动见 CHANGELOG.md。
这一版做两件事:把界面里会互相打架的东西收敛到单一来源,
以及补上「失败了能查原因」——并把这个能力从生图做到视频链。
判据始终是「去掉修复后,对应检查必须变红」,而不是「看起来改好了」。
主要更新
-
导航栏跟随宿主主题变化。
GooeyNav的四个颜色原先写死成字面量,而且只在挂载时探测一次表面颜色;
宿主在它显示期间切浅色/深色,它仍按旧表面作画,在新底色上读不清。
现在配色从--dsw-alias-*变量派生,并新增surface-theme.ts订阅,
在宿主属性(含 DSH 的data-ds-dark-theme)、系统偏好、以及被重新挂载时
都会重新推导。注意--dsw-alias-brand-primary是中性反转色、不是强调色
(浅色下近白、深色下近黑)——它按中性色使用,标注红刻意不用它。 -
标注色成为一个变量,CSS 与画布两侧同源。
画布上看到的标注框由 CSS 上色,而烧进图片里的画框由 Canvas2D 用#ff2d55
字面量画——两边会漂移。现在都读--canvas-annotation。
因为该变量声明在画布根类上、不在documentElement上,
themeColor()增加了origin参数,调用方传入画布根节点;
从文档根读会永远拿到空串并静默回退到字面量,等于没修。 -
统一的 z-index 表,且不重编已经正确的层序。
模块样式表里的字面量全部改为panel.module.css里的一张有文档的表。
数值就是各层原本的值,只有真正同号的才拆开,且只拆到刚好保住
原有比较关系为止(1000 → 1000/1005/1010,130 → 130/131/132,
60 → 60/61/62,70 → 70/72,20 → 20/21)。这些同号是真实的:
谁压谁由文档顺序决定,一次无害的重构就能改变堆叠。
守卫有三重——文档表必须与声明逐条一致、26 条必需的先后关系必须成立、
以及三个与宿主外壳交界的档位按值钉死;另有一条真浏览器检查,
把其中一对原同号层按相反顺序渲染,要求胜者不变。 -
浮层不再顺带清空画布选择。
所有浮层(输入条、菜单、弹窗)都是视口的兄弟节点,
所以在浮层上按下指针不会传到视口处理器。这条现在用结构断言保证,
而不是靠一段实际为死代码的守卫。 -
触屏支持双指缩放。
两个触摸点分开即缩放画布,与触控板行为一致。 -
键盘可达性。
坞站按钮获得焦点后按空格是激活按钮,不再被平移处理器吞掉;
Esc 能关闭画布内视频预览、技能菜单、润色弹窗与视频拾取器;
节点隐藏的悬浮工具条退出 Tab 顺序、并由焦点唤出,
Tab 不再落在看不见的控件上(包含删除按钮);
所有role="tablist"都接上共享的 roving-tabIndex + 方向键契约。 -
读取失败不再伪装成空列表。
历史、素材库、模板收藏在读取失败时显示「这里还没有内容」。
现在会显示失败原因与重试;收藏状态读不到时显示「未知」标记,
而不是一颗看似「未收藏」的星。
失败可查的诊断记录,以及视频链的对等
这一版吸收了上游的诊断能力(上游 issue #38:生成失败后没有任何地方可以查看原因),
并补上上游没有的那一半——视频链。上游源码是本仓库的起点,不是要追的版本线:
两边没有共同祖先,所以吸收是文件级移植而非 git merge;这里装的是本仓库自己的
1.7.5,版本号不跟上游(上游代码的署名见 NOTICE)。
- 失败可查:每一次失败的上游请求都留档。
新增内存环形缓冲(200 条,重启即清空,不落盘),记录实际调用地址、
HTTP 状态、网络错误码、耗时、请求/响应体积与上游原始响应体。
写入前统一脱敏(Bearer令牌、查询串密钥、内联 base64 → 占位符),
复制出来的内容可以安全贴进公开 issue;
读取失败时面板显示失败原因,不再伪装成「无记录」。 - 失败任务在任务列表里自己解释自己,不再只有一个「失败」:
错误信息里带上请求地址与网络错误码——这正是「请求根本没到网关」这类
报告的决定性证据。 - 生图工作台不再被插件市场页挡住:两者共用同一个
main插槽,
该插槽内的非对话内容现在正确让位。 - 视频链写入同一个缓冲(本仓库补的对等)。
上游的 #38 只覆盖了生图:图能生、视频不能生的用户无处可查,
而DiagnosticPhase当时根本说不出视频的那几条腿。
视频是 submit → poll → download 而非一次同步调用,所以每条腿各自成 phase
(video-submit/video-poll/video-download),
「渲染根本没开始」与「状态接口不再应答」现在能分开。
参考帧只记数量、绝不记那几 MB 的 base64;
轮询循环会重试的单次抖动刻意不记(记了会淹没真正要看的那条),
但重试预算耗尽必记,并带上接口一直回的那个状态码。
入口挂在两个工作台常显的工具栏上——
提交就失败的时刻恰恰没有任何任务行可点。
兼容性
- 不新增运行时依赖,无配置变更,无需迁移。
- 画布数据、历史记录、素材库、模板与渠道设置全部不变。
- z-index 表的数值改动只影响原先同号的那几层;其余层序逐位保持原样
(与上一版对比,全仓仅 8 处层号发生变化,且都有记录)。 - 诊断日志是新增功能,默认记录、无需开启,不产生任何后台请求,
仅存内存、重启即清空。
安装
dsh plugin --profile web add https://github.com/q253595422/dsh-imagegen-video/releases/download/v1.7.5/q253595422-dsh-imagegen-video-1.7.5.tgz从本页的 tgz 附件安装:
dsh plugin --profile web add <下载路径>/q253595422-dsh-imagegen-video-1.7.5.tgz验证
pnpm run typecheck通过;pnpm test全链通过(含smoke、
smoke-video、smoke-canvas-video、smoke-video-picker、smoke-compose、
verify-b-defect、verify-video-layout、verify-frame-grab、
verify-ui-contracts)。- 涉及布局的三项都在真实浏览器里实测,不是读源码推断:
层序(在反转 DOM 顺序下实测遮挡关系)、悬浮工具条的可见性与焦点、
输入条占满面板宽度(实测 976/1010px)。 - 每处修复都做了反向验证:
pnpm run test:negative共 31 个变异
(contracts 21 + smoke 6 + video 4)全部让对应检查变红,包括
「把下拉层降回 60 让它掉到自己的弹窗之下」「恢复 60/60 同号」
「把文档表改得与声明不一致」「视频提交不再留档」「视频三条腿丢掉自己的 phase」
「重试预算耗尽不再记录」「耗尽后不带上接口一直回的状态码」
「视频工作台不再提供诊断入口」等。
反向验证在仓库副本上进行,工作树不被改动。 - 诊断的视频对等在
smoke-video里单独验证:V1h(重试预算耗尽留档,
含 phase / 状态码 / 任务 id)、V9(提交失败可解释:拒连记最终 URL 与错误码,
非 2xx 记状态与上游原文,密钥不落库,参考图不入缓冲)、
V9b(poll 与 download 各记在自己的 phase 下)。 - 视频工作台的入口可达性(本版补的对等):在
smoke的 jsdom 客户端用例里
断言「视频工作台在零任务时也能打开同一个记录面板」——
面板里出现的是video-submit这个视频 phase,而图片托盘此时根本没渲染。
已知边界(诚实说明)
settings-card的.presetInline与.footer在上一版就存在层序翻转
(10 压在 4 之上,改表后变成 2 在 3 之下)。本版按「保住既有行为」处理,
未改变其可见结果;是否要重新设计这两层的意图,留待后续决定。
v1.7.4 · 四条只在中途才现形的时序修复
围绕 1.7.3 复核时报出来的四条问题,全部是时序类故障:平时不出现,一出现就没有绕过的办法。
修了什么
- 一个宿主拒收的产物,不再让整次技能运行白跑。 画布技能会把跑出来的文件逐个交给宿主保存,而宿主对扩展名和体积有硬拒(
.svg、.html这类不允许,超过 50MB 不允许)。以前任一个被拒,异常会一路冒到整次运行:前面已经跑好、也已经写进画布的东西全部不算数,用户只看到一条错误、还得重跑一次可能花了十分钟的任务。现在被拒的那个文件会被跳过,其余产物照常入画布,并给出一条三语警告指名说清是哪个文件、为什么没保存。 - 片段文件的读取流挂掉,不再把整个 DSH Web 进程带走。 播放片段时宿主是把文件
pipe给响应的,而pipe只会把错误转给目的地、永远不转给来源流;宿主也没有装uncaughtException处理器。所以「stat 通过之后、流打开之前」这个窗口里文件被删掉(用户删条目,或 30 条上限把最旧的挤掉,而浏览器还在预加载它),未处理的error事件会直接终止整个 Web 服务。现在来源流挂了自己的监听,出错时只干净地断掉这一个响应。 - 切画布不再丢失刚做的改动,也不再被上一个画布的迟到答复顶掉。 自动保存是防抖的,于是「改完标题立刻切到另一个画布」曾经有两种坏结果:改动没来得及写就切换,静默丢失;或者旧画布的保存答复晚到一步落到屏幕上,把新画布顶掉。现在每次写入带序号,落后于当前编辑的答复一律丢弃;切换/新建之前先把待写的改动冲刷下去;删除画布时会记下这份文档已对账,避免随后的切换把刚删掉的画布又写回去。
- 视频工作台提交/取消之后,列表立刻更新。 任务列表由父组件统一轮询(这样画布和视频页签看的是同一份状态),但页签自己的刷新函数在受控模式下直接返回,于是用户点了「生成」或「取消」要等满一个轮询周期(5 秒)才看到那一行出现或变成已取消。现在这个请求向上走,交给父组件那唯一一个轮询器重新读取,不新增第二个轮询循环。
安装
dsh plugin --profile web add https://github.com/q253595422/dsh-imagegen-video/releases/download/v1.7.4/q253595422-dsh-imagegen-video-1.7.4.tgz验证
pnpm exec tsc --noEmit通过;pnpm test全链通过(七个套件全 OK,其中smoke-canvas-video的 ffmpeg 真实编码路径没有跳过,0 checks skipped)。- 四条修复各自都有能复现原缺陷的检查,并且都做了反向验证——把修复去掉后对应检查会变红,而不是「看起来做了」:
- 被拒产物:把异常重新抛回去,检查立刻报
the task failed with error 出于安全考虑,不支持上传 .svg 文件。 - 迟到答复 / 切换前冲刷:去掉守卫后分别报
a late answer for the canvas the user left is discarded与the pending edit was flushed before the canvas was replaced。 - 视频列表刷新:去掉上行调用后报
submitting asks the parent to re-read the queue (reads: 1 -> 1)。 - 片段读取流:由真实 HTTP 竞态检查覆盖(真起服务、真发请求、真断流,用裸 socket 驱动,因为正确行为是
res.destroy())。
- 被拒产物:把异常重新抛回去,检查立刻报
- 版本号一致性由
smoke.mjs的 A3 守住(它断言宿主上报的CURRENT_VERSION等于package.json的版本);这条在本版发布过程中真的抓到了一次漏改,包内两处版本号现已都是 1.7.4。 - 归档 sha256
3f59dbc500f190c300f9b693153d7b631f2344d994bb06f1e1251d8d23fd1780。
若你还没升级过:请直接用 1.7.4。1.7.3 修了
~展开与拖拽柄语言,1.7.2 修掉了「含视频节点的画布无法保存」,1.7.1 补上了 1.7.0 漏发的两条修复。
v1.7.3 · 数据目录支持 ~ 展开,拖拽柄跟随语言
围绕 1.7.1 自身改动复核时发现的两处边界问题。
修了什么
- 数据目录设置里的
~现在会展开成主目录。 这个值是在设置表单里手打的,~/my-images是最自然的写法,而path.resolve不会展开它 —— 于是宿主会在自己的工作目录下建出一个字面名为~的目录、把数据全放进去,用户去主目录里却什么都找不到。~user形式刻意不解析(那是另一个用户的 home,不该由这个设置去碰)。 - 对话区拖拽柄的
aria-label现在跟随界面语言。 它在 React 树之外、只创建一次,语言切换时没有任何东西会重渲染它,于是一直停在面板创建时的语言。现在它订阅语言变化,并在元素被替换或面板卸载时释放订阅。
安装
dsh plugin --profile web add https://github.com/q253595422/dsh-imagegen-video/releases/download/v1.7.3/q253595422-dsh-imagegen-video-1.7.3.tgz验证
pnpm test全链通过,退出码 0,0 个 FAIL。~展开实测了 5 种输入:~/x、裸~、绝对路径、空白、undefined。- 归档 sha256
73056f970615ea76212982a50bd7e9a319e4c908da8c447638acefa7721a4b53。
若你还没升级过:请直接用 1.7.3。1.7.2 修掉了「含视频节点的画布无法保存」,1.7.1 补上了 1.7.0 漏发的两条修复。