@gitruck/cli 1.0.5 → 1.0.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/AGENT.md CHANGED
@@ -8,6 +8,9 @@
8
8
  > → 拉回 gtrk/剪映/PR 三方工程文件 →(可选)本地 ffmpeg 渲染成片 → 三端打开**。云端零改动、纯结构产物,
9
9
  > 源视频不出本地。结果/报告恒落盘 `result.json`,可按 `task_id` 秒级取回、无需重跑(见 §2.1 / §4)。
10
10
 
11
+ > **写/改 structure 级成片图纸**(旅拍 / 口播链 / 直播切片 / Vlog……)先过 `docs/成片型图纸公约.md`
12
+ > ——双模式命名(快速成片 / 逐步推进)、决策前置三条腿、MG 临场泛化的横切正本与自检清单都在那里。
13
+
11
14
  ---
12
15
 
13
16
  ## 产物落点纪律(全局 MUST · 本 playbook 与随包全部 skill 通用)
@@ -34,6 +37,21 @@
34
37
 
35
38
  ---
36
39
 
40
+ ## 工程文件改动纪律(全局 MUST · 2026-08-25 立)
41
+
42
+ - **agent MUST NOT 裸手改 `.gtrk` JSON。** 元素级编辑(挪位置 / 改时长 / 切开 / 改参数)
43
+ 一律走 **`gtrk patch`**。
44
+ - **为什么不是「小心点就行」**:`.gtrk` 一个片段的时码是**两套并存**的
45
+ (`clip_st`+`clip_ed` 与 `clip_st`+`duration`)。改 `duration` 不同步 `clip_ed`,
46
+ **客户端 importer 优先读 `clip_ed`** ⇒ 用的是陈旧出点;而**后端 Profile A 反而不强校验它**
47
+ ⇒ 没人报错。这是**静默失败**:命令说成功、你以为改了、实际没改。
48
+ - 另外轨道时基端点要落在 `video_rate` 的帧边界上,浮点秒累加会漂。这两件 `gtrk patch`
49
+ 都替你做(恒等式同步 + 帧对齐 + 写前全档校验 + 原子写回 + 机器可读回执)。
50
+ - **例外只有一个**:铺自产物的那几条既有链路(`gtrk matrix` 铺轨、`gtrk mg` 铺颗粒、
51
+ `gtrk audio` / `gtrk subtitle` 建新轨)—— 它们只动自己新建的东西,不改既有 clip 的时码。
52
+
53
+ ---
54
+
37
55
  ## 0. 一句话流程
38
56
 
39
57
  ```
@@ -85,6 +103,12 @@ gtrk transcript <本地视频.mp4> --json # 转成一个含总结/时
85
103
 
86
104
  ## 2. 核心命令:`gtrk oralcut <毛片>`
87
105
 
106
+ > **双轨收音的毛片先对轨**:用户有独立外录音轨(领夹麦/录音笔的 wav/mp3/m4a/flac)时,先跑
107
+ > `gtrk audio align "<毛片>" "<外录>"`(纯本地零计费)——自动互相关测偏移+置信度,高置信直接换轨
108
+ > 产 `<名>_extaudio.mp4`(视频流零像素改动),低置信产对齐工程交客户端拖齐后 `--resume` 读回;
109
+ > 然后拿换轨产物进 oralcut,转写与成片就都是外录声。已换好轨/无外录的毛片直接进,零差别。
110
+ > 场景编排细节见 `/gtrk-talking-head` 图纸 §二。
111
+
88
112
  | 参数 | 作用 | 缺省 |
89
113
  |---|---|---|
90
114
  | `<毛片>`(位置参数) | 本地口播原视频路径 | 必填 |
@@ -224,6 +248,71 @@ gtrk transcript "D:/素材/采访视频.mp4" --json
224
248
 
225
249
  ---
226
250
 
251
+ ## 2.4 元素级编辑:`gtrk patch`(改工程唯一入口)
252
+
253
+ ```bash
254
+ gtrk patch move --project <dir> --clip c2 --to 5.0 # 挪位置
255
+ gtrk patch trim --project <dir> --clip c2 --out -1s # 改时长(出点相对增量)
256
+ gtrk patch split --project <dir> --clip c2 --cut 5.5 # 切成两段
257
+ gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
258
+ gtrk patch set --project <dir> --total max # 改顶层总长(工程级)
259
+ ```
260
+
261
+ **寻址两条路**(互斥,二选一):
262
+
263
+ | | 用法 | 说明 |
264
+ |---|---|---|
265
+ | 按 id | `--clip <clip_id>` | 最常用。命中 video/audio **镜像对**时视为**一个编辑单元** |
266
+ | 按位置 | `--track <video\|audio\|beat>:<track_index> --at <sec>` | 命中条件 `track_st ≤ at < track_ed` |
267
+
268
+ ⚠️ **`--at` 是寻址参数,不是 split 的切点**;split 的切点是独立的 **`--cut`**。
269
+ 两者可同时给:`patch split --track video:0 --at 5.0 --cut 5.5` = 「定位 5.0s 处那个元素,在 5.5s 切开」。
270
+
271
+ ⚠️ **空档(gap)不能用 `--clip ""` 寻址** —— 契约允许多个 gap 共享 `clip_id=""`,它不构成地址;用 `--track/--at`。
272
+
273
+ **四个动作的参数**:
274
+
275
+ | 动作 | 参数 | 语义 |
276
+ |---|---|---|
277
+ | `move` | `--to <sec\|Nf>` | 只改落点,时长与源窗都不动 |
278
+ | `trim` | `--in` / `--out` | **相对增量**。`--in` 让源窗与轨上入点**同动**(标准 trim);`--out` 只改出点 |
279
+ | | `--set-in` / `--set-out` | 同上,但给**绝对时码** |
280
+ | | `--slip <delta>` | **只换源窗**:轨上落点与时长都不动。⚠️ trim-in 有两种业界语义,所以必须你显式选一种 |
281
+ | `split` | `--cut <sec\|Nf>` | 切点。两段各须 ≥1 帧;新片段 id 为 `<orig>-2` 递增 |
282
+ | `set` | `--muted` / `--no-muted` / `--volume <gain>` / `--opaque` | 元素级参数。`--volume` 是**线性增益不是 dB** |
283
+ | | `--total <sec\|Nf\|max>` | 顶层总长。**工程级 op,与元素寻址互斥** |
284
+
285
+ **通用**:`--dry-run` 只算不写;`--json` 回执到 stdout(人读日志转 stderr);
286
+ `--ops <file|->` 批量事务(一次读、全算、全校验、一次写;**任一条失败零写**并报第几条)。
287
+
288
+ **`--expected-revision <sha256>` — 跨命令写回断言**(并发写仲裁,你多半用得上):
289
+ `patch` 每次都会自己护住「本次读→改→写」这段窗口,但它护不到**你两条命令之间**的空隙——
290
+ 典型形态是「先 `--dry-run` 看一眼 → 用户在客户端顺手改了 → 你再真写」,第二条命令重新读盘、
291
+ 拿到的是新内容,于是**照写不误、把用户的改动覆盖掉**。
292
+ 做法:把上一条回执里的 `revision` 原样传给下一条的 `--expected-revision`;盘上内容一旦变过即拒写。
293
+ 缺省不传 = 只护进程内窗口(既有行为不变)。
294
+
295
+ **时码字面**:秒(`3.5` / `3.5s`)或帧(`105f`);相对量带正负号(`-1s` / `-2f`)。
296
+
297
+ **回执字段**:`applied`(是否真写了)、`revision`(工程当前内容指纹:写入成功=**落盘后的新值**、
298
+ 干跑=读取时刻的值)、`ops[]`(每条含 `action` / `scope` / `resolved` 定位三元组
299
+ `{track, clip_id, track_st}`、改前改后时码)、`warnings[]`、`preexisting[]`(入档既存问题,非本次造成)。
300
+ ⇒ **下一轮据 `resolved` 复核「我上轮改的还是这一个吗」**,据 `revision` 作下一条的 `--expected-revision`。
301
+
302
+ **它会拒你的几种情况**(都是零副作用、文件逐字节未变):
303
+
304
+ - 幻觉 id / `--track/--at` 没命中
305
+ - `clip_id` 真撞名(同轨重复 id)⇒ 列出候选,改用 `--track/--at`
306
+ - 镜像对上做**参数类**改动 ⇒ 参数是投影私有的,要 `--track` 指明改哪个投影
307
+ - 本次改动会造成时码不变量违规(如同轨重叠)⇒ 硬拒;**入档既存的**违规只报 `preexisting` 不阻断
308
+ - **写回冲突**:读进来之后工程内容被改过(客户端保存了实质改动 / 你传的 `--expected-revision` 已过期)
309
+ ⇒ 拒写并回 `conflict: {expected_revision, actual_revision}`。**处置:重读工程、在新内容上重算你的改动、再写**,
310
+ MUST NOT 硬覆盖。⚠️ 判据是**内容**不是时间戳——用户只是按了保存但一个字没改(内容逐字节相同)**不会**触发拒写
311
+ - 顶层 `duration` 键不在场时用 `--total` ⇒ 缺席自带「按末端机械算出」语义,新增该键会改消费与计费口径
312
+ - 只给 `--track` 不给 `--at` ⇒ v1 射程是**元素级**,不写轨对象上的键
313
+
314
+ ---
315
+
227
316
  ## 3. 产物结构 + 三端打开
228
317
 
229
318
  ```
