@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,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
- });