@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,429 +0,0 @@
1
- /**
2
- * @module ai-analyze
3
- *
4
- * Media analysis execute functions using Gemini multimodal AI.
5
- *
6
- * CLI commands: gemini-video, analyze
7
- *
8
- * Execute functions:
9
- * executeGeminiVideo - Analyze video files or YouTube URLs with Gemini
10
- * executeAnalyze - Unified analysis for images, videos, and YouTube URLs
11
- *
12
- * @dependencies Gemini (Google)
13
- */
14
-
15
- import { Command } from "commander";
16
- import { readFile } from "node:fs/promises";
17
- import { extname, resolve } from "node:path";
18
- import { existsSync } from "node:fs";
19
- import chalk from "chalk";
20
- import ora from "ora";
21
- import { GeminiProvider } from "@vibeframe/ai-providers";
22
- import { getApiKey } from "../utils/api-key.js";
23
-
24
- /** Options for {@link executeGeminiVideo}. */
25
- export interface GeminiVideoOptions {
26
- /** Video file path or YouTube URL */
27
- source: string;
28
- /** Analysis prompt (e.g. "Summarize this video") */
29
- prompt: string;
30
- /** Gemini model shorthand (default: "flash") */
31
- model?: "flash" | "flash-2.5" | "pro";
32
- /** Frames per second for video sampling (default: 1) */
33
- fps?: number;
34
- /** Start offset in seconds for clipping */
35
- start?: number;
36
- /** End offset in seconds for clipping */
37
- end?: number;
38
- /** Use low-resolution mode (fewer tokens, longer videos) */
39
- lowRes?: boolean;
40
- }
41
-
42
- /** Result from {@link executeGeminiVideo}. */
43
- export interface GeminiVideoResult {
44
- /** Whether the analysis succeeded */
45
- success: boolean;
46
- /** Gemini's text response */
47
- response?: string;
48
- /** Model used for analysis */
49
- model?: string;
50
- /** Total tokens consumed */
51
- totalTokens?: number;
52
- /** Prompt tokens consumed */
53
- promptTokens?: number;
54
- /** Response tokens generated */
55
- responseTokens?: number;
56
- /** Error message on failure */
57
- error?: string;
58
- }
59
-
60
- /**
61
- * Analyze a video file or YouTube URL using Gemini multimodal AI.
62
- *
63
- * Supports local video files and YouTube URLs. Provides structured responses
64
- * with optional token usage reporting.
65
- *
66
- * @param options - Video analysis configuration
67
- * @returns Result with Gemini's response text and token usage
68
- */
69
- export async function executeGeminiVideo(
70
- options: GeminiVideoOptions
71
- ): Promise<GeminiVideoResult> {
72
- try {
73
- const apiKey = await getApiKey("GOOGLE_API_KEY", "Google");
74
- if (!apiKey) {
75
- return { success: false, error: "Google API key required. Run 'vibe setup' or set GOOGLE_API_KEY in .env" };
76
- }
77
-
78
- const isYouTube = options.source.includes("youtube.com") || options.source.includes("youtu.be");
79
-
80
- const modelMap: Record<string, string> = {
81
- flash: "gemini-3-flash-preview",
82
- "flash-2.5": "gemini-2.5-flash",
83
- pro: "gemini-2.5-pro",
84
- };
85
- const modelId = modelMap[options.model || "flash"] || modelMap.flash;
86
-
87
- let videoData: Buffer | string;
88
- if (isYouTube) {
89
- videoData = options.source;
90
- } else {
91
- const absPath = resolve(process.cwd(), options.source);
92
- if (!existsSync(absPath)) {
93
- return { success: false, error: `File not found: ${absPath}` };
94
- }
95
- videoData = await readFile(absPath);
96
- }
97
-
98
- const gemini = new GeminiProvider();
99
- await gemini.initialize({ apiKey });
100
-
101
- const result = await gemini.analyzeVideo(videoData, options.prompt, {
102
- model: modelId as "gemini-3-flash-preview" | "gemini-2.5-flash" | "gemini-2.5-pro",
103
- fps: options.fps,
104
- startOffset: options.start,
105
- endOffset: options.end,
106
- lowResolution: options.lowRes,
107
- });
108
-
109
- if (!result.success) {
110
- return { success: false, error: result.error || "Video analysis failed" };
111
- }
112
-
113
- return {
114
- success: true,
115
- response: result.response,
116
- model: result.model,
117
- totalTokens: result.totalTokens,
118
- promptTokens: result.promptTokens,
119
- responseTokens: result.responseTokens,
120
- };
121
- } catch (error) {
122
- return {
123
- success: false,
124
- error: error instanceof Error ? error.message : String(error),
125
- };
126
- }
127
- }
128
-
129
- /** Options for {@link executeAnalyze}. */
130
- export interface AnalyzeOptions {
131
- /** Image/video file path, image URL, or YouTube URL */
132
- source: string;
133
- /** Analysis prompt (e.g. "Describe this image") */
134
- prompt: string;
135
- /** Gemini model shorthand (default: "flash") */
136
- model?: "flash" | "flash-2.5" | "pro";
137
- /** Frames per second for video sampling (default: 1) */
138
- fps?: number;
139
- /** Start offset in seconds (video only) */
140
- start?: number;
141
- /** End offset in seconds (video only) */
142
- end?: number;
143
- /** Use low-resolution mode (fewer tokens) */
144
- lowRes?: boolean;
145
- }
146
-
147
- /** Result from {@link executeAnalyze}. */
148
- export interface AnalyzeResult {
149
- /** Whether the analysis succeeded */
150
- success: boolean;
151
- /** Gemini's text response */
152
- response?: string;
153
- /** Model used for analysis */
154
- model?: string;
155
- /** Detected source media type */
156
- sourceType?: "image" | "video" | "youtube";
157
- /** Total tokens consumed */
158
- totalTokens?: number;
159
- /** Prompt tokens consumed */
160
- promptTokens?: number;
161
- /** Response tokens generated */
162
- responseTokens?: number;
163
- /** Error message on failure */
164
- error?: string;
165
- }
166
-
167
- /**
168
- * Analyze any media source (image, video, or YouTube URL) using Gemini.
169
- *
170
- * Auto-detects source type from file extension or URL pattern. Supports
171
- * local files, remote URLs, and YouTube links.
172
- *
173
- * @param options - Unified analysis configuration
174
- * @returns Result with Gemini's response, detected source type, and token usage
175
- */
176
- export async function executeAnalyze(
177
- options: AnalyzeOptions
178
- ): Promise<AnalyzeResult> {
179
- try {
180
- const apiKey = await getApiKey("GOOGLE_API_KEY", "Google");
181
- if (!apiKey) {
182
- return { success: false, error: "Google API key required. Run 'vibe setup' or set GOOGLE_API_KEY in .env" };
183
- }
184
-
185
- const source = options.source;
186
-
187
- const isYouTube = source.includes("youtube.com") || source.includes("youtu.be");
188
- const isImageUrl = /^https?:\/\/.+\.(png|jpg|jpeg|webp|gif)(\?.*)?$/i.test(source);
189
- const isVideoUrl = /^https?:\/\/.+\.(mp4|mov|webm)(\?.*)?$/i.test(source);
190
- const ext = extname(source).toLowerCase();
191
- const imageExts = [".png", ".jpg", ".jpeg", ".webp", ".gif"];
192
- const videoExts = [".mp4", ".mov", ".webm", ".avi", ".mkv"];
193
- const isLocalImage = imageExts.includes(ext);
194
- const isLocalVideo = videoExts.includes(ext);
195
- const isImage = isImageUrl || isLocalImage;
196
- const isVideo = isYouTube || isVideoUrl || isLocalVideo;
197
-
198
- if (!isImage && !isVideo) {
199
- return {
200
- success: false,
201
- error: "Cannot detect source type. Supported: images (.png/.jpg/.webp/.gif), videos (.mp4/.mov/.webm), YouTube URLs, image URLs.",
202
- };
203
- }
204
-
205
- const modelMap: Record<string, string> = {
206
- flash: "gemini-3-flash-preview",
207
- "flash-2.5": "gemini-2.5-flash",
208
- pro: "gemini-2.5-pro",
209
- };
210
- const modelId = modelMap[options.model || "flash"] || modelMap.flash;
211
-
212
- const gemini = new GeminiProvider();
213
- await gemini.initialize({ apiKey });
214
-
215
- if (isImage) {
216
- let imageBuffer: Buffer;
217
- if (isImageUrl) {
218
- const response = await fetch(source);
219
- if (!response.ok) {
220
- return { success: false, error: `Failed to fetch image: ${response.status}` };
221
- }
222
- imageBuffer = Buffer.from(await response.arrayBuffer());
223
- } else {
224
- const absPath = resolve(process.cwd(), source);
225
- if (!existsSync(absPath)) {
226
- return { success: false, error: `File not found: ${absPath}` };
227
- }
228
- imageBuffer = await readFile(absPath);
229
- }
230
-
231
- const result = await gemini.analyzeImage(imageBuffer, options.prompt, {
232
- model: modelId as "gemini-3-flash-preview" | "gemini-2.5-flash" | "gemini-2.5-pro",
233
- lowResolution: options.lowRes,
234
- });
235
-
236
- if (!result.success) {
237
- return { success: false, error: result.error || "Image analysis failed" };
238
- }
239
-
240
- return {
241
- success: true,
242
- response: result.response,
243
- model: result.model,
244
- sourceType: "image",
245
- totalTokens: result.totalTokens,
246
- promptTokens: result.promptTokens,
247
- responseTokens: result.responseTokens,
248
- };
249
- }
250
-
251
- let videoData: Buffer | string;
252
- let sourceType: "video" | "youtube" = "video";
253
-
254
- if (isYouTube) {
255
- videoData = source;
256
- sourceType = "youtube";
257
- } else if (isVideoUrl) {
258
- const response = await fetch(source);
259
- if (!response.ok) {
260
- return { success: false, error: `Failed to fetch video: ${response.status}` };
261
- }
262
- videoData = Buffer.from(await response.arrayBuffer());
263
- } else {
264
- const absPath = resolve(process.cwd(), source);
265
- if (!existsSync(absPath)) {
266
- return { success: false, error: `File not found: ${absPath}` };
267
- }
268
- videoData = await readFile(absPath);
269
- }
270
-
271
- const result = await gemini.analyzeVideo(videoData, options.prompt, {
272
- model: modelId as "gemini-3-flash-preview" | "gemini-2.5-flash" | "gemini-2.5-pro",
273
- fps: options.fps,
274
- startOffset: options.start,
275
- endOffset: options.end,
276
- lowResolution: options.lowRes,
277
- });
278
-
279
- if (!result.success) {
280
- return { success: false, error: result.error || "Video analysis failed" };
281
- }
282
-
283
- return {
284
- success: true,
285
- response: result.response,
286
- model: result.model,
287
- sourceType,
288
- totalTokens: result.totalTokens,
289
- promptTokens: result.promptTokens,
290
- responseTokens: result.responseTokens,
291
- };
292
- } catch (error) {
293
- return {
294
- success: false,
295
- error: error instanceof Error ? error.message : String(error),
296
- };
297
- }
298
- }
299
-
300
- export function registerAnalyzeCommands(aiCommand: Command): void {
301
- aiCommand
302
- .command("gemini-video")
303
- .description("Analyze video using Gemini (summarize, Q&A, extract info)")
304
- .argument("<source>", "Video file path or YouTube URL")
305
- .argument("<prompt>", "Analysis prompt (e.g., 'Summarize this video')")
306
- .option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)")
307
- .option("-m, --model <model>", "Model: flash (default), flash-2.5, pro", "flash")
308
- .option("--fps <number>", "Frames per second (default: 1, higher for action)")
309
- .option("--start <seconds>", "Start offset in seconds (for clipping)")
310
- .option("--end <seconds>", "End offset in seconds (for clipping)")
311
- .option("--low-res", "Use low resolution mode (fewer tokens, longer videos)")
312
- .option("-v, --verbose", "Show token usage")
313
- .action(async (source: string, prompt: string, options) => {
314
- try {
315
- if (options.apiKey) {
316
- process.env.GOOGLE_API_KEY = options.apiKey;
317
- } else {
318
- const apiKey = await getApiKey("GOOGLE_API_KEY", "Google");
319
- if (!apiKey) {
320
- console.error(chalk.red("Google API key required. Set GOOGLE_API_KEY in .env or run: vibe setup"));
321
- console.error(chalk.dim("Use --api-key or set GOOGLE_API_KEY environment variable"));
322
- process.exit(1);
323
- }
324
- }
325
-
326
- const spinner = ora("Analyzing video...").start();
327
- const result = await executeGeminiVideo({
328
- source,
329
- prompt,
330
- model: options.model as "flash" | "flash-2.5" | "pro",
331
- fps: options.fps ? parseFloat(options.fps) : undefined,
332
- start: options.start ? parseInt(options.start, 10) : undefined,
333
- end: options.end ? parseInt(options.end, 10) : undefined,
334
- lowRes: options.lowRes,
335
- });
336
-
337
- if (!result.success) {
338
- spinner.fail(chalk.red(result.error || "Video analysis failed"));
339
- process.exit(1);
340
- }
341
-
342
- spinner.succeed(chalk.green("Video analyzed"));
343
- console.log();
344
- console.log(result.response);
345
- console.log();
346
-
347
- if (options.verbose && result.totalTokens) {
348
- console.log(chalk.dim("-".repeat(40)));
349
- console.log(chalk.dim(`Model: ${result.model}`));
350
- if (result.promptTokens) {
351
- console.log(chalk.dim(`Prompt tokens: ${result.promptTokens.toLocaleString()}`));
352
- }
353
- if (result.responseTokens) {
354
- console.log(chalk.dim(`Response tokens: ${result.responseTokens.toLocaleString()}`));
355
- }
356
- console.log(chalk.dim(`Total tokens: ${result.totalTokens.toLocaleString()}`));
357
- }
358
- } catch (error) {
359
- console.error(chalk.red("Video analysis failed"));
360
- console.error(error);
361
- process.exit(1);
362
- }
363
- });
364
-
365
- aiCommand
366
- .command("analyze")
367
- .description("Analyze any media: images, videos, or YouTube URLs using Gemini")
368
- .argument("<source>", "Image/video file path, image URL, or YouTube URL")
369
- .argument("<prompt>", "Analysis prompt (e.g., 'Describe this image', 'Summarize this video')")
370
- .option("-k, --api-key <key>", "Google API key (or set GOOGLE_API_KEY env)")
371
- .option("-m, --model <model>", "Model: flash (default), flash-2.5, pro", "flash")
372
- .option("--fps <number>", "Frames per second for video (default: 1)")
373
- .option("--start <seconds>", "Start offset in seconds (video only)")
374
- .option("--end <seconds>", "End offset in seconds (video only)")
375
- .option("--low-res", "Use low resolution mode (fewer tokens)")
376
- .option("-v, --verbose", "Show token usage")
377
- .action(async (source: string, prompt: string, options) => {
378
- try {
379
- if (options.apiKey) {
380
- process.env.GOOGLE_API_KEY = options.apiKey;
381
- } else {
382
- const apiKey = await getApiKey("GOOGLE_API_KEY", "Google");
383
- if (!apiKey) {
384
- console.error(chalk.red("Google API key required. Set GOOGLE_API_KEY in .env or run: vibe setup"));
385
- console.error(chalk.dim("Use --api-key or set GOOGLE_API_KEY environment variable"));
386
- process.exit(1);
387
- }
388
- }
389
-
390
- const spinner = ora("Analyzing source...").start();
391
- const result = await executeAnalyze({
392
- source,
393
- prompt,
394
- model: options.model as "flash" | "flash-2.5" | "pro",
395
- fps: options.fps ? parseFloat(options.fps) : undefined,
396
- start: options.start ? parseInt(options.start, 10) : undefined,
397
- end: options.end ? parseInt(options.end, 10) : undefined,
398
- lowRes: options.lowRes,
399
- });
400
-
401
- if (!result.success) {
402
- spinner.fail(chalk.red(result.error || "Analysis failed"));
403
- process.exit(1);
404
- }
405
-
406
- spinner.succeed(chalk.green("Analysis complete"));
407
- console.log();
408
- console.log(result.response);
409
- console.log();
410
-
411
- if (options.verbose && result.totalTokens) {
412
- console.log(chalk.dim("-".repeat(40)));
413
- console.log(chalk.dim(`Source type: ${result.sourceType}`));
414
- console.log(chalk.dim(`Model: ${result.model}`));
415
- if (result.promptTokens) {
416
- console.log(chalk.dim(`Prompt tokens: ${result.promptTokens.toLocaleString()}`));
417
- }
418
- if (result.responseTokens) {
419
- console.log(chalk.dim(`Response tokens: ${result.responseTokens.toLocaleString()}`));
420
- }
421
- console.log(chalk.dim(`Total tokens: ${result.totalTokens.toLocaleString()}`));
422
- }
423
- } catch (error) {
424
- console.error(chalk.red("Analysis failed"));
425
- console.error(error);
426
- process.exit(1);
427
- }
428
- });
429
- }