@vargai/sdk 0.1.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.
- package/.env.example +24 -0
- package/CLAUDE.md +118 -0
- package/HIGGSFIELD_REWRITE_SUMMARY.md +300 -0
- package/README.md +231 -0
- package/SKILLS.md +157 -0
- package/STRUCTURE.md +92 -0
- package/TEST_RESULTS.md +122 -0
- package/action/captions/SKILL.md +170 -0
- package/action/captions/index.ts +169 -0
- package/action/edit/SKILL.md +235 -0
- package/action/edit/index.ts +437 -0
- package/action/image/SKILL.md +140 -0
- package/action/image/index.ts +105 -0
- package/action/sync/SKILL.md +136 -0
- package/action/sync/index.ts +145 -0
- package/action/transcribe/SKILL.md +179 -0
- package/action/transcribe/index.ts +210 -0
- package/action/video/SKILL.md +116 -0
- package/action/video/index.ts +125 -0
- package/action/voice/SKILL.md +125 -0
- package/action/voice/index.ts +136 -0
- package/biome.json +33 -0
- package/bun.lock +842 -0
- package/cli/commands/find.ts +58 -0
- package/cli/commands/help.ts +70 -0
- package/cli/commands/list.ts +49 -0
- package/cli/commands/run.ts +237 -0
- package/cli/commands/which.ts +66 -0
- package/cli/discover.ts +66 -0
- package/cli/index.ts +33 -0
- package/cli/runner.ts +65 -0
- package/cli/types.ts +49 -0
- package/cli/ui.ts +185 -0
- package/index.ts +75 -0
- package/lib/README.md +144 -0
- package/lib/ai-sdk/fal.ts +106 -0
- package/lib/ai-sdk/replicate.ts +107 -0
- package/lib/elevenlabs.ts +382 -0
- package/lib/fal.ts +467 -0
- package/lib/ffmpeg.ts +467 -0
- package/lib/fireworks.ts +235 -0
- package/lib/groq.ts +246 -0
- package/lib/higgsfield/MIGRATION.md +308 -0
- package/lib/higgsfield/README.md +273 -0
- package/lib/higgsfield/example.ts +228 -0
- package/lib/higgsfield/index.ts +241 -0
- package/lib/higgsfield/soul.ts +262 -0
- package/lib/higgsfield.ts +176 -0
- package/lib/remotion/SKILL.md +823 -0
- package/lib/remotion/cli.ts +115 -0
- package/lib/remotion/functions.ts +283 -0
- package/lib/remotion/index.ts +19 -0
- package/lib/remotion/templates.ts +73 -0
- package/lib/replicate.ts +304 -0
- package/output.txt +1 -0
- package/package.json +42 -0
- package/pipeline/cookbooks/SKILL.md +285 -0
- package/pipeline/cookbooks/remotion-video.md +585 -0
- package/pipeline/cookbooks/round-video-character.md +337 -0
- package/pipeline/cookbooks/talking-character.md +59 -0
- package/scripts/produce-menopause-campaign.sh +202 -0
- package/service/music/SKILL.md +229 -0
- package/service/music/index.ts +296 -0
- package/test-import.ts +7 -0
- package/test-services.ts +97 -0
- package/tsconfig.json +29 -0
- package/utilities/s3.ts +147 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* varg find command
|
|
3
|
+
* fuzzy search by scanning filesystem
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { defineCommand } from "citty";
|
|
7
|
+
import { search } from "../discover";
|
|
8
|
+
import { box, c, header, separator } from "../ui";
|
|
9
|
+
|
|
10
|
+
export const findCmd = defineCommand({
|
|
11
|
+
meta: {
|
|
12
|
+
name: "find",
|
|
13
|
+
description: "fuzzy search for models/actions",
|
|
14
|
+
},
|
|
15
|
+
args: {
|
|
16
|
+
query: {
|
|
17
|
+
type: "positional",
|
|
18
|
+
description: "search query",
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
async run({ args }) {
|
|
23
|
+
const query = args.query;
|
|
24
|
+
|
|
25
|
+
if (!query) {
|
|
26
|
+
console.error(`${c.red("error:")} search query required`);
|
|
27
|
+
console.log(`\nusage: ${c.cyan("varg find <query>")}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const results = await search(query);
|
|
32
|
+
|
|
33
|
+
if (results.length === 0) {
|
|
34
|
+
console.log(`\nno matches for "${query}"`);
|
|
35
|
+
console.log(`\ntry ${c.cyan("varg list")} to see all available actions`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const content: string[] = [];
|
|
40
|
+
content.push("");
|
|
41
|
+
content.push(header("MATCHES"));
|
|
42
|
+
content.push("");
|
|
43
|
+
|
|
44
|
+
for (const action of results) {
|
|
45
|
+
content.push(
|
|
46
|
+
` ${c.cyan(action.name.padEnd(16))}${action.inputType} → ${action.outputType}`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
content.push("");
|
|
51
|
+
content.push(separator());
|
|
52
|
+
content.push("");
|
|
53
|
+
content.push(` run ${c.cyan("varg run <name> --help")} for usage`);
|
|
54
|
+
content.push("");
|
|
55
|
+
|
|
56
|
+
console.log(box(`search: "${query}"`, content));
|
|
57
|
+
},
|
|
58
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* varg help command
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { defineCommand } from "citty";
|
|
6
|
+
import { box, c, header, separator } from "../ui";
|
|
7
|
+
|
|
8
|
+
export const helpCmd = defineCommand({
|
|
9
|
+
meta: {
|
|
10
|
+
name: "help",
|
|
11
|
+
description: "show help",
|
|
12
|
+
},
|
|
13
|
+
run() {
|
|
14
|
+
const content: string[] = [];
|
|
15
|
+
content.push("");
|
|
16
|
+
content.push(" AI video infrastructure from your terminal.");
|
|
17
|
+
content.push("");
|
|
18
|
+
content.push(separator());
|
|
19
|
+
content.push("");
|
|
20
|
+
content.push(header("USAGE"));
|
|
21
|
+
content.push("");
|
|
22
|
+
content.push(` varg ${c.cyan("<command>")} [target] [options]`);
|
|
23
|
+
content.push("");
|
|
24
|
+
content.push(separator());
|
|
25
|
+
content.push("");
|
|
26
|
+
content.push(header("COMMANDS"));
|
|
27
|
+
content.push("");
|
|
28
|
+
content.push(` ${c.cyan("run".padEnd(12))}run a model or action`);
|
|
29
|
+
content.push(` ${c.cyan("list".padEnd(12))}discover what's available`);
|
|
30
|
+
content.push(
|
|
31
|
+
` ${c.cyan("find".padEnd(12))}fuzzy search for models/actions`,
|
|
32
|
+
);
|
|
33
|
+
content.push(
|
|
34
|
+
` ${c.cyan("which".padEnd(12))}inspect what's behind an action`,
|
|
35
|
+
);
|
|
36
|
+
content.push(` ${c.cyan("help".padEnd(12))}show this help`);
|
|
37
|
+
content.push("");
|
|
38
|
+
content.push(separator());
|
|
39
|
+
content.push("");
|
|
40
|
+
content.push(header("EXAMPLES"));
|
|
41
|
+
content.push("");
|
|
42
|
+
content.push(` ${c.dim("# generate video from text")}`);
|
|
43
|
+
content.push(` varg run kling --prompt "a cat dancing"`);
|
|
44
|
+
content.push("");
|
|
45
|
+
content.push(` ${c.dim("# animate an image")}`);
|
|
46
|
+
content.push(` varg run image-to-video --image ./cat.png`);
|
|
47
|
+
content.push("");
|
|
48
|
+
content.push(` ${c.dim("# transcribe audio")}`);
|
|
49
|
+
content.push(` varg run transcribe ./video.mp4`);
|
|
50
|
+
content.push("");
|
|
51
|
+
content.push(` ${c.dim("# see what's available")}`);
|
|
52
|
+
content.push(` varg list`);
|
|
53
|
+
content.push("");
|
|
54
|
+
content.push(separator());
|
|
55
|
+
content.push("");
|
|
56
|
+
content.push(header("ENVIRONMENT"));
|
|
57
|
+
content.push("");
|
|
58
|
+
content.push(` ${c.dim("FAL_KEY".padEnd(24))}fal.ai api key`);
|
|
59
|
+
content.push(
|
|
60
|
+
` ${c.dim("REPLICATE_API_TOKEN".padEnd(24))}replicate api key`,
|
|
61
|
+
);
|
|
62
|
+
content.push(
|
|
63
|
+
` ${c.dim("ELEVENLABS_API_KEY".padEnd(24))}elevenlabs api key`,
|
|
64
|
+
);
|
|
65
|
+
content.push(` ${c.dim("GROQ_API_KEY".padEnd(24))}groq api key`);
|
|
66
|
+
content.push("");
|
|
67
|
+
|
|
68
|
+
console.log(box("varg", content));
|
|
69
|
+
},
|
|
70
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* varg list command
|
|
3
|
+
* discover what's available by scanning filesystem
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { defineCommand } from "citty";
|
|
7
|
+
import { discoverActions } from "../discover";
|
|
8
|
+
import { box, c, header, separator, table } from "../ui";
|
|
9
|
+
|
|
10
|
+
export const listCmd = defineCommand({
|
|
11
|
+
meta: {
|
|
12
|
+
name: "list",
|
|
13
|
+
description: "discover what's available",
|
|
14
|
+
},
|
|
15
|
+
args: {
|
|
16
|
+
filter: {
|
|
17
|
+
type: "positional",
|
|
18
|
+
description: "filter by type",
|
|
19
|
+
required: false,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
async run() {
|
|
23
|
+
const actions = await discoverActions();
|
|
24
|
+
|
|
25
|
+
const content: string[] = [];
|
|
26
|
+
content.push("");
|
|
27
|
+
|
|
28
|
+
content.push(header("ACTIONS"));
|
|
29
|
+
content.push("");
|
|
30
|
+
|
|
31
|
+
const rows = actions.map((a) => ({
|
|
32
|
+
name: a.name,
|
|
33
|
+
description:
|
|
34
|
+
`${a.inputType} → ${a.outputType}`.padEnd(20) + a.description,
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
content.push(...table(rows));
|
|
38
|
+
content.push("");
|
|
39
|
+
|
|
40
|
+
content.push(separator());
|
|
41
|
+
content.push("");
|
|
42
|
+
content.push(
|
|
43
|
+
` ${actions.length} actions · run ${c.cyan("varg run <action> --info")} for details`,
|
|
44
|
+
);
|
|
45
|
+
content.push("");
|
|
46
|
+
|
|
47
|
+
console.log(box("varg", content));
|
|
48
|
+
},
|
|
49
|
+
});
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* varg run command
|
|
3
|
+
* execute actions by scanning filesystem
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { defineCommand } from "citty";
|
|
8
|
+
import { resolve } from "../discover";
|
|
9
|
+
import type { Meta } from "../types";
|
|
10
|
+
import { box, c, runningBox } from "../ui";
|
|
11
|
+
|
|
12
|
+
interface RunOptions {
|
|
13
|
+
[key: string]: string | boolean | undefined;
|
|
14
|
+
info?: boolean;
|
|
15
|
+
schema?: boolean;
|
|
16
|
+
json?: boolean;
|
|
17
|
+
quiet?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseArgs(args: string[]): { target: string; options: RunOptions } {
|
|
21
|
+
const options: RunOptions = {};
|
|
22
|
+
let target = "";
|
|
23
|
+
|
|
24
|
+
for (let i = 0; i < args.length; i++) {
|
|
25
|
+
const arg = args[i];
|
|
26
|
+
if (!arg) continue;
|
|
27
|
+
|
|
28
|
+
if (arg.startsWith("--")) {
|
|
29
|
+
const key = arg.slice(2);
|
|
30
|
+
if (
|
|
31
|
+
key === "info" ||
|
|
32
|
+
key === "schema" ||
|
|
33
|
+
key === "json" ||
|
|
34
|
+
key === "quiet"
|
|
35
|
+
) {
|
|
36
|
+
options[key] = true;
|
|
37
|
+
} else {
|
|
38
|
+
const value = args[++i];
|
|
39
|
+
if (value) options[key] = value;
|
|
40
|
+
}
|
|
41
|
+
} else if (!target) {
|
|
42
|
+
target = arg;
|
|
43
|
+
} else {
|
|
44
|
+
// positional args - check if it looks like a file
|
|
45
|
+
if (existsSync(arg) || arg.startsWith("./") || arg.startsWith("/")) {
|
|
46
|
+
if (!options.image && !options.audio) {
|
|
47
|
+
options.image = arg;
|
|
48
|
+
}
|
|
49
|
+
} else if (!options.prompt && !options.text) {
|
|
50
|
+
options.prompt = arg;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return { target, options };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function showHelp(item: Meta) {
|
|
59
|
+
const content: string[] = [];
|
|
60
|
+
content.push("");
|
|
61
|
+
content.push(` ${item.description}`);
|
|
62
|
+
content.push("");
|
|
63
|
+
content.push(c.bold(c.dim(" USAGE")));
|
|
64
|
+
content.push("");
|
|
65
|
+
|
|
66
|
+
const required = item.schema.input.required;
|
|
67
|
+
const reqArgs = required.map((r) => `--${r} <${r}>`).join(" ");
|
|
68
|
+
content.push(` varg run ${item.name} ${reqArgs} [options]`);
|
|
69
|
+
|
|
70
|
+
content.push("");
|
|
71
|
+
content.push(c.bold(c.dim(" OPTIONS")));
|
|
72
|
+
content.push("");
|
|
73
|
+
|
|
74
|
+
for (const [key, prop] of Object.entries(item.schema.input.properties)) {
|
|
75
|
+
const req = item.schema.input.required.includes(key);
|
|
76
|
+
const reqTag = req ? c.yellow(" (required)") : "";
|
|
77
|
+
const defaultVal =
|
|
78
|
+
prop.default !== undefined ? c.dim(` default: ${prop.default}`) : "";
|
|
79
|
+
const enumVals = prop.enum ? c.dim(` [${prop.enum.join(", ")}]`) : "";
|
|
80
|
+
|
|
81
|
+
content.push(
|
|
82
|
+
` --${key.padEnd(12)}${prop.description}${reqTag}${defaultVal}${enumVals}`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
content.push("");
|
|
87
|
+
content.push(` --json output result as json`);
|
|
88
|
+
content.push(` --quiet minimal output`);
|
|
89
|
+
content.push(` --info show this help`);
|
|
90
|
+
content.push("");
|
|
91
|
+
|
|
92
|
+
console.log(box(`action: ${item.name}`, content));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function showSchema(item: Meta) {
|
|
96
|
+
const schema = {
|
|
97
|
+
name: item.name,
|
|
98
|
+
type: item.type,
|
|
99
|
+
description: item.description,
|
|
100
|
+
input: item.schema.input,
|
|
101
|
+
output: item.schema.output,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
console.log(JSON.stringify(schema, null, 2));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const runCmd = defineCommand({
|
|
108
|
+
meta: {
|
|
109
|
+
name: "run",
|
|
110
|
+
description: "run a model or action",
|
|
111
|
+
},
|
|
112
|
+
args: {
|
|
113
|
+
target: {
|
|
114
|
+
type: "positional",
|
|
115
|
+
description: "action to run",
|
|
116
|
+
required: false,
|
|
117
|
+
},
|
|
118
|
+
info: {
|
|
119
|
+
type: "boolean",
|
|
120
|
+
description: "show action info",
|
|
121
|
+
},
|
|
122
|
+
schema: {
|
|
123
|
+
type: "boolean",
|
|
124
|
+
description: "show action schema as json",
|
|
125
|
+
},
|
|
126
|
+
json: {
|
|
127
|
+
type: "boolean",
|
|
128
|
+
description: "output result as json",
|
|
129
|
+
},
|
|
130
|
+
quiet: {
|
|
131
|
+
type: "boolean",
|
|
132
|
+
description: "minimal output",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
async run({ rawArgs }) {
|
|
136
|
+
// use rawArgs for dynamic action options
|
|
137
|
+
const { target, options } = parseArgs(rawArgs);
|
|
138
|
+
|
|
139
|
+
if (!target) {
|
|
140
|
+
console.error(`${c.red("error:")} target required`);
|
|
141
|
+
console.log(`\nusage: ${c.cyan("varg run <action> [options]")}`);
|
|
142
|
+
console.log(`\nrun ${c.cyan("varg list")} to see available actions`);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const item = await resolve(target);
|
|
147
|
+
|
|
148
|
+
if (!item) {
|
|
149
|
+
console.error(`${c.red("error:")} '${target}' not found`);
|
|
150
|
+
console.log(`\nrun ${c.cyan("varg list")} to see available actions`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (options.info) {
|
|
155
|
+
showHelp(item);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (options.schema) {
|
|
160
|
+
showSchema(item);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// validate required args
|
|
165
|
+
for (const req of item.schema.input.required) {
|
|
166
|
+
if (!options[req]) {
|
|
167
|
+
console.error(`${c.red("error:")} --${req} is required`);
|
|
168
|
+
console.log(`\nrun ${c.cyan(`varg run ${target} --info`)} for usage`);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// build params for display
|
|
174
|
+
const params: Record<string, string> = {};
|
|
175
|
+
for (const key of Object.keys(item.schema.input.properties)) {
|
|
176
|
+
if (options[key] && typeof options[key] === "string") {
|
|
177
|
+
params[key] = options[key] as string;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (!options.quiet && !options.json) {
|
|
182
|
+
console.log(runningBox(target, params, "running"));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const startTime = Date.now();
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
const result = await item.run(options);
|
|
189
|
+
const elapsed = Date.now() - startTime;
|
|
190
|
+
|
|
191
|
+
if (options.json) {
|
|
192
|
+
console.log(JSON.stringify({ success: true, result, time: elapsed }));
|
|
193
|
+
} else if (options.quiet) {
|
|
194
|
+
console.log(JSON.stringify(result));
|
|
195
|
+
} else {
|
|
196
|
+
// extract url from result if present
|
|
197
|
+
const resultObj = result as Record<string, unknown> | null;
|
|
198
|
+
const url =
|
|
199
|
+
resultObj?.imageUrl || resultObj?.videoUrl || resultObj?.url || null;
|
|
200
|
+
|
|
201
|
+
console.log("\x1b[2J\x1b[H");
|
|
202
|
+
console.log(
|
|
203
|
+
runningBox(target, params, "done", {
|
|
204
|
+
output: url ? "saved" : "done",
|
|
205
|
+
time: elapsed,
|
|
206
|
+
}),
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
// print url outside box so it's clickable
|
|
210
|
+
if (url) {
|
|
211
|
+
console.log(`\n ${c.cyan("url")} ${url}\n`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
} catch (err) {
|
|
215
|
+
const elapsed = Date.now() - startTime;
|
|
216
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
217
|
+
|
|
218
|
+
if (options.json) {
|
|
219
|
+
console.log(
|
|
220
|
+
JSON.stringify({ success: false, error: errorMsg, time: elapsed }),
|
|
221
|
+
);
|
|
222
|
+
} else if (options.quiet) {
|
|
223
|
+
console.error(errorMsg);
|
|
224
|
+
} else {
|
|
225
|
+
console.log("\x1b[2J\x1b[H");
|
|
226
|
+
console.log(
|
|
227
|
+
runningBox(target, params, "error", {
|
|
228
|
+
error: errorMsg,
|
|
229
|
+
time: elapsed,
|
|
230
|
+
}),
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* varg which command
|
|
3
|
+
* inspect an action by scanning filesystem
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { defineCommand } from "citty";
|
|
7
|
+
import { resolve } from "../discover";
|
|
8
|
+
import { box, c, header, separator } from "../ui";
|
|
9
|
+
|
|
10
|
+
export const whichCmd = defineCommand({
|
|
11
|
+
meta: {
|
|
12
|
+
name: "which",
|
|
13
|
+
description: "inspect what's behind an action",
|
|
14
|
+
},
|
|
15
|
+
args: {
|
|
16
|
+
name: {
|
|
17
|
+
type: "positional",
|
|
18
|
+
description: "action name",
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
async run({ args }) {
|
|
23
|
+
const name = args.name;
|
|
24
|
+
|
|
25
|
+
if (!name) {
|
|
26
|
+
console.error(`${c.red("error:")} action name required`);
|
|
27
|
+
console.log(`\nusage: ${c.cyan("varg which <name>")}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const item = await resolve(name);
|
|
32
|
+
|
|
33
|
+
if (!item) {
|
|
34
|
+
console.error(`${c.red("error:")} '${name}' not found`);
|
|
35
|
+
console.log(`\nrun ${c.cyan("varg list")} to see available actions`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const content: string[] = [];
|
|
40
|
+
content.push("");
|
|
41
|
+
content.push(` ${item.description}`);
|
|
42
|
+
content.push("");
|
|
43
|
+
|
|
44
|
+
content.push(header("SCHEMA"));
|
|
45
|
+
content.push("");
|
|
46
|
+
|
|
47
|
+
for (const [key, prop] of Object.entries(item.schema.input.properties)) {
|
|
48
|
+
const required = item.schema.input.required.includes(key);
|
|
49
|
+
const reqTag = required ? c.yellow("*") : " ";
|
|
50
|
+
const defaultVal = prop.default
|
|
51
|
+
? c.dim(` (default: ${prop.default})`)
|
|
52
|
+
: "";
|
|
53
|
+
content.push(
|
|
54
|
+
` ${reqTag}${c.cyan(key.padEnd(12))}${prop.description}${defaultVal}`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
content.push("");
|
|
59
|
+
content.push(separator());
|
|
60
|
+
content.push("");
|
|
61
|
+
content.push(` run ${c.cyan(`varg run ${name} --info`)} for full options`);
|
|
62
|
+
content.push("");
|
|
63
|
+
|
|
64
|
+
console.log(box(`action: ${name}`, content));
|
|
65
|
+
},
|
|
66
|
+
});
|
package/cli/discover.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* filesystem-based discovery for varg cli
|
|
3
|
+
* scans action/ directory for modules with meta exports
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readdir } from "node:fs/promises";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import type { ActionMeta, Meta } from "./types";
|
|
9
|
+
|
|
10
|
+
const ACTION_DIR = join(import.meta.dir, "..", "action");
|
|
11
|
+
|
|
12
|
+
let cachedActions: ActionMeta[] | null = null;
|
|
13
|
+
|
|
14
|
+
export async function discoverActions(): Promise<ActionMeta[]> {
|
|
15
|
+
if (cachedActions) return cachedActions;
|
|
16
|
+
|
|
17
|
+
const actions: ActionMeta[] = [];
|
|
18
|
+
const dirs = await readdir(ACTION_DIR);
|
|
19
|
+
|
|
20
|
+
for (const dir of dirs) {
|
|
21
|
+
try {
|
|
22
|
+
const mod = await import(`../action/${dir}`);
|
|
23
|
+
if (mod.meta && mod.meta.type === "action") {
|
|
24
|
+
actions.push(mod.meta);
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// skip directories without valid modules
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
cachedActions = actions;
|
|
32
|
+
return actions;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function resolve(name: string): Promise<Meta | null> {
|
|
36
|
+
const actions = await discoverActions();
|
|
37
|
+
|
|
38
|
+
// check explicit namespace
|
|
39
|
+
if (name.startsWith("action/")) {
|
|
40
|
+
const actionName = name.slice(7);
|
|
41
|
+
return actions.find((a) => a.name === actionName) || null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// check actions
|
|
45
|
+
const action = actions.find((a) => a.name === name);
|
|
46
|
+
if (action) return action;
|
|
47
|
+
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function search(query: string): Promise<Meta[]> {
|
|
52
|
+
const actions = await discoverActions();
|
|
53
|
+
const q = query.toLowerCase();
|
|
54
|
+
|
|
55
|
+
return actions.filter(
|
|
56
|
+
(a) =>
|
|
57
|
+
a.name.toLowerCase().includes(q) ||
|
|
58
|
+
a.description.toLowerCase().includes(q) ||
|
|
59
|
+
a.inputType.toLowerCase().includes(q) ||
|
|
60
|
+
a.outputType.toLowerCase().includes(q),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function list(): Promise<Meta[]> {
|
|
65
|
+
return discoverActions();
|
|
66
|
+
}
|
package/cli/index.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* varg cli
|
|
5
|
+
* ai video infrastructure from your terminal
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { defineCommand, runMain } from "citty";
|
|
9
|
+
import { findCmd } from "./commands/find";
|
|
10
|
+
import { helpCmd } from "./commands/help";
|
|
11
|
+
import { listCmd } from "./commands/list";
|
|
12
|
+
import { runCmd } from "./commands/run";
|
|
13
|
+
import { whichCmd } from "./commands/which";
|
|
14
|
+
|
|
15
|
+
const main = defineCommand({
|
|
16
|
+
meta: {
|
|
17
|
+
name: "varg",
|
|
18
|
+
version: "0.1.0",
|
|
19
|
+
description: "ai video infrastructure from your terminal",
|
|
20
|
+
},
|
|
21
|
+
subCommands: {
|
|
22
|
+
run: runCmd,
|
|
23
|
+
list: listCmd,
|
|
24
|
+
ls: listCmd,
|
|
25
|
+
find: findCmd,
|
|
26
|
+
search: findCmd,
|
|
27
|
+
which: whichCmd,
|
|
28
|
+
inspect: whichCmd,
|
|
29
|
+
help: helpCmd,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
runMain(main);
|
package/cli/runner.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shared cli runner for actions
|
|
3
|
+
* parses args and calls meta.run()
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Meta } from "./types";
|
|
7
|
+
|
|
8
|
+
export async function runCli(meta: Meta) {
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
|
|
11
|
+
if (args[0] === "help" || args[0] === "--help" || args.length === 0) {
|
|
12
|
+
console.log(`
|
|
13
|
+
${meta.name} - ${meta.description}
|
|
14
|
+
|
|
15
|
+
usage:
|
|
16
|
+
bun run action/${meta.name} [options]
|
|
17
|
+
|
|
18
|
+
options:`);
|
|
19
|
+
|
|
20
|
+
for (const [key, prop] of Object.entries(meta.schema.input.properties)) {
|
|
21
|
+
const req = meta.schema.input.required.includes(key) ? " (required)" : "";
|
|
22
|
+
const def =
|
|
23
|
+
prop.default !== undefined ? ` [default: ${prop.default}]` : "";
|
|
24
|
+
console.log(` --${key.padEnd(14)} ${prop.description}${req}${def}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(`
|
|
28
|
+
examples:
|
|
29
|
+
bun run action/${meta.name} --${meta.schema.input.required[0]} "value"
|
|
30
|
+
`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// parse args
|
|
35
|
+
const options: Record<string, unknown> = {};
|
|
36
|
+
const firstRequired = meta.schema.input.required[0];
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < args.length; i++) {
|
|
39
|
+
const arg = args[i];
|
|
40
|
+
if (arg?.startsWith("--")) {
|
|
41
|
+
const key = arg.slice(2);
|
|
42
|
+
const value = args[++i];
|
|
43
|
+
options[key] = value;
|
|
44
|
+
} else if (arg && firstRequired && !options[firstRequired]) {
|
|
45
|
+
// first positional arg goes to first required field
|
|
46
|
+
options[firstRequired] = arg;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// validate required
|
|
51
|
+
for (const req of meta.schema.input.required) {
|
|
52
|
+
if (!options[req]) {
|
|
53
|
+
console.error(`error: --${req} is required`);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const result = await meta.run(options);
|
|
60
|
+
console.log(JSON.stringify(result, null, 2));
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error(`error: ${err instanceof Error ? err.message : err}`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
}
|
package/cli/types.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shared types for varg cli
|
|
3
|
+
* actions and models export meta objects conforming to these types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface SchemaProperty {
|
|
7
|
+
type: string;
|
|
8
|
+
description: string;
|
|
9
|
+
enum?: (string | number)[];
|
|
10
|
+
default?: unknown;
|
|
11
|
+
format?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Schema {
|
|
15
|
+
input: {
|
|
16
|
+
type: "object";
|
|
17
|
+
required: string[];
|
|
18
|
+
properties: Record<string, SchemaProperty>;
|
|
19
|
+
};
|
|
20
|
+
output: {
|
|
21
|
+
type: string;
|
|
22
|
+
format?: string;
|
|
23
|
+
description: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ActionMeta {
|
|
28
|
+
name: string;
|
|
29
|
+
type: "action";
|
|
30
|
+
description: string;
|
|
31
|
+
inputType: string;
|
|
32
|
+
outputType: string;
|
|
33
|
+
schema: Schema;
|
|
34
|
+
run: (options: Record<string, unknown>) => Promise<unknown>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ModelMeta {
|
|
38
|
+
name: string;
|
|
39
|
+
type: "model";
|
|
40
|
+
description: string;
|
|
41
|
+
inputType: string;
|
|
42
|
+
outputType: string;
|
|
43
|
+
providers: string[];
|
|
44
|
+
defaultProvider: string;
|
|
45
|
+
schema: Schema;
|
|
46
|
+
run: (options: Record<string, unknown>) => Promise<unknown>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type Meta = ActionMeta | ModelMeta;
|