ossclip 0.1.33 → 0.1.35

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.
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The argv the editor's Render button replays (2026-08-29).
3
+ *
4
+ * A render started FROM the editor must reproduce what the user just
5
+ * reviewed. Replaying `command.json` verbatim did not: it carried
6
+ * `--produce`, so every render re-called the LLM, and the beat-sheet cache
7
+ * key covers the repaired words and the MEASURED framing — both of which the
8
+ * user's own editor work changes. The plan came back renumbered, edits
9
+ * anchored to scenes it no longer had were orphaned, and an approved cut was
10
+ * silently rewritten (the failure `produce.ts`' §143 note already named once,
11
+ * 2026-08-23; hit again through a different door).
12
+ *
13
+ * So the editor pins the plan on screen with `--scenes` (no LLM in the loop)
14
+ * and drops `--produce`. The two paths stay distinct on purpose:
15
+ *
16
+ * - CLI/CI: `--produce` plans fresh. The command line is the authority.
17
+ * - Editor: the reviewed plan is the authority; `replan` opts back in.
18
+ *
19
+ * Pure, so the whole matrix is testable without spawning a produce.
20
+ */
21
+ /** The reviewed plan the editor pins for a render (see the module docstring).
22
+ * Its own name, never `scenes-<key>.json`: those are keyed to a beat sheet
23
+ * this render may no longer match. */
24
+ export const REVIEWED_SCENES_BASENAME = "scenes-reviewed.json";
25
+
26
+ export function renderReplayArgs(
27
+ recorded: readonly string[],
28
+ opts: { scenesPath?: string; replan?: boolean },
29
+ ): string[] {
30
+ // A deliberate re-plan replays exactly what was recorded — including
31
+ // `--produce` when it was there, since that IS the fresh-plan request.
32
+ if (opts.replan === true || opts.scenesPath === undefined) return [...recorded];
33
+
34
+ const out: string[] = [];
35
+ for (let i = 0; i < recorded.length; i++) {
36
+ const arg = recorded[i]!;
37
+ // `--produce` is a boolean flag: drop it alone, never a following value.
38
+ if (arg === "--produce") continue;
39
+ // An existing `--scenes <path>` is dropped WITH its value: two of them
40
+ // would let commander pick one, and the stale one is precisely the plan
41
+ // the editor is not showing.
42
+ if (arg === "--scenes") {
43
+ i++;
44
+ continue;
45
+ }
46
+ out.push(arg);
47
+ }
48
+ out.push("--scenes", opts.scenesPath);
49
+ return out;
50
+ }
@@ -20,6 +20,9 @@
20
20
  // Type-only, so no runtime edge back into produce.ts (which imports this
21
21
  // module): the tri-state's vocabulary belongs to its resolver.
22
22
  import type { JumpCutsMode } from "./produce";
23
+ // Type-only for the same reason: the level's own zod enum lives in core's
24
+ // producer half, and this module must stay a pure argv builder.
25
+ import type { SfxLevel } from "@ossclip/core";
23
26
 
24
27
  let stashed: string[] | null = null;
25
28
 
@@ -71,6 +74,10 @@ export function recordedProduceArgs(pins: {
71
74
  audience?: string;
72
75
  /** The RESOLVED thumbnail brief — pinned only when non-empty. */
73
76
  thumbnailBrief?: string;
77
+ /** The RESOLVED `--sfx` switch (flag or config), pinned only when ON. */
78
+ sfx?: boolean;
79
+ /** The RESOLVED `--sfx-level`, pinned alongside an ON `sfx`. */
80
+ sfxLevel?: SfxLevel;
74
81
  }): string[] {
75
82
  // --review and --no-render are stripped at record (cut-review step 1):
76
83
  // command.json exists for exactly one consumer — the editor's Render
@@ -201,5 +208,28 @@ export function recordedProduceArgs(pins: {
201
208
  ) {
202
209
  args.push("--thumbnail-brief", pins.thumbnailBrief);
203
210
  }
211
+ // The sound-effect pins, the watermark's config-dependent-default rationale
212
+ // on a pair of flags: `sfx`/`sfxLevel` are both config keys, so an unpinned
213
+ // record replays a different amount of sound design — or none — the moment
214
+ // that config is edited or the replay runs on another machine. It matters
215
+ // more here than for the watermark: an editor render carries the REVIEWED
216
+ // plan forward from production.json instead of re-placing (produce's
217
+ // `priorSfxPlan`), so `--sfx` is what decides whether the sound design the
218
+ // user just dragged into place is in the video at all.
219
+ //
220
+ // ON ONLY, and that is the jump-cuts "auto" case rather than the watermark's
221
+ // both-directions rule: there is no `--no-sfx` spelling to pin an off-run
222
+ // with (program.ts declares `--sfx` alone, so the config key can still
223
+ // supply the default). An off-record replayed under a later config-on
224
+ // therefore GAINS sound effects — the accepted cost of a flag with one
225
+ // spelling, and the day `--no-sfx` exists this pin becomes unconditional
226
+ // like the watermark's. `--sfx-level` implies `--sfx`, so a typed level in
227
+ // the argv already settles the switch and the includes-guard leaves it be.
228
+ if (pins.sfx === true) {
229
+ if (!args.includes("--sfx") && !args.includes("--sfx-level")) args.push("--sfx");
230
+ if (pins.sfxLevel !== undefined && !args.includes("--sfx-level")) {
231
+ args.push("--sfx-level", pins.sfxLevel);
232
+ }
233
+ }
204
234
  return args;
205
235
  }