@officexapp/vidfarm-devcli 0.21.43 → 0.21.46

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 (49) hide show
  1. package/.agents/skills/editor-capabilities/SKILL.md +4 -0
  2. package/.agents/skills/vidfarm/SKILL.md +95 -17
  3. package/.agents/skills/vidfarm/harnesses/explainer.HARNESS.md +1 -1
  4. package/.agents/skills/vidfarm/harnesses/product-demo.HARNESS.md +2 -0
  5. package/.agents/skills/vidfarm/harnesses/short-form.HARNESS.md +1 -0
  6. package/.agents/skills/vidfarm/recipes/local-edit-render-approve.md +1 -1
  7. package/.agents/skills/vidfarm/recipes/onboard-a-new-director.md +1 -1
  8. package/.agents/skills/vidfarm/references/agent-included-imagegen.md +75 -0
  9. package/.agents/skills/vidfarm/references/assets-and-sourcing.md +152 -2
  10. package/.agents/skills/vidfarm/references/automation-and-local-dev.md +22 -9
  11. package/.agents/skills/vidfarm/references/browser-harness.md +93 -0
  12. package/.agents/skills/vidfarm/references/content-ideas.md +232 -10
  13. package/.agents/skills/vidfarm/references/core-workflows.md +11 -1
  14. package/.agents/skills/vidfarm/references/editor-workflows.md +39 -0
  15. package/.agents/skills/vidfarm/references/onboarding.md +1 -1
  16. package/.agents/skills/vidfarm/references/primitives.md +51 -0
  17. package/.agents/skills/vidfarm-media/SKILL.md +2 -0
  18. package/SKILL.director.md +775 -42
  19. package/SKILL.md +157 -115
  20. package/crowdsourcing.md +417 -3
  21. package/dist/src/cli.js +750 -34
  22. package/dist/src/devcli/agent-imagegen.js +181 -0
  23. package/dist/src/devcli/browser-harness.js +384 -0
  24. package/dist/src/devcli/clip-store.js +41 -3
  25. package/dist/src/devcli/consult.js +14 -0
  26. package/dist/src/devcli/cost-mode.js +23 -3
  27. package/dist/src/devcli/doctor.js +52 -3
  28. package/dist/src/devcli/hyperframes-cli.js +11 -1
  29. package/dist/src/devcli/local-render.js +4 -7
  30. package/dist/src/devcli/marketplace-gigs.js +623 -0
  31. package/dist/src/devcli/qa-check.js +89 -1
  32. package/dist/src/devcli/shared-folder.js +387 -0
  33. package/dist/src/devcli/skill-docs.js +61 -7
  34. package/dist/src/devcli/stills.js +4 -8
  35. package/dist/src/lib/ffprobe-path.js +64 -0
  36. package/dist/src/lib/render-media-prep.js +2 -11
  37. package/dist/src/services/clip-curation/ffmpeg.js +4 -15
  38. package/dist/src/services/clip-curation/index.js +1 -1
  39. package/dist/src/services/clip-curation/local-agent.js +6 -2
  40. package/dist/src/services/clip-curation/media-select.js +146 -3
  41. package/experimental/google-news-to-video.md +235 -0
  42. package/package.json +8 -150
  43. package/public/assets/file-directory-app.js +35 -35
  44. package/public/assets/homepage-client-app.js +15 -15
  45. package/public/serve-shells/library-files.html +5 -1
  46. package/public/serve-shells/library-raws.html +10 -1
  47. package/public/serve-shells/tools-clipper.html +5 -1
  48. package/public/serve-shells/tools-image.html +5 -1
  49. package/public/serve-shells/tools-video.html +5 -1
@@ -7,7 +7,11 @@
7
7
  // their AI agent up front), then every billed command respects it:
8
8
  // - minimize : ~$0 per video. Never burn AI credits by surprise. Prefer free
9
9
  // local engines; refuse billed cloud/AI ops unless the user
10
- // re-confirms (--yes).
10
+ // re-confirms (--yes). NOTE this does not mean "no AI at all":
11
+ // if the AGENT driving the terminal has image generation included
12
+ // in its own subscription (Antigravity / Gemini CLI, Codex /
13
+ // ChatGPT — Claude Code does not), it should generate the graphic
14
+ // itself for $0 rather than go without. See agent-imagegen.ts.
11
15
  // - hybrid : roughly $0.01–$1 per video. Free where it's free, spend on AI
12
16
  // only where it clearly wins. (default recommendation.) Billed
13
17
  // ops run but print a cost line.
