@mevdragon/vidfarm-devcli 0.5.3 → 0.7.0

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 (116) hide show
  1. package/README.md +3 -3
  2. package/SKILL.director.md +28 -7
  3. package/SKILL.platform.md +9 -5
  4. package/demo/README.md +28 -0
  5. package/demo/dist/app.css +1 -0
  6. package/demo/dist/app.js +1184 -0
  7. package/demo/dist/chunks/chunk-DXB73IDG.js +1 -0
  8. package/demo/dist/chunks/chunk-S7OWAJDS.js +36 -0
  9. package/demo/dist/chunks/chunk-VTIBZ6AN.js +1 -0
  10. package/demo/dist/chunks/dist-ADSJKBVE.js +332 -0
  11. package/demo/dist/chunks/domEditingLayers-VZMLL4AP-SGHWPND4.js +1 -0
  12. package/demo/dist/chunks/hyperframes-player-XB65TCD6.js +425 -0
  13. package/demo/dist/chunks/lib-XAQ37YOE.js +1 -0
  14. package/demo/dist/chunks/src-TJ2QYA4U.js +207 -0
  15. package/demo/dist/favicon.ico +0 -0
  16. package/demo/dist/icons/timeline/audio.svg +7 -0
  17. package/demo/dist/icons/timeline/captions.svg +5 -0
  18. package/demo/dist/icons/timeline/composition.svg +12 -0
  19. package/demo/dist/icons/timeline/image.svg +18 -0
  20. package/demo/dist/icons/timeline/music.svg +10 -0
  21. package/demo/dist/icons/timeline/text.svg +3 -0
  22. package/demo/dist/index.html +15 -0
  23. package/dist/src/account-pages-legacy.js +9396 -0
  24. package/dist/src/account-pages.js +61 -0
  25. package/dist/src/app.js +14663 -0
  26. package/dist/src/cli.js +60 -97
  27. package/dist/src/composition-runtime.js +613 -0
  28. package/dist/src/config.js +173 -0
  29. package/dist/src/context.js +447 -0
  30. package/dist/src/dev-app-legacy.js +739 -0
  31. package/dist/src/dev-app.js +6 -0
  32. package/dist/src/domain.js +2 -0
  33. package/dist/src/editor-chat-history.js +82 -0
  34. package/dist/src/editor-chat.js +449 -0
  35. package/dist/src/editor-dark-theme.js +1128 -0
  36. package/dist/src/frontend/debug.js +71 -0
  37. package/dist/src/frontend/flockposter-cache-store.js +124 -0
  38. package/dist/src/frontend/homepage-client.js +182 -0
  39. package/dist/src/frontend/homepage-shared.js +4 -0
  40. package/dist/src/frontend/homepage-store.js +28 -0
  41. package/dist/src/frontend/homepage-view.js +547 -0
  42. package/dist/src/frontend/page-runtime-client.js +132 -0
  43. package/dist/src/frontend/page-runtime-store.js +9 -0
  44. package/dist/src/frontend/sentry.js +42 -0
  45. package/dist/src/frontend/template-editor-chat.js +3960 -0
  46. package/dist/src/help-page.js +346 -0
  47. package/dist/src/homepage.js +1235 -0
  48. package/dist/src/hyperframes/composition.js +180 -0
  49. package/dist/src/index.js +16 -0
  50. package/dist/src/instrument.js +30 -0
  51. package/dist/src/lib/crypto.js +45 -0
  52. package/dist/src/lib/dev-log.js +54 -0
  53. package/dist/src/lib/display-name.js +11 -0
  54. package/dist/src/lib/ids.js +24 -0
  55. package/dist/src/lib/images.js +19 -0
  56. package/dist/src/lib/json.js +15 -0
  57. package/dist/src/lib/package-root.js +47 -0
  58. package/dist/src/lib/template-paths.js +28 -0
  59. package/dist/src/lib/time.js +7 -0
  60. package/dist/src/lib/url-clean.js +85 -0
  61. package/dist/src/page-runtime.js +2 -0
  62. package/dist/src/page-shell.js +1381 -0
  63. package/dist/src/primitive-context.js +357 -0
  64. package/dist/src/primitive-registry.js +2561 -0
  65. package/dist/src/primitive-sdk.js +4 -0
  66. package/dist/src/primitives/hyperframes-media.js +108 -0
  67. package/dist/src/react-page-shell.js +35 -0
  68. package/dist/src/ready-post-schedule-component.js +1540 -0
  69. package/dist/src/registry.js +296 -0
  70. package/dist/src/runtime.js +35 -0
  71. package/dist/src/services/api-call-history.js +249 -0
  72. package/dist/src/services/auth.js +152 -0
  73. package/dist/src/services/billing-pricing.js +39 -0
  74. package/dist/src/services/billing.js +228 -0
  75. package/dist/src/services/cast.js +127 -0
  76. package/dist/src/services/chat-threads.js +92 -0
  77. package/dist/src/services/composition-sanitize.js +124 -0
  78. package/dist/src/services/composition-watch.js +79 -0
  79. package/dist/src/services/fork-access.js +93 -0
  80. package/dist/src/services/fork-manifest.js +42 -0
  81. package/dist/src/services/ghostcut.js +179 -0
  82. package/dist/src/services/hyperframes.js +2307 -0
  83. package/dist/src/services/job-capacity.js +14 -0
  84. package/dist/src/services/job-logs.js +197 -0
  85. package/dist/src/services/jobs.js +136 -0
  86. package/dist/src/services/local-dynamo.js +0 -0
  87. package/dist/src/services/media-processing.js +766 -0
  88. package/dist/src/services/primitive-media-lambda.js +280 -0
  89. package/dist/src/services/providers.js +2926 -0
  90. package/dist/src/services/rate-limits.js +262 -0
  91. package/dist/src/services/serverless-auth.js +382 -0
  92. package/dist/src/services/serverless-jobs.js +1082 -0
  93. package/dist/src/services/serverless-provider-keys.js +409 -0
  94. package/dist/src/services/serverless-records.js +1385 -0
  95. package/dist/src/services/serverless-template-configs.js +75 -0
  96. package/dist/src/services/storage.js +383 -0
  97. package/dist/src/services/template-certification.js +413 -0
  98. package/dist/src/services/template-loader.js +99 -0
  99. package/dist/src/services/template-runtime-bundles.js +217 -0
  100. package/dist/src/services/template-sources.js +1017 -0
  101. package/dist/src/services/upstream.js +248 -0
  102. package/dist/src/services/video-normalization.js +2 -0
  103. package/dist/src/services/webhooks.js +62 -0
  104. package/dist/src/template-editor-pages.js +2576 -0
  105. package/dist/src/template-editor-shell.js +2840 -0
  106. package/dist/src/template-sdk.js +4 -0
  107. package/dist/src/worker.js +17 -0
  108. package/package.json +6 -4
  109. package/public/assets/homepage-app.js +54 -0
  110. package/public/assets/homepage-client-app.js +80 -0
  111. package/public/assets/page-runtime-client-app.js +94 -0
  112. package/src/assets/SELLING_AWARENESS_STAGES.md +579 -0
  113. package/src/assets/SELLING_WITH_HOOKS.md +377 -0
  114. package/src/assets/SELLING_WITH_VSLS.md +606 -0
  115. package/src/assets/favicon.ico +0 -0
  116. package/src/assets/logo-vidfarm.png +0 -0
