@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.
Files changed (2) hide show
  1. package/dist/src/cli.js +104 -0
  2. 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.0",
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": {