ossclip 0.1.28 → 0.1.29
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/package.json +4 -4
- package/src/interactive/produce-argv.ts +14 -0
- package/src/interactive/produce-wizard.ts +28 -0
- package/src/produce.ts +41 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ossclip",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"description": "Local-first CLI video producer: cuts silence and fillers, word-timed captions, face-aware framing, and LLM-planned code-rendered graphics — transcription and rendering never leave your machine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"commander": "^12.1.0",
|
|
37
37
|
"tsx": "^4.19.0",
|
|
38
38
|
"zod": "^3.25.76",
|
|
39
|
-
"@ossclip/core": "0.1.
|
|
40
|
-
"@ossclip/scenes": "0.1.
|
|
41
|
-
"@ossclip/renderer": "0.1.
|
|
39
|
+
"@ossclip/core": "0.1.29",
|
|
40
|
+
"@ossclip/scenes": "0.1.29",
|
|
41
|
+
"@ossclip/renderer": "0.1.29"
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://github.com/AhsanAyaz/ossclip#readme",
|
|
44
44
|
"bugs": {
|
|
@@ -63,6 +63,15 @@ export interface ProduceAnswers {
|
|
|
63
63
|
graphics: boolean;
|
|
64
64
|
intent?: string;
|
|
65
65
|
out?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Review the cut in the editor instead of rendering now (§148). A main-flow
|
|
68
|
+
* answer like `graphics`, not an extra: it decides what the run DOES, and
|
|
69
|
+
* burying it in "Anything else?" would hide it from the people the wizard
|
|
70
|
+
* exists for. The only answer whose wizard default (review) differs from
|
|
71
|
+
* the CLI's (render) — which costs nothing here, because the elision rule
|
|
72
|
+
* below keys off the CLI default, not off what the prompt preselected.
|
|
73
|
+
*/
|
|
74
|
+
review?: boolean;
|
|
66
75
|
extras: ProduceExtras;
|
|
67
76
|
}
|
|
68
77
|
|
|
@@ -76,6 +85,11 @@ export function produceArgv(a: ProduceAnswers): string[] {
|
|
|
76
85
|
if (a.aspect !== "9:16") argv.push("--aspect", a.aspect);
|
|
77
86
|
if (a.cleanup !== "standard") argv.push("--cleanup", a.cleanup);
|
|
78
87
|
if (a.out) argv.push("--out", a.out);
|
|
88
|
+
// Rendering is the CLI's default, so only reviewing is worth saying — the
|
|
89
|
+
// rule above is about the DEFAULT, not about which option the prompt
|
|
90
|
+
// preselected. --out still travels either way: nothing renders now, but the
|
|
91
|
+
// editor's Render button replays command.json, and that is where out lands.
|
|
92
|
+
if (a.review === true) argv.push("--review");
|
|
79
93
|
|
|
80
94
|
if (a.graphics) {
|
|
81
95
|
argv.push("--produce");
|
|
@@ -505,6 +505,33 @@ export async function produceWizard(
|
|
|
505
505
|
) as ProduceExtras["llm"];
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
+
// LAST, because it decides what happens after every answer above it — and
|
|
509
|
+
// asked at all because until §148 the wizard could not reach --review, so
|
|
510
|
+
// `ossclip` with no arguments, the entry point a first-time user takes,
|
|
511
|
+
// could only render first and offer the editor afterwards. That is the
|
|
512
|
+
// opposite of what --review is for: the render is the expensive step, and
|
|
513
|
+
// reviewing exists so it happens once, on a cut you already agreed with.
|
|
514
|
+
//
|
|
515
|
+
// Leaning to review is the one place a wizard default differs from the
|
|
516
|
+
// CLI's. It costs nothing: produceArgv elides against the CLI default, so
|
|
517
|
+
// choosing to render still teaches `ossclip produce <file>` and choosing to
|
|
518
|
+
// review teaches the flag that did it.
|
|
519
|
+
const review =
|
|
520
|
+
unwrap(
|
|
521
|
+
await select({
|
|
522
|
+
message: "Render now, or review the cut first?",
|
|
523
|
+
initialValue: "review",
|
|
524
|
+
options: [
|
|
525
|
+
{
|
|
526
|
+
value: "review",
|
|
527
|
+
label: "Review the cut first",
|
|
528
|
+
hint: "opens the editor; render from its button",
|
|
529
|
+
},
|
|
530
|
+
{ value: "render", label: "Render now", hint: "straight to a finished file" },
|
|
531
|
+
],
|
|
532
|
+
}),
|
|
533
|
+
) === "review";
|
|
534
|
+
|
|
508
535
|
return produceArgv({
|
|
509
536
|
input,
|
|
510
537
|
aspect,
|
|
@@ -514,6 +541,7 @@ export async function produceWizard(
|
|
|
514
541
|
// Already `string | undefined`: pickSavePath's use-default row IS the
|
|
515
542
|
// old empty answer — no --out, produce derives its own default.
|
|
516
543
|
out,
|
|
544
|
+
review,
|
|
517
545
|
extras,
|
|
518
546
|
});
|
|
519
547
|
}
|
package/src/produce.ts
CHANGED
|
@@ -152,6 +152,7 @@ import {
|
|
|
152
152
|
type LlmEffort,
|
|
153
153
|
type LlmProvider,
|
|
154
154
|
type LlmUsage,
|
|
155
|
+
AGY_PRINT_TIMEOUT,
|
|
155
156
|
type Production,
|
|
156
157
|
ossclipOutputPathFor,
|
|
157
158
|
type ProviderName,
|
|
@@ -1413,6 +1414,14 @@ export function cleanupChoicesLine(vetoed: readonly Segment[], outputDuration: n
|
|
|
1413
1414
|
* and even on a talking head a 7% lurch reads as the camera stumbling. Big
|
|
1414
1415
|
* enough to break up the jump, small enough to pass as sensor noise.
|
|
1415
1416
|
*/
|
|
1417
|
+
/**
|
|
1418
|
+
* How long a silent antigravity call runs before the spinner admits it (§149).
|
|
1419
|
+
* Well clear of the 17-46s a healthy call takes, so a normal run never shows
|
|
1420
|
+
* the notice, and well short of AGY_PRINT_TIMEOUT, so it lands while the wait
|
|
1421
|
+
* still has somewhere to go.
|
|
1422
|
+
*/
|
|
1423
|
+
export const AGY_SLOW_NOTICE_MS = 30_000;
|
|
1424
|
+
|
|
1416
1425
|
export const FACE_PUNCH_SCALE = 1.015;
|
|
1417
1426
|
|
|
1418
1427
|
/**
|
|
@@ -2787,17 +2796,38 @@ export async function produce(inputArg: string, opts: ProduceOptions): Promise<P
|
|
|
2787
2796
|
: null;
|
|
2788
2797
|
if (!aiAnim) console.log(`▸ producing scenes (${providerName})…`);
|
|
2789
2798
|
if (opts.forceComponent) console.log(`▸ forcing every graphic to ${opts.forceComponent}`);
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2799
|
+
// A hung agy is indistinguishable from a working one on screen: the
|
|
2800
|
+
// 2026-08-23 field run sat on this spinner for 605.9s with no hint that
|
|
2801
|
+
// a budget existed or that a recovery was coming, which reads as a
|
|
2802
|
+
// freeze rather than as waiting (§149). Only antigravity has a
|
|
2803
|
+
// print-timeout and a fallback, so only it gets the notice — and only
|
|
2804
|
+
// once the call is actually slow, so a healthy run never sees it.
|
|
2805
|
+
const slowNotice =
|
|
2806
|
+
aiAnim && providerName === "antigravity"
|
|
2807
|
+
? setTimeout(
|
|
2808
|
+
() =>
|
|
2809
|
+
// Short on purpose: StageAnimator clamps the subtitle to the
|
|
2810
|
+
// terminal width and floors that at 40 columns, and the first
|
|
2811
|
+
// draft lost the budget to "falling back to the n...". The
|
|
2812
|
+
// number is the only part that changes what the user does
|
|
2813
|
+
// (wait vs. Ctrl-C), so it has to survive the clamp.
|
|
2814
|
+
aiAnim.update(`agy not replying — falling back at ${AGY_PRINT_TIMEOUT}...`),
|
|
2815
|
+
AGY_SLOW_NOTICE_MS,
|
|
2816
|
+
)
|
|
2817
|
+
: undefined;
|
|
2818
|
+
const result = await phases
|
|
2819
|
+
.time("llm", () =>
|
|
2820
|
+
produceScenes(provider!, {
|
|
2821
|
+
transcript,
|
|
2822
|
+
outputDuration: map.outputDuration,
|
|
2823
|
+
intent: opts.intent,
|
|
2824
|
+
speaker: opts.speaker ?? cfg.speaker,
|
|
2825
|
+
forceComponent: opts.forceComponent,
|
|
2826
|
+
framing: framingCtx,
|
|
2827
|
+
aspect: landscape ? "16:9" : "9:16",
|
|
2828
|
+
}),
|
|
2829
|
+
)
|
|
2830
|
+
.finally(() => clearTimeout(slowNotice));
|
|
2801
2831
|
if (aiAnim) aiAnim.stop();
|
|
2802
2832
|
scenes = result.scenes;
|
|
2803
2833
|
beatSheet = { hook: result.beatSheet.hook, coverText: result.beatSheet.coverText };
|