vargai 0.4.0-alpha15 → 0.4.0-alpha17

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/package.json CHANGED
@@ -64,7 +64,7 @@
64
64
  "replicate": "^1.4.0",
65
65
  "zod": "^4.2.1"
66
66
  },
67
- "version": "0.4.0-alpha15",
67
+ "version": "0.4.0-alpha17",
68
68
  "exports": {
69
69
  ".": "./src/index.ts",
70
70
  "./ai": "./src/ai-sdk/index.ts",
@@ -106,7 +106,7 @@ function flatten(value: unknown): unknown {
106
106
  * });
107
107
  * ```
108
108
  */
109
- const DEFAULT_TTL = "1h";
109
+ const DEFAULT_TTL = "7d";
110
110
 
111
111
  export function withCache<T extends object, R>(
112
112
  fn: (options: T) => Promise<R>,
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * varg find command
3
4
  * Ink-based search view
@@ -1,7 +1,4 @@
1
- /**
2
- * varg help command
3
- * Ink-based help display
4
- */
1
+ /** @jsxImportSource react */
5
2
 
6
3
  import { defineCommand } from "citty";
7
4
  import { Box, Text } from "ink";
@@ -1,7 +1,7 @@
1
1
  export { findCmd, showFindHelp } from "./find.tsx";
2
2
  export { helpCmd, showHelp } from "./help.tsx";
3
3
  export { listCmd, showListHelp } from "./list.tsx";
4
- export { renderCmd } from "./render.ts";
4
+ export { fastCmd, previewCmd, renderCmd } from "./render.ts";
5
5
  export { runCmd, showRunHelp, showTargetHelp } from "./run.tsx";
6
6
  export { studioCmd } from "./studio.ts";
7
7
  export { showWhichHelp, whichCmd } from "./which.tsx";
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * varg list command
3
4
  * Ink-based discovery view
@@ -65,100 +65,119 @@ async function loadComponent(filePath: string): Promise<VargElement> {
65
65
  }
66
66
  }
67
67
 
68
+ const sharedArgs = {
69
+ file: {
70
+ type: "positional" as const,
71
+ description: "component file (.tsx)",
72
+ required: true,
73
+ },
74
+ output: {
75
+ type: "string" as const,
76
+ alias: "o",
77
+ description: "output path",
78
+ },
79
+ cache: {
80
+ type: "string" as const,
81
+ alias: "c",
82
+ description: "cache directory",
83
+ default: ".cache/ai",
84
+ },
85
+ quiet: {
86
+ type: "boolean" as const,
87
+ alias: "q",
88
+ description: "minimal output",
89
+ default: false,
90
+ },
91
+ "no-cache": {
92
+ type: "boolean" as const,
93
+ description: "disable cache (don't read or write)",
94
+ default: false,
95
+ },
96
+ verbose: {
97
+ type: "boolean" as const,
98
+ alias: "v",
99
+ description: "show ffmpeg commands",
100
+ default: false,
101
+ },
102
+ };
103
+
104
+ async function runRender(
105
+ args: Record<string, unknown>,
106
+ mode: RenderMode,
107
+ commandName: string,
108
+ ) {
109
+ const file = args.file as string;
110
+
111
+ if (!file) {
112
+ console.error(`usage: varg ${commandName} <component.tsx> [-o output.mp4]`);
113
+ process.exit(1);
114
+ }
115
+
116
+ const component = await loadComponent(file);
117
+
118
+ if (!component || component.type !== "render") {
119
+ console.error("error: default export must be a <Render> element");
120
+ process.exit(1);
121
+ }
122
+
123
+ const basename = file
124
+ .replace(/\.tsx?$/, "")
125
+ .split("/")
126
+ .pop();
127
+ const outputPath = (args.output as string) ?? `output/${basename}.mp4`;
128
+
129
+ if (!args.quiet) {
130
+ const modeLabel =
131
+ mode === "preview" ? " (fast)" : mode === "strict" ? "" : " (preview)";
132
+ console.log(`rendering ${file} → ${outputPath}${modeLabel}`);
133
+ }
134
+
135
+ const useCache = !args["no-cache"] && mode !== "preview";
136
+
137
+ const defaults = await detectDefaultModels();
138
+
139
+ const buffer = await render(component, {
140
+ output: outputPath,
141
+ cache: useCache ? (args.cache as string) : undefined,
142
+ mode,
143
+ defaults,
144
+ verbose: args.verbose as boolean,
145
+ });
146
+
147
+ if (!args.quiet) {
148
+ console.log(`done! ${buffer.byteLength} bytes → ${outputPath}`);
149
+ }
150
+ }
151
+
68
152
  export const renderCmd = defineCommand({
69
153
  meta: {
70
154
  name: "render",
71
- description: "render a react component to video",
155
+ description: "render to video (strict mode - fails on errors)",
72
156
  },
73
- args: {
74
- file: {
75
- type: "positional",
76
- description: "component file (.tsx)",
77
- required: true,
78
- },
79
- output: {
80
- type: "string",
81
- alias: "o",
82
- description: "output path",
83
- },
84
- cache: {
85
- type: "string",
86
- alias: "c",
87
- description: "cache directory",
88
- default: ".cache/ai",
89
- },
90
- quiet: {
91
- type: "boolean",
92
- alias: "q",
93
- description: "minimal output",
94
- default: false,
95
- },
96
- strict: {
97
- type: "boolean",
98
- description: "fail on provider errors (no fallback)",
99
- default: false,
100
- },
101
- preview: {
102
- type: "boolean",
103
- description: "skip all generation, use placeholders only",
104
- default: false,
105
- },
106
- "no-cache": {
107
- type: "boolean",
108
- description: "disable cache (don't read or write)",
109
- default: false,
110
- },
157
+ args: sharedArgs,
158
+ async run({ args }) {
159
+ await runRender(args, "strict", "render");
160
+ },
161
+ });
162
+
163
+ export const previewCmd = defineCommand({
164
+ meta: {
165
+ name: "preview",
166
+ description: "render with fallback placeholders on errors",
167
+ },
168
+ args: sharedArgs,
169
+ async run({ args }) {
170
+ await runRender(args, "default", "preview");
171
+ },
172
+ });
173
+
174
+ export const fastCmd = defineCommand({
175
+ meta: {
176
+ name: "fast",
177
+ description: "render with all placeholders (no generation)",
111
178
  },
179
+ args: sharedArgs,
112
180
  async run({ args }) {
113
- const file = args.file as string;
114
-
115
- if (!file) {
116
- console.error("usage: varg render <component.tsx> [-o output.mp4]");
117
- process.exit(1);
118
- }
119
-
120
- const component = await loadComponent(file);
121
-
122
- if (!component || component.type !== "render") {
123
- console.error("error: default export must be a <Render> element");
124
- process.exit(1);
125
- }
126
-
127
- const basename = file
128
- .replace(/\.tsx?$/, "")
129
- .split("/")
130
- .pop();
131
- const outputPath = args.output ?? `output/${basename}.mp4`;
132
-
133
- const mode: RenderMode = args.strict
134
- ? "strict"
135
- : args.preview
136
- ? "preview"
137
- : "default";
138
-
139
- if (!args.quiet) {
140
- const modeLabel =
141
- mode === "preview"
142
- ? " (preview)"
143
- : mode === "strict"
144
- ? " (strict)"
145
- : "";
146
- console.log(`rendering ${file} → ${outputPath}${modeLabel}`);
147
- }
148
-
149
- const useCache = !args["no-cache"] && mode !== "preview";
150
-
151
- const defaults = await detectDefaultModels();
152
-
153
- const buffer = await render(component, {
154
- output: outputPath,
155
- cache: useCache ? args.cache : undefined,
156
- mode,
157
- defaults,
158
- });
159
-
160
- if (!args.quiet) {
161
- console.log(`done! ${buffer.byteLength} bytes → ${outputPath}`);
162
- }
181
+ await runRender(args, "preview", "fast");
163
182
  },
164
183
  });
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * varg run command
3
4
  * Ink-based execution with live status updates
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * varg which command
3
4
  * Ink-based inspection view
package/src/cli/index.ts CHANGED
@@ -12,9 +12,11 @@ import { defineCommand, runMain } from "citty";
12
12
  import { registry } from "../core/registry";
13
13
  import { allDefinitions } from "../definitions";
14
14
  import {
15
+ fastCmd,
15
16
  findCmd,
16
17
  helpCmd,
17
18
  listCmd,
19
+ previewCmd,
18
20
  renderCmd,
19
21
  runCmd,
20
22
  showFindHelp,
@@ -104,6 +106,8 @@ const main = defineCommand({
104
106
  subCommands: {
105
107
  run: runCmd,
106
108
  render: renderCmd,
109
+ preview: previewCmd,
110
+ fast: fastCmd,
107
111
  studio: studioCmd,
108
112
  list: listCmd,
109
113
  ls: listCmd,
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * Badge - Type indicator badge
3
4
  * Shows [model] [action] [skill] with appropriate styling
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * DataTable - Table display component
3
4
  * Clean text-based table for listing items
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * Header - Section header component
3
4
  * Bold dimmed text for section titles
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * HelpBlock - Command help and examples
3
4
  * Displays usage patterns and command examples
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * KeyValue - Label-value pair display
3
4
  * Aligned key-value pairs with optional required marker
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * OptionRow - CLI option display with better spacing
3
4
  * Shows option name, description, type hints, defaults, and enums
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * Separator - Horizontal divider line
3
4
  * Minimal visual separator between sections
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * StatusBox - Execution status display
3
4
  * Shows running/done/error state with params and results
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * VargBox - Container component
3
4
  * Luxury minimal styled box with optional title and borders
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * VargProgress - Progress bar component
3
4
  * Elegant thin progress visualization
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * VargSpinner - Animated loading indicator
3
4
  * Elegant braille spinner with label
@@ -1,3 +1,4 @@
1
+ /** @jsxImportSource react */
1
2
  /**
2
3
  * VargText - Typography component
3
4
  * Provides semantic text variants for consistent styling
@@ -0,0 +1,40 @@
1
+ import { elevenlabs } from "../../ai-sdk/providers/elevenlabs";
2
+ import { fal } from "../../ai-sdk/providers/fal";
3
+ import { Clip, Music, Render, render, Title, Video } from "..";
4
+
5
+ export default (
6
+ <Render>
7
+ <Clip duration={4}>
8
+ <Video prompt="A sophisticated tabby cat wearing a tailored tiny business suit and small round glasses, standing upright at a McDonald's counter. One paw raised pointing assertively at the illuminated menu board above. The cat has an extremely serious, concentrated expression with furrowed brows. Cinematic lighting with warm McDonald's interior ambiance, shallow depth of field focusing on the cat's determined face, photorealistic fur texture with fine detail. Professional business atmosphere meets fast food chaos." />
9
+ </Clip>
10
+
11
+ <Clip duration={4}>
12
+ <Video prompt="Absolute mayhem - four to five cats in a chaotic pile fight. Orange tabby, black and white tuxedo cat, calico with patches, and fluffy gray cat all scrambling, paws flailing, tumbling over each other in exaggerated cartoon-style motion. They're all desperately reaching for a single perfect golden McDonald's french fry sitting on a red plastic tray in the center. Wide-eyed expressions, mouths open mid-meow, dynamic motion blur, comedic timing. Fast food restaurant background slightly blurred. Playful, over-the-top energy." />
13
+ </Clip>
14
+
15
+ <Clip duration={3}>
16
+ <Video prompt="Proud orange tabby cat wearing an official McDonald's crew member visor and name tag, standing upright behind a restaurant register counter. Front paws crossed confidently across chest, chin lifted with a smug, self-satisfied expression. Perfect posture, professional demeanor. Bright McDonald's interior lighting, red and yellow color scheme in background. The cat radiates 'employee of the month' energy. Crisp, clean, professional fast food aesthetic." />
17
+ <Title position="bottom">McMeow's: NOW HIRING</Title>
18
+ </Clip>
19
+
20
+ <Music
21
+ model={elevenlabs.musicModel()}
22
+ prompt="playful upbeat comedy music with quirky pizzicato strings and light percussion, funny corporate training video vibes"
23
+ duration={11}
24
+ />
25
+ </Render>
26
+ );
27
+
28
+ async function main() {
29
+ const component = await import("./mcmeows.tsx").then((m) => m.default);
30
+ await render(component, {
31
+ output: "output/mcmeows.mp4",
32
+ cache: ".cache/ai",
33
+ verbose: true,
34
+ defaults: {
35
+ video: fal.videoModel("wan-2.5"),
36
+ },
37
+ });
38
+ }
39
+
40
+ main().catch(console.error);
@@ -0,0 +1,24 @@
1
+ import { elevenlabs } from "../../ai-sdk/providers/elevenlabs";
2
+ import { Clip, Image, Music, Render, render } from "..";
3
+
4
+ export default (
5
+ <Render width={1920} height={1080}>
6
+ <Clip duration={5}>
7
+ <Image src="media/cyberpunk-street.png" />
8
+ </Clip>
9
+ <Music prompt="calm ambient electronic music" duration={5} />
10
+ </Render>
11
+ );
12
+
13
+ async function main() {
14
+ const component = await import("./music-defaults.tsx").then((m) => m.default);
15
+ await render(component, {
16
+ output: "output/music-defaults.mp4",
17
+ defaults: {
18
+ music: elevenlabs.musicModel(),
19
+ },
20
+ });
21
+ console.log("done! check output/music-defaults.mp4");
22
+ }
23
+
24
+ main().catch(console.error);
@@ -22,7 +22,7 @@ export async function renderMusic(
22
22
  duration: props.duration,
23
23
  });
24
24
 
25
- const modelId = model.modelId;
25
+ const modelId = model.modelId ?? "music";
26
26
  const taskId = ctx.progress ? addTask(ctx.progress, "music", modelId) : null;
27
27
 
28
28
  const generateFn = async () => {
@@ -103,7 +103,7 @@ export function completeTask(tracker: ProgressTracker, id: string): void {
103
103
  }
104
104
 
105
105
  function getEstimate(task: ProgressTask): number {
106
- const modelLower = task.model.toLowerCase();
106
+ const modelLower = task.model?.toLowerCase() ?? "";
107
107
  for (const [key, estimate] of Object.entries(MODEL_TIME_ESTIMATES)) {
108
108
  if (modelLower.includes(key.toLowerCase())) {
109
109
  return estimate;
@@ -269,11 +269,11 @@ export async function renderRoot(
269
269
  let path: string;
270
270
  if (musicProps.src) {
271
271
  path = resolvePath(musicProps.src);
272
- } else if (musicProps.prompt && musicProps.model) {
272
+ } else if (musicProps.prompt) {
273
273
  const result = await renderMusic(musicElement, ctx);
274
274
  path = result.path;
275
275
  } else {
276
- throw new Error("Music requires either src or prompt+model");
276
+ throw new Error("Music requires either src or prompt");
277
277
  }
278
278
 
279
279
  audioTracks.push({