varg.ai-sdk 0.1.1 → 0.4.0-alpha.1

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 (246) hide show
  1. package/.claude/settings.local.json +1 -1
  2. package/.env.example +3 -0
  3. package/.github/workflows/ci.yml +23 -0
  4. package/.husky/README.md +102 -0
  5. package/.husky/commit-msg +6 -0
  6. package/.husky/pre-commit +9 -0
  7. package/.husky/pre-push +6 -0
  8. package/.size-limit.json +8 -0
  9. package/.test-hooks.ts +5 -0
  10. package/CLAUDE.md +10 -3
  11. package/CONTRIBUTING.md +150 -0
  12. package/LICENSE.md +53 -0
  13. package/README.md +56 -209
  14. package/SKILLS.md +26 -10
  15. package/biome.json +7 -1
  16. package/bun.lock +1286 -0
  17. package/commitlint.config.js +22 -0
  18. package/docs/index.html +1130 -0
  19. package/docs/prompting.md +326 -0
  20. package/docs/react.md +834 -0
  21. package/docs/sdk.md +812 -0
  22. package/ffmpeg/CLAUDE.md +68 -0
  23. package/package.json +43 -10
  24. package/pipeline/cookbooks/scripts/animate-frames-parallel.ts +84 -0
  25. package/pipeline/cookbooks/scripts/combine-scenes.sh +53 -0
  26. package/pipeline/cookbooks/scripts/generate-frames-parallel.ts +99 -0
  27. package/pipeline/cookbooks/scripts/still-to-video.sh +37 -0
  28. package/pipeline/cookbooks/text-to-tiktok.md +669 -0
  29. package/pipeline/cookbooks/trendwatching.md +156 -0
  30. package/plan.md +281 -0
  31. package/scripts/.gitkeep +0 -0
  32. package/src/ai-sdk/cache.ts +142 -0
  33. package/src/ai-sdk/examples/cached-generation.ts +53 -0
  34. package/src/ai-sdk/examples/duet-scene-4.ts +53 -0
  35. package/src/ai-sdk/examples/duet-scene-5-audio.ts +32 -0
  36. package/src/ai-sdk/examples/duet-video.ts +56 -0
  37. package/src/ai-sdk/examples/editly-composition.ts +63 -0
  38. package/src/ai-sdk/examples/editly-test.ts +57 -0
  39. package/src/ai-sdk/examples/editly-video-test.ts +52 -0
  40. package/src/ai-sdk/examples/fal-lipsync.ts +43 -0
  41. package/src/ai-sdk/examples/higgsfield-image.ts +61 -0
  42. package/src/ai-sdk/examples/music-generation.ts +19 -0
  43. package/src/ai-sdk/examples/openai-sora.ts +34 -0
  44. package/src/ai-sdk/examples/replicate-bg-removal.ts +52 -0
  45. package/src/ai-sdk/examples/simpsons-scene.ts +61 -0
  46. package/src/ai-sdk/examples/talking-lion.ts +55 -0
  47. package/src/ai-sdk/examples/video-generation.ts +39 -0
  48. package/src/ai-sdk/examples/workflow-animated-girl.ts +104 -0
  49. package/src/ai-sdk/examples/workflow-before-after.ts +114 -0
  50. package/src/ai-sdk/examples/workflow-character-grid.ts +112 -0
  51. package/src/ai-sdk/examples/workflow-slideshow.ts +161 -0
  52. package/src/ai-sdk/file-cache.ts +112 -0
  53. package/src/ai-sdk/file.ts +238 -0
  54. package/src/ai-sdk/generate-element.ts +92 -0
  55. package/src/ai-sdk/generate-music.ts +46 -0
  56. package/src/ai-sdk/generate-video.ts +165 -0
  57. package/src/ai-sdk/index.ts +72 -0
  58. package/src/ai-sdk/music-model.ts +110 -0
  59. package/src/ai-sdk/providers/editly/editly.test.ts +1108 -0
  60. package/src/ai-sdk/providers/editly/ffmpeg.ts +60 -0
  61. package/src/ai-sdk/providers/editly/index.ts +817 -0
  62. package/src/ai-sdk/providers/editly/layers.ts +776 -0
  63. package/src/ai-sdk/providers/editly/plan.md +144 -0
  64. package/src/ai-sdk/providers/editly/types.ts +328 -0
  65. package/src/ai-sdk/providers/elevenlabs-provider.ts +255 -0
  66. package/src/ai-sdk/providers/fal-provider.ts +512 -0
  67. package/src/ai-sdk/providers/higgsfield.ts +379 -0
  68. package/src/ai-sdk/providers/openai.ts +251 -0
  69. package/src/ai-sdk/providers/replicate.ts +16 -0
  70. package/src/ai-sdk/video-model.ts +185 -0
  71. package/src/cli/commands/find.tsx +137 -0
  72. package/src/cli/commands/help.tsx +85 -0
  73. package/src/cli/commands/index.ts +6 -0
  74. package/src/cli/commands/list.tsx +238 -0
  75. package/src/cli/commands/render.tsx +71 -0
  76. package/src/cli/commands/run.tsx +511 -0
  77. package/src/cli/commands/which.tsx +253 -0
  78. package/src/cli/index.ts +114 -0
  79. package/src/cli/quiet.ts +44 -0
  80. package/src/cli/types.ts +32 -0
  81. package/src/cli/ui/components/Badge.tsx +29 -0
  82. package/src/cli/ui/components/DataTable.tsx +51 -0
  83. package/src/cli/ui/components/Header.tsx +23 -0
  84. package/src/cli/ui/components/HelpBlock.tsx +44 -0
  85. package/src/cli/ui/components/KeyValue.tsx +33 -0
  86. package/src/cli/ui/components/OptionRow.tsx +81 -0
  87. package/src/cli/ui/components/Separator.tsx +23 -0
  88. package/src/cli/ui/components/StatusBox.tsx +108 -0
  89. package/src/cli/ui/components/VargBox.tsx +51 -0
  90. package/src/cli/ui/components/VargProgress.tsx +36 -0
  91. package/src/cli/ui/components/VargSpinner.tsx +34 -0
  92. package/src/cli/ui/components/VargText.tsx +56 -0
  93. package/src/cli/ui/components/index.ts +19 -0
  94. package/src/cli/ui/index.ts +12 -0
  95. package/src/cli/ui/render.ts +35 -0
  96. package/src/cli/ui/theme.ts +63 -0
  97. package/src/cli/utils.ts +78 -0
  98. package/src/core/executor/executor.ts +201 -0
  99. package/src/core/executor/index.ts +13 -0
  100. package/src/core/executor/job.ts +214 -0
  101. package/src/core/executor/pipeline.ts +222 -0
  102. package/src/core/index.ts +11 -0
  103. package/src/core/registry/index.ts +9 -0
  104. package/src/core/registry/loader.ts +149 -0
  105. package/src/core/registry/registry.ts +221 -0
  106. package/src/core/registry/resolver.ts +206 -0
  107. package/src/core/schema/helpers.ts +134 -0
  108. package/src/core/schema/index.ts +8 -0
  109. package/src/core/schema/shared.ts +102 -0
  110. package/src/core/schema/types.ts +279 -0
  111. package/src/core/schema/validator.ts +92 -0
  112. package/src/definitions/actions/captions.ts +261 -0
  113. package/src/definitions/actions/edit.ts +298 -0
  114. package/src/definitions/actions/image.ts +125 -0
  115. package/src/definitions/actions/index.ts +114 -0
  116. package/src/definitions/actions/music.ts +205 -0
  117. package/src/definitions/actions/sync.ts +128 -0
  118. package/{action/transcribe/index.ts → src/definitions/actions/transcribe.ts} +58 -68
  119. package/src/definitions/actions/upload.ts +111 -0
  120. package/src/definitions/actions/video.ts +163 -0
  121. package/src/definitions/actions/voice.ts +119 -0
  122. package/src/definitions/index.ts +23 -0
  123. package/src/definitions/models/elevenlabs.ts +50 -0
  124. package/src/definitions/models/flux.ts +56 -0
  125. package/src/definitions/models/index.ts +36 -0
  126. package/src/definitions/models/kling.ts +56 -0
  127. package/src/definitions/models/llama.ts +54 -0
  128. package/src/definitions/models/nano-banana-pro.ts +102 -0
  129. package/src/definitions/models/sonauto.ts +68 -0
  130. package/src/definitions/models/soul.ts +65 -0
  131. package/src/definitions/models/wan.ts +54 -0
  132. package/src/definitions/models/whisper.ts +44 -0
  133. package/src/definitions/skills/index.ts +12 -0
  134. package/src/definitions/skills/talking-character.ts +87 -0
  135. package/src/definitions/skills/text-to-tiktok.ts +97 -0
  136. package/src/index.ts +118 -0
  137. package/src/providers/apify.ts +269 -0
  138. package/src/providers/base.ts +264 -0
  139. package/src/providers/elevenlabs.ts +217 -0
  140. package/src/providers/fal.ts +392 -0
  141. package/src/providers/ffmpeg.ts +544 -0
  142. package/src/providers/fireworks.ts +193 -0
  143. package/src/providers/groq.ts +149 -0
  144. package/src/providers/higgsfield.ts +145 -0
  145. package/src/providers/index.ts +143 -0
  146. package/src/providers/replicate.ts +147 -0
  147. package/src/providers/storage.ts +206 -0
  148. package/src/react/cli.ts +52 -0
  149. package/src/react/elements.ts +146 -0
  150. package/src/react/examples/branching.tsx +66 -0
  151. package/src/react/examples/captions-demo.tsx +37 -0
  152. package/src/react/examples/character-video.tsx +84 -0
  153. package/src/react/examples/grid.tsx +53 -0
  154. package/src/react/examples/layouts-demo.tsx +57 -0
  155. package/src/react/examples/madi.tsx +60 -0
  156. package/src/react/examples/music-test.tsx +35 -0
  157. package/src/react/examples/onlyfans-1m/workflow.tsx +88 -0
  158. package/src/react/examples/orange-portrait.tsx +41 -0
  159. package/src/react/examples/split-element-demo.tsx +60 -0
  160. package/src/react/examples/split-layout-demo.tsx +60 -0
  161. package/src/react/examples/split.tsx +41 -0
  162. package/src/react/examples/video-grid.tsx +46 -0
  163. package/src/react/index.ts +43 -0
  164. package/src/react/layouts/grid.tsx +28 -0
  165. package/src/react/layouts/index.ts +2 -0
  166. package/src/react/layouts/split.tsx +20 -0
  167. package/src/react/react.test.ts +309 -0
  168. package/src/react/render.ts +21 -0
  169. package/src/react/renderers/animate.ts +59 -0
  170. package/src/react/renderers/captions.ts +297 -0
  171. package/src/react/renderers/clip.ts +248 -0
  172. package/src/react/renderers/context.ts +17 -0
  173. package/src/react/renderers/image.ts +109 -0
  174. package/src/react/renderers/index.ts +22 -0
  175. package/src/react/renderers/music.ts +60 -0
  176. package/src/react/renderers/packshot.ts +84 -0
  177. package/src/react/renderers/progress.ts +173 -0
  178. package/src/react/renderers/render.ts +243 -0
  179. package/src/react/renderers/slider.ts +69 -0
  180. package/src/react/renderers/speech.ts +53 -0
  181. package/src/react/renderers/split.ts +91 -0
  182. package/src/react/renderers/subtitle.ts +16 -0
  183. package/src/react/renderers/swipe.ts +75 -0
  184. package/src/react/renderers/title.ts +17 -0
  185. package/src/react/renderers/utils.ts +124 -0
  186. package/src/react/renderers/video.ts +127 -0
  187. package/src/react/runtime/jsx-dev-runtime.ts +43 -0
  188. package/src/react/runtime/jsx-runtime.ts +35 -0
  189. package/src/react/types.ts +232 -0
  190. package/src/studio/index.ts +26 -0
  191. package/src/studio/scanner.ts +102 -0
  192. package/src/studio/server.ts +554 -0
  193. package/src/studio/stages.ts +251 -0
  194. package/src/studio/step-renderer.ts +279 -0
  195. package/src/studio/types.ts +60 -0
  196. package/src/studio/ui/cache.html +303 -0
  197. package/src/studio/ui/index.html +1820 -0
  198. package/src/tests/all.test.ts +509 -0
  199. package/src/tests/index.ts +33 -0
  200. package/src/tests/unit.test.ts +403 -0
  201. package/tsconfig.cli.json +8 -0
  202. package/tsconfig.json +21 -3
  203. package/TEST_RESULTS.md +0 -122
  204. package/action/captions/SKILL.md +0 -170
  205. package/action/captions/index.ts +0 -169
  206. package/action/edit/SKILL.md +0 -235
  207. package/action/edit/index.ts +0 -437
  208. package/action/image/SKILL.md +0 -140
  209. package/action/image/index.ts +0 -105
  210. package/action/sync/SKILL.md +0 -136
  211. package/action/sync/index.ts +0 -145
  212. package/action/transcribe/SKILL.md +0 -179
  213. package/action/video/SKILL.md +0 -116
  214. package/action/video/index.ts +0 -125
  215. package/action/voice/SKILL.md +0 -125
  216. package/action/voice/index.ts +0 -136
  217. package/cli/commands/find.ts +0 -58
  218. package/cli/commands/help.ts +0 -70
  219. package/cli/commands/list.ts +0 -49
  220. package/cli/commands/run.ts +0 -237
  221. package/cli/commands/which.ts +0 -66
  222. package/cli/discover.ts +0 -66
  223. package/cli/index.ts +0 -33
  224. package/cli/runner.ts +0 -65
  225. package/cli/types.ts +0 -49
  226. package/cli/ui.ts +0 -185
  227. package/index.ts +0 -75
  228. package/lib/README.md +0 -144
  229. package/lib/ai-sdk/fal.ts +0 -106
  230. package/lib/ai-sdk/replicate.ts +0 -107
  231. package/lib/elevenlabs.ts +0 -382
  232. package/lib/fal.ts +0 -467
  233. package/lib/ffmpeg.ts +0 -467
  234. package/lib/fireworks.ts +0 -235
  235. package/lib/groq.ts +0 -246
  236. package/lib/higgsfield.ts +0 -176
  237. package/lib/remotion/SKILL.md +0 -823
  238. package/lib/remotion/cli.ts +0 -115
  239. package/lib/remotion/functions.ts +0 -283
  240. package/lib/remotion/index.ts +0 -19
  241. package/lib/remotion/templates.ts +0 -73
  242. package/lib/replicate.ts +0 -304
  243. package/output.txt +0 -1
  244. package/test-import.ts +0 -7
  245. package/test-services.ts +0 -97
  246. package/utilities/s3.ts +0 -147
