@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.
Files changed (109) 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/setup.js +5 -2
  16. package/dist/commands/setup.js.map +1 -1
  17. package/dist/config/schema.d.ts +2 -1
  18. package/dist/config/schema.d.ts.map +1 -1
  19. package/dist/config/schema.js +2 -0
  20. package/dist/config/schema.js.map +1 -1
  21. package/dist/index.js +0 -0
  22. package/package.json +16 -12
  23. package/.turbo/turbo-build.log +0 -4
  24. package/.turbo/turbo-lint.log +0 -21
  25. package/.turbo/turbo-test.log +0 -689
  26. package/src/agent/adapters/claude.ts +0 -143
  27. package/src/agent/adapters/gemini.ts +0 -159
  28. package/src/agent/adapters/index.ts +0 -61
  29. package/src/agent/adapters/ollama.ts +0 -231
  30. package/src/agent/adapters/openai.ts +0 -116
  31. package/src/agent/adapters/xai.ts +0 -119
  32. package/src/agent/index.ts +0 -251
  33. package/src/agent/memory/index.ts +0 -151
  34. package/src/agent/prompts/system.ts +0 -106
  35. package/src/agent/tools/ai-editing.ts +0 -845
  36. package/src/agent/tools/ai-generation.ts +0 -1073
  37. package/src/agent/tools/ai-pipeline.ts +0 -1055
  38. package/src/agent/tools/ai.ts +0 -21
  39. package/src/agent/tools/batch.ts +0 -429
  40. package/src/agent/tools/e2e.test.ts +0 -545
  41. package/src/agent/tools/export.ts +0 -184
  42. package/src/agent/tools/filesystem.ts +0 -237
  43. package/src/agent/tools/index.ts +0 -150
  44. package/src/agent/tools/integration.test.ts +0 -775
  45. package/src/agent/tools/media.ts +0 -697
  46. package/src/agent/tools/project.ts +0 -313
  47. package/src/agent/tools/timeline.ts +0 -951
  48. package/src/agent/types.ts +0 -68
  49. package/src/commands/agent.ts +0 -340
  50. package/src/commands/ai-analyze.ts +0 -429
  51. package/src/commands/ai-animated-caption.ts +0 -390
  52. package/src/commands/ai-audio.ts +0 -941
  53. package/src/commands/ai-broll.ts +0 -490
  54. package/src/commands/ai-edit-cli.ts +0 -658
  55. package/src/commands/ai-edit.ts +0 -1542
  56. package/src/commands/ai-fill-gaps.ts +0 -566
  57. package/src/commands/ai-helpers.ts +0 -65
  58. package/src/commands/ai-highlights.ts +0 -1303
  59. package/src/commands/ai-image.ts +0 -761
  60. package/src/commands/ai-motion.ts +0 -347
  61. package/src/commands/ai-narrate.ts +0 -451
  62. package/src/commands/ai-review.ts +0 -309
  63. package/src/commands/ai-script-pipeline-cli.ts +0 -1710
  64. package/src/commands/ai-script-pipeline.ts +0 -1365
  65. package/src/commands/ai-suggest-edit.ts +0 -264
  66. package/src/commands/ai-video-fx.ts +0 -445
  67. package/src/commands/ai-video.ts +0 -915
  68. package/src/commands/ai-viral.ts +0 -595
  69. package/src/commands/ai-visual-fx.ts +0 -601
  70. package/src/commands/ai.test.ts +0 -627
  71. package/src/commands/ai.ts +0 -307
  72. package/src/commands/analyze.ts +0 -282
  73. package/src/commands/audio.ts +0 -644
  74. package/src/commands/batch.test.ts +0 -279
  75. package/src/commands/batch.ts +0 -440
  76. package/src/commands/detect.ts +0 -329
  77. package/src/commands/doctor.ts +0 -237
  78. package/src/commands/edit-cmd.ts +0 -1014
  79. package/src/commands/export.ts +0 -918
  80. package/src/commands/generate.ts +0 -2146
  81. package/src/commands/media.ts +0 -177
  82. package/src/commands/output.ts +0 -142
  83. package/src/commands/pipeline.ts +0 -398
  84. package/src/commands/project.test.ts +0 -127
  85. package/src/commands/project.ts +0 -149
  86. package/src/commands/sanitize.ts +0 -60
  87. package/src/commands/schema.ts +0 -130
  88. package/src/commands/setup.ts +0 -509
  89. package/src/commands/timeline.test.ts +0 -499
  90. package/src/commands/timeline.ts +0 -529
  91. package/src/commands/validate.ts +0 -77
  92. package/src/config/config.test.ts +0 -197
  93. package/src/config/index.ts +0 -125
  94. package/src/config/schema.ts +0 -82
  95. package/src/engine/index.ts +0 -2
  96. package/src/engine/project.test.ts +0 -702
  97. package/src/engine/project.ts +0 -439
  98. package/src/index.ts +0 -146
  99. package/src/utils/api-key.test.ts +0 -41
  100. package/src/utils/api-key.ts +0 -247
  101. package/src/utils/audio.ts +0 -83
  102. package/src/utils/exec-safe.ts +0 -75
  103. package/src/utils/first-run.ts +0 -52
  104. package/src/utils/provider-resolver.ts +0 -56
  105. package/src/utils/remotion.ts +0 -951
  106. package/src/utils/subtitle.test.ts +0 -227
  107. package/src/utils/subtitle.ts +0 -169
  108. package/src/utils/tty.ts +0 -196
  109. package/tsconfig.json +0 -20
