@gitruck/cli 1.3.14 → 1.3.15

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.
@@ -296,6 +296,8 @@ gtrk client segment --no 12 --json
296
296
  gtrk client frame --at 31.5 --json # 31.5 s on the timeline, not 31.5 s into the raw footage
297
297
  ```
298
298
 
299
+ > When `state` reads the live client it also carries `disk`, a comparison with the project on disk: `{revision, same_layout, unsaved_changes, track_map:[{client, disk, clips}], disk_only}`. Unsaved track additions/removals in the client shift track numbers (e.g. the concept track is `video:2` in the client but `video:1` on disk). `gtrk patch` / `gtrk matrix` edit the project on disk, so **use the `disk` side's track numbers**, or save in the client first; a one-line notice on stderr flags any mismatch.
300
+
299
301
  - `--project` defaults to the current directory (`gtrk/project.gtrk` or `project.gtrk`).
300
302
  - `frame` writes to `$GTRK_FRAMES_DIR` by default, or `gtrk-frames/<project-path-hash>/frame-<sec>.jpg` under the system temp folder — **never into the project folder** (projects get packed up whole). `-o <file.jpg>` picks the path; an existing file needs `--force`.
301
303
  - When the bridge was not used, `--json` carries `bridge:{tried, reason}` (`no_file` / `not_running` / `not_open` / `protocol_too_new` / `protocol_too_old` / `timeout` / …) for troubleshooting; human output says on its first line whether it read files or rendered locally.
@@ -351,7 +353,7 @@ Finished cut × transcript projection → beat storyboard. **No positional argum
351
353
  >
352
354
  > **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.
353
355
 
354
- ### `gtrk patch <move|trim|split|set|add|replace>` — element-level editing (the only way to edit a project)
356
+ ### `gtrk patch <move|trim|split|set|add|replace|remove>` — element-level editing (the only way to edit a project)
355
357
 
356
358
  Edit the timecode or parameters of a single clip / gap / particle. **Agents must not hand-edit `.gtrk` JSON** —
357
359
  a clip carries **two parallel timecode representations** (`clip_st`+`clip_ed` and `clip_st`+`duration`).
@@ -366,6 +368,8 @@ gtrk patch split --project <dir> --clip c2 --cut 5.5
366
368
  gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
367
369
  gtrk patch add --project <dir> --track video:2 --to 263.733 --candidate <clip_id> # put a candidate into a gap
368
370
  gtrk patch replace --project <dir> --clip <clip_id> --candidate <clip_id> # swap the source in place
371
+ gtrk patch add --project <dir> --track video:5 --to 263.7 --candidate A --to 266.2 --candidate B # several segments at once
372
+ gtrk patch remove --project <dir> --clip <clip_id> # delete one clip, leave its spot empty
369
373
  ```
370
374
 
371
375
  | Flag | Purpose | Default |
@@ -378,6 +382,7 @@ gtrk patch replace --project <dir> --clip <clip_id> --candidate <clip_id>
378
382
  | `--beat <id>` | The beat the candidate belongs to (required when the same candidate appears in several beats with different windows) | — |
379
383
  | `--from <sec>` | Source in-point for `add` / `replace` (a candidate uses its own source time; external candidates are converted to preview-file time) | Same window as dragging a candidate in the client: centred on `seg.best`, clamped to the material; a material starts at 0 |
380
384
  | `--dur <sec\|Nf>` | Duration for `add` | The length of the gap at the target (up to the start of the next element on that track, ending on the same frame number); the candidate's window length when nothing follows |
385
+ | Repeated `--to` … (`add`, several segments) | Each `--to` is one segment; `--candidate` / `--material` / `--track` / `--beat` / `--from` / `--dur` are given once (shared) or as many times as `--to` (paired in order). Prepared once (a material is downloaded once) and written once; with default durations on one track, each segment stops where the next begins. Mismatched counts give `paired_count_mismatch`; mixing `--candidate` and `--material` gives `paired_mixed_source` (use `--ops` for that); a failing segment is reported as "segment N (the N-th --to)" with nothing written. Repeating these flags on other actions gives `repeat_only_on_add` | — |
381
386
  | `--in` / `--out` / `--set-in` / `--set-out` / `--slip` | The five `trim` semantics (first two relative, next two absolute, `--slip` shifts only the source window) | — |
382
387
  | `--cut <sec\|Nf>` | Cut point for `split`. ⚠️ Distinct from the addressing flag `--at` | — |
383
388
  | `--muted` / `--no-muted` / `--volume <gain>` / `--opaque` | Element-level parameters for `set` (`--volume` is linear gain, not dB, and must be > 0; `--volume 0` fails with `volume_zero_use_muted` — use `--muted` to silence). Track mute is a master switch: if the clip's track is muted, `--no-muted` fails with `track_muted_master` — unmute the track's speaker in the client | — |
@@ -403,8 +408,11 @@ gtrk patch replace --project <dir> --clip <clip_id> --candidate <clip_id>
403
408
  - When the candidate's material is not yet in `materials`, the preview is downloaded to `assets/broll-preview/` and registered (the same landing code as `gtrk matrix lay`); a registered material is reused, never downloaded again. So right after `matrix source-import` a single `patch add` puts it on the timeline. A failed download writes nothing and exits non-zero (`preview_download_failed`: the candidate URL may have expired — re-run the search / import to refresh); a preview already on disk is kept for next time.
404
409
  - `add` only uses existing video tracks; overlapping a non-gap element is refused (`add_overlap`, listing the blockers; when the blocker is a black fill patch it points to `patch replace`); explicit gaps covered by the new clip give way; no ripple, no new tracks. Image candidates are refused (they need a camera-move render first). A source that is too short is clamped with an `add_clamped` warning, never stretched. The new clip's `clip_id` is `<beat>-add-<n>`, it carries no `producer`, and a candidate source gets a solid black `background_fill`.
