@gitruck/cli 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,84 @@
1
1
  # 更新日志
2
2
 
3
+ ## 未发布
4
+
5
+ ### 文档:`gtrk-tools` 图纸写明 `audio_tts_clone` 可选出字幕(link-add-tts-subtitle-output-cli 3.2)
6
+
7
+ 输入列补 `--subtitle-format <fmt>`(可选、缺省不出、不额外计费、取值以服务端为准),产物列补另产 `tts-<音色代号>.srt`(服务端降级时不留空文件);
8
+ 新增守卫 `test/skill-tools-tts-subtitle.test.mjs` 按列校验,防止文案被改回。
9
+
10
+ ### 加:文字模板候选态可按分类过滤(add-text-template-category 2.2)
11
+
12
+ `gtrk mg fetch --source text [检索词] --category 打字机` 先按目录分类圈池子再检索,JSON 多返回 `category` 与 `categories`;
13
+ 分类不存在时零候选并列出可用分类,不会退回成「不过滤」。取块态给了 `--category` 就要与模板分类对得上,对不上直接拒。
14
+ ⚠️ `--category overlay|fullscreen` 是 registry 路的不透明度品类,文字模板路收到这两个值会当场报错,并指路到 `--slot <beat> --project <dir>` 派单模式。
15
+
16
+ ### 改:B-roll 云端编排版本不一致时,告警不再列「命中旧幂等条目」这条成因(link-arrange-decision-pin-echo 9.7)
17
+
18
+ 服务端已把决策层版本钉进幂等键,且入键前写下的条目已随 24 小时有效期排空(2026-09-16 生产核实:
19
+ 新鲜请求与逐字节重放都回传当前版本、重放不二次计费)。这条成因在当前部署下不可能发生,继续列出只会把排查引向不存在的地方。
20
+ `IDEM_KEY_PINNED_DEPLOYED` 改为 `true`;服务端若回滚到版本钉入键之前,须改回 `false`。
21
+
22
+ ## 1.2.5(2026-09-14 定版,2026-09-15 发布)
23
+
24
+ > 下面四条补录于 2026-09-16:**它们随 1.2.5 一起发出去了,但当时漏写了用户面条目**。
25
+ > 判据取自 registry 拉回的 `@gitruck/cli@1.2.5` 包体(`dist/index.js` 里的运行期串),
26
+ > 不是本地源码——本机全局 `gtrk` 是指向开发仓的符号链接,照它判会把未发的算进来。
27
+ > 已发的 1.2.5 代码切在 `69a1f51`:`gate-mg-visual-job` 与「本地编译补校验」**不在这一版里**。
28
+
29
+ ### 修:`maxWidth` 的文字层换画幅会被挤窄(fix-text-ir-maxwidth-shrink)
30
+
31
+ 编译器给带 `maxWidth` 的文字层补 `width:max-content`。原先只给 `max-width`,
32
+ 块级盒会占满父宽,居中与右对齐算出来的落点因此偏。
33
+
34
+ ### 加:满屏槽位必须真有实心底(gate-fullscreen-slot-needs-solid-bed)
35
+
36
+ `dispatch.mg` 的 `category:"fullscreen"` 表达「这段 MG 盖住画面」,此前**声明了也不会兑现**——
37
+ 信号打过(`x-category-opaque`),但走灰字 `log.info`、夹在一模一样的 `x-soft-alpha` 之间、
38
+ `exit 0`,等于没打。现在拿不出满幅实心底就**致命拒落盘**,并给两条出路(改 `overlay`/补 `canvas.bg`)。
39
+ 配套:`dispatch.mg[].bg` 这个一直没有消费方的字段接上了——取块时钉进 IR 的 `canvas.bg`,
40
+ 声明当场兑现。**判据只取产物不取出身**:按「这颗是不是文字模板」写的闸,在加档上线当天就会错。
41
+
42
+ ### 修:`mg lay` 拿会漂的 `track_index` 当自产轨主键(fix-mg-lay-track-identity)
43
+
44
+ 契约明写它会漂、MUST NOT 当身份判据;客户端保存时按 `10+i` 重发,还会按有无物化视频劈轨。
45
+ 失败形态是「剥一半」(静默重复叠加)与「误剥用户轨」。改用内容指纹,口径照抄 `matrix-lay`
46
+ 那边早修过的成熟实现。
47
+
48
+ ### 改:随包文字模板目录刷到 `v2026-09-15.1` / 103 件
49
+
50
+ ### 修:`mg fetch --source text --slot` 派单模式必败(fix-mg-fetch-text-slot-identity)
51
+
52
+ 真机上这条命令**从来没成功过**:
53
+
54
+ ```bash
55
+ gtrk mg fetch --source text --pick tfx-type-terminal --slot B05 --project <工程>
56
+ # → composition_id "B05" / lint 致命 1-cid-expect / 不落盘
57
+ ```
58
+
59
+ 两处不对。① `--slot` 收的是 beat id(`B05`),而派单里的 `composition_id` 是
60
+ `<工程slug>-<beatId>`(`t07-B05`)——铺轨与 `mg lint --dispatch` 都按后者对账,旧实现却把前者
61
+ 直接当 id 用,`dispatch.json` 一个字没读。② 取到的模板 HTML 原样送 lint,而模板内的
62
+ `data-composition-id` 恒为模板 id、期望 id 恒为 `<slug>-<beat>`,两者永远不等 ⇒ 必然致命。
63
+
64
+ 文字模板是 `ir` 态、**不能直改 HTML**(改一字节就掉成 `detached`,云端再也调不动),
65
+ 所以钉 id 的合法路径只有一条:改内嵌 IR → 走 `mg compile` 同一条本地编译链重编。现在命令替你做:
66
+
67
+ - 派单模式的 `composition_id` / 坑位包络 / `category` 全部取自 `dispatch.mg` 那条(与中性块
68
+ `registry` 路共用同一份 `matchSlot`,两条路不再各写一份);
69
+ - 内嵌 IR 的 `id` 钉成期望 composition_id,`canvas.duration` 钉到**坑位包络 + 0.3s 余量**
70
+ (铁律⑦),且**原本贴在模板末尾的层跟着钉**——不钉的话坑位长于模板时,那些层会在原时长处
71
+ 被隐藏,后半段元素凭空消失;
72
+ - 重编产物自证仍须是 `ir` 态,否则报错零落盘;`id` 与时长都没改时**原字节落盘**,不重编。
73
+
74
+ 独立模式同病一并修:`--as` 过去只改文件名、不改颗粒内部 id;`--duration` 在 text 路被**静默忽略**
75
+ (命令面照收、代码里根本没这个字段)。现在 `--as` 改写 IR `id`、`--duration` 钉 `canvas.duration`,
76
+ 且 `--slot` 与 `--duration` **互斥**(派单的包络由 `track_st` / `track_ed` 定,显式给时长会与它打架)。
77
+
78
+ 另两条顺带:镜像块自身不是 `ir` 态时**报错零落盘**(那是发布事故,静默落一颗改不动的颗粒,
79
+ 用户要到 `mg edit` 被拒才发现);派单 `category` 透传给 lint,槽位派 `fullscreen` 而模板是透明叠加时
80
+ 报**非致命**的 `x-category-opaque`——不拦落盘,但提醒你给这颗补一层全幅实心底。
81
+
3
82
  ## 1.2.4(2026-09-14)
