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,149 @@
1
+ /**
2
+ * Definition Loader
3
+ * Auto-loads definitions from the definitions/ directory
4
+ */
5
+
6
+ import { readdir } from "node:fs/promises";
7
+ import { join } from "node:path";
8
+ import type { Definition } from "../schema/types";
9
+ import { registry } from "./registry";
10
+
11
+ const DEFINITIONS_DIR = join(import.meta.dir, "..", "..", "definitions");
12
+
13
+ export interface LoaderOptions {
14
+ /** Additional paths to scan for definitions */
15
+ additionalPaths?: string[];
16
+ /** If true, log loading progress */
17
+ verbose?: boolean;
18
+ }
19
+
20
+ /**
21
+ * Load all definitions from the definitions directory
22
+ */
23
+ export async function loadDefinitions(options?: LoaderOptions): Promise<void> {
24
+ const { verbose = false } = options ?? {};
25
+
26
+ // Load built-in definitions
27
+ await loadFromDirectory(join(DEFINITIONS_DIR, "models"), verbose);
28
+ await loadFromDirectory(join(DEFINITIONS_DIR, "actions"), verbose);
29
+ await loadFromDirectory(join(DEFINITIONS_DIR, "skills"), verbose);
30
+
31
+ // Load from additional paths
32
+ if (options?.additionalPaths) {
33
+ for (const path of options.additionalPaths) {
34
+ await loadFromDirectory(path, verbose);
35
+ }
36
+ }
37
+
38
+ if (verbose) {
39
+ console.log(`[loader] loaded: ${JSON.stringify(registry.stats)}`);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Load definitions from a directory
45
+ */
46
+ async function loadFromDirectory(
47
+ dirPath: string,
48
+ verbose: boolean,
49
+ ): Promise<void> {
50
+ try {
51
+ const entries = await readdir(dirPath, { withFileTypes: true });
52
+
53
+ for (const entry of entries) {
54
+ // Skip non-TypeScript files
55
+ if (!entry.isFile() || !entry.name.endsWith(".ts")) {
56
+ continue;
57
+ }
58
+
59
+ // Skip index files
60
+ if (entry.name === "index.ts") {
61
+ continue;
62
+ }
63
+
64
+ try {
65
+ const modulePath = join(dirPath, entry.name);
66
+ const mod = await import(modulePath);
67
+
68
+ // Check for definition export (named 'definition' or default)
69
+ const definition: Definition | undefined =
70
+ mod.definition ?? mod.default;
71
+
72
+ if (definition && isValidDefinition(definition)) {
73
+ registry.register(definition);
74
+ if (verbose) {
75
+ console.log(
76
+ `[loader] loaded: ${definition.name} (${definition.type})`,
77
+ );
78
+ }
79
+ }
80
+
81
+ // Also check for meta export (backward compatibility with action format)
82
+ if (mod.meta && isValidDefinition(mod.meta)) {
83
+ registry.register(mod.meta);
84
+ if (verbose) {
85
+ console.log(`[loader] loaded: ${mod.meta.name} (${mod.meta.type})`);
86
+ }
87
+ }
88
+ } catch (error) {
89
+ if (verbose) {
90
+ console.warn(
91
+ `[loader] failed to load ${entry.name}:`,
92
+ error instanceof Error ? error.message : error,
93
+ );
94
+ }
95
+ }
96
+ }
97
+ } catch (error) {
98
+ // Directory doesn't exist - that's okay
99
+ if (verbose && (error as NodeJS.ErrnoException).code !== "ENOENT") {
100
+ console.warn(`[loader] error reading ${dirPath}:`, error);
101
+ }
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Check if an object is a valid definition
107
+ */
108
+ function isValidDefinition(obj: unknown): obj is Definition {
109
+ if (!obj || typeof obj !== "object") return false;
110
+
111
+ const def = obj as Record<string, unknown>;
112
+
113
+ return (
114
+ typeof def.type === "string" &&
115
+ ["model", "action", "skill"].includes(def.type) &&
116
+ typeof def.name === "string" &&
117
+ typeof def.description === "string" &&
118
+ typeof def.schema === "object"
119
+ );
120
+ }
121
+
122
+ /**
123
+ * Load user skills from ~/.varg/skills/
124
+ */
125
+ export async function loadUserSkills(verbose = false): Promise<void> {
126
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "";
127
+ const userSkillsDir = join(homeDir, ".varg", "skills");
128
+
129
+ await loadFromDirectory(userSkillsDir, verbose);
130
+ }
131
+
132
+ /**
133
+ * Reload all definitions (useful for hot-reloading)
134
+ */
135
+ export async function reloadDefinitions(
136
+ options?: LoaderOptions,
137
+ ): Promise<void> {
138
+ // Clear existing definitions (but keep providers)
139
+ const stats = registry.stats;
140
+
141
+ if (options?.verbose) {
142
+ console.log(
143
+ `[loader] clearing ${stats.models + stats.actions + stats.skills} definitions...`,
144
+ );
145
+ }
146
+
147
+ // Re-load everything
148
+ await loadDefinitions(options);
149
+ }
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Central Registry
3
+ * The brain that knows about all models, actions, skills, and providers
4
+ */
5
+
6
+ import { getCliSchemaInfo, toJsonSchema } from "../schema/helpers";
7
+ import type {
8
+ ActionDefinition,
9
+ Definition,
10
+ ModelDefinition,
11
+ Provider,
12
+ SearchOptions,
13
+ SkillDefinition,
14
+ } from "../schema/types";
15
+
16
+ export class Registry {
17
+ private models = new Map<string, ModelDefinition>();
18
+ private actions = new Map<string, ActionDefinition>();
19
+ private skills = new Map<string, SkillDefinition>();
20
+ private providers = new Map<string, Provider>();
21
+
22
+ // ============================================================================
23
+ // Registration
24
+ // ============================================================================
25
+
26
+ /**
27
+ * Register a definition (model, action, or skill)
28
+ */
29
+ register(definition: Definition): void {
30
+ switch (definition.type) {
31
+ case "model":
32
+ this.models.set(definition.name, definition);
33
+ break;
34
+ case "action":
35
+ this.actions.set(definition.name, definition);
36
+ break;
37
+ case "skill":
38
+ this.skills.set(definition.name, definition);
39
+ break;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Register a provider
45
+ */
46
+ registerProvider(provider: Provider): void {
47
+ this.providers.set(provider.name, provider);
48
+ }
49
+
50
+ /**
51
+ * Unregister a definition by name
52
+ */
53
+ unregister(name: string): boolean {
54
+ return (
55
+ this.models.delete(name) ||
56
+ this.actions.delete(name) ||
57
+ this.skills.delete(name)
58
+ );
59
+ }
60
+
61
+ // ============================================================================
62
+ // Resolution
63
+ // ============================================================================
64
+
65
+ /**
66
+ * Resolve a name to its definition
67
+ * Resolution order: models -> actions -> skills
68
+ */
69
+
70
+ resolve(name: string): Definition | null {
71
+ // Handle explicit namespace prefixes
72
+ if (name.startsWith("model/")) {
73
+ return this.models.get(name.slice(6)) ?? null;
74
+ }
75
+ if (name.startsWith("action/")) {
76
+ return this.actions.get(name.slice(7)) ?? null;
77
+ }
78
+ if (name.startsWith("skill/")) {
79
+ return this.skills.get(name.slice(6)) ?? null;
80
+ }
81
+
82
+ // Try each type in order
83
+ return (
84
+ this.models.get(name) ??
85
+ this.actions.get(name) ??
86
+ this.skills.get(name) ??
87
+ null
88
+ );
89
+ }
90
+
91
+ /**
92
+ * Get a provider by name
93
+ */
94
+ getProvider(name: string): Provider | undefined {
95
+ return this.providers.get(name);
96
+ }
97
+
98
+ /**
99
+ * Check if a name exists
100
+ */
101
+ has(name: string): boolean {
102
+ return this.resolve(name) !== null;
103
+ }
104
+
105
+ // ============================================================================
106
+ // Search
107
+ // ============================================================================
108
+
109
+ /**
110
+ * Search definitions by query string
111
+ */
112
+ search(query: string, options?: SearchOptions): Definition[] {
113
+ const q = query.toLowerCase();
114
+ const results: Definition[] = [];
115
+
116
+ // Get all definitions based on type filter
117
+ const definitions = this.list(options?.type);
118
+
119
+ for (const def of definitions) {
120
+ // Match by name or description
121
+ if (
122
+ def.name.toLowerCase().includes(q) ||
123
+ def.description.toLowerCase().includes(q)
124
+ ) {
125
+ results.push(def);
126
+ continue;
127
+ }
128
+
129
+ // Match by input/output type (from schema)
130
+ const inputSchema = getCliSchemaInfo(def.schema.input);
131
+ const outputSchema = toJsonSchema(def.schema.output);
132
+ const inputType = inputSchema.properties?.type?.type ?? "";
133
+ const outputType = outputSchema.type ?? "";
134
+
135
+ if (
136
+ options?.inputType &&
137
+ inputType.toLowerCase().includes(options.inputType.toLowerCase())
138
+ ) {
139
+ results.push(def);
140
+ continue;
141
+ }
142
+
143
+ if (
144
+ options?.outputType &&
145
+ outputType.toLowerCase().includes(options.outputType.toLowerCase())
146
+ ) {
147
+ results.push(def);
148
+ continue;
149
+ }
150
+
151
+ // Match by provider (for models)
152
+ if (
153
+ options?.provider &&
154
+ def.type === "model" &&
155
+ (def as ModelDefinition).providers.includes(options.provider)
156
+ ) {
157
+ results.push(def);
158
+ }
159
+ }
160
+
161
+ return results;
162
+ }
163
+
164
+ /**
165
+ * List all definitions, optionally filtered by type
166
+ */
167
+ list(type?: "model" | "action" | "skill"): Definition[] {
168
+ const results: Definition[] = [];
169
+
170
+ if (!type || type === "model") {
171
+ results.push(...this.models.values());
172
+ }
173
+ if (!type || type === "action") {
174
+ results.push(...this.actions.values());
175
+ }
176
+ if (!type || type === "skill") {
177
+ results.push(...this.skills.values());
178
+ }
179
+
180
+ return results;
181
+ }
182
+
183
+ /**
184
+ * List all providers
185
+ */
186
+ listProviders(): Provider[] {
187
+ return Array.from(this.providers.values());
188
+ }
189
+
190
+ // ============================================================================
191
+ // Getters
192
+ // ============================================================================
193
+
194
+ getModel(name: string): ModelDefinition | undefined {
195
+ return this.models.get(name);
196
+ }
197
+
198
+ getAction(name: string): ActionDefinition | undefined {
199
+ return this.actions.get(name);
200
+ }
201
+
202
+ getSkill(name: string): SkillDefinition | undefined {
203
+ return this.skills.get(name);
204
+ }
205
+
206
+ // ============================================================================
207
+ // Stats
208
+ // ============================================================================
209
+
210
+ get stats() {
211
+ return {
212
+ models: this.models.size,
213
+ actions: this.actions.size,
214
+ skills: this.skills.size,
215
+ providers: this.providers.size,
216
+ };
217
+ }
218
+ }
219
+
220
+ // Global registry instance
221
+ export const registry = new Registry();
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Name Resolution Logic
3
+ * Handles smart resolution of names to definitions with fuzzy matching
4
+ */
5
+
6
+ import type { Definition, SearchOptions } from "../schema/types";
7
+ import { registry } from "./registry";
8
+
9
+ export interface ResolveOptions {
10
+ /** If true, throw an error if not found */
11
+ required?: boolean;
12
+ /** Preferred type to resolve to */
13
+ preferType?: "model" | "action" | "skill";
14
+ /** If true, allow fuzzy matching */
15
+ fuzzy?: boolean;
16
+ }
17
+
18
+ export interface ResolveResult {
19
+ definition: Definition | null;
20
+ matchType: "exact" | "namespace" | "fuzzy" | "alias" | null;
21
+ suggestions?: string[];
22
+ }
23
+
24
+ // Common aliases for actions/models
25
+ const ALIASES: Record<string, string> = {
26
+ // Video generation
27
+ i2v: "image-to-video",
28
+ t2v: "text-to-video",
29
+ img2vid: "image-to-video",
30
+ txt2vid: "text-to-video",
31
+
32
+ // Image generation
33
+ i2i: "image-to-image",
34
+ t2i: "text-to-image",
35
+ img2img: "image-to-image",
36
+ txt2img: "text-to-image",
37
+
38
+ // Voice/Audio
39
+ tts: "text-to-speech",
40
+ stt: "speech-to-text",
41
+ voice: "text-to-speech",
42
+
43
+ // Video editing
44
+ concat: "merge",
45
+ join: "merge",
46
+ combine: "merge",
47
+ crop: "trim",
48
+ clip: "trim",
49
+ };
50
+
51
+ /**
52
+ * Resolve a name to a definition with smart matching
53
+ */
54
+ export function resolve(name: string, options?: ResolveOptions): ResolveResult {
55
+ // 1. Check direct/exact match
56
+ const exact = registry.resolve(name);
57
+ if (exact) {
58
+ return { definition: exact, matchType: "exact" };
59
+ }
60
+
61
+ // 2. Check aliases
62
+ const aliasTarget = ALIASES[name.toLowerCase()];
63
+ if (aliasTarget) {
64
+ const aliased = registry.resolve(aliasTarget);
65
+ if (aliased) {
66
+ return { definition: aliased, matchType: "alias" };
67
+ }
68
+ }
69
+
70
+ // 3. Try with namespace prefix if preferType is set
71
+ if (options?.preferType) {
72
+ const namespaced = registry.resolve(`${options.preferType}/${name}`);
73
+ if (namespaced) {
74
+ return { definition: namespaced, matchType: "namespace" };
75
+ }
76
+ }
77
+
78
+ // 4. Fuzzy matching if enabled
79
+ if (options?.fuzzy) {
80
+ const suggestions = findSimilar(name);
81
+ const firstSuggestion = suggestions[0];
82
+ if (firstSuggestion) {
83
+ const topMatch = registry.resolve(firstSuggestion);
84
+ if (topMatch) {
85
+ return {
86
+ definition: topMatch,
87
+ matchType: "fuzzy",
88
+ suggestions,
89
+ };
90
+ }
91
+ }
92
+ }
93
+
94
+ // 5. Not found
95
+ if (options?.required) {
96
+ const suggestions = findSimilar(name);
97
+ const suggestionText =
98
+ suggestions.length > 0
99
+ ? ` Did you mean: ${suggestions.slice(0, 3).join(", ")}?`
100
+ : "";
101
+ throw new Error(`Definition not found: "${name}".${suggestionText}`);
102
+ }
103
+
104
+ return {
105
+ definition: null,
106
+ matchType: null,
107
+ suggestions: findSimilar(name),
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Find similar names using Levenshtein distance
113
+ */
114
+ export function findSimilar(query: string, limit = 5): string[] {
115
+ const q = query.toLowerCase();
116
+ const all = registry.list();
117
+
118
+ const scored = all.map((def) => ({
119
+ name: def.name,
120
+ score: similarity(q, def.name.toLowerCase()),
121
+ }));
122
+
123
+ // Sort by similarity score (higher is better)
124
+ scored.sort((a, b) => b.score - a.score);
125
+
126
+ // Return top matches with reasonable similarity
127
+ return scored
128
+ .filter((s) => s.score > 0.3)
129
+ .slice(0, limit)
130
+ .map((s) => s.name);
131
+ }
132
+
133
+ /**
134
+ * Simple similarity score based on common substrings and Levenshtein
135
+ */
136
+ function similarity(a: string, b: string): number {
137
+ // Exact match
138
+ if (a === b) return 1;
139
+
140
+ // Prefix match
141
+ if (b.startsWith(a) || a.startsWith(b)) return 0.9;
142
+
143
+ // Contains match
144
+ if (b.includes(a) || a.includes(b)) return 0.7;
145
+
146
+ // Levenshtein-based similarity
147
+ const distance = levenshteinDistance(a, b);
148
+ const maxLen = Math.max(a.length, b.length);
149
+ return 1 - distance / maxLen;
150
+ }
151
+
152
+ /**
153
+ * Calculate Levenshtein edit distance
154
+ */
155
+ function levenshteinDistance(a: string, b: string): number {
156
+ if (a.length === 0) return b.length;
157
+ if (b.length === 0) return a.length;
158
+
159
+ // Create matrix with proper initialization
160
+ const matrix: number[][] = Array.from({ length: b.length + 1 }, (_, i) =>
161
+ Array.from({ length: a.length + 1 }, (_, j) =>
162
+ i === 0 ? j : j === 0 ? i : 0,
163
+ ),
164
+ );
165
+
166
+ // Fill matrix
167
+ for (let i = 1; i <= b.length; i++) {
168
+ for (let j = 1; j <= a.length; j++) {
169
+ const prevRow = matrix[i - 1];
170
+ const currRow = matrix[i];
171
+ if (!prevRow || !currRow) continue;
172
+
173
+ if (b[i - 1] === a[j - 1]) {
174
+ currRow[j] = prevRow[j - 1] ?? 0;
175
+ } else {
176
+ currRow[j] = Math.min(
177
+ (prevRow[j - 1] ?? 0) + 1, // substitution
178
+ (currRow[j - 1] ?? 0) + 1, // insertion
179
+ (prevRow[j] ?? 0) + 1, // deletion
180
+ );
181
+ }
182
+ }
183
+ }
184
+
185
+ return matrix[b.length]?.[a.length] ?? Math.max(a.length, b.length);
186
+ }
187
+
188
+ /**
189
+ * Search with filters
190
+ */
191
+ export function search(query: string, options?: SearchOptions): Definition[] {
192
+ return registry.search(query, options);
193
+ }
194
+
195
+ /**
196
+ * Get suggestions for partial input (autocomplete)
197
+ */
198
+ export function suggest(partial: string, limit = 10): string[] {
199
+ const p = partial.toLowerCase();
200
+ const all = registry.list();
201
+
202
+ return all
203
+ .filter((def) => def.name.toLowerCase().startsWith(p))
204
+ .slice(0, limit)
205
+ .map((def) => def.name);
206
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Schema helpers for CLI introspection
3
+ * Uses Zod v4's native toJSONSchema() method
4
+ */
5
+
6
+ import type { JsonSchema, SchemaProperty } from "./types";
7
+
8
+ /**
9
+ * Convert a Zod schema to JSON Schema format
10
+ * Uses Zod v4's native toJSONSchema() method
11
+ */
12
+ // biome-ignore lint/suspicious/noExplicitAny: Zod v4 type compatibility
13
+ export function toJsonSchema(schema: any): JsonSchema {
14
+ // Zod v4 has native toJSONSchema() method
15
+ if (typeof schema.toJSONSchema === "function") {
16
+ try {
17
+ return schema.toJSONSchema() as JsonSchema;
18
+ } catch {
19
+ // Some Zod types (transforms, custom) can't be represented in JSON Schema
20
+ // Return a basic schema with description if available
21
+ return {
22
+ type: "object",
23
+ description: schema._def?.description,
24
+ } as JsonSchema;
25
+ }
26
+ }
27
+ // Fallback for older Zod versions or non-Zod schemas
28
+ return schema as JsonSchema;
29
+ }
30
+
31
+ /**
32
+ * Get CLI-friendly schema info for displaying help
33
+ * Returns properties and required fields in JSON Schema format
34
+ */
35
+ // biome-ignore lint/suspicious/noExplicitAny: Zod v4 type compatibility
36
+ export function getCliSchemaInfo(schema: any): {
37
+ properties: Record<string, SchemaProperty>;
38
+ required: string[];
39
+ } {
40
+ const jsonSchema = toJsonSchema(schema);
41
+
42
+ return {
43
+ properties: (jsonSchema.properties || {}) as Record<string, SchemaProperty>,
44
+ required: jsonSchema.required || [],
45
+ };
46
+ }
47
+
48
+ /**
49
+ * Generate CLI help text from a Zod schema
50
+ */
51
+ // biome-ignore lint/suspicious/noExplicitAny: Zod v4 type compatibility
52
+ export function schemaToCliHelp(schema: any): string {
53
+ const { properties, required } = getCliSchemaInfo(schema);
54
+ const lines: string[] = [];
55
+
56
+ for (const [key, prop] of Object.entries(properties)) {
57
+ const isRequired = required.includes(key);
58
+ const parts: string[] = [`--${key.padEnd(15)}`];
59
+
60
+ if (prop.description) {
61
+ parts.push(prop.description);
62
+ }
63
+
64
+ if (isRequired) {
65
+ parts.push("(required)");
66
+ }
67
+
68
+ if (prop.default !== undefined) {
69
+ parts.push(`[default: ${JSON.stringify(prop.default)}]`);
70
+ }
71
+
72
+ if (prop.enum && prop.enum.length > 0) {
73
+ parts.push(`[${prop.enum.join(", ")}]`);
74
+ }
75
+
76
+ lines.push(parts.join(" "));
77
+ }
78
+
79
+ return lines.join("\n");
80
+ }
81
+
82
+ /**
83
+ * Coerce a CLI string value to the proper type based on JSON Schema property
84
+ */
85
+ export function coerceCliValue(value: string, prop: SchemaProperty): unknown {
86
+ switch (prop.type) {
87
+ case "number":
88
+ case "integer":
89
+ return Number(value);
90
+ case "boolean":
91
+ return value === "true" || value === "1";
92
+ case "array":
93
+ // Handle comma-separated values
94
+ return value.split(",").map((v) => v.trim());
95
+ default:
96
+ return value;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Parse CLI arguments into an object based on schema
102
+ */
103
+ export function parseCliArgs(
104
+ args: string[],
105
+ // biome-ignore lint/suspicious/noExplicitAny: Zod v4 type compatibility
106
+ schema: any,
107
+ ): Record<string, unknown> {
108
+ const { properties } = getCliSchemaInfo(schema);
109
+ const result: Record<string, unknown> = {};
110
+
111
+ for (let i = 0; i < args.length; i++) {
112
+ const arg = args[i];
113
+ if (!arg?.startsWith("--")) continue;
114
+
115
+ const key = arg.slice(2);
116
+ const prop = properties[key];
117
+
118
+ if (!prop) continue;
119
+
120
+ // Boolean flags don't require a value
121
+ if (prop.type === "boolean") {
122
+ result[key] = true;
123
+ continue;
124
+ }
125
+
126
+ // Get the value
127
+ const value = args[++i];
128
+ if (value && !value.startsWith("--")) {
129
+ result[key] = coerceCliValue(value, prop);
130
+ }
131
+ }
132
+
133
+ return result;
134
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Schema module exports
3
+ */
4
+
5
+ export * from "./helpers";
6
+ export * from "./shared";
7
+ export * from "./types";
8
+ export * from "./validator";