@gitruck/cli 0.2.14 → 0.2.16
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 +38 -37
- package/README.md +27 -7
- package/contracts/gsap-emit-v1.md +176 -6
- package/dist/index.js +2496 -504
- package/package.json +65 -64
- package/skills/gtrk-matrix/SKILL.md +33 -8
- package/skills/gtrk-mg/SKILL.md +63 -10
- package/skills/gtrk-splitter/SKILL.md +1 -0
- package/skills/gtrk-splitter/references/field-schema.md +5 -2
- package/skills/gtrk-style-maker/references/contracts-ref.md +1 -1
package/package.json
CHANGED
|
@@ -1,64 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@gitruck/cli",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "同合云成片流水线 CLI —— agent 驱动云端任务、产物拉回本地、三方工程文件(客户端/剪映/PR)互通。",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Gitruck (同合云)",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/Gitruck/cli.git"
|
|
10
|
-
},
|
|
11
|
-
"homepage": "https://github.com/Gitruck/cli#readme",
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/Gitruck/cli/issues"
|
|
14
|
-
},
|
|
15
|
-
"type": "module",
|
|
16
|
-
"bin": {
|
|
17
|
-
"gtrk": "dist/index.js"
|
|
18
|
-
},
|
|
19
|
-
"files": [
|
|
20
|
-
"dist",
|
|
21
|
-
"assets",
|
|
22
|
-
"skills",
|
|
23
|
-
"contracts",
|
|
24
|
-
"AGENT.md",
|
|
25
|
-
"README.md",
|
|
26
|
-
"LICENSE"
|
|
27
|
-
],
|
|
28
|
-
"engines": {
|
|
29
|
-
"node": ">=20.6"
|
|
30
|
-
},
|
|
31
|
-
"publishConfig": {
|
|
32
|
-
"access": "public",
|
|
33
|
-
"registry": "https://registry.npmjs.org/"
|
|
34
|
-
},
|
|
35
|
-
"keywords": [
|
|
36
|
-
"gitruck",
|
|
37
|
-
"同合云",
|
|
38
|
-
"video",
|
|
39
|
-
"oral-cut",
|
|
40
|
-
"口播剪辑",
|
|
41
|
-
"cli",
|
|
42
|
-
"jianying",
|
|
43
|
-
"剪映",
|
|
44
|
-
"agent"
|
|
45
|
-
],
|
|
46
|
-
"scripts": {
|
|
47
|
-
"gtrk": "bun run src/index.ts",
|
|
48
|
-
"build": "bun build ./src/index.ts --target=node --outfile dist/index.js",
|
|
49
|
-
"typecheck": "tsc --noEmit",
|
|
50
|
-
"prepublishOnly": "bun run build",
|
|
51
|
-
"test": "esbuild src/lib/chunk-upload.ts src/lib/upload-cache.ts src/lib/upload-submit.ts src/lib/render.ts src/lib/cloud.ts src/lib/materialize.ts src/lib/projection.ts src/lib/splitdoc.ts src/lib/gtrk-writeback.ts src/lib/column-config.ts src/lib/matrix.ts src/lib/matrix-lay.ts src/lib/solid-png.ts src/lib/mg-lint.ts src/lib/mg-lay.ts src/lib/tool-descriptors.ts src/lib/tool-runner.ts src/lib/tool-pricing.ts src/lib/transcript.ts --bundle --platform=node --format=esm --outdir=.test-build --out-extension:.js=.mjs && esbuild src/commands/split.ts --bundle --platform=node --format=esm --outdir=.test-build --out-extension:.js=.mjs && esbuild src/commands/matrix.ts --bundle --platform=node --format=esm --outfile=.test-build/matrix-cmd.mjs && esbuild src/commands/mg.ts --bundle --platform=node --format=esm --outfile=.test-build/mg-cmd.mjs && esbuild src/commands/tool.ts --bundle --platform=node --format=esm --outfile=.test-build/tool-cmd.mjs && esbuild src/commands/transcript.ts --bundle --platform=node --format=esm --outfile=.test-build/transcript-cmd.mjs && esbuild src/commands/music-visualizer.ts --bundle --platform=node --format=esm --external:commander --outfile=.test-build/music-visualizer-cmd.mjs && esbuild src/commands/skills.ts --bundle --platform=node --format=esm --outfile=.test-build/skills-cmd.mjs && esbuild src/lib/convert/ir_to_jsx.ts src/lib/convert/ir_to_am.ts src/lib/convert/ir_to_nv.ts src/lib/convert/am_parse.ts src/lib/convert/nv_parse.ts src/lib/convert/parse.ts src/lib/convert/download.ts src/lib/convert/bake_ops.ts --bundle --platform=node --format=esm --outdir=.test-build/convert --out-extension:.js=.mjs && esbuild src/lib/mad/selector.ts src/lib/mad/beat.ts src/lib/mad/scan.ts src/lib/mad/data.ts src/lib/mad/pool.ts src/lib/mad/cloud-beat.ts src/lib/mad/mad.ts --bundle --platform=node --format=esm --outdir=.test-build/mad --out-extension:.js=.mjs && node --test \"test/*.test.mjs\""
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@gitruck/cli",
|
|
3
|
+
"version": "0.2.16",
|
|
4
|
+
"description": "同合云成片流水线 CLI —— agent 驱动云端任务、产物拉回本地、三方工程文件(客户端/剪映/PR)互通。",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Gitruck (同合云)",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Gitruck/cli.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/Gitruck/cli#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/Gitruck/cli/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"bin": {
|
|
17
|
+
"gtrk": "dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"assets",
|
|
22
|
+
"skills",
|
|
23
|
+
"contracts",
|
|
24
|
+
"AGENT.md",
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20.6"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public",
|
|
33
|
+
"registry": "https://registry.npmjs.org/"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"gitruck",
|
|
37
|
+
"同合云",
|
|
38
|
+
"video",
|
|
39
|
+
"oral-cut",
|
|
40
|
+
"口播剪辑",
|
|
41
|
+
"cli",
|
|
42
|
+
"jianying",
|
|
43
|
+
"剪映",
|
|
44
|
+
"agent"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"gtrk": "bun run src/index.ts",
|
|
48
|
+
"build": "bun build ./src/index.ts --target=node --outfile dist/index.js",
|
|
49
|
+
"typecheck": "tsc --noEmit",
|
|
50
|
+
"prepublishOnly": "npm run typecheck && npm test && bun run build",
|
|
51
|
+
"test": "esbuild src/lib/chunk-upload.ts src/lib/upload-cache.ts src/lib/upload-submit.ts src/lib/render.ts src/lib/cloud.ts src/lib/materialize.ts src/lib/projection.ts src/lib/reproject.ts src/lib/splitdoc.ts src/lib/gtrk-writeback.ts src/lib/column-config.ts src/lib/matrix.ts src/lib/matrix-lay.ts src/lib/material-integrity.ts src/lib/solid-png.ts src/lib/mg-lint.ts src/lib/mg-lay.ts src/lib/tool-descriptors.ts src/lib/tool-runner.ts src/lib/tool-pricing.ts src/lib/transcript.ts --bundle --platform=node --format=esm --outdir=.test-build --out-extension:.js=.mjs && esbuild src/commands/split.ts --bundle --platform=node --format=esm --outdir=.test-build --out-extension:.js=.mjs && esbuild src/commands/matrix.ts --bundle --platform=node --format=esm --outfile=.test-build/matrix-cmd.mjs && esbuild src/commands/mg.ts --bundle --platform=node --format=esm --outfile=.test-build/mg-cmd.mjs && esbuild src/commands/tool.ts --bundle --platform=node --format=esm --outfile=.test-build/tool-cmd.mjs && esbuild src/commands/transcript.ts --bundle --platform=node --format=esm --outfile=.test-build/transcript-cmd.mjs && esbuild src/commands/music-visualizer.ts --bundle --platform=node --format=esm --external:commander --outfile=.test-build/music-visualizer-cmd.mjs && esbuild src/commands/skills.ts --bundle --platform=node --format=esm --outfile=.test-build/skills-cmd.mjs && esbuild src/lib/convert/ir_to_jsx.ts src/lib/convert/ir_to_am.ts src/lib/convert/ir_to_nv.ts src/lib/convert/am_parse.ts src/lib/convert/nv_parse.ts src/lib/convert/parse.ts src/lib/convert/download.ts src/lib/convert/bake_ops.ts --bundle --platform=node --format=esm --outdir=.test-build/convert --out-extension:.js=.mjs && esbuild src/lib/mad/selector.ts src/lib/mad/beat.ts src/lib/mad/scan.ts src/lib/mad/data.ts src/lib/mad/pool.ts src/lib/mad/cloud-beat.ts src/lib/mad/mad.ts --bundle --platform=node --format=esm --outdir=.test-build/mad --out-extension:.js=.mjs && node --test \"test/*.test.mjs\"",
|
|
52
|
+
"openspec:gate": "node openspec/gate.mjs"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@xmldom/xmldom": "^0.9.6",
|
|
56
|
+
"bun-types": "^1.1.0",
|
|
57
|
+
"commander": "^12.1.0",
|
|
58
|
+
"esbuild": "^0.28.1",
|
|
59
|
+
"typescript": "^5.6.0"
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"hash-wasm": "^4.12.0",
|
|
63
|
+
"jszip": "^3.10.1"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -22,7 +22,7 @@ description: B-roll 检索铺轨器——成片管线里第一个铺的车道(
|
|
|
22
22
|
- 需要一个**跑过 `gtrk split` 的产物目录**,里面有 `split/dispatch.json`。没有 → 先回到 ② 触发 `/gtrk-splitter` 产派单。
|
|
23
23
|
- 看 `dispatch.json` 的 `film_broll` 队列:**空 = 本片没有 B-roll 车道**(拆分时没有段落被判给 `FILM_BROLL`)→ 直接跳过本步、交棒 ④ 铺 MG,别空跑。非空才往下。
|
|
24
24
|
- `gtrk` 命令找不到 → 让用户装 `npm i -g @gitruck/cli@latest`(需先有 Node.js)。
|
|
25
|
-
- 用户可以先在 opencut
|
|
25
|
+
- 用户可以先在 opencut 里手调切点再保存——**轨号与剥旧**按工程现状算(append 候选轨),**时码也跟随**:命令每次都用 `transcript × 当刻 .gtrk` **现场重投影** beat 窗口,`dispatch.json` 里的时码只是投影那一刻的快照、仅在重投影不可行时兜底。**所以微调口播轨不用回去重跑 `gtrk split`**;只有**拆分稿本身**变了才要重跑。
|
|
26
26
|
|
|
27
27
|
## 业务分离:B-roll 无栏目生产 skill,检索偏好由栏目配置供
|
|
28
28
|
|
|
@@ -45,12 +45,13 @@ description: B-roll 检索铺轨器——成片管线里第一个铺的车道(
|
|
|
45
45
|
| 多铺几条候选来对比 | `--lay <n>` | 非负整数 · `1`(`0`=只出 plan 不铺轨) | 平铺 N 条候选轨,opencut 里小眼睛切换对比挑选 |
|
|
46
46
|
| 每段多给几个候选 | `--top-k <n>` | 整数 · 派单 `shots` 值(服务端上限 50) | 覆盖派单里每 query 的候选数上限 |
|
|
47
47
|
| 指定素材类型 | `--material-class <c>` | `real_shot` \| `concept` · 栏目策略 | 仅 internal 矩阵成员口;external 固定 real_shot、传 concept 报错 |
|
|
48
|
-
| 填充太满/太差调门槛 | `--score-floor <f>` | 浮点 0–1 · `0.2` | segment score
|
|
48
|
+
| 填充太满/太差调门槛 | `--score-floor <f>` | 浮点 0–1 · `0.2` | segment score 低于此值不采纳、槽位**留空露黑底**(黑底默认铺;除非同时带 `--no-black-bed` 才露主轨)。**调高有代价**:取材池收缩,整段铺不满时那段就是纯黑压口播——调完先看铺轨输出的空洞告警 |
|
|
49
49
|
| 不要那条纯黑底轨 | `--no-black-bed` | 开关 · 默认铺 | 默认在候选轨之下、口播主轨之上垫一条纯黑底轨,按 beat 包络整条铺满,B-roll 期间遮住底下的口播画面(含候选轨留空处);不想要就传这个 |
|
|
50
|
+
| 候选轨已被改过仍要强铺 | `--force-relay` | 开关 · 关 | **逃生门,别默认带**:缺省下「候选轨已被你编辑过(改过 clip / 确认过原片)」会**拒铺 + 工程零改动**;传它才强剥重铺——**会删掉已确认原片的 `broll-raw-*` 素材登记、盘上原片成孤儿、那条轨上的编辑不可恢复**。只在用户明确点头后带 |
|
|
50
51
|
| ad-hoc 结果落文件 | `--out <file>` | 路径 · 缺省 stdout | 仅 `search` 模式 |
|
|
51
52
|
| 机读(你必带) | `--json` | 开关 · 关 | 人读日志转 stderr,stdout 只出一行结果 JSON |
|
|
52
53
|
|
|
53
|
-
> **因势象形举例**:「B-roll 多铺几条候选让我挑」→ `--lay 3`;「这段填得太杂、卡严点」→
|
|
54
|
+
> **因势象形举例**:「B-roll 多铺几条候选让我挑」→ `--lay 3`;「这段填得太杂、卡严点」→ **先别急着改地板**:按默认 `0.2` 跑一遍,看铺轨输出的空洞告警与 `lay.blackBedHoleSec`,再决定要不要调严——调严会砍掉大半取材池,铺不满的地方是**纯黑压口播**(黑底默认铺,留空处露黑底而非主轨),真要调就小步试、每次都对着空洞告警看;「每段多给点候选」→ `--top-k 12`;「先只出清单别铺轨」→ `--lay 0`;「别给我垫那条黑底」→ `--no-black-bed`;「单独给『深夜地铁失神』搜一组」→ `gtrk matrix search "exhausted commuter staring blankly on a late night subway" --project <目录> --json`。
|
|
54
55
|
|
|
55
56
|
## 执行(每次都带 `--json`)
|
|
56
57
|
|
|
@@ -59,10 +60,13 @@ gtrk matrix --project "<split 产物目录>" [--lay N] [--score-floor F] [--top-
|
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
- `--json`:人读日志走 stderr,**成功时 stdout 只有一行结果 JSON**:
|
|
62
|
-
`{ ok, mode:"plan", memberType:"internal"|"external", columnId?, planPath, lay:{ laidTracks:[…], laidClips, blackTrack, downloads:{preview,raw,reused,failed} }, counts:{ beats, queries, results, errors } }`
|
|
63
|
+
`{ ok, mode:"plan", memberType:"internal"|"external", columnId?, planPath, lay:{ refused, laidTracks:[…], laidClips, removedTracks:[…], keptEditedTracks:[…], blackTrack, blackBedHoleSec, blackBedHoles:[{beat,track_st,track_ed,sec}…], downloads:{preview,raw,reused,failed} }, integrity:{ checked, counts:{relative,absolute,remote,noPath}, dangling:[…], danglingReferenced, danglingOrphan, external:[…], noPathIds:[…] }, counts:{ beats, queries, results, errors } }`
|
|
63
64
|
(`--lay 0` 时无 `lay` 字段;ad-hoc `search` 模式则是 `{ ok, mode:"search", results:[…], counts, outPath? }`)
|
|
64
|
-
-
|
|
65
|
+
- **拒铺结局**(候选轨已被用户编辑过):stdout 出 `{ ok:false, refused:[<track_index>…], reason:"tracks_edited", planReusable:true, planPath, lay:{ refused:true, … } }` 且**进程非 0 退出**。
|
|
66
|
+
这**不是命令失败**——`broll-plan.json` 已产出、代理已落盘,只是工程一个字节没动。处置口径见下方「常见情况处置」表。
|
|
67
|
+
- 产物:候选清单 `<目录>/split/broll-plan.json`(只含引用不含素材;`cover_url`/`preview_url` **不带签名、不会过期**,带签名 24h 过期的是原片 `url`),铺轨则把候选轨写回工程 `gtrk/project.gtrk`。
|
|
65
68
|
- **命令失败**(缺 `--dispatch`/派单、鉴权失败、全部 query 检索失败、参数越界等)→ **进程非 0 退出、报错打到 stderr、stdout 无 JSON**。先看退出码,非 0 就把 stderr 的报错如实回给用户,别当成功。
|
|
69
|
+
**非 0 退出还有一种是上面的「拒铺」**(stdout 有 JSON 且 `refused` 非空)——两者靠有没有 JSON 区分,别把拒铺讲成命令挂了。
|
|
66
70
|
- 检索是分钟级(逐 beat 逐 query + 下载代理),耐心等命令返回。
|
|
67
71
|
|
|
68
72
|
## 跑完读结果、给用户交代
|
|
@@ -73,7 +77,25 @@ gtrk matrix --project "<split 产物目录>" [--lay N] [--score-floor F] [--top-
|
|
|
73
77
|
- `memberType`:`internal` = 矩阵成员口(栏目偏好/concept 生效);`external` = 通用口(固定 real_shot + 有版权素材)——档位影响命中类型,若用户期望 concept 却是 external,明说「当前身份只能出实拍有版权素材」。
|
|
74
78
|
- `lay.laidTracks` / `lay.laidClips`:铺了几条候选轨、共几个颗粒(`--lay 0` 时无此字段,只出了 plan)。**`laidTracks` 只含候选轨、不含黑底垫轨。**
|
|
75
79
|
- `lay.blackTrack`:纯黑底垫轨的 `track_index`(未铺时 `null`,如传了 `--no-black-bed`、画布尺寸非法、或零候选轨落成)。
|
|
80
|
+
- `lay.blackBedHoleSec` / `lay.blackBedHoles`:**黑底空洞**——黑底盖着、其上却没有任何 B-roll 的**纯黑压口播**时段(全片累计秒数 / 逐段 `{beat, track_st, track_ed, sec}`,按 `track_st` 升序)。
|
|
81
|
+
**这两个字段恒全量列出、不按告警阈值过滤**(读到 `blackBedHoleSec:0` 才是真没有);超阈值时 stderr 另有一条人读告警。
|
|
82
|
+
非零就**主动报给用户**(哪个 beat、几秒、在哪)——这是粗剪期的既定取舍不是故障,但用户有权知道并决定是调参还是手动补片。别只报「铺好了」。
|
|
83
|
+
- `lay.removedTracks` / `lay.keptEditedTracks`:本次**剥掉了哪些旧自产轨** / **因判定「你编辑过」而保留未剥的轨**。
|
|
84
|
+
重跑是「剥旧重铺」,删了什么必须跟用户说,别只报铺了几条。`lay.refused:true` = 本次一条轨都没铺、工程零改动。
|
|
76
85
|
- `lay.downloads`:`preview` 代理数 / `raw` **原片回落**数(无 preview 代理的候选回落下原片、体积大,服务端 backfill 后重跑本命令可换回代理)/ `reused` 复用 / `failed` 掉的槽位——`raw`/`failed` 非零时提一句。
|
|
86
|
+
- **`integrity`(素材落盘自检)**:写回工程之后自动查一遍「`materials[].path` 是不是真的都落盘了」。
|
|
87
|
+
只在**真写回过**的运行里出现(`--lay 0` / 拒铺 / 工程缺失时**字段缺席** = 本次没查,别当成「查过且干净」)。
|
|
88
|
+
- `integrity.dangling`:**悬空引用**全量清单(工程自带的相对路径素材,登记在、文件不在)。每条带 `id` / `path` /
|
|
89
|
+
`resolved`(解析后的绝对路径)/ `referenced`(是否被时间线引用)/ `refs`(引用位置:轨类型、`track_index`、
|
|
90
|
+
`clip_id`、区间)。**恒全量、不截断**。
|
|
91
|
+
- `integrity.danglingReferenced` / `integrity.danglingOrphan`:**被时间线引用的**悬空数 / 孤儿数。
|
|
92
|
+
**两者严重度差一个量级**:被引用 = 时间线上那一段没素材可放(客户端可能 relink 回落到别的素材);
|
|
93
|
+
孤儿 = 只在 `materials` 里挂着、不影响画面。回报时**必须分开说**,别只报总数。
|
|
94
|
+
- `integrity.external`:**绝对路径**素材当前找不到文件(毛片被移走 / 外接盘没挂载都会这样)——另一档,不进 `dangling`。
|
|
95
|
+
- `integrity.counts` / `noPathIds`:形态分布与「没有 path」的素材(结构问题,非落盘问题)。
|
|
96
|
+
- **这是告知不是拦阻**:查出悬空**不会**让命令失败、不改退出码、不删任何东西。非零就主动报给用户
|
|
97
|
+
(哪几条、在哪一段、是不是被引用),并说明多半是历史遗留(如客户端「确认原片」下载中断),
|
|
98
|
+
修法是在客户端重新确认原片、或删掉那条 clip。**别自己去删素材或文件。**
|
|
77
99
|
- **单 query 失败是局部化的**(`counts.errors > 0` 但 `ok:true`):个别检索失败不拖垮整盘,如实说哪几段没检到、其余照铺。只有**全部 query 都失败**才会整体非 0 退出。
|
|
78
100
|
- 工程缺失/非 v1 → 命令会**告警跳过铺轨但仍产 plan**(stderr 有提示)——这时 `lay` 字段缺失,告诉用户 plan 已出、可在有工程的目录重跑铺轨。
|
|
79
101
|
|
|
@@ -93,14 +115,17 @@ gtrk matrix --project "<split 产物目录>" [--lay N] [--score-floor F] [--top-
|
|
|
93
115
|
|
|
94
116
|
| 情况 | 怎么做 |
|
|
95
117
|
|---|---|
|
|
96
|
-
| 想在多个候选里挑 | `--lay N` 多铺几条候选轨,opencut 小眼睛切换对比(N
|
|
118
|
+
| 想在多个候选里挑 | `--lay N` 多铺几条候选轨,opencut 小眼睛切换对比(N 越大越占轨、挑完可删多余轨)。**只增加可选方案数,不扩大覆盖**——(clip,segment) 对跨轨不复用,地板抬高时第二轨可能一个槽位都落不成,**别把它当空洞的解药** |
|
|
97
119
|
| 不要那条黑底垫轨 | `--no-black-bed` 重跑,黑轨与黑底素材一并剥净、候选轨层级不受影响 |
|
|
98
|
-
| 填充太差 / 命中太杂 | 调 `--score-floor
|
|
120
|
+
| 填充太差 / 命中太杂 | 调 `--score-floor`(调低更满、可能杂;调高更严但**留空处露的是黑底不是主轨**——取材池一收缩就可能整段纯黑压口播)。**调高后必看**铺轨输出的空洞告警与 `lay.blackBedHoleSec`:不接受就调回来、改 `--no-black-bed`、或在客户端手动补片 |
|
|
121
|
+
| **出现「黑底空洞」告警**(某几段是纯黑、上面没有任何 B-roll) | **这不是故障、也没拦你**,是把粗剪期的既定取舍如实报出来:黑底按 beat 包络整条铺,槽位没填满的地方就是纯黑。照 `lay.blackBedHoles` 逐段报给用户(哪个 beat、几秒、在哪),三条出路让他挑:① 调低 `--score-floor` 多放些候选进来;② `--no-black-bed` 改成露主轨口播;③ 到 opencut 里手动往那几段补片 |
|
|
99
122
|
| 每段候选太少不够挑 | 调 `--top-k`(每 query 给更多候选)重跑 |
|
|
100
123
|
| 某段有空槽 / 漏检 / 想补个特定意象 | `gtrk matrix search "<英文长句场景描述>" --project <目录> --json` 单条 ad-hoc 补检,把中意的候选记下、在 opencut 里手动铺进那段 |
|
|
101
124
|
| 只想先看清单不铺轨 | `--lay 0`(只产 `broll-plan.json`,不动工程) |
|
|
102
|
-
|
|
|
125
|
+
| **命令报「候选轨已被你编辑过」并拒绝铺轨** | **这是保护,不是故障**:说明那条轨你动过(改过 clip / 在客户端确认过原片),本次**一条轨都不铺、工程零改动**(`.gtrk` 逐字节没变),`broll-plan.json` 照常产出。告警里会指名 `track_index` 与证据。二选一:① 在 opencut 里把那条轨处置掉(不要了就删、要留就先移走/改用别的轨)后重跑;② 确知要丢弃那条轨上的编辑 → 加 `--force-relay` 强剥重铺——**会删掉已确认原片的 `broll-raw-*` 素材登记、盘上已下载原片就地成孤儿,不可恢复**,先把后果说给用户听、等他点头再跑 |
|
|
126
|
+
| 预览看不了 / 想「重签」代理 url | **别为此重跑铺轨**:候选 `preview_url`/`cover_url` 本就不带签名、不会过期,本地代理落盘后一律复用;带签名 24h 过期的是**原片 `url`**,那条链路由客户端「确认原片」时重签,不是本命令的事。真缺代理文件(被删了)才重跑本命令补下载 |
|
|
103
127
|
| 出现 raw 原片回落 / 体积大 | 提示用户;服务端 backfill 后重跑可换回轻量代理 |
|
|
128
|
+
| **报「已降级至派单快照时码」**(`reprojection.degraded:true`) | **不是故障、没拦你**:命令算不出当刻窗口,退回 `dispatch.json` 里那份可能已过期的快照继续检索/铺轨。照 `reprojection.reason` 给出路:`transcript_missing` → 把 `transcript.json` 补回产物目录(`transcript/` 或 `json/` 下),或用新版 `gtrk oralcut` 重出产物;`no_project`/`gtrk_unreadable` → 把工程放回 `<产物目录>/gtrk/project.gtrk` 或用 `--project` 指对目录;`no_material_clip` → 口播主轨被整条删了 / relink 换了素材 id / 拿了另一个工程的 dispatch。**用户若接受快照就照跑**,但要如实告诉他「这批位置按的是上一次投影的时间线,可能已经偏了」 |
|
|
104
129
|
| 期望 concept 却报 external 限制 | 如实说明当前身份(`memberType:external`)只出 real_shot 有版权素材,concept 需矩阵成员口 |
|
|
105
130
|
|
|
106
131
|
> **搜词规范**(ad-hoc `search` 与理解派单 queries 通用):用**英文长句场景描述**(5–12 词,谁+在哪+做什么),一条只装一个场景意象,**避多义/字面强的动词**("pointing"/"hunting" 会召回特写/猎人,改用场景语义如 "giving suggestions in a meeting")。派单里的 queries 已按此校准,你补检时照此写。
|
package/skills/gtrk-mg/SKILL.md
CHANGED
|
@@ -52,7 +52,7 @@ gtrk mg status --project "<split产物目录>" --json
|
|
|
52
52
|
- **产前先抽帧看底轨(`overlay` 槽位必做,别只凭派单盲产)**:颗粒最终要叠在真实画面上,构图必须因势象形。对该槽位挂点用本地 ffmpeg 抽 1-2 帧(`ffmpeg -ss <track_st秒> -i <底轨视频> -frames:v 1 <out.jpg>`,成本≈0)看清三件事——①真人主体/人脸的位置(颗粒 bbox 避开,呼应栏目「不盖说话人」铁律);②该处是否已有烧入包装或 AI 画面(有 → 别铺这颗,报用户裁决——二次过毛片高发);③画面明暗基调(深底/浅底影响衬底与配色取舍)。把这些**连同抽帧图一起附进产片订单**交给栏目生产 skill;`fullscreen` 槽位可免(满屏不透明无避让问题)。
|
|
53
53
|
- **产片订单必须附带坑位硬约束(gsap-emit v1 铁律⑦,2026-07-24 主理人硬性规定)**:颗粒 GSAP 时间线总长 ≥ **坑位时长**(该槽位 `track_ed − track_st` 包络,**不是** `duration_hint`)+ 0.3s 余量;`duration_hint` 只是动画主叙事节奏参考。主叙事播完后颗粒必须**定格保持或有限循环驻留到坑位末尾**——坑位内任意一帧核心内容都可见;**禁全局渐隐/整体退场/清空画面**(渐隐与剪辑层转场冲突,淡出由剪辑层决定);定格不动是合法终态。违反的观感 = 动画一过完颗粒突兀消失。
|
|
54
54
|
- **`-aux<n>` 叠层颗粒同样处理**:`gtrk split` 若在某 beat 的 `aux_layers` 派了 `overlay`,会派生 `<beat>-aux<n>` 进 `dispatch.mg`(多为 B-roll 底轨之上叠透明概念图解)——照样产、照样存到对应 `composition_id.html`。
|
|
55
|
-
- **category 决定叠法**:`overlay` 颗粒背景透明、盖在 B-roll 上不挡主体;`fullscreen` 不透明满屏。最终透明度由颗粒 HTML
|
|
55
|
+
- **category 决定叠法**:`overlay` 颗粒背景透明、盖在 B-roll 上不挡主体;`fullscreen` 不透明满屏。最终透明度由颗粒 HTML 的 `background` 声明反推的 `opaque` 定,生产 skill 要让二者自洽(lint 会查)。**「实心底该写在哪个元素上」的正本条款是 `contracts/gsap-emit-v1.md` 铁律 4(含真机证据锚)——本 skill 不复述元素位置,改了要以契约为准**;`fullscreen` 颗粒把实心底写错地方会吃非致命 `4-bg-on-root`(见下节)。
|
|
56
56
|
|
|
57
57
|
### 3. lint 门:铺之前先单测每颗(不过就退回生产 skill,别硬铺)
|
|
58
58
|
|
|
@@ -60,9 +60,28 @@ gtrk mg status --project "<split产物目录>" --json
|
|
|
60
60
|
gtrk mg lint "<产物目录>/mg/<composition_id>.html" --dispatch "<产物目录>/split/dispatch.json"
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
- 纯本地静态校验颗粒 HTML
|
|
63
|
+
- 纯本地静态校验颗粒 HTML 的**铁律机器可判定子集**:`<template>` 包裹、`data-composition-id` + 1920×1080、`gsap.timeline({ paused: true })`、`window.__timelines` 注册、无 `Math.random` / `Date.now`(可逐帧 seek 的确定性)、自包含无相对外链、`background` 声明与 `opaque` 自洽…;给 `--dispatch` 会额外校验 `composition_id` 命中派单。
|
|
64
|
+
- **`1-cid-expect`(致命)——复制改名必查**:颗粒内部的 `data-composition-id` 必须等于期望 id(`--dispatch` 命中时 = 该条派单的 `composition_id`,否则 = 文件名)。**你从别的颗粒复制模板时最容易漏改内部 id**:那样铺出来的 clip 指向 A、文件注册的却是 `__timelines["B"]`,渲染必错,且两颗粒抢同一个 `[data-composition-id]` 样式作用域。改名的临时副本(`./tmp.html`)不比对,不会误伤。
|
|
65
|
+
- **铁律④「实心底与透明度」两项恒非致命**(正本条款 = `contracts/gsap-emit-v1.md` 铁律 4,含 2026-07-26 真机证据锚;**本处只说看到该码怎么办,元素位置以契约为准**):
|
|
66
|
+
- `4-bg-on-root`:这颗把**实心底写在了根元素的 `style` 上**。**根元素的绘制属性会在子合成挂载时被丢弃**——那层底在成片里**一个像素都不落地**:前景照常渲出、底没了、底轨透出来,观感是「浮空面板」;而**本地播放器与客户端预览都看不出**(预览会按登记的 `opaque` 位自己给根盒打底,对这个问题结构性失明)。**报了要回步骤 2 让生产 skill 把实心底下沉为子层**——改法是机械的(把那条 `background` 声明整体搬到根下第一个全幅子层,根上改写 `background:transparent`)。⚠️ 它**不影响退出码、不拦铺轨**(避免存量颗粒一夜之间铺不进去),但**不是可以放着不管的噪音**:不改就是出片丢底。
|
|
67
|
+
- `4-bg-explicit`:根与根下首个全幅子层**都**没有 `background` 声明 → lint 只能按「透明叠加」处理。契约要求**透明与否显式**:满屏颗粒在全幅子层写实心底,透明叠加颗粒在根写 `background:transparent`。**别靠「不写」表达透明**——作者与机器都分不清「想透明」和「忘了想」。
|
|
68
|
+
- 两项都**只看 `background` 声明摆在哪**,不看色值(色值属栏目审美,契约不管)。`opaque` 的推导面 = 「根 `style` ∪ 根下首个全幅子层 `style`」,与契约铁律 4 同源;**合规的子层写法不会再被误判成 `opaque=false`**(旧版 CLI 会,导致满屏颗粒被登记成透明叠加)。
|
|
69
|
+
- **铁律⑦ 估长三项恒非致命、不是放行凭据**(`--dispatch` 命中派单条目才跑,因为要拿该条的坑位包络):
|
|
70
|
+
- `7-fill-slot`:静态估长 < 坑位包络 → 「疑未占满」。估长是**下界**(表达式 position、非字面量 duration 那些调用算不了、跳过不计),报出来基本就是真短,**回步骤 2 让生产 skill 把驻留补到坑位末尾**。
|
|
71
|
+
- `7-no-estimate`:一条时长调用都解析不到 → **明说「铁律⑦这颗没校验」**,不是通过。这时 tl 总长只能靠真引擎 seek 或人读代码确认,别当它过了。
|
|
72
|
+
- `7-infinite-repeat`:颗粒里写了 `repeat:-1` → 总长变 `Infinity`、铁律⑦不可验证(契约 2026-07-26 已明文禁)。让生产 skill 改成按坑位算死的有限次数:`repeat = ceil((坑位 − 循环起点) / 单圈) − 1`。
|
|
73
|
+
- 三项都**不影响退出码、不拦铺轨**——真判据是渲染引擎逐帧,静态估长只做提醒。**但「没报 7-fill-slot」≠「时长够了」**,要看是否同时出了 `7-no-estimate`。
|
|
74
|
+
- **铁律⑧「重复图元合并」为恒非致命提示,但看见必须处理**:
|
|
75
|
+
- `8-primitive-merge`:这颗有一批由循环直接创建、或由循环调用具名工厂创建的可合并重复图元;它们落到同一父节点,且没有逐元素动画驱动。纯数字循环可算且同父累计 **≥ 8** 时会报数;边界算不出时会报「条数未知」。逐元素 `gsap.set` / tween、或作为 tween 首实参使用的元素数组会被排除。
|
|
76
|
+
- 本项报的是「这批图元可**无损**合并,合并后画面逐像素不变」这一写法事实,**不是**「该颗粒有缺陷」或「超过某个数量会出问题」;真实触发轴未知。反过来,没报也**不代表安全**,真判据仍是真渲染出片抽帧。
|
|
77
|
+
- **处置**:回步骤 2,把原始提示完整交给栏目 MG 生产 skill,让它把整组同步驱动的网格 / 排线 / 刻度 / 点阵合成单元素(SVG 用一条 `<path>` 多子路径;同色分档可分档合成),然后重产、重 lint。**别硬铺,也别当没看见**;CLI 为兼容存量把它做成**非致命、不影响退出码、不拦铺轨**,不等于 agent 可以跳过修正。确需 stagger / 逐条画入 / 逐个变色的逐元素动画批次属于契约豁免,不要为了消项删掉动画身份。
|
|
78
|
+
- **「回调与 seek 语义」三项恒非致命**(契约同名一节,2026-07-26 增补;**报了不用改颗粒**):
|
|
79
|
+
- `x-callback-driven`:这颗的画面靠 `onUpdate` 等时间线回调写 DOM 驱动,且没带任何 seek 兜底(GSAP `seek(t)` 的 `suppressEvents` 缺省为 `true`,会吞掉回调)。**该写法合规**——回调可达性由契约压在**引擎侧**的 MUST 条款保证(引擎定帧 MUST 用 `seek(t,false)` / `time(t)` / `progress(p)`),**且该条款已于 2026-07-26 经真渲染引擎核实**(producer `0.6.101`,纯回调驱动无垫片颗粒三帧读数各不相同)。本项**核实之后照留**做**哨兵**:结论绑死引擎版本,引擎换实现或失守时补间属性照常插值、回调不跑 → 画面**静默定格在初始态**(不是黑屏,本地播放器和预览都看不出)。**别因为它去让生产 skill 改写法,更别让它自己加垫片。**
|
|
80
|
+
- `x-engine-api-override`:颗粒运行时覆写了 `tl.seek`(老颗粒常见的 `rr-seek-shim`)或把 `__timelines[…]` 换成了包装对象。它会推翻引擎显式传的 `seek(t, true)`,且引擎改走 `time()`/`progress()` 就完全失效。**既有垫片属过渡态**:2026-07-26 引擎侧结论已核实(引擎本就不抑制回调),垫片已无保护作用、也无害,**可择期清理**(删后须重跑 lint 并重渲复验),不清也不拦;新颗粒别再加。
|
|
81
|
+
- `x-raf-interval`:颗粒里有 `requestAnimationFrame(` / `setInterval(`。这类自有时钟**不被 seek 驱动**,逐帧渲染时等于冻结(契约明令:所有视觉变化必须挂在 tl 上)。静态正则分不清用途,报了要**人眼确认它是不是在驱动画面**;若是 → 回步骤 2 让生产 skill 改挂 tl。
|
|
82
|
+
- 另:引擎不抑制回调 = 逐帧 scrub 时 `onComplete`/`onStart`/`onRepeat` 会**反复触发**。颗粒里**别写「只跑一次」的回调**(累加计数 / `push` 数组 / 一次性 DOM 插入),要写成每次从补间状态**重算**的幂等形式。
|
|
64
83
|
- **不过(非 0 退出、逐条报因)→ 把报错原样丢回栏目 MG 生产 skill 修,重产重 lint,别硬铺**。铺一颗不合规颗粒会污染工程。
|
|
65
|
-
- 只想批量干校验不写回:`gtrk mg --project <dir> --lint-only
|
|
84
|
+
- 只想批量干校验不写回:`gtrk mg --project <dir> --lint-only`(有 beat 没过就 `ok:false` + **非 0 退出**,工程一个字节都不动)。
|
|
66
85
|
|
|
67
86
|
### 4. 铺轨:全槽位就绪后铺进工程(叠在 B-roll 之上)
|
|
68
87
|
|
|
@@ -71,23 +90,57 @@ gtrk mg --project "<split产物目录>" --json
|
|
|
71
90
|
```
|
|
72
91
|
|
|
73
92
|
- 读 `dispatch.mg` → 逐 beat 从 `<project>/mg/<composition_id>.html` 取源颗粒 → lint → 铺进 `.gtrk` 的 `beat_track`,把 `struct_meta.mg` 原子写回。**幂等**:重铺先剥旧自产轨再 append,用户在 opencut 手加的轨零连带。
|
|
74
|
-
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
-
|
|
93
|
+
- **剥离面口径**(= 「本次会剥掉什么」,和「本次铺什么」是两件事):
|
|
94
|
+
- **`--only <beat>` = 只剥命中的那几颗**(真增量合并)——轨上其余已铺颗粒连同用户手调**原样保留**。
|
|
95
|
+
- **全量重铺 = 剥掉登记里的全部自产轨再整轨重建**,**唯一例外**:本次派单里有、却因缺 HTML / lint 未过 / 重投影后零存活而**没铺成**的那些(`skipped` 里那几颗),它们上一轮的 clip **留在轨上**——不会因为新的做坏了就把旧的也毁掉。反过来,**派单里已不存在**的已铺条目(你重跑过 `gtrk split`、这个 beat 不做 MG 了)仍照剥:那是计划变更,不是做坏了。
|
|
96
|
+
- 所以「轨上共几颗」**不一定**等于「本次铺了几颗」——差额就是 `kept`(见下 `--json`),**必须一起读**。
|
|
97
|
+
- 真要**重置整轨**(连其余已铺颗粒一起剥掉重来):加 `--replace-all` 显式授权。
|
|
98
|
+
- **素材表不再囤积**(剥离键按「自产身份 × 零引用」判,不认客户端可改写的 `html_material` 前缀):
|
|
99
|
+
在 opencut 里编辑过工程之后重铺,旧的自产素材条目照样剥得掉,`mg-` 素材数**恒等于轨上颗粒数**;
|
|
100
|
+
历史遗留的重复 / 孤儿条目会在下一次重铺时一并清掉。**非自产素材零连带**——`broll-*`、`ex-solid-*`
|
|
101
|
+
垫轨、你自己加的素材一条不碰(哪怕它当前没被任何 clip 引用)。盘上 `assets/mg/` 的 html 副本从不删。
|
|
102
|
+
- `--json` 输出:`{ ok, mode:"lay", laid, track_total, kept, kept_ids, removed, skipped, reason?, integrity?, … }`。
|
|
103
|
+
- **`laid`** = **本次**铺成数;**`track_total`** = **轨上现存**已铺数;**`kept`** = 其中**上轮遗留**(本次没重铺)的颗数。三个数一起读——只看 `laid` 会让「铺 1 颗、剥 20 颗」跟「补铺 1 颗」长得一模一样。恒有 `track_total = laid + kept`。
|
|
104
|
+
- **`kept_ids`** = 上轮遗留的 `composition_id` 清单。**要判断轨上某颗是不是这一轮的版本,看它在不在这里**——`kept > 0` 就意味着轨上内容与本次派单不完全对应(要全部刷新:去掉 `--only` 全量重铺)。
|
|
105
|
+
- **`removed`** = 本次被剥掉的旧自产颗粒数(= 上一轮已铺里没被保留下来的,含「剥了再铺」的那些)。
|
|
106
|
+
- **`skipped`** = 缺 HTML / lint 失败的 beat(不拦其余)——**回步骤 2 补产、重铺**,别当没看见。**注意它和 `kept_ids` 会重叠**:某颗这轮没铺成(进 `skipped`)、上一轮那条还留在轨上(进 `kept_ids`),画面在但不是新版本,跟用户说清楚。
|
|
107
|
+
- **`reason`** = 非全绿时的机读判据:`skipped`(部分没铺上)/ `empty_queue`(**拒写回**,工程未被改动)/ `no_project`(工程缺失未铺轨)。
|
|
108
|
+
- **`reprojection`** = 本次落轨时码的来源与漂移摘要(恒出,`--lint-only` 也有):`{ mode:"reprojected"|"dispatch_snapshot", degraded, reason?, drifted, max_offset, shrunk:[…], dropped:[…] }`。
|
|
109
|
+
**时码是现场重投影出来的**:命令每次都用 `transcript × 当刻 .gtrk` 重算每个 beat 的窗口(与 `gtrk split` 落地同一段代码),`dispatch.json` 里的时码只是投影那一刻的快照。**所以用户在 split 之后微调口播轨不用回去重跑 `gtrk split`**,只有**拆分稿本身**变了才要重跑。
|
|
110
|
+
`drifted > 0` = 这次铺的位置和派单上写的不一样(正是它该做的),把条数与 `max_offset` 报给用户;`dropped` 里的 beat = 那段已被整个剪出成片,**故意不铺**(不会按快照塞回去)。
|
|
111
|
+
- **`integrity`** = **素材落盘自检**(与 `gtrk matrix` 同名同形):写回工程之后自动查一遍
|
|
112
|
+
「`materials[].path` 是不是真的都落盘了」。**只在真写回过的运行里出现**(`no_project` / 拒写回 /
|
|
113
|
+
`--lint-only` 时**字段缺席** = 本次没查,别当成「查过且干净」)。
|
|
114
|
+
`dangling` = 悬空引用全量(相对路径素材登记在、文件不在,每条带 `referenced` 与引用位置 `refs`);
|
|
115
|
+
`danglingReferenced` / `danglingOrphan` = 被时间线引用数 / 孤儿数——**两者严重度差一个量级,回报时分开说**;
|
|
116
|
+
`external` = 绝对路径素材找不到文件(另一档,不进 `dangling`)。
|
|
117
|
+
**告知不拦阻**:查出悬空不改 `ok`、不改退出码、不删任何东西;非零就报给用户(哪几条、在哪一段),
|
|
118
|
+
多半是历史遗留(如客户端「确认原片」下载中断),修法在客户端而不在这里。**别自己去删素材或文件。**
|
|
119
|
+
- **退出码**:`ok:false` 一律连带**非 0 退出**(含「有 beat 被 skip」这种循环中途的正常态)。**别把非 0 读成「命令崩了」**——它说的是「这一轮没全铺成」,按 `reason` / `skipped` 处理后重跑即可。
|
|
120
|
+
- **只铺单个 beat**:`--only <beatId>`(收的是 **beat id** 如 `B12`,不是 `composition_id`;主颗粒 + 其 `-aux<n>` 叠层一并选)。
|
|
121
|
+
- **语义 = 真增量合并**:只重铺命中的那几颗,轨上**其余已铺颗粒原样保留**——连它们的透明度与用户在 opencut 的手调一起活着(保留的是既有 clip 原件,不是照登记重建的)。适合迭代改单段。
|
|
122
|
+
- 保留下来的那几颗**不重新 lint、不重新复制源 HTML**:工程是自包含的,`<project>/mg/` 下对应源文件即便已经删了也不影响。
|
|
123
|
+
- 代价看 `kept` / `kept_ids`:轨上会同时存在「本次这版」和「上轮那版」。要把全部颗粒刷成最新(含按当刻时间线重投影的新位置),**去掉 `--only` 全量重铺**(幂等、多铺几颗不花钱)。
|
|
124
|
+
- 确实要**重置整轨**(连其余已铺颗粒一起剥掉重来)才加 `--replace-all` 显式授权。
|
|
125
|
+
- **仍会拒写的唯一情形**:本次**一条都没定位到**(`--only` 打错 beat id、`dispatch.mg` 为空、或本次条目全被 skip)**而轨上已有已铺颗粒**——那是派单或选择器出问题的信号,不是清空指令,CLI 拒绝写回并报因(`.gtrk` 逐字节不变)。
|
|
78
126
|
- **铺完必核「clip 占满坑位」**:读回 `.gtrk`,各 beat clip 的时长必须 = 槽位包络(`track_ed − track_st`)。若你的 CLI 版本按 `dispatch.mg[].duration`(旧 `duration_hint` 语义)落轨、导致 clip 短于坑位(颗粒在 beat 中途突兀消失,2026-07-24 真机实测),**把 `dispatch.mg[]` 各条 `duration` 改为包络秒数(`track_ed − track_st`)后重铺**(铺轨幂等、直接覆盖)。CLI 侧根治(落轨恒用包络)落地后此步可省。
|
|
79
127
|
|
|
80
128
|
### 5. 循环到铺满
|
|
81
129
|
|
|
82
|
-
多 MG 槽位就**循环「产 → lint → 铺」直到 `dispatch.mg` 全部铺满**(`gtrk mg status` 逐 beat 全标「已铺」、`gtrk mg` 的 `skipped`
|
|
130
|
+
多 MG 槽位就**循环「产 → lint → 铺」直到 `dispatch.mg` 全部铺满**(`gtrk mg status` 逐 beat 全标「已铺」、`gtrk mg` 的 `skipped` 为空、`ok:true` 且退出码 0)。**循环中途 `skipped` 非空时命令按 `ok:false` + 非 0 退出如实上报**,那是「还没铺满」不是「命令失败」——照常补产重铺即可;`--lint-only` 同口径。
|
|
131
|
+
|
|
132
|
+
> **循环里别用 `--only` 逐颗铺**:`--only` 是增量的(安全,不会铲掉别的),但它**只刷新命中的那几颗**——轨上其余颗粒会一直停在上一轮的版本与上一轮的落轨位置(`kept_ids` 会如实点名)。循环的正确姿势是**每轮都全量重铺**:铺轨幂等,多铺几颗不花钱,而且顺带把全部颗粒按当刻时间线重投影一遍。`--only` 留给「已经铺满、只想改某一段」。
|
|
83
133
|
|
|
84
134
|
> 旧名 `gtrk rrv` 是去品牌化前的弃用别名(仍能跑但会打提示)——**一律用 `gtrk mg`**。
|
|
85
135
|
|
|
86
136
|
## 读结果、给用户交代(别只说「铺好了」)
|
|
87
137
|
|
|
88
138
|
- **铺了哪些**:`laid[]` 的 `composition_id`,对应哪些 beat;其中哪些是 `overlay` 透明叠加(盖在 B-roll 上)、哪些是 `fullscreen` 满屏。
|
|
89
|
-
- **没铺上的**:`skipped[]` + 原因(缺 HTML 还是 lint
|
|
90
|
-
-
|
|
139
|
+
- **没铺上的**:`skipped[]` + 原因(缺 HTML 还是 lint 失败 / 重投影后零存活)——如实说,别谎报全铺;已补产重铺的说清楚补了哪几颗。
|
|
140
|
+
- **落轨位置变了要说**:`reprojection.drifted > 0` 时报出「本次按当刻时间线重投影,N 个 beat 的位置与派单不同、最大偏移 X 秒」。这是对的(用户改过口播轨),但**必须让他看见**,别悄悄改掉。
|
|
141
|
+
- **报「已降级至派单快照时码」**(`reprojection.degraded:true`):不是故障、没拦你,是算不出当刻窗口、退回了可能已过期的快照。照 `reprojection.reason` 给出路——`transcript_missing` → 把 `transcript.json` 补回产物目录(`transcript/` 或 `json/` 下),或用新版 `gtrk oralcut` 重出产物;`no_project`/`gtrk_unreadable` → 把工程放回 `<产物目录>/gtrk/project.gtrk` 或 `--project` 指对目录;`no_material_clip` → 口播主轨被整条删了 / relink 换了素材 id / 拿了另一个工程的 dispatch。用户接受快照也行,但要如实说「这批位置按的是上一次投影的时间线」。
|
|
142
|
+
- **轨上有几颗不是这一轮的**:`kept > 0` 时点名 `kept_ids`——「这次只重铺了 N 颗,轨上另外 K 颗是上一轮的(位置和内容都还是旧版),要全刷新就全量重铺一次」。**别让「铺轨完成」读起来像轨上全是新的。**
|
|
143
|
+
- 想在 opencut 里精修颗粒(手调参数/时长)→ 提示用户可打开工程手调。**但要把话说全**:手调只在「这颗**没被**下一次重铺命中」时活得下来——`--only <别的 beat>` 或全量重铺时被 skip 掉的那几颗会原样保留(含手调);**一旦某次重铺真的铺到了这颗,CLI 自产的新 clip 会整条覆盖它,手调就没了**。要长期保留的手调,别放在 CLI 自产的 MG clip 上。
|
|
91
144
|
|
|
92
145
|
## 交棒 ⑤(别停在铺完)
|
|
93
146
|
|
|
@@ -20,6 +20,7 @@ description: 视觉拆分派单器——把一条已剪好的口播工程(gtrk
|
|
|
20
20
|
- 需要一个 **oralcut 产物目录**(跑过 `gtrk oralcut` 得到的目录),里面有 `gtrk/project.gtrk` 与 `transcript/transcript.json`。没有 transcript(旧任务)→ 让用户用新版本重跑 `gtrk oralcut`(恒出 transcript)。
|
|
21
21
|
- `gtrk` 命令找不到 → 让用户装 `npm i -g @gitruck/cli@latest`。
|
|
22
22
|
- 用户可以先在客户端手调切点再保存——**每次拆分都基于「发起那一刻」的时间线投影**,所见即所得。
|
|
23
|
+
- **下游后果**:落地写进 `dispatch.json` 的 `track_st/track_ed` 因此是**那一刻的快照**。不用担心它变旧——下游消费方(`gtrk mg` / `gtrk matrix`)每次消费都**自己现场重投影**(`transcript × 当刻 .gtrk`,与本命令同一段代码),**用户之后再微调口播轨无需回来重跑 split**。只有**拆分稿本身**要改(beat 划分 / lane / handoff 变了)才重跑。
|
|
23
24
|
|
|
24
25
|
## 完整流程(取视图 → 拆分 → 落地 → 修正循环 ≤3 轮)
|
|
25
26
|
|
|
@@ -118,10 +118,13 @@
|
|
|
118
118
|
|
|
119
119
|
## 落地产物(CLI 写,供参照)
|
|
120
120
|
|
|
121
|
-
- **`.gtrk` 的 `struct_meta.split`**:`{contract_version, transcript_hash, projected_at, material_id, beats:[{id, lane, span, track_st, track_ed, source_ranges, narrative, container_stage, visual_task, shrunk?, handoff}]}
|
|
121
|
+
- **`.gtrk` 的 `struct_meta.split`**:`{contract_version, transcript_hash, projected_at, material_id, beats:[{id, lane, span, track_st, track_ed, source_ranges, narrative, container_stage, visual_task, shrunk?, handoff}]}`——投影时刻快照。
|
|
122
|
+
**谁负责重投影**:CLI 的消费方命令(`gtrk mg` / `gtrk matrix`)**每次消费都自己现场重投影**(`transcript × 当刻 .gtrk`,与 `gtrk split` 落地同一段代码),所以**用户在 split 之后继续微调口播轨是常态、无需重跑 split**;只有**拆分稿本身**变了才要重跑 `gtrk split`。快照只在重投影不可行时(transcript 缺失 / 工程定位不到 / 主轨查不到口播素材)作回退值,届时命令会显式告警并在 `--json` 里标注降级。
|
|
122
123
|
- `material_id`:口播素材 id(= transcript.material_id),消费方脱离 transcript 文件即可定位素材。
|
|
123
124
|
- `beats[].source_ranges`:`[{st, ed}]` 源时基秒(v1 恒单元素 = span 源包络,含句间静默与被剪词)——**源时基不随时间线编辑漂移**,消费方以「源区间 ∩ 当刻颗粒源窗口」投影可得实时覆盖(客户端色带跟随模式即此)。
|
|
124
|
-
- **`split/dispatch.json`**:`{mg:[{beat, composition_id, duration, category?, theme, bg, slug_hint, track_st, track_ed}], film_broll:[{beat, queries, shots, per_shot_sec, exclude, track_st, track_ed}], ai_drama:[{beat, ...handoff, track_st, track_ed}]}`(去品牌化前 `mg` 键为 `rrv_mg`,消费方 `mg ?? rrv_mg`
|
|
125
|
+
- **`split/dispatch.json`**:`{mg:[{beat, composition_id, duration, category?, theme, bg, slug_hint, track_st, track_ed, span}], film_broll:[{beat, queries, shots, per_shot_sec, exclude, track_st, track_ed, span}], ai_drama:[{beat, ...handoff, track_st, track_ed, span}]}`(去品牌化前 `mg` 键为 `rrv_mg`,消费方 `mg ?? rrv_mg` 双读)。
|
|
126
|
+
- **`span:{from,to}`**:该条目对应的 utterance 区间——派单**自述「派什么」**,消费方据它现场重投影,时码不再是派单唯一的权威内容。**aux 派生条目写的是 aux 自己的 span**(`mount` 为子区间时 ≠ 主 beat span);注意 aux 条目的 `beat` 字段记的仍是**主 beat id**,所以按 `beat` 回查 `struct_meta.split` 会把 aux 错算成主 beat 的整段窗口——要回查一律用 `composition_id`。
|
|
127
|
+
- **`track_st/track_ed` 是快照**:投影那一刻的值。老档(无 `span`)消费方会回落到 `struct_meta.split.beats[].span` 定位,照样重投影。`composition_id` = `<工程slug>-<beatId>`(MG 颗粒 `data-composition-id` 直接用它,打通 beat↔颗粒命名);`overlay` aux 派生颗粒 = `<工程slug>-<beatId>-aux<n>`(`n` 从 1)——`composition_id` 全局唯一,一 beat 可派生主 + N 个 `-aux<n>` 颗粒。
|
|
125
128
|
- **`split/visual-split.md`**(`--md`):由机器 JSON 单向渲染的人读稿,不回读。
|
|
126
129
|
|
|
127
130
|
## 落地时的 dropped 处理(你要知道)
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
- `contracts/README.md` — 收录双轴边界(管线性 + 脱敏)
|
|
6
6
|
- `contracts/handoff-contracts.json` — handoff 类型 → 契约映射表(**查表,不硬编码**)
|
|
7
|
-
- `contracts/gsap-emit-v1.md` — HTML 动画颗粒逐帧 seek 合规契约 v1
|
|
7
|
+
- `contracts/gsap-emit-v1.md` — HTML 动画颗粒逐帧 seek 合规契约 v1(**含「回调与 seek 语义」一节**:颗粒可用 `onUpdate` 等时间线回调驱动画面,回调可达性由**引擎侧** MUST 条款保证,颗粒不应自加 `tl.seek` 垫片;该节是本主题的唯一口径来源)
|
|
8
8
|
|
|
9
9
|
定位方式:本 skill 经 `gtrk skills install` 安装时,CLI 包根即 `gtrk` 命令所属包(`npm root -g` 下的 `@gitruck/cli`,或开发仓根)。找不到包时,让用户跑 `gtrk doctor` 确认安装。
|