@officexapp/vidfarm-devcli 0.21.27 → 0.21.29
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 +52 -0
- package/.agents/skills/vidfarm/SKILL.md +58 -5
- package/.agents/skills/vidfarm/recipes/bulk-scripting-with-a-regime.md +65 -0
- package/.agents/skills/vidfarm/recipes/cutout-graphics-for-explainers.md +78 -7
- package/.agents/skills/vidfarm/recipes/local-edit-render-approve.md +4 -3
- package/.agents/skills/vidfarm/recipes/retheme-template.md +1 -1
- package/.agents/skills/vidfarm/references/assets-and-sourcing.md +3 -3
- package/.agents/skills/vidfarm/references/automation-and-local-dev.md +92 -1
- package/.agents/skills/vidfarm/references/editor-workflows.md +135 -6
- package/.agents/skills/vidfarm/references/hooks-and-virality.md +237 -0
- package/.agents/skills/vidfarm/references/onboarding.md +5 -5
- package/.agents/skills/vidfarm/references/primitives.md +5 -1
- package/.agents/skills/vidfarm/regimes/README.md +77 -0
- package/.agents/skills/vidfarm/regimes/explainer.QA_REGIME.md +82 -0
- package/.agents/skills/vidfarm/regimes/hooks.QA_REGIME.md +117 -0
- package/.agents/skills/vidfarm/regimes/product-demo.QA_REGIME.md +92 -0
- package/.agents/skills/vidfarm/regimes/short-form.QA_REGIME.md +163 -0
- package/.agents/skills/vidfarm/regimes/ugc-testimonial.QA_REGIME.md +82 -0
- package/SKILL.director.md +685 -32
- package/SKILL.md +22 -3
- package/demo/dist/app.js +103 -103
- package/dist/src/cli.js +987 -11
- package/dist/src/devcli/handoff.js +162 -0
- package/dist/src/devcli/interaction-mode.js +154 -0
- package/dist/src/devcli/qa-check.js +593 -0
- package/dist/src/devcli/qa-regime.js +396 -0
- package/dist/src/devcli/sticker-pack.js +396 -0
- package/dist/src/devcli/storyboard.js +243 -0
- package/package.json +8 -1
- package/public/serve-shells/tools-image.html +378 -265
- package/public/serve-shells/tools-video.html +760 -167
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// Interactive-mode HAND-OFF briefs — the copy-paste packets an agent gives the
|
|
2
|
+
// human when the pair (cost mode × interaction mode) says "a human step here
|
|
3
|
+
// beats spending, and beats going without".
|
|
4
|
+
//
|
|
5
|
+
// Two hand-offs cover almost every real case:
|
|
6
|
+
//
|
|
7
|
+
// 1. IMAGES (`buildImageHandoff`) — the agent writes the prompt, the user runs
|
|
8
|
+
// it in a FREE frontier web generator (meta.ai / ChatGPT / Gemini / a
|
|
9
|
+
// Hugging Face Space) and drops the file back. Defaults to a STICKER PACK:
|
|
10
|
+
// one prompt → one greenscreen sheet holding every graphic → `vidfarm
|
|
11
|
+
// sticker-pack` splits it into many transparent stickers locally. One round
|
|
12
|
+
// trip for a whole cast is both the cheapest thing for the user's time and
|
|
13
|
+
// the most token-efficient thing for the agent.
|
|
14
|
+
//
|
|
15
|
+
// 2. RAW CLIPS (`buildRawsHandoff`) — the agent hands over search keywords and
|
|
16
|
+
// where to search, the user downloads a few clips with a free online
|
|
17
|
+
// downloader and points the agent at the folder. This is the LAST rung of
|
|
18
|
+
// the sourcing ladder: an agent should first try its own browser control,
|
|
19
|
+
// then vidfarm's cloud scan, and only ask the human when neither is
|
|
20
|
+
// available (fully-local, keyless devcli) or when human taste matters.
|
|
21
|
+
//
|
|
22
|
+
// Both builders return plain text meant to be shown verbatim to the user, plus a
|
|
23
|
+
// structured form for `--json` so an agent can render it its own way. No network,
|
|
24
|
+
// no backend imports — this module is pure string assembly.
|
|
25
|
+
import { pickPlateColor } from "./sticker-pack.js";
|
|
26
|
+
const DEFAULT_STYLE = "simple flat vector illustration, minimal detail, 2-3 flat colors, no shadows, no text";
|
|
27
|
+
/** Pick a sensible grid for N items (roughly square, wider than tall). */
|
|
28
|
+
function gridFor(count) {
|
|
29
|
+
if (count <= 1)
|
|
30
|
+
return "1x1";
|
|
31
|
+
const cols = Math.ceil(Math.sqrt(count));
|
|
32
|
+
const rows = Math.ceil(count / cols);
|
|
33
|
+
return `${cols}x${rows}`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build the free-image-generation hand-off. Sticker-pack shaped by default: ONE
|
|
37
|
+
* image containing every item on a flat chroma plate, generously spaced, which
|
|
38
|
+
* `vidfarm sticker-pack` then splits into individually-trimmed transparent
|
|
39
|
+
* stickers. The spacing/no-touching instruction is load-bearing — items that
|
|
40
|
+
* touch on the sheet segment as a single sticker.
|
|
41
|
+
*/
|
|
42
|
+
export function buildImageHandoff(input) {
|
|
43
|
+
// Plate choice matters MORE here than anywhere else: the user is about to
|
|
44
|
+
// spend their own effort generating this sheet, and a green plate under green
|
|
45
|
+
// art means the stickers come back with holes. Pick the plate off the subject
|
|
46
|
+
// unless the caller pinned one.
|
|
47
|
+
const picked = pickPlateColor([input.theme, input.items.join(" "), input.style ?? ""].join(" "));
|
|
48
|
+
const keyColor = (input.keyColor ?? picked.keyColor).toUpperCase();
|
|
49
|
+
const keyColorNote = input.keyColor
|
|
50
|
+
? null
|
|
51
|
+
: picked.moved
|
|
52
|
+
? `Plate moved off green to ${picked.preset} (${picked.keyColor}) — ${picked.reason}. A green plate would key holes through green artwork.`
|
|
53
|
+
: picked.reason;
|
|
54
|
+
const style = input.style?.trim() || DEFAULT_STYLE;
|
|
55
|
+
const items = input.items.map((s) => s.trim()).filter(Boolean);
|
|
56
|
+
const pack = input.pack ?? items.length > 1;
|
|
57
|
+
const outDir = input.outDir ?? "./stickers";
|
|
58
|
+
const grid = input.grid ?? gridFor(items.length || 6);
|
|
59
|
+
const prompt = pack
|
|
60
|
+
? [
|
|
61
|
+
`A sticker sheet of ${items.length || "several"} separate objects — ${style} — on a solid pure ${keyColor} background`,
|
|
62
|
+
`(flat, evenly lit, no gradient, no shadow, no text, no labels, no frames or dividing lines).`,
|
|
63
|
+
`Theme: ${input.theme}.`,
|
|
64
|
+
items.length
|
|
65
|
+
? `Arranged in a ${grid} grid with generous even spacing: ${items.map((it, i) => `(${i + 1}) ${it}`).join(", ")}.`
|
|
66
|
+
: `Arranged in a ${grid} grid with generous even spacing.`,
|
|
67
|
+
`CRITICAL: every object must be fully separated from the others by a clear margin of plain ${keyColor} background —`,
|
|
68
|
+
`nothing touching, overlapping or connected, and nothing touching the image edge.`,
|
|
69
|
+
`One consistent art style, line weight and palette across all objects. Front-facing, centered in its own cell.`,
|
|
70
|
+
`Square image, high resolution.`
|
|
71
|
+
].join(" ")
|
|
72
|
+
: [
|
|
73
|
+
`${input.theme} — ${style} — isolated on a solid pure ${keyColor} background`,
|
|
74
|
+
`(flat, evenly lit, no gradient, no shadow cast on the background, no text).`,
|
|
75
|
+
`Center the subject with generous empty margin on all sides, crisp clean edges, single subject.`,
|
|
76
|
+
`Square image, high resolution.`
|
|
77
|
+
].join(" ");
|
|
78
|
+
const steps = pack
|
|
79
|
+
? [
|
|
80
|
+
"Open a FREE image generator you're already signed into (list below).",
|
|
81
|
+
"Paste the prompt below and generate. If any two objects come out touching, re-generate asking for wider spacing — touching objects get cut out as one sticker.",
|
|
82
|
+
"Download the image (PNG preferred) and tell me the file path — or drop it in this project folder.",
|
|
83
|
+
`I'll split it into individual transparent stickers locally for $0: \`vidfarm sticker-pack <sheet> --out-dir ${outDir}\`.`
|
|
84
|
+
]
|
|
85
|
+
: [
|
|
86
|
+
"Open a FREE image generator you're already signed into (list below).",
|
|
87
|
+
"Paste the prompt below and generate.",
|
|
88
|
+
"Download the image (PNG preferred) and tell me the file path.",
|
|
89
|
+
"I'll key the background out and trim it to a snug transparent sticker locally for $0: `vidfarm cutout <file>`."
|
|
90
|
+
];
|
|
91
|
+
const keyFlag = keyColor === "#00FF00" ? "" : ` --key-color "${keyColor}"`;
|
|
92
|
+
const followUp = pack
|
|
93
|
+
? `vidfarm sticker-pack <downloaded-sheet.png>${items.length ? ` --items "${items.join(",")}"` : ""}${keyFlag} --out-dir ${outDir}`
|
|
94
|
+
: `vidfarm cutout <downloaded.png>${keyFlag}`;
|
|
95
|
+
return {
|
|
96
|
+
prompt,
|
|
97
|
+
steps,
|
|
98
|
+
followUp,
|
|
99
|
+
keyColor,
|
|
100
|
+
keyColorNote,
|
|
101
|
+
tools: [
|
|
102
|
+
"https://meta.ai (free, generous)",
|
|
103
|
+
"ChatGPT free tier (image generation included)",
|
|
104
|
+
"Google Gemini free tier",
|
|
105
|
+
"a free image Space on https://huggingface.co/spaces (search \"flux\" or \"sdxl\")"
|
|
106
|
+
]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Build the manual raw-clip sourcing hand-off. Deliberately does NOT name one
|
|
111
|
+
* downloader site: those rot, get blocked, and vary by region — so the brief
|
|
112
|
+
* hands over a SEARCH for a downloader instead, which stays correct forever.
|
|
113
|
+
*/
|
|
114
|
+
export function buildRawsHandoff(input) {
|
|
115
|
+
const keywords = input.keywords.map((k) => k.trim()).filter(Boolean);
|
|
116
|
+
if (!keywords.length)
|
|
117
|
+
throw new Error("A raws hand-off needs at least one search keyword.");
|
|
118
|
+
const platforms = (input.platforms?.length ? input.platforms : ["tiktok", "youtube"]).map((p) => p.trim().toLowerCase());
|
|
119
|
+
const count = input.count ?? Math.max(3, keywords.length * 2);
|
|
120
|
+
const outDir = input.outDir ?? "./downloads";
|
|
121
|
+
const searchLines = keywords.map((k) => ` • "${k}"`).join("\n");
|
|
122
|
+
const prompt = [
|
|
123
|
+
`Search these keywords on ${platforms.join(" / ")} and download ${count} clips you like:`,
|
|
124
|
+
searchLines,
|
|
125
|
+
"",
|
|
126
|
+
`To download: search Google for a downloader — https://google.com/search?q=${encodeURIComponent(`${platforms[0]} video downloader`)} — and use whichever one works today.`
|
|
127
|
+
].join("\n");
|
|
128
|
+
return {
|
|
129
|
+
prompt,
|
|
130
|
+
steps: [
|
|
131
|
+
`Search ${platforms.join(" and ")} for the keywords below.`,
|
|
132
|
+
input.purpose
|
|
133
|
+
? `Pick ${count} clips that fit: ${input.purpose}. Favor clean, well-lit footage with no burned-in captions or watermarks over the subject.`
|
|
134
|
+
: `Pick ${count} clips with clean, well-lit footage and no burned-in captions or watermarks over the subject.`,
|
|
135
|
+
`Download them with any free online downloader (google "${platforms[0]} video downloader" — the working one changes often) into ${outDir}.`,
|
|
136
|
+
`Tell me the folder and I'll import each one into your raws library: \`vidfarm clipper ${outDir}/<file>.mp4\` (whole clip), or \`vidfarm raws scan ${outDir}/<file>.mp4\` to mine short clips out of a long one.`
|
|
137
|
+
],
|
|
138
|
+
followUp: `vidfarm clipper ${outDir}/<file>.mp4 # per download; or: vidfarm raws scan ${outDir}/<file>.mp4`,
|
|
139
|
+
tools: [
|
|
140
|
+
`https://google.com/search?q=${encodeURIComponent(`${platforms[0]} video downloader`)}`,
|
|
141
|
+
...platforms.map((p) => `https://google.com/search?q=${encodeURIComponent(`${p} ${keywords[0]}`)}`)
|
|
142
|
+
]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/** Render a brief as the block of text an agent shows the user verbatim. */
|
|
146
|
+
export function formatHandoff(title, brief, opts = {}) {
|
|
147
|
+
const lines = [];
|
|
148
|
+
lines.push(title);
|
|
149
|
+
lines.push("");
|
|
150
|
+
brief.steps.forEach((s, i) => lines.push(`${i + 1}. ${s}`));
|
|
151
|
+
lines.push("");
|
|
152
|
+
lines.push(`${opts.promptLabel ?? "─── copy from here ───"}`);
|
|
153
|
+
lines.push(brief.prompt);
|
|
154
|
+
lines.push("──────────────────────");
|
|
155
|
+
lines.push("");
|
|
156
|
+
lines.push("Free tools:");
|
|
157
|
+
brief.tools.forEach((t) => lines.push(` • ${t}`));
|
|
158
|
+
lines.push("");
|
|
159
|
+
lines.push(`When the file(s) come back: ${brief.followUp}`);
|
|
160
|
+
return lines.join("\n");
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=handoff.js.map
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// Interaction mode — is the human IN THE LOOP, or is the agent running solo?
|
|
2
|
+
//
|
|
3
|
+
// This is a SECOND, INDEPENDENT axis from cost mode (cost-mode.ts). Cost mode
|
|
4
|
+
// answers "how much money may I spend?"; interaction mode answers "how much of
|
|
5
|
+
// the user's own time and hands may I use?". Every cost mode can run either
|
|
6
|
+
// way — interactive minimize, autonomous rich-ai, interactive pure-videogen —
|
|
7
|
+
// and the pair is what actually determines the plan.
|
|
8
|
+
//
|
|
9
|
+
// - interactive : the user is willing to do some manual work in exchange for
|
|
10
|
+
// better output. The agent hands them copy-paste briefs at
|
|
11
|
+
// fixed checkpoints — an image prompt to run in a free web
|
|
12
|
+
// generator, a keyword list to source raw clips with — and
|
|
13
|
+
// waits for the files to come back. Quality goes UP, because
|
|
14
|
+
// the frontier web models (free tiers) beat what an API-key
|
|
15
|
+
// budget usually buys, and a human eye picks better clips than
|
|
16
|
+
// any keyword scan. In `minimize` this is the difference
|
|
17
|
+
// between "no custom art at all" and "a full sticker pack for
|
|
18
|
+
// $0", so ALWAYS offer it there.
|
|
19
|
+
// - autonomous : the agent finishes end-to-end with zero user steps. It
|
|
20
|
+
// spends (within cost mode) or does without. Faster and
|
|
21
|
+
// hands-off; typically a quality floor below interactive.
|
|
22
|
+
//
|
|
23
|
+
// Like cost mode, this is a durable preference the human picks ONCE (`vidfarm
|
|
24
|
+
// mode <interactive|autonomous>`) and every relevant command respects. Unset
|
|
25
|
+
// means "nobody has asked yet" — the agent should ask before it either spends
|
|
26
|
+
// money or silently downgrades quality.
|
|
27
|
+
//
|
|
28
|
+
// Backend-free (Node built-ins only) so it ships in the public cloud-only CLI.
|
|
29
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
30
|
+
import path from "node:path";
|
|
31
|
+
import { resolveDevcliHome } from "./auth-store.js";
|
|
32
|
+
export const INTERACTION_MODES = ["interactive", "autonomous"];
|
|
33
|
+
/** What we assume when nothing is set. Autonomous is the safe assumption for a
|
|
34
|
+
* running pipeline (never block on a human who isn't there), but `isSet:false`
|
|
35
|
+
* is the signal for an agent to ASK — interactive usually wins on quality. */
|
|
36
|
+
export const DEFAULT_INTERACTION_MODE = "autonomous";
|
|
37
|
+
function interactionModeFilePath(home) {
|
|
38
|
+
return path.join(resolveDevcliHome(home), "interaction-mode.json");
|
|
39
|
+
}
|
|
40
|
+
/** Normalize loose spellings ("manual", "hands-on", "auto", "solo"). */
|
|
41
|
+
export function normalizeInteractionMode(raw) {
|
|
42
|
+
const v = (raw ?? "").trim().toLowerCase().replace(/[\s_]+/g, "-");
|
|
43
|
+
if (!v)
|
|
44
|
+
return null;
|
|
45
|
+
if (["interactive", "manual", "hands-on", "handson", "collab", "collaborative", "human", "human-in-the-loop", "hitl", "assisted", "guided", "with-me"].includes(v)) {
|
|
46
|
+
return "interactive";
|
|
47
|
+
}
|
|
48
|
+
if (["autonomous", "auto", "automatic", "solo", "hands-off", "handsoff", "unattended", "headless", "agentic", "full-auto"].includes(v)) {
|
|
49
|
+
return "autonomous";
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
export function readStoredInteractionMode(home) {
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(readFileSync(interactionModeFilePath(home), "utf8"));
|
|
56
|
+
const mode = normalizeInteractionMode(parsed?.mode);
|
|
57
|
+
if (mode)
|
|
58
|
+
return { mode, note: parsed.note ?? null, savedAt: String(parsed.savedAt ?? "") };
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Persist the interaction mode. Returns the file path written. */
|
|
66
|
+
export function writeStoredInteractionMode(mode, savedAt, note, home) {
|
|
67
|
+
const dir = resolveDevcliHome(home);
|
|
68
|
+
mkdirSync(dir, { recursive: true });
|
|
69
|
+
const file = interactionModeFilePath(home);
|
|
70
|
+
const payload = { mode, note: note ?? null, savedAt };
|
|
71
|
+
writeFileSync(file, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
72
|
+
return file;
|
|
73
|
+
}
|
|
74
|
+
export function clearStoredInteractionMode(home) {
|
|
75
|
+
const file = interactionModeFilePath(home);
|
|
76
|
+
if (!existsSync(file))
|
|
77
|
+
return false;
|
|
78
|
+
rmSync(file, { force: true });
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolve the effective interaction mode. Precedence:
|
|
83
|
+
* --interaction-mode/--interactive/--autonomous → VIDFARM_INTERACTION_MODE →
|
|
84
|
+
* stored preference → default (autonomous, isSet:false).
|
|
85
|
+
*/
|
|
86
|
+
export function resolveInteractionMode(values) {
|
|
87
|
+
if (values.interactive && !values.autonomous)
|
|
88
|
+
return { mode: "interactive", isSet: true, source: "flag" };
|
|
89
|
+
if (values.autonomous && !values.interactive)
|
|
90
|
+
return { mode: "autonomous", isSet: true, source: "flag" };
|
|
91
|
+
const flag = normalizeInteractionMode(values["interaction-mode"]);
|
|
92
|
+
if (flag)
|
|
93
|
+
return { mode: flag, isSet: true, source: "flag" };
|
|
94
|
+
const env = normalizeInteractionMode(process.env.VIDFARM_INTERACTION_MODE);
|
|
95
|
+
if (env)
|
|
96
|
+
return { mode: env, isSet: true, source: "env" };
|
|
97
|
+
const stored = readStoredInteractionMode(values.home);
|
|
98
|
+
if (stored)
|
|
99
|
+
return { mode: stored.mode, isSet: true, source: "stored" };
|
|
100
|
+
return { mode: DEFAULT_INTERACTION_MODE, isSet: false, source: "default" };
|
|
101
|
+
}
|
|
102
|
+
export const INTERACTION_MODE_BLURB = {
|
|
103
|
+
interactive: "Interactive — you're in the loop, and the video gets better for it. At fixed checkpoints the agent " +
|
|
104
|
+
"hands you a copy-paste brief instead of spending: an IMAGE PROMPT to run in a free web generator " +
|
|
105
|
+
"(meta.ai / ChatGPT / Gemini / a Hugging Face Space) and drop the PNG back, or a KEYWORD LIST to " +
|
|
106
|
+
"search TikTok/YouTube and download raw clips with a free online downloader. Frontier web models on " +
|
|
107
|
+
"their free tiers usually beat what an API budget buys, and a human eye picks better clips than any " +
|
|
108
|
+
"keyword scan — so quality goes UP, especially in cost mode `minimize` where the alternative is no " +
|
|
109
|
+
"custom art at all. Manual image work defaults to STICKER PACKS: one prompt → one greenscreen sheet " +
|
|
110
|
+
"→ `vidfarm sticker-pack` splits it into many transparent stickers.",
|
|
111
|
+
autonomous: "Autonomous — the agent finishes end-to-end with zero steps from you. No prompts to paste, no files " +
|
|
112
|
+
"to fetch: it sources clips itself (browser control, the free public raws catalog, cloud scan) and " +
|
|
113
|
+
"generates art within the cost mode's budget, or does without. Fastest and fully hands-off; the " +
|
|
114
|
+
"quality ceiling is usually a notch below interactive, and in `minimize` it means custom art simply " +
|
|
115
|
+
"doesn't happen."
|
|
116
|
+
};
|
|
117
|
+
/** One short human line summarizing the active interaction mode. */
|
|
118
|
+
export function interactionModeSummaryLine(resolved) {
|
|
119
|
+
const setNote = resolved.isSet ? `set via ${resolved.source}` : "NOT set — assuming autonomous";
|
|
120
|
+
return `interaction mode: ${resolved.mode} (${setNote})`;
|
|
121
|
+
}
|
|
122
|
+
/** The "explain it simply" block an agent should relay to the user. */
|
|
123
|
+
export function interactionModeExplainer() {
|
|
124
|
+
return [
|
|
125
|
+
"Do you want to be in the loop, or should the agent finish on its own?",
|
|
126
|
+
" • interactive — you do a little manual work, the video comes out better. At checkpoints you get",
|
|
127
|
+
" a copy-paste IMAGE PROMPT for a free web generator (and drop the PNG back), or a",
|
|
128
|
+
" KEYWORD LIST to hand-source raw clips. Manual images default to sticker packs.",
|
|
129
|
+
" • autonomous — zero steps from you: the agent sources and generates everything itself, within",
|
|
130
|
+
" the cost mode's budget (or goes without).",
|
|
131
|
+
"This is INDEPENDENT of cost mode — any cost mode can run either way:",
|
|
132
|
+
" minimize + interactive → $0 videos WITH custom art and hand-picked footage (the sweet spot).",
|
|
133
|
+
" minimize + autonomous → $0 videos from stock + existing raws only; no custom art.",
|
|
134
|
+
" hybrid/rich-ai + interactive → paid generation for the hard shots, your hands on the hero art.",
|
|
135
|
+
" rich-ai/pure-videogen + autonomous → fully hands-off, budget does the work.",
|
|
136
|
+
"Quality usually goes UP in interactive mode — most of all in `minimize`, where the free frontier",
|
|
137
|
+
"web models replace an AI budget you're not spending.",
|
|
138
|
+
"Set it: vidfarm mode <interactive|autonomous> (cost is separate: vidfarm cost-mode <…>)"
|
|
139
|
+
].join("\n");
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The line an agent should print (and act on) when it is about to do something
|
|
143
|
+
* that interactive mode would do better — generate art, or source raw clips.
|
|
144
|
+
* Returns null when the mode is set and the agent should just proceed.
|
|
145
|
+
*/
|
|
146
|
+
export function interactiveOfferLine(input) {
|
|
147
|
+
if (input.interaction.isSet)
|
|
148
|
+
return null;
|
|
149
|
+
return (`[mode] No interaction preference set — about to ${input.about} autonomously. ` +
|
|
150
|
+
"Ask the user whether they'd rather work INTERACTIVELY (they paste a prompt into a free image " +
|
|
151
|
+
"generator / hand-source clips — usually better output, and the only way to get custom art in " +
|
|
152
|
+
"`minimize`) and save it: vidfarm mode <interactive|autonomous>.");
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=interaction-mode.js.map
|