package/dist/src/cli.js CHANGED
@@ -43,6 +43,11 @@ Local editor loop:
43
43
  serve [template_id] [opts] Boot the FULL editor locally (single origin, disk-backed).
44
44
  Records + storage run on disk; render runs in-process on
45
45
  this box for FREE (no cloud, no wallet charge).
46
+ /discover and /library still list the CLOUD catalog —
47
+ opening a cloud template seeds it onto local disk, and
48
+ the editor's Render button can hand off to the cloud
49
+ renderer (needs the cloud --api-key). Only the editor
50
+ and its data are local.
46
51
  With a template_id or --fork, pulls that composition
47
52
  (or the template's default/shared decomposition) from
48
53
  the cloud host onto local disk to edit offline.
@@ -51,8 +56,9 @@ Local editor loop:
51
56
  --key <api-key> Bootstrap/browser key (default: VIDFARM_API_KEY or a dev key)
52
57
  --fork <id> Pull + open a specific cloud fork
53
58
  --host <url> Cloud host to pull from (default: ${DEFAULT_HOST})
54
- --api-key <key> Cloud key for the pull (default: VIDFARM_API_KEY)
59
+ --api-key <key> Cloud key for pulls/library/cloud render (default: VIDFARM_API_KEY)
55
60
  --refetch Overwrite local composition with the cloud copy
61
+ --no-cloud Fully local: no cloud catalog, seeding, or cloud render
56
62
  --no-open Don't auto-open the browser
57
63
  <template_id> [opts] Alias for 'serve <template_id>' (boot the local editor)
58
64
  publish [template_id] Push local composition.html/json to your fork → PUT/PATCH composition + POST versions
@@ -104,8 +110,9 @@ Generate AI media and drop it on the timeline (for local coding agents):
104
110
  --track <n> Timeline layer index (auto if omitted)
105
111
  --x --y --width --height Geometry as % (default full canvas 0/0/100/100)
106
112
  --object-fit <fit> cover|contain|fill|none|scale-down (default cover)
107
- ghostcut <forkId> Read the two video sources: original vs → GET .../compositions/:forkId/ghostcut
108
- decomposed (caption-free), non-billing
113
+ remove-video-captions <forkId> Read the two video sources: → GET .../compositions/:forkId/remove-video-captions
114
+ original vs decomposed (caption-free),
115
+ non-billing (alias: ghostcut)
109
116
  versions <forkId> List immutable version snapshots → GET .../compositions/:forkId/versions
110
117
  snapshot <forkId> Save the working state as a new version → POST .../compositions/:forkId/versions
111
118
  render <forkId> Render the fork to MP4 (--wait to poll) → POST .../compositions/:forkId/render
@@ -244,8 +251,9 @@ async function main() {
244
251
  case "decompose":
245
252
  await runDecomposeCommand(rest);
246
253
  return;
254
+ case "remove-video-captions":
247
255
  case "ghostcut":
248
- await runGhostcutCommand(rest);
256
+ await runRemoveVideoCaptionsCommand(rest);
249
257
  return;
250
258
  case "versions":
251
259
  await runVersionsCommand(rest);
@@ -454,7 +462,10 @@ async function runServeCommand(argv) {
454
462
  share: { type: "string" },
455
463
  refetch: { type: "boolean", default: false },
456
464
  open: { type: "boolean", default: true },
457
- "no-open": { type: "boolean", default: false }
465
+ "no-open": { type: "boolean", default: false },
466
+ // Disable the cloud passthrough entirely: /discover and /library list
467
+ // only local data and the editor offers no "Render in Cloud".
468
+ "no-cloud": { type: "boolean", default: false }
458
469
  }
459
470
  });