@@ -1,440 +0,0 @@
1
- import { Command } from "commander";
2
- import { readFile, writeFile, readdir } from "node:fs/promises";
3
- import { resolve, basename, extname, join } from "node:path";
4
- import chalk from "chalk";
5
- import ora from "ora";
6
- import { Project, type ProjectFile } from "../engine/index.js";
7
- import type { MediaType, EffectType } from "@vibeframe/core/timeline";
8
-
9
- export const batchCommand = new Command("batch")
10
- .description("Batch operations for processing multiple items");
11
-
12
- /**
13
- * Detect media type from file extension
14
- */
15
- function detectMediaType(filePath: string): MediaType {
16
- const ext = extname(filePath).toLowerCase();
17
- const videoExts = [".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v"];
18
- const audioExts = [".mp3", ".wav", ".aac", ".flac", ".ogg", ".m4a"];
19
- const imageExts = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"];
20
-
21
- if (videoExts.includes(ext)) return "video";
22
- if (audioExts.includes(ext)) return "audio";
23
- if (imageExts.includes(ext)) return "image";
24
- return "video"; // Default to video
25
- }
26
-
27
- /**
28
- * Check if file is a media file
29
- */
30
- function isMediaFile(filePath: string): boolean {
31
- const ext = extname(filePath).toLowerCase();
32
- const mediaExts = [
33
- ".mp4", ".mov", ".avi", ".mkv", ".webm", ".m4v",
34
- ".mp3", ".wav", ".aac", ".flac", ".ogg", ".m4a",
35
- ".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp",
36
- ];
37
- return mediaExts.includes(ext);
38
- }
39
-
40
- // ============ batch import ============
41
-
42
- batchCommand
43
- .command("import")
44
- .description("Import multiple media files from a directory")
45
- .argument("<project>", "Project file path")
46
- .argument("<directory>", "Directory containing media files")
47
- .option("-r, --recursive", "Search subdirectories", false)
48
- .option("-d, --duration <seconds>", "Default duration for images", "5")
49
- .option("--filter <pattern>", "Filter files by extension (e.g., '.mp4,.mov')")
50
- .action(async (projectPath: string, directory: string, options) => {
51
- const spinner = ora("Scanning directory...").start();
52
-
53
- try {
54
- const filePath = resolve(process.cwd(), projectPath);
55
- const content = await readFile(filePath, "utf-8");
56
- const data: ProjectFile = JSON.parse(content);
57
- const project = Project.fromJSON(data);
58
-
59
- const dirPath = resolve(process.cwd(), directory);
60
- const filterExts = options.filter
61
- ? options.filter.split(",").map((e: string) => e.trim().toLowerCase())
62
- : null;
63
-
64
- // Collect media files
65
- const mediaFiles: string[] = [];
66
-
67
- const scanDir = async (dir: string): Promise<void> => {
68
- const entries = await readdir(dir, { withFileTypes: true });
69
-
70
- for (const entry of entries) {
71
- const entryPath = join(dir, entry.name);
72
-
73
- if (entry.isDirectory() && options.recursive) {
74
- await scanDir(entryPath);
75
- } else if (entry.isFile()) {
76
- const ext = extname(entry.name).toLowerCase();
77
- const matchesFilter = !filterExts || filterExts.includes(ext);
78
-
79
- if (matchesFilter && isMediaFile(entryPath)) {
80
- mediaFiles.push(entryPath);
81
- }
82
- }
83
- }
84
- };
85
-
86
- await scanDir(dirPath);
87
-
88
- if (mediaFiles.length === 0) {
89
- spinner.fail(chalk.red("No media files found in directory"));
90
- process.exit(1);
91
- }
92
-
93
- // Sort files alphabetically
94
- mediaFiles.sort();
95
-
96
- spinner.text = `Importing ${mediaFiles.length} files...`;
97
-
98
- const addedSources: string[] = [];
99
- const defaultDuration = parseFloat(options.duration);
100
-
101
- for (const mediaFile of mediaFiles) {
102
- const mediaName = basename(mediaFile);
103
- const mediaType = detectMediaType(mediaFile);
104
- const duration = mediaType === "image" ? defaultDuration : 0;
105
-
106
- const source = project.addSource({
107
- name: mediaName,
108
- type: mediaType,
109
- url: mediaFile,
110
- duration,
111
- });
112
-
113
- addedSources.push(source.id);
114
- }
115
-
116
- await writeFile(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
117
-
118
- spinner.succeed(chalk.green(`Imported ${addedSources.length} media files`));
119
- console.log();
120
-
121
- for (const file of mediaFiles) {
122
- console.log(chalk.dim(" +"), basename(file));
123
- }
124
-
125
- console.log();
126
- } catch (error) {
127
- spinner.fail(chalk.red("Import failed"));
128
- if (error instanceof Error) {
129
- console.error(chalk.red(error.message));
130
- }
131
- process.exit(1);
132
- }
133
- });
134
-
135
- // ============ batch concat ============
136
-
137
- batchCommand
138
- .command("concat")
139
- .description("Concatenate multiple sources into sequential clips")
140
- .argument("<project>", "Project file path")
141
- .argument("[source-ids...]", "Source IDs to concatenate (or --all)")
142
- .option("--all", "Concatenate all sources in order", false)
143
- .option("--track <track-id>", "Track to place clips on")
144
- .option("--start <seconds>", "Starting time", "0")
145
- .option("--gap <seconds>", "Gap between clips", "0")
146
- .action(async (projectPath: string, sourceIds: string[], options) => {
147
- const spinner = ora("Creating clips...").start();
148
-
149
- try {
150
- const filePath = resolve(process.cwd(), projectPath);
151
- const content = await readFile(filePath, "utf-8");
152
- const data: ProjectFile = JSON.parse(content);
153
- const project = Project.fromJSON(data);
154
-
155
- const sources = project.getSources();
156
-
157
- if (sources.length === 0) {
158
- spinner.fail(chalk.red("No sources in project"));
159
- process.exit(1);
160
- }
161
-
162
- // Get sources to concatenate
163
- let selectedSources = sources;
164
- if (!options.all && sourceIds.length > 0) {
165
- selectedSources = sourceIds
166
- .map((id) => sources.find((s) => s.id === id))
167
- .filter((s): s is NonNullable<typeof s> => s !== undefined);
168
-
169
- if (selectedSources.length === 0) {
170
- spinner.fail(chalk.red("No matching sources found"));
171
- process.exit(1);
172
- }
173
- }
174
-
175
- // Determine track
176
- const tracks = project.getTracks();
177
- let trackId = options.track;
178
-
179
- if (!trackId) {
180
- // Use first video track for video, first audio track for audio
181
- const firstSource = selectedSources[0];
182
- const matchingTrack = tracks.find((t) => t.type === firstSource.type);
183
- trackId = matchingTrack?.id || tracks[0].id;
184
- }
185
-
186
- const startTime = parseFloat(options.start);
187
- const gap = parseFloat(options.gap);
188
- let currentTime = startTime;
189
- const addedClips: string[] = [];
190
-
191
- for (const source of selectedSources) {
192
- const clip = project.addClip({
193
- sourceId: source.id,
194
- trackId,
195
- startTime: currentTime,
196
- duration: source.duration,
197
- sourceStartOffset: 0,
198
- sourceEndOffset: source.duration,
199
- });
200
-
201
- addedClips.push(clip.id);
202
- currentTime += source.duration + gap;
203
- }
204
-
205
- await writeFile(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
206
-
207
- spinner.succeed(chalk.green(`Created ${addedClips.length} clips`));
208
- console.log();
209
- console.log(chalk.dim(" Total duration:"), `${currentTime - gap}s`);
210
- console.log(chalk.dim(" Track:"), trackId);
211
-
212
- for (let i = 0; i < selectedSources.length; i++) {
213
- console.log(chalk.dim(` ${i + 1}.`), selectedSources[i].name);
214
- }
215
-
216
- console.log();
217
- } catch (error) {
218
- spinner.fail(chalk.red("Concat failed"));
219
- if (error instanceof Error) {
220
- console.error(chalk.red(error.message));
221
- }
222
- process.exit(1);
223
- }
224
- });
225
-
226
- // ============ batch apply-effect ============
227
-
228
- batchCommand
229
- .command("apply-effect")
230
- .description("Apply an effect to multiple clips")
231
- .argument("<project>", "Project file path")
232
- .argument("<effect-type>", "Effect type (fadeIn, fadeOut, blur, etc.)")
233
- .argument("[clip-ids...]", "Clip IDs to apply effect to (or --all)")
234
- .option("--all", "Apply to all clips", false)
235
- .option("-d, --duration <seconds>", "Effect duration", "1")
236
- .option("-s, --start <seconds>", "Effect start time (relative to clip)", "0")
237
- .option("--intensity <value>", "Effect intensity (0-1)", "1")
238
- .action(
239
- async (
240
- projectPath: string,
241
- effectType: string,
242
- clipIds: string[],
243
- options
244
- ) => {
245
- const spinner = ora("Applying effects...").start();
246
-
247
- try {
248
- const filePath = resolve(process.cwd(), projectPath);
249
- const content = await readFile(filePath, "utf-8");
250
- const data: ProjectFile = JSON.parse(content);
251
- const project = Project.fromJSON(data);
252
-
253
- const clips = project.getClips();
254
-
255
- if (clips.length === 0) {
256
- spinner.fail(chalk.red("No clips in project"));
257
- process.exit(1);
258
- }
259
-
260
- // Get clips to apply effect to
261
- let selectedClips = clips;
262
- if (!options.all && clipIds.length > 0) {
263
- selectedClips = clipIds
264
- .map((id) => clips.find((c) => c.id === id))
265
- .filter((c): c is NonNullable<typeof c> => c !== undefined);
266
-
267
- if (selectedClips.length === 0) {
268
- spinner.fail(chalk.red("No matching clips found"));
269
- process.exit(1);
270
- }
271
- }
272
-
273
- const duration = parseFloat(options.duration);
274
- const startTime = parseFloat(options.start);
275
- const intensity = parseFloat(options.intensity);
276
- let appliedCount = 0;
277
-
278
- for (const clip of selectedClips) {
279
- const effect = project.addEffect(clip.id, {
280
- type: effectType as EffectType,
281
- startTime,
282
- duration,
283
- params: { intensity },
284
- });
285
-
286
- if (effect) {
287
- appliedCount++;
288
- }
289
- }
290
-
291
- await writeFile(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
292
-
293
- spinner.succeed(
294
- chalk.green(`Applied ${effectType} to ${appliedCount} clips`)
295
- );
296
- console.log();
297
- console.log(chalk.dim(" Effect:"), effectType);
298
- console.log(chalk.dim(" Duration:"), `${duration}s`);
299
- console.log(chalk.dim(" Intensity:"), intensity);
300
- console.log();
301
- } catch (error) {
302
- spinner.fail(chalk.red("Apply effect failed"));
303
- if (error instanceof Error) {
304
- console.error(chalk.red(error.message));
305
- }
306
- process.exit(1);
307
- }
308
- }
309
- );
310
-
311
- // ============ batch remove-clips ============
312
-
313
- batchCommand
314
- .command("remove-clips")
315
- .description("Remove multiple clips from the timeline")
316
- .argument("<project>", "Project file path")
317
- .argument("[clip-ids...]", "Clip IDs to remove")
318
- .option("--all", "Remove all clips", false)
319
- .option("--track <track-id>", "Remove clips from specific track only")
320
- .action(async (projectPath: string, clipIds: string[], options) => {
321
- const spinner = ora("Removing clips...").start();
322
-
323
- try {
324
- const filePath = resolve(process.cwd(), projectPath);
325
- const content = await readFile(filePath, "utf-8");
326
- const data: ProjectFile = JSON.parse(content);
327
- const project = Project.fromJSON(data);
328
-
329
- const clips = project.getClips();
330
-
331
- if (clips.length === 0) {
332
- spinner.fail(chalk.red("No clips in project"));
333
- process.exit(1);
334
- }
335
-
336
- // Get clips to remove
337
- let clipsToRemove = clips;
338
-
339
- if (options.track) {
340
- clipsToRemove = clips.filter((c) => c.trackId === options.track);
341
- }
342
-
343
- if (!options.all && clipIds.length > 0) {
344
- clipsToRemove = clipIds
345
- .map((id) => clips.find((c) => c.id === id))
346
- .filter((c): c is NonNullable<typeof c> => c !== undefined);
347
- }
348
-
349
- if (clipsToRemove.length === 0) {
350
- spinner.fail(chalk.red("No matching clips found"));
351
- process.exit(1);
352
- }
353
-
354
- let removedCount = 0;
355
- for (const clip of clipsToRemove) {
356
- if (project.removeClip(clip.id)) {
357
- removedCount++;
358
- }
359
- }
360
-
361
- await writeFile(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
362
-
363
- spinner.succeed(chalk.green(`Removed ${removedCount} clips`));
364
- console.log();
365
- } catch (error) {
366
- spinner.fail(chalk.red("Remove clips failed"));
367
- if (error instanceof Error) {
368
- console.error(chalk.red(error.message));
369
- }
370
- process.exit(1);
371
- }
372
- });
373
-
374
- // ============ batch info ============
375
-
376
- batchCommand
377
- .command("info")
378
- .description("Show batch processing statistics")
379
- .argument("<project>", "Project file path")
380
- .action(async (projectPath: string) => {
381
- const spinner = ora("Loading project...").start();
382
-
383
- try {
384
- const filePath = resolve(process.cwd(), projectPath);
385
- const content = await readFile(filePath, "utf-8");
386
- const data: ProjectFile = JSON.parse(content);
387
- const project = Project.fromJSON(data);
388
-
389
- const sources = project.getSources();
390
- const clips = project.getClips();
391
- const tracks = project.getTracks();
392
- const summary = project.getSummary();
393
-
394
- spinner.stop();
395
-
396
- console.log(chalk.bold("\nProject Statistics\n"));
397
-
398
- // Sources breakdown
399
- const videoSources = sources.filter((s) => s.type === "video").length;
400
- const audioSources = sources.filter((s) => s.type === "audio").length;
401
- const imageSources = sources.filter((s) => s.type === "image").length;
402
-
403
- console.log(chalk.cyan("Sources:"), sources.length);
404
- if (videoSources > 0) console.log(chalk.dim(" Video:"), videoSources);
405
- if (audioSources > 0) console.log(chalk.dim(" Audio:"), audioSources);
406
- if (imageSources > 0) console.log(chalk.dim(" Image:"), imageSources);
407
-
408
- // Clips breakdown
409
- const clipsPerTrack = tracks.map((t) => ({
410
- track: t.name,
411
- count: clips.filter((c) => c.trackId === t.id).length,
412
- }));
413
-
414
- console.log(chalk.cyan("\nClips:"), clips.length);
415
- for (const { track, count } of clipsPerTrack) {
416
- if (count > 0) console.log(chalk.dim(` ${track}:`), count);
417
- }
418
-
419
- // Effects count
420
- const totalEffects = clips.reduce((sum, c) => sum + c.effects.length, 0);
421
- if (totalEffects > 0) {
422
- console.log(chalk.cyan("\nEffects:"), totalEffects);
423
- }
424
-
425
- // Timeline info
426
- console.log(chalk.cyan("\nTimeline:"));
427
- console.log(chalk.dim(" Duration:"), `${summary.duration.toFixed(1)}s`);
428
- console.log(chalk.dim(" Tracks:"), tracks.length);
429
- console.log(chalk.dim(" Frame rate:"), `${summary.frameRate} fps`);
430
- console.log(chalk.dim(" Aspect ratio:"), summary.aspectRatio);
431
-
432
- console.log();
433
- } catch (error) {
434
- spinner.fail(chalk.red("Failed to load project"));
435
- if (error instanceof Error) {
436
- console.error(chalk.red(error.message));
437
- }
438
- process.exit(1);
439
- }
440
- });