@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,775 +0,0 @@
1
- /**
2
- * Integration Tests: CLI ↔ Agent Tool Synchronization
3
- *
4
- * These tests verify that:
5
- * 1. All Agent tools are properly registered
6
- * 2. Agent tools correctly wrap CLI functions
7
- * 3. Parameter schemas match between CLI and Agent
8
- * 4. Tool handlers produce expected output formats
9
- */
10
-
11
- import { describe, it, expect, beforeEach, vi } from "vitest";
12
- import { ToolRegistry } from "./index.js";
13
- import { registerProjectTools } from "./project.js";
14
- import { registerTimelineTools } from "./timeline.js";
15
- import { registerFilesystemTools } from "./filesystem.js";
16
- import { registerMediaTools } from "./media.js";
17
- import { registerAITools } from "./ai.js";
18
- import { registerExportTools } from "./export.js";
19
- import { registerBatchTools } from "./batch.js";
20
- // Mock the imported CLI functions to avoid actual API calls
21
- vi.mock("../../commands/ai-script-pipeline.js", () => ({
22
- executeScriptToVideo: vi.fn().mockResolvedValue({
23
- success: true,
24
- outputDir: "/test/output",
25
- scenes: 3,
26
- storyboardPath: "/test/output/storyboard.json",
27
- projectPath: "/test/output/project.vibe.json",
28
- narrations: ["/test/output/narration-1.mp3"],
29
- images: ["/test/output/scene-1.png"],
30
- videos: ["/test/output/scene-1.mp4"],
31
- totalDuration: 30,
32
- failedScenes: [],
33
- }),
34
- executeRegenerateScene: vi.fn().mockResolvedValue({ success: true }),
35
- }));
36
-
37
- vi.mock("../../commands/ai-highlights.js", () => ({
38
- executeHighlights: vi.fn().mockResolvedValue({
39
- success: true,
40
- highlights: [
41
- {
42
- index: 1,
43
- startTime: 10,
44
- endTime: 25,
45
- duration: 15,
46
- category: "emotional",
47
- confidence: 0.95,
48
- reason: "Test highlight",
49
- transcript: "Test transcript",
50
- },
51
- ],
52
- totalDuration: 120,
53
- totalHighlightDuration: 15,
54
- }),
55
- executeAutoShorts: vi.fn().mockResolvedValue({
56
- success: true,
57
- shorts: [
58
- {
59
- index: 1,
60
- startTime: 30,
61
- endTime: 60,
62
- duration: 30,
63
- confidence: 0.9,
64
- reason: "Viral moment",
65
- outputPath: "/test/short-1.mp4",
66
- },
67
- ],
68
- }),
69
- }));
70
-
71
- vi.mock("../../commands/ai-animated-caption.js", () => ({
72
- executeAnimatedCaption: vi.fn().mockResolvedValue({
73
- success: true,
74
- outputPath: "/test/captioned.mp4",
75
- wordCount: 42,
76
- groupCount: 10,
77
- style: "highlight",
78
- tier: "remotion",
79
- }),
80
- }));
81
-
82
- vi.mock("../../commands/ai-analyze.js", () => ({
83
- executeGeminiVideo: vi.fn().mockResolvedValue({
84
- success: true,
85
- response: "This is a test video summary.",
86
- model: "gemini-3-flash-preview",
87
- totalTokens: 1000,
88
- }),
89
- executeAnalyze: vi.fn().mockResolvedValue({
90
- success: true,
91
- response: "Test analysis",
92
- }),
93
- }));
94
-
95
- vi.mock("../../commands/ai-edit.js", () => ({
96
- executeSilenceCut: vi.fn().mockResolvedValue({
97
- success: true,
98
- outputPath: "/test/video-cut.mp4",
99
- totalDuration: 120,
100
- silentPeriods: [
101
- { start: 10, end: 15, duration: 5 },
102
- { start: 60, end: 63, duration: 3 },
103
- ],
104
- silentDuration: 8,
105
- }),
106
- executeJumpCut: vi.fn().mockResolvedValue({
107
- success: true,
108
- outputPath: "/test/video-jumpcut.mp4",
109
- totalDuration: 120,
110
- fillerCount: 5,
111
- fillerDuration: 3.2,
112
- fillers: [
113
- { word: "um", start: 5.1, end: 5.6 },
114
- { word: "like", start: 12.3, end: 12.8 },
115
- ],
116
- }),
117
- executeCaption: vi.fn().mockResolvedValue({
118
- success: true,
119
- outputPath: "/test/video-captioned.mp4",
120
- srtPath: "/test/video-captioned.srt",
121
- segmentCount: 12,
122
- }),
123
- executeNoiseReduce: vi.fn().mockResolvedValue({
124
- success: true,
125
- outputPath: "/test/audio-denoised.mp4",
126
- inputDuration: 60,
127
- }),
128
- executeFade: vi.fn().mockResolvedValue({
129
- success: true,
130
- outputPath: "/test/video-faded.mp4",
131
- totalDuration: 120,
132
- fadeInApplied: true,
133
- fadeOutApplied: true,
134
- }),
135
- executeTranslateSrt: vi.fn().mockResolvedValue({
136
- success: true,
137
- outputPath: "/test/subtitles-ko.srt",
138
- segmentCount: 20,
139
- sourceLanguage: "en",
140
- targetLanguage: "ko",
141
- }),
142
- executeTextOverlay: vi.fn().mockResolvedValue({
143
- success: true,
144
- outputPath: "/test/video-overlay.mp4",
145
- }),
146
- DEFAULT_FILLER_WORDS: ["um", "uh", "like", "you know"],
147
- detectFillerRanges: vi.fn(),
148
- }));
149
-
150
- vi.mock("../../commands/ai-review.js", () => ({
151
- executeReview: vi.fn().mockResolvedValue({
152
- success: true,
153
- issues: [],
154
- }),
155
- }));
156
-
157
- vi.mock("../../commands/ai-image.js", () => ({
158
- executeThumbnailBestFrame: vi.fn().mockResolvedValue({
159
- success: true,
160
- outputPath: "/test/video-thumbnail.png",
161
- timestamp: 15.5,
162
- reason: "Best composed frame",
163
- }),
164
- executeGeminiEdit: vi.fn().mockResolvedValue({
165
- success: true,
166
- outputPath: "/test/edited.png",
167
- }),
168
- }));
169
-
170
- describe("CLI ↔ Agent Tool Synchronization", () => {
171
- let registry: ToolRegistry;
172
-
173
- beforeEach(() => {
174
- registry = new ToolRegistry();
175
- registerProjectTools(registry);
176
- registerTimelineTools(registry);
177
- registerFilesystemTools(registry);
178
- registerMediaTools(registry);
179
- registerAITools(registry);
180
- registerExportTools(registry);
181
- registerBatchTools(registry);
182
- });
183
-
184
- describe("Tool Registration", () => {
185
- it("should register all 57 tools", () => {
186
- const tools = registry.getAll();
187
- expect(tools.length).toBe(58);
188
- });
189
-
190
- it("should register all project tools (5)", () => {
191
- const projectTools = [
192
- "project_create",
193
- "project_info",
194
- "project_set",
195
- "project_open",
196
- "project_save",
197
- ];
198
- for (const name of projectTools) {
199
- expect(registry.get(name)).toBeDefined();
200
- }
201
- });
202
-
203
- it("should register all timeline tools (11)", () => {
204
- const timelineTools = [
205
- "timeline_add_source",
206
- "timeline_add_clip",
207
- "timeline_add_track",
208
- "timeline_add_effect",
209
- "timeline_trim",
210
- "timeline_split",
211
- "timeline_move",
212
- "timeline_clear",
213
- "timeline_delete",
214
- "timeline_duplicate",
215
- "timeline_list",
216
- ];
217
- for (const name of timelineTools) {
218
- expect(registry.get(name)).toBeDefined();
219
- }
220
- });
221
-
222
- it("should register all filesystem tools (4)", () => {
223
- const fsTools = ["fs_list", "fs_read", "fs_write", "fs_exists"];
224
- for (const name of fsTools) {
225
- expect(registry.get(name)).toBeDefined();
226
- }
227
- });
228
-
229
- it("should register all media tools (8)", () => {
230
- const mediaTools = [
231
- "media_info",
232
- "detect_scenes",
233
- "detect_silence",
234
- "detect_beats",
235
- "audio_transcribe",
236
- "media_compress",
237
- "media_convert",
238
- "media_concat",
239
- ];
240
- for (const name of mediaTools) {
241
- expect(registry.get(name)).toBeDefined();
242
- }
243
- });
244
-
245
- it("should register all batch tools (3)", () => {
246
- const batchTools = [
247
- "batch_import",
248
- "batch_concat",
249
- "batch_apply_effect",
250
- ];
251
- for (const name of batchTools) {
252
- expect(registry.get(name)).toBeDefined();
253
- }
254
- });
255
-
256
- it("should register all AI tools (23)", () => {
257
- const aiTools = [
258
- // Generation tools (8)
259
- "generate_image",
260
- "generate_video",
261
- "generate_speech",
262
- "generate_sound_effect",
263
- "generate_music",
264
- "generate_storyboard",
265
- "generate_motion",
266
- "generate_thumbnail",
267
- // Edit tools (8)
268
- "edit_text_overlay",
269
- "edit_silence_cut",
270
- "edit_jump_cut",
271
- "edit_caption",
272
- "edit_noise_reduce",
273
- "edit_fade",
274
- "edit_translate_srt",
275
- "edit_image",
276
- // Analyze tools (3)
277
- "analyze_review",
278
- "analyze_video",
279
- "analyze_media",
280
- // Pipeline tools (4)
281
- "pipeline_script_to_video",
282
- "pipeline_highlights",
283
- "pipeline_auto_shorts",
284
- "pipeline_regenerate_scene",
285
- ];
286
- for (const name of aiTools) {
287
- expect(registry.get(name)).toBeDefined();
288
- }
289
- });
290
-
291
- it("should register all export tools (3)", () => {
292
- const exportTools = ["export_video", "export_audio", "export_subtitles"];
293
- for (const name of exportTools) {
294
- expect(registry.get(name)).toBeDefined();
295
- }
296
- });
297
- });
298
-
299
- describe("Tool Definition Schema Validation", () => {
300
- it("all tools should have valid definitions", () => {
301
- const tools = registry.getAll();
302
- for (const tool of tools) {
303
- expect(tool.name).toBeTruthy();
304
- expect(tool.description).toBeTruthy();
305
- expect(tool.parameters).toBeDefined();
306
- expect(tool.parameters.type).toBe("object");
307
- expect(tool.parameters.properties).toBeDefined();
308
- }
309
- });
310
-
311
- it("all tools should have required parameters listed", () => {
312
- const tools = registry.getAll();
313
- for (const tool of tools) {
314
- if (tool.parameters.required && tool.parameters.required.length > 0) {
315
- for (const requiredParam of tool.parameters.required) {
316
- expect(tool.parameters.properties[requiredParam]).toBeDefined();
317
- }
318
- }
319
- }
320
- });
321
-
322
- it("all parameter properties should have type and description", () => {
323
- const tools = registry.getAll();
324
- for (const tool of tools) {
325
- for (const paramDef of Object.values(
326
- tool.parameters.properties
327
- )) {
328
- const param = paramDef as { type?: string; description?: string };
329
- expect(param.type).toBeTruthy();
330
- expect(param.description).toBeTruthy();
331
- }
332
- }
333
- });
334
- });
335
-
336
- describe("AI Pipeline Tools - Parameter Mapping", () => {
337
- describe("pipeline_script_to_video", () => {
338
- it("should have all CLI options as parameters", () => {
339
- const tool = registry.get("pipeline_script_to_video");
340
- expect(tool).toBeDefined();
341
-
342
- const params = tool!.parameters.properties;
343
- // Required
344
- expect(params.script).toBeDefined();
345
- // Optional (matching CLI options)
346
- expect(params.outputDir).toBeDefined();
347
- expect(params.duration).toBeDefined();
348
- expect(params.voice).toBeDefined();
349
- expect(params.generator).toBeDefined();
350
- expect(params.imageProvider).toBeDefined();
351
- expect(params.aspectRatio).toBeDefined();
352
- expect(params.imagesOnly).toBeDefined();
353
- expect(params.noVoiceover).toBeDefined();
354
- expect(params.retries).toBeDefined();
355
- });
356
-
357
- it("should have correct enum values for generator", () => {
358
- const tool = registry.get("pipeline_script_to_video");
359
- const generator = tool!.parameters.properties.generator as {
360
- enum?: string[];
361
- };
362
- expect(generator.enum).toContain("runway");
363
- expect(generator.enum).toContain("kling");
364
- });
365
-
366
- it("should have correct enum values for imageProvider", () => {
367
- const tool = registry.get("pipeline_script_to_video");
368
- const imageProvider = tool!.parameters.properties.imageProvider as {
369
- enum?: string[];
370
- };
371
- expect(imageProvider.enum).toContain("openai");
372
- expect(imageProvider.enum).toContain("gemini");
373
- });
374
-
375
- it("should have correct enum values for aspectRatio", () => {
376
- const tool = registry.get("pipeline_script_to_video");
377
- const aspectRatio = tool!.parameters.properties.aspectRatio as {
378
- enum?: string[];
379
- };
380
- expect(aspectRatio.enum).toContain("16:9");
381
- expect(aspectRatio.enum).toContain("9:16");
382
- expect(aspectRatio.enum).toContain("1:1");
383
- });
384
- });
385
-
386
- describe("pipeline_highlights", () => {
387
- it("should have all CLI options as parameters", () => {
388
- const tool = registry.get("pipeline_highlights");
389
- expect(tool).toBeDefined();
390
-
391
- const params = tool!.parameters.properties;
392
- // Required
393
- expect(params.media).toBeDefined();
394
- // Optional (matching CLI options)
395
- expect(params.output).toBeDefined();
396
- expect(params.project).toBeDefined();
397
- expect(params.duration).toBeDefined();
398
- expect(params.count).toBeDefined();
399
- expect(params.threshold).toBeDefined();
400
- expect(params.criteria).toBeDefined();
401
- expect(params.language).toBeDefined();
402
- expect(params.useGemini).toBeDefined();
403
- expect(params.lowRes).toBeDefined();
404
- });
405
-
406
- it("should have correct enum values for criteria", () => {
407
- const tool = registry.get("pipeline_highlights");
408
- const criteria = tool!.parameters.properties.criteria as {
409
- enum?: string[];
410
- };
411
- expect(criteria.enum).toContain("emotional");
412
- expect(criteria.enum).toContain("informative");
413
- expect(criteria.enum).toContain("funny");
414
- expect(criteria.enum).toContain("all");
415
- });
416
- });
417
-
418
- describe("pipeline_auto_shorts", () => {
419
- it("should have all CLI options as parameters", () => {
420
- const tool = registry.get("pipeline_auto_shorts");
421
- expect(tool).toBeDefined();
422
-
423
- const params = tool!.parameters.properties;
424
- // Required
425
- expect(params.video).toBeDefined();
426
- // Optional (matching CLI options)
427
- expect(params.outputDir).toBeDefined();
428
- expect(params.duration).toBeDefined();
429
- expect(params.count).toBeDefined();
430
- expect(params.aspect).toBeDefined();
431
- expect(params.addCaptions).toBeDefined();
432
- expect(params.captionStyle).toBeDefined();
433
- expect(params.analyzeOnly).toBeDefined();
434
- expect(params.language).toBeDefined();
435
- expect(params.useGemini).toBeDefined();
436
- expect(params.lowRes).toBeDefined();
437
- });
438
-
439
- it("should have correct enum values for aspect", () => {
440
- const tool = registry.get("pipeline_auto_shorts");
441
- const aspect = tool!.parameters.properties.aspect as { enum?: string[] };
442
- expect(aspect.enum).toContain("9:16");
443
- expect(aspect.enum).toContain("1:1");
444
- });
445
-
446
- it("should have correct enum values for captionStyle", () => {
447
- const tool = registry.get("pipeline_auto_shorts");
448
- const captionStyle = tool!.parameters.properties.captionStyle as {
449
- enum?: string[];
450
- };
451
- expect(captionStyle.enum).toContain("minimal");
452
- expect(captionStyle.enum).toContain("bold");
453
- expect(captionStyle.enum).toContain("animated");
454
- });
455
- });
456
-
457
- describe("analyze_video", () => {
458
- it("should have all CLI options as parameters", () => {
459
- const tool = registry.get("analyze_video");
460
- expect(tool).toBeDefined();
461
-
462
- const params = tool!.parameters.properties;
463
- // Required
464
- expect(params.source).toBeDefined();
465
- expect(params.prompt).toBeDefined();
466
- // Optional (matching CLI options)
467
- expect(params.model).toBeDefined();
468
- expect(params.fps).toBeDefined();
469
- expect(params.start).toBeDefined();
470
- expect(params.end).toBeDefined();
471
- expect(params.lowRes).toBeDefined();
472
- });
473
-
474
- it("should have correct enum values for model", () => {
475
- const tool = registry.get("analyze_video");
476
- const model = tool!.parameters.properties.model as { enum?: string[] };
477
- expect(model.enum).toContain("flash");
478
- expect(model.enum).toContain("flash-2.5");
479
- expect(model.enum).toContain("pro");
480
- });
481
- });
482
- });
483
-
484
- describe("Tool Handler Execution (Mocked)", () => {
485
- const mockContext = {
486
- workingDirectory: "/test/workdir",
487
- projectPath: "/test/project.vibe.json",
488
- };
489
-
490
- describe("pipeline_script_to_video handler", () => {
491
- it("should call executeScriptToVideo with correct parameters", async () => {
492
- const { executeScriptToVideo } = await import("../../commands/ai-script-pipeline.js");
493
- const handler = registry.getHandler("pipeline_script_to_video");
494
- expect(handler).toBeDefined();
495
-
496
- const result = await handler!(
497
- {
498
- script: "Test script. Scene two. Conclusion.",
499
- outputDir: "output",
500
- generator: "runway",
501
- imageProvider: "gemini",
502
- aspectRatio: "16:9",
503
- },
504
- mockContext
505
- );
506
-
507
- expect(executeScriptToVideo).toHaveBeenCalledWith(
508
- expect.objectContaining({
509
- script: "Test script. Scene two. Conclusion.",
510
- generator: "runway",
511
- imageProvider: "gemini",
512
- aspectRatio: "16:9",
513
- })
514
- );
515
- expect(result.success).toBe(true);
516
- expect(result.output).toContain("Script-to-Video complete");
517
- });
518
-
519
- it("should handle failure gracefully", async () => {
520
- const { executeScriptToVideo } = await import("../../commands/ai-script-pipeline.js");
521
- vi.mocked(executeScriptToVideo).mockResolvedValueOnce({
522
- success: false,
523
- outputDir: "/test/output",
524
- scenes: 0,
525
- error: "API key missing",
526
- });
527
-
528
- const handler = registry.getHandler("pipeline_script_to_video");
529
- const result = await handler!({ script: "Test" }, mockContext);
530
-
531
- expect(result.success).toBe(false);
532
- expect(result.error).toContain("API key missing");
533
- });
534
- });
535
-
536
- describe("pipeline_highlights handler", () => {
537
- it("should call executeHighlights with correct parameters", async () => {
538
- const { executeHighlights } = await import("../../commands/ai-highlights.js");
539
- const handler = registry.getHandler("pipeline_highlights");
540
- expect(handler).toBeDefined();
541
-
542
- const result = await handler!(
543
- {
544
- media: "video.mp4",
545
- duration: 60,
546
- criteria: "emotional",
547
- useGemini: true,
548
- },
549
- mockContext
550
- );
551
-
552
- expect(executeHighlights).toHaveBeenCalledWith(
553
- expect.objectContaining({
554
- media: "/test/workdir/video.mp4",
555
- duration: 60,
556
- criteria: "emotional",
557
- useGemini: true,
558
- })
559
- );
560
- expect(result.success).toBe(true);
561
- expect(result.output).toContain("Found 1 highlights");
562
- });
563
- });
564
-
565
- describe("pipeline_auto_shorts handler", () => {
566
- it("should call executeAutoShorts with correct parameters", async () => {
567
- const { executeAutoShorts } = await import("../../commands/ai-highlights.js");
568
- const handler = registry.getHandler("pipeline_auto_shorts");
569
- expect(handler).toBeDefined();
570
-
571
- const result = await handler!(
572
- {
573
- video: "long-video.mp4",
574
- count: 3,
575
- duration: 45,
576
- aspect: "9:16",
577
- },
578
- mockContext
579
- );
580
-
581
- expect(executeAutoShorts).toHaveBeenCalledWith(
582
- expect.objectContaining({
583
- video: "/test/workdir/long-video.mp4",
584
- count: 3,
585
- duration: 45,
586
- aspect: "9:16",
587
- })
588
- );
589
- expect(result.success).toBe(true);
590
- expect(result.output).toContain("Generated 1 short");
591
- });
592
-
593
- it("should handle analyzeOnly mode", async () => {
594
- const handler = registry.getHandler("pipeline_auto_shorts");
595
- const result = await handler!(
596
- {
597
- video: "video.mp4",
598
- analyzeOnly: true,
599
- },
600
- mockContext
601
- );
602
-
603
- expect(result.success).toBe(true);
604
- });
605
- });
606
-
607
- describe("analyze_video handler", () => {
608
- it("should call executeGeminiVideo with correct parameters", async () => {
609
- const { executeGeminiVideo } = await import("../../commands/ai-analyze.js");
610
- const handler = registry.getHandler("analyze_video");
611
- expect(handler).toBeDefined();
612
-
613
- const result = await handler!(
614
- {
615
- source: "video.mp4",
616
- prompt: "Summarize this video",
617
- model: "flash",
618
- },
619
- mockContext
620
- );
621
-
622
- expect(executeGeminiVideo).toHaveBeenCalledWith(
623
- expect.objectContaining({
624
- source: "/test/workdir/video.mp4",
625
- prompt: "Summarize this video",
626
- model: "flash",
627
- })
628
- );
629
- expect(result.success).toBe(true);
630
- expect(result.output).toContain("test video summary");
631
- });
632
-
633
- it("should handle YouTube URLs without modification", async () => {
634
- const { executeGeminiVideo } = await import("../../commands/ai-analyze.js");
635
- const handler = registry.getHandler("analyze_video");
636
-
637
- await handler!(
638
- {
639
- source: "https://youtube.com/watch?v=test",
640
- prompt: "Summarize",
641
- },
642
- mockContext
643
- );
644
-
645
- expect(executeGeminiVideo).toHaveBeenCalledWith(
646
- expect.objectContaining({
647
- source: "https://youtube.com/watch?v=test",
648
- })
649
- );
650
- });
651
- });
652
- });
653
-
654
- describe("Tool Categories Match CLAUDE.md Documentation", () => {
655
- it("should have correct tool counts per category", () => {
656
- const allTools = registry.getAll();
657
-
658
- const projectTools = allTools.filter((t) => t.name.startsWith("project_"));
659
- const timelineTools = allTools.filter((t) =>
660
- t.name.startsWith("timeline_")
661
- );
662
- const fsTools = allTools.filter((t) => t.name.startsWith("fs_"));
663
- const mediaTools = allTools.filter(
664
- (t) =>
665
- t.name.startsWith("media_") ||
666
- t.name.startsWith("detect_") ||
667
- t.name.startsWith("audio_")
668
- );
669
- const generateTools = allTools.filter((t) => t.name.startsWith("generate_"));
670
- const editTools = allTools.filter((t) => t.name.startsWith("edit_"));
671
- const analyzeTools = allTools.filter((t) => t.name.startsWith("analyze_"));
672
- const pipelineTools = allTools.filter((t) => t.name.startsWith("pipeline_"));
673
- const exportTools = allTools.filter((t) => t.name.startsWith("export_"));
674
- const batchTools = allTools.filter((t) => t.name.startsWith("batch_"));
675
-
676
- expect(projectTools.length).toBe(5);
677
- expect(timelineTools.length).toBe(11); // Added timeline_clear
678
- expect(fsTools.length).toBe(4);
679
- expect(mediaTools.length).toBe(8); // Added media_compress, media_convert, media_concat
680
- expect(generateTools.length).toBe(8); // image, video, speech, sound_effect, music, storyboard, motion, thumbnail
681
- expect(editTools.length).toBe(8); // text_overlay, silence_cut, jump_cut, caption, noise_reduce, fade, translate_srt, image
682
- expect(analyzeTools.length).toBe(3); // video, media, review
683
- expect(pipelineTools.length).toBe(5); // script_to_video, highlights, auto_shorts, regenerate_scene, animated_caption
684
- expect(exportTools.length).toBe(3);
685
- expect(batchTools.length).toBe(3);
686
-
687
- // Total: 5+11+4+8+8+8+3+4+3+3 = 57
688
- const totalTools = projectTools.length +
689
- timelineTools.length +
690
- fsTools.length +
691
- mediaTools.length +
692
- generateTools.length +
693
- editTools.length +
694
- analyzeTools.length +
695
- pipelineTools.length +
696
- exportTools.length +
697
- batchTools.length;
698
- expect(totalTools).toBe(58);
699
- });
700
- });
701
- });
702
-
703
- describe("Exported CLI Functions", () => {
704
- describe("Function signatures match Agent tool parameters", () => {
705
- it("executeScriptToVideo accepts ScriptToVideoOptions", async () => {
706
- // Type check - this will fail at compile time if signatures don't match
707
- const { executeScriptToVideo } = await import("../../commands/ai-script-pipeline.js");
708
- expect(typeof executeScriptToVideo).toBe("function");
709
- });
710
-
711
- it("executeHighlights accepts HighlightsOptions", async () => {
712
- const { executeHighlights } = await import("../../commands/ai-highlights.js");
713
- expect(typeof executeHighlights).toBe("function");
714
- });
715
-
716
- it("executeAutoShorts accepts AutoShortsOptions", async () => {
717
- const { executeAutoShorts } = await import("../../commands/ai-highlights.js");
718
- expect(typeof executeAutoShorts).toBe("function");
719
- });
720
-
721
- it("executeGeminiVideo accepts GeminiVideoOptions", async () => {
722
- const { executeGeminiVideo } = await import("../../commands/ai-analyze.js");
723
- expect(typeof executeGeminiVideo).toBe("function");
724
- });
725
- });
726
- });
727
-
728
- describe("Tool Name Consistency", () => {
729
- let registry: ToolRegistry;
730
-
731
- beforeEach(() => {
732
- registry = new ToolRegistry();
733
- registerProjectTools(registry);
734
- registerTimelineTools(registry);
735
- registerFilesystemTools(registry);
736
- registerMediaTools(registry);
737
- registerAITools(registry);
738
- registerExportTools(registry);
739
- registerBatchTools(registry);
740
- });
741
-
742
- it("all tool names should follow naming convention", () => {
743
- const tools = registry.getAll();
744
- const validPrefixes = [
745
- "project_",
746
- "timeline_",
747
- "fs_",
748
- "media_",
749
- "detect_",
750
- "audio_",
751
- "generate_",
752
- "edit_",
753
- "analyze_",
754
- "pipeline_",
755
- "export_",
756
- "batch_",
757
- ];
758
-
759
- for (const tool of tools) {
760
- const hasValidPrefix = validPrefixes.some((prefix) =>
761
- tool.name.startsWith(prefix)
762
- );
763
- expect(hasValidPrefix).toBe(true);
764
- }
765
- });
766
-
767
- it("all tool names should be lowercase with underscores", () => {
768
- const tools = registry.getAll();
769
- const validNamePattern = /^[a-z_]+$/;
770
-
771
- for (const tool of tools) {
772
- expect(tool.name).toMatch(validNamePattern);
773
- }
774
- });
775
- });