405
410
  - `replace` swaps only `material` and the source window: `clip_id`, track, start, speed, transform, fill, transitions and keyframes stay. If the new material is too short from the in-point, the clip is shortened honestly (`replace_shortened`) — never stretched, start never moved; `producer` is removed so the next `matrix lay` keeps the track as a user track; the old material entry is kept. Mirror pairs (video + mirrored audio) are refused.
411
+ - A candidate that is only in a plan (`split/broll-plan.json` or a layer snapshot) and not in the project's pool is registered into that beat's pool as it goes on the timeline (layer = the plan it came from; a missing beat registration is created from the plan's window), so the client's B-roll panel shows it and can swap it; the receipt carries `source.pooled: {beat, layer}`. Candidates already in the pool are not registered twice.
406
412
  - Every change is first computed and validated with declared values; only then is anything landed. `--dry-run` downloads and writes nothing and the receipt carries `would_download`. The op receipt also carries `source` (candidate / material, `material_id`, `landed`: existing / reused / downloaded / registered) and, for `add`, `gaps_consumed`. `--ops` entries have the same shape: `{"action":"add","track":"video:2","to":263.733,"candidate":"…"}`.
407
413
 
414
+ **`remove` (delete a clip)**: `gtrk patch remove (--clip <id> | --track video:<N> --at <sec>)` deletes one clip (or explicit gap) and leaves its spot empty — later clips do not move (B-roll stays aligned with the voice by its timeline position; close the hole with `patch seal`, move things with `patch move`). A mirrored pair (video + same-id mirrored audio) is deleted together; split ranges on the beat track are refused (`remove_beat_track`); any other flag gives `remove_args`. The material stays registered; transitions that referenced it are maintained before writing (`transition_dropped`). In `--ops`: `{"action":"remove","clip":"…"}`, which can be batched with `add` to "delete, then fill".
415
+
408
416
  **Preserving and maintaining transitions** (`transition_in` / `transition_out` / `transition_next`; created in the client — the CLI does not produce transitions in this release and adds no flags):
409
417
 
410
418
  - `split`: the entrance transition stays on the front part; the exit transition and the transition into the next clip go to the back part (`to_clip_id` unchanged); the new cut carries no transition.
@@ -447,7 +455,7 @@ With `--beat`, each beat reports:
447
455
  | `clips` | Clips on every video track that intersect the window: track, `clip_id`, material, start/end, `category` (broll / raw / black_fill / user / a_roll), and whether it carries a producer identity |
448
456
  | `gaps` / `black_only` | Spans above the main track with no picture (seams shorter than one frame are ignored); the part of them covered only by black fill patches |
449
457
 
450
- Without `--beat`, one line per B-roll beat: window, candidate count, plan candidate count, covered seconds, number and seconds of gaps. Both forms also carry the project `revision` (usable as `gtrk patch --expected-revision`), `main_track`, the re-projection summary, the strip verdict of each candidate track and `lay.relay_refused` (whether a full re-lay would now be refused with `tracks_edited`). Beats in non-B-roll lanes get only the window, lane and clips. An unknown beat gives `ok:false`, exit code 1, and the list of all known beats.
458
+ Without `--beat`, one line per B-roll beat: window, candidate count, plan candidate count, covered seconds, number and seconds of gaps. Both forms also carry the project `revision` (usable as `gtrk patch --expected-revision`), `main_track`, an overview of every video track `video_tracks[]` (`{track, track_index, main?, verdict, layer?, clips, hidden?}`, ascending, empty tracks included; the human output starts with a "video tracks: …" line — these are the numbers to use with `gtrk patch --track`), the re-projection summary, the strip verdict of each candidate track and `lay.relay_refused` (whether a full re-lay would now be refused with `tracks_edited`). Beats in non-B-roll lanes get only the window, lane and clips. An unknown beat gives `ok:false`, exit code 1, and the list of all known beats.
451
459
 
452
460
  ### `gtrk matrix` — B-roll retrieval + candidate track laying
453
461
 
@@ -471,6 +479,10 @@ Without `--beat`, one line per B-roll beat: window, candidate count, plan candid
471
479
  | `--arrange-cost-cap <n>` | Hard cap on arrangement volume for a single cloud run: over the cap the server **refuses up front** — zero execution, zero charge (it does not cut off midway). Only meaningful with `--arrange shadow\|cloud` | uncapped |
472
480
  | `--dump-request <file>` | **For troubleshooting**: write the **exact bytes actually sent** for the cloud arrangement request to this file. The server **does not keep your plan** (only a size summary), so when something goes wrong this file is the only thing that can reproduce the call — just send it to us. ⚠️ It **must not point inside the project directory** (projects get zipped, copied and synced around, and this file contains your beat names and search queries); with `--arrange-qc` each round writes its own file, round N landing at the same name plus `.roundN`. The machine-readable receipt is `lay.arrange_run.dump_request` | not written |
473
481
  | `--explain` | **Emit the tuning gauges**: by default the machine-readable accounting gives only the empty-slot count `lay.dedup.emptySlots` (enough to tell whether your material pool is too thin); the rest of the tuning detail (how many of those were caused by window refinement, how many jump-cut waivers were exhausted, how many high-motion / blurry segments were used) sits behind this flag, and the human-readable log follows the same rule. It changes no decision — the project output is byte-for-byte identical | off |
482
+ | `--query <q>` | Search terms for `matrix search`, repeatable: several angles in one run, merged per clip (highest score kept), tagged with `matched_queries`, sorted by score; the receipt gains `queries`. The positional term (the whole string as one term) comes first; online search takes one term per run | — |
483
+ | `--estimate-only` | `matrix search`: report the most this run could cost, without searching — `billing_estimate: {credits, basis}` in `--json` (`credits` is an upper bound at the overage price; `null` when it cannot be worked out, e.g. the public price list is unreachable or the online-search price is not on it). Member endpoint 0, public endpoint list price × number of terms, `--local` 0. The built-in AI in Jijian skips the confirmation for commands estimated at 100 credits or less based on this | off |
484
+ | `--beat <id>` + `--project <dir>` (`matrix search`) | Write the results into this beat's candidate pool without laying: merged into the layer snapshot `split/broll-plan.<layer>.json` (so `gtrk patch --candidate` finds them) and appended to the project's candidate registration (visible in the client panel right away; a missing beat is created from the dispatch window). Re-runs add nothing twice; the receipt carries `pool: {beat, added_to_plan, added_to_pool}`. The two flags go together | — |
485
+ | `--pool-only` (`matrix lay`) | Register plan candidates that are not yet in the project's pool: **no laying, no downloads, no track touched**, no network, no key needed (fixes `not_in_pool` in `matrix status`). Reads the main plan and every layer snapshot by default (`--plan` reads only that one), each with its own layer; `--beat <id,…>` limits it to those beats (unknown beats fail); nothing new means the project is not written. Receipt `{pool_only:true, pooled:[{beat, layer, added}]}`. On `matrix lay`, `--beat` only goes with this flag | off |
474
486
  | `--arrange-estimate-only` | **Estimate only, do not execute**: stop right at the cloud-arrangement billing confirmation, report the arrangement volume and return **successfully** (`ok:true` + `estimateOnly:true` — that is "I am deciding", not "I declined"). Zero cloud calls, zero changes to the project file. Machine-readable values live in `lay.arrange.units` / `lay.arrange.scale`. ⚠️ What it saves is **that one cloud call and its charge** (plus the candidate downloads and laying that follow), not the whole chain: the denominators of the arrangement volume still require reading the project, the plan, and re-projection. On the asset-matrix route it reports `applicable:false` rather than **0**. When given together with `--yes`, this flag wins | off |
475
487
  | `--cut-align <ratio>` | Sentence-boundary snapping target ratio 0..1: `0.7` ≈ about seven in ten subtitle sentence starts land exactly on a shot cut, three in ten deliberately off (snapping all of them reads mechanical); `0` = off, back to the old rhythm-slot cutting. ⚠️ Sentence-level timecodes come from live `transcript` re-projection (same source as the keyword anchors), and **when re-projection degrades it silently falls back to the old behaviour and warns** — the snapping ratio does not hold for that run | `0.7` |
476
488
  | `--gap-fill <mode>` | How holes in the main track of an audio-driven project get filled: `fast` = **leave as little black as possible** (relax the score floor and fill from the candidate pool → then extend neighbouring grains → then borrow unconsumed candidates across beats → then fill residual holes shorter than the minimum shot length with real footage → only pad black when a whole segment cannot be filled); `solid` = pad everything with black (so in fine-cut you can see at a glance "nothing matched here"); `none` = leave the gap as is. ⚠️ Under `fast`, borrowed footage is weakly related to that segment's script and sub-floor slots are quick cuts under 1.2s; both are reported in the log with `kind` `borrowed` / `subfloor` — **that is honest disclosure, not a defect**. `none` combined with main-track magnetic snapping in the client will swallow the gap and shift everything after it **out of sync with the voiceover** | `solid` |
@@ -517,6 +529,7 @@ gtrk matrix lay --project <dir> [--plan <path>] # ③ consume the
517
529
  - **Projects containing local footage cannot cloud-render**: submission is rejected (`local_broll_cloud_render_rejected`) — produce locally in the desktop client or via `gtrk render`.
518
530
  - **Optional atoms**: `matrix describe --plan <path> [--top-k N]` / `--materials <a,b>` understands candidates on demand (VLM description / tags / quality mark / watermark·subtitle·black-border·blur signals; 1 credit per frame (**async task billing**: pre-deducted on submit → settled on completion, auto-refunded on failure; Gitruck internal members are exempt, detected automatically at run time — with `--json`, `credits_estimated` is the actual charge and `credits_would_be` the list price), results injected into the plan and cached locally, cache hits are free, >20 frames triggers a confirmation guard). **One describe speaks for one segment, not the whole candidate**: in `--plan` mode each candidate is sampled at a single frame (`segments[0].best`), the result carries the scope anchor `describe.at_sec` (seconds on the material timebase), and the run reports "describe coverage = frames understood / total **segments** carried by the understood candidates" (`describe_coverage` in `--json`) — injecting N entries does not mean those N candidates were all looked at; `--source-window <start,end>` filters by source-time window (only with `--local`; the film-commentary pattern "segment N of the narration gets footage from around segment N of the film"); `matrix lay --mark-weight <0..1>` blends describe's quality mark into candidate ranking (fused score = sim×(1-w)+(mark/100)×w; reorders only, never changes admission; candidates without a cached mark are treated as neutral).
519
531
  - **Highlight rubric**: `--highlight-rubric <text|@file>` (same flag on `describe` and `lay`; ≤2000 characters; `@<path>` reads from a file, which is the main form since a rubric is multi-line). It tells the highlight score (`--highlight-weight`) **what to judge by** — each vertical blueprint carries its own (food judges portion contrast and visible prices, travel judges rare landforms and extreme weather). **Omit it and the field is not sent at all**: the server falls back to its own domain-agnostic default, byte-for-byte identical to behaviour before this flag existed. Highlight scores are cached in **per-rubric buckets**: switching rubric rescores without invalidating or overwriting the objective description cache. `describe --plan` pins the run's `rubric_hash` into the plan and `lay` reads that same bucket automatically (no need to pass it twice); if the two disagree `lay` **fails hard** instead of silently picking one — scoring against the wrong rubric is undetectable after the fact. ⚠️ Rescoring under a new rubric still re-sends the frames (billed per frame): a text-only rescore channel needs server support and does not exist yet.
532
+ - **Grid understanding**: `matrix describe --layout grid` asks the server to tile candidates of the same query (the same material for `--materials`) into contact sheets and understand them in batches (≤9 frames per sheet, a cell-by-cell scan for corner logos and black bars, blur judged by a sharpness metric). **Still 1 credit per frame**, faster, and the same budget covers more frames; but mark / highlight are **only comparable within one sheet** and shot size / black-border calls are less stable than per-frame, so keep the default per-frame mode when you rank by `--mark-weight` / `--highlight-weight` or rely on shot size. **Omit `--layout` = per-frame, request body byte-for-byte identical to before this flag existed.** Whether the server actually used grids is taken from its receipt (an old or ops-disabled server is reported as "this run was per-frame"; read `layout_receipt` with `--json`); the cache records how each frame was understood, and a per-frame run **does not reuse grid results** (it re-understands them per frame and reports the count).
520
533
  - **Index knobs and score scale**: `--scene-threshold` tunes scene-split granularity, `--stability-threshold` collapses static-camera scenes to fewer sampled frames, `--rebuild` forces a rebuild (describe caches are kept); the index is not portable across machines (keys are absolute paths — just re-run `index` on the new machine). Local score scale differs from the cloud's (a perfect hit can score as low as ~0.25), so do not raise `--score-floor` on cloud instincts.
521
534
 
522
535
  **`gtrk matrix material "<query>"` (general tri-state material search)**: the second line alongside the B-roll search above, returning a download link for the **whole material** (not a segment) — `--scope clip|image|audio` (default `audio`, the BGM use case), `--commercial-only` searches commercially usable material only (**an explicit opt-in switch — off by default**), `--min-duration/--max-duration` picks by finished-cut length, `--top-k` (default 5, server cap 50), `--diversity`, `--json` for machine reading, `--out` to write a file. With `--scope clip|image` it also returns **Pexels supplementary results**, listed separately in `pexels_results` and not counted as candidates (`--no-stock` turns this off); download them straight from `download_url` (not via `matrix fetch`) and keep the photographer credit and the Pexels link when you use them.
package/docs/reference.md CHANGED
@@ -299,6 +299,8 @@ gtrk client segment --no 12 --json
299
299
  gtrk client frame --at 31.5 --json # 时间线上的 31.5 秒,不是毛片的 31.5 秒
300
300
  ```
301
301
 
302
+ > `state` 读到客户端实时状态时另带 `disk`:与盘上工程的对照 `{revision, same_layout, unsaved_changes, track_map:[{client, disk, clips}], disk_only}`。客户端里有没保存的轨道增删时两边轨号会错开(如概念轨在客户端是 `video:2`、盘上是 `video:1`),`gtrk patch` / `gtrk matrix` 改的是盘上工程,**轨号按 `disk` 一侧写**,或先在客户端保存;两边不一致时 stderr 另有一行提示。
303
+
302
304
  - `--project` 缺省当前目录(`gtrk/project.gtrk` 或 `project.gtrk`)。
303
305
  - `frame` 的图缺省写到 `$GTRK_FRAMES_DIR`,未设时为系统临时目录下 `gtrk-frames/<工程路径哈希>/frame-<秒>.jpg`,**不写进工程目录**(工程会被整体打包带走);`-o <file.jpg>` 指定落点,已存在须 `--force`。
304
306
  - 没走成本机通道时 `--json` 带 `bridge:{tried, reason}`(`no_file` / `not_running` / `not_open` / `protocol_too_new` / `protocol_too_old` / `timeout` / …)便于排障;人读输出首行注明读的是文件还是本地渲染。
@@ -354,7 +356,7 @@ gtrk client frame --at 31.5 --json # 时间线上的 31.5 秒,不是
354
356
  >
355
357
  > **派单条目自带 `span:{from,to}`**(该条目对应的 utterance 区间;`overlay` aux 派生条目写 **aux 自己的** span,可为主 beat span 的子区间)。**`track_st/track_ed` 是投影时刻的快照**——`gtrk mg` / `gtrk matrix` 消费时会**现场重投影**(见下),所以改完口播轨**不必**回来重跑 `gtrk split`,只有拆分稿本身变了才要重跑。
356
358
 
357
- ### `gtrk patch <move|trim|split|set|add|replace>` — 元素级编辑(改工程唯一入口)
359
+ ### `gtrk patch <move|trim|split|set|add|replace|remove>` — 元素级编辑(改工程唯一入口)
358
360
 
359
361
  改一个 clip / gap / 颗粒的时码或参数。**agent 勿裸手改 `.gtrk` JSON** —— 片段时码是两套并存的
360
362
  (`clip_st`+`clip_ed` 与 `clip_st`+`duration`),改一份不改另一份是**静默失败**:客户端优先读 `clip_ed`,
@@ -367,6 +369,8 @@ gtrk patch split --project <dir> --clip c2 --cut 5.5
367
369
  gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
368
370
  gtrk patch add --project <dir> --track video:2 --to 263.733 --candidate <clip_id> # 把候选放上空位
369
371
  gtrk patch replace --project <dir> --clip <clip_id> --candidate <clip_id> # 原地换源
372
+ gtrk patch add --project <dir> --track video:5 --to 263.7 --candidate A --to 266.2 --candidate B # 一次放多段
373
+ gtrk patch remove --project <dir> --clip <clip_id> # 删掉一个片段,原位置留空
370
374
  ```
371
375
 
372
376
  | 参数 | 作用 | 缺省 |
@@ -379,6 +383,7 @@ gtrk patch replace --project <dir> --clip <clip_id> --candidate <clip_id>
379
383
  | `--beat <id>` | 候选所在 beat(同一候选在多个 beat 取窗不同时必给) | — |
380
384
  | `--from <sec>` | `add` / `replace` 的源片入点(候选按它自己的源片时间,外网候选自动换成预览文件时间) | 与客户端拖候选上轨同一取窗:以 `seg.best` 居中、钳在素材范围内;素材从 0 |
381
385
  | `--dur <sec\|Nf>` | `add` 的时长 | 落点所在空位的长度(到该轨上落点之后第一个元素的起点,出点与它取同一帧号);后面没有元素时取候选取窗长度 |
386
+ | 重复 `--to` …(`add` 一次放多段) | 每个 `--to` 一段;`--candidate` / `--material` / `--track` / `--beat` / `--from` / `--dur` 各给一次(各段共用)或与 `--to` 一样多次(按顺序配对)。一次准备(同一素材只下载一次)、一次写回;同轨缺省时长下前一段停在后一段起点。次数不齐报 `paired_count_mismatch`,`--candidate` 与 `--material` 混用报 `paired_mixed_source`(混着来写 `--ops`);某段失败报「第 N 段(第 N 个 --to)」、零写。别的动作重复给这些参数报 `repeat_only_on_add` | — |
382
387
  | `--in` / `--out` / `--set-in` / `--set-out` / `--slip` | `trim` 的五种语义(前两个相对、中两个绝对、`--slip` 只换源窗) | — |
383
388
  | `--cut <sec\|Nf>` | `split` 的切点。⚠️ 与寻址用的 `--at` 是两个参数 | — |
384
389
  | `--muted` / `--no-muted` / `--volume <gain>` / `--opaque` | `set` 的元素级参数(`--volume` 是线性增益不是 dB,须 > 0;`--volume 0` 报 `volume_zero_use_muted`,静音用 `--muted`)。轨静音是总开关:片段所在轨已静音时 `--no-muted` 报 `track_muted_master`,请在客户端点开轨喇叭 | — |
@@ -401,8 +406,11 @@ gtrk patch replace --project <dir> --clip <clip_id> --candidate <clip_id>
401
406
  - 候选的素材还不在 `materials` 里时,顺手把预览下载到 `assets/broll-preview/` 并登记(与 `gtrk matrix lay` 同一份落地实现);已登记的直接复用、不重下。所以 `matrix source-import` 之后一条 `patch add` 就能上轨。下载失败零写、非 0(`preview_download_failed`:候选地址可能过期,重跑检索 / 导入刷新);已落盘的预览留作下次复用。
402
407
  - `add` 只放已存在的视频轨;落点与非空档元素重叠即拒(`add_overlap`,列出挡路元素;挡路的是黑底补片时指路 `patch replace`);落点覆盖到的显式空档让位;不 ripple、不新建轨。图片候选不收(上轨要先生成运镜)。源片不够长时钳短并告警 `add_clamped`,不拉伸。新片段 `clip_id` 为 `<beat>-add-<n>`,不带 `producer`,候选来源带纯黑 `background_fill`。
403
408
  - `replace` 只换 `material` 与源窗:`clip_id`、所在轨、起点、倍速、变换、填充、转场、关键帧都不动;新素材从入点起不够长时如实缩短(`replace_shortened`),不拉伸、不挪起点;删去 `producer`,下一次 `matrix lay` 把这条轨当用户轨保留;旧素材条目不删。镜像对(视频 + 镜像音频)不收。
409
+ - 候选只在 plan(`split/broll-plan.json` 或分层快照)里、工程候选池没有时,放上轨的同时登记进该 beat 的候选池(层取它所在那份 plan;该 beat 没登记就按 plan 时间窗新建),客户端 B-roll 面板随即可见可换;回执 `source.pooled: {beat, layer}`。已在池里的不重复登记。
404
410
  - 先按自述值把全部改动算一遍、全档校验,通过了才落地;`--dry-run` 不下载、不写文件,回执带 `would_download`。回执的 op 另带 `source`(候选 / 素材、`material_id`、`landed`:existing / reused / downloaded / registered)与 `add` 的 `gaps_consumed`。`--ops` 条目同形:`{"action":"add","track":"video:2","to":263.733,"candidate":"…"}`。
405
411
 
412
+ **`remove`(删片段)**:`gtrk patch remove (--clip <id> | --track video:<N> --at <秒>)` 删掉一个片段(或显式空档),原位置留空——后面的片段不动(B-roll 与口播对齐靠的就是时间位置;要补平用 `patch seal`,要挪用 `patch move`)。镜像对(视频 + 同 id 镜像音频)一起删;beat 轨上的拆分区间不收(`remove_beat_track`);带别的参数报 `remove_args`。素材登记保留;引用它的转场写回前统一维护(`transition_dropped`)。`--ops` 条目 `{"action":"remove","clip":"…"}`,可与 `add` 同批「删了再放」。
413
+
406
414
  **转场字段的保真与维护**(`transition_in` / `transition_out` / `transition_next`;由客户端产生,CLI 本期不产出、无新参数):
407
415
 
408
416
  - `split`:入场转场留前段,出场转场与接下一段的转场归后段(`to_clip_id` 不变),新切口不带转场。
@@ -445,7 +453,7 @@ gtrk matrix status --project <工程目录> --json # 全部 B-roll beat
445
453
  | `clips` | 时间窗内各视频轨上的片段:轨、`clip_id`、素材、起止、`category`(broll / raw / black_fill / user / a_roll)、是否带产出方身份 |
446
454
  | `gaps` / `black_only` | 主轨之上没有画面的区间(短于一帧的缝不算);其中只盖着黑底补片的区间 |
447
455
 
448
- 不带 `--beat` 时,每个 B-roll beat 一行:时间窗、候选数、plan 候选数、已覆盖秒数、空缺段数与秒数。顶层另给工程 `revision`(可直接作 `gtrk patch --expected-revision`)、`main_track`、重投影摘要、各候选轨的剥离判定与 `lay.relay_refused`(现在整轮重铺会不会被 `tracks_edited` 拒)。非 B-roll 车道的 beat 只给时间窗、车道与轨上片段。beat 不存在时 `ok:false`、退出码 1,并列出全部已知 beat。
456
+ 不带 `--beat` 时,每个 B-roll beat 一行:时间窗、候选数、plan 候选数、已覆盖秒数、空缺段数与秒数。顶层另给工程 `revision`(可直接作 `gtrk patch --expected-revision`)、`main_track`、全工程视频轨总览 `video_tracks[]`(`{track, track_index, main?, verdict, layer?, clips, hidden?}`,按轨号升序,空轨也列;人读首行「视频轨:…」——`gtrk patch --track` 用这里的轨号)、重投影摘要、各候选轨的剥离判定与 `lay.relay_refused`(现在整轮重铺会不会被 `tracks_edited` 拒)。非 B-roll 车道的 beat 只给时间窗、车道与轨上片段。beat 不存在时 `ok:false`、退出码 1,并列出全部已知 beat。
449
457
 
450
458
  ### `gtrk matrix` — B-roll 检索 + 候选铺轨
451
459
 
@@ -468,6 +476,10 @@ gtrk matrix status --project <工程目录> --json # 全部 B-roll beat
468
476
  | `--arrange-cost-cap <n>` | 云端编排单次编排量上限:超限服务端**前置拒绝**、零执行零计费(不是跑到一半掐断)。只在 `--arrange shadow\|cloud` 时有意义 | 不限 |
469
477
  | `--dump-request <file>` | **排障用**:把**实际上行的**云端编排请求体逐字节写到该文件。服务端**不保存你的 plan**(只留规模摘要),所以出了问题只有这份文件能复现——把它发给我们即可。⚠️ **不能指向工程目录内**(工程会被打包、拷贝、同步出去,而这份文件里有你的 beat 名与检索词);开 `--arrange-qc` 时每轮各写一份,第 N 轮落在同名加 `.roundN`。机读回执在 `lay.arrange_run.dump_request` | 不写 |
470
478
  | `--explain` | **外发调参仪表**:缺省的机读账面只给「留空槽数」`lay.dedup.emptySlots`(够判断素材池是不是不够用),其余调参用的细账(其中多少是窗口精修致空、跳剪避让枯竭放行几次、取用了几个高运动/模糊段)收在本开关后,人读日志同口径。不影响任何决策,工程产物逐字节不变 | 关 |
479
+ | `--query <q>` | `matrix search` 的检索词,可重复给:一次跑完多个角度,结果按 clip 合并(留最高分)、标 `matched_queries`、分数降序,回执多 `queries`。位置参数(整串一个词)在前;外网检索一次只收一个词 | — |
480
+ | `--estimate-only` | `matrix search`:只报这次最多花多少积分、不检索——`--json` 的 `billing_estimate: {credits, basis}`(`credits` 为本次花费上界,按超额价算;算不出为 `null`,如公开口价目表取不到、外网检索单价不在公开价目表里)。成员口 0、公开口按价目表 × 检索词数、`--local` 0。即剪内置 AI 据此对估价不超过 100 积分的命令免确认 | 关 |
481
+ | `--beat <id>` + `--project <dir>`(`matrix search`) | 把检索结果写进这个 beat 的候选池、不铺轨:并进本层快照 `split/broll-plan.<层>.json`(`gtrk patch --candidate` 直接认得),追加进工程候选登记(客户端面板立刻可见;beat 没登记就按派单时间窗新建)。重跑不重复;回执 `pool: {beat, added_to_plan, added_to_pool}`。两个参数要成对给 | — |
482
+ | `--pool-only`(`matrix lay`) | 只把 plan 里还没进工程候选池的候选登记进去:**不铺轨、不下载、不动任何轨**,零网络、不需要 Key(治 `matrix status` 的 `not_in_pool`)。缺省读主 plan 与各层快照(`--plan` 只读那一份),层取各自 plan;配 `--beat <id,…>` 只登记这几个 beat(不在 plan 里报错);一条都没新增时不写工程。回执 `{pool_only:true, pooled:[{beat, layer, added}]}`。`matrix lay` 的 `--beat` 只配本开关 | 关 |
471
483
  | `--arrange-estimate-only` | **只要预估不要执行**:走到云端编排的计价确认那一步就停,报出编排量后**成功**返回(`ok:true` + `estimateOnly:true`——那是「我在做决定」,不是「我拒绝了」),零云端调用、工程文件零改动。机读值在 `lay.arrange.units` / `lay.arrange.scale`。⚠️ 它省的是**云端那一次调用与其计费**(以及其后的候选下载与落轨),不是整条链:编排量的分母本来就要读工程、读 plan、做重投影才算得出。素材矩阵路报 `applicable:false` 而**不是 0**。与 `--yes` 同给时以本开关为准 | 关 |
472
484
  | `--cut-align <ratio>` | 句界吸附目标比例 0..1:`0.7` ≈ 约七成字幕句起点恰逢镜头切点、三成有意错开(全对齐反而机械),`0` = 关闭、回旧节奏切槽。⚠️ 句级时码取 `transcript` 现场重投影(与关键词锚同源),**重投影降级时自动回旧行为并告警**——那一轮的吸附比例不作数 | `0.7` |
473
485
  | `--gap-fill <mode>` | 音频驱动工程主轨的空洞怎么填:`fast` = **尽量不留黑**(放宽 score 地板从候选池填 → 耗尽则延长相邻颗粒 → 再耗尽跨 beat 借候选 → 短于最小镜头长的残洞也补真画面 → 补不满整段才垫黑片);`solid` = 一律黑片垫齐(精修时一眼看出「这里没匹配到」);`none` = 原样留 gap。⚠️ `fast` 借来的画面与本段稿子相关性弱、次地板槽是不到 1.2s 的快切,两者都会在日志里按 `kind` 报成 `borrowed` / `subfloor`——**如实告知,不是缺陷**;`none` 撞上客户端主轨磁吸会把 gap 吸掉,导致其后画面与配音**整体错位** | `solid` |
@@ -544,6 +556,7 @@ gtrk matrix lay --project <目录> [--plan <path>] # ③ 消费(
544
556
  - **含本地素材的工程不能云渲**:提交会被拒(`local_broll_cloud_render_rejected`)——走客户端本地出片或 `gtrk render`。
545
557
  - **可选零件**:`matrix describe --plan <path> [--top-k N]` / `--materials <a,b>` 按需理解候选(VLM 描述/标签/质量分/水印·字幕·黑边·模糊信号,1 积分/张(**异步任务计费**:提交预扣→完成结算,失败自动退款;同合云内部成员豁免,跑时自动探测,`--json` 的 `credits_estimated` 即实耗、`credits_would_be` 为原价)、产物注入 plan 并本地缓存、缓存命中零计费、>20 张确认护栏)。**一条 describe 只代表一段**:`--plan` 形态每个候选只抽 `segments[0]` 的 best 一帧,产物带射程锚点 `describe.at_sec`(素材时基秒),跑完报「理解覆盖率 = 理解帧数 / 被理解候选携带的**段总数**」(`--json` 读 `describe_coverage`)——注入 N 条 ≠ 这 N 条候选都被看过;`--source-window <start,end>` 源时间窗过滤(仅 `--local`,影视解说式「第 N 段解说配影片第 N 段邻域画面」);`matrix lay --mark-weight <0..1>` 把 describe 的质量分融进候选排序(融合分 = sim×(1-w)+(mark/100)×w,只重排序不改准入,无缓存候选按中性处理)。
546
558
  - **看点准则**:`--highlight-rubric <text|@file>`(describe 与 lay 同参,≤2000 字符,`@<路径>` 从文件读)给看点分(`--highlight-weight`)指定**评判基准**——垂类图纸各持一份(美食判分量对比/价格实物,旅拍判奇观地貌/极端天候)。**不传 = 整个字段不上行、服务端走领域无关缺省,与本参数引入前逐字节一致**。看点分按准则分桶缓存:换准则只重打分、客观描述缓存照常复用不被覆盖;`describe --plan` 会把本轮准则的 `rubric_hash` 钉进 plan,`lay` 据此自动取同一个桶(无需重复传参),两者不同源时**硬失败**而不是静默择一。⚠️ 换准则要重新打分就得重新看片(按张计费)——免看片的文本级重打分要等服务端轻通道,现在没有。
559
+ - **宫格理解**:`matrix describe --layout grid` 让服务端把同一 query 的候选(`--materials` 为同一素材)拼成宫格批量理解(每页 ≤9 帧,逐格扫描角标与黑边,模糊由清晰度指标判),**单价仍 1 积分/张**、更快、同样的钱能看更多帧;但 mark / highlight **只在同页内可比**、景别与黑边不如逐张稳,要按 `--mark-weight` / `--highlight-weight` 排序或依赖景别时用缺省逐张。**不传 `--layout` = 逐张,请求体与本参数引入前逐字节一致**。是否真按宫格执行以服务端回执为准(未升级 / 运维停用时如实告知「本轮按逐张」,`--json` 读 `layout_receipt`);缓存记每帧的产出方式,逐张理解**不复用宫格产物**(会按逐张重理解并单列张数)。
547
560
  - **索引参数与量纲**:`--scene-threshold` 调场景切分粒度、`--stability-threshold` 固定机位判稳收敛抽帧、`--rebuild` 强制重建(理解缓存不清);索引跨机不可移植(键=绝对路径,换机重跑 index 即可)。本地 score 量纲与云端不同(完美命中可低至 ~0.25),`--score-floor` 别按云端直觉调高。
548
561
 
549
562
  **`gtrk matrix material "<词>"`(通用三态素材检索)**:与上面的 B-roll 检索并列的第二条线,出**整条素材**的下载直链(不是段落)——`--scope clip|image|audio`(缺省 `audio`,BGM 主场)、`--commercial-only` 只搜可商用(**按需收紧的显式开关,缺省不带**)、`--min-duration/--max-duration` 按成片时长挑、`--top-k`(缺省 5,服务端上限 50)、`--diversity` 去同质、`--json` 机读、`--out` 落盘。`--scope clip|image` 时另附 **Pexels 补充结果**,单列在 `pexels_results`、不计入候选数(`--no-stock` 关闭);补充素材直接用 `download_url` 下载(不走 `matrix fetch`),引用时保留摄影师署名与 Pexels 链接。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitruck/cli",
3
- "version": "1.3.14",
3
+ "version": "1.3.15",
4
4
  "description": "同合云成片流水线 CLI —— agent 驱动云端任务、产物拉回本地、三方工程文件(客户端/剪映/PR)互通。",
5
5
  "license": "MIT",
6
6
  "author": "Gitruck (同合云)",
@@ -70,6 +70,9 @@ gtrk matrix describe --materials <同一素材> --review <工程目录/visual-ov
70
70
  gtrk matrix lay --project <目录> --json # ④ 消费你编辑后的 plan 铺轨
71
71
  ```
72
72
  - **变奏点**:`--top-k` 控理解成本(1 积分/张,只理解你会认真考虑的那几条);云端 plan 同样可 describe(帧从签名 url 现抽);理解产物有本地缓存,反复迭代不重复扣费。
73
+ 要**看得多**(候选多、只用 flags 与描述做取舍)时加 `--layout grid`:服务端把同一 query 的候选拼成宫格批量理解,更快、同样单价能放开 `--top-k`;
74
+ 但宫格的 mark / highlight 只在同页内可比、景别与黑边不如逐张稳——接下来要 `lay --mark-weight / --highlight-weight` 排序或依赖景别时,
75
+ 对真正要比的那几条再跑一遍缺省逐张(逐张不复用宫格缓存,会重理解并单列张数)。服务端是否真用了宫格看 describe 的回执告知 / `--json` 的 `layout_receipt`。
73
76
  - **裁定要点**:`usable_flags` 是信号不是判决——结合 `desc` 复核(水印在角落的航拍也许仍可用);剔除动作=从 plan 删掉那条 result,CLI 不会替你剔。
74
77
  另读 describe 输出的**剔除风险**清单:候选数 ≤1 的 beat 一删就掏空(音频驱动 ⇒ 整段黑屏或跨 beat 借片;口播 ⇒ 露 A-roll)。先补素材再剔,MUST NOT 见 flag 就删。
75
78
  该清单只是判据,剔不剔仍归你(铁律①「零件不裁定」,见 §四层架构与三条铁律)。
@@ -277,6 +280,7 @@ gtrk matrix describe --materials <同一素材> --review <工程目录/visual-ov
277
280
  | 只理解前 N 条 | `--top-k <n>` | 整数 · 全部 | 每 query 限量(省钱:只理解会认真考虑的候选) |
278
281
  | 直接理解素材文件 | `--materials <a,b,...>` | 逗号分隔文件 · — | 视频按**场景中点**逐帧理解;图片文件直传;结果在 stdout JSON `items` |
279
282
  | 跳过确认 | `--yes` | 开关 · 关 | 将实际调用 >20 张才触发确认(预估积分明示);internal 豁免免确认仅提示 |
283
+ | 看得多、快一点 | `--layout grid` | `single` / `grid` · 不传 = 逐张 | 服务端宫格批量理解(同 query / 同素材同页,≤9 帧一页,单价不变);分数只在同页内可比、景别与黑边不如逐张稳;以回执 `layout_receipt` 为准;逐张不复用宫格缓存 |
280
284
 
281
285
  理解产物形态:`{desc(≤200字中文描述), tags[], mark(0-100 质量分), usable_flags{watermark, text_overlay, black_border, blurry}, at_sec(射程锚点)}`。**缓存即钱**:产物按(素材, 帧时刻)落本地索引库,同帧重复 describe 零调用零计费;素材内容变了(size:mtime 指纹变)该素材缓存自动作废。
282
286
 
@@ -480,7 +484,8 @@ gtrk matrix --project "<split 产物目录>" [--lay N] [--score-floor F] [--top-
480
484
  | **`--online` 结果带 `plan_kept`** | 外网这轮零可铺候选,**既有 plan 没被覆盖**(`planPath` 仍是上一轮的,可直接 `matrix lay`);本轮逐条报错与待核候选在 `plan_kept.online_attempt_path`,照它说明失败原因 |
481
485
  | **外网「0 条自动候选,另有 N 条待人工确认」**(`counts.review_only` > 0) | 不是失败、也**不要重跑**(同参重跑结果不变,换描述 = 新建计费任务):需求里写了地点 / 事件 / 年份 / 素材类型这类硬条件,服务端在画面上核实不了,整批进了 plan 的 `queries[].online.review_candidates`(铺轨后也进客户端候选池)。你按标题 / 片段裁定,把贴题的条目**原样搬**进同一 query 的 `results`(可加 `pinned:true`)后 `gtrk matrix lay --plan <plan>`。硬条件只写真正非满足不可的;只是偏好(「最好是日本的」)写进 `intent` / `visual_description` |
482
486
  | 每段候选太少不够挑 | `--top-k` 调大重跑 |
483
- | 某段有空槽 / 想补特定意象 | `gtrk matrix search "<英文长句场景描述>" --project <目录> --json` 单条补检;影视解说类补检记得带 `--source-window` 保时序 |
487
+ | 某段有空槽 / 想补特定意象 | `gtrk matrix search "<英文长句场景描述>" --project <目录> --beat <id> --json` 补检并写进这个 beat 的候选池(不铺轨;客户端面板立刻可见,`patch add --candidate` 直接认得);几个角度一次跑:`--query "<词1>" --query "<词2>"`(按 clip 合并)。影视解说类补检记得带 `--source-window` 保时序 |
488
+ | **plan 里有候选、客户端面板里没有**(`matrix status` 的 `plan.not_in_pool` > 0) | `gtrk matrix lay --project . --pool-only --beat <id> --json`:只登记候选池,**不铺轨、不新建轨、不下载**。不要为了「让面板看到」去跑局部 `matrix lay`——那会按铺轨口径另起一条候选轨 |
484
489
  | **精修某个 beat / 用户指着某个空位** | 先 `gtrk matrix status --project . --beat <id> --json` 看现状(时间窗、候选池、轨上片段、空缺),再决定补候选还是直接放上轨;**不要**去翻 `split/broll-plan.json` 和 `.gtrk`(见「精修某个 beat 前」节) |
485
490
  | **用户指着某个空位要换 / 补素材** | `matrix source-import`(用户给了链接)或 `matrix search`(要检索)拿到候选 → `gtrk patch add --project . --track video:<N> --to <空位起点> --candidate <clip_id> --json`(空位被黑底补片占着则 `gtrk patch replace --clip <补片 clip_id> --candidate <clip_id>`)。**不要** `--force-relay`,也不要手改 `.gtrk` |
486
491
  | 只想先看清单不铺轨 | `--lay 0`(只产 plan);之后铺 = `matrix lay`(不重新检索、不重新烧配额) |
@@ -605,7 +610,9 @@ gtrk patch add --project <dir> --track video:2 --to 263.733 --candidate <cli
605
610
  gtrk patch replace --project <dir> --clip <clip_id> --candidate <clip_id> --json
606
611
  ```
607
612
 
608
- - `add`:用 `--to` 指落点(不收 `--at`);时长缺省 = 这个空位的长度,出点贴右邻;候选还没落地会顺手下载预览、登记素材。落点被占就拒(列出挡路片段),被黑底补片占着就改用 `replace`。
613
+ - `add`:用 `--to` 指落点(不收 `--at`);时长缺省 = 这个空位的长度,出点贴右邻;候选还没落地会顺手下载预览、登记素材;候选只在 plan 里时顺手登记进该 beat 的候选池(回执 `source.pooled`)。落点被占就拒(列出挡路片段),被黑底补片占着就改用 `replace`。
614
+ - 一次放多段:`--to A --candidate X --to B --candidate Y`(成对重复;只给一次的参数各段共用),一次下载一次写回;同轨缺省时长下前一段停在后一段起点。
615
+ - `remove`:`gtrk patch remove --clip <clip_id>` 删掉多铺的一段,原位置留空、后面不挪;镜像对一起删。
609
616
  - `replace`:起点、轨、`clip_id` 不动,只换素材与源窗;新素材不够长会**如实缩短**、不拉伸——回执出 `replace_shortened` 时把前后时长告诉用户。
610
617
  - 精修期**不要**整轮 `matrix lay` 或 `--force-relay`:`add` / `replace` 放上去的片段带 patch 自己的产出方身份,所在候选轨判「已编辑」——**同一层**再铺会被拒(`tracks_edited`,工程零改动;不剥你的精修、也不另起一条),**别的层**照常铺、这条轨随层带保留。确要丢掉精修重铺本层才加 `--force-relay`,先问用户。
611
618