@@ -134,9 +138,15 @@ export const COST_MODE_BLURB = {
134
138
  'For any ICON, STICKER, illustration, 3D prop or Lottie, use vidfarm iconscout "<meaning>" ' +
135
139
  "--free before even considering AI image generation: free IconScout assets cost $0 (a credit " +
136
140
  "line is the only price) and arrive as clean transparent vectors. " +
141
+ "$0 does NOT mean no AI: if YOUR OWN agent subscription already includes image generation " +
142
+ "(Google Antigravity / Gemini CLI, OpenAI Codex / ChatGPT — Claude Code does not, Anthropic " +
143
+ 'ships no image model), generate the graphic yourself — `vidfarm agent-image "<subject>"` ' +
144
+ "prints the prompt, the plate rules and the import command. It is free in minimize. " +
137
145
  "Billed cloud/AI generation is refused unless you re-confirm it (--yes).",
138
146
  hybrid: "Hybrid (recommended) — roughly $0.01–$1 per video. Free where it's free, spend AI " +
139
147
  "credits only where they clearly win (a hero shot, a voice you can't fake locally). " +
148
+ 'If your own agent subscription includes image generation, use it first (`vidfarm agent-image "<subject>"`) — ' +
149
+ "it costs nothing extra and leaves the budget for the shots only Vidfarm can make. " +
140
150
  'Never GENERATE an icon, sticker, illustration or 3D prop — vidfarm iconscout "<meaning>" ' +
141
151
  "buys a designer's finished asset for a fraction of one AI attempt, with no prompt loop. " +
142
152
  "Billed ops run but each prints its cost so nothing is a surprise. Charges land on " +
@@ -171,6 +181,10 @@ export function costModeExplainer() {
171
181
  " frame-by-frame scene generation. Most cinematic, most expensive.",
172
182
  "Any spend is billed to YOUR own AI provider keys (BYOK) — add them with",
173
183
  " `vidfarm add-provider-key <provider> <key>` or at vidfarm.cc/settings/developer.",
184
+ "Even minimize can make custom art: if the AI agent you are talking to has image generation",
185
+ " included in its own subscription (Google Antigravity / Gemini CLI, OpenAI Codex / ChatGPT —",
186
+ " Claude Code does not), it generates the graphic itself for $0 extra. Ask it to run",
187
+ ' `vidfarm agent-image "<subject>" --items "a,b,c"`.',
174
188
  "Tip: before paying to generate music/SFX/images/video, try the free stock catalog —",
175
189
  ' vidfarm media search "<meaning>" --type bgm|sfx|image|vector|icon|video.',
176
190
  " For icons, STICKERS, illustrations, 3D props and Lottie, IconScout beats AI generation on price",
@@ -200,14 +214,20 @@ export class CostModeBlockedError extends Error {
200
214
  * nudge once so the default posture really is "ask before spending."
201
215
  */
202
216
  export function assertBilledAllowed(input) {
203
- const { resolved, yes, json, label, estimate, freeAlternative } = input;
217
+ const { resolved, yes, json, label, estimate, freeAlternative, agentAlternative } = input;
204
218
  const log = input.log ?? ((line) => console.error(line));
205
219
  const cost = estimate ? ` (${estimate})` : "";
206
220
  if (resolved.mode === "minimize" && !yes) {
221
+ const agentAlt = agentAlternative ? `\nDo it yourself for $0: ${agentAlternative}` : "";
207
222
  const alt = freeAlternative ? `\nFree alternative: ${freeAlternative}` : "";
208
223
  throw new CostModeBlockedError(`Blocked by cost mode "minimize": ${label}${cost} spends billed AI credits.\n` +
209
224
  `Confirm the spend with the user, then re-run with --yes (or switch modes: ` +
210
- `vidfarm cost-mode hybrid).${alt}`);
225
+ `vidfarm cost-mode hybrid).${agentAlt}${alt}`);
226
+ }
227
+ // Not blocked, but still worth saying: a capability the agent already pays for
228
+ // beats one Vidfarm bills for, in every mode below rich-ai.
229
+ if (!json && agentAlternative && (resolved.mode === "hybrid" || !resolved.isSet)) {
230
+ log(`[cost] Cheaper first: ${agentAlternative}`);
211
231
  }
212
232
  if (json)
213
233
  return;
@@ -8,6 +8,7 @@
8
8
  // unconditionally at session start.
9
9
  import { spawnSync } from "node:child_process";
10
10
  import { existsSync, readdirSync } from "node:fs";
11
+ import { createRequire } from "node:module";
11
12
  import net from "node:net";
12
13
  import { homedir } from "node:os";
13
14
  import path from "node:path";
@@ -17,6 +18,7 @@ import { hasFfmpeg, resolveFfmpeg, resolveFfprobe } from "../services/clip-curat
17
18
  import { resolveHyperframesCli } from "./hyperframes-cli.js";
18
19
  import { applyVidfarmStudioBrand } from "./studio-brand.js";
19
20
  import { resolveSkillsRoot } from "./skills.js";
21
+ import { browserHarnessDoctorCheck } from "./browser-harness.js";
20
22
  import { readStoredAuth } from "./auth-store.js";
21
23
  import { scanLocalServers, reapProcesses } from "./process-scan.js";
22
24
  const GREEN = "\x1b[32m";
@@ -47,6 +49,24 @@ function isPortInUse(port) {
47
49
  server.listen(port, "127.0.0.1");
48
50
  });
49
51
  }
52
+ // Windows installs Chrome/Edge under one of three roots depending on whether it
53
+ // was a per-machine or per-user install. Without these the check ALWAYS reported
54
+ // "no Chrome" on Windows, and agents went off installing a browser the user
55
+ // already had. Edge is included because it is Chromium and always present.
56
+ function windowsChromeCandidates() {
57
+ const roots = [
58
+ process.env["PROGRAMFILES"],
59
+ process.env["PROGRAMFILES(X86)"],
60
+ process.env.LOCALAPPDATA
61
+ ].filter((value) => Boolean(value?.trim()));
62
+ const relative = [
63
+ ["Google", "Chrome", "Application", "chrome.exe"],
64
+ ["Google", "Chrome Beta", "Application", "chrome.exe"],
65
+ ["Chromium", "Application", "chrome.exe"],
66
+ ["Microsoft", "Edge", "Application", "msedge.exe"]
67
+ ];
68
+ return roots.flatMap((root) => relative.map((parts) => path.join(root, ...parts)));
69
+ }
50
70
  // Best-effort Chrome availability for the in-process HyperFrames render:
51
71
  // explicit env overrides, the puppeteer download cache, or a system Chrome.
52
72
  function detectChromeForRender() {
@@ -66,7 +86,9 @@ function detectChromeForRender() {
66
86
  }
67
87
  const systemCandidates = process.platform === "darwin"
68
88
  ? ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "/Applications/Chromium.app/Contents/MacOS/Chromium"]
69
- : ["/usr/bin/google-chrome", "/usr/bin/chromium", "/usr/bin/chromium-browser"];
89
+ : process.platform === "win32"
90
+ ? windowsChromeCandidates()
91
+ : ["/usr/bin/google-chrome", "/usr/bin/chromium", "/usr/bin/chromium-browser"];
70
92
  for (const candidate of systemCandidates) {
71
93
  if (existsSync(candidate))
72
94
  return { found: true, detail: candidate };
@@ -154,6 +176,11 @@ export async function runDoctorCommand(argv) {
154
176
  // 4. Chrome for the in-process render (stills / serve local render).
155
177
  const chrome = detectChromeForRender();
156
178
  add("chrome", chrome.found ? "ok" : "warn", chrome.found ? chrome.detail : `${chrome.detail} — local render/stills will try to download one on first run`);
179
+ // 4b. browser-harness — OPTIONAL, and the only free substitute for the paid
180
+ // search/download primitives. Reported even when absent because a free-plan
181
+ // user who doesn't know it exists gets a 402 instead of footage.
182
+ const browserHarness = browserHarnessDoctorCheck();
183
+ add("browser control", browserHarness.level, browserHarness.detail);
157
184
  // 5. Vidfarm cloud auth — --api-key / env, else the persisted `vidfarm login`
158
185
  // (auth-store), which is how most users authenticate. Without the store
159
186
  // lookup a logged-in user got a false "VIDFARM_API_KEY not set" warning.
@@ -175,9 +202,31 @@ export async function runDoctorCommand(argv) {
175
202
  add("provider keys", presentKeys.length > 0 ? "ok" : "warn", presentKeys.length > 0
176
203
  ? presentKeys.join(", ")
177
204
  : "none of OPENAI/GEMINI/OPENROUTER/ELEVENLABS_API_KEY set — BYOK speech/clip tagging unavailable (keyless local engines still work)");
178
- // 7. Local agent CLI (claude / codex) for clips scan etc.
205
+ // 7. Local agent CLI (claude / codex) for clips scan etc. On Windows the CLI
206
+ // is a .cmd shim and the scan passes a multi-line prompt as an argv, which a
207
+ // cmd.exe command line cannot carry — so report the limit rather than
208
+ // claiming a path that fails at use time.
179
209
  const agent = detectLocalAgent();
180
- add("agent CLI", agent ? "ok" : "warn", agent ? `${agent.kind} (${agent.bin})` : "no claude/codex CLI on PATH — `clips scan` falls back to provider keys");
210
+ if (agent && process.platform === "win32") {
211
+ add("agent CLI", "warn", `${agent.kind} found (${agent.bin}) but agent-driven \`clips scan\` is not supported on Windows yet — use provider keys (OPENAI/GEMINI_API_KEY)`);
212
+ }
213
+ else {
214
+ add("agent CLI", agent ? "ok" : "warn", agent ? `${agent.kind} (${agent.bin})` : "no claude/codex CLI on PATH — `clips scan` falls back to provider keys");
215
+ }
216
+ // 7b. The local clip library rides on the OPTIONAL native module
217
+ // better-sqlite3. It is optional precisely because a Windows box with no C++
218
+ // toolchain cannot build it — report that here instead of letting
219
+ // `vidfarm clips` be the thing that discovers it.
220
+ try {
221
+ createRequire(import.meta.url)("better-sqlite3");
222
+ add("clip library", "ok", "better-sqlite3 native module loaded (`vidfarm clips` available)");
223
+ }
224
+ catch {
225
+ add("clip library", "warn", "optional native module better-sqlite3 is not built — only `vidfarm clips` is affected; everything else works. " +
226
+ (process.platform === "win32"
227
+ ? "To enable it, install \"Desktop development with C++\" from the Visual Studio Installer, then reinstall the devcli."
228
+ : "To enable it, install a C++ toolchain (macOS: xcode-select --install; Linux: apt install build-essential python3), then reinstall the devcli."));
229
+ }
181
230
  // 8. Poisoned-env traps.
182
231
  if (process.env.AWS_PROFILE?.trim()) {
183
232
  add("env AWS_PROFILE", "warn", `AWS_PROFILE=${process.env.AWS_PROFILE} is set — it can hijack AWS SDK auth; run \`env -u AWS_PROFILE\` or unset it`);
@@ -74,11 +74,21 @@ export async function runHyperframesCommand(subcommand, args, opts = {}) {
74
74
  const [bin, baseArgs] = cli
75
75
  ? [process.execPath, [cli]]
76
76
  : ["npx", ["-y", "hyperframes"]];
77
+ // On Windows `npx` is `npx.cmd`, and Node >= 20.12 refuses to spawn a
78
+ // .cmd/.bat without a shell (it throws EINVAL, which surfaced here as the
79
+ // misleading "npx unavailable" error below). Route the FALLBACK through a
80
+ // shell there. The primary path spawns process.execPath directly and needs
81
+ // no shell on any platform, so this never touches the normal case.
82
+ const useShell = !cli && process.platform === "win32";
83
+ // A shell re-parses the command line, so quote anything with whitespace
84
+ // (project paths under "C:\Users\Some Name\..." are the common case).
85
+ const quote = (value) => (useShell && /[\s"&|<>^]/.test(value) ? `"${value.replace(/"/g, '\\"')}"` : value);
77
86
  const capture = opts.stdio === "capture";
78
87
  return new Promise((resolvePromise, rejectPromise) => {
79
- const child = spawn(bin, [...baseArgs, subcommand, ...args], {
88
+ const child = spawn(bin, [...baseArgs, subcommand, ...args].map(quote), {
80
89
  cwd: opts.cwd,
81
90
  env,
91
+ shell: useShell,
82
92
  stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit"
83
93
  });
84
94
  let stdout = "";
@@ -19,6 +19,7 @@ import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
19
19
  import os from "node:os";
20
20
  import path from "node:path";
21
21
  import { prepareProjectMediaForRender } from "../lib/render-media-prep.js";
22
+ import { resolveBundledFfprobe } from "../lib/ffprobe-path.js";
22
23
  import { runHyperframesCommand } from "./hyperframes-cli.js";
23
24
  import { normalizeTikTokCaptionLayout } from "./composition-edit.js";
24
25
  // Same invariant as the backend's forceEvenCompositionDimensions: libx264
@@ -53,13 +54,9 @@ async function producerFfmpegEnv() {
53
54
  catch { /* PATH fallback */ }
54
55
  }
55
56
  if (!process.env.HYPERFRAMES_FFPROBE_PATH?.trim()) {
56
- try {
57
- const mod = (await import("ffprobe-static"));
58
- const resolved = (mod.path ?? mod.default?.path);
59
- if (typeof resolved === "string" && resolved && existsSync(resolved))
60
- env.HYPERFRAMES_FFPROBE_PATH = resolved;
61
- }
62
- catch { /* PATH fallback */ }
57
+ const resolved = resolveBundledFfprobe();
58
+ if (resolved)
59
+ env.HYPERFRAMES_FFPROBE_PATH = resolved;
63
60
  }
64
61
  return env;
65
62
  }