4
83
 
5
84
  ### `gtrk mg` 文字模板三口:`fetch --source text` / `compile` / `edit`(add-text-template-source)
package/README.en.md CHANGED
@@ -39,7 +39,7 @@
39
39
  | 🎞️ | `gtrk render` | Render a gtrk project (EDL) locally → finished mp4 (requires ffmpeg); composites **every visible overlay layer** in contract z-order (B-roll and other overlay video tracks + MG particles; `hidden` tracks stay out); output frames are allocated against the **cumulative** timeline (per-clip rounding never accumulates, so the picture cannot drift away from the voiceover); runs a QC pass afterwards and writes `.qc.json` (`--no-qc` skips it); picture-in-picture clips get their `clip_transform` (scale / position / rotation / opacity), `border_radius` corners and `clip_mask` shape masks (ellipse / rounded rectangle / heart / diamond / star, feathered) composited locally, visually matching the client preview. ⚠️ MG particles that miss the cache are cloud-rendered and **billed** (estimate + confirmation first; `--no-particles` renders particle-free at zero cost) |
40
40
  | 🔬 | `gtrk qc <cut>` | Final-cut QC: one decoding pass over the whole file for flash frames, black/frozen frames, clipping, silence and audio/video drift, each with a timecode; `--gtrk <project>` enables project-aware detection of **intra-clip cuts**, `--fail-on error\|warn\|never` gates pipelines via the exit code |
