Conversation
0d50ebf to
7320ccd
Compare
Narrated-video pipeline: HTML slides with staged entrance animations, TTS voiceover measured with ffprobe, burned-in subtitles, deterministic frame-stepping capture, ffmpeg assembly, and ASR verification. - 11 Node scripts, no build step; works with mcode connectors or mmx-cli - 13 themes, 17 layout recipes, image framing primitives - Subtitles confined to their own windows (no overlap); 16:9 and 9:16 canvases - Research phase documented: source grading, cross-verification rules, notes template - Discloses dependencies, accounts, network destinations and data handling (bilingual README) - Validation: node scripts/validate.mjs -> OK (exit 0)
7320ccd to
4104572
Compare
Add Plugin: html2video-for-mcode Narrated-video pipeline: HTML slides with staged entrance animations, TTS voiceover measured with ffprobe, burned-in subtitles, deterministic frame-stepping capture, ffmpeg assembly, and ASR verification. - 11 Node scripts, no build step; works with mcode connectors or mmx-cli - 13 themes, 17 layout recipes, image framing primitives - Subtitles confined to their own windows (no overlap); 16:9 and 9:16 canvases - Research phase documented: source grading, cross-verification rules, notes template, plus how to fetch official-site / press-release text (SPA rendering, PDF-first numbers) - Discloses dependencies, accounts, network destinations and data handling (bilingual README) - Validation: node scripts/validate.mjs -> OK (exit 0)
… them to the repo root) Add Plugin: html2video-for-mcode Narrated-video pipeline: HTML slides with staged entrance animations, TTS voiceover measured with ffprobe, burned-in subtitles, deterministic frame-stepping capture, ffmpeg assembly, and ASR verification. - 11 Node scripts, no build step; works with mcode connectors or mmx-cli - 13 themes, 17 layout recipes, image framing primitives - Subtitles confined to their own windows (no overlap); 16:9 and 9:16 canvases - Research phase documented: source grading, cross-verification rules, notes template, plus how to fetch official-site / press-release text (SPA rendering, PDF-first numbers) - Discloses dependencies, accounts, network destinations and data handling (bilingual README) - Validation: node scripts/validate.mjs -> OK (exit 0)
hetaoBackend
left a comment
There was a problem hiding this comment.
Request changes for exact current head 737ee96.
Blocking security and evidence issues:
- Input-derived IDs and paths are not contained.
skills/html2video-for-mcode/scripts/capture.mjs:75-77,228-230usess.htmlands.idto construct paths and recursively deletes the frame directory;build-video.mjs:55-58,191-197usest.idfor output/frame/ASR paths;plan-timings.mjs:47-50andbuild-video.mjs:102-105also consume script-provided paths. An Agent-editablescript.jsonvalue such as../../victimcan escape the intended build directory and trigger out-of-scope reads/writes/deletion. Add strict ID validation, resolve-and-containment checks, symlink checks, and malicious-ID tests. init-project.mjs:7-16,468-477accepts an existing directory and then overwrites project files without a non-empty check or explicit--force.fetch-official-images.mjs:31-32,102-115accepts arbitrary--out-dirand overwrites files;prep-image.mjs:64-87uses ffmpeg-yfor arbitrary output. This contradicts the README claim that writes stay inside the supplied project directory and creates destructive overwrite behavior. Default to refusing existing/non-empty targets and require explicit force, with output containment enforced.asr.mjs:29-32,65-74allows--base-url/MINIMAX_BASE_URLto replace the endpoint without validation while sending the MiniMax API key as a Bearer token. A misconfiguration or prompt-controlled environment can exfiltrate the credential to arbitrary HTTPS/HTTP endpoints. Default to an HTTPS allowlist for official hosts; make custom endpoints an explicit, separately disclosed dangerous opt-in.fetch-official-images.mjs:25-29,40-46,98-115accepts arbitraryhttp:,https:, andfile:URLs and downloads through a browser/request client without protocol, private-address, redirect, or response-size restrictions. This exposes SSRF and local-file-read/copy behavior. Restrict to validated HTTPS public targets, block loopback/private/link-local/metadata addresses and redirects, bound responses, and make local files explicit opt-in with containment.- The PR adds roughly 2,000 lines of executable scripts but no executable test suite;
evals/evals.jsonis prompt/expected-output data and is not run bynpm run check, while the repository validator does not execute these scripts or validate.claude-plugin/plugin.json. Add automated negative and smoke tests for containment, overwrite refusal, endpoint allowlist, SSRF/file rejection, and a minimal render/checker/build dry-run. The current[code]smithcheck is skipped and cannot substitute for this evidence.
Do not approve or merge until these security boundaries and executable test evidence are present on a new head.
|
Thanks for the review — all five blockers were reproduced against the exact head you flagged and are fixed on the new head (v1.1.0). Point-by-point: 1. Input-derived IDs and paths are not contained — fixed. 2. Destructive overwrite behaviour — fixed. 3. Endpoint replacement could exfiltrate the credential — fixed. 4. SSRF / local-file read in 5. No executable test suite — added. Also in this head (non-blocking, from user feedback while the review was open): pure-CSS/SVG chart recipes with entrance-and-growth animations, a one-switch The validator reports |
追加:放映页(可以先自己放一遍再渲染)+ 修一个"文档说能用、闸门说不能用"的类新提交 1. 新增 单文件、零依赖、 为什么不是"直接打开 2. 3. 修 4. 测试 +21 例(共 93,7 个文件):新增 5. 文档漂移修正:插件树 README 此前落后仓库树一轮(缺整个
|
追加:
|
| 情形 | 页面表现 |
|---|---|
有 clauses + 有 timings.json |
列出该张口播文案(P 可开 / 关) |
| 有 clauses、还没对时 | 只列文案,标题标「(未对时)」—— 口播还没做也能先看 HTML |
没有 clauses,或 --no-script |
面板与口播按钮完全不出现,画面占满整宽 |
顺带修掉一个误导标签:底部提示原写成「X 关配音画对比」(本意是「关动效 / 画面对照」),读起来像是在管音频。现在统一写作「X 动效 / 关动效 对照」,测试里加了断言:页面不得出现「配音」字样。
3. 响应式(此前只考虑了桌面)。 原来右侧固定 320px 面板 + 固定行高的顶/底栏,窄窗口和手机上挤成一团。现在:顶栏/底栏可换行、话题名过长省略号截断;窄窗口与手机上口播面板收成底部抽屉并默认收起(画面优先);手机给触摸条按钮 + 左右滑动翻页;总览网格按宽度自动列数;高度用 100dvh(免得被手机地址栏切掉)。
实测(Playwright,五档视口 + 触屏模拟):1600×900 / 1024×600 / 800×600 / 390×844 / 360×640 全部零横向溢出、零控制台报错,触摸条无标签截断;390×844 上左滑确实翻页;窄屏下点「口播」画面从 385→755px 高。
另外把「还没对时」这一档做实用:没有 timings.json 时,副本按 HTML 里实际用到的 stage 等间隔排(0.3/1.3/2.3s),页面顶部黄条如实标注「不是成片时序」—— 占位值会把动画全挤在 2 秒内,那才是真看不懂。
测试 99 例(+6:不做计时器 / 不得出现「配音」字样 / 响应式与触摸 / 口播三态 / 等间隔兜底)。
总计:评审之后的全部优化与新增(1.1.0 → 1.6.0,测试 93 → 174)五条阻塞项的逐条修复见前面的回复;本条把其余的全部优化与新增(含新增的预览模式)汇总成一份,便于整体复核。对应 CHANGELOG 1. 预览模式(放映页,新增交付物)新增
2. 图表与表格工具箱(评审后陆续合入)+ CSS 传播根治(v1.2.0)
3. 三维审计(文档对齐 / 安全 / 流程)修复(v1.3.0)
4. 调研链路的环境归属(v1.3.1)工具链对照表"调研"行补齐:mcode = 5. 工作流:开工对齐新增"数据与图表"必问项(v1.3.2)图表工具箱合入后,入口此前只藏在 Phase 1/4 的文档里,开工对齐必问清单没有图表项。现新增一行"数据与图表":题材含关键数字 / 对比 / 占比 / 趋势时必问 —— ①有没有值得单独成张的可视化数据;②要不要图表张、大约几张(默认建议:有硬数据且版式合适 → 1–2 张);③样式偏好(横向条形 / 柱状 / 环形 / 折线 / 进度条,或按数据形态让 agent 选);④图上数字同受 Gate 0 约束(≥2 独立来源、带口径与时点)。就算用户没提图表,数据密集题材也要主动给这个选项。Phase 1 配套"数据密集的题材主动做图"(≥2 个可比数字 → 优先 data-viz + 图表工具箱,不罗成 bullets)。 6. Gate 1 呈现格式补"表格与动效"必填列(v1.3.3)实测反馈:Gate 1 给用户过的表此前只有「版式 / 画面 / 口播」,用到表格原语或有入场动效(淡入错峰、数字滚动、条形生长)的张没有说明,用户只能凭空想象、等 Gate 4 才第一次看到动起来的样子。现 Gate 1 呈现格式定为「# / 版式 / 画面 / 表格与动效 / 口播逐字稿」,表格与动效列必填:表格张说明形态(几行几列、用哪个原语、高亮哪行/列),动效张点名效果与次序 —— 让用户凭这张表就能在脑内放一遍成片。 7. 配图 SOP 新增"路径 D · 公告与报道截图"(v1.3.4)暴雷 / 监管处罚 / 诉讼 / 翻车类题材,公司官网不可能提供素材(路径 A/B 必然落空),此前 SOP 没覆盖这条真实路径。新增路径 D:素材取自事件本身的一手载体——交易所公告 / 监管文书 > 公司官方声明 > 媒体报道页;一线权威(新华社/央视/澎湃)与主流门户(腾讯新闻/新浪/网易等)均为合格来源,排除的只有自媒体 / 聚合号。截图纪律:画面保留媒体名与日期、只截正文区、MANIFEST 登记"来源 URL / 日期 / 报道性合理引用"、入画 8. 铁律 4 措辞收紧:开工对齐必须"问、等答"(v1.3.5)实测踩坑:agent 把必问清单执行成"一条消息甩出『默认项(不特别说的话就按这个):中文普通话 · 中文字幕 · 1920×1080 · 温润男声 · 10–12 张…』然后继续推进"—— 用户没有逐项表态的机会,等于没对齐;根因是旧措辞"(用户没答的项可用默认值,但必须先问)"留有"先告知、不反对即同意"的解读空间。现规则:第一次响应 = 问题以问句形式逐项列出、然后停下等回答;每项可附推荐默认值,但必须是"问、等答";只有用户明确说"按默认"或没答到的项才用默认,且进入下一步前复述最终采用了哪些默认。实测反例原文写进 SKILL.md 作为禁例。 9. 开工对齐"素材边界"补负面事件加问项(v1.3.6)实测踩坑:负面新闻稿视频,agent 问了主题 / 图表 / 受众,但没问"要不要新闻或媒体平台截图当配图"—— 路径 D(v1.3.4)写进了取图 SOP,却没接进开工必问清单。现"素材边界"行加注:负面事件题材(暴雷 / 处罚 / 诉讼 / 争议)必须加问"要不要用公告或新闻报道截图当配图"(默认建议:要,1–2 张,来源分级与截图纪律见 image-sources.md 路径 D)。 10. 开工对齐清单重排 + Gate 3 补"选素材 / 补充素材"问(v1.3.7)
11. 放映页交互模型重做:动效开 = 手动逐级入场 + 三项实测反馈修复(v1.4.0)
12. 第二轮评审整改:输出收监 / 网络边界 / 字幕时间轴(v1.5.0,3 个 P1 + 4 个 P2)逐条对应评审意见,全部有可执行证据:
13. 交付质量三修:封面 / 切页 / 语速与试听对齐(v1.6.0)来自真实交付的反馈(转发出去的缩略图是纯黑首帧、每次切页黑屏、默认语速偏慢):
验证
对应提交(插件分支): |
…ingual UI (1.4.0)
hetaoBackend
left a comment
There was a problem hiding this comment.
Re-reviewed current head fcf363095d6062441f6df1dd6a988a1493213f54 (v1.4.0). Request changes: the added validation and executable tests address parts of the previous review, but the following issues remain reproducible on this exact head.
All script paths below are relative to plugins/Wzdhehe/html2video-for-mcode/skills/html2video-for-mcode/scripts/.
Security boundaries
The two findings below are intentionally summarized without exploit inputs or reproduction steps, consistent with this repository's SECURITY.md.
-
[P1] Output containment is still incomplete. The capture pipeline's output writes and recursive frame cleanup do not consistently enforce the real filesystem boundary. A controlled test using disposable canary data demonstrated deletion outside the supplied project while the command reported success. Validate the canonical project boundary and all output-path ancestors before destructive operations, including derived output paths; add regression coverage for output-directory indirection. The current safe-ID/input-path checks are insufficient to substantiate the README's containment guarantee.
-
[P1] The image-fetch network policy does not cover all actual requests. Controlled local-server tests demonstrated access to a disallowed destination through both the direct-download and browser paths. Enforce destination validation at the actual connection/request boundary, covering name resolution, navigation redirects, and browser subresources. Pure URL-classification tests alone do not verify this boundary; add end-to-end tests asserting that rejected destinations receive no requests.
Functional correctness
-
[P1] Keep subtitle changes in the rendering window.
capture.mjs:221-235excludes.kit-subanimations when calculatinganimEnd, then stops frame capture after the visual entrance animations finish.build-video.mjspads the rest with the final captured frame, freezing later subtitles. In a realplan-timings → capture --mode motion → build-videorun, an 8-second MP4 passed duration and full-decode checks, but its SRT scheduled the fourth clause at 5.322 seconds while the frame at 6 seconds still displayed the second clause. Withno-fx, capture falls back to a static frame at subtitle time zero, producing no burned-in subtitles. This violates the documented promise that subtitles continue normally when effects are disabled. Include subtitle changes in the capture duration, or burn them independently during encoding; test both multiple clauses sharing a stage andno-fx. -
[P2] Count ASR request errors as failures and exit nonzero.
asr.mjs:230-239catches request errors into{ error }, but the final summary only counts failed text verdicts. A local mock returning HTTP 503 produced an error followed by完成: 1 通过 / 0 待复核 / 0 不通过, with exit code 0. Authentication, rate-limit, and network failures can therefore falsely pass the ASR gate. Track processing errors separately, exclude them from the pass count, and return nonzero when any required transcription failed. -
[P2] Handle existing single-quoted HTML attributes in the preview generator.
preview-page.mjs:63-73,86-92recognizes only double-quotedstyleandclassattributes. Valid input such as<html class='theme' style='--t2:800ms'>receives duplicate attributes; Chromium retains the first ones. Real-browser verification showed that the original delay remained, the injected canvas width was absent, andno-fxwas not applied. Parse/update existing attributes without producing duplicates, with coverage for single-quoted and unquoted forms, so preview timing, portrait dimensions, and the effects toggle match rendering. -
[P2] Complete discovery of project-local ffmpeg dependencies.
tools.mjs:20-21does not searchprocess.cwd(), whileprep-image.mjs:23-24andasr.mjs:65-66do not supply a project directory or setKIT_PROJECT_DIR. The README explicitly supportsffmpeg-static/ffprobe-staticinstalled in the video project. With system PATH isolated and a tool present under the project'snode_modules, running the image-processing entry point from that project still exits 2 with “找不到 ffmpeg”. Include the invocation/project directory consistently in tool discovery and cover these entry points without system ffmpeg. -
[P2] Canonicalize output directories before the containment comparison on macOS.
fetch-official-images.mjs:57-60compares lexical paths, so the equivalent/var/...and/private/var/...spellings can be treated as different directories. A legitimate absolute--out-dirinside the working project is rejected. This also causes the plugin's existingno-clobbertest to fail on the tested macOS environment. Compare canonical paths, resolving existing ancestors when the output does not exist, while preserving the security boundary.
Validation
- Reviewed and reproduced against the exact head above; source files were not modified.
- macOS, Node 26.4.0, local ffmpeg/ffprobe and real Playwright Chromium.
- Repository validation passed all 27 hosted plugins and examples.
- Full
npm run check: 640 tests, 616 passed, 1 failed, 23 skipped. The failure is the macOS path-alias issue in item 7. - Plugin-only suite: 150/151 passed with the default temporary directory; 151/151 passed, zero skips, after using a canonical temporary-directory path. Both existing render smoke tests passed, but they do not detect the subtitle failure above.
- ASR error handling used a local HTTP mock and a fake credential; no real ASR service was called. Windows and Linux were not exercised locally.
- At review time, GitHub CI, scoped smoke, and CodeQL runs were
action_required; the visible[code]smithcheck was skipped. These are not passing CI evidence.
…keep subtitles on the timeline (1.5.0)
|
Re-reviewed all seven items on the new head Note on the head you reviewed: you tested [P1] 1. Output containment — fixed (
|
…peech-rate alignment; docs in English (1.6.0)
…d-round review fixes (1.7.0)
Third review round — every finding fixed, plus a review of the fix itself (1.7.0, tests 174 → 235)Both review rounds are now closed item by item. Below: what was wrong, what changed, and the command 1. CSS propagation did not work, and it failed silently in six different waysThe skill writes generated CSS into the project's
Fix. The whole generated body is now one # ⑤/⑥ and the whole vocabulary, one run:
node scripts/init-project.mjs <project> --check-css # every non-ok item listed, exit 1
node scripts/init-project.mjs <project> --upgrade-css # in-place, idempotent, .bak written
node --test "tests/*.test.mjs" # css-kit: 29 cases incl. ⑤/⑥Ordering bug found while fixing (worth flagging, it was mine). The leftover-copy cleanup ran 2. Stale CSS is no longer silent — it blocks
node scripts/capture.mjs <project> # exit 1 + issue list + the upgrade command
node scripts/capture.mjs <project> --allow-stale-css # explicit opt-out, warns and continues3. Wrong artefacts (highest priority)
4. Six functional defects — each one a documented way to get a wrong file
5. Packaging and the validation entry point (a green light that proved nothing)The host validator scans node publish/validate-plugin.mjs
# 2/3 指纹一致: 52 个文件逐字节相同(sha256)
# 3/3 运行上游校验器 … OK plugin Wzdhehe/html2video-for-mcodeThe scoped workflow now runs 6. A standards/spec review of this change set — what it caughtThis diff was then reviewed against its own spec and the repo's documented conventions. The real
7. EvidenceThe suite needs ffmpeg, ffprobe and Chromium (any of Deliberately not changed (disclosed rather than hidden):
|
… flag 去重/VALUE_FLAGS 清理 + 文档措辞改真(235→236)
… 上次只改了本地, PR 分支上一直是旧枚举版)
|
Fourth review pass (standards + spec axes) over the published diff — four real findings, all fixed in 1.7.1 ( 1. The corrected smoke workflow had never been pushed. The 1.7.0 entry described a workflow that runs 2. This Plugin would have reddened the monorepo's own CI. 3. The 1.7.0 README sentence "the rendering suites fail rather than skip" was itself wrong — it rested on an observation made where 4. Plan B2's third manifest check was claimed but not implemented. The 1.7.0 comment said Smaller items from the same pass: Evidence Remote bytes re-verified after the pushes: skill repo |
|
Thank you for both reviews. They targeted
Two notes on your Validation section. First, the CI runs marked If any of these still reproduces on |
…ight 守卫(无工具 ubuntu CI 不再红) + 沙盒证据数字修正(236→237)
|
Final audit round (1.7.2, commits
Updated evidence, all reproduced today: Version is 1.7.2 in both |
What changes
Add Plugin:
html2video-for-mcodeatplugins/Wzdhehe/html2video-for-mcode.A Skill that turns a topic, outline, or script into a narrated MP4: HTML slides with staged
entrance animations, a TTS voiceover, burned-in subtitles, and an ASR pass that verifies the
voiceover says what the script says.
User value
After installing, a MiniMax Code user can ask in plain language:
and get:
What makes it more than a slide exporter:
derived from the TTS audio via ffprobe, so the picture can never lag behind the voiceover.
is just a headline.
screen-recording.
images, external resources, or entrance animations without an animation class: the silent
failure modes that otherwise ship a broken-looking video while every script reports success.
Plugin submission checklist
plugins/<github-owner>/<plugin-name>.plugin.jsonname matches the Plugin directory.README.mdincludes a real example prompt and expected result (bilingual:README.md+README.zh-CN.md).LICENSEandplugin.jsondeclare an open-source license (MIT).(Node 18+, ffmpeg/ffprobe, Playwright Chromium; MiniMax API key or Token Plan for voice and
ASR; Windows/macOS/Linux; PowerShell caveat documented).
(
api.minimaxi.com/api.minimax.iofor ASR only when invoked; voice via mcode connectorsor
mmx-cli; image fetching only from URLs the user passes; no telemetry).are included. The ASR script reads its key from an environment variable or CLI flag at
runtime and never writes it.
TODOhas been replaced.publish/validate-plugin.mjs: it stages the Plugin tree into the host checkout, verifies all 52 files are fingerprint-identical (sha256) to the source tree, then runs the upstream validator →OK plugin Wzdhehe/html2video-for-mcode, exit 0. (Validating the host'snpm run checkalone is not sufficient: it scans the staged copy under_official-plugins/plugins/**, so a stale staged copy yields a green result that proves nothing.)Evidence
All 237 skill tests pass, with 0 skips, in the development tree and in both published trees. When ffmpeg / ffprobe / Chromium are absent (the monorepo's own root-level
node --testruns in exactly that environment), every test that needs one of them skips with its stated reason — verified in two isolated tool-less sandboxes (symlinks/junctions creatable, and not creatable), both reporting 0 fail and 23 skipped with stated reasons — and the scoped workflow installs them and runs the whole suite for real. The host repository's owntest/hosted-plugins.test.mjscontains a symlink fixture that fails on a Windows checkout without Developer Mode (EPERM: operation not permitted, symlink …); that is a pre-existing host-side issue, it reproduces on a clean checkout without this Plugin, it passes on the CI'subuntu-latest, and this PR does not touch it. The part ofnpm run checkthat inspects Plugins passes with exit code 0 when the staged copy is current.Manual end-to-end test (Windows, Node 24, ffmpeg-static):
plan-timings.mjs→ every slide duration andstage entrance time derived from measured audio.
check-slides.mjscorrectly rejects slides with undefined CSS variables (--coral-a/--coral-b),missing images, external font links, and
data-stagewithout an animation class; clean slides pass.capture.mjs --mode motionproduced 143 frames for an 8.6s slide; frame-diff (PSNR) confirms thestaged entrance actually renders at its scheduled time (
infbefore the entrance, ~14 dB across it).build-video.mjs --asrproduced a 14.20s MP4 matching the expected duration exactly, full decodeclean,
out/subs.srtgenerated, and per-sentence ASR parts produced.#FFB84Don white)is rejected with a non-zero exit code, a compliant one (
#C2410C) passes.traditional characters (Cantonese voice) and mismatched numbers fail with exit code 1.
Full disclosure of dependencies, network access, and data handling is in the Plugin README.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.