@vibeframe/cli 0.27.0 → 0.30.0
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/LICENSE +21 -0
- package/dist/agent/adapters/index.d.ts +1 -0
- package/dist/agent/adapters/index.d.ts.map +1 -1
- package/dist/agent/adapters/index.js +5 -0
- package/dist/agent/adapters/index.js.map +1 -1
- package/dist/agent/adapters/openrouter.d.ts +16 -0
- package/dist/agent/adapters/openrouter.d.ts.map +1 -0
- package/dist/agent/adapters/openrouter.js +100 -0
- package/dist/agent/adapters/openrouter.js.map +1 -0
- package/dist/agent/types.d.ts +1 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +3 -1
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/ai-edit-cli.d.ts.map +1 -1
- package/dist/commands/ai-edit-cli.js +18 -0
- package/dist/commands/ai-edit-cli.js.map +1 -1
- package/dist/commands/generate.js +14 -0
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/schema.d.ts +1 -0
- package/dist/commands/schema.d.ts.map +1 -1
- package/dist/commands/schema.js +122 -21
- package/dist/commands/schema.js.map +1 -1
- package/dist/commands/setup.js +5 -2
- package/dist/commands/setup.js.map +1 -1
- package/dist/config/schema.d.ts +2 -1
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +2 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/index.js +0 -0
- package/package.json +16 -12
- package/.turbo/turbo-build.log +0 -4
- package/.turbo/turbo-lint.log +0 -21
- package/.turbo/turbo-test.log +0 -689
- package/src/agent/adapters/claude.ts +0 -143
- package/src/agent/adapters/gemini.ts +0 -159
- package/src/agent/adapters/index.ts +0 -61
- package/src/agent/adapters/ollama.ts +0 -231
- package/src/agent/adapters/openai.ts +0 -116
- package/src/agent/adapters/xai.ts +0 -119
- package/src/agent/index.ts +0 -251
- package/src/agent/memory/index.ts +0 -151
- package/src/agent/prompts/system.ts +0 -106
- package/src/agent/tools/ai-editing.ts +0 -845
- package/src/agent/tools/ai-generation.ts +0 -1073
- package/src/agent/tools/ai-pipeline.ts +0 -1055
- package/src/agent/tools/ai.ts +0 -21
- package/src/agent/tools/batch.ts +0 -429
- package/src/agent/tools/e2e.test.ts +0 -545
- package/src/agent/tools/export.ts +0 -184
- package/src/agent/tools/filesystem.ts +0 -237
- package/src/agent/tools/index.ts +0 -150
- package/src/agent/tools/integration.test.ts +0 -775
- package/src/agent/tools/media.ts +0 -697
- package/src/agent/tools/project.ts +0 -313
- package/src/agent/tools/timeline.ts +0 -951
- package/src/agent/types.ts +0 -68
- package/src/commands/agent.ts +0 -340
- package/src/commands/ai-analyze.ts +0 -429
- package/src/commands/ai-animated-caption.ts +0 -390
- package/src/commands/ai-audio.ts +0 -941
- package/src/commands/ai-broll.ts +0 -490
- package/src/commands/ai-edit-cli.ts +0 -658
- package/src/commands/ai-edit.ts +0 -1542
- package/src/commands/ai-fill-gaps.ts +0 -566
- package/src/commands/ai-helpers.ts +0 -65
- package/src/commands/ai-highlights.ts +0 -1303
- package/src/commands/ai-image.ts +0 -761
- package/src/commands/ai-motion.ts +0 -347
- package/src/commands/ai-narrate.ts +0 -451
- package/src/commands/ai-review.ts +0 -309
- package/src/commands/ai-script-pipeline-cli.ts +0 -1710
- package/src/commands/ai-script-pipeline.ts +0 -1365
- package/src/commands/ai-suggest-edit.ts +0 -264
- package/src/commands/ai-video-fx.ts +0 -445
- package/src/commands/ai-video.ts +0 -915
- package/src/commands/ai-viral.ts +0 -595
- package/src/commands/ai-visual-fx.ts +0 -601
- package/src/commands/ai.test.ts +0 -627
- package/src/commands/ai.ts +0 -307
- package/src/commands/analyze.ts +0 -282
- package/src/commands/audio.ts +0 -644
- package/src/commands/batch.test.ts +0 -279
- package/src/commands/batch.ts +0 -440
- package/src/commands/detect.ts +0 -329
- package/src/commands/doctor.ts +0 -237
- package/src/commands/edit-cmd.ts +0 -1014
- package/src/commands/export.ts +0 -918
- package/src/commands/generate.ts +0 -2146
- package/src/commands/media.ts +0 -177
- package/src/commands/output.ts +0 -142
- package/src/commands/pipeline.ts +0 -398
- package/src/commands/project.test.ts +0 -127
- package/src/commands/project.ts +0 -149
- package/src/commands/sanitize.ts +0 -60
- package/src/commands/schema.ts +0 -130
- package/src/commands/setup.ts +0 -509
- package/src/commands/timeline.test.ts +0 -499
- package/src/commands/timeline.ts +0 -529
- package/src/commands/validate.ts +0 -77
- package/src/config/config.test.ts +0 -197
- package/src/config/index.ts +0 -125
- package/src/config/schema.ts +0 -82
- package/src/engine/index.ts +0 -2
- package/src/engine/project.test.ts +0 -702
- package/src/engine/project.ts +0 -439
- package/src/index.ts +0 -146
- package/src/utils/api-key.test.ts +0 -41
- package/src/utils/api-key.ts +0 -247
- package/src/utils/audio.ts +0 -83
- package/src/utils/exec-safe.ts +0 -75
- package/src/utils/first-run.ts +0 -52
- package/src/utils/provider-resolver.ts +0 -56
- package/src/utils/remotion.ts +0 -951
- package/src/utils/subtitle.test.ts +0 -227
- package/src/utils/subtitle.ts +0 -169
- package/src/utils/tty.ts +0 -196
- package/tsconfig.json +0 -20
package/src/commands/ai.test.ts
DELETED
|
@@ -1,627 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { execSync } from "child_process";
|
|
3
|
-
import { resolve } from "path";
|
|
4
|
-
import { detectFillerRanges, DEFAULT_FILLER_WORDS } from "./ai-edit.js";
|
|
5
|
-
|
|
6
|
-
const CLI = `npx tsx ${resolve(__dirname, "../index.ts")}`;
|
|
7
|
-
|
|
8
|
-
describe("CLI command groups", () => {
|
|
9
|
-
describe("audio transcribe", () => {
|
|
10
|
-
it("fails without API key", () => {
|
|
11
|
-
expect(() => {
|
|
12
|
-
execSync(`${CLI} audio transcribe /tmp/nonexistent.mp3`, {
|
|
13
|
-
cwd: process.cwd(),
|
|
14
|
-
encoding: "utf-8",
|
|
15
|
-
env: { ...process.env, OPENAI_API_KEY: undefined },
|
|
16
|
-
});
|
|
17
|
-
}).toThrow();
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
describe("analyze suggest", () => {
|
|
22
|
-
it("fails without API key", () => {
|
|
23
|
-
expect(() => {
|
|
24
|
-
execSync(`${CLI} analyze suggest /tmp/nonexistent.json "trim clip"`, {
|
|
25
|
-
cwd: process.cwd(),
|
|
26
|
-
encoding: "utf-8",
|
|
27
|
-
env: { ...process.env, GOOGLE_API_KEY: undefined },
|
|
28
|
-
});
|
|
29
|
-
}).toThrow();
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe("pipeline highlights", () => {
|
|
34
|
-
it("shows help", () => {
|
|
35
|
-
const output = execSync(`${CLI} pipeline highlights --help`, {
|
|
36
|
-
cwd: process.cwd(),
|
|
37
|
-
encoding: "utf-8",
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
expect(output).toContain("Extract highlights");
|
|
41
|
-
expect(output).toContain("--threshold");
|
|
42
|
-
expect(output).toContain("--criteria");
|
|
43
|
-
expect(output).toContain("--duration");
|
|
44
|
-
expect(output).toContain("--count");
|
|
45
|
-
expect(output).toContain("--output");
|
|
46
|
-
expect(output).toContain("--project");
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("fails without API keys", () => {
|
|
50
|
-
expect(() => {
|
|
51
|
-
execSync(`${CLI} pipeline highlights /tmp/nonexistent.mp4`, {
|
|
52
|
-
cwd: process.cwd(),
|
|
53
|
-
encoding: "utf-8",
|
|
54
|
-
env: { ...process.env, OPENAI_API_KEY: undefined, ANTHROPIC_API_KEY: undefined },
|
|
55
|
-
});
|
|
56
|
-
}).toThrow();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it("fails with nonexistent file", () => {
|
|
60
|
-
expect(() => {
|
|
61
|
-
execSync(`${CLI} pipeline highlights /tmp/nonexistent_video_12345.mp4`, {
|
|
62
|
-
cwd: process.cwd(),
|
|
63
|
-
encoding: "utf-8",
|
|
64
|
-
env: { ...process.env, OPENAI_API_KEY: "test", ANTHROPIC_API_KEY: "test" },
|
|
65
|
-
});
|
|
66
|
-
}).toThrow();
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe("pipeline b-roll", () => {
|
|
71
|
-
it("shows help", () => {
|
|
72
|
-
const output = execSync(`${CLI} pipeline b-roll --help`, {
|
|
73
|
-
cwd: process.cwd(),
|
|
74
|
-
encoding: "utf-8",
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
expect(output).toContain("Match B-roll footage");
|
|
78
|
-
expect(output).toContain("--threshold");
|
|
79
|
-
expect(output).toContain("--broll");
|
|
80
|
-
expect(output).toContain("--broll-dir");
|
|
81
|
-
expect(output).toContain("--output");
|
|
82
|
-
expect(output).toContain("--analyze-only");
|
|
83
|
-
expect(output).toContain("--language");
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("fails without B-roll files", () => {
|
|
87
|
-
expect(() => {
|
|
88
|
-
execSync(`${CLI} pipeline b-roll "test narration"`, {
|
|
89
|
-
cwd: process.cwd(),
|
|
90
|
-
encoding: "utf-8",
|
|
91
|
-
env: { ...process.env, OPENAI_API_KEY: "test", ANTHROPIC_API_KEY: "test" },
|
|
92
|
-
});
|
|
93
|
-
}).toThrow();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("fails without API keys", () => {
|
|
97
|
-
expect(() => {
|
|
98
|
-
execSync(`${CLI} pipeline b-roll test.mp3 -b clip.mp4`, {
|
|
99
|
-
cwd: process.cwd(),
|
|
100
|
-
encoding: "utf-8",
|
|
101
|
-
env: { ...process.env, OPENAI_API_KEY: undefined, ANTHROPIC_API_KEY: undefined },
|
|
102
|
-
});
|
|
103
|
-
}).toThrow();
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
describe("pipeline viral", () => {
|
|
108
|
-
it("shows help", () => {
|
|
109
|
-
const output = execSync(`${CLI} pipeline viral --help`, {
|
|
110
|
-
cwd: process.cwd(),
|
|
111
|
-
encoding: "utf-8",
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
expect(output).toContain("Optimize video for viral potential");
|
|
115
|
-
expect(output).toContain("--platforms");
|
|
116
|
-
expect(output).toContain("--output-dir");
|
|
117
|
-
expect(output).toContain("--analyze-only");
|
|
118
|
-
expect(output).toContain("--skip-captions");
|
|
119
|
-
expect(output).toContain("--caption-style");
|
|
120
|
-
expect(output).toContain("--hook-duration");
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("validates platform names", () => {
|
|
124
|
-
expect(() => {
|
|
125
|
-
execSync(`${CLI} pipeline viral /tmp/test.vibe.json --platforms invalid-platform`, {
|
|
126
|
-
cwd: process.cwd(),
|
|
127
|
-
encoding: "utf-8",
|
|
128
|
-
env: { ...process.env, OPENAI_API_KEY: "test", ANTHROPIC_API_KEY: "test" },
|
|
129
|
-
});
|
|
130
|
-
}).toThrow();
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it("fails without API keys", () => {
|
|
134
|
-
expect(() => {
|
|
135
|
-
execSync(`${CLI} pipeline viral /tmp/test.vibe.json`, {
|
|
136
|
-
cwd: process.cwd(),
|
|
137
|
-
encoding: "utf-8",
|
|
138
|
-
env: { ...process.env, OPENAI_API_KEY: undefined, ANTHROPIC_API_KEY: undefined },
|
|
139
|
-
});
|
|
140
|
-
}).toThrow();
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("fails with nonexistent project", () => {
|
|
144
|
-
expect(() => {
|
|
145
|
-
execSync(`${CLI} pipeline viral /tmp/nonexistent_project_12345.vibe.json`, {
|
|
146
|
-
cwd: process.cwd(),
|
|
147
|
-
encoding: "utf-8",
|
|
148
|
-
env: { ...process.env, OPENAI_API_KEY: "test", ANTHROPIC_API_KEY: "test" },
|
|
149
|
-
});
|
|
150
|
-
}).toThrow();
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
describe("generate video-extend", () => {
|
|
155
|
-
it("shows help", () => {
|
|
156
|
-
const output = execSync(`${CLI} generate video-extend --help`, {
|
|
157
|
-
cwd: process.cwd(),
|
|
158
|
-
encoding: "utf-8",
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
expect(output).toContain("Extend video duration");
|
|
162
|
-
expect(output).toContain("--output");
|
|
163
|
-
expect(output).toContain("--prompt");
|
|
164
|
-
expect(output).toContain("--duration");
|
|
165
|
-
expect(output).toContain("--negative");
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it("fails without API key", () => {
|
|
169
|
-
expect(() => {
|
|
170
|
-
execSync(`${CLI} generate video-extend /tmp/video.mp4`, {
|
|
171
|
-
cwd: process.cwd(),
|
|
172
|
-
encoding: "utf-8",
|
|
173
|
-
env: { ...process.env, KLING_API_KEY: undefined },
|
|
174
|
-
});
|
|
175
|
-
}).toThrow();
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe("edit upscale-video", () => {
|
|
180
|
-
it("shows help", () => {
|
|
181
|
-
const output = execSync(`${CLI} edit upscale-video --help`, {
|
|
182
|
-
cwd: process.cwd(),
|
|
183
|
-
encoding: "utf-8",
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
expect(output).toContain("Upscale video resolution");
|
|
187
|
-
expect(output).toContain("--output");
|
|
188
|
-
expect(output).toContain("--scale");
|
|
189
|
-
expect(output).toContain("--model");
|
|
190
|
-
expect(output).toContain("--ffmpeg");
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it("validates scale option", () => {
|
|
194
|
-
expect(() => {
|
|
195
|
-
execSync(`${CLI} edit upscale-video /tmp/video.mp4 --scale 3 --ffmpeg`, {
|
|
196
|
-
cwd: process.cwd(),
|
|
197
|
-
encoding: "utf-8",
|
|
198
|
-
});
|
|
199
|
-
}).toThrow();
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
describe("edit interpolate", () => {
|
|
204
|
-
it("shows help", () => {
|
|
205
|
-
const output = execSync(`${CLI} edit interpolate --help`, {
|
|
206
|
-
cwd: process.cwd(),
|
|
207
|
-
encoding: "utf-8",
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
expect(output).toContain("slow motion");
|
|
211
|
-
expect(output).toContain("--output");
|
|
212
|
-
expect(output).toContain("--factor");
|
|
213
|
-
expect(output).toContain("--fps");
|
|
214
|
-
expect(output).toContain("--quality");
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it("validates factor option", () => {
|
|
218
|
-
expect(() => {
|
|
219
|
-
execSync(`${CLI} edit interpolate /tmp/video.mp4 --factor 3`, {
|
|
220
|
-
cwd: process.cwd(),
|
|
221
|
-
encoding: "utf-8",
|
|
222
|
-
});
|
|
223
|
-
}).toThrow();
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
// Voice & Audio Features
|
|
228
|
-
describe("audio voice-clone", () => {
|
|
229
|
-
it("shows help", () => {
|
|
230
|
-
const output = execSync(`${CLI} audio voice-clone --help`, {
|
|
231
|
-
cwd: process.cwd(),
|
|
232
|
-
encoding: "utf-8",
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
expect(output).toContain("Clone a voice");
|
|
236
|
-
expect(output).toContain("--name");
|
|
237
|
-
expect(output).toContain("--description");
|
|
238
|
-
expect(output).toContain("--labels");
|
|
239
|
-
expect(output).toContain("--remove-noise");
|
|
240
|
-
expect(output).toContain("--list");
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it("requires name option when cloning", () => {
|
|
244
|
-
expect(() => {
|
|
245
|
-
execSync(`${CLI} audio voice-clone sample.mp3`, {
|
|
246
|
-
cwd: process.cwd(),
|
|
247
|
-
encoding: "utf-8",
|
|
248
|
-
env: { ...process.env, ELEVENLABS_API_KEY: "test" },
|
|
249
|
-
});
|
|
250
|
-
}).toThrow();
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it("fails without API key", () => {
|
|
254
|
-
expect(() => {
|
|
255
|
-
execSync(`${CLI} audio voice-clone sample.mp3 --name "TestVoice"`, {
|
|
256
|
-
cwd: process.cwd(),
|
|
257
|
-
encoding: "utf-8",
|
|
258
|
-
env: { ...process.env, ELEVENLABS_API_KEY: undefined },
|
|
259
|
-
});
|
|
260
|
-
}).toThrow();
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
describe("generate music", () => {
|
|
265
|
-
it("shows help", () => {
|
|
266
|
-
const output = execSync(`${CLI} generate music --help`, {
|
|
267
|
-
cwd: process.cwd(),
|
|
268
|
-
encoding: "utf-8",
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
expect(output).toContain("Generate background music");
|
|
272
|
-
expect(output).toContain("--duration");
|
|
273
|
-
expect(output).toContain("--melody");
|
|
274
|
-
expect(output).toContain("--model");
|
|
275
|
-
expect(output).toContain("--output");
|
|
276
|
-
expect(output).toContain("--no-wait");
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
it("requires API key or shows error", () => {
|
|
280
|
-
try {
|
|
281
|
-
const output = execSync(`${CLI} generate music "upbeat electronic" --no-wait`, {
|
|
282
|
-
cwd: process.cwd(),
|
|
283
|
-
encoding: "utf-8",
|
|
284
|
-
env: { ...process.env, REPLICATE_API_TOKEN: undefined },
|
|
285
|
-
timeout: 10000,
|
|
286
|
-
});
|
|
287
|
-
expect(output).toBeTruthy();
|
|
288
|
-
} catch (error: unknown) {
|
|
289
|
-
const execError = error as { stderr?: string; stdout?: string };
|
|
290
|
-
const errorOutput = execError.stderr || execError.stdout || "";
|
|
291
|
-
expect(errorOutput.toLowerCase()).toMatch(/api|key|token|replicate/i);
|
|
292
|
-
}
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
describe("generate music-status", () => {
|
|
297
|
-
it("shows help", () => {
|
|
298
|
-
const output = execSync(`${CLI} generate music-status --help`, {
|
|
299
|
-
cwd: process.cwd(),
|
|
300
|
-
encoding: "utf-8",
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
expect(output).toContain("Check music generation status");
|
|
304
|
-
expect(output).toContain("task-id");
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it("requires API key or shows error", () => {
|
|
308
|
-
try {
|
|
309
|
-
const output = execSync(`${CLI} generate music-status test-task-id`, {
|
|
310
|
-
cwd: process.cwd(),
|
|
311
|
-
encoding: "utf-8",
|
|
312
|
-
env: { ...process.env, REPLICATE_API_TOKEN: undefined },
|
|
313
|
-
timeout: 10000,
|
|
314
|
-
});
|
|
315
|
-
expect(output).toBeTruthy();
|
|
316
|
-
} catch (error: unknown) {
|
|
317
|
-
const execError = error as { stderr?: string; stdout?: string };
|
|
318
|
-
const errorOutput = execError.stderr || execError.stdout || "";
|
|
319
|
-
expect(errorOutput.toLowerCase()).toMatch(/api|key|token|replicate|task|invalid/i);
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
describe("audio dub", () => {
|
|
325
|
-
it("shows help", () => {
|
|
326
|
-
const output = execSync(`${CLI} audio dub --help`, {
|
|
327
|
-
cwd: process.cwd(),
|
|
328
|
-
encoding: "utf-8",
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
expect(output).toContain("Dub audio/video");
|
|
332
|
-
expect(output).toContain("--language");
|
|
333
|
-
expect(output).toContain("--source");
|
|
334
|
-
expect(output).toContain("--voice");
|
|
335
|
-
expect(output).toContain("--analyze-only");
|
|
336
|
-
expect(output).toContain("--output");
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
it("requires language option", () => {
|
|
340
|
-
expect(() => {
|
|
341
|
-
execSync(`${CLI} audio dub /tmp/video.mp4`, {
|
|
342
|
-
cwd: process.cwd(),
|
|
343
|
-
encoding: "utf-8",
|
|
344
|
-
env: { ...process.env, OPENAI_API_KEY: "test", ANTHROPIC_API_KEY: "test" },
|
|
345
|
-
});
|
|
346
|
-
}).toThrow();
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it("fails without API keys", () => {
|
|
350
|
-
expect(() => {
|
|
351
|
-
execSync(`${CLI} audio dub /tmp/video.mp4 -l es`, {
|
|
352
|
-
cwd: process.cwd(),
|
|
353
|
-
encoding: "utf-8",
|
|
354
|
-
env: { ...process.env, OPENAI_API_KEY: undefined, ANTHROPIC_API_KEY: undefined },
|
|
355
|
-
});
|
|
356
|
-
}).toThrow();
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
it("fails with nonexistent file", () => {
|
|
360
|
-
expect(() => {
|
|
361
|
-
execSync(`${CLI} audio dub /tmp/nonexistent_video_12345.mp4 -l es`, {
|
|
362
|
-
cwd: process.cwd(),
|
|
363
|
-
encoding: "utf-8",
|
|
364
|
-
env: { ...process.env, OPENAI_API_KEY: "test", ANTHROPIC_API_KEY: "test", ELEVENLABS_API_KEY: "test" },
|
|
365
|
-
});
|
|
366
|
-
}).toThrow();
|
|
367
|
-
});
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
describe("edit jump-cut", () => {
|
|
371
|
-
it("shows help", () => {
|
|
372
|
-
const output = execSync(`${CLI} edit jump-cut --help`, {
|
|
373
|
-
cwd: process.cwd(),
|
|
374
|
-
encoding: "utf-8",
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
expect(output).toContain("Remove filler words");
|
|
378
|
-
expect(output).toContain("--fillers");
|
|
379
|
-
expect(output).toContain("--padding");
|
|
380
|
-
expect(output).toContain("--analyze-only");
|
|
381
|
-
expect(output).toContain("--language");
|
|
382
|
-
expect(output).toContain("--api-key");
|
|
383
|
-
expect(output).toContain("--output");
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
it("fails with nonexistent file", () => {
|
|
387
|
-
expect(() => {
|
|
388
|
-
execSync(`${CLI} edit jump-cut /tmp/nonexistent_video_12345.mp4`, {
|
|
389
|
-
cwd: process.cwd(),
|
|
390
|
-
encoding: "utf-8",
|
|
391
|
-
env: { ...process.env, OPENAI_API_KEY: "test" },
|
|
392
|
-
});
|
|
393
|
-
}).toThrow();
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
it("fails without API key", () => {
|
|
397
|
-
expect(() => {
|
|
398
|
-
execSync(`${CLI} edit jump-cut /tmp/nonexistent.mp4`, {
|
|
399
|
-
cwd: process.cwd(),
|
|
400
|
-
encoding: "utf-8",
|
|
401
|
-
env: { ...process.env, OPENAI_API_KEY: undefined },
|
|
402
|
-
});
|
|
403
|
-
}).toThrow();
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
describe("detectFillerRanges", () => {
|
|
408
|
-
const words = [
|
|
409
|
-
{ word: "Hello", start: 0.0, end: 0.5 },
|
|
410
|
-
{ word: "um", start: 0.6, end: 0.9 },
|
|
411
|
-
{ word: "I", start: 1.0, end: 1.1 },
|
|
412
|
-
{ word: "think", start: 1.2, end: 1.5 },
|
|
413
|
-
{ word: "like", start: 1.6, end: 1.9 },
|
|
414
|
-
{ word: "this", start: 2.0, end: 2.3 },
|
|
415
|
-
{ word: "is", start: 2.4, end: 2.6 },
|
|
416
|
-
{ word: "basically", start: 2.7, end: 3.2 },
|
|
417
|
-
{ word: "great", start: 3.3, end: 3.6 },
|
|
418
|
-
];
|
|
419
|
-
|
|
420
|
-
it("detects filler words with default list", () => {
|
|
421
|
-
const result = detectFillerRanges(words, DEFAULT_FILLER_WORDS, 0.05);
|
|
422
|
-
|
|
423
|
-
expect(result.length).toBe(3);
|
|
424
|
-
expect(result[0].word).toBe("um");
|
|
425
|
-
expect(result[1].word).toBe("like");
|
|
426
|
-
expect(result[2].word).toBe("basically");
|
|
427
|
-
});
|
|
428
|
-
|
|
429
|
-
it("detects fillers case-insensitively", () => {
|
|
430
|
-
const mixedCase = [
|
|
431
|
-
{ word: "UM", start: 0.0, end: 0.3 },
|
|
432
|
-
{ word: "Like", start: 1.0, end: 1.3 },
|
|
433
|
-
];
|
|
434
|
-
const result = detectFillerRanges(mixedCase, DEFAULT_FILLER_WORDS, 0.05);
|
|
435
|
-
|
|
436
|
-
expect(result.length).toBe(2);
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
it("strips punctuation before matching", () => {
|
|
440
|
-
const punctuated = [
|
|
441
|
-
{ word: "um,", start: 0.0, end: 0.3 },
|
|
442
|
-
{ word: "like.", start: 1.0, end: 1.3 },
|
|
443
|
-
{ word: "right?", start: 2.0, end: 2.3 },
|
|
444
|
-
];
|
|
445
|
-
const result = detectFillerRanges(punctuated, DEFAULT_FILLER_WORDS, 0.05);
|
|
446
|
-
|
|
447
|
-
expect(result.length).toBe(3);
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
it("merges adjacent filler ranges within padding distance", () => {
|
|
451
|
-
const adjacent = [
|
|
452
|
-
{ word: "um", start: 1.0, end: 1.3 },
|
|
453
|
-
{ word: "uh", start: 1.35, end: 1.6 },
|
|
454
|
-
];
|
|
455
|
-
const result = detectFillerRanges(adjacent, DEFAULT_FILLER_WORDS, 0.05);
|
|
456
|
-
|
|
457
|
-
expect(result.length).toBe(1);
|
|
458
|
-
expect(result[0].start).toBe(1.0);
|
|
459
|
-
expect(result[0].end).toBe(1.6);
|
|
460
|
-
expect(result[0].word).toContain("um");
|
|
461
|
-
expect(result[0].word).toContain("uh");
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
it("does not merge distant filler ranges", () => {
|
|
465
|
-
const distant = [
|
|
466
|
-
{ word: "um", start: 1.0, end: 1.3 },
|
|
467
|
-
{ word: "uh", start: 5.0, end: 5.3 },
|
|
468
|
-
];
|
|
469
|
-
const result = detectFillerRanges(distant, DEFAULT_FILLER_WORDS, 0.05);
|
|
470
|
-
|
|
471
|
-
expect(result.length).toBe(2);
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
it("returns empty array when no fillers found", () => {
|
|
475
|
-
const clean = [
|
|
476
|
-
{ word: "This", start: 0.0, end: 0.3 },
|
|
477
|
-
{ word: "is", start: 0.4, end: 0.5 },
|
|
478
|
-
{ word: "great", start: 0.6, end: 0.9 },
|
|
479
|
-
];
|
|
480
|
-
const result = detectFillerRanges(clean, DEFAULT_FILLER_WORDS, 0.05);
|
|
481
|
-
|
|
482
|
-
expect(result.length).toBe(0);
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
it("respects custom filler list", () => {
|
|
486
|
-
const customFillers = ["hello", "great"];
|
|
487
|
-
const result = detectFillerRanges(words, customFillers, 0.05);
|
|
488
|
-
|
|
489
|
-
expect(result.length).toBe(2);
|
|
490
|
-
expect(result[0].word).toBe("Hello");
|
|
491
|
-
expect(result[1].word).toBe("great");
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
it("handles empty word array", () => {
|
|
495
|
-
const result = detectFillerRanges([], DEFAULT_FILLER_WORDS, 0.05);
|
|
496
|
-
|
|
497
|
-
expect(result.length).toBe(0);
|
|
498
|
-
});
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
describe("DEFAULT_FILLER_WORDS", () => {
|
|
502
|
-
it("contains expected common fillers", () => {
|
|
503
|
-
expect(DEFAULT_FILLER_WORDS).toContain("um");
|
|
504
|
-
expect(DEFAULT_FILLER_WORDS).toContain("uh");
|
|
505
|
-
expect(DEFAULT_FILLER_WORDS).toContain("like");
|
|
506
|
-
expect(DEFAULT_FILLER_WORDS).toContain("you know");
|
|
507
|
-
expect(DEFAULT_FILLER_WORDS).toContain("basically");
|
|
508
|
-
expect(DEFAULT_FILLER_WORDS).toContain("literally");
|
|
509
|
-
expect(DEFAULT_FILLER_WORDS).toContain("i mean");
|
|
510
|
-
expect(DEFAULT_FILLER_WORDS).toContain("actually");
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
it("has all words in lowercase", () => {
|
|
514
|
-
for (const word of DEFAULT_FILLER_WORDS) {
|
|
515
|
-
expect(word).toBe(word.toLowerCase());
|
|
516
|
-
}
|
|
517
|
-
});
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
describe("edit noise-reduce", () => {
|
|
521
|
-
it("shows help", () => {
|
|
522
|
-
const output = execSync(`${CLI} edit noise-reduce --help`, {
|
|
523
|
-
cwd: process.cwd(),
|
|
524
|
-
encoding: "utf-8",
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
expect(output).toContain("Remove background noise");
|
|
528
|
-
expect(output).toContain("--strength");
|
|
529
|
-
expect(output).toContain("--noise-floor");
|
|
530
|
-
expect(output).toContain("--output");
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
it("fails with nonexistent file", () => {
|
|
534
|
-
expect(() => {
|
|
535
|
-
execSync(`${CLI} edit noise-reduce /tmp/nonexistent_audio_12345.mp4`, {
|
|
536
|
-
cwd: process.cwd(),
|
|
537
|
-
encoding: "utf-8",
|
|
538
|
-
});
|
|
539
|
-
}).toThrow();
|
|
540
|
-
});
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
describe("edit fade", () => {
|
|
544
|
-
it("shows help", () => {
|
|
545
|
-
const output = execSync(`${CLI} edit fade --help`, {
|
|
546
|
-
cwd: process.cwd(),
|
|
547
|
-
encoding: "utf-8",
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
expect(output).toContain("Apply fade in/out");
|
|
551
|
-
expect(output).toContain("--fade-in");
|
|
552
|
-
expect(output).toContain("--fade-out");
|
|
553
|
-
expect(output).toContain("--audio-only");
|
|
554
|
-
expect(output).toContain("--video-only");
|
|
555
|
-
expect(output).toContain("--output");
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
it("fails with nonexistent file", () => {
|
|
559
|
-
expect(() => {
|
|
560
|
-
execSync(`${CLI} edit fade /tmp/nonexistent_video_12345.mp4`, {
|
|
561
|
-
cwd: process.cwd(),
|
|
562
|
-
encoding: "utf-8",
|
|
563
|
-
});
|
|
564
|
-
}).toThrow();
|
|
565
|
-
});
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
describe("generate thumbnail --best-frame", () => {
|
|
569
|
-
it("shows help with best-frame option", () => {
|
|
570
|
-
const output = execSync(`${CLI} generate thumbnail --help`, {
|
|
571
|
-
cwd: process.cwd(),
|
|
572
|
-
encoding: "utf-8",
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
expect(output).toContain("--best-frame");
|
|
576
|
-
expect(output).toContain("--prompt");
|
|
577
|
-
expect(output).toContain("--model");
|
|
578
|
-
expect(output).toContain("--output");
|
|
579
|
-
});
|
|
580
|
-
|
|
581
|
-
it("fails with nonexistent video for best-frame", () => {
|
|
582
|
-
expect(() => {
|
|
583
|
-
execSync(`${CLI} generate thumbnail --best-frame /tmp/nonexistent_video_12345.mp4`, {
|
|
584
|
-
cwd: process.cwd(),
|
|
585
|
-
encoding: "utf-8",
|
|
586
|
-
env: { ...process.env, GOOGLE_API_KEY: "test" },
|
|
587
|
-
});
|
|
588
|
-
}).toThrow();
|
|
589
|
-
});
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
describe("edit translate-srt", () => {
|
|
593
|
-
it("shows help", () => {
|
|
594
|
-
const output = execSync(`${CLI} edit translate-srt --help`, {
|
|
595
|
-
cwd: process.cwd(),
|
|
596
|
-
encoding: "utf-8",
|
|
597
|
-
});
|
|
598
|
-
|
|
599
|
-
expect(output).toContain("Translate SRT");
|
|
600
|
-
expect(output).toContain("--target");
|
|
601
|
-
expect(output).toContain("--provider");
|
|
602
|
-
expect(output).toContain("--source");
|
|
603
|
-
expect(output).toContain("--output");
|
|
604
|
-
expect(output).toContain("--api-key");
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
it("fails without target language", () => {
|
|
608
|
-
expect(() => {
|
|
609
|
-
execSync(`${CLI} edit translate-srt /tmp/test.srt`, {
|
|
610
|
-
cwd: process.cwd(),
|
|
611
|
-
encoding: "utf-8",
|
|
612
|
-
env: { ...process.env, ANTHROPIC_API_KEY: "test" },
|
|
613
|
-
});
|
|
614
|
-
}).toThrow();
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
it("fails with nonexistent file", () => {
|
|
618
|
-
expect(() => {
|
|
619
|
-
execSync(`${CLI} edit translate-srt /tmp/nonexistent_12345.srt -t ko`, {
|
|
620
|
-
cwd: process.cwd(),
|
|
621
|
-
encoding: "utf-8",
|
|
622
|
-
env: { ...process.env, ANTHROPIC_API_KEY: "test" },
|
|
623
|
-
});
|
|
624
|
-
}).toThrow();
|
|
625
|
-
});
|
|
626
|
-
});
|
|
627
|
-
});
|