41
41
  | 🔎 | `gtrk matrix` | B-roll retrieval + **candidate track laying**: consumes the FILM_BROLL dispatch → produces a candidate list + downloads preview proxies and lays N candidate tracks (`--lay N`, default 1; open it in opencut and toggle track visibility to compare; `--lay 0` produces the list only); `matrix search "<query>"` is a one-off ad-hoc search; `matrix fetch <clip_id...>` pulls raw footage during the fine cut (free re-signing + download for already-granted materials, drag straight into Jianying); **local-footage mode**: `matrix index --dirs <folders>` builds a slice-free index → `--local --dirs` retrieves and lays tracks (**your footage never leaves your machine**) → `matrix lay` consumes the (editable) plan; `matrix describe` understands candidates on demand |
42
- | 🎨 | `gtrk mg` | MG motion-graphics particle laying: consumes the MG dispatch → lays html-particle assets (transparent overlay / full-screen bed, produced by your show's MG skill) into the `.gtrk` `beat_track`; `mg lint <particle.html>` runs the statically checkable subset of the house rules, `mg status --project <dir>` is an orchestration dashboard; `mg render <particle.html> --duration <sec>` renders a single particle in the cloud, independent of any project, into a Jianying-readable qtrle transparent MOV (the fine-cut supplement channel); aux overlay particles can be layered on the same span (one beat derives a main particle plus `-aux<n>`). The old name `gtrk rrv` remains as a deprecated alias; `gtrk mg fetch` pulls neutral block skeletons from the HyperFrames registry (offline snapshot candidates, three-source fetch with our mirror first, mechanical rewrite then lint); `gtrk mg fetch --source text` pulls Tonghe's own text-effect templates (finished, no mechanical rewrite), paired with `gtrk mg compile` (edit the IR and recompile, 0 credits) and `gtrk mg edit --say` (natural-language rewrite, billed per candidate) |
42
+ | 🎨 | `gtrk mg` | MG motion-graphics particle laying: consumes the MG dispatch → lays html-particle assets (transparent overlay / full-screen bed, produced by your show's MG skill) into the `.gtrk` `beat_track`; `mg lint <particle.html>` runs the statically checkable subset of the house rules, `mg status --project <dir>` is an orchestration dashboard; `mg render <particle.html> --duration <sec>` renders a single particle in the cloud, independent of any project, into a Jianying-readable qtrle transparent MOV (the fine-cut supplement channel); aux overlay particles can be layered on the same span (one beat derives a main particle plus `-aux<n>`). The old name `gtrk rrv` remains as a deprecated alias; `gtrk mg fetch` pulls neutral block skeletons from the HyperFrames registry (offline snapshot candidates, three-source fetch with our mirror first, mechanical rewrite then lint); `gtrk mg fetch --source text` pulls Tonghe's own text-effect templates (finished, no mechanical rewrite; the dispatched `composition_id` and the slot duration are pinned into the embedded IR and recompiled through the same local compiler, so the particle stays in the `ir` state), paired with `gtrk mg compile` (edit the IR and recompile, 0 credits) and `gtrk mg edit --say` (natural-language rewrite, billed per candidate) |
43
43
  | 🎙️ | `gtrk project init` | Audio-first project bootstrap: build a `.gtrk` project from a voice-over — main path `--tts-task <task_id>` references a completed TTS task (fetches the audio plus sentence timecodes directly, zero ASR); fallback path `--audio`+`--transcript` takes your own voice-over as a pair. Once landed, `gtrk split --project` continues the production pipeline as usual |
44
44
  | 🎼 | `gtrk audio lay` / `tighten` | Audio-track atoms: `lay` appends an audio track to a `.gtrk` project (BGM/score; idempotent same-source replacement, no track pile-up); `--beat-align` runs cloud analysis and **pins the BGM’s emotional peak onto the cut’s climax**, tiling outward on bar lines and tiling **not at all** when both sides are already long enough (billed once; the climax comes from the `split.beats` criterion chain and can be overridden with `--climax <track-sec>`; `--no-loop` lays only the anchored span and leaves head/tail silence; without a key / on failure / when the track has no highlight it degrades to no anchoring and the command still succeeds). `tighten` tightens the pauses between sentences in the voice-over (purely local, zero billing; only silence straddling a sentence boundary is compressed, within-sentence breaths untouched) |
45
45
  | 🎯 | `gtrk audio align` | Audio-video alignment part (fully local, zero billing): cross-correlates an external audio recording (lav mic / recorder) against the video to measure offset + confidence; high confidence swaps the track directly (video stream untouched byte-for-byte), low confidence emits an alignment project for the client timeline, then `--resume` reads the confirmed offset back; `--offset` swaps at an explicit offset |
package/README.md CHANGED
@@ -625,6 +625,7 @@ gtrk matrix lay --project <目录> [--plan <path>] # ③ 消费(
625
625
  - **render**(`gtrk mg render <颗粒.html> --duration <sec> [--out <dir>] [--yes]`):**脱离工程**把单颗颗粒云渲成剪映可读的 qtrle 透明 alpha MOV(精剪补给口——粗剪导剪映后缺一颗动态图,不回客户端就能补)。链路 = lint 前置(包络 = `--duration`,任一致命项本地拦截、零提交零计费)→ **计费预估确认**(实时查价;CLI 无本地 HTML 渲染引擎,独立颗粒唯一路 = 云渲计费任务,`--yes` 跳过确认)→ 内联提交云端 → `<composition_id>.mov` 落盘 + `task.json`/`result.json` 面包屑(崩溃可凭 task_id 恢复)。**射程**:首发只出 qtrle(`--format webm` 明确拒绝,剪映不吃 VP8-alpha)、只收 1920×1080 颗粒(契约未开竖屏/异形口)、`--duration` 必填。产物不进 `.gtrk`、不写剪映草稿目录;qtrle 无损体积偏大,适合秒级颗粒。注意与 `gtrk render`(整片成片渲染)同词不同物。
626
626
  - **fetch**(`gtrk mg fetch <检索词|块名> [--top 3] [--all]` / `gtrk mg fetch --pick <块名> --slot <beat> --project <dir>` / `--pick <块名> --as <composition_id> --duration <sec> [--out <dir>]`):**registry 中性颗粒源**——没建栏目也能出 MG。候选态**离线**(快照随包、钉死来源 commit)按检索词列 2–3 件(含 compat 标记与海报链接);取块态按三源顺序取块(我方镜像优先、jsdelivr、GitHub raw,每源 5 s,**逐源 sha256 强校验**,三源皆败零落盘)→ 机械改写八条(`<template>` 包裹 / 改 id / 去 data-start 贴坑位 / 实心底下沉子层 / GSAP 源换契约 CDN / 字体换运行时镜像可证的 CJK 字体 / 时长贴坑位 / 信箱缩放不拉伸)→ `gtrk mg lint` 致命项不过不落盘 → 落 `<project>/mg/<composition_id>.html`。**骨架不是成品**:返回的 `editable`(文案 / 数值数组 / 色值)MUST 按 beat 与栏目改写后再铺。契约当前只收 1920×1080 颗粒,其它画布拒绝;`excluded` 件拒取,`review` 件(canvas / 铁律 8 高危形态)可取但须真渲验收。`GITRUCK_MG_REGISTRY_BASE` 可整体覆盖取块前缀。
627
627
  - **fetch --source text**(`gtrk mg fetch --source text <检索词> [--top 3] [--offline]` / `--pick <模板 id> --slot <beat> --project <dir>` / `--pick <模板 id> --as <composition_id> [--out <dir>]`):**同合云自家的文字特效模板库**——与中性块是两条路。模板是我方 clean-room 重写的**成品**(配色与排版已做过),**不做机械改写、MUST NOT 直接改 HTML**。每颗内嵌产生它的 IR 与双哈希,颗粒因此自带出身证明(三态 `ir` / `detached` / `html`);手改一个字节就掉成 `detached`,云端改写会拒绝它(`gtrk mg lint` 报非致命的 `x-ir-detached`)。目录走**远端择新、随包兜底**:优先取镜像上的 `catalog.json` 按 `version` 择新并缓存 24h,三源皆不可达时回落随包那份并**明示**(候选态因此永远离线可用)。取块仍逐源 sha256 强校验,三源皆败零落盘。`GITRUCK_TEXT_TEMPLATE_BASE` 可整体覆盖取块与目录前缀。
628
+ **落点与时长由命令钉定**:派单模式的 `composition_id` 取自 `dispatch.mg` 那条(`<工程slug>-<beatId>`,不是 `--slot` 收的 beat id),颗粒内嵌 IR 的 `id` 与 `canvas.duration` 被钉到「期望 id」与「坑位包络 + 0.3s 余量」(铁律⑦,贴模板末尾的层跟着钉),再走 `mg compile` 同一条本地编译链重编——产物仍是 `ir` 态,`1-cid-expect` 天然对得上。独立模式 `--as` 同样改写颗粒内部 id,`--duration` 钉时长;`--slot` 与 `--duration` 互斥。两者都没改时原字节落盘。
628
629
  - **compile**(`gtrk mg compile <ir.json> [--out <dir>]`):把 IR 交给云端**确定性编译**成颗粒(**0 积分**)。改字、换色、改字号描边阴影、改时长都走它——改 IR 再编,比手改 HTML 干净,且颗粒保持 `ir` 态(云端还能继续调)。**本地没有编译器**是有意的:第二份编译器意味着第二套产物字节,而三态身份判的就是字节。
629
630
  - **edit**(`gtrk mg edit <颗粒.html> --say "<一句话>" [--n 1|3] [--pick <k>] [--yes]`):自然语言改写文字模板颗粒,经云端模型链出候选。`--n` 只收 1 或 3,**它就是计费单位数**(2 积分/候选,首次与改写同价、无免费次数)。`detached` / 无内嵌 IR 的颗粒**本地就拒**,不提交云任务、不花钱。候选带 `scope`:`L1` = 在模板可调范围内、`L2` = 越界即新生成(**不是失败**);服务端说做不到时给一句 `refusal`,命令如实转述并以非 0 退出码区分于网络错误。不给 `--pick` 就只落候选不动原文件;给了才替换并留 `<cid>.bak.html`。
630
631
 
@@ -85,7 +85,32 @@
85
85
 
86
86
  ## 八条铁律(违反任一条 → 整片渲染失败 / 颗粒冻结 / 全黑 / 坑位内突兀消失 / 画面被切成横带、内容纵向重复叠印并逐帧闪烁)
87
87
 
88
- 1. **`<template>` 包裹根元素**:`<template><div data-composition-id="<id>" data-width="1920" data-height="1080">…</div></template>`。编译器取的是 `<template>` 内容;裸 `<div>` 会被判 "empty or could not be parsed" 整片失败。(1920×1080 为**当前引擎版本约束**,分辨率参数化预留——升版时以本契约新版为准。)
88
+ 1. **`<template>` 包裹根元素**:`<template><div data-composition-id="<id>" data-width="1920" data-height="1080">…</div></template>`。编译器取的是 `<template>` 内容;裸 `<div>` 会被判 "empty or could not be parsed" 整片失败。(**尺寸不再固定 1920×1080**,见下方「画幅」小节。)
89
+
90
+ > **画幅**(2026-09-16 改写,change `add-text-ir-aspect-agnostic-layout`)
91
+ >
92
+ > 原文写的是「1920×1080 为**当前引擎版本约束**,分辨率参数化预留」。
93
+ > **那句话已经过时,但不删——读者需要知道它为什么曾经是对的,否则下次还会有人按旧结论判断
94
+ > (2026-09-15 我自己就被它误导了整整一轮)。**
95
+ >
96
+ > - **曾经**:`fix-particle-subcomposition-scale` **之前**,颗粒声明尺寸与根合成尺寸不等
97
+ > 会被 `#stage` 的 `overflow` 裁掉、只渲左上一角(真机雷:opencut 720p 降采备料
98
+ > 根 1280×720 × 颗粒声明 1920×1080)。那时放行别的尺寸就是静默出坏片,
99
+ > 所以「只收 1920×1080」是**当时正确的**保护。
100
+ > - **现在**:该修复已上线并过无裁切真机验收。`html_animate_render` 按颗粒声明的
101
+ > `data-width/height` 挂载缩放,根合成尺寸本就是 `flags.width/height` 参数
102
+ > ⇒ **引擎不限画幅**。
103
+ > - **因此现在的口径是校验器口径,不是引擎约束**:颗粒声明尺寸 MUST 为正整数,
104
+ > 且 MUST **等于目标工程画幅**。
105
+ >
106
+ > ⚠️ **「引擎不限画幅」MUST NOT 被读成「随便什么尺寸丢进去都行」**:
107
+ > 挂载用的是**非等比** `transform:scale(w/dw, h/dh)`。同比例时它退化成等比(无害),
108
+ > **跨比例是拉伸变形,不是加黑边**——16:9 的颗粒进 9:16 工程会被纵向拉 3.16 倍。
109
+ > 所以「声明尺寸 == 目标画幅」这条不是形式要求,它就是防拉伸的那道闸。
110
+ >
111
+ > 文字模板(`text-v0` IR)据此做成了**一份 IR 通吃横竖屏**:IR 恒住在 1920 宽的参考系里,
112
+ > 画幅是**编译入参**,编译期按九宫锚点定位、所有像素量乘 `k = 目标宽 / 1920`。
113
+ > 手写颗粒没有这条路,仍需按工程画幅各写一份。
89
114
  2. **GSAP `paused` 时间线 + 注册**:`var tl = gsap.timeline({paused:true}); … window.__timelines = window.__timelines || {}; window.__timelines["<id>"] = tl;`。`<id>` 必须等于根的 `data-composition-id`。
90
115
  3. **确定性**:禁用 `Math.random` / `Date.now` / 无参 `new Date()`(过不了引擎 StaticGuard)。要"随机感"用固定种子/解析式/递归生成(见「确定性配方」)。
91
116
  4. **自包含 + 实心底下沉子层 + 透明度显式声明**(**2026-07-26 按真机实测改写**;原文「全屏颗粒给根设明确 `background`;透明颗粒根不设 background」**已作废**,见下方证据锚):颗粒不依赖外部文件(除脚本 CDN)。底色的**取值**由调用方按其栏目规则决定,本契约只管**摆在哪个元素上**。