ossclip 0.1.17 → 0.1.19
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/README.md +2 -0
- package/editor-dist/assets/index-B44I-xE4.js +163 -0
- package/editor-dist/assets/index-ChRVBVLj.css +1 -0
- package/editor-dist/index.html +2 -2
- package/package.json +4 -4
- package/src/caption-report.ts +217 -0
- package/src/edit.ts +38 -0
- package/src/interactive/ask-input.ts +191 -0
- package/src/interactive/picker.ts +286 -0
- package/src/interactive/produce-wizard.ts +6 -22
- package/src/interactive/suggest-inputs.ts +164 -0
- package/src/overrides-write.ts +77 -0
- package/src/produce.ts +61 -36
- package/src/program.ts +32 -0
- package/editor-dist/assets/index-C8IPo60X.css +0 -1
- package/editor-dist/assets/index-CdwzWN3j.js +0 -162
package/src/produce.ts
CHANGED
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
applyOverrides,
|
|
16
16
|
applyRepairs,
|
|
17
17
|
assembleScenes,
|
|
18
|
-
applyCaptionEdits,
|
|
19
18
|
buildCaptionLines,
|
|
20
19
|
buildCutlist,
|
|
21
20
|
buildZoomPlan,
|
|
@@ -105,6 +104,8 @@ import {
|
|
|
105
104
|
workdirBaseName,
|
|
106
105
|
} from "./stranded-overrides";
|
|
107
106
|
import { editHint } from "./interactive/edit-hint";
|
|
107
|
+
import { reconcileCaptionEdits } from "./caption-report";
|
|
108
|
+
import { overridesWriteLine, writeOverrideDoc } from "./overrides-write";
|
|
108
109
|
import { recordedProduceArgs } from "./replay-argv";
|
|
109
110
|
import { renderCover, renderProduction } from "@ossclip/renderer";
|
|
110
111
|
import {
|
|
@@ -1595,7 +1596,8 @@ export async function produce(inputArg: string, opts: ProduceOptions): Promise<P
|
|
|
1595
1596
|
clipStarts: map.spans.map((s) => s.outIn),
|
|
1596
1597
|
});
|
|
1597
1598
|
// User splits (R16 §61) — after the fill so takes split like scenes, and
|
|
1598
|
-
// before the final override pass so edits on the `id
|
|
1599
|
+
// before the final override pass so edits on the `id@<split id>` halves land
|
|
1600
|
+
// (the suffix is the split's own minted id, §137, not its time). A
|
|
1599
1601
|
// split whose ROOT was a graphic scene already happened once inside
|
|
1600
1602
|
// `splitThenDropHidden` above (PLAN 2026-08-04 Task 1) — re-running it here
|
|
1601
1603
|
// is a no-op for that scene (the split point sits exactly on the joint
|
|
@@ -1607,7 +1609,7 @@ export async function produce(inputArg: string, opts: ProduceOptions): Promise<P
|
|
|
1607
1609
|
}
|
|
1608
1610
|
const { cues: mergedCues, orphans: rawOrphans } = applyOverrides(split, overrideDoc);
|
|
1609
1611
|
// Halves of a TAKE the user deleted after splitting: a take id only exists
|
|
1610
|
-
// once the fill above runs, so its `id
|
|
1612
|
+
// once the fill above runs, so its `id@<split id>` half couldn't have been seen by
|
|
1611
1613
|
// `splitThenDropHidden` earlier (that pass only ever saw graphic scenes).
|
|
1612
1614
|
// Scene halves were already caught above; this is a no-op for them. Same
|
|
1613
1615
|
// order as the editor's live memo.
|
|
@@ -1931,22 +1933,36 @@ export async function produce(inputArg: string, opts: ProduceOptions): Promise<P
|
|
|
1931
1933
|
// caption output for zero visual reason (PLAN Task A4.4).
|
|
1932
1934
|
breakpoints: graphicCues.flatMap((c) => [c.startSec, c.endSec]),
|
|
1933
1935
|
});
|
|
1934
|
-
//
|
|
1935
|
-
//
|
|
1936
|
-
//
|
|
1937
|
-
//
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1936
|
+
// §137 (Task 6 review, Critical 1): the caption half of a run — migrate the
|
|
1937
|
+
// doc's keys, apply what applies, and account for the rest — is one pure
|
|
1938
|
+
// pass in `caption-report.ts`, and this is its I/O.
|
|
1939
|
+
//
|
|
1940
|
+
// MIGRATION RUNS HERE, not only in the editor. The editor's is in memory and
|
|
1941
|
+
// `edits.load` leaves the doc CLEAN, so `onRender` (which saves only when
|
|
1942
|
+
// dirty) sends a user who opened an old project, saw every retype come back
|
|
1943
|
+
// on screen, and clicked Render straight into this function with the
|
|
1944
|
+
// untouched legacy doc — and `applyCaptionEdits` matched nothing, so the
|
|
1945
|
+
// render shipped without a single retype after showing a state strictly more
|
|
1946
|
+
// convincing than the truth. None of the reasoning that keeps this call out
|
|
1947
|
+
// of `edit.ts` applies: `buildCaptionLines` just stamped a real `srcStart`
|
|
1948
|
+
// on every word above (`captions.ts:128`), so there is nothing to backfill
|
|
1949
|
+
// and no repair rule to duplicate.
|
|
1950
|
+
//
|
|
1951
|
+
// THE MIGRATED DOC IS WRITTEN BACK — the decision, stated: through the one
|
|
1952
|
+
// sanctioned `overrides.json` write further down, with its `.bak` and atomic
|
|
1953
|
+
// rename, never a second write here. A legacy key's resolvability DECAYS (it
|
|
1954
|
+
// is found by the word it names, so the next re-plan that rewrites that word
|
|
1955
|
+
// loses it for good), and this is the only durable repair in the product —
|
|
1956
|
+
// the editor's evaporates, as Critical 1 showed. The edits it could NOT
|
|
1957
|
+
// place stay in the doc regardless (`captionEditsToKeep`): they are printed
|
|
1958
|
+
// by name below, and a run that cannot anchor one today is not permission to
|
|
1959
|
+
// delete it — the next run, against a different cut, may place it (final
|
|
1960
|
+
// review, Critical 1).
|
|
1961
|
+
const captionWork = reconcileCaptionEdits(overrideDoc, baseCaptionLines);
|
|
1962
|
+
overrideDoc = captionWork.doc;
|
|
1963
|
+
const captionLines = captionWork.lines;
|
|
1964
|
+
const captionKeysReanchored = captionWork.reanchored;
|
|
1965
|
+
for (const line of captionWork.log) console.log(line);
|
|
1950
1966
|
|
|
1951
1967
|
// Micro zoom punches (FINDINGS §15) reversing at real phrase breaks (§18).
|
|
1952
1968
|
// Breaths are source-time; TimeMap has no span mapper, so both ends go
|
|
@@ -2185,23 +2201,32 @@ export async function produce(inputArg: string, opts: ProduceOptions): Promise<P
|
|
|
2185
2201
|
// next run's `priorMap` then sees drift and re-anchors again, the same
|
|
2186
2202
|
// recovery path finding 3 already has to support — never a false "nothing
|
|
2187
2203
|
// changed" that quietly corrupts positions.
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2204
|
+
// `cutResult.changed` OR a §137 caption-key migration that actually MOVED an
|
|
2205
|
+
// edit — the second is why this is no longer a bare cut check. Both are
|
|
2206
|
+
// re-anchorings of the user's doc to something the pipeline just recomputed,
|
|
2207
|
+
// and both go through the one sanctioned write; a separate write for the
|
|
2208
|
+
// migration would be a SECOND sanctioned write, which the comment above
|
|
2209
|
+
// exists to prevent.
|
|
2210
|
+
//
|
|
2211
|
+
// "ACTUALLY MOVED" is load-bearing and was not there at first (final review,
|
|
2212
|
+
// Critical 2). Gated on "the migration reported something" instead, this
|
|
2213
|
+
// fires on a run that repaired NOTHING — and since a caption migration is
|
|
2214
|
+
// independent of the cut, it fires on runs where the pre-§137 gate wrote
|
|
2215
|
+
// nothing at all.
|
|
2216
|
+
//
|
|
2217
|
+
// THEY DO NOT SHARE THE `.bak`, THOUGH, and that is the rest of the same
|
|
2218
|
+
// finding (final review round 2). `refreshBackup: cutResult.changed`, never
|
|
2219
|
+
// the gate: on the field workdir the caption migration re-anchors THREE
|
|
2220
|
+
// edits, so the gate legitimately fires while `cutResult.changed` is false —
|
|
2221
|
+
// and an unconditional refresh would then copy the already-damaged
|
|
2222
|
+
// `overrides.json` over `overrides.json.bak`, which is that user's only
|
|
2223
|
+
// pre-cut save and the only artefact their deleted split half can still be
|
|
2224
|
+
// recovered from (`legacySplitId`). Repairing the captions would destroy the
|
|
2225
|
+
// evidence for the split. `writeOverrideDoc` carries the full argument for
|
|
2226
|
+
// why a caption-only write has nothing worth backing up.
|
|
2227
|
+
if (cutResult.changed || captionKeysReanchored) {
|
|
2228
|
+
await writeOverrideDoc(overridesPath, overrideDoc, { refreshBackup: cutResult.changed });
|
|
2229
|
+
console.log(overridesWriteLine(cutResult.changed));
|
|
2205
2230
|
}
|
|
2206
2231
|
|
|
2207
2232
|
if (!opts.render) {
|
package/src/program.ts
CHANGED
|
@@ -7,6 +7,21 @@ import { CleanupLevelSchema, SceneComponentIdSchema } from "@ossclip/core";
|
|
|
7
7
|
import { STUDIO_ENTRY } from "@ossclip/renderer";
|
|
8
8
|
import { loadEnvFiles } from "./env";
|
|
9
9
|
import { produce } from "./produce";
|
|
10
|
+
// The one interactive import that is STATIC rather than `await import()`: the
|
|
11
|
+
// `resetInputSource()` run boundary in `buildProgram` has to run synchronously
|
|
12
|
+
// while the program is being built, and `buildProgram` cannot await. The graph
|
|
13
|
+
// already loads @ossclip/renderer and @ossclip/scenes eagerly through
|
|
14
|
+
// produce.ts, so clack riding along costs ~14ms on a ~320ms startup — cheap
|
|
15
|
+
// enough not to trade for a racy fire-and-forget import (§136).
|
|
16
|
+
//
|
|
17
|
+
// Consequence worth stating for whoever edits ask-input.ts next: this module,
|
|
18
|
+
// and everything it imports (picker.ts, prompts.ts → @clack/prompts,
|
|
19
|
+
// suggest-inputs.ts), is now EAGER on every ossclip invocation — `--version`
|
|
20
|
+
// and `doctor` included. A heavy dependency added there is no longer free.
|
|
21
|
+
// Removing this line to "restore laziness" deletes the run boundary with it:
|
|
22
|
+
// `input_source` would then report the PREVIOUS run's branch, and the only
|
|
23
|
+
// test that notices is the buildProgram case in telemetry.test.ts.
|
|
24
|
+
import { inputSourceUsed, resetInputSource } from "./interactive/ask-input";
|
|
10
25
|
import { setReplayArgv } from "./replay-argv";
|
|
11
26
|
import {
|
|
12
27
|
bootstrapTelemetry,
|
|
@@ -38,6 +53,19 @@ const envFiles = loadEnvFiles();
|
|
|
38
53
|
export function buildProgram(): Command {
|
|
39
54
|
const program = new Command();
|
|
40
55
|
|
|
56
|
+
// §136: the input-source telemetry is module state, so something has to say
|
|
57
|
+
// when a RUN begins. Not the produce action — every wizard route re-enters
|
|
58
|
+
// that same action through `program.parseAsync` (§129), so a reset there
|
|
59
|
+
// fires on the re-entered parse, AFTER `askInput` recorded the branch, and
|
|
60
|
+
// `input_source` would read "argv" for every wizard run: the feature would
|
|
61
|
+
// measure exactly nothing. Nor is the process the boundary — a batch or REPL
|
|
62
|
+
// driver runs produce more than once, and the second run would report the
|
|
63
|
+
// first one's branch. The PROGRAM CONSTRUCTION is the boundary: commander 12
|
|
64
|
+
// keeps option state across parseAsync calls (see the bare-`produce` refusal
|
|
65
|
+
// below), so any batch has to rebuild the program per run anyway, which makes
|
|
66
|
+
// one reset per `buildProgram` exactly one per run in both cases.
|
|
67
|
+
resetInputSource();
|
|
68
|
+
|
|
41
69
|
// Before dispatch, so the one-time first-run notice precedes any command's
|
|
42
70
|
// own output. Inert in this repo's tests by construction: while POSTHOG_KEY
|
|
43
71
|
// is the placeholder, bootstrap touches no disk and sends nothing (FINDINGS
|
|
@@ -433,6 +461,10 @@ export function buildProgram(): Command {
|
|
|
433
461
|
render: opts.render !== false,
|
|
434
462
|
source_duration_bucket: durationBucket(result.sourceDurationSec),
|
|
435
463
|
scenes: result.sceneCount,
|
|
464
|
+
// Which branch of the input prompt was used — a branch name, never
|
|
465
|
+
// the path itself (§136). The picker exists because typing a path
|
|
466
|
+
// blocked non-technical users; this is how we find out if it helped.
|
|
467
|
+
input_source: inputSourceUsed(),
|
|
436
468
|
});
|
|
437
469
|
if (!telemetry.disabled) {
|
|
438
470
|
telemetry.state.produceCount += 1;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.ossclip-scroll-list{scrollbar-width:thin;scrollbar-color:#3a3a44 transparent}.ossclip-scroll-list::-webkit-scrollbar{width:8px}.ossclip-scroll-list::-webkit-scrollbar-track{background:transparent}.ossclip-scroll-list::-webkit-scrollbar-thumb{background:#3a3a44;border-radius:4px}
|