@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.
Files changed (118) hide show
  1. package/LICENSE +21 -0
  2. package/dist/agent/adapters/index.d.ts +1 -0
  3. package/dist/agent/adapters/index.d.ts.map +1 -1
  4. package/dist/agent/adapters/index.js +5 -0
  5. package/dist/agent/adapters/index.js.map +1 -1
  6. package/dist/agent/adapters/openrouter.d.ts +16 -0
  7. package/dist/agent/adapters/openrouter.d.ts.map +1 -0
  8. package/dist/agent/adapters/openrouter.js +100 -0
  9. package/dist/agent/adapters/openrouter.js.map +1 -0
  10. package/dist/agent/types.d.ts +1 -1
  11. package/dist/agent/types.d.ts.map +1 -1
  12. package/dist/commands/agent.d.ts.map +1 -1
  13. package/dist/commands/agent.js +3 -1
  14. package/dist/commands/agent.js.map +1 -1
  15. package/dist/commands/ai-edit-cli.d.ts.map +1 -1
  16. package/dist/commands/ai-edit-cli.js +18 -0
  17. package/dist/commands/ai-edit-cli.js.map +1 -1
  18. package/dist/commands/generate.js +14 -0
  19. package/dist/commands/generate.js.map +1 -1
  20. package/dist/commands/schema.d.ts +1 -0
  21. package/dist/commands/schema.d.ts.map +1 -1
  22. package/dist/commands/schema.js +122 -21
  23. package/dist/commands/schema.js.map +1 -1
  24. package/dist/commands/setup.js +5 -2
  25. package/dist/commands/setup.js.map +1 -1
  26. package/dist/config/schema.d.ts +2 -1
  27. package/dist/config/schema.d.ts.map +1 -1
  28. package/dist/config/schema.js +2 -0
  29. package/dist/config/schema.js.map +1 -1
  30. package/dist/index.js +0 -0
  31. package/package.json +16 -12
  32. package/.turbo/turbo-build.log +0 -4
  33. package/.turbo/turbo-lint.log +0 -21
  34. package/.turbo/turbo-test.log +0 -689
  35. package/src/agent/adapters/claude.ts +0 -143
  36. package/src/agent/adapters/gemini.ts +0 -159
  37. package/src/agent/adapters/index.ts +0 -61
  38. package/src/agent/adapters/ollama.ts +0 -231
  39. package/src/agent/adapters/openai.ts +0 -116
  40. package/src/agent/adapters/xai.ts +0 -119
  41. package/src/agent/index.ts +0 -251
  42. package/src/agent/memory/index.ts +0 -151
  43. package/src/agent/prompts/system.ts +0 -106
  44. package/src/agent/tools/ai-editing.ts +0 -845
  45. package/src/agent/tools/ai-generation.ts +0 -1073
  46. package/src/agent/tools/ai-pipeline.ts +0 -1055
  47. package/src/agent/tools/ai.ts +0 -21
  48. package/src/agent/tools/batch.ts +0 -429
  49. package/src/agent/tools/e2e.test.ts +0 -545
  50. package/src/agent/tools/export.ts +0 -184
  51. package/src/agent/tools/filesystem.ts +0 -237
  52. package/src/agent/tools/index.ts +0 -150
  53. package/src/agent/tools/integration.test.ts +0 -775
  54. package/src/agent/tools/media.ts +0 -697
  55. package/src/agent/tools/project.ts +0 -313
  56. package/src/agent/tools/timeline.ts +0 -951
  57. package/src/agent/types.ts +0 -68
  58. package/src/commands/agent.ts +0 -340
  59. package/src/commands/ai-analyze.ts +0 -429
  60. package/src/commands/ai-animated-caption.ts +0 -390
  61. package/src/commands/ai-audio.ts +0 -941
  62. package/src/commands/ai-broll.ts +0 -490
  63. package/src/commands/ai-edit-cli.ts +0 -658
  64. package/src/commands/ai-edit.ts +0 -1542
  65. package/src/commands/ai-fill-gaps.ts +0 -566
  66. package/src/commands/ai-helpers.ts +0 -65
  67. package/src/commands/ai-highlights.ts +0 -1303
  68. package/src/commands/ai-image.ts +0 -761
  69. package/src/commands/ai-motion.ts +0 -347
  70. package/src/commands/ai-narrate.ts +0 -451
  71. package/src/commands/ai-review.ts +0 -309
  72. package/src/commands/ai-script-pipeline-cli.ts +0 -1710
  73. package/src/commands/ai-script-pipeline.ts +0 -1365
  74. package/src/commands/ai-suggest-edit.ts +0 -264
  75. package/src/commands/ai-video-fx.ts +0 -445
  76. package/src/commands/ai-video.ts +0 -915
  77. package/src/commands/ai-viral.ts +0 -595
  78. package/src/commands/ai-visual-fx.ts +0 -601
  79. package/src/commands/ai.test.ts +0 -627
  80. package/src/commands/ai.ts +0 -307
  81. package/src/commands/analyze.ts +0 -282
  82. package/src/commands/audio.ts +0 -644
  83. package/src/commands/batch.test.ts +0 -279
  84. package/src/commands/batch.ts +0 -440
  85. package/src/commands/detect.ts +0 -329
  86. package/src/commands/doctor.ts +0 -237
  87. package/src/commands/edit-cmd.ts +0 -1014
  88. package/src/commands/export.ts +0 -918
  89. package/src/commands/generate.ts +0 -2146
  90. package/src/commands/media.ts +0 -177
  91. package/src/commands/output.ts +0 -142
  92. package/src/commands/pipeline.ts +0 -398
  93. package/src/commands/project.test.ts +0 -127
  94. package/src/commands/project.ts +0 -149
  95. package/src/commands/sanitize.ts +0 -60
  96. package/src/commands/schema.ts +0 -130
  97. package/src/commands/setup.ts +0 -509
  98. package/src/commands/timeline.test.ts +0 -499
  99. package/src/commands/timeline.ts +0 -529
  100. package/src/commands/validate.ts +0 -77
  101. package/src/config/config.test.ts +0 -197
  102. package/src/config/index.ts +0 -125
  103. package/src/config/schema.ts +0 -82
  104. package/src/engine/index.ts +0 -2
  105. package/src/engine/project.test.ts +0 -702
  106. package/src/engine/project.ts +0 -439
  107. package/src/index.ts +0 -146
  108. package/src/utils/api-key.test.ts +0 -41
  109. package/src/utils/api-key.ts +0 -247
  110. package/src/utils/audio.ts +0 -83
  111. package/src/utils/exec-safe.ts +0 -75
  112. package/src/utils/first-run.ts +0 -52
  113. package/src/utils/provider-resolver.ts +0 -56
  114. package/src/utils/remotion.ts +0 -951
  115. package/src/utils/subtitle.test.ts +0 -227
  116. package/src/utils/subtitle.ts +0 -169
  117. package/src/utils/tty.ts +0 -196
  118. package/tsconfig.json +0 -20
@@ -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
- });