@vibeframe/cli 0.27.0 → 0.29.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/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
|
@@ -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
|
-
});
|