package/README.en.md CHANGED
@@ -33,14 +33,15 @@
33
33
  | ⚙️ | `gtrk init` | Guided one-time setup (API key + Jianying draft folder), then forget about it |
34
34
  | 🩺 | `gtrk doctor` | Health check: config / cloud connectivity / Jianying folder / runtime in one shot |
35
35
  | 📦 | `gtrk deps` | Runtime assets: `status` shows where ffmpeg/fonts come from and under which licence, `install` fetches them from the Gitruck Cloud mirror (**must be triggered explicitly — never a silent auto-download**) |
36
- | 🤖 | `gtrk skills install` | Installs the 12 bundled CLI skills into the agents detected on this machine, via the generic `skills` adapter plus a gtrk supplement layer; `--all` covers every registered host |
36
+ | 🤖 | `gtrk skills install` | Installs the 14 bundled CLI skills into the agents detected on this machine, via the generic `skills` adapter plus a gtrk supplement layer; `--all` covers every registered host |
37
37
  | ⬆️ | `gtrk upgrade` | Upgrade the CLI to the latest version + refresh skills (config preserved); `--check` only reports |
38
38
  | 🎞️ | `gtrk render` | Render a gtrk project (EDL) locally → finished mp4 (requires ffmpeg); 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) |
39
39
  | 🔬 | `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 |
40
- | 🔎 | `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; **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 |
41
- | 🎨 | `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; 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 |
40
+ | 🔎 | `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 |
41
+ | 🎨 | `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 |
42
42
  | 🎙️ | `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 |
43
43
  | 🎼 | `gtrk audio lay` | Audio-track atom: appends an audio track to a `.gtrk` project (BGM/score; idempotent same-source replacement, no track pile-up); `--beat-align` runs cloud beat analysis and snaps the in-point to the nearest downbeat (billed once; degrades gracefully without a key or on failure) |