@@ -0,0 +1,509 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * Comprehensive tests for all varg SDK actions and models
5
+ * Run with: bun run src/tests/all.test.ts
6
+ *
7
+ * Note: Most tests require API keys to be set in environment variables:
8
+ * - FAL_KEY
9
+ * - REPLICATE_API_TOKEN
10
+ * - ELEVENLABS_API_KEY
11
+ * - GROQ_API_KEY
12
+ * - FIREWORKS_API_KEY
13
+ * - HIGGSFIELD_API_KEY / HF_API_KEY
14
+ * - CLOUDFLARE_R2_API_URL, CLOUDFLARE_ACCESS_KEY_ID, CLOUDFLARE_ACCESS_SECRET
15
+ */
16
+
17
+ import { executor } from "../core/executor";
18
+ import { registry } from "../core/registry";
19
+ import { getCliSchemaInfo } from "../core/schema/helpers";
20
+ import { applyDefaults, validateInputs } from "../core/schema/validator";
21
+ import { allDefinitions } from "../definitions";
22
+ import { providers } from "../providers";
23
+
24
+ // Register all definitions
25
+ for (const definition of allDefinitions) {
26
+ registry.register(definition);
27
+ }
28
+
29
+ // Test results tracking
30
+ interface TestResult {
31
+ name: string;
32
+ passed: boolean;
33
+ error?: string;
34
+ duration: number;
35
+ skipped?: boolean;
36
+ }
37
+
38
+ const results: TestResult[] = [];
39
+
40
+ // Helper to run a test
41
+ async function test(
42
+ name: string,
43
+ fn: () => Promise<void>,
44
+ skip = false,
45
+ ): Promise<void> {
46
+ if (skip) {
47
+ results.push({ name, passed: true, duration: 0, skipped: true });
48
+ console.log(`ā­ļø SKIP: ${name}`);
49
+ return;
50
+ }
51
+
52
+ const start = Date.now();
53
+ try {
54
+ await fn();
55
+ const duration = Date.now() - start;
56
+ results.push({ name, passed: true, duration });
57
+ console.log(`āœ… PASS: ${name} (${duration}ms)`);
58
+ } catch (error) {
59
+ const duration = Date.now() - start;
60
+ const errorMsg = error instanceof Error ? error.message : String(error);
61
+ results.push({ name, passed: false, error: errorMsg, duration });
62
+ console.log(`āŒ FAIL: ${name} (${duration}ms)`);
63
+ console.log(` Error: ${errorMsg}`);
64
+ }
65
+ }
66
+
67
+ // Check if an API key is available
68
+ function hasApiKey(envVar: string | string[]): boolean {
69
+ const vars = Array.isArray(envVar) ? envVar : [envVar];
70
+ return vars.some((v) => !!process.env[v]);
71
+ }
72
+
73
+ // ============================================================================
74
+ // Registry Tests
75
+ // ============================================================================
76
+
77
+ console.log("\nšŸ“‹ REGISTRY TESTS\n");
78
+
79
+ await test("registry has models registered", async () => {
80
+ const models = registry.list("model");
81
+ if (models.length === 0) throw new Error("No models registered");
82
+ console.log(` Found ${models.length} models`);
83
+ });
84
+
85
+ await test("registry has actions registered", async () => {
86
+ const actions = registry.list("action");
87
+ if (actions.length === 0) throw new Error("No actions registered");
88
+ console.log(` Found ${actions.length} actions`);
89
+ });
90
+
91
+ await test("registry has skills registered", async () => {
92
+ const skills = registry.list("skill");
93
+ if (skills.length === 0) throw new Error("No skills registered");
94
+ console.log(` Found ${skills.length} skills`);
95
+ });
96
+
97
+ await test("registry has providers registered", async () => {
98
+ const providerList = providers.all();
99
+ if (providerList.length === 0) throw new Error("No providers registered");
100
+ console.log(` Found ${providerList.length} providers`);
101
+ });
102
+
103
+ await test("registry resolves 'video' action", async () => {
104
+ const video = registry.resolve("video");
105
+ if (!video) throw new Error("Could not resolve 'video'");
106
+ if (video.type !== "action") throw new Error("Expected action type");
107
+ });
108
+
109
+ await test("registry resolves 'kling' model", async () => {
110
+ const kling = registry.resolve("kling");
111
+ if (!kling) throw new Error("Could not resolve 'kling'");
112
+ if (kling.type !== "model") throw new Error("Expected model type");
113
+ });
114
+
115
+ await test("registry resolves 'talking-character' skill", async () => {
116
+ const skill = registry.resolve("talking-character");
117
+ if (!skill) throw new Error("Could not resolve 'talking-character'");
118
+ if (skill.type !== "skill") throw new Error("Expected skill type");
119
+ });
120
+
121
+ await test("registry search works", async () => {
122
+ const searchResults = registry.search("video");
123
+ if (searchResults.length === 0) throw new Error("No search results");
124
+ console.log(` Found ${searchResults.length} results for 'video'`);
125
+ });
126
+
127
+ // ============================================================================
128
+ // Provider Tests
129
+ // ============================================================================
130
+
131
+ console.log("\nšŸ”Œ PROVIDER TESTS\n");
132
+
133
+ await test("fal provider is registered", async () => {
134
+ const fal = providers.get("fal");
135
+ if (!fal) throw new Error("Fal provider not found");
136
+ });
137
+
138
+ await test("replicate provider is registered", async () => {
139
+ const replicate = providers.get("replicate");
140
+ if (!replicate) throw new Error("Replicate provider not found");
141
+ });
142
+
143
+ await test("elevenlabs provider is registered", async () => {
144
+ const el = providers.get("elevenlabs");
145
+ if (!el) throw new Error("ElevenLabs provider not found");
146
+ });
147
+
148
+ await test("groq provider is registered", async () => {
149
+ const groq = providers.get("groq");
150
+ if (!groq) throw new Error("Groq provider not found");
151
+ });
152
+
153
+ await test("ffmpeg provider is registered", async () => {
154
+ const ffmpeg = providers.get("ffmpeg");
155
+ if (!ffmpeg) throw new Error("FFmpeg provider not found");
156
+ });
157
+
158
+ await test("storage provider is registered", async () => {
159
+ const storage = providers.get("storage");
160
+ if (!storage) throw new Error("Storage provider not found");
161
+ });
162
+
163
+ // ============================================================================
164
+ // Schema Validation Tests
165
+ // ============================================================================
166
+
167
+ console.log("\nšŸ“ SCHEMA VALIDATION TESTS\n");
168
+
169
+ await test("validator accepts valid inputs", async () => {
170
+ const def = registry.resolve("video");
171
+ if (!def) throw new Error("No definition");
172
+
173
+ // Use the input schema directly
174
+ const result = validateInputs({ prompt: "test video" }, def.schema.input);
175
+ if (!result.valid)
176
+ throw new Error(
177
+ `Validation failed: ${result.errors.map((e) => e.message).join(", ")}`,
178
+ );
179
+ });
180
+
181
+ await test("validator rejects missing required fields", async () => {
182
+ const def = registry.resolve("video");
183
+ if (!def) throw new Error("No definition");
184
+
185
+ const result = validateInputs({}, def.schema.input);
186
+ if (result.valid) throw new Error("Should have failed validation");
187
+ if (!result.errors.some((e) => e.path === "prompt")) {
188
+ throw new Error("Should report missing 'prompt' field");
189
+ }
190
+ });
191
+
192
+ await test("validator applies defaults", async () => {
193
+ const def = registry.resolve("video");
194
+ if (!def) throw new Error("No definition");
195
+
196
+ const inputs = applyDefaults({ prompt: "test" }, def.schema.input);
197
+ // Check that duration and aspectRatio have defaults applied
198
+ const { properties } = getCliSchemaInfo(def.schema.input);
199
+ if (properties.duration?.default !== undefined) {
200
+ console.log(` Defaults applied: duration=${inputs.duration}`);
201
+ }
202
+ });
203
+
204
+ // ============================================================================
205
+ // Model Definition Tests
206
+ // ============================================================================
207
+
208
+ console.log("\nšŸ¤– MODEL DEFINITION TESTS\n");
209
+
210
+ const modelNames = [
211
+ "kling",
212
+ "flux",
213
+ "wan",
214
+ "whisper",
215
+ "elevenlabs-tts",
216
+ "soul",
217
+ "sonauto",
218
+ "llama",
219
+ ];
220
+
221
+ for (const name of modelNames) {
222
+ await test(`model '${name}' is properly defined`, async () => {
223
+ const model = registry.getModel(name);
224
+ if (!model) throw new Error(`Model '${name}' not found`);
225
+ if (!model.providers || model.providers.length === 0) {
226
+ throw new Error("Model has no providers");
227
+ }
228
+ if (!model.defaultProvider) {
229
+ throw new Error("Model has no default provider");
230
+ }
231
+ if (!model.schema) {
232
+ throw new Error("Model has no schema");
233
+ }
234
+ console.log(
235
+ ` Providers: ${model.providers.join(", ")}, default: ${model.defaultProvider}`,
236
+ );
237
+ });
238
+ }
239
+
240
+ // ============================================================================
241
+ // Action Definition Tests
242
+ // ============================================================================
243
+
244
+ console.log("\n⚔ ACTION DEFINITION TESTS\n");
245
+
246
+ const actionNames = [
247
+ "video",
248
+ "image",
249
+ "voice",
250
+ "transcribe",
251
+ "music",
252
+ "sync",
253
+ "captions",
254
+ "trim",
255
+ "cut",
256
+ "merge",
257
+ "split",
258
+ "fade",
259
+ "transition",
260
+ "remove",
261
+ ];
262
+
263
+ for (const name of actionNames) {
264
+ await test(`action '${name}' is properly defined`, async () => {
265
+ const action = registry.getAction(name);
266
+ if (!action) throw new Error(`Action '${name}' not found`);
267
+ if (!action.schema) {
268
+ throw new Error("Action has no schema");
269
+ }
270
+ if (!action.routes && !action.execute) {
271
+ throw new Error("Action has no routes or execute function");
272
+ }
273
+ const hasRoutes = action.routes && action.routes.length > 0;
274
+ const hasExecute = !!action.execute;
275
+ console.log(` Routes: ${hasRoutes}, Execute: ${hasExecute}`);
276
+ });
277
+ }
278
+
279
+ // ============================================================================
280
+ // Skill Definition Tests
281
+ // ============================================================================
282
+
283
+ console.log("\nšŸŽÆ SKILL DEFINITION TESTS\n");
284
+
285
+ const skillNames = ["talking-character", "text-to-tiktok"];
286
+
287
+ for (const name of skillNames) {
288
+ await test(`skill '${name}' is properly defined`, async () => {
289
+ const skill = registry.getSkill(name);
290
+ if (!skill) throw new Error(`Skill '${name}' not found`);
291
+ if (!skill.steps || skill.steps.length === 0) {
292
+ throw new Error("Skill has no steps");
293
+ }
294
+ console.log(` Steps: ${skill.steps.length}`);
295
+ for (const step of skill.steps) {
296
+ console.log(` - ${step.name} → ${step.run}`);
297
+ }
298
+ });
299
+ }
300
+
301
+ // ============================================================================
302
+ // Live API Tests (require API keys)
303
+ // ============================================================================
304
+
305
+ console.log("\n🌐 LIVE API TESTS (requires API keys)\n");
306
+
307
+ // Fal.ai tests
308
+ await test(
309
+ "fal: generate image with flux",
310
+ async () => {
311
+ const { falProvider } = await import("../providers/fal");
312
+ const result = await falProvider.generateImage({
313
+ prompt: "a cute cat sitting on a rainbow",
314
+ imageSize: "square",
315
+ });
316
+ if (!result?.data?.images?.[0]?.url) {
317
+ throw new Error("No image URL in result");
318
+ }
319
+ console.log(` Generated: ${result.data.images[0].url}`);
320
+ },
321
+ !hasApiKey("FAL_KEY"),
322
+ );
323
+
324
+ await test(
325
+ "fal: text-to-video with kling",
326
+ async () => {
327
+ const { falProvider } = await import("../providers/fal");
328
+ const result = await falProvider.textToVideo({
329
+ prompt: "ocean waves crashing on beach",
330
+ duration: 5,
331
+ });
332
+ if (!result?.data?.video?.url) {
333
+ throw new Error("No video URL in result");
334
+ }
335
+ console.log(` Generated: ${result.data.video.url}`);
336
+ },
337
+ !hasApiKey("FAL_KEY"),
338
+ );
339
+
340
+ // Replicate tests
341
+ await test(
342
+ "replicate: run flux image generation",
343
+ async () => {
344
+ const { replicateProvider, MODELS } = await import(
345
+ "../providers/replicate"
346
+ );
347
+ const result = await replicateProvider.runImage({
348
+ model: MODELS.IMAGE.FLUX_SCHNELL,
349
+ input: { prompt: "a mountain landscape at sunset" },
350
+ });
351
+ console.log(` Generated: ${JSON.stringify(result).slice(0, 100)}...`);
352
+ },
353
+ !hasApiKey("REPLICATE_API_TOKEN"),
354
+ );
355
+
356
+ // ElevenLabs tests
357
+ await test(
358
+ "elevenlabs: text-to-speech",
359
+ async () => {
360
+ const { elevenlabsProvider } = await import("../providers/elevenlabs");
361
+ const buffer = await elevenlabsProvider.textToSpeech({
362
+ text: "Hello, this is a test of the varg SDK.",
363
+ });
364
+ if (buffer.length === 0) {
365
+ throw new Error("Empty audio buffer");
366
+ }
367
+ console.log(` Generated: ${buffer.length} bytes of audio`);
368
+ },
369
+ !hasApiKey("ELEVENLABS_API_KEY"),
370
+ );
371
+
372
+ await test(
373
+ "elevenlabs: list voices",
374
+ async () => {
375
+ const { elevenlabsProvider } = await import("../providers/elevenlabs");
376
+ const voices = await elevenlabsProvider.listVoices();
377
+ if (voices.length === 0) {
378
+ throw new Error("No voices found");
379
+ }
380
+ console.log(` Found ${voices.length} voices`);
381
+ },
382
+ !hasApiKey("ELEVENLABS_API_KEY"),
383
+ );
384
+
385
+ // Groq tests
386
+ await test(
387
+ "groq: chat completion",
388
+ async () => {
389
+ const { groqProvider } = await import("../providers/groq");
390
+ const result = await groqProvider.chatCompletion({
391
+ messages: [{ role: "user", content: "Say hello in one word" }],
392
+ maxTokens: 10,
393
+ });
394
+ if (!result) {
395
+ throw new Error("No response");
396
+ }
397
+ console.log(` Response: ${result}`);
398
+ },
399
+ !hasApiKey("GROQ_API_KEY"),
400
+ );
401
+
402
+ await test(
403
+ "groq: list models",
404
+ async () => {
405
+ const { groqProvider } = await import("../providers/groq");
406
+ const models = await groqProvider.listModels();
407
+ if (models.length === 0) {
408
+ throw new Error("No models found");
409
+ }
410
+ console.log(` Found ${models.length} models`);
411
+ },
412
+ !hasApiKey("GROQ_API_KEY"),
413
+ );
414
+
415
+ // Higgsfield tests
416
+ await test(
417
+ "higgsfield: list soul styles",
418
+ async () => {
419
+ const { higgsfieldProvider } = await import("../providers/higgsfield");
420
+ const styles = await higgsfieldProvider.listSoulStyles();
421
+ console.log(` Found styles: ${JSON.stringify(styles).slice(0, 100)}...`);
422
+ },
423
+ !hasApiKey(["HIGGSFIELD_API_KEY", "HF_API_KEY"]),
424
+ );
425
+
426
+ // FFmpeg tests (local, no API needed)
427
+ await test("ffmpeg: probe video info", async () => {
428
+ const { ffmpegProvider } = await import("../providers/ffmpeg");
429
+ // This test requires a local video file - skip if not available
430
+ const testVideo = "./media/test.mp4";
431
+ const file = Bun.file(testVideo);
432
+ if (!(await file.exists())) {
433
+ console.log(` Skipped: No test video at ${testVideo}`);
434
+ return;
435
+ }
436
+ const info = await ffmpegProvider.probe(testVideo);
437
+ console.log(` Video: ${info.width}x${info.height}, ${info.duration}s`);
438
+ });
439
+
440
+ // ============================================================================
441
+ // Executor Tests
442
+ // ============================================================================
443
+
444
+ console.log("\nšŸš€ EXECUTOR TESTS\n");
445
+
446
+ await test(
447
+ "executor: run image action",
448
+ async () => {
449
+ const result = await executor.run("image", {
450
+ prompt: "a beautiful sunset over mountains",
451
+ size: "landscape_4_3",
452
+ });
453
+ if (!result.output) {
454
+ throw new Error("No output");
455
+ }
456
+ console.log(` Output: ${JSON.stringify(result.output).slice(0, 100)}...`);
457
+ },
458
+ !hasApiKey("FAL_KEY"),
459
+ );
460
+
461
+ await test(
462
+ "executor: run voice action",
463
+ async () => {
464
+ const result = await executor.run("voice", {
465
+ text: "Hello from the varg SDK executor test.",
466
+ });
467
+ if (!result.output) {
468
+ throw new Error("No output");
469
+ }
470
+ console.log(` Duration: ${result.duration}ms`);
471
+ },
472
+ !hasApiKey("ELEVENLABS_API_KEY"),
473
+ );
474
+
475
+ // ============================================================================
476
+ // Summary
477
+ // ============================================================================
478
+
479
+ console.log(`\n${"=".repeat(60)}`);
480
+ console.log("TEST SUMMARY");
481
+ console.log(`${"=".repeat(60)}\n`);
482
+
483
+ const passed = results.filter((r) => r.passed && !r.skipped).length;
484
+ const failed = results.filter((r) => !r.passed).length;
485
+ const skipped = results.filter((r) => r.skipped).length;
486
+ const total = results.length;
487
+
488
+ console.log(`Total: ${total}`);
489
+ console.log(`Passed: ${passed} āœ…`);
490
+ console.log(`Failed: ${failed} āŒ`);
491
+ console.log(`Skipped: ${skipped} ā­ļø`);
492
+ console.log("");
493
+
494
+ if (failed > 0) {
495
+ console.log("Failed tests:");
496
+ for (const r of results.filter((r) => !r.passed)) {
497
+ console.log(` - ${r.name}: ${r.error}`);
498
+ }
499
+ console.log("");
500
+ }
501
+
502
+ const totalDuration = results.reduce((sum, r) => sum + r.duration, 0);
503
+ console.log(`Total time: ${totalDuration}ms`);
504
+ console.log("");
505
+
506
+ // Exit with error code if any tests failed
507
+ if (failed > 0) {
508
+ process.exit(1);
509
+ }
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Test runner index
4
+ *
5
+ * Usage:
6
+ * bun run src/tests/unit.test.ts - Run unit tests (no API needed)
7
+ * bun run src/tests/all.test.ts - Run all tests (requires API keys)
8
+ */
9
+
10
+ console.log(`
11
+ varg SDK Tests
12
+ ==============
13
+
14
+ Available test files:
15
+
16
+ bun run src/tests/unit.test.ts
17
+ Unit tests that don't require API keys.
18
+ Tests registry, resolver, validation, and definition structure.
19
+
20
+ bun run src/tests/all.test.ts
21
+ Comprehensive tests including live API calls.
22
+ Requires API keys set in environment variables:
23
+ - FAL_KEY
24
+ - REPLICATE_API_TOKEN
25
+ - ELEVENLABS_API_KEY
26
+ - GROQ_API_KEY
27
+ - FIREWORKS_API_KEY
28
+ - HIGGSFIELD_API_KEY / HF_API_KEY
29
+
30
+ Run specific test file with:
31
+ bun run <test-file>
32
+
33
+ `);