@mevdragon/vidfarm-devcli 0.4.0 → 0.4.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/dist/src/cli.js +104 -0
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createWriteStream, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
4
6
|
import { parseArgs } from "node:util";
|
|
5
7
|
import { spawnSync } from "node:child_process";
|
|
6
8
|
import { Readable } from "node:stream";
|
|
@@ -11,6 +13,12 @@ import { pipeline } from "node:stream/promises";
|
|
|
11
13
|
// starts a local dev-serve, and prints the editor URL to open in the browser.
|
|
12
14
|
const DEFAULT_HOST = "https://vidfarm.cc";
|
|
13
15
|
const DEFAULT_PORT = 4321;
|
|
16
|
+
// Agent skill files the `update-skill` command can install from the live host
|
|
17
|
+
// (`GET /skill/<name>`), falling back to the copy bundled in this npm package.
|
|
18
|
+
const SKILL_TARGETS = {
|
|
19
|
+
"vidfarm-director": { route: "/skill/vidfarm-director", bundled: "SKILL.director.md" },
|
|
20
|
+
"vidfarm-platform": { route: "/skill/vidfarm-platform", bundled: "SKILL.platform.md" }
|
|
21
|
+
};
|
|
14
22
|
// Every command below is a thin wrapper over ONE Vidfarm REST call (the `→`
|
|
15
23
|
// line documents the exact route). The devcli adds nothing the raw API can't
|
|
16
24
|
// do — it just resolves your fork, sets the `vidfarm-api-key` header, prints
|
|
@@ -66,6 +74,13 @@ Account:
|
|
|
66
74
|
provider-keys List saved AI provider keys → GET /api/v1/user/me/provider-keys
|
|
67
75
|
add-provider-key <provider> <secret> Save an AI provider key → POST /api/v1/user/me/provider-keys
|
|
68
76
|
|
|
77
|
+
Agent skill (install the latest director skill so your AI agent can act):
|
|
78
|
+
update-skill Fetch latest SKILL.director.md → .claude/skills → GET /skill/vidfarm-director
|
|
79
|
+
--global Install into ~/.claude/skills (default: ./.claude/skills)
|
|
80
|
+
--dir <path> Install into a custom skills root
|
|
81
|
+
--platform Also install SKILL.platform.md (vidfarm-platform)
|
|
82
|
+
--print Print the skill to stdout instead of writing a file
|
|
83
|
+
|
|
69
84
|
Files (multi-step flows the devcli handles for you):
|
|
70
85
|
upload <file> Upload a local file, print its durable URL → POST /api/v1/user/me/temporary-files/upload
|
|
71
86
|
download <url> [dest] Stream any Vidfarm/media URL to disk
|
|
@@ -188,6 +203,10 @@ async function main() {
|
|
|
188
203
|
case "whoami":
|
|
189
204
|
await runWhoamiCommand(rest);
|
|
190
205
|
return;
|
|
206
|
+
case "update-skill":
|
|
207
|
+
case "skill":
|
|
208
|
+
await runUpdateSkillCommand(rest);
|
|
209
|
+
return;
|
|
191
210
|
case "provider-keys":
|
|
192
211
|
await runProviderKeysCommand(rest);
|
|
193
212
|
return;
|
|
@@ -1297,4 +1316,89 @@ async function runDownloadCommand(argv) {
|
|
|
1297
1316
|
console.log(`${GREEN}Downloaded ${formatBytes(bytes)} → ${dest}${RESET}`);
|
|
1298
1317
|
}
|
|
1299
1318
|
}
|
|
1319
|
+
// ── Agent skill ───────────────────────────────────────────────────────────────
|
|
1320
|
+
// Install the latest director skill onto disk as a Claude Code / agent skill so
|
|
1321
|
+
// the user's AI agent can read SKILL.director.md and act. We pull the freshest
|
|
1322
|
+
// copy from the live host (`GET /skill/<name>`) and fall back to the copy that
|
|
1323
|
+
// shipped inside this npm package when offline. Written as `<skill>/SKILL.md`.
|
|
1324
|
+
// Walk up from this module's directory to find a bundled skill file. Handles
|
|
1325
|
+
// both the published layout (dist/src/cli.js → package root) and running from
|
|
1326
|
+
// source (src/cli.ts → repo root).
|
|
1327
|
+
function locateBundledSkill(filename) {
|
|
1328
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
1329
|
+
for (let i = 0; i < 6; i += 1) {
|
|
1330
|
+
const candidate = path.join(dir, filename);
|
|
1331
|
+
if (existsSync(candidate))
|
|
1332
|
+
return candidate;
|
|
1333
|
+
const parent = path.dirname(dir);
|
|
1334
|
+
if (parent === dir)
|
|
1335
|
+
break;
|
|
1336
|
+
dir = parent;
|
|
1337
|
+
}
|
|
1338
|
+
return null;
|
|
1339
|
+
}
|
|
1340
|
+
async function fetchSkillContents(host, target) {
|
|
1341
|
+
try {
|
|
1342
|
+
const res = await fetch(new URL(target.route, host));
|
|
1343
|
+
if (res.ok) {
|
|
1344
|
+
const contents = await res.text();
|
|
1345
|
+
if (contents.trim())
|
|
1346
|
+
return { contents, source: "remote" };
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
catch {
|
|
1350
|
+
// fall through to the bundled copy below
|
|
1351
|
+
}
|
|
1352
|
+
const bundledPath = locateBundledSkill(target.bundled);
|
|
1353
|
+
if (bundledPath) {
|
|
1354
|
+
return { contents: readFileSync(bundledPath, "utf8"), source: "bundled" };
|
|
1355
|
+
}
|
|
1356
|
+
throw new Error(`Could not fetch ${target.bundled} from ${host} and no bundled copy was found.`);
|
|
1357
|
+
}
|
|
1358
|
+
async function runUpdateSkillCommand(argv) {
|
|
1359
|
+
const parsed = parseArgs({
|
|
1360
|
+
args: argv,
|
|
1361
|
+
allowPositionals: false,
|
|
1362
|
+
options: {
|
|
1363
|
+
...commonOptions(),
|
|
1364
|
+
global: { type: "boolean", default: false },
|
|
1365
|
+
dir: { type: "string" },
|
|
1366
|
+
platform: { type: "boolean", default: false },
|
|
1367
|
+
print: { type: "boolean", default: false }
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1370
|
+
const ctx = commonContext(parsed.values);
|
|
1371
|
+
const skillNames = ["vidfarm-director", ...(parsed.values.platform ? ["vidfarm-platform"] : [])];
|
|
1372
|
+
if (parsed.values.print) {
|
|
1373
|
+
for (const name of skillNames) {
|
|
1374
|
+
const { contents } = await fetchSkillContents(ctx.host, SKILL_TARGETS[name]);
|
|
1375
|
+
process.stdout.write(contents.endsWith("\n") ? contents : `${contents}\n`);
|
|
1376
|
+
}
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
const skillsRoot = parsed.values.dir
|
|
1380
|
+
? path.resolve(process.cwd(), String(parsed.values.dir))
|
|
1381
|
+
: parsed.values.global
|
|
1382
|
+
? path.join(homedir(), ".claude", "skills")
|
|
1383
|
+
: path.resolve(process.cwd(), ".claude", "skills");
|
|
1384
|
+
const written = [];
|
|
1385
|
+
for (const name of skillNames) {
|
|
1386
|
+
const { contents, source } = await fetchSkillContents(ctx.host, SKILL_TARGETS[name]);
|
|
1387
|
+
const destDir = path.join(skillsRoot, name);
|
|
1388
|
+
mkdirSync(destDir, { recursive: true });
|
|
1389
|
+
const destPath = path.join(destDir, "SKILL.md");
|
|
1390
|
+
writeFileSync(destPath, contents, "utf8");
|
|
1391
|
+
written.push({ skill: name, path: destPath, source, bytes: Buffer.byteLength(contents, "utf8") });
|
|
1392
|
+
}
|
|
1393
|
+
if (ctx.json) {
|
|
1394
|
+
printJson({ ok: true, skillsRoot, installed: written });
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
for (const entry of written) {
|
|
1398
|
+
const tag = entry.source === "bundled" ? " (offline — bundled copy)" : "";
|
|
1399
|
+
console.log(`${GREEN}Installed ${entry.skill} skill${tag} → ${entry.path}${RESET}`);
|
|
1400
|
+
}
|
|
1401
|
+
console.log("");
|
|
1402
|
+
console.log(` ${BOLD}Your AI agent can now use the "vidfarm-director" skill.${RESET}`);
|
|
1403
|
+
}
|
|
1300
1404
|
//# sourceMappingURL=cli.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mevdragon/vidfarm-devcli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Local bridge for the Vidfarm Trackpad Editor. Point it at a template id, edit composition.html on disk (Claude Code, Codex, etc.), preview live in the browser at https://vidfarm.cc/editor/.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|