460
471
  const port = Number(parsed.values.port);
@@ -476,16 +487,27 @@ async function runServeCommand(argv) {
476
487
  const templateId = parsed.positionals[0];
477
488
  const forkFlag = parsed.values.fork;
478
489
  // Env MUST be set before importing runtime — config.ts reads it at module
479
- // load. Force the fully-local drivers; keep any cloud creds already present
480
- // in the environment so render passthrough still works.
490
+ // load. Force the fully-local drivers.
481
491
  process.env.RECORDS_DRIVER = "local";
482
492
  process.env.STORAGE_DRIVER = "local";
483
493
  process.env.AWS_S3_BUCKET = "";
494
+ // A dev-shell .env can carry the staging Step Functions ARN, which would
495
+ // silently route this box's renders to the cloud state machine. serve is
496
+ // local-render by definition — cloud rendering is the EXPLICIT
497
+ // render_target="cloud" upstream handoff (the editor's "Render in Cloud").
498
+ process.env.VIDFARM_JOB_STATE_MACHINE_ARN = "";
484
499
  process.env.VIDFARM_DATA_DIR = dataDir;
485
500
  process.env.VIDFARM_API_KEY = apiKey;
486
501
  process.env.PORT = String(port);
487
502
  if (!process.env.NODE_ENV)
488
503
  process.env.NODE_ENV = "development";
504
+ // Cloud passthrough: only the editor is local — /discover and /library keep
505
+ // listing the upstream (cloud) catalog, templates seed onto disk on demand,
506
+ // and the editor's Render button can hand off to the cloud renderer. The
507
+ // upstream key is the AMBIENT cloud key (never the local bootstrap key).
508
+ const cloudEnabled = !parsed.values["no-cloud"];
509
+ process.env.VIDFARM_UPSTREAM_HOST = cloudEnabled ? host : "";
510
+ process.env.VIDFARM_UPSTREAM_API_KEY = cloudEnabled ? (cloudApiKey ?? "") : "";
489
511
  const { startRuntime } = await import("./runtime.js");
490
512
  await startRuntime();
491
513
  // If a template/fork was requested, pull its composition from the cloud host
@@ -493,13 +515,14 @@ async function runServeCommand(argv) {
493
515
  // resolves it. Best-effort: a failure just drops us to /discover.
494
516
  let openTemplateId = templateId;
495
517
  let openForkId = forkFlag;
496
- if (templateId || forkFlag) {
518
+ if ((templateId || forkFlag) && !cloudEnabled) {
519
+ console.warn("[vidfarm] serve: --no-cloud set — skipping cloud seed of the requested template/fork.");
520
+ }
521
+ else if (templateId || forkFlag) {
497
522
  try {
498
523
  const seeded = await seedForkFromCloud({
499
- host,
500
524
  templateId,
501
525
  forkId: forkFlag,
502
- cloudApiKey,
503
526
  shareToken: parsed.values.share,
504
527
  bootstrapKey: apiKey,
505
528
  refetch: parsed.values.refetch
@@ -518,105 +541,45 @@ async function runServeCommand(argv) {
518
541
  ? `/editor/${encodeURIComponent(openTemplateId)}${openForkId ? `?fork=${encodeURIComponent(openForkId)}` : ""}`
519
542
  : "/discover";
520
543
  const openUrl = `${base}/auto-login?api_key=${encodeURIComponent(apiKey)}&redirect=${encodeURIComponent(editorPath)}`;
521
- printServeBanner({ base, dataDir, openUrl, editorPath });
544
+ printServeBanner({ base, dataDir, openUrl, editorPath, cloud: cloudEnabled ? { host, hasKey: Boolean(cloudApiKey) } : null });
522
545
  const shouldOpen = parsed.values.open && !parsed.values["no-open"];
523
546
  if (shouldOpen)
524
547
  openInBrowser(openUrl);
525
548
  // startRuntime() keeps the process alive via its HTTP server; nothing else to do.
526
549
  }
527
550
  // Pull a cloud fork's composition onto local disk and create the local
528
- // template + fork records so the editor resolves it. The fork is either an
529
- // explicit --fork or the template's default fork (which may be another user's
530
- // public decomposition). Media stays on cloud URLs only the composition +
531
- // records are localized. Runs in-process after startRuntime(), so it shares the
532
- // server's disk-backed records/storage singletons.
551
+ // template + fork records so the editor resolves it. Thin wrapper over
552
+ // services/upstream.ts seedFromUpstream (which reads VIDFARM_UPSTREAM_HOST/
553
+ // _API_KEY set above from --host/--api-key). Runs in-process after
554
+ // startRuntime(), so it shares the server's disk-backed records/storage.
533
555
  async function seedForkFromCloud(input) {
534
- const { serverlessRecords } = await import("./services/serverless-records.js");
535
- const { StorageService } = await import("./services/storage.js");
536
556
  const { ServerlessAuthService } = await import("./services/serverless-auth.js");
537
- const storage = new StorageService();
538
- const auth = new ServerlessAuthService();
557
+ const { seedFromUpstream } = await import("./services/upstream.js");
539
558
  // Ensure the local bootstrap customer exists and grab its id to own the seed.
540
- const customer = await auth.authenticate(input.bootstrapKey);
541
- const authHeaders = buildAuthHeaders({ apiKey: input.cloudApiKey, shareToken: input.shareToken });
542
- // 1. Resolve the source fork: explicit --fork wins, else the template's
543
- // default fork (grabs the shared decomposition even if another user owns it).
544
- let cloudForkId = input.forkId ?? null;
545
- if (!cloudForkId && input.templateId) {
546
- cloudForkId = await resolveForkId({ host: input.host, templateId: input.templateId, apiKey: input.cloudApiKey, shareToken: input.shareToken });
547
- }
548
- if (!cloudForkId) {
549
- console.warn("[vidfarm] serve: no --fork and no default fork resolvable from cloud; starting empty.");
550
- return null;
551
- }
552
- // 2. Read the serialized fork for its template id + title.
553
- const forkMetaRes = await fetch(`${input.host}/api/v1/compositions/${encodeURIComponent(cloudForkId)}`, { headers: authHeaders });
554
- const forkMeta = forkMetaRes.ok ? (await forkMetaRes.json().catch(() => null)) : null;
555
- const templateId = input.templateId ?? (typeof forkMeta?.template_id === "string" ? forkMeta.template_id : null);
556
- if (!templateId || !templateId.startsWith("template_")) {
557
- console.warn(`[vidfarm] serve: could not determine a template id for fork ${cloudForkId}; starting empty.`);
558
- return null;
559
- }
560
- const title = (typeof forkMeta?.title === "string" && forkMeta.title) || `Local · ${templateId}`;
561
- // 3. Materialize the local template record (the editor 404s without it).
562
- const existingTemplate = await serverlessRecords.getTemplate(templateId);
563
- if (!existingTemplate) {
564
- await serverlessRecords.createTemplate({
565
- id: templateId,
566
- inspirationId: `local:${templateId}`,
567
- customerId: customer.id,
568
- originalUrl: typeof forkMeta?.original_url === "string" ? forkMeta.original_url : "",
569
- sourceHost: "local",
570
- title,
571
- visibility: "public"
572
- });
573
- }
574
- // 4. Materialize the local fork (reuse the cloud id for stable URLs).
575
- const localForkId = cloudForkId;
576
- const existingFork = await serverlessRecords.getCompositionFork(localForkId);
577
- if (!existingFork) {
578
- await serverlessRecords.createCompositionFork({
579
- id: localForkId,
580
- customerId: customer.id,
581
- templateId,
582
- title,
583
- visibility: "private"
584
- });
585
- }
586
- // 5. Pull composition.html/json onto disk (skip if present unless --refetch,
587
- // so local edits aren't clobbered on re-serve).
588
- const htmlKey = storage.compositionForkWorkingKey(localForkId, "composition.html");
589
- const jsonKey = storage.compositionForkWorkingKey(localForkId, "composition.json");
590
- const hasLocalHtml = Boolean(await storage.readText(htmlKey));
591
- if (!hasLocalHtml || input.refetch) {
592
- const htmlRes = await fetch(`${input.host}/api/v1/compositions/${encodeURIComponent(cloudForkId)}/composition.html`, { headers: authHeaders });
593
- if (!htmlRes.ok) {
594
- console.warn(`[vidfarm] serve: could not fetch composition.html for ${cloudForkId} (${htmlRes.status}); starting empty.`);
595
- return null;
596
- }
597
- await storage.putText(htmlKey, await htmlRes.text(), "text/html; charset=utf-8");
598
- const jsonRes = await fetch(`${input.host}/api/v1/compositions/${encodeURIComponent(cloudForkId)}/composition.json`, { headers: authHeaders });
599
- if (jsonRes.ok)
600
- await storage.putBuffer(jsonKey, Buffer.from(await jsonRes.text(), "utf8"), "application/json");
601
- console.log(`[vidfarm] seeded fork ${localForkId} from ${input.host}`);
602
- }
603
- else {
604
- console.log(`[vidfarm] fork ${localForkId} already local (use --refetch to overwrite)`);
605
- }
606
- // 6. Point the template's default fork at the local copy so a bare
607
- // /editor/:templateId resolves it too.
608
- await serverlessRecords.stampDefaultForkIfUnset({ templateId, forkId: localForkId });
609
- return { templateId, forkId: localForkId };
559
+ const customer = await new ServerlessAuthService().authenticate(input.bootstrapKey);
560
+ return seedFromUpstream({
561
+ customerId: customer.id,
562
+ templateId: input.templateId,
563
+ forkId: input.forkId,
564
+ shareToken: input.shareToken,
565
+ refetch: input.refetch
566
+ });
610
567
  }
611
568
  function printServeBanner(input) {
612
569
  const line = `${DIM}${"─".repeat(74)}${RESET}`;
613
570
  console.log("");
614
571
  console.log(line);
615
- console.log(`${BOLD}${GREEN} Vidfarm local server${RESET} ${DIM}(fully local — records + storage on disk)${RESET}`);
572
+ console.log(`${BOLD}${GREEN} Vidfarm local server${RESET} ${DIM}(local editor — records + storage on disk)${RESET}`);
616
573
  console.log(line);
617
574
  console.log(` server ${input.base}`);
618
575
  console.log(` data dir ${input.dataDir}`);
619
- console.log(` render ${DIM}cloud (submitted to the deployed renderer)${RESET}`);
576
+ console.log(` render ${DIM}local (in-process HyperFrames render free, no cloud charge)${RESET}`);
577
+ if (input.cloud) {
578
+ console.log(` cloud ${input.cloud.host} ${DIM}(/discover + /library list the cloud catalog; templates seed locally on open${input.cloud.hasKey ? "; Render can hand off to the cloud renderer" : "; set VIDFARM_API_KEY for /library + cloud render"})${RESET}`);
579
+ }
580
+ else {
581
+ console.log(` cloud ${DIM}off (--no-cloud) — local data only${RESET}`);
582
+ }
620
583
  console.log("");
621
584
  console.log(` ${DIM}Agents: edit composition files under ${input.dataDir}/storage — the`);
622
585
  console.log(` browser live-reloads on save. Multiple forks can be edited at once.${RESET}`);
@@ -1249,18 +1212,18 @@ async function runDecomposeCommand(argv) {
1249
1212
  });
1250
1213
  assertApiOk(result, "decompose");
1251
1214
  if (!ctx.json && result.json?.ghostcut_pending) {
1252
- console.log(`${DIM}GhostCut subtitle-removal is running in the background — poll \`vidfarm api POST /api/v1/compositions/${forkId}/ghostcut-poll\` or GET .../ghostcut until done.${RESET}`);
1215
+ console.log(`${DIM}Subtitle removal (GhostCut) is running in the background — poll \`vidfarm api POST /api/v1/compositions/${forkId}/remove-video-captions-poll\` or GET .../remove-video-captions until done.${RESET}`);
1253
1216
  }
1254
1217
  emitResult(result, ctx.json);
1255
1218
  }
1256
- async function runGhostcutCommand(argv) {
1219
+ async function runRemoveVideoCaptionsCommand(argv) {
1257
1220
  const parsed = parseArgs({ args: argv, allowPositionals: true, options: commonOptions() });
1258
1221
  const forkId = parsed.positionals[0];
1259
1222
  if (!forkId)
1260
- throw new Error("ghostcut requires a fork id.");
1223
+ throw new Error("remove-video-captions requires a fork id.");
1261
1224
  const ctx = commonContext(parsed.values);
1262
- const result = await apiRequest({ method: "GET", host: ctx.host, path: `/api/v1/compositions/${encodeURIComponent(forkId)}/ghostcut`, auth: ctx.auth });
1263
- assertApiOk(result, "ghostcut");
1225
+ const result = await apiRequest({ method: "GET", host: ctx.host, path: `/api/v1/compositions/${encodeURIComponent(forkId)}/remove-video-captions`, auth: ctx.auth });
1226
+ assertApiOk(result, "remove-video-captions");
1264
1227
  emitResult(result, ctx.json);
1265
1228
  }
1266
1229
  async function runVersionsCommand(argv) {