@officexapp/vidfarm-devcli 0.21.45 → 0.21.47
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/.agents/skills/editor-capabilities/SKILL.md +2 -0
- package/.agents/skills/vidfarm/SKILL.md +60 -7
- package/.agents/skills/vidfarm/harnesses/explainer.HARNESS.md +1 -1
- package/.agents/skills/vidfarm/harnesses/product-demo.HARNESS.md +2 -0
- package/.agents/skills/vidfarm/harnesses/short-form.HARNESS.md +1 -0
- package/.agents/skills/vidfarm/recipes/local-edit-render-approve.md +1 -1
- package/.agents/skills/vidfarm/references/agent-included-imagegen.md +75 -0
- package/.agents/skills/vidfarm/references/assets-and-sourcing.md +71 -2
- package/.agents/skills/vidfarm/references/automation-and-local-dev.md +13 -6
- package/.agents/skills/vidfarm/references/browser-harness.md +93 -0
- package/.agents/skills/vidfarm/references/editor-workflows.md +22 -0
- package/SKILL.director.md +337 -16
- package/SKILL.md +45 -4
- package/dist/src/cli.js +210 -4
- package/dist/src/devcli/agent-imagegen.js +181 -0
- package/dist/src/devcli/browser-harness.js +384 -0
- package/dist/src/devcli/clip-store.js +41 -3
- package/dist/src/devcli/cost-mode.js +23 -3
- package/dist/src/devcli/doctor.js +52 -3
- package/dist/src/devcli/hyperframes-cli.js +11 -1
- package/dist/src/devcli/local-render.js +4 -7
- package/dist/src/devcli/marketplace-gigs.js +651 -0
- package/dist/src/devcli/qa-check.js +89 -1
- package/dist/src/devcli/shared-folder.js +387 -0
- package/dist/src/devcli/stills.js +4 -8
- package/dist/src/lib/ffprobe-path.js +64 -0
- package/dist/src/lib/render-media-prep.js +2 -11
- package/dist/src/services/clip-curation/ffmpeg.js +4 -15
- package/dist/src/services/clip-curation/local-agent.js +6 -2
- package/experiments.md +2 -2
- package/marketplace.md +549 -0
- package/package.json +21 -10
- package/public/assets/file-directory-app.js +34 -34
- package/public/serve-shells/library-files.html +5 -1
- package/public/serve-shells/library-raws.html +10 -1
- package/public/serve-shells/tools-clipper.html +5 -1
- package/public/serve-shells/tools-image.html +5 -1
- package/public/serve-shells/tools-video.html +5 -1
- package/crowdsourcing.md +0 -157
package/SKILL.md
CHANGED
|
@@ -14,13 +14,36 @@ This page is the router. It holds the setup, one worked example, the standards,
|
|
|
14
14
|
```bash
|
|
15
15
|
npm i -g @officexapp/vidfarm-devcli # `vidfarm` — wraps every REST route
|
|
16
16
|
npm i -g hyperframes # Vidfarm's own render engine (whitelabel; reach it via `vidfarm hf`)
|
|
17
|
-
brew install ffmpeg # or apt install ffmpeg — required
|
|
18
17
|
vidfarm login <email> # one-time email code; or --api-key <key>, or VIDFARM_API_KEY
|
|
19
18
|
vidfarm doctor # verifies vidfarm + ffmpeg + hyperframes + Chrome
|
|
20
19
|
vidfarm skills add vidfarm # install the full director skill on disk — do this
|
|
21
20
|
vidfarm serve # free local editor + render loop at localhost:3000
|
|
21
|
+
vidfarm browser setup # optional: drive the user's own Chrome — FREE footage sourcing
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
**Image generation you already pay for is free — check before you spend or go without.** If the agent driving this terminal includes image generation in its own subscription (Google Antigravity / Gemini CLI, OpenAI Codex / ChatGPT — **Claude Code does not**, Anthropic ships no image model), generating a graphic bills Vidfarm $0 and the provider $0 extra. That makes it legal in cost mode `minimize`, with no `--yes`. `vidfarm agent-image --check` answers "do I have it here?"; `vidfarm agent-image "<subject>" --items "a,b,c"` prints the prompt, the key-plate rules and the cut + import commands. Free stock and IconScout still come first. Full page: `references/agent-included-imagegen.md`.
|
|
25
|
+
|
|
26
|
+
**`vidfarm browser setup` is the one optional install worth offering unprompted.** It installs [browser-harness](https://github.com/browser-use/browser-harness), which attaches you to the user's running Chrome over CDP. That makes `vidfarm browse videos|images|news|page "<query>"` a **$0 substitute for the paid `video-search` / `image-search` / `news-search` / `download-video` primitives** — the routes a free-plan user otherwise hits a 402 on. Offer it to every free-plan user and everyone in cost mode `minimize`, ask before installing (it drives their personal browser), and read `references/browser-harness.md` before the first browse.
|
|
27
|
+
|
|
28
|
+
**Do not install ffmpeg first.** The devcli bundles `ffmpeg-static` and a per-platform
|
|
29
|
+
ffprobe, so ffmpeg is already there on macOS, Linux, and Windows x64. Run `vidfarm doctor`
|
|
30
|
+
and install a system ffmpeg **only if it reports ffmpeg missing** (`brew install ffmpeg`,
|
|
31
|
+
`apt install ffmpeg`, `winget install Gyan.FFmpeg`).
|
|
32
|
+
|
|
33
|
+
**Windows** — the two things worth knowing before the first install:
|
|
34
|
+
|
|
35
|
+
- Use **PowerShell**, not Git Bash or cmd. Node >= 22 is required (`winget install OpenJS.NodeJS.LTS`).
|
|
36
|
+
- If the install is slow, exclude the npm folders from Defender's real-time scan. It scans
|
|
37
|
+
every extracted file, which dominates first-run setup time:
|
|
38
|
+
```powershell
|
|
39
|
+
Add-MpPreference -ExclusionPath "$env:APPDATA\npm", "$env:APPDATA\npm-cache", "$env:LOCALAPPDATA\npm-cache"
|
|
40
|
+
```
|
|
41
|
+
- `better-sqlite3` is an **optional** native module. If it fails to build, that is not a broken
|
|
42
|
+
install — only `vidfarm clips` (the local clip library) is unavailable. Everything else,
|
|
43
|
+
including local render, works. To enable it, install "Desktop development with C++" from
|
|
44
|
+
the Visual Studio Installer and reinstall.
|
|
45
|
+
- Windows on ARM has no prebuilt ffmpeg/ffprobe. Install a system ffmpeg and put it on PATH.
|
|
46
|
+
|
|
24
47
|
Work in **one folder per brand or offer** (`~/vidfarm/<brand>/`). Run every command from it, or pass `--dir`. Strategy documents, `STORYBOARD.md`, `brand-assets/`, `raws/` and `renders/` all land there, so a session weeks later reads the history back instead of re-interviewing the user.
|
|
25
48
|
|
|
26
49
|
**If that folder already exists, read `CONTEXT.md` and `OFFER.md` before you ask the user anything.**
|
|
@@ -66,9 +89,11 @@ vidfarm publish <forkId> # push edits back to th
|
|
|
66
89
|
| "Give me a consultation" | the `brainstorm/*` chain: cold-start → awareness stages → angles → hooks. No AI key: `vidfarm consult` prints the prompt for **you** to answer, $0 | `references/onboarding.md` |
|
|
67
90
|
| "Find a template and start" | `vidfarm templates search` → `fork` → `pull` | `references/core-workflows.md`, `recipes/find-and-fork-template.md` |
|
|
68
91
|
| "Change / re-theme this video" | timeline edits, decompose, captions | `references/editor-workflows.md`, `recipes/retheme-template.md` |
|
|
69
|
-
| "Find footage / a clip of X" | public raws → own library → `vidfarm
|
|
92
|
+
| "Find footage / a clip of X" | public raws → own library → `vidfarm browse videos "<the shot>"` (free, your Chrome) or `vidfarm video-search` (paid, $0.0003/call) → generate last | `references/assets-and-sourcing.md` |
|
|
93
|
+
| "Make a graphic / sticker / illustration" in cost mode `minimize` | free stock → IconScout → `vidfarm mask` → **generate it with YOUR OWN image tool if this subscription includes one** (Antigravity / Gemini CLI, Codex / ChatGPT — Claude Code has none): `vidfarm agent-image "<subject>"`. $0, and no `--yes` needed | `references/agent-included-imagegen.md` |
|
|
94
|
+
| A free plan / a 402 / cost mode `minimize` on any search or download | `vidfarm browser setup`, then `vidfarm browse videos\|images\|news\|page "<q>"`. Never answer a sourcing ask with "that needs a paid plan." | `references/browser-harness.md` |
|
|
70
95
|
| "Make a video about what just happened" | two stages: `vidfarm news-search "<topic>" --fresh w` for the STORY, then `video-search` for the VISUALS | `vidfarm.cc/experimental/google-news-to-video.md` |
|
|
71
|
-
| "Download this video from `<url>`" | `vidfarm download-video <url>` (paid). Free plan gets a 402 —
|
|
96
|
+
| "Download this video from `<url>`" | `vidfarm download-video <url>` (paid). Free plan gets a 402 — `vidfarm browse page "<url>"` and save it from their Chrome yourself, else have them download it, then `vidfarm put-file`. Never answer "I can't." | `references/browser-harness.md` |
|
|
72
97
|
| "Turn this thread / subreddit / profile into a video" | `vidfarm recycle <source>` — returns the raw decomposition, unranked; you pick the hook (paid) | `references/assets-and-sourcing.md` |
|
|
73
98
|
| "Create an avatar / spokesperson / talking head" | `vidfarm avatar "<who>" --say "<line>"` — a greenscreen talking-head video, keyed in the same job | `references/primitives.md` |
|
|
74
99
|
| "TTS / music / captions / background removal" | the primitive catalog | `references/primitives.md` |
|
|
@@ -101,12 +126,26 @@ AI charges go to the user's own provider keys (`vidfarm add-provider-key`), not
|
|
|
101
126
|
|
|
102
127
|
Two consequences worth stating out loud: `minimize + interactive` still gets custom art, for $0. `minimize + autonomous` gets none. Voice samples (`vidfarm voices --sample`, `--free --sample`) are free on both tiers — offer them either way.
|
|
103
128
|
|
|
129
|
+
## 5b. Production has phases — plan, collect, build
|
|
130
|
+
|
|
131
|
+
**Do not open the timeline before you know what footage you have.** Building to a shot you assumed existed is the most expensive mistake available: you either pay to generate it or rewrite a beat you already built. Four phases, in order — plan the shot list (`vidfarm storyboard --init`), collect assets for **every** beat in one pass, build, then review and cut.
|
|
132
|
+
|
|
133
|
+
The collection phase is where the cost mode actually bites:
|
|
134
|
+
|
|
135
|
+
- **`minimize`** — collection *is* the job, and being cheap is not being worse. Work the ladder: `public-raws --categories` → `media search` / `iconscout --free` → `raws search` (what they already own) → **browser control** (`vidfarm browse videos "<the shot>"`, $0) → mine it with `raws scan` / `clipper`. One long source cut eight ways beats one generated clip.
|
|
136
|
+
- **`minimize` + `interactive`** — buy quality with the user's hands, not their wallet. Direct them like an editor: hand over the shot list and let them pick clips themselves (`vidfarm handoff raws`), and hand over ONE prompt for a free web image generator to get a whole sticker sheet back (`vidfarm handoff image` → `vidfarm sticker-pack`). Both beat anything autonomous, at $0.
|
|
137
|
+
- **`hybrid`** — collect free first, then spend on the gaps only. AI image generation for the hero graphic, `vidfarm avatar` for a presenter; keep AI *video* for beats nothing static can carry.
|
|
138
|
+
- **`rich-ai` / `pure-videogen`** — collection becomes generation, and moves earlier. `rich-ai` mints reusable greenscreen raws that get keyed once and saved to the library; `pure-videogen` runs script → storyboard stills → scene-by-scene (`vidfarm sequence`). Even here, search what already exists before generating it.
|
|
139
|
+
|
|
140
|
+
Say the phase out loud when you switch. Deciding to source mid-build is how a $0 video turns into a $3 one.
|
|
141
|
+
|
|
104
142
|
## 6. Standards — these override your defaults
|
|
105
143
|
|
|
106
144
|
The standards themselves are not optional. `vidfarm qa <dir>` is — it is a free local checker for most of them, feedback rather than a gate. Nothing calls it, skipping it is fine, and it allows one fix round by default. **Watching the render is the review that counts.** Full reasoning: `references/hooks-and-virality.md` and `references/reviewing-renders.md`.
|
|
107
145
|
|
|
108
146
|
- **Write the four charges before the timeline.** Hook: first line is a complete clause naming a situation, on screen at `start:0`. Loop: one open question by 0:10, closing inside this video. Payoff: shown, not summarized. Bait: one ask, final beat. Banned openers — throat-clearing, a logo, a title card, a fade from black.
|
|
109
147
|
- **No HTML slop.** Test: could you have made this element inside TikTok's own editor? If you reached past that — a padded capsule, border, gradient fill, blur panel, card, CTA "button", benefit chips, feature grid — cut it. Nothing in a video is clickable. Emphasize with size, weight, caps, an accent colour, or a drawn mark.
|
|
148
|
+
- **No layout templates — judge the whole frame.** The stack is the tell, not the box: headline + subheadline + CTA centred in a well is a landing page even with every border, fill and capsule stripped off. Banned at frame level — a modal/dialog floating over a dimmed or blurred backdrop, a full-frame wash used to stage a floating block, nav/hero/feature-row sections, a blurred website screenshot as the background plate, document margins. Unstack it into time: hook at t=0, support line on the next cut, CTA spoken or a bare caption. Are you arranging words relative to each other, or relative to the picture? Two text runs at once is the ceiling.
|
|
110
149
|
- **Captions**: imported display font (Montserrat 700–900 default), ~36–64px on a 1080 frame, inside the 8%–85% safe zone, and within that band placed in the **emptiest part of the frame**. Long narration pages into 3–5-word cues. Exactly one of four backgrounds: `outline`, `plain`, active-word `spotlight`/`karaoke`, or a tight `highlight-solid` band.
|
|
111
150
|
- **The first frame is the thumbnail.** A real visual and the hook words at `start:0`. No fade-up, no entrance transition on the first clip. Check with `vidfarm stills <dir> --at 0`.
|
|
112
151
|
- **Cut ruthlessly.** First assembly is 30–50% too long. Delete every beat that the video survives without, then ripple the hole closed. Length is an output, not a target.
|
|
@@ -140,6 +179,8 @@ Otherwise fetch `https://vidfarm.cc/skill-pack/vidfarm/files/<path>`. Load one f
|
|
|
140
179
|
| `references/core-workflows.md` | discovery, auth, fork/publish/share, cost spectrum, dedupe |
|
|
141
180
|
| `references/editor-workflows.md` | timeline editing, decompose, captions, the replication harnesses *(largest file)* |
|
|
142
181
|
| `references/assets-and-sourcing.md` | Google search for footage, raws hunts, My Files, recurring characters, downloads |
|
|
182
|
+
| `references/agent-included-imagegen.md` | free custom art — image generation the AGENT's own subscription already includes, and why cost mode `minimize` allows it |
|
|
183
|
+
| `references/browser-harness.md` | free-plan sourcing and cost mode `minimize` — driving the user's Chrome as the $0 substitute for the paid search/download primitives |
|
|
143
184
|
| `references/automation-and-local-dev.md` | REST + devcli command table, scripting mode, the local serve loop |
|
|
144
185
|
| `references/hooks-and-virality.md` | before writing any hook, caption script, or re-theme |
|
|
145
186
|
| `references/reviewing-renders.md` | before reporting a video as done |
|
|
@@ -150,4 +191,4 @@ Otherwise fetch `https://vidfarm.cc/skill-pack/vidfarm/files/<path>`. Load one f
|
|
|
150
191
|
| `recipes/*.md` | `find-and-fork-template` · `retheme-template` · `local-edit-render-approve` · `onboard-a-new-director` · `bulk-scripting-with-a-harness` · `cutout-graphics-for-explainers` |
|
|
151
192
|
| `harnesses/README.md` | anything harness-shaped — start here. Bases: `short-form` · `hooks` · `ugc-testimonial` · `explainer` · `product-demo` · `product-explainer` |
|
|
152
193
|
|
|
153
|
-
Also served at `vidfarm.cc`: `/experiments.md` (ad testing), `/
|
|
194
|
+
Also served at `vidfarm.cc`: `/experiments.md` (ad testing), `/marketplace.md` (producing a batch with gigworkers), `/update.md` (upgrade runbook), `/experimental` (methods under live testing), `/skill/vidfarm-platform` (architecture), `/skill/hyperframes` (composition-authoring craft — route broad "make me a video" asks here first).
|
package/dist/src/cli.js
CHANGED
|
@@ -32,11 +32,14 @@ import { runSkillsCommand } from "./devcli/skills.js";
|
|
|
32
32
|
import { AmbiguousDocRef, DEFAULT_PACK, bundledPackDir, listPackDocs, listPackTopics, loadAngleBank, loadAwarenessLadder, loadIdeaBank, readPackDoc, readPackTopic, resolvePackTopic, searchPackDocs } from "./devcli/skill-docs.js";
|
|
33
33
|
import { initTelemetry, reportCliCrash } from "./devcli/telemetry.js";
|
|
34
34
|
import { resolveLocalDataDir, localBackendAvailable, LocalModeUnavailableError, localApiRequest } from "./devcli/local-backend.js";
|
|
35
|
+
import { NativeModuleUnavailableError } from "./devcli/clip-store.js";
|
|
35
36
|
import { startLocalFrontendServer, serveShellsPresent } from "./devcli/local-frontend-server.js";
|
|
36
37
|
import { readStoredAuth, writeStoredAuth, clearStoredAuth, hostsMatch } from "./devcli/auth-store.js";
|
|
37
38
|
import { CostModeBlockedError, assertBilledAllowed, clearStoredCostMode, costModeExplainer, costModeSummaryLine, normalizeCostMode, resolveCostMode, writeStoredCostMode, COST_MODE_BLURB, COST_MODE_DISPLAY_LIST, costModeDisplayName } from "./devcli/cost-mode.js";
|
|
38
39
|
import { INTERACTION_MODES, INTERACTION_MODE_BLURB, clearStoredInteractionMode, interactionModeExplainer, interactionModeSummaryLine, interactiveOfferLine, normalizeInteractionMode, resolveInteractionMode, writeStoredInteractionMode } from "./devcli/interaction-mode.js";
|
|
39
40
|
import { buildImageHandoff, buildRawsHandoff, formatHandoff } from "./devcli/handoff.js";
|
|
41
|
+
import { AGENT_IMAGEGEN_ALTERNATIVE, KNOWN_HOST_AGENTS, buildAgentImageBrief, detectHostAgent, formatAgentImageBrief } from "./devcli/agent-imagegen.js";
|
|
42
|
+
import { runBrowserHarnessCommand, runBrowseCommand } from "./devcli/browser-harness.js";
|
|
40
43
|
import { buildConsultBrief, CONSULT_ARTIFACTS, consultContextState, consultCountRange, defaultConsultCount, findOfferFile, formatConsultBrief, looksLikeOfferPath, planConsultation, resolveConsultStep, resolveOfferPath } from "./devcli/consult.js";
|
|
41
44
|
import { resolveRootFileCandidates } from "./lib/package-root.js";
|
|
42
45
|
import { STORYBOARD_FILENAME, readStoryboard, renderStoryboardScaffold, storyboardStage } from "./devcli/storyboard.js";
|
|
@@ -121,7 +124,31 @@ Account (persisted login — points the CLI + \`serve\` at cloud prod):
|
|
|
121
124
|
A manual clip-sourcing brief: what to search, how to
|
|
122
125
|
download (a downloader SEARCH, not a rotting link), and
|
|
123
126
|
the vidfarm clipper / raws scan follow-up. Try browser control
|
|
124
|
-
or "vidfarm raws scan" first.
|
|
127
|
+
("vidfarm browse", below) or "vidfarm raws scan" first.
|
|
128
|
+
agent-image "<subject>" [--items "a,b,c"] [--single] [--out ./sheet.png]
|
|
129
|
+
FREE CUSTOM ART — image generation YOUR OWN agent
|
|
130
|
+
subscription already includes. Antigravity / Gemini CLI
|
|
131
|
+
(Nano Banana / Imagen) and Codex / ChatGPT (gpt-image)
|
|
132
|
+
include one; Claude Code does NOT (Anthropic ships no
|
|
133
|
+
image model). Prints the prompt, the key-plate rules and
|
|
134
|
+
the cut + import commands. Vidfarm bills nothing and the
|
|
135
|
+
provider bills nothing extra, so it is allowed in EVERY
|
|
136
|
+
cost mode — minimize included.
|
|
137
|
+
--check (or no args) = is it included here? --json
|
|
138
|
+
(aliases: agent-imagegen, own-image, native-image)
|
|
139
|
+
browser [status|setup|doctor] FREE BROWSER SOURCING — set up browser-harness so I can
|
|
140
|
+
drive YOUR Chrome myself. It substitutes for the PAID
|
|
141
|
+
video-search / image-search / news-search / download-video
|
|
142
|
+
primitives at $0, on your own logged-in session and IP.
|
|
143
|
+
setup = install via uv + register the skill + the one
|
|
144
|
+
Chrome step (chrome://inspect) you must do once.
|
|
145
|
+
status = what's installed · doctor = connection check.
|
|
146
|
+
Suggest this to every free-plan user before saying "I can't".
|
|
147
|
+
browse <videos|images|news|page> "<query|url>"
|
|
148
|
+
Mint the browse recipe for one sourcing job: the Google
|
|
149
|
+
surface to open, what to pull off the page, and the vidfarm
|
|
150
|
+
command it feeds. --run pipes it straight into browser-harness,
|
|
151
|
+
--json for an agent, --legacy for the old tbm=… params.
|
|
125
152
|
consult [step] THE CONSULTATION / BRAINSTORM CHAIN, KEYLESS AND LOCAL.
|
|
126
153
|
The cloud runs these as brainstorm/* primitives that need
|
|
127
154
|
a provider key or wallet credits. This prints the IDENTICAL
|
|
@@ -1127,6 +1154,15 @@ Marketplace (paid, cloud-only — the bazaar never renders locally):
|
|
|
1127
1154
|
directory share-update <token> --mode/--label/--disable/--enable → PATCH /api/v1/user/me/directory/shares/:token
|
|
1128
1155
|
directory unshare <token> Delete a share link for good → DELETE /api/v1/user/me/directory/shares/:token
|
|
1129
1156
|
(alias: dir · save-url|from-url|import-url — CLI twin of the "Save to Files" picker)
|
|
1157
|
+
gigs <sub> Your vending machines, BOTH sides (client + gigworker)
|
|
1158
|
+
machines · tasks · add-task · proofs · approve · reject · ring-bell (client, paid)
|
|
1159
|
+
work · feed · join-feed · join · claim · submit · mine (gigworker, free — bring DOLLARPLATOON_API_KEY)
|
|
1160
|
+
e.g. vidfarm gigs add-task --task "60s explainer for acme.com" --price 0.50 --upload-link <share url>
|
|
1161
|
+
vidfarm gigs proofs --status pending · vidfarm gigs approve PRF_01H…
|
|
1162
|
+
(see: vidfarm gigs help)
|
|
1163
|
+
shared <sub> <link> USE a link someone shared with you — NO account, NO API key
|
|
1164
|
+
info · ls · search · mkdir · put · get e.g. vidfarm shared put <link> clip.mp4 --subfolder batch-01
|
|
1165
|
+
(the gigworker/agent side of directory share; see: vidfarm shared help)
|
|
1130
1166
|
put-file / get-file / files / annotate-file are the My Files (persistent) set;
|
|
1131
1167
|
upload is the throwaway temp store for dropping media into a composition.
|
|
1132
1168
|
Annotate assets you'll want back — esp. recurring characters, kept under
|
|
@@ -1165,6 +1201,12 @@ Cost spectrum (default to the cheapest approach that works; see SKILL.director.m
|
|
|
1165
1201
|
In minimize AND hybrid, 'vidfarm tts' DEFAULTS to the free local Kokoro voice — ask for
|
|
1166
1202
|
a premium voice (--style/--voice/--provider/--own-key/--cloud), or be in rich-ai /
|
|
1167
1203
|
pure-videogen, to opt out.
|
|
1204
|
+
minimize is NOT "no AI images". If the agent driving this terminal has image generation
|
|
1205
|
+
included in its own subscription (Google Antigravity / Gemini CLI, OpenAI Codex /
|
|
1206
|
+
ChatGPT — Claude Code does NOT, Anthropic ships no image model), it generates the
|
|
1207
|
+
graphic itself: nothing is billed by Vidfarm and nothing extra by the provider, so it
|
|
1208
|
+
is allowed in EVERY mode. 'vidfarm agent-image --check' answers "do I have it?", and
|
|
1209
|
+
'vidfarm agent-image "<subject>" --items "a,b,c"' prints the prompt + cut/import steps.
|
|
1168
1210
|
|
|
1169
1211
|
Escape hatch — call ANY route directly:
|
|
1170
1212
|
api <METHOD> <path> Raw REST call with auth + pretty errors
|
|
@@ -1477,6 +1519,23 @@ async function main() {
|
|
|
1477
1519
|
case "hand-off":
|
|
1478
1520
|
await runHandoffCommand(rest);
|
|
1479
1521
|
return;
|
|
1522
|
+
// Image generation the AGENT already pays for — free in every cost mode.
|
|
1523
|
+
case "agent-image":
|
|
1524
|
+
case "agent-imagegen":
|
|
1525
|
+
case "own-image":
|
|
1526
|
+
case "native-image":
|
|
1527
|
+
await runAgentImageCommand(rest);
|
|
1528
|
+
return;
|
|
1529
|
+
// Free browser sourcing — the agent drives the user's own Chrome instead of
|
|
1530
|
+
// paying for video-search / image-search / news-search / download-video.
|
|
1531
|
+
case "browser":
|
|
1532
|
+
case "browser-harness":
|
|
1533
|
+
case "bh":
|
|
1534
|
+
await runBrowserHarnessCommand(rest);
|
|
1535
|
+
return;
|
|
1536
|
+
case "browse":
|
|
1537
|
+
await runBrowseCommand(rest);
|
|
1538
|
+
return;
|
|
1480
1539
|
// The brainstorm chain with no AI key: the prompt goes to the agent that is
|
|
1481
1540
|
// already here, not to a provider. "consultation" is the director's word.
|
|
1482
1541
|
case "consult":
|
|
@@ -1547,6 +1606,15 @@ async function main() {
|
|
|
1547
1606
|
case "market":
|
|
1548
1607
|
await runMarketplaceCommand(rest);
|
|
1549
1608
|
return;
|
|
1609
|
+
// Both sides of the vending machines: a paid client posting tasks and
|
|
1610
|
+
// reviewing proofs, and a FREE gigworker with their own dollarplatoon key.
|
|
1611
|
+
case "gigs":
|
|
1612
|
+
case "gig":
|
|
1613
|
+
case "vending": {
|
|
1614
|
+
const { runGigsCommand } = await import("./devcli/marketplace-gigs.js");
|
|
1615
|
+
await runGigsCommand(rest);
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1550
1618
|
case "get-file":
|
|
1551
1619
|
await runGetFileCommand(rest);
|
|
1552
1620
|
return;
|
|
@@ -1561,6 +1629,15 @@ async function main() {
|
|
|
1561
1629
|
case "dir":
|
|
1562
1630
|
await runDirectoryCommand(rest);
|
|
1563
1631
|
return;
|
|
1632
|
+
// The VISITOR side of a share link — no account, no API key. A gigworker or
|
|
1633
|
+
// their agent works a folder someone else shared with them.
|
|
1634
|
+
case "shared":
|
|
1635
|
+
case "shared-folder":
|
|
1636
|
+
case "dropbox": {
|
|
1637
|
+
const { runSharedCommand } = await import("./devcli/shared-folder.js");
|
|
1638
|
+
await runSharedCommand(rest);
|
|
1639
|
+
return;
|
|
1640
|
+
}
|
|
1564
1641
|
case "migrate-local": {
|
|
1565
1642
|
if (!localBackendAvailable())
|
|
1566
1643
|
throw new LocalModeUnavailableError();
|
|
@@ -1866,6 +1943,7 @@ function guardBilled(ctx, input) {
|
|
|
1866
1943
|
json: ctx.json,
|
|
1867
1944
|
label: input.label,
|
|
1868
1945
|
estimate: input.estimate,
|
|
1946
|
+
agentAlternative: input.agentAlternative,
|
|
1869
1947
|
freeAlternative: input.freeAlternative
|
|
1870
1948
|
? `${input.freeAlternative}${interactiveNote}`
|
|
1871
1949
|
: (interactiveNote ? interactiveNote.trimStart() : undefined)
|
|
@@ -2664,6 +2742,7 @@ Rules:
|
|
|
2664
2742
|
- For replacement graphics, screenshots, or still-like scenes, prefer AI image generation plus Ken Burns before paying for AI video unless static_vs_pivot says motion footage is load-bearing.
|
|
2665
2743
|
- If narration must be customized, default to premium ElevenLabs first, then the user's own ElevenLabs path, then BYOK OpenAI/Gemini/OpenRouter. If captions or scenes were timed to the old VO, retime them to the new narration.
|
|
2666
2744
|
- NO HTML SLOP. You are editing HTML, but the output is a social video, not a web page. THE TEST IS THE NATIVE-EDITOR TEST: could you have made this element with the tools inside TikTok's own editor? That toolset is a font, a color, a stroke/outline, a soft shadow, a tight text box, alignment, opacity, rotation, animation presets — plus stickers, emoji, drawn marks and clips. It has NO padded capsule, NO border, NO gradient fill, NO blur panel, NO card. If you reached past it, cut it. Never author landing-page furniture: CTA "buttons" (a filled/gradient rounded capsule with action copy like "Sign Up for a Free Trial →"), benefit chip/badge rows ("✓ No Credit Card Needed"), bordered/shadowed/frosted cards holding a headline + URL, gradient text fills, feature grids, bulleted lists, or web-default fonts (Inter/Roboto/Arial/system-ui). AND NOT A SINGLE PILL EITHER: one lonely rounded, padded, filled capsule around a static stat or label — "10 hrs / week", "STEP 2", "EP.01", "+40%" — is a web badge, and being the only one on screen does not make it native. The ONLY legitimate capsule in a video is the active-word spotlight/karaoke caption highlight, because it moves with the spoken word. Emphasize a stat the way the editor would: bigger, heavier, ALL-CAPS, an accent color, a hand-drawn circle or underline, or its own beat on screen. Rule of thumb on anything holding words: border-radius over ~8px PLUS a background fill PLUS padding = a badge; drop the fill or drop the radius until the band hugs the glyphs. None of this appears in a real TikTok, and nothing in a video is clickable — say it as timed text on the footage instead. Arrows, scribble/underline marks, italics, ALL-CAPS, single-word color pops, emoji, transparent cut-out stickers, and mock social UI (iMessage bubbles, comment cards) are all fine. Captions use an imported family (Montserrat default / TikTok Sans / Abel / Source Code Pro / Yesteryear) at weight 700-900, ~36-64px on a 1080-wide frame, inside the 8%-85% safe zone, with exactly one of four backgrounds: outline, plain, an active-word spotlight/karaoke pill, or a tight-hugging solid band (radius <=8px, no border/shadow/gradient/blur).
|
|
2745
|
+
- NO LAYOUT TEMPLATES — JUDGE THE WHOLE FRAME, NOT JUST THE ELEMENT. Every rule above judges one element, and a frame can pass element-by-element and still be a web page. The archetype is the MODAL: the backdrop dimmed and blurred out of focus, and floating on top of it a rounded bordered box holding a big headline, a smaller support line, and a fat CTA button. THE STACK IS THE TELL, NOT THE BOX — delete the border, the fill and the capsule, keep headline then subheadline then CTA centred in a well with even margins, and it STILL reads as a landing page, because a viewer recognizes the SHAPE before reading a single word. Banned at frame level: a modal/dialog staged on top of a backdrop that has been dimmed, blurred, greyed or scaled back (nothing in a video pops "above" the video); the hero triplet and its cousins (title + kicker + logo lockup, question + answer + URL); a full-frame dark wash used to stage a floating block (a legibility band on ONE caption is legal, a page-wide wash to stage a panel is not; likewise a blurred backdrop is fine alone — a blurred fill behind a 16:9 clip in a 9:16 frame is a real technique — but blur PLUS dimming is modal staging); nav strip / hero / three-up feature row / testimonial block / footer fine print; a blurred website screenshot used as the background plate (if the backdrop is a web page, the frame is a screen recording of a web page — show the real product UI full-bleed and in focus, or don't show it); a centred content column with even gutters and document margins. THE FIX IS ALWAYS TO UNSTACK IT INTO TIME: the headline is the hook at start:0, the support line lands on the next cut, the CTA is SPOKEN or a bare caption on the final frame. You lose nothing — a viewer reads one line at a time anyway — and you gain the pacing that makes it look shot rather than designed. Self-check before you place any text group: am I arranging words relative to EACH OTHER, or relative to the PICTURE? Relative to each other is a layout, which is web. Two on-screen text runs at once is the ceiling. Verify on real pixels: \`vidfarm stills . --at <t>\` — if the still could be a screenshot of a website, rebuild the beat. \`vidfarm qa\` catches only the mechanical half (layout-template, modal-scrim); the frame-level judgement is yours.
|
|
2667
2746
|
- STRUCTURE BEFORE POLISH — THE FOUR CHARGES, WRITTEN BEFORE YOU TOUCH THE TIMELINE. Most agent-made videos fail on structure, not polish, because the timeline is the fun part so it gets built first and the words get retrofitted. Invert it: (1) HOOK — write the opening line as text first: a complete clause (subject + verb), no jargon, naming a SITUATION ("I've quit six businesses") not a label ("anonymity"); it goes on screen at start:0, because caption chunk 1 is read before any audio and muted autoplay is the default. Banned openings: throat-clearing ("so I was thinking", "here's the thing"), a logo, a title card, a fade from black, context before the claim. (2) LOOP — one open question by 0:10, said ON SCREEN, closing INSIDE this video (state the timestamp it closes at; if you can't, there is no loop), and the withheld answer must be one the viewer CANNOT supply themselves — a formally-correct loop with a guessable answer passes every mechanical check and dies in the field. (3) PAYOFF — shown, not summarized, ≥5 uninterrupted seconds, landing BEFORE the final beat; the payoff is not the CTA. (4) BAIT — one ask in the final beat and in the post caption; a keyword comment ask ("comment CLIPPER and I'll send the breakdown") is standard and allowed, but never "follow for part two", ragebait, or an earnings/health claim traded for the reply. Then build the timeline. Re-theming a decomposed template: viral_dna already names the source's hook/retention/payoff — rebuild each charge for the new subject, never flatten the loop into a product statement. Full craft harness: the vidfarm skill's references/hooks-and-virality.md. Checkable form: \`vidfarm harness show hooks\`.
|
|
2668
2747
|
- ORIENT THE COLD VIEWER IN THE FIRST 3 SECONDS — THE VIEWER HAS NO CONTEXT AND DID NOT CHOOSE THIS VIDEO. Distinct from the hook: the hook makes them WANT to watch, orientation makes the watching POSSIBLE. A stranger mid-scroll must be able to answer three things by ~3s — what am I looking at (the CATEGORY noun), who is it for, and why is this on my screen (the situation). The failure is not a bad first frame, it is a good video that BEGINS AT BEAT TWO, and the author cannot see it because the author already knows what the thing is. Signatures, each a rebuild not a polish: a pronoun with no referent ("it just works", "this changes everything", "here's how they do it"); starting at step three (the process already running, the dashboard already full); a metaphor whose subject only lands at 6s; insider vocabulary, a product's own feature name, or an ACRONYM in the first line; a detail crop that reads as texture until you know the whole. Instead, the opening beat is BOTH channels at once: an EASY IMAGE (one large subject, already moving, legible at a glance and at thumbnail scale — a relevant die-cut sticker names the category before a word is read) AND an EASY LINE (first spoken sentence one clause, <=12 words, everyday words, concrete noun + verb, no subordinate clause, brand name said once plainly, and the CATEGORY named: "X is a language app that…"). Give the SITUATION, not the label — "the end of the month, and your receipts are in a shoebox" orients, "expense automation" does not. THIS IS NOT AN INTRO AND COSTS NO EXTRA SECONDS: it replaces the wind-up sentence, it never precedes it, and it never licenses a logo, a title card or a fade from black. Test it on the render, not the script: play the first 3 seconds ONLY to somebody with no context and stop — they should say what kind of thing it is and roughly who it is for. "Something about audio" is a fail. Fullest form: \`vidfarm harness show product-explainer\` (Rule 0).
|
|
2669
2748
|
- THE FIRST FRAME IS THE THUMBNAIL. Frame 0 is one frame of ~30 in the first second, but every feed card, share link, and paused player freezes on it — more people see that frame than watch the video. It must never be black, empty, mid-fade, or mid-animation: a real visual at start:0 (\`vidfarm retime . --layer <key> --start 0\`), the hook words already on screen at t=0, and NO entrance transition on the FIRST clip (\`vidfarm transitions set . --layer <key> --in none\`; junction transitions between later clips are fine). Look at the actual pixels before you render: \`vidfarm stills . --at 0\`.
|
|
@@ -4682,6 +4761,7 @@ async function runGenerateCommand(argv) {
|
|
|
4682
4761
|
: {
|
|
4683
4762
|
label: "AI image generation",
|
|
4684
4763
|
estimate: "cheap, ~$0.01–$0.05",
|
|
4764
|
+
agentAlternative: AGENT_IMAGEGEN_ALTERNATIVE,
|
|
4685
4765
|
freeAlternative: 'free stock image/vector — vidfarm media search "<meaning>" --type image|vector ($0). ' +
|
|
4686
4766
|
"Openverse (CC images) is keyless and always on — check it first; a free Pixabay key adds " +
|
|
4687
4767
|
"photos/vectors and may already be saved (check vidfarm provider-keys). " +
|
|
@@ -4933,7 +5013,11 @@ async function runInpaintCommand(argv) {
|
|
|
4933
5013
|
}
|
|
4934
5014
|
});
|
|
4935
5015
|
const ctx = commonContext(parsed.values);
|
|
4936
|
-
guardBilled(ctx, {
|
|
5016
|
+
guardBilled(ctx, {
|
|
5017
|
+
label: "AI image inpaint",
|
|
5018
|
+
estimate: "cheap, ~$0.01–$0.05",
|
|
5019
|
+
agentAlternative: AGENT_IMAGEGEN_ALTERNATIVE
|
|
5020
|
+
});
|
|
4937
5021
|
const sourceArg = parsed.values.source ?? parsed.positionals[0];
|
|
4938
5022
|
if (!sourceArg)
|
|
4939
5023
|
throw new Error("inpaint requires a source image: `vidfarm inpaint <image|url> --mask <mask.png> --prompt \"...\"`.");
|
|
@@ -5069,7 +5153,11 @@ async function runCreateOverlayCommand(argv) {
|
|
|
5069
5153
|
}
|
|
5070
5154
|
});
|
|
5071
5155
|
const ctx = commonContext(parsed.values);
|
|
5072
|
-
guardBilled(ctx, {
|
|
5156
|
+
guardBilled(ctx, {
|
|
5157
|
+
label: "AI transparent overlay generation",
|
|
5158
|
+
estimate: "cheap, ~$0.01–$0.05",
|
|
5159
|
+
agentAlternative: AGENT_IMAGEGEN_ALTERNATIVE
|
|
5160
|
+
});
|
|
5073
5161
|
const prompt = (parsed.values.prompt ?? parsed.positionals.join(" ")).trim();
|
|
5074
5162
|
if (!prompt) {
|
|
5075
5163
|
throw new Error("create-overlay requires a subject prompt: `vidfarm create-overlay \"a cartoon rocket ship\" [--key-color #00FF00] [--out overlay.png]`. Describe ONLY the subject — the flat key-color background is added for you.");
|
|
@@ -6150,6 +6238,7 @@ async function runCutoutCommand(argv) {
|
|
|
6150
6238
|
guardBilled(ctx, {
|
|
6151
6239
|
label: "AI image generation (cutout plate)",
|
|
6152
6240
|
estimate: "cheap, ~$0.01–$0.05",
|
|
6241
|
+
agentAlternative: AGENT_IMAGEGEN_ALTERNATIVE,
|
|
6153
6242
|
freeAlternative: "pass an existing graphic instead — `vidfarm cutout <image|url>` keys+trims for $0.00",
|
|
6154
6243
|
interactiveAlternative: 'vidfarm handoff image --theme "<subject>" --single — the user generates the plate in a free web tool ' +
|
|
6155
6244
|
"and hands the PNG back; `vidfarm cutout <file>` then keys + trims it for $0"
|
|
@@ -6699,6 +6788,7 @@ async function runStickerPackCommand(argv) {
|
|
|
6699
6788
|
guardBilled(ctx, {
|
|
6700
6789
|
label: `AI image generation (sticker sheet of ${count} items)`,
|
|
6701
6790
|
estimate: "cheap, ~$0.01–$0.05 for the WHOLE pack (one image job, not one per sticker)",
|
|
6791
|
+
agentAlternative: AGENT_IMAGEGEN_ALTERNATIVE,
|
|
6702
6792
|
freeAlternative: "pass a greenscreen sheet you already have — `vidfarm sticker-pack <sheet.png>` cuts it up for $0.00",
|
|
6703
6793
|
interactiveAlternative: `vidfarm handoff image --theme "${generatePrompt.replace(/"/g, "'")}"${itemNames.length ? ` --items "${itemNames.join(",")}"` : ""} — ` +
|
|
6704
6794
|
"the user generates the SAME sheet in a free web tool (often better art than the API tier) and hands it " +
|
|
@@ -9478,6 +9568,15 @@ async function runCostModeCommand(argv) {
|
|
|
9478
9568
|
if (resolved.mode === "minimize") {
|
|
9479
9569
|
console.log(`${DIM}In minimize, ${interaction.mode === "interactive" ? "you're already on" : "offer"} the sweet spot: minimize + interactive = $0 videos that still get custom art (free web image gen → vidfarm sticker-pack) and hand-picked clips (vidfarm handoff raws).${RESET}`);
|
|
9480
9570
|
}
|
|
9571
|
+
// The one exception worth naming out loud: image generation the AGENT already
|
|
9572
|
+
// owns is free custom art with NO manual step, so minimize keeps it.
|
|
9573
|
+
if (resolved.mode === "minimize" || resolved.mode === "hybrid") {
|
|
9574
|
+
const detection = detectHostAgent();
|
|
9575
|
+
const verdict = detection.host
|
|
9576
|
+
? `${detection.host.name} — image generation ${detection.availability}`
|
|
9577
|
+
: "host agent not detected";
|
|
9578
|
+
console.log(`${DIM}Image generation included in YOUR agent's own subscription is free in every mode, minimize included (${verdict}). Check: ${BOLD}vidfarm agent-image --check${RESET}${DIM} · brief: vidfarm agent-image "<subject>".${RESET}`);
|
|
9579
|
+
}
|
|
9481
9580
|
}
|
|
9482
9581
|
// `vidfarm storyboard [dir]` — the PLAN pass, before any animation work.
|
|
9483
9582
|
// Storyboarding is a first-class part of the composition format now: a project
|
|
@@ -10029,6 +10128,106 @@ async function runHandoffCommand(argv) {
|
|
|
10029
10128
|
}
|
|
10030
10129
|
throw new Error('handoff needs a kind: `vidfarm handoff image --theme "…" --items "a,b,c"` (free web image gen → sticker pack) or `vidfarm handoff raws --keywords "…"` (manual clip sourcing).');
|
|
10031
10130
|
}
|
|
10131
|
+
// `vidfarm agent-image "<subject>"` — the brief for image generation the AGENT
|
|
10132
|
+
// runs on its OWN subscription. Vidfarm charges nothing and the provider charges
|
|
10133
|
+
// nothing extra, so this rung is allowed in EVERY cost mode, `minimize`
|
|
10134
|
+
// included. Antigravity / Gemini CLI and Codex / ChatGPT include an image tool;
|
|
10135
|
+
// Claude Code does not (Anthropic ships no image model) — those runs fall back
|
|
10136
|
+
// to stock, IconScout, a human hand-off, or a confirmed billed generation.
|
|
10137
|
+
async function runAgentImageCommand(argv) {
|
|
10138
|
+
const parsed = parseArgs({
|
|
10139
|
+
args: argv,
|
|
10140
|
+
allowPositionals: true,
|
|
10141
|
+
options: {
|
|
10142
|
+
...commonOptions(),
|
|
10143
|
+
theme: { type: "string" },
|
|
10144
|
+
items: { type: "string" },
|
|
10145
|
+
style: { type: "string" },
|
|
10146
|
+
"key-color": { type: "string" },
|
|
10147
|
+
"out-dir": { type: "string" },
|
|
10148
|
+
out: { type: "string" },
|
|
10149
|
+
folder: { type: "string" },
|
|
10150
|
+
grid: { type: "string" },
|
|
10151
|
+
single: { type: "boolean", default: false },
|
|
10152
|
+
zoned: { type: "boolean", default: false },
|
|
10153
|
+
check: { type: "boolean", default: false }
|
|
10154
|
+
}
|
|
10155
|
+
});
|
|
10156
|
+
const json = Boolean(parsed.values.json);
|
|
10157
|
+
const detection = detectHostAgent();
|
|
10158
|
+
// `--check` (and a bare invocation) answers only "do I have this at all?".
|
|
10159
|
+
if (parsed.values.check || (!parsed.values.theme && !parsed.values.items && !parsed.positionals.length)) {
|
|
10160
|
+
if (json) {
|
|
10161
|
+
return printJson({
|
|
10162
|
+
ok: true,
|
|
10163
|
+
host: detection.host?.id ?? null,
|
|
10164
|
+
host_name: detection.host?.name ?? null,
|
|
10165
|
+
availability: detection.availability,
|
|
10166
|
+
matched_env: detection.matched,
|
|
10167
|
+
known_hosts: KNOWN_HOST_AGENTS.map((h) => ({ id: h.id, name: h.name, availability: h.availability, note: h.note }))
|
|
10168
|
+
});
|
|
10169
|
+
}
|
|
10170
|
+
console.log(`${BOLD}Agent-included image generation${RESET}`);
|
|
10171
|
+
console.log(`${DIM}Vidfarm does not need to sell you an image model if the agent driving this terminal already has one.${RESET}\n`);
|
|
10172
|
+
if (detection.host) {
|
|
10173
|
+
const flag = detection.availability === "included" ? GREEN : detection.availability === "none" ? YELLOW : DIM;
|
|
10174
|
+
console.log(`Detected: ${flag}${detection.host.name}${RESET} — image generation ${BOLD}${detection.availability}${RESET}`);
|
|
10175
|
+
console.log(`${DIM}${detection.host.note}${RESET}`);
|
|
10176
|
+
console.log(`${DIM}Matched env: ${detection.matched.join(", ")}${RESET}\n`);
|
|
10177
|
+
}
|
|
10178
|
+
else {
|
|
10179
|
+
console.log(`${DIM}Host agent not detected from the environment.${RESET}\n`);
|
|
10180
|
+
}
|
|
10181
|
+
for (const h of KNOWN_HOST_AGENTS) {
|
|
10182
|
+
console.log(` ${h.availability === "included" ? GREEN + "✓" : h.availability === "none" ? YELLOW + "✗" : DIM + "?"}${RESET} ${h.name} ${DIM}— ${h.availability}${RESET}`);
|
|
10183
|
+
}
|
|
10184
|
+
console.log(`\n${DIM}The env check is a hint only. The authority is your own tool list — if you have an image tool, you have this.${RESET}`);
|
|
10185
|
+
console.log(`${DIM}Brief: ${BOLD}vidfarm agent-image "<subject>" --items "a,b,c"${RESET}${DIM} · free in EVERY cost mode, minimize included.${RESET}`);
|
|
10186
|
+
return;
|
|
10187
|
+
}
|
|
10188
|
+
const splitList = (raw) => (raw ?? "").split(/\s*[;,]\s*/).map((s) => s.trim()).filter(Boolean);
|
|
10189
|
+
const theme = parsed.values.theme?.trim() || parsed.positionals.join(" ").trim();
|
|
10190
|
+
const items = splitList(parsed.values.items);
|
|
10191
|
+
if (!theme && !items.length) {
|
|
10192
|
+
throw new Error('agent-image needs a subject: `vidfarm agent-image "cozy farm props" --items "barn,tractor,hay bale"`.');
|
|
10193
|
+
}
|
|
10194
|
+
const brief = buildAgentImageBrief({
|
|
10195
|
+
theme: theme || items.join(", "),
|
|
10196
|
+
items,
|
|
10197
|
+
style: parsed.values.style,
|
|
10198
|
+
keyColor: parsed.values["key-color"],
|
|
10199
|
+
outDir: parsed.values["out-dir"],
|
|
10200
|
+
outFile: parsed.values.out,
|
|
10201
|
+
folder: parsed.values.folder,
|
|
10202
|
+
grid: parsed.values.grid,
|
|
10203
|
+
pack: parsed.values.single ? false : undefined,
|
|
10204
|
+
zoned: Boolean(parsed.values.zoned),
|
|
10205
|
+
detection
|
|
10206
|
+
});
|
|
10207
|
+
if (json) {
|
|
10208
|
+
return printJson({
|
|
10209
|
+
ok: true,
|
|
10210
|
+
host: detection.host?.id ?? null,
|
|
10211
|
+
availability: brief.availability,
|
|
10212
|
+
out_file: brief.outFile,
|
|
10213
|
+
prompt: brief.prompt,
|
|
10214
|
+
steps: brief.steps,
|
|
10215
|
+
follow_up: brief.followUp,
|
|
10216
|
+
fallbacks: brief.fallbacks,
|
|
10217
|
+
key_color: brief.keyColor,
|
|
10218
|
+
key_color_note: brief.keyColorNote
|
|
10219
|
+
});
|
|
10220
|
+
}
|
|
10221
|
+
if (detection.availability === "none") {
|
|
10222
|
+
console.log(`${YELLOW}${BOLD}This host has no image tool of its own — read the fallbacks at the bottom first.${RESET}`);
|
|
10223
|
+
console.log(`${DIM}The prompt is still below: it is the same prompt for a human hand-off or a billed generation.${RESET}\n`);
|
|
10224
|
+
}
|
|
10225
|
+
else {
|
|
10226
|
+
console.log(`${BOLD}Generate this yourself — it is already in your subscription.${RESET}`);
|
|
10227
|
+
console.log(`${DIM}Costs $0 on Vidfarm and $0 extra on the provider, so it is allowed in cost mode minimize.${RESET}\n`);
|
|
10228
|
+
}
|
|
10229
|
+
console.log(formatAgentImageBrief(brief, detection));
|
|
10230
|
+
}
|
|
10032
10231
|
// `vidfarm consult [step]` — the consultation / brainstorm chain, run KEYLESS
|
|
10033
10232
|
// and LOCAL. The cloud version of each step is a `brainstorm/*` primitive that
|
|
10034
10233
|
// needs a provider key or wallet credits; this prints the identical prompt for
|
|
@@ -12843,7 +13042,14 @@ async function runUpdateSkillCommand(argv) {
|
|
|
12843
13042
|
void main().catch(async (error) => {
|
|
12844
13043
|
// Deliberate, expected user-facing conditions (e.g. local mode in the
|
|
12845
13044
|
// published cloud-only CLI) print just the message — no stack, no crash report.
|
|
12846
|
-
if (error instanceof LocalModeUnavailableError
|
|
13045
|
+
if (error instanceof LocalModeUnavailableError
|
|
13046
|
+
|| error instanceof CostModeBlockedError
|
|
13047
|
+
// A missing OPTIONAL native module (better-sqlite3 with no C++ toolchain,
|
|
13048
|
+
// the common Windows case) is an environment fact, not a vidfarm bug.
|
|
13049
|
+
|| error instanceof NativeModuleUnavailableError
|
|
13050
|
+
// marketplace-gigs is imported lazily, so match its "no key yet" error by
|
|
13051
|
+
// name rather than pulling the module into the startup path just for this.
|
|
13052
|
+
|| (error instanceof Error && error.name === "GigsAuthMissingError")) {
|
|
12847
13053
|
console.error(error.message);
|
|
12848
13054
|
process.exit(1);
|
|
12849
13055
|
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// Agent-included image generation — the $0 rung between "free stock" and "pay
|
|
2
|
+
// Vidfarm to generate it".
|
|
3
|
+
//
|
|
4
|
+
// The premise: Vidfarm does not need to broker an image model when the agent
|
|
5
|
+
// driving the terminal ALREADY has one included in its own subscription. Google
|
|
6
|
+
// Antigravity / Gemini CLI ship image generation (Nano Banana / Imagen) at no
|
|
7
|
+
// extra charge. OpenAI Codex / ChatGPT ship gpt-image. Claude does not — there
|
|
8
|
+
// is no Anthropic image model, so Claude Code has nothing to fall back on here.
|
|
9
|
+
//
|
|
10
|
+
// That distinction is the whole feature. In cost mode `minimize` the old answer
|
|
11
|
+
// to "I need a graphic" was: free stock, IconScout, or hand the human a prompt.
|
|
12
|
+
// If the agent's own runtime includes image generation, there is a better answer
|
|
13
|
+
// that is still $0 — the agent generates the file itself and imports it. Same
|
|
14
|
+
// house pattern as `vidfarm consult`: the devcli writes the brief, the agent in
|
|
15
|
+
// the terminal executes it. See references/agent-included-imagegen.md.
|
|
16
|
+
//
|
|
17
|
+
// Availability is asserted by the AGENT, not sniffed by us. Env detection here
|
|
18
|
+
// is a hint for the opening line only; the authoritative check is the agent
|
|
19
|
+
// looking at its own tool list. Never claim a capability the agent has to prove.
|
|
20
|
+
//
|
|
21
|
+
// Backend-free (Node built-ins + pure sibling modules) so it ships in the public
|
|
22
|
+
// cloud-only package.
|
|
23
|
+
import { buildImageHandoff } from "./handoff.js";
|
|
24
|
+
/**
|
|
25
|
+
* Hosts we can say something concrete about. Kept deliberately short: a wrong
|
|
26
|
+
* "yes" costs the user a wasted turn, a wrong "no" costs them money, so anything
|
|
27
|
+
* we are not sure of stays `unknown` and the agent checks its own tools.
|
|
28
|
+
*/
|
|
29
|
+
export const KNOWN_HOST_AGENTS = [
|
|
30
|
+
{
|
|
31
|
+
id: "claude-code",
|
|
32
|
+
name: "Claude Code",
|
|
33
|
+
availability: "none",
|
|
34
|
+
envMarkers: ["CLAUDECODE", "CLAUDE_CODE", "CLAUDE_CODE_ENTRYPOINT"],
|
|
35
|
+
note: "Anthropic ships no image model, so there is nothing included here. Use free stock / IconScout, hand the user a prompt (`vidfarm handoff image`), or spend on `vidfarm generate image`."
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "antigravity",
|
|
39
|
+
name: "Google Antigravity",
|
|
40
|
+
availability: "included",
|
|
41
|
+
tool: "the built-in Gemini image generation (Nano Banana / Imagen)",
|
|
42
|
+
envMarkers: ["ANTIGRAVITY", "ANTIGRAVITY_SESSION", "ANTIGRAVITY_WORKSPACE"],
|
|
43
|
+
note: "Image generation is part of the Gemini subscription — generating a graphic costs $0 extra."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "gemini-cli",
|
|
47
|
+
name: "Gemini CLI",
|
|
48
|
+
availability: "included",
|
|
49
|
+
tool: "the built-in Gemini image generation (Nano Banana / Imagen)",
|
|
50
|
+
envMarkers: ["GEMINI_CLI", "GEMINI_CLI_SESSION", "GEMINI_SANDBOX"],
|
|
51
|
+
note: "Image generation is part of the Gemini subscription — generating a graphic costs $0 extra."
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "codex",
|
|
55
|
+
name: "OpenAI Codex",
|
|
56
|
+
availability: "included",
|
|
57
|
+
tool: "the built-in OpenAI image generation (gpt-image)",
|
|
58
|
+
envMarkers: ["CODEX_SANDBOX", "CODEX_HOME", "CODEX_CLI"],
|
|
59
|
+
note: "Image generation is part of the ChatGPT/Codex subscription — generating a graphic costs $0 extra."
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "opencode",
|
|
63
|
+
name: "OpenCode",
|
|
64
|
+
availability: "unknown",
|
|
65
|
+
envMarkers: ["OPENCODE", "OPENCODE_SESSION"],
|
|
66
|
+
note: "Depends entirely on which model is configured — check your own tool list."
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "cursor",
|
|
70
|
+
name: "Cursor",
|
|
71
|
+
availability: "unknown",
|
|
72
|
+
envMarkers: ["CURSOR_TRACE_ID", "CURSOR_SESSION_ID"],
|
|
73
|
+
note: "Depends on the selected model — check your own tool list."
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
/**
|
|
77
|
+
* Guess which agent runtime is driving this terminal from its env markers.
|
|
78
|
+
* A miss is normal and harmless — `availability: "unknown"` just means the brief
|
|
79
|
+
* asks the agent to check its own tools instead of asserting anything.
|
|
80
|
+
*/
|
|
81
|
+
export function detectHostAgent(env = process.env) {
|
|
82
|
+
for (const host of KNOWN_HOST_AGENTS) {
|
|
83
|
+
const matched = host.envMarkers.filter((k) => {
|
|
84
|
+
const v = env[k];
|
|
85
|
+
return typeof v === "string" && v.trim() !== "" && v.trim() !== "0" && v.trim().toLowerCase() !== "false";
|
|
86
|
+
});
|
|
87
|
+
if (matched.length)
|
|
88
|
+
return { host, matched, availability: host.availability };
|
|
89
|
+
}
|
|
90
|
+
return { host: null, matched: [], availability: "unknown" };
|
|
91
|
+
}
|
|
92
|
+
/** One line naming this rung, for cost-mode block messages and help text. */
|
|
93
|
+
export const AGENT_IMAGEGEN_ALTERNATIVE = "generate it YOURSELF for $0 if your own agent subscription includes image generation " +
|
|
94
|
+
"(Google Antigravity / Gemini CLI and OpenAI Codex / ChatGPT do; Claude Code does NOT — " +
|
|
95
|
+
'Anthropic ships no image model) — run `vidfarm agent-image "<subject>" --items "a,b,c"` for ' +
|
|
96
|
+
"the prompt, the plate rules and the import command, then `vidfarm put-file` the result";
|
|
97
|
+
/** The shorter form used inside prose blurbs. */
|
|
98
|
+
export const AGENT_IMAGEGEN_SHORT = 'if YOUR agent subscription includes image generation (Gemini/Antigravity, Codex/ChatGPT — not Claude), generate it yourself: `vidfarm agent-image "<subject>"`';
|
|
99
|
+
/**
|
|
100
|
+
* Build the brief the AGENT executes itself. The prompt body is shared verbatim
|
|
101
|
+
* with `vidfarm handoff image` (`buildImageHandoff`) — a plate that keys cleanly
|
|
102
|
+
* and art that survives the cut are the same craft whoever runs the generator —
|
|
103
|
+
* only the STEPS change, because here the runner is the agent, not the human.
|
|
104
|
+
*/
|
|
105
|
+
export function buildAgentImageBrief(input) {
|
|
106
|
+
const base = buildImageHandoff(input);
|
|
107
|
+
const detection = input.detection ?? detectHostAgent();
|
|
108
|
+
const items = input.items.map((s) => s.trim()).filter(Boolean);
|
|
109
|
+
const pack = input.pack ?? items.length > 1;
|
|
110
|
+
const outDir = input.outDir ?? "./stickers";
|
|
111
|
+
const outFile = input.outFile ?? (pack ? "./sheet.png" : "./art.png");
|
|
112
|
+
const folderFlag = input.folder ? ` --folder ${input.folder}` : "";
|
|
113
|
+
const cutCmd = pack
|
|
114
|
+
? `vidfarm sticker-pack ${outFile}${items.length ? ` --items "${items.join(",")}"` : ""} --out-dir ${outDir}`
|
|
115
|
+
: `vidfarm cutout ${outFile}`;
|
|
116
|
+
const steps = [
|
|
117
|
+
"Check YOUR OWN tool list for an image-generation tool included in this subscription — " +
|
|
118
|
+
"Antigravity / Gemini CLI have one (Nano Banana / Imagen), Codex / ChatGPT have one (gpt-image), " +
|
|
119
|
+
"Claude Code has none. If you have none, use the fallbacks below instead; do not pretend.",
|
|
120
|
+
`Generate the image with that tool using the prompt below, and save it to ${outFile}. ` +
|
|
121
|
+
"This spends nothing on Vidfarm and nothing extra on the provider — it is already in the subscription.",
|
|
122
|
+
"Look at the result before you use it: a flat even plate, crisp edges, nothing touching or " +
|
|
123
|
+
"cropped at the frame edge. Re-generate rather than shipping a sheet that will cut badly.",
|
|
124
|
+
`Cut it locally for $0: \`${cutCmd}\`.`,
|
|
125
|
+
`Bring the asset into the library so later videos reuse it: \`vidfarm put-file ${outDir}/<file>.png${folderFlag}\`.`
|
|
126
|
+
];
|
|
127
|
+
const fallbacks = [
|
|
128
|
+
'Free stock first, always — `vidfarm media search "<meaning>" --type image|vector` (Openverse is keyless).',
|
|
129
|
+
'Any icon, sticker, illustration, 3D prop or Lottie — `vidfarm iconscout "<meaning>" --free` beats generation on price AND quality.',
|
|
130
|
+
'Hand the human the prompt — `vidfarm handoff image --theme "<what>" --items "a,b,c"`; they run it in a free web generator.',
|
|
131
|
+
"Only then spend: `vidfarm generate image --prompt \"…\"` (~$0.01–$0.05, billed to the user's own provider key)."
|
|
132
|
+
];
|
|
133
|
+
return {
|
|
134
|
+
...base,
|
|
135
|
+
outFile,
|
|
136
|
+
availability: detection.availability,
|
|
137
|
+
hostName: detection.host?.name ?? null,
|
|
138
|
+
steps,
|
|
139
|
+
followUp: cutCmd,
|
|
140
|
+
fallbacks,
|
|
141
|
+
tools: detection.host?.tool
|
|
142
|
+
? [detection.host.tool]
|
|
143
|
+
: ["your own runtime's image-generation tool, if this subscription includes one"]
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/** Render the brief as the block an agent reads (and may show the user). */
|
|
147
|
+
export function formatAgentImageBrief(brief, detection) {
|
|
148
|
+
const lines = [];
|
|
149
|
+
const host = detection.host;
|
|
150
|
+
if (host && host.availability === "included") {
|
|
151
|
+
lines.push(`Detected host: ${host.name} — image generation IS included in this subscription.`);
|
|
152
|
+
lines.push(host.note);
|
|
153
|
+
}
|
|
154
|
+
else if (host && host.availability === "none") {
|
|
155
|
+
lines.push(`Detected host: ${host.name} — image generation is NOT included.`);
|
|
156
|
+
lines.push(host.note);
|
|
157
|
+
}
|
|
158
|
+
else if (host) {
|
|
159
|
+
lines.push(`Detected host: ${host.name} — unclear whether image generation is included.`);
|
|
160
|
+
lines.push(host.note);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
lines.push("Host agent not detected from the environment.");
|
|
164
|
+
}
|
|
165
|
+
lines.push("The env check is only a hint. YOU are the authority: look at your own tool list.");
|
|
166
|
+
lines.push("");
|
|
167
|
+
brief.steps.forEach((s, i) => lines.push(`${i + 1}. ${s}`));
|
|
168
|
+
lines.push("");
|
|
169
|
+
lines.push("─── the generation prompt ───");
|
|
170
|
+
lines.push(brief.prompt);
|
|
171
|
+
lines.push("─────────────────────────────");
|
|
172
|
+
if (brief.keyColorNote) {
|
|
173
|
+
lines.push("");
|
|
174
|
+
lines.push(`Plate: ${brief.keyColorNote}`);
|
|
175
|
+
}
|
|
176
|
+
lines.push("");
|
|
177
|
+
lines.push("If you have NO image tool of your own, in this order:");
|
|
178
|
+
brief.fallbacks.forEach((f) => lines.push(` • ${f}`));
|
|
179
|
+
return lines.join("\n");
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=agent-imagegen.js.map
|