44
+ | 🎯 | `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 |
44
45
  | 🧰 | `gtrk tool <name>` | Single-shot tool family: image-to-camera-move, image/video matting, image black-border removal / aspect adaptation / cleanup / square conversion / LivePhoto, smart collage covers and vertical stitching (multi-image input), video black-border removal / aspect adaptation / stabilization / vaporwave filter / mechanical & semantic shot segmentation / motion highlights / AI subtitles, vocal-accompaniment separation / speaker diarization / pitch-and-tempo shift, piano-to-MIDI and piano restoration, audio denoising, silence removal, MAD, and more; `gtrk tool list` shows every input/output/live price/status. Single request, single result, shared runner — adding a tool means adding one descriptor |
45
46
  | 💬 | `gtrk feedback` | Tell us what feels wrong: `gtrk feedback "<one line>" --command <command>`. **Disclosed submission** — when an assistant files it for you it must first read the exact content back to you and only add `--disclosed` once you agree; in a pipe or any non-interactive environment, sending without that declaration is refused outright. Content is redacted before it leaves your machine (local paths, credentials, e-mail addresses, phone numbers and the like are replaced by shape), so what you are shown is exactly what gets sent |
46
47
  | 🚧 | `struct` | (planned) convert an existing gtrk project into the three formats |
@@ -219,7 +220,7 @@ Once installed, a single sentence in any agent invokes a gtrk skill:
219
220
  | ![Calling gtrk from an agent, example 1](assets/agent-example-1.png) | ![Calling gtrk from an agent, example 2](assets/agent-example-2.png) |
220
221
  | ![Calling gtrk from an agent, example 3](assets/agent-example-3.png) | ![Calling gtrk from an agent, example 4](assets/agent-example-4.png) |
221
222
 
222
- `gtrk install` installs the 12 bundled CLI skills (`gtrk-oralcut`·`gtrk-long2short`·`gtrk-splitter`·`gtrk-matrix`·`gtrk-mg`·`gtrk-ai-drama`·`gtrk-style-maker`·`gtrk-transcript`·`gtrk-tools`·`gtrk-music-visualizer`·`gtrk-cover`·`gtrk-travel-recap`) into the agents detected on this machine. The mechanism matches lark-cli: gtrk hands its local skill sources to the generic `skills` CLI, which owns agent detection, directory mapping and update rules; gtrk no longer hardcodes per-vendor paths.
223
+ `gtrk install` installs the 14 bundled CLI skills (`gtrk-oralcut`·`gtrk-long2short`·`gtrk-splitter`·`gtrk-matrix`·`gtrk-mg`·`gtrk-ai-drama`·`gtrk-style-maker`·`gtrk-transcript`·`gtrk-tools`·`gtrk-music-visualizer`·`gtrk-cover`·`gtrk-travel-recap`·`gtrk-live-slicing`·`gtrk-talking-head`) into the agents detected on this machine. The mechanism matches lark-cli: gtrk hands its local skill sources to the generic `skills` CLI, which owns agent detection, directory mapping and update rules; gtrk no longer hardcodes per-vendor paths.
223
224
 
224
225
  By default `~/.agents/skills` is the single source of truth, linked into each agent's compatible directory (junctions on Windows); where linking is unavailable the adapter falls back to copying. That way updates touch one canonical copy instead of letting duplicates drift apart. Common commands:
225
226
 
@@ -392,9 +393,48 @@ Finished cut × transcript projection → beat storyboard. **No positional argum
392
393
  >
393
394
  > **Dispatch entries carry their own `span:{from,to}`** (the utterance range that entry covers; `overlay` aux entries carry **their own** span, which may be a sub-range of the main beat's). **`track_st/track_ed` are a snapshot taken at projection time** — `gtrk mg` / `gtrk matrix` **re-project on the spot** when consuming them (see below), so after editing the talking-head track you do **not** need to re-run `gtrk split`; only a change to the split doc itself requires that.
394
395
 
396
+ ### `gtrk patch <move|trim|split|set>` — element-level editing (the only way to edit a project)
397
+
398
+ Edit the timecode or parameters of a single clip / gap / particle. **Agents must not hand-edit `.gtrk` JSON** —
399
+ a clip carries **two parallel timecode representations** (`clip_st`+`clip_ed` and `clip_st`+`duration`).
400
+ Changing one without the other is a **silent failure**: the desktop client reads `clip_ed` first while the
401
+ backend does not strictly validate it, so nothing errors out yet the render uses a stale out-point.
402
+ This command handles identity synchronisation + frame alignment + a whole-file check before writing.
403
+
404
+ ```bash
405
+ gtrk patch move --project <dir> --clip c2 --to 5.0
406
+ gtrk patch trim --project <dir> --clip c2 --out -1s
407
+ gtrk patch split --project <dir> --clip c2 --cut 5.5
408
+ gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
409
+ ```
410
+
411
+ | Flag | Purpose | Default |
412
+ |---|---|---|
413
+ | `--project <dir>` / `--gtrk <path>` | Project dir (auto-locates `gtrk/project.gtrk`) or an explicit path | — |
414
+ | `--clip <clip_id>` | Address by id. A video/audio **mirror pair** counts as one editing unit | — |
415
+ | `--track <kind:idx> --at <sec>` | Address by position (`track_st ≤ at < track_ed`). Mutually exclusive with `--clip` | — |
416
+ | `--to <sec\|Nf>` | Target position for `move` | — |
417
+ | `--in` / `--out` / `--set-in` / `--set-out` / `--slip` | The five `trim` semantics (first two relative, next two absolute, `--slip` shifts only the source window) | — |
418
+ | `--cut <sec\|Nf>` | Cut point for `split`. ⚠️ Distinct from the addressing flag `--at` | — |
419
+ | `--muted` / `--volume <gain>` / `--opaque` | Element-level parameters for `set` (`--volume` is linear gain, not dB) | — |
420
+ | `--total <sec\|Nf\|max>` | Top-level duration for `set` (project-scoped op, mutually exclusive with element addressing) | — |
421
+ | `--ops <file\|->` | Batch transaction: read once, compute all, validate all, write once; any failure writes **nothing** | off |
422
+ | `--dry-run` | Compute and validate only, do not write | off |
423
+ | `--json` | Machine-readable receipt on stdout (human logs go to stderr) | off |
424
+
425
+ > Time literals: seconds (`3.5` / `3.5s`) or frames (`105f`); relative values take a sign (`-1s`).
426
+ >
427
+ > The receipt carries `ops[].resolved`, a locator triple `{track, clip_id, track_st}` — use it on the next
428
+ > round to confirm you are still pointing at the same element.
429
+ > `preexisting[]` lists invariant problems that were **already in the file** (not caused by this run, not
430
+ > blocking); violations caused by this run mean **zero writes and a non-zero exit**.
431
+ >
432
+ > ⚠️ A gap cannot be addressed with `--clip ""`: the contract lets multiple gaps share that value, so it is
433
+ > not an address. Use `--track/--at` instead.
434
+
395
435
  ### `gtrk matrix` — B-roll retrieval + candidate track laying
396
436
 
397
- **No positional argument = consume the dispatch**: reads the `film_broll` queue from `split/dispatch.json` → dual-endpoint retrieval → produces the candidate list `split/broll-plan.json`, downloads preview proxies, and lays N candidate tracks in the project (open it in opencut and toggle track visibility to compare and choose). **`matrix search "<query>"` = a one-off ad-hoc search** (independent of any dispatch).
437
+ **No positional argument = consume the dispatch**: reads the `film_broll` queue from `split/dispatch.json` → dual-endpoint retrieval → produces the candidate list `split/broll-plan.json`, downloads preview proxies, and lays N candidate tracks in the project (open it in opencut and toggle track visibility to compare and choose). **`matrix search "<query>"` = a one-off ad-hoc search** (independent of any dispatch). **`matrix fetch <clip_id...>` = pull raw footage during the fine cut** (project-independent; see below).
398
438
 
399
439
  | Parameter | Purpose | Default |
400
440
  |---|---|---|
@@ -407,7 +447,9 @@ Finished cut × transcript projection → beat storyboard. **No positional argum
407
447
  | `--score-floor <f>` | Fill-confidence floor: segments scoring below this are not used and the slot stays empty — empty spots **expose the black bed track** (laid by default; only `--no-black-bed` exposes the main track instead). Raising it shrinks the candidate pool, and a span that cannot be filled at all becomes pure black over the talking-head, so check the hole warnings after adjusting | `0.2` |
408
448
  | `--no-black-bed` | Do not lay the solid black bed track (one is laid by default) | laid by default |
409
449
  | `--force-relay` | Strip and re-lay even when you have already edited a candidate track in the client (by default it refuses and keeps that track) — **this deletes the `broll-raw-*` material registrations of confirmed source clips, orphaning those files on disk** | off |
410
- | `--out <file>` | Write ad-hoc results to a file | stdout |
450
+ | `--out <file>` | Write ad-hoc results to a file; for `matrix fetch`, the raw-footage output directory (never the Jianying draft folder) | stdout / `./matrix-fetch/` |
451
+
452
+ **`matrix fetch <clip_id...>` (pull raw footage during the fine cut, project-independent)**: for materials you have **searched with billing** (hits in the grant ledger), re-signs fresh download links for free by clip_id and lands them as `<clip_id>.<ext>` — when the rough cut is already exported to Jianying and one more B-roll is needed, you can pull the raw file locally and drag it straight in without going back to the client app. The flow is always **two-step**: pick clip_ids from `matrix search` → `matrix fetch` to pull (fetch itself is free of charge, performs no search, and has no confirmation gate). **Grants are persistent**: the 24h-expiring signature is no obstacle — a clip searched three days ago still fetches fine. Ungranted items are reported one by one as "not granted" with the way out (run one billed search for that keyword to obtain the grant) and never block the rest; one batch ≤ 500. **The initial scope covers video clip raws only** (the re-sign surface for image/audio materials is not open yet; such ids land in missing with a hint). Outputs never enter `.gtrk` and never land in the Jianying draft folder; material added inside Jianying does not flow back into the project (export is one-way).
411
453
  | `--json` | Machine-readable: stdout carries only the result JSON | off |
412
454
 
413
455
  > **Beat windows are re-projected on the spot**: in dispatch-consumption mode, **before the first cloud retrieval**, each beat's `[track_st, track_ed]` is recomputed from "`transcript` × the current `.gtrk`", and retrieval, `broll-plan.json` and track laying all use the recomputed values (`--lay 0` obeys the same rule; ad-hoc `search` is unaffected). The timecodes in `dispatch.json` are only a **projection-time snapshot**, used as a fallback solely when re-projection is impossible — **so after editing the talking-head track you can run this command directly without re-running `gtrk split`**. `--json` always emits `reprojection:{mode,degraded,reason?,drifted,max_offset,shrunk,dropped}`; beats with **zero surviving span** after re-projection are skipped (no retrieval quota is burned on them and nothing is laid). If re-projection is impossible (missing transcript / project not found / no talking-head material on the main track) → it **degrades to the snapshot with a warning and a `--json` marker**, while retrieval and the plan still complete instead of hard-failing; behaviour for non-v1 projects is unchanged (the plan lands first, then the version gate exits non-zero).
@@ -437,9 +479,9 @@ gtrk matrix lay --project <dir> [--plan <path>] # ③ consume the
437
479
 
438
480
  Orchestration recipes (pure matching / describe-then-lay / time-window / footage-first scripting / three-layer stacking) and the plan-editing contract live in the bundled skill `/gtrk-matrix`.
439
481
 
440
- ### `gtrk mg` — MG motion-graphics particles (lay / lint / status)
482
+ ### `gtrk mg` — MG motion-graphics particles (lay / lint / status / render)
441
483
 
442
- Consumes the `dispatch.mg` dispatch landed by `gtrk split`, laying html-particle assets produced by **your show's MG skill** into the `.gtrk` project's `beat_track`. Three modes are dispatched by the first positional word: **no argument = lay**, `mg lint <file>` = single-file validation, `mg status` = orchestration dashboard. The old name `gtrk rrv` remains a deprecated alias (it prints a notice; prefer `gtrk mg`).
484
+ Consumes the `dispatch.mg` dispatch landed by `gtrk split`, laying html-particle assets produced by **your show's MG skill** into the `.gtrk` project's `beat_track`. Four modes are dispatched by the first positional word: **no argument = lay**, `mg lint <file>` = single-file validation, `mg status` = orchestration dashboard, `mg render <file>` = standalone particle cloud render (project-independent; the fine-cut supplement channel). The old name `gtrk rrv` remains a deprecated alias (it prints a notice; prefer `gtrk mg`).
443
485
 
444
486
  | Parameter | Purpose | Default |
445
487
  |---|---|---|
@@ -448,6 +490,10 @@ Consumes the `dispatch.mg` dispatch landed by `gtrk split`, laying html-particle
448
490
  | `--only <beat>` | Run a single beat only (takes a **beat id** such as `B12`, not a `composition_id`; the main particle and its `-aux<n>` overlays are selected together). **True incremental merge**: only the matched particles are re-laid, and every other already-laid particle on the track (including your manual tweaks) is preserved as is | all |
449
491
  | `--lint-only` | Lint only; lay nothing and write nothing back | off |
450
492
  | `--replace-all` | Explicitly authorize a **full track reset**: no incremental preservation, the whole track is stripped and re-laid — **this deletes every other already-laid particle on the track** | off |
493
+ | `--duration <sec>` | **Required in render mode**: the explicit duration anchor (seconds) — standalone mode has no slot envelope, so this value is at once the lint envelope, the output duration and the billed duration | — |
494
+ | `--format <fmt>` | Render-mode output format: `qtrle` only for now (Jianying-readable transparent MOV; `webm` is explicitly refused — Jianying cannot read VP8-alpha) | `qtrle` |
495
+ | `--out <dir>` | Render-mode output directory (never writes into the Jianying draft folder — dragging into Jianying is your move) | `./mg-render/<composition_id>/` |
496
+ | `--yes` | Render mode: skip the billing-estimate confirmation | off |
451
497
  | `--json` | Machine-readable: human logs go to stderr, stdout carries only the result JSON | off |
452
498
 
453
499
  - **Laying** (`gtrk mg --project <dir>`): reads `dispatch.mg` → for each beat takes the source particle from `<project>/mg/<composition_id>.html` → lints → lays it into `beat_track` and atomically writes `struct_meta.mg` back into `.gtrk` (self-produced tracks are registered idempotently in `lay_tracks`; a re-lay strips the previous self-produced items before appending, and user-added tracks are never touched). Whether a particle is a "transparent overlay" or a "full-screen bed" is decided by `opaque`, inferred from the particle HTML's root `background`. Beats with a missing HTML file or a failed lint are counted in `skipped` and do not block the rest.
@@ -461,6 +507,7 @@ Consumes the `dispatch.mg` dispatch landed by `gtrk split`, laying html-particle
461
507
  - **House rule ⑧, repeated-primitive merging** (`8-primitive-merge`, **always non-fatal, never blocks laying**): identifies mergeable batches of `line` / `rect` / `path` / `polyline` / `polygon` that are "created inside a loop, or by a named factory called in a loop; landing under the same parent node; and not driven by per-element animation". Only batches whose purely numeric loop trip counts sum to **≥ 8** under the same parent are reported; when bounds involve `.length` or named constants and cannot be computed it still reports "count unknown" without constant folding; elements with per-element `gsap.set` / tweens, or used as a tween's first argument, are excluded. This item only points out "there is a batch of repeated primitives here that can be merged **losslessly**, pixel-identical after merging" — it is **not a risk verdict**: a hit does not mean the particle will reproduce a defect, and a miss does not mean it is safe. The real criterion remains sampling frames from a real render.
462
508
  - **Callback and seek semantics** (`x-callback-driven` / `x-engine-api-override` / `x-raf-interval`, **always non-fatal, never blocks laying**): aligned with the same-named section of the contract (added 2026-07-26). GSAP `seek(t)` suppresses callbacks by default → tweened properties still interpolate, but DOM writes inside `onUpdate` do not run, and the failure mode is **the picture freezing at its initial state rather than going black**. The contract places the guarantee on the **engine side** (fixing a frame MUST use `seek(t,false)` / `time(t)` / `progress(p)`), so a particle **driving its picture from callbacks is a compliant style**; these three lint items are merely **sentinels**: `x-callback-driven` = callbacks write the DOM with no seek fallback anywhere (it stays silent when a fallback exists, to avoid nagging); `x-engine-api-override` = the particle overrides `tl.seek` at runtime or replaces `__timelines[…]` with a wrapper object (which would override the engine's explicit `seek(t,true)` and stops working the moment the engine switches to `time()`/`progress()`; a transitional state); `x-raf-interval` = it contains `requestAnimationFrame(` / `setInterval(` (its own clock is not driven by seek, i.e. frozen). All three MUST NOT be fatal — "driving the picture from callbacks" is not a violation.
463
509
  - **status** (`gtrk mg status --project <dir>`): summarizes the MG pipeline — total beats in `dispatch.mg` / how many source HTML files exist / how many are laid into `.gtrk`, annotating each beat (missing HTML / produced but not laid / laid).
510
+ - **render** (`gtrk mg render <particle.html> --duration <sec> [--out <dir>] [--yes]`): renders a single particle in the cloud, **independent of any project**, into a Jianying-readable qtrle transparent alpha MOV (the fine-cut supplement channel — when the rough cut is already exported to Jianying and one more motion graphic is needed, you can add it without going back to the client app). The chain = lint upfront (envelope = `--duration`; any fatal item is blocked locally, zero submission, zero billing) → **billing-estimate confirmation** (live price lookup; the CLI has no local HTML render engine, so the cloud billed task is the only path for standalone particles; `--yes` skips the prompt) → inline submission to the cloud → `<composition_id>.mov` landed with `task.json`/`result.json` breadcrumbs (recoverable by task_id after a crash). **Scope**: qtrle only for now (`--format webm` is explicitly refused — Jianying cannot read VP8-alpha), 1920×1080 particles only (the contract has no portrait/odd-canvas opening), and `--duration` is required. The output never enters `.gtrk` and never lands in the Jianying draft folder; qtrle is lossless and relatively large, suited to seconds-long particles. Note it shares a word with `gtrk render` (full-video rendering) but is a different thing.
464
511
 
465
512
  `--json` output: `{ ok, mode:"lay"|"lint"|"status", … }` (each mode carries its own fields, e.g. `laid` / `skipped` when laying, per-beat status for `status`). Laying mode additionally carries **`track_total`** (how many laid particles currently exist on the track), **`kept`** / **`kept_ids`** (how many are **left over from the previous round** and not re-laid this time, plus their `composition_id` list) and **`removed`** (how many old self-produced particles were stripped this run) — `laid` (this run), `track_total` (total on the track) and `kept` (left over) **must be read together**, and `track_total = laid + kept` always holds. Reading `laid` alone makes "lay 1, strip 20" look identical to "patch in 1", and reading only the first two hides the cost that "a few particles on the track are not from this round" (`kept_ids` and `skipped` overlap: something that failed to land this round is still there from the previous one). When not fully green it also carries a machine-readable **`reason`**: `skipped` (some were not laid) / `empty_queue` (**write-back refused**, the project was not modified, with `refused:true` and `blocked[]`) / `no_project` (project missing, nothing laid). Runs that actually wrote back also carry **`integrity`** (the material-on-disk self-check, identical in name and shape to `gtrk matrix`; see the previous section).
466
513
 
@@ -518,7 +565,7 @@ Standalone single-request capabilities, kept separate from the pipeline's lane c
518
565
  | `piano_audio_to_midi` | One audio file | A MIDI file `.mid` | Queried live before the run | Live |
519
566
  | `piano_audio_enhance` | One audio file | High-quality WAV + accompanying MIDI (two artifacts) | Queried live before the run | Live |
520
567
  | `image_to_square` | One image; optional `--max-line <px>` (≤ 20000) | Square image | Queried live before the run | Live |
521
- | `image_to_live` | One image | A short video of about 4 seconds `.mp4` (silent; the artifact is a video) | Queried live before the run | Live |
568
+ | `image_to_live` | One image | A short video of about 4 seconds `.mp4` (silent); or an Android motion photo `.jpg` plus the same clip as a companion `.mp4` | Queried live before the run | Live |
522
569
  | `image_classic_template` | **Several images** + a required `--main-title`; optional subtitle/mode/ratio/quality/count/layout | Finished cover/collage (text/pic/render groups, possibly several images) | Queried live before the run | Live |
523
570
  | `image_vertical_stitch` | **Several images** (order = top-to-bottom stitching order) | One vertically stitched long image | Queried live before the run | Live |
524
571
  | `video_split_screen` | **2–16 video segments** (multiple positionals); the precise tier uses `--clips-json` (entries `{input:0-based index, begin_time_ms, end_time_ms, crop}`, millisecond time base); nine optional layout/aspect/audio parameters | One split-screen video (its length matches the shortest segment) | Queried live before the run | Live |
@@ -557,7 +604,7 @@ The seven shared video tools — black-border removal, aspect adaptation, stabil
557
604
  - `gtrk tool piano_audio_to_midi ./piano.mp3` — transcribe piano audio into `.mid`.
558
605
  - `gtrk tool piano_audio_enhance ./piano.mp3` — piano recording restoration, producing a high-quality WAV as the main artifact plus a companion MIDI.
559
606
  - `gtrk tool image_to_square ./long.jpg [--max-line 8000]` — long image to square; `--max-line` defaults to 4000 and caps at 20000.
560
- - `gtrk tool image_to_live ./photo.jpg` — bring a still photo to life; the artifact is a silent `.mp4` video of about 4 seconds.
607
+ - `gtrk tool image_to_live ./photo.jpg [--output-format motion_photo]` — bring a still photo to life. By default the artifact is a silent `.mp4` video of about 4 seconds; `--output-format motion_photo` instead delivers an **Android motion photo** (a single `.jpg` with the clip embedded after the still image, so a gallery plays it on long-press), plus the same clip as a companion `.mp4`. Both formats cost the same. Compatibility: Android galleries that support the standard recognise and play it; **iOS does not** and shows a plain still image; a few Android models may only ever show the still.
561
608
  - `gtrk tool image_classic_template a.jpg b.jpg c.jpg --main-title "新品速览"` — title + several images into a cover/collage; `--output-pic-count`/`--output-text-count` are clamped to ≤ 20 by the server.
562
609
  - `gtrk tool image_vertical_stitch top.png mid.png bottom.png` — stitch several images vertically in the order given.
563
610
  - `gtrk tool video_split_screen a.mp4 b.mp4 --output-ratio 16:9` — simple tier: automatic split-screen layout over the whole clips (reaction / side-by-side comparison).
package/README.md CHANGED
@@ -33,14 +33,15 @@
33
33
  | ⚙️ | `gtrk init` | 引导式一次性配置(API Key + 剪映草稿目录),之后免管 |
34
34
  | 🩺 | `gtrk doctor` | 体检:配置 / 云端连通 / 剪映目录 / 运行时一键自检 |
35
35
  | 📦 | `gtrk deps` | 运行时资产:`status` 查 ffmpeg/字体的来源与授权,`install` 从同合云镜像装(**须显式触发,绝不静默自动下载**) |
36
- | 🤖 | `gtrk skills install` | 通过通用 `skills` 适配器和 gtrk 补充层,把 12 个 CLI 自带 skill 装进本机检测到的主流 Agent;`--all` 可覆盖全部已登记宿主 |
36
+ | 🤖 | `gtrk skills install` | 通过通用 `skills` 适配器和 gtrk 补充层,把 14 个 CLI 自带 skill 装进本机检测到的主流 Agent;`--all` 可覆盖全部已登记宿主 |
37
37
  | ⬆️ | `gtrk upgrade` | 升级 CLI 到最新版 + 刷新 skill(配置保留);`--check` 只查不装 |
38
38
  | 🎞️ | `gtrk render` | 本地渲染 gtrk 工程(EDL)→ 成片 mp4(需 ffmpeg);输出帧按时间线**累计对齐**(逐段取整误差不累加,画面不会对配音渐进失步);渲完自动质检并落 `.qc.json`(`--no-qc` 跳过) |
39
39
  | 🔬 | `gtrk qc <成片>` | 成片质检:单趟扫全片查闪帧/黑帧/冻结/爆音/静音/音画不同步,带时码定位;`--gtrk <工程>` 开工程感知识别**段内跳切**,`--fail-on error\|warn\|never` 供管线门控 |
40
- | 🔎 | `gtrk matrix` | B-roll 检索+**候选铺轨**:消费 FILM_BROLL 派单 → 产候选清单 + 下载 preview 代理铺 N 条候选轨(`--lay N` 默认 1,opencut 打开即可用轨道小眼睛对比;`--lay 0` 只出清单);`matrix search "<词>"` 单条 ad-hoc;**本地素材模式**:`matrix index --dirs <素材夹>` 免切片建索引 → `--local --dirs` 检索铺轨(**素材本体不上云**)→ `matrix lay` 消费(可编辑的)plan;`matrix describe` 按需理解候选 |
41
- | 🎨 | `gtrk mg` | MG 动态图颗粒铺轨:消费 MG 派单 → 把 html-particle 颗粒(透明叠加 / 满屏底层,由你栏目的 MG 生产 skill 所产)铺进 `.gtrk` 的 beat_track;`mg lint <颗粒.html>` 铁律静态子集校验、`mg status --project <dir>` 编排看板(缺 HTML / 已产未铺 / 已铺);aux 叠层颗粒同段多铺(一 beat 派生主 + `-aux<n>`)。旧名 `gtrk rrv` 保留为弃用别名 |
40
+ | 🔎 | `gtrk matrix` | B-roll 检索+**候选铺轨**:消费 FILM_BROLL 派单 → 产候选清单 + 下载 preview 代理铺 N 条候选轨(`--lay N` 默认 1,opencut 打开即可用轨道小眼睛对比;`--lay 0` 只出清单);`matrix search "<词>"` 单条 ad-hoc;`matrix fetch <clip_id...>` 精剪期拉原片(已授予素材免费重签+下载落盘,直接拖进剪映);**本地素材模式**:`matrix index --dirs <素材夹>` 免切片建索引 → `--local --dirs` 检索铺轨(**素材本体不上云**)→ `matrix lay` 消费(可编辑的)plan;`matrix describe` 按需理解候选 |
41
+ | 🎨 | `gtrk mg` | MG 动态图颗粒铺轨:消费 MG 派单 → 把 html-particle 颗粒(透明叠加 / 满屏底层,由你栏目的 MG 生产 skill 所产)铺进 `.gtrk` 的 beat_track;`mg lint <颗粒.html>` 铁律静态子集校验、`mg status --project <dir>` 编排看板(缺 HTML / 已产未铺 / 已铺);`mg render <颗粒.html> --duration <sec>` 脱离工程独立云渲单颗颗粒为剪映可读 qtrle 透明 MOV(精剪补给口);aux 叠层颗粒同段多铺(一 beat 派生主 + `-aux<n>`)。旧名 `gtrk rrv` 保留为弃用别名 |
42
42
  | 🎙️ | `gtrk project init` | 音频驱动工程起盘:从一条配音建 `.gtrk` 工程——主路 `--tts-task <task_id>` 引用已完成的 TTS 配音任务(直取产物音频+句级时码,零 ASR);兜底 `--audio`+`--transcript` 自备配音成对给。落好即可 `gtrk split --project` 接成片流水线 |
43
43
  | 🎼 | `gtrk audio lay` | 音频轨零件:往 `.gtrk` 工程追加一条音频轨(BGM/配乐上轨,同源幂等替换不堆轨);`--beat-align` 云端节拍分析把入点吸附最近 downbeat(计费一次,无 Key/失败自动降级不失败) |
44
+ | 🎯 | `gtrk audio align` | 音画对轨零件(纯本地零计费):外录音轨(领夹麦/录音笔)与视频互相关测偏移+置信度;高置信直接换轨(视频流零像素改动),低置信产对齐工程交客户端拖齐后 `--resume` 读回;`--offset` 显式偏移直换 |
44
45
  | 🧰 | `gtrk tool <name>` | 单点工具族:图转运镜、图片/视频抠像、图片去黑边/比例转换/净化/转方图/LivePhoto、智能拼图封面/拼长图(多图输入)、视频去黑边/比例转换/防抖/蒸汽波滤镜/机械·智能分镜/运镜高光/智能字幕、人声伴奏分离/说话人分轨/变调变速、钢琴转MIDI/修复、音视频降噪、静音移除、MAD 等;`gtrk tool list` 查全部输入/产物/实时价格/状态。单发单收、共享 runner,接新工具只加一个 descriptor |
45
46
  | 💬 | `gtrk feedback` | 把用得不顺手的地方反馈给我们:`gtrk feedback "<一句话>" --command <命令名>`。**告知式提交**——助手代提时必须先把要发的内容原样念给你、得到同意后才加 `--disclosed` 重跑;管道/非交互环境下没有这句声明会直接拒发。发送前内容会先做一遍脱敏(本机路径、凭据、邮箱、手机号等按形态替换),你看到的就是将要发出的那一份 |
46
47
  | 🚧 | `struct` | (规划中)已有 gtrk 转三方工程 |
@@ -217,7 +218,7 @@ irm https://api.ai-mcn.tv:9000/broadcast/exe/install.ps1 | iex
217
218
  | ![在 Agent 中调用 gtrk 示例 1](assets/agent-example-1.png) | ![在 Agent 中调用 gtrk 示例 2](assets/agent-example-2.png) |
218
219
  | ![在 Agent 中调用 gtrk 示例 3](assets/agent-example-3.png) | ![在 Agent 中调用 gtrk 示例 4](assets/agent-example-4.png) |
219
220
 
220
- `gtrk install` 会把 12 个 CLI 自带 skill(`gtrk-oralcut`·`gtrk-long2short`·`gtrk-splitter`·`gtrk-matrix`·`gtrk-mg`·`gtrk-ai-drama`·`gtrk-style-maker`·`gtrk-transcript`·`gtrk-tools`·`gtrk-music-visualizer`·`gtrk-cover`)装进本机检测到的 Agent。实现方式与 lark-cli 一致:gtrk 把本地 skill 源交给通用 `skills` CLI,由它维护 Agent 探测、目录映射及更新规则;gtrk 不再硬编码各家路径。
221
+ `gtrk install` 会把 14 个 CLI 自带 skill(`gtrk-oralcut`·`gtrk-long2short`·`gtrk-splitter`·`gtrk-matrix`·`gtrk-mg`·`gtrk-ai-drama`·`gtrk-style-maker`·`gtrk-transcript`·`gtrk-tools`·`gtrk-music-visualizer`·`gtrk-cover`·`gtrk-travel-recap`·`gtrk-live-slicing`·`gtrk-talking-head`)装进本机检测到的 Agent。实现方式与 lark-cli 一致:gtrk 把本地 skill 源交给通用 `skills` CLI,由它维护 Agent 探测、目录映射及更新规则;gtrk 不再硬编码各家路径。
221
222
 
222
223
  默认使用 `~/.agents/skills` 作为统一正本,再链接到各 Agent 的兼容目录(Windows 使用 junction);链接不可用时适配器会回退复制。这样更新只有一份正本,不会让多份副本逐渐漂移。常用命令:
223
224
 
@@ -390,9 +391,43 @@ gtrk transcript "D:/素材/采访视频.mp4" --lang zh-CN --out "D:/文字稿/
390
391
  >
391
392
  > **派单条目自带 `span:{from,to}`**(该条目对应的 utterance 区间;`overlay` aux 派生条目写 **aux 自己的** span,可为主 beat span 的子区间)。**`track_st/track_ed` 是投影时刻的快照**——`gtrk mg` / `gtrk matrix` 消费时会**现场重投影**(见下),所以改完口播轨**不必**回来重跑 `gtrk split`,只有拆分稿本身变了才要重跑。
392
393
 
394
+ ### `gtrk patch <move|trim|split|set>` — 元素级编辑(改工程唯一入口)
395
+
396
+ 改一个 clip / gap / 颗粒的时码或参数。**agent 勿裸手改 `.gtrk` JSON** —— 片段时码是两套并存的
397
+ (`clip_st`+`clip_ed` 与 `clip_st`+`duration`),改一份不改另一份是**静默失败**:客户端优先读 `clip_ed`,
398
+ 而后端不强校验它,于是没人报错、成片却用了陈旧出点。本命令负责恒等式同步 + 帧对齐 + 写前全档校验。
399
+
400
+ ```bash
401
+ gtrk patch move --project <dir> --clip c2 --to 5.0
402
+ gtrk patch trim --project <dir> --clip c2 --out -1s
403
+ gtrk patch split --project <dir> --clip c2 --cut 5.5
404
+ gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
405
+ ```
406
+
407
+ | 参数 | 作用 | 缺省 |
408
+ |---|---|---|
409
+ | `--project <dir>` / `--gtrk <path>` | 工程目录(自动定位 `gtrk/project.gtrk`)或直接给路径 | — |
410
+ | `--clip <clip_id>` | 按 id 寻址。命中 video/audio **镜像对**时视为一个编辑单元 | — |
411
+ | `--track <kind:idx> --at <sec>` | 按位置寻址(`track_st ≤ at < track_ed`)。与 `--clip` 互斥 | — |
412
+ | `--to <sec\|Nf>` | `move` 的落点 | — |
413
+ | `--in` / `--out` / `--set-in` / `--set-out` / `--slip` | `trim` 的五种语义(前两个相对、中两个绝对、`--slip` 只换源窗) | — |
414
+ | `--cut <sec\|Nf>` | `split` 的切点。⚠️ 与寻址用的 `--at` 是两个参数 | — |
415
+ | `--muted` / `--volume <gain>` / `--opaque` | `set` 的元素级参数(`--volume` 是线性增益不是 dB) | — |
416
+ | `--total <sec\|Nf\|max>` | `set` 的顶层总长(工程级 op,与元素寻址互斥) | — |
417
+ | `--ops <file\|->` | 批量事务:一次读、全算、全校验、一次写;任一条失败**零写** | 关 |
418
+ | `--dry-run` | 只算与校验、不写文件 | 关 |
419
+ | `--json` | 机读回执到 stdout(人读日志转 stderr) | 关 |
420
+
421
+ > 时码字面:秒(`3.5` / `3.5s`)或帧(`105f`);相对量带正负号(`-1s`)。
422
+ >
423
+ > 回执含 `ops[].resolved` 定位三元组 `{track, clip_id, track_st}` —— 下一轮据它复核「所指是否仍是同一元素」。
424
+ > `preexisting[]` 是**入档既存**的不变量问题(非本次造成,不阻断);本次改动造成违规则**零写非 0**。
425
+ >
426
+ > ⚠️ 空档(gap)不能用 `--clip ""` 寻址:契约允许多个 gap 共享该取值,它不构成地址;用 `--track/--at`。
427
+
393
428
  ### `gtrk matrix` — B-roll 检索 + 候选铺轨
394
429
 
395
- **无 positional = 派单消费**:读 `split/dispatch.json` 的 `film_broll` 队列 → 双口检索 → 产候选清单 `split/broll-plan.json` + 下载 preview 代理、在工程里平铺 N 条候选轨(opencut 打开即可用轨道小眼睛对比挑选)。**`matrix search "<query>"` = 单条 ad-hoc 检索**(不依赖派单)。
430
+ **无 positional = 派单消费**:读 `split/dispatch.json` 的 `film_broll` 队列 → 双口检索 → 产候选清单 `split/broll-plan.json` + 下载 preview 代理、在工程里平铺 N 条候选轨(opencut 打开即可用轨道小眼睛对比挑选)。**`matrix search "<query>"` = 单条 ad-hoc 检索**(不依赖派单)。**`matrix fetch <clip_id...>` = 精剪期拉原片**(脱离工程,见下)。
396
431
 
397
432
  | 参数 | 作用 | 缺省 |
398
433
  |---|---|---|
@@ -405,9 +440,11 @@ gtrk transcript "D:/素材/采访视频.mp4" --lang zh-CN --out "D:/文字稿/
405
440
  | `--score-floor <f>` | 填充置信度地板:segment score 低于此值不采纳、槽位留空——留空处**露黑底垫轨**(默认铺;除非 `--no-black-bed` 才露主轨)。调高会收缩取材池,整段铺不满即纯黑压口播,调完先看空洞告警 | `0.2` |
406
441
  | `--no-black-bed` | 不铺纯黑底垫轨(默认铺一条) | 默认铺 |
407
442
  | `--force-relay` | 候选轨已被你在客户端编辑过时仍强剥重铺(缺省会拒铺并保留那条轨)——**会删掉已确认原片的 `broll-raw-*` 素材登记、盘上原片成孤儿** | 关 |
408
- | `--out <file>` | ad-hoc 模式结果落文件 | stdout |
443
+ | `--out <file>` | ad-hoc 模式结果落文件;`matrix fetch` 原片落盘目录(绝不写剪映草稿目录) | stdout / `./matrix-fetch/` |
409
444
  | `--json` | 机读:stdout 只输出结果 JSON | 关 |
410
445
 
446
+ **`matrix fetch <clip_id...>`(精剪期拉原片,脱离工程)**:对**计费检索过**(授予账本命中)的素材按 clip_id 免费重签新鲜下载直链并落盘 `<clip_id>.<ext>`——粗剪导剪映后想补一段 B-roll,不回客户端就能拉到本地直接拖进剪映。动线恒为**两段式**:`matrix search` 挑定 clip_id → `matrix fetch` 拉取(fetch 自身零计费、不发起检索、无确认闸)。**授予持久**:24h 过期签名不构成障碍,三天前 search 出的 clip 照样 fetch。未购项逐条报「未购授予」并给出路(对该词跑一次计费检索即获授予),不连坐其余;单批 ≤500。**首发只覆盖视频 clip 原片**(图片/音频素材重签面未开,进 missing 附提示)。产物不进 `.gtrk`、不写剪映草稿目录;在剪映里补的料不回流工程(导出单向)。
447
+
411
448
  > **beat 窗口现场重投影**:派单消费模式在**发起第一次云端检索之前**,用「`transcript` × 当刻 `.gtrk`」重算每个 beat 的 `[track_st, track_ed]`,检索、`broll-plan.json` 与铺轨一律以重算值为准(`--lay 0` 同守;ad-hoc `search` 不受影响)。`dispatch.json` 里的时码只是**投影时刻快照**,仅在重投影不可行时兜底——**所以改完口播轨直接跑本命令即可,不必先重跑 `gtrk split`**。`--json` 恒出 `reprojection:{mode,degraded,reason?,drifted,max_offset,shrunk,dropped}`;重投影后**零存活**的 beat 会被跳过(不为它烧检索配额、也不铺)。重投影不可行(transcript 缺失 / 工程定位不到 / 主轨查不到口播素材)→ **降级用快照 + 告警 + `--json` 标注**,检索与 plan 照产、不硬崩;非 v1 工程的既有行为不变(plan 先落盘、随后版本门非 0 退出)。
412
449
  >
413
450
  > 候选的 `preview_url`/`cover_url` **不带签名、不会过期**(本地代理落盘后一律复用);带签名约 24h 过期的是**原片 `url`**,由客户端「确认原片」链路重签——**不必为「重签」重跑本命令**。
@@ -435,9 +472,9 @@ gtrk matrix lay --project <目录> [--plan <path>] # ③ 消费(
435
472
 
436
473
  编排配方(纯匹配 / 先理解后铺 / 时间窗 / 素材先行编剧 / 三层层叠)与 plan 编辑口径见随包 skill `/gtrk-matrix`。
437
474
 
438
- ### `gtrk mg` — MG 动态图颗粒(铺轨 / lint / status)
475
+ ### `gtrk mg` — MG 动态图颗粒(铺轨 / lint / status / render
439
476
 
440
- 消费 `gtrk split` 落地的 `dispatch.mg` 派单,把**你栏目的 MG 生产 skill** 产的 html-particle 颗粒铺进 `.gtrk` 工程的 `beat_track`。三种模式按首个 positional 分派:**无参 = 铺轨**、`mg lint <file>` = 单文件校验、`mg status` = 编排看板。旧名 `gtrk rrv` 保留为弃用别名(会打提示,建议改用 `gtrk mg`)。
477
+ 消费 `gtrk split` 落地的 `dispatch.mg` 派单,把**你栏目的 MG 生产 skill** 产的 html-particle 颗粒铺进 `.gtrk` 工程的 `beat_track`。四种模式按首个 positional 分派:**无参 = 铺轨**、`mg lint <file>` = 单文件校验、`mg status` = 编排看板、`mg render <file>` = 独立颗粒云渲(脱离工程,精剪补给口)。旧名 `gtrk rrv` 保留为弃用别名(会打提示,建议改用 `gtrk mg`)。
441
478
 
442
479
  | 参数 | 作用 | 缺省 |
443
480
  |---|---|---|
@@ -446,6 +483,10 @@ gtrk matrix lay --project <目录> [--plan <path>] # ③ 消费(
446
483
  | `--only <beat>` | 只跑单 beat(收 **beat id** 如 `B12`、非 `composition_id`;主 + 其 `-aux<n>` 叠层颗粒一并选)。**真增量合并**:只重铺命中的那几颗,轨上其余已铺颗粒(连同手调)原样保留 | 全部 |
447
484
  | `--lint-only` | 只 lint 校验,不铺轨不写回 | 关 |
448
485
  | `--replace-all` | 显式授权**重置整轨**:不走增量保留、整轨剥掉重铺——**会删掉轨上其余已铺颗粒** | 关 |
486
+ | `--duration <sec>` | **render 模式必填**:显式时长锚(秒)——独立模式无坑位包络,它同时是 lint 包络、成片时长与计费时长 | — |
487
+ | `--format <fmt>` | render 模式产物格式:首发仅 `qtrle`(剪映可读透明 MOV;`webm` 剪映不吃、明确拒绝) | `qtrle` |
488
+ | `--out <dir>` | render 模式落盘目录(绝不写剪映草稿目录——拖入剪映由你做) | `./mg-render/<composition_id>/` |
489
+ | `--yes` | render 模式:跳过计费预估确认 | 关 |
449
490
  | `--json` | 机读:人读日志转 stderr,stdout 只输出结果 JSON | 关 |
450
491
 
451
492
  - **铺轨**(`gtrk mg --project <dir>`):读 `dispatch.mg` → 逐 beat 从 `<project>/mg/<composition_id>.html` 取源颗粒 → lint → 铺进 `beat_track`,把 `struct_meta.mg` 原子写回 `.gtrk`(幂等登记自产轨 `lay_tracks`,重铺先剥旧自产物再 append、用户手加轨零连带)。「透明叠加 / 满屏底层」由颗粒 HTML 根 `background` 反推的 `opaque` 决定。缺 HTML / lint 失败的 beat 计入 `skipped`、不拦其余。
@@ -459,6 +500,7 @@ gtrk matrix lay --project <目录> [--plan <path>] # ③ 消费(
459
500
  - **铁律⑧重复图元合并**(`8-primitive-merge`,**恒非致命、不拦铺轨**):识别「循环体内创建,或由循环调用具名工厂创建;落到同一父节点;且没有逐元素动画驱动」的可合并 `line` / `rect` / `path` / `polyline` / `polygon` 批次。同一父节点的纯数字循环 trip count 累加后 **≥ 8** 才报数;边界含 `.length` / 具名常量而算不出时仍报「条数未知」,不做常量折叠;逐元素 `gsap.set` / tween 或被 tween 首实参使用的元素数组会被排除。本项只提示「这里有一批可**无损**合并的重复图元,合并后画面逐像素不变」,**不是风险判定**:命中不代表该颗粒会复现缺陷,未命中也不代表安全,真判据仍是真渲染出片抽帧。
460
501
  - **回调与 seek 语义**(`x-callback-driven` / `x-engine-api-override` / `x-raf-interval`,**恒非致命、不拦铺轨**):对齐契约同名一节(2026-07-26 增补)。GSAP `seek(t)` 默认抑制回调 → 补间属性照常插值、但 `onUpdate` 里的 DOM 写入不执行,翻车形态是**画面定在初始态而非黑屏**。契约把保证压在**引擎侧**(定帧 MUST 用 `seek(t,false)` / `time(t)` / `progress(p)`),故颗粒**用回调驱动画面是合规写法**;lint 这三项只是**哨兵**:`x-callback-driven` = 回调写 DOM 且无任何 seek 兜底(有兜底则沉默,避免重复提醒);`x-engine-api-override` = 颗粒运行时覆写 `tl.seek` 或把 `__timelines[…]` 换成包装对象(会推翻引擎显式传的 `seek(t,true)`,且引擎改走 `time()`/`progress()` 即失效,属过渡态);`x-raf-interval` = 含 `requestAnimationFrame(` / `setInterval(`(自有时钟不被 seek,等于冻结)。三项 MUST NOT 致命——「用回调驱动画面」不是违规。
461
502
  - **status**(`gtrk mg status --project <dir>`):汇总 MG 流水线——`dispatch.mg` beat 总数 / 已产源 HTML 数 / 已铺进 `.gtrk` 数,并逐 beat 标注(缺 HTML / 已产未铺 / 已铺)。
503
+ - **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`(整片成片渲染)同词不同物。
462
504
 
463
505
  `--json` 输出:`{ ok, mode:"lay"|"lint"|"status", … }`(各模式带对应字段,如铺轨的 `laid` / `skipped`、status 的逐 beat 状态)。铺轨模式另带 **`track_total`**(轨上现存已铺数)、**`kept`** / **`kept_ids`**(其中**上轮遗留**、本次没重铺的颗数与 `composition_id` 清单)与 **`removed`**(本次被剥的旧自产颗粒数)——`laid`(本次)、`track_total`(轨上共)与 `kept`(上轮遗留)**要一起读**,恒有 `track_total = laid + kept`;只看 `laid` 会让「铺 1 颗、剥 20 颗」跟「补铺 1 颗」长得一模一样,只看前两个又会漏掉「轨上那几颗不是这一轮的版本」这条代价(`kept_ids` 与 `skipped` 会重叠:这轮没铺成、上一轮那条还在轨上)。非全绿时另带机读 **`reason`**:`skipped`(部分没铺上)/ `empty_queue`(**拒写回**,工程未被改动,另带 `refused:true` 与 `blocked[]`)/ `no_project`(工程缺失未铺轨)。真写回过的运行另带 **`integrity`**(素材落盘自检,与 `gtrk matrix` 同名同形,口径见上节)。
464
506
 
@@ -516,7 +558,7 @@ gtrk matrix lay --project <目录> [--plan <path>] # ③ 消费(
516
558
  | `piano_audio_to_midi` | 单条音频 | MIDI 文件 `.mid` | 运行前实时查询 | 已上线 |
517
559
  | `piano_audio_enhance` | 单条音频 | 高质量 WAV + 配套 MIDI(双产物) | 运行前实时查询 | 已上线 |
518
560
  | `image_to_square` | 单张图片;可选 `--max-line <px>`(≤20000) | 方形图片 | 运行前实时查询 | 已上线 |
519
- | `image_to_live` | 单张图片 | 约 4 秒短视频 `.mp4`(无声,产物是视频) | 运行前实时查询 | 已上线 |
561
+ | `image_to_live` | 单张图片 | 约 4 秒短视频 `.mp4`(无声);或安卓动态照片 `.jpg` + 附带同一条 `.mp4` | 运行前实时查询 | 已上线 |
520
562
  | `image_classic_template` | **多张图片** + `--main-title` 必填;可选副标题/模式/比例/质量/数量/版式 | 封面/拼图成品(text/pic/render 三组、可多张) | 运行前实时查询 | 已上线 |
521
563
  | `image_vertical_stitch` | **多张图片**(顺序=自上而下拼接顺序) | 一张垂直拼接长图 | 运行前实时查询 | 已上线 |
522
564
  | `video_split_screen` | **2~16 段视频**(多 positional);精确档 `--clips-json`(条目 `{input:0 起序号, begin_time_ms, end_time_ms, crop}`,毫秒时基);九个可选布局/画幅/音频参数 | 一条分屏成片(成片时长对齐最短段) | 运行前实时查询 | 已上线 |
@@ -555,7 +597,7 @@ gtrk matrix lay --project <目录> [--plan <path>] # ③ 消费(
555
597
  - `gtrk tool piano_audio_to_midi ./piano.mp3` — 钢琴音频扒谱为 `.mid`。
556
598
  - `gtrk tool piano_audio_enhance ./piano.mp3` — 钢琴录音修复增强,产高质量 WAV 主产物 + 配套 MIDI 副产物。
557
599
  - `gtrk tool image_to_square ./long.jpg [--max-line 8000]` — 长图转方图;`--max-line` 默认 4000、上限 20000。
558
- - `gtrk tool image_to_live ./photo.jpg` — 让静态照片动起来,产出约 4 秒的 `.mp4` 短视频(无声)。
600
+ - `gtrk tool image_to_live ./photo.jpg [--output-format motion_photo]` — 让静态照片动起来。缺省产出约 4 秒的 `.mp4` 短视频(无声);`--output-format motion_photo` 改为直出**安卓动态照片**(单个 `.jpg`,静图末尾内嵌该视频,相册里长按即播),并附带同一条 `.mp4`,两种格式同价。兼容边界:支持该标准的安卓相册可识别并播放;**iOS 不识别**,表现为普通静态图片;少数安卓机型可能只显示静图。
559
601
  - `gtrk tool image_classic_template a.jpg b.jpg c.jpg --main-title "新品速览"` — 标题+多图出封面/拼图;`--output-pic-count`/`--output-text-count` 由服务端钳制 ≤20。
560
602
  - `gtrk tool image_vertical_stitch top.png mid.png bottom.png` — 多图按传入顺序竖拼成一张长图。
561
603
  - `gtrk tool video_split_screen a.mp4 b.mp4 --output-ratio 16:9` — 简单档:整段视频自动布局分屏(reaction/对比同框)。