@vibeframe/cli 0.113.0 → 0.113.2
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/CONTEXT.md +59 -10
- package/dist/commands/_shared/build-cache.d.ts +10 -1
- package/dist/commands/_shared/build-cache.test.d.ts +1 -0
- package/dist/commands/_shared/init-templates.d.ts +1 -1
- package/dist/commands/_shared/render-inspect.d.ts +4 -1
- package/dist/commands/_shared/review-report.d.ts +50 -1
- package/dist/commands/_shared/review-report.test.d.ts +1 -0
- package/dist/commands/_shared/scene-build.d.ts +13 -0
- package/dist/commands/_shared/scene-html-emit.d.ts +4 -2
- package/dist/commands/_shared/scene-inspect.d.ts +2 -1
- package/dist/commands/_shared/status-jobs.d.ts +3 -0
- package/dist/commands/_shared/storyboard-edit.d.ts +15 -1
- package/dist/commands/_shared/storyboard-parse.d.ts +34 -0
- package/dist/commands/error-envelopes.test.d.ts +26 -0
- package/dist/commands/review-actions-cli.test.d.ts +1 -0
- package/dist/commands/scene.d.ts +12 -0
- package/dist/index.js +1428 -272
- package/dist/tools/manifest/edit.d.ts +6 -6
- package/dist/tools/manifest/index.js +1506 -471
- package/dist/tools/manifest/scene.d.ts +3 -0
- package/package.json +4 -4
package/CONTEXT.md
CHANGED
|
@@ -5,12 +5,57 @@
|
|
|
5
5
|
VibeFrame CLI (`vibe`) is a CLI-first video toolkit. Every operation is
|
|
6
6
|
a shell command. The same surface is exposed as MCP tools through
|
|
7
7
|
[`@vibeframe/mcp-server`](https://www.npmjs.com/package/@vibeframe/mcp-server).
|
|
8
|
+
For long-running video work, native Codex Goal mode and Claude Code `/goal`
|
|
9
|
+
should own the outer loop: persistence, iteration, and stop decisions.
|
|
10
|
+
VibeFrame owns the video-specific command surface, JSON reports, cost gates,
|
|
11
|
+
deterministic repair, render inspection, and `retryWith` recovery hints.
|
|
8
12
|
|
|
9
13
|
For the full reference (every flag, default, enum), read
|
|
10
14
|
[`docs/cli-reference.md`](../../docs/cli-reference.md) — auto-generated
|
|
11
15
|
from `vibe schema --list`. This file is the _agent quickstart_: rules,
|
|
12
16
|
conventions, and discovery hooks.
|
|
13
17
|
|
|
18
|
+
## Native host goal loop
|
|
19
|
+
|
|
20
|
+
Use the host's native goal feature rather than inventing a VibeFrame-owned
|
|
21
|
+
goal runner. The canonical loop is:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
native host goal -> vibe context/schema -> plan dry-run -> build with budget
|
|
25
|
+
-> status polling -> inspect project -> render -> inspect render
|
|
26
|
+
-> repair/edit using nextActions/fixOwner -> repeat until stop rules pass
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Copy-paste Codex goal:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
/goal Build my-video/ into a reviewed VibeFrame MP4. Use --json for every vibe
|
|
33
|
+
command, run --dry-run before paid operations, cap generated-asset spend with
|
|
34
|
+
--max-cost 5 where supported, and read build-report.json plus
|
|
35
|
+
review-report.json before deciding the next action. Prefer nextActions: run
|
|
36
|
+
only safeToAutoRun:true actions automatically, ask before
|
|
37
|
+
requiresConfirmation:true actions, and use retryWith only as the compatibility
|
|
38
|
+
fallback. Treat fixOwner:"vibe" as deterministic CLI repair work and
|
|
39
|
+
fixOwner:"host-agent" as storyboard, DESIGN.md, or composition edits.
|
|
40
|
+
Stop only when my-video/renders/final.mp4 exists, duration is within the target,
|
|
41
|
+
aspect ratio matches the brief, inspect render --cheap has no errors, review
|
|
42
|
+
AI review score is >= 90 when AI review is requested, and unresolved host-agent issues are fixed, intentionally
|
|
43
|
+
accepted with a written reason, or reported as blocked.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Copy-paste Claude Code goal:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
/goal Finish the VibeFrame render for my-video/ using Claude Code goal mode as
|
|
50
|
+
the outer loop. Use vibe context/schema when unsure, --json everywhere,
|
|
51
|
+
dry-run before paid operations, --max-cost 5 for builds, nextActions before
|
|
52
|
+
custom recovery, and build-report.json/review-report.json as loop state.
|
|
53
|
+
Stop only when renders/final.mp4 exists, target duration and aspect ratio are
|
|
54
|
+
met, render inspection has no errors, any AI review score is at least 90 when AI review is requested, and every
|
|
55
|
+
remaining host-agent issue is fixed, accepted with rationale, or reported as
|
|
56
|
+
blocked.
|
|
57
|
+
```
|
|
58
|
+
|
|
14
59
|
## Discovery (use these first)
|
|
15
60
|
|
|
16
61
|
```bash
|
|
@@ -38,12 +83,12 @@ vibe guide <topic> --json # Step-by-step guides (motion | scene | p
|
|
|
38
83
|
|
|
39
84
|
## Cost tiers
|
|
40
85
|
|
|
41
|
-
| Tier | Commands
|
|
42
|
-
| --------- |
|
|
86
|
+
| Tier | Commands | Per-call cost |
|
|
87
|
+
| --------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
|
|
43
88
|
| Free | `schema/context/doctor`, `detect *`, `status *`, `plan`, `storyboard validate`, `inspect project/render --cheap`, deterministic edits | $0 |
|
|
44
|
-
| Low | `generate narration/sound-effect/music`, `audio transcribe/list-voices`, `inspect media`, optional AI review
|
|
45
|
-
| High | `generate image/motion`, `edit image/reframe/grade/speed-ramp`
|
|
46
|
-
| Very High | `generate video`, `edit fill-gaps`, `remix highlights/auto-shorts`, `build` with generated assets
|
|
89
|
+
| Low | `generate narration/sound-effect/music`, `audio transcribe/list-voices`, `inspect media`, optional AI review | $0.01–0.10 |
|
|
90
|
+
| High | `generate image/motion`, `edit image/reframe/grade/speed-ramp` | $1–5 |
|
|
91
|
+
| Very High | `generate video`, `edit fill-gaps`, `remix highlights/auto-shorts`, `build` with generated assets | $5–50+ |
|
|
47
92
|
|
|
48
93
|
> Rule: **confirm with the user before any High / Very-High call**.
|
|
49
94
|
|
|
@@ -173,10 +218,14 @@ Review report contract:
|
|
|
173
218
|
`review-report.json` by default. The file uses `kind:"review"`,
|
|
174
219
|
`mode:"project"|"render"`, `status`, `score`, `issues[]`,
|
|
175
220
|
`summary:{issueCount,errorCount,warningCount,infoCount,fixOwners}`,
|
|
176
|
-
`sourceReports`, and `retryWith`. Each issue has
|
|
177
|
-
deterministic CLI recovery or `fixOwner:"host-agent"`
|
|
178
|
-
composition edits the host agent should make.
|
|
179
|
-
|
|
221
|
+
`sourceReports`, `nextActions`, and `retryWith`. Each issue has
|
|
222
|
+
`fixOwner:"vibe"` for deterministic CLI recovery or `fixOwner:"host-agent"`
|
|
223
|
+
for storyboard/design/composition edits the host agent should make. Prefer
|
|
224
|
+
`nextActions` first: run only `safeToAutoRun:true` actions automatically, ask
|
|
225
|
+
before `requiresConfirmation:true`, and use `retryWith` only as the fallback.
|
|
226
|
+
A host-native goal should not stop while `host-agent` issues remain unless
|
|
227
|
+
they are fixed, intentionally accepted with a written reason, or reported as
|
|
228
|
+
blocked.
|
|
180
229
|
|
|
181
230
|
Product surface contract:
|
|
182
231
|
|
|
@@ -242,7 +291,7 @@ vibe scene repair --project my-video --json
|
|
|
242
291
|
|
|
243
292
|
`vibe status job --json` emits the normal success envelope with `data.kind:"job"`, flat job fields (`id`, `jobType`, `provider`, `status`, timestamps), `progress`, `result`, `retryWith`, and the raw `job` record for compatibility.
|
|
244
293
|
|
|
245
|
-
`vibe status project --json` emits `data.kind:"project"`, `status`, `currentStage`, `beats:{total,assetsReady,compositionsReady,needsAuthor}`, `jobs.latest`, `build`, `review`, `warnings`, and `retryWith`. `review` includes `mode`, `issueCount`, `errorCount`, `warningCount`, `infoCount`, `fixOwners`, `sourceReports`, and its own `retryWith`; top-level `
|
|
294
|
+
`vibe status project --json` emits `data.kind:"project"`, `status`, `currentStage`, `beats:{total,assetsReady,compositionsReady,needsAuthor}`, `jobs.latest`, `build`, `review`, `warnings`, `nextActions`, and `retryWith`. `review` includes `mode`, `issueCount`, `errorCount`, `warningCount`, `infoCount`, `fixOwners`, `sourceReports`, `nextActions`, and its own `retryWith`; top-level `nextActions` carries the preferred resume contract while `retryWith` remains the compatibility fallback.
|
|
246
295
|
|
|
247
296
|
### Storyboard revision contract
|
|
248
297
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type BuildAssetKind = "narration" | "backdrop" | "video" | "music";
|
|
1
|
+
export type BuildAssetKind = "narration" | "backdrop" | "character" | "video" | "music";
|
|
2
2
|
export interface CacheAssetDescriptor {
|
|
3
3
|
key: string;
|
|
4
4
|
path: string;
|
|
@@ -20,12 +20,21 @@ export declare function backdropCacheDescriptor(opts: {
|
|
|
20
20
|
size: string;
|
|
21
21
|
ratio?: string;
|
|
22
22
|
}): CacheAssetDescriptor;
|
|
23
|
+
export declare function characterCacheDescriptor(opts: {
|
|
24
|
+
name: string;
|
|
25
|
+
cue: string;
|
|
26
|
+
provider: string;
|
|
27
|
+
quality: "standard" | "hd";
|
|
28
|
+
size: string;
|
|
29
|
+
}): CacheAssetDescriptor;
|
|
23
30
|
export declare function imageRatioForSize(size: string | undefined): string;
|
|
24
31
|
export declare function videoCacheDescriptor(opts: {
|
|
25
32
|
beatId: string;
|
|
26
33
|
cue: string;
|
|
27
34
|
provider: string;
|
|
28
35
|
duration: number | undefined;
|
|
36
|
+
/** Character reference image paths — changing them must invalidate the clip. */
|
|
37
|
+
characters?: string[];
|
|
29
38
|
}): CacheAssetDescriptor;
|
|
30
39
|
export declare function musicCacheDescriptor(opts: {
|
|
31
40
|
beatId: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* file. Keep this as the canonical source of truth for agent guidance —
|
|
19
19
|
* \`CLAUDE.md\` and \`GEMINI.md\` just import it.
|
|
20
20
|
*/
|
|
21
|
-
export declare const AGENTS_MD = "# AGENTS.md\n\nThis project uses [VibeFrame](https://github.com/vericontext/vibeframe) \u2014\na CLI for AI-powered video editing. The `vibe` command provides 80+\nsubcommands for video generation, editing, analysis, and pipeline\norchestration. Cost tiers below \u2014 **always confirm with the user before\nrunning High / Very High tier commands**.\n\n## Agent host coverage\n\nVibeFrame's CLI works with any bash-capable AI coding agent. Six host\nfamilies have first-class auto-detection and scaffolds today:\n\n- **Claude Code** \u2014 `CLAUDE.md` (this file's import wrapper) +\n `AGENTS.md` + `/vibe-*` slash commands.\n- **OpenAI Codex** \u2014 reads `AGENTS.md` natively (agents.md spec).\n- **Cursor** \u2014 reads `AGENTS.md` plus `.cursor/rules/` for project\n rules; supports MCP via `.cursor/mcp.json`.\n- **Aider** \u2014 reads `AGENTS.md` (binary-only detection by VibeFrame).\n- **Gemini CLI** \u2014 primary context file is `GEMINI.md`; also reads\n `AGENTS.md` if present.\n- **OpenCode** \u2014 reads `AGENTS.md` (officially supported per\n `opencode.ai/docs/rules`); supports MCP via `.opencode/mcp.json`.\n\nRun `vibe doctor` to see which host(s) the CLI detects in your\nenvironment. Anyone running another bash-capable agent (Continue,\nSourcegraph Cody, etc.) still gets this `AGENTS.md` as the universal\nfallback.\n\n## Self-discovery\n\nDon't memorise the command surface \u2014 read it from the CLI:\n\n```bash\nvibe --help # command groups overview\nvibe schema --list # full machine-readable catalog (80+)\nvibe schema --list --surface public # small first-run/product command surface\nvibe schema generate.video # JSON Schema for any single command\nvibe doctor # available providers + system health\nvibe host setup all # print Codex/Claude/Cursor app integration snippets\nvibe host doctor all --json # verify project guidance + MCP config\nvibe guide motion # choose text-overlay vs motion-overlay vs generate motion\nvibe guide scene # step-by-step authoring guide (scene)\nvibe guide pipeline # step-by-step authoring guide (pipeline)\n```\n\n## Route by the user's actual request\n\nRouting the user's request correctly is the most important judgement call\nyou'll make. Do not force everything into a scene project.\n\n**ASSET \u2014 default for any single-asset request OR ambiguous prompt.**\nIf the user asks for a single image, single video clip, sound effect, music\nbed, or narration file \u2014 **OR pastes a visual/audio brief without explicit\nstoryboard / scene / multi-scene language** \u2014 treat it as ASSET. Use\n`vibe generate ...` directly. Do **not** edit `DESIGN.md`,\n`STORYBOARD.md`, run `vibe scene ...`, or auto-load the hyperframes\nskill until BUILD intent is explicit. The visual-identity hard-gate\napplies to BUILD only.\n\nExamples:\n- \"make this image\" \u2192 `vibe generate image \"...\" -o assets/name.png`\n- \"use this image to make a video\" \u2192 `vibe generate video \"...\" -i image.png -o renders/name.mp4`\n- \"add a lower-third/title/animated overlay/grain/vignette to this clip\" \u2192 prefer `vibe edit motion-overlay clip.mp4 \"...\" --understand auto -o out.mp4` when the request asks for designed or animated motion graphics.\n- \"please add visuals using OpenAI image gen\" \u2192 `vibe generate image \"...\" -p openai ...`\n- *(verb-less paste)* \"aerial view of a misty mountain peak at sunrise...\" \u2192 `vibe generate image \"<paste>\" -o assets/mountain-peak.png`. **Don't** read it as a brief for DESIGN.md.\n\nIf genuinely uncertain, ask one short question: *\"single asset or\nmulti-scene project?\"* before authoring DESIGN.md or loading the\nhyperframes skill.\n\n**BUILD \u2014 create new video from text intent.**\nUse `vibe build` with a STORYBOARD.md + DESIGN.md. The\nskills-driven pipeline (v0.60+) dispatches narration TTS + backdrop\nimage-gen per beat, composes scene HTML via the bundled composition rules\nbundle, then renders to MP4. Idempotent re-runs reuse cached assets.\n\n**REMIX \u2014 transform existing video / audio.**\nUse `vibe remix`, `vibe edit`, or `vibe audio`. One-shot,\nbatch-oriented operations on a file the user already has on disk.\n`vibe edit text-overlay` is the free deterministic path for simple static\ntext burn-in. If the user asks for motion design, animated lower-thirds,\ndesigned titles, grain/vignette as part of a graphic treatment, or says\n\"motion graphics\", use `vibe edit motion-overlay ... --understand auto` instead.\n\nDecision rule: if the user asks for one asset, it's ASSET. If the user asks\nfor a multi-scene/storyboard/composed video, it's BUILD. If the user is\nstarting from a media file and wants it transformed, it's REMIX.\n\n## Common workflows\n\n### BUILD (new video from text)\n\n| Task | Command |\n|---|---|\n| One-shot storyboard \u2192 video | `vibe build [project-dir]` |\n| Render an existing scene project | `vibe render [project-dir] -o out.mp4` |\n| Lint scene HTML | `vibe scene lint --json` |\n| Generate a single image | `vibe generate image \"prompt\" -o img.png --quality hd` |\n| Generate a single video | `vibe generate video \"prompt\" -i image.png -o clip.mp4` |\n| Generate narration | `vibe generate narration \"text\" -o voice.mp3` |\n\n### REMIX (transform existing media)\n\n| Task | Command |\n|---|---|\n| Extract highlights from a long video | `vibe remix highlights file.mp4 -d 60` |\n| Long video \u2192 vertical shorts | `vibe remix auto-shorts file.mp4 -n 3 --add-captions` |\n| Add animated word-by-word captions | `vibe remix animated-caption file.mp4 -s karaoke-sweep` |\n| Add designed motion graphics overlay | `vibe edit motion-overlay file.mp4 \"lower-third...\" --understand auto -o out.mp4` |\n| Remove silence | `vibe edit silence-cut in.mp4 -o out.mp4` |\n| Add static captions | `vibe edit caption in.mp4 -o out.mp4` |\n| Translate audio (transcribe \u2192 TTS) | `vibe audio dub file.mp4 -t ko` |\n| Transcribe (Whisper, word-level) | `vibe audio transcribe file.mp4 --granularity word` |\n| Inspect media with Gemini | `vibe inspect media file.mp4 \"summarise\" --json` |\n\n### Compose pipelines (Video as Code)\n\n| Task | Command |\n|---|---|\n| Run a YAML pipeline | `vibe run pipeline.yaml --dry-run` |\n| Resume from last checkpoint | `vibe run pipeline.yaml --resume` |\n\n## Cost tiers\n\n| Tier | Examples | Approx. per call |\n|---|---|---|\n| **Free** | `schema/context/doctor`, `detect *`, `status *`, `plan`, `storyboard validate`, `inspect project/render --cheap`, deterministic edits | $0 |\n| **Low** | `generate narration/sound-effect/music`, `audio transcribe`, `inspect media`, optional AI review | $0.01\u2013$0.10 |\n| **High** | `generate image/motion`, `edit image/reframe/grade/speed-ramp` | $1\u2013$5 |\n| **Very High** | `generate video`, `edit fill-gaps`, `remix highlights/auto-shorts`, `build` with generated assets | $5\u2013$50+ |\n\n## Agent invariants\n\nWhen you run vibe commands programmatically:\n\n1. **Always `--json`** for structured output you can parse without regex\n2. **Always `--dry-run` first** for any High/Very-High tier command \u2014 it returns\n the cost estimate without spending API budget\n3. **Use `vibe schema <command>`** to discover parameters; do not guess flags\n4. **Pass complex options via `--stdin`**:\n ```bash\n echo '{\"video\":\"long.mp4\",\"count\":3,\"aspect\":\"9:16\"}' | vibe remix auto-shorts --stdin --json\n ```\n\n## Provider keys and project scope\n\nPrefer `vibe setup --scope project` for project-local keys. It writes\n`.vibeframe/config.yaml` in the setup directory; when you work from a\nnested scene directory, the `vibe` CLI automatically searches parent\ndirectories and uses the nearest project config. Do not assume the config\nfile must exist in the current subdirectory.\n\nRun `vibe doctor --json` from the directory where you will run commands\nand check `data.scope.project.configPath` / `data.scope.activeScope` before\ndeciding keys are missing. Never print or copy config file contents.\n\nFor generated project assets, use VibeFrame commands such as\n`vibe generate image|video|speech ...` so these project-scope keys are\nused. Do not switch to a host agent's built-in image/audio generation tool\nunless the user explicitly asks for a non-VibeFrame asset.\n\n`.env` is still supported as a gitignored fallback. Copy `.env.example`\nto start if you prefer environment variables.\n\n## App host setup\n\nVibeFrame is CLI-first, not terminal-only. Codex, Claude Code, and Cursor can\ndrive the same project through shell commands, and app hosts can also use\nVibeFrame's MCP server as a typed tool surface.\n\n```bash\nvibe host setup all # print snippets only\nvibe host setup all --write # write project/app config\nvibe host doctor all --json # verify readiness\n```\n\nDefault setup is snippet-only; use `--write` when you want VibeFrame to merge\nthe generated config. Keep provider keys in `.vibeframe/config.yaml`, user\nconfig, or env files \u2014 not in app host config.\n\n### Composition rules (scene HTML)\n\n`vibe init` installs local composition rules into your project. The\nuniversal copy lives at `SKILL.md` (with `references/*.md`), and\nhost-specific copies are placed where each agent expects them\n(`.claude/skills/hyperframes/` for Claude Code, `.cursor/rules/hyperframes.mdc`\nfor Cursor). **Read `SKILL.md` before authoring any scene composition HTML\nunder `compositions/`** \u2014 it defines the framework rules, motion\nprinciples, type system, and visual-identity hard-gate. The same skill\ngoverns `vibe scene lint` so your authored HTML and the linter stay in\nagreement.\n\nFor render-stable text, do not apply continuous `scale`, `x`, `y`,\n`filter`, or other transform tweens to `.scene-content` or any ancestor\ncontaining live text/cards. Put ambient zoom/parallax on background or media\nlayers only; text should enter briefly and then hold still at its final CSS\nposition.\n\nTo retro-install on a project scaffolded before this command existed, run\n`vibe scene install-skill [--host all]`.\n\n### Scene composer (batch / non-agent fallback)\n\nWhen you don't want to author HTML yourself, `vibe build --mode batch` runs an\nLLM internally with the same skill bundle. It auto-picks a provider based\non available keys (`claude > gemini > openai`) \u2014 pass `--composer <name>`\nto force one:\n\n| Provider | Env var | Spike notes (v0.70) |\n|---|---|---|\n| Claude (default) | `ANTHROPIC_API_KEY` | ~9 s/beat. Fastest, validated baseline. |\n| Gemini | `GOOGLE_API_KEY` | ~20 s/beat. ~2.6\u00D7 cheaper than Claude. |\n| OpenAI | `OPENAI_API_KEY` | ~70 s/beat. gpt-5 reasoning latency \u2014 opt-in only. |\n\nAll three pass first-shot lint at every effort tier on the `vibeframe-promo`\nfixture. Quality on more complex storyboards may differ \u2014 fall back to\n`--composer claude` if a non-default provider repeatedly fails lint.\n\n## Project conventions\n\n<!-- Edit this section with YOUR project's specifics. Examples below. -->\n\n- Default aspect ratio: `16:9`\n- Default scene duration: `3 seconds` (per beat)\n- Brand voice: <describe>\n- Output naming: `renders/<name>-<timestamp>.mp4`\n";
|
|
21
|
+
export declare const AGENTS_MD = "# AGENTS.md\n\nThis project uses [VibeFrame](https://github.com/vericontext/vibeframe) \u2014\na CLI for AI-powered video editing. The `vibe` command provides 80+\nsubcommands for video generation, editing, analysis, and pipeline\norchestration. Cost tiers below \u2014 **always confirm with the user before\nrunning High / Very High tier commands**.\n\n## Agent host coverage\n\nVibeFrame's CLI works with any bash-capable AI coding agent. Six host\nfamilies have first-class auto-detection and scaffolds today:\n\n- **Claude Code** \u2014 `CLAUDE.md` (this file's import wrapper) +\n `AGENTS.md` + `/vibe-*` slash commands.\n- **OpenAI Codex** \u2014 reads `AGENTS.md` natively (agents.md spec).\n- **Cursor** \u2014 reads `AGENTS.md` plus `.cursor/rules/` for project\n rules; supports MCP via `.cursor/mcp.json`.\n- **Aider** \u2014 reads `AGENTS.md` (binary-only detection by VibeFrame).\n- **Gemini CLI** \u2014 primary context file is `GEMINI.md`; also reads\n `AGENTS.md` if present.\n- **OpenCode** \u2014 reads `AGENTS.md` (officially supported per\n `opencode.ai/docs/rules`); supports MCP via `.opencode/mcp.json`.\n\nRun `vibe doctor` to see which host(s) the CLI detects in your\nenvironment. Anyone running another bash-capable agent (Continue,\nSourcegraph Cody, etc.) still gets this `AGENTS.md` as the universal\nfallback.\n\n## Self-discovery\n\nDon't memorise the command surface \u2014 read it from the CLI:\n\n```bash\nvibe --help # command groups overview\nvibe schema --list # full machine-readable catalog (80+)\nvibe schema --list --surface public # small first-run/product command surface\nvibe schema generate.video # JSON Schema for any single command\nvibe doctor # available providers + system health\nvibe host setup all # print Codex/Claude/Cursor app integration snippets\nvibe host doctor all --json # verify project guidance + MCP config\nvibe guide motion # choose text-overlay vs motion-overlay vs generate motion\nvibe guide scene # step-by-step authoring guide (scene)\nvibe guide pipeline # step-by-step authoring guide (pipeline)\n```\n\n## Route by the user's actual request\n\nRouting the user's request correctly is the most important judgement call\nyou'll make. Do not force everything into a scene project.\n\n**ASSET \u2014 default for any single-asset request OR ambiguous prompt.**\nIf the user asks for a single image, single video clip, sound effect, music\nbed, or narration file \u2014 **OR pastes a visual/audio brief without explicit\nstoryboard / scene / multi-scene language** \u2014 treat it as ASSET. Use\n`vibe generate ...` directly. Do **not** edit `DESIGN.md`,\n`STORYBOARD.md`, run `vibe scene ...`, or auto-load the hyperframes\nskill until BUILD intent is explicit. The visual-identity hard-gate\napplies to BUILD only.\n\nExamples:\n- \"make this image\" \u2192 `vibe generate image \"...\" -o assets/name.png`\n- \"use this image to make a video\" \u2192 `vibe generate video \"...\" -i image.png -o renders/name.mp4`\n- \"add a lower-third/title/animated overlay/grain/vignette to this clip\" \u2192 prefer `vibe edit motion-overlay clip.mp4 \"...\" --understand auto -o out.mp4` when the request asks for designed or animated motion graphics.\n- \"please add visuals using OpenAI image gen\" \u2192 `vibe generate image \"...\" -p openai ...`\n- *(verb-less paste)* \"aerial view of a misty mountain peak at sunrise...\" \u2192 `vibe generate image \"<paste>\" -o assets/mountain-peak.png`. **Don't** read it as a brief for DESIGN.md.\n\nIf genuinely uncertain, ask one short question: *\"single asset or\nmulti-scene project?\"* before authoring DESIGN.md or loading the\nhyperframes skill.\n\n**BUILD \u2014 create new video from text intent.**\nUse `vibe build` with a STORYBOARD.md + DESIGN.md. The\nskills-driven pipeline (v0.60+) dispatches narration TTS + backdrop\nimage-gen per beat, composes scene HTML via the bundled composition rules\nbundle, then renders to MP4. Idempotent re-runs reuse cached assets.\n\n**REMIX \u2014 transform existing video / audio.**\nUse `vibe remix`, `vibe edit`, or `vibe audio`. One-shot,\nbatch-oriented operations on a file the user already has on disk.\n`vibe edit text-overlay` is the free deterministic path for simple static\ntext burn-in. If the user asks for motion design, animated lower-thirds,\ndesigned titles, grain/vignette as part of a graphic treatment, or says\n\"motion graphics\", use `vibe edit motion-overlay ... --understand auto` instead.\n\nDecision rule: if the user asks for one asset, it's ASSET. If the user asks\nfor a multi-scene/storyboard/composed video, it's BUILD. If the user is\nstarting from a media file and wants it transformed, it's REMIX.\n\n## Common workflows\n\n### BUILD (new video from text)\n\n| Task | Command |\n|---|---|\n| One-shot storyboard \u2192 video | `vibe build [project-dir]` |\n| Render an existing scene project | `vibe render [project-dir] -o out.mp4` |\n| Lint scene HTML | `vibe scene lint --json` |\n| Generate a single image | `vibe generate image \"prompt\" -o img.png --quality hd` |\n| Generate a single video | `vibe generate video \"prompt\" -i image.png -o clip.mp4` |\n| Generate narration | `vibe generate narration \"text\" -o voice.mp3` |\n\n### REMIX (transform existing media)\n\n| Task | Command |\n|---|---|\n| Extract highlights from a long video | `vibe remix highlights file.mp4 -d 60` |\n| Long video \u2192 vertical shorts | `vibe remix auto-shorts file.mp4 -n 3 --add-captions` |\n| Add animated word-by-word captions | `vibe remix animated-caption file.mp4 -s karaoke-sweep` |\n| Add designed motion graphics overlay | `vibe edit motion-overlay file.mp4 \"lower-third...\" --understand auto -o out.mp4` |\n| Remove silence | `vibe edit silence-cut in.mp4 -o out.mp4` |\n| Add static captions | `vibe edit caption in.mp4 -o out.mp4` |\n| Translate audio (transcribe \u2192 TTS) | `vibe audio dub file.mp4 -t ko` |\n| Transcribe (Whisper, word-level) | `vibe audio transcribe file.mp4 --granularity word` |\n| Inspect media with Gemini | `vibe inspect media file.mp4 \"summarise\" --json` |\n\n### Compose pipelines (Video as Code)\n\n| Task | Command |\n|---|---|\n| Run a YAML pipeline | `vibe run pipeline.yaml --dry-run` |\n| Resume from last checkpoint | `vibe run pipeline.yaml --resume` |\n\n## Cost tiers\n\n| Tier | Examples | Approx. per call |\n|---|---|---|\n| **Free** | `schema/context/doctor`, `detect *`, `status *`, `plan`, `storyboard validate`, `inspect project/render --cheap`, deterministic edits | $0 |\n| **Low** | `generate narration/sound-effect/music`, `audio transcribe`, `inspect media`, optional AI review | $0.01\u2013$0.10 |\n| **High** | `generate image/motion`, `edit image/reframe/grade/speed-ramp` | $1\u2013$5 |\n| **Very High** | `generate video`, `edit fill-gaps`, `remix highlights/auto-shorts`, `build` with generated assets | $5\u2013$50+ |\n\n## Agent invariants\n\nWhen you run vibe commands programmatically:\n\n1. **Always `--json`** for structured output you can parse without regex\n2. **Always `--dry-run` first** for any High/Very-High tier command \u2014 it returns\n the cost estimate without spending API budget\n3. **Use `vibe schema <command>`** to discover parameters; do not guess flags\n4. **Pass complex options via `--stdin`**:\n ```bash\n echo '{\"video\":\"long.mp4\",\"count\":3,\"aspect\":\"9:16\"}' | vibe remix auto-shorts --stdin --json\n ```\n\n## Provider keys and project scope\n\nPrefer `vibe setup --scope project` for project-local keys. It writes\n`.vibeframe/config.yaml` in the setup directory; when you work from a\nnested scene directory, the `vibe` CLI automatically searches parent\ndirectories and uses the nearest project config. Do not assume the config\nfile must exist in the current subdirectory.\n\nRun `vibe doctor --json` from the directory where you will run commands\nand check `data.scope.project.configPath` / `data.scope.activeScope` before\ndeciding keys are missing. Never print or copy config file contents.\n\nFor generated project assets, use VibeFrame commands such as\n`vibe generate image|video|speech ...` so these project-scope keys are\nused. Do not switch to a host agent's built-in image/audio generation tool\nunless the user explicitly asks for a non-VibeFrame asset.\n\n`.env` is still supported as a gitignored fallback. Copy `.env.example`\nto start if you prefer environment variables.\n\n## App host setup\n\nVibeFrame is CLI-first, not terminal-only. Codex, Claude Code, and Cursor can\ndrive the same project through shell commands, and app hosts can also use\nVibeFrame's MCP server as a typed tool surface.\n\n```bash\nvibe host setup all # print snippets only\nvibe host setup all --write # write project/app config\nvibe host doctor all --json # verify readiness\n```\n\nDefault setup is snippet-only; use `--write` when you want VibeFrame to merge\nthe generated config. Keep provider keys in `.vibeframe/config.yaml`, user\nconfig, or env files \u2014 not in app host config.\n\n## Native host goal loop\n\nFor long-running work, use Codex Goal mode, Claude Code `/goal`, Cursor, or\nanother host-native goal feature as the outer loop. VibeFrame should not own a\ncompeting project-level goal runner. It provides `--json` commands, dry runs,\nbudget caps, `build-report.json`, `review-report.json`, `nextActions`,\n`safeToAutoRun`, `requiresConfirmation`, `fixOwner`, deterministic repair,\nand render inspection for the host agent to decide what to do next.\n\nCopy-paste Codex:\n\n```text\n/goal Build this VibeFrame project into renders/final.mp4. Use --json for every\nvibe command, run --dry-run before paid operations, use --max-cost 5 for builds\nunless the user gives another budget, read build-report.json and\nreview-report.json before deciding the next action, prefer nextActions before\nguessing, run only safeToAutoRun:true actions automatically, and ask before\nrequiresConfirmation:true actions. Treat retryWith as the compatibility\nfallback, fixOwner:\"vibe\" as CLI repair work, and fixOwner:\"host-agent\" as\nSTORYBOARD.md, DESIGN.md, or composition edits.\nStop only when renders/final.mp4 exists, target duration and aspect ratio are\nmet, inspect render --cheap has no errors, any AI review score is >= 90 when AI review is requested, and every\nremaining host-agent issue is fixed, accepted with rationale, or reported as\nblocked.\n```\n\nCopy-paste Claude Code:\n\n```text\n/goal Finish this VibeFrame render using Claude Code goal mode as the outer\nloop. Use vibe context/schema when unsure, --json everywhere, dry-run before\npaid operations, budget cap via --max-cost 5, nextActions before guessing,\nbuild-report.json/review-report.json as loop state, and safeToAutoRun,\nrequiresConfirmation, and fixOwner to decide between vibe scene repair and\nhost-agent edits. Stop only after final MP4,\ntarget duration/aspect ratio, clean render inspection, any AI review score >= 90 when AI review is requested, and\nno unresolved unacknowledged host-agent issues.\n```\n\n### Composition rules (scene HTML)\n\n`vibe init` installs local composition rules into your project. The\nuniversal copy lives at `SKILL.md` (with `references/*.md`), and\nhost-specific copies are placed where each agent expects them\n(`.claude/skills/hyperframes/` for Claude Code, `.cursor/rules/hyperframes.mdc`\nfor Cursor). **Read `SKILL.md` before authoring any scene composition HTML\nunder `compositions/`** \u2014 it defines the framework rules, motion\nprinciples, type system, and visual-identity hard-gate. The same skill\ngoverns `vibe scene lint` so your authored HTML and the linter stay in\nagreement.\n\nFor render-stable text, do not apply continuous `scale`, `x`, `y`,\n`filter`, or other transform tweens to `.scene-content` or any ancestor\ncontaining live text/cards. Put ambient zoom/parallax on background or media\nlayers only; text should enter briefly and then hold still at its final CSS\nposition.\n\nTo retro-install on a project scaffolded before this command existed, run\n`vibe scene install-skill [--host all]`.\n\n### Scene composer (batch / non-agent fallback)\n\nWhen you don't want to author HTML yourself, `vibe build --mode batch` runs an\nLLM internally with the same skill bundle. It auto-picks a provider based\non available keys (`claude > gemini > openai`) \u2014 pass `--composer <name>`\nto force one:\n\n| Provider | Env var | Spike notes (v0.70) |\n|---|---|---|\n| Claude (default) | `ANTHROPIC_API_KEY` | ~9 s/beat. Fastest, validated baseline. |\n| Gemini | `GOOGLE_API_KEY` | ~20 s/beat. ~2.6\u00D7 cheaper than Claude. |\n| OpenAI | `OPENAI_API_KEY` | ~70 s/beat. gpt-5 reasoning latency \u2014 opt-in only. |\n\nAll three pass first-shot lint at every effort tier on the `vibeframe-promo`\nfixture. Quality on more complex storyboards may differ \u2014 fall back to\n`--composer claude` if a non-default provider repeatedly fails lint.\n\n## Project conventions\n\n<!-- Edit this section with YOUR project's specifics. Examples below. -->\n\n- Default aspect ratio: `16:9`\n- Default scene duration: `3 seconds` (per beat)\n- Brand voice: <describe>\n- Output naming: `renders/<name>-<timestamp>.mp4`\n";
|
|
22
22
|
/**
|
|
23
23
|
* Claude Code project file. Imports AGENTS.md so guidance stays
|
|
24
24
|
* single-sourced; adds Claude-specific overrides (slash commands, etc.).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VideoReviewFeedback } from "../ai-edit.js";
|
|
2
|
-
import { type ReviewIssue, type ReviewSeverity, type ReviewSummary, type ReviewStatus } from "./review-report.js";
|
|
2
|
+
import { type ReviewAction, type ReviewIssue, type ReviewSeverity, type ReviewSummary, type ReviewStatus } from "./review-report.js";
|
|
3
3
|
export interface TimeRange {
|
|
4
4
|
start: number;
|
|
5
5
|
end: number;
|
|
@@ -64,6 +64,7 @@ export interface RenderInspectResult {
|
|
|
64
64
|
score: number;
|
|
65
65
|
issues: ReviewIssue[];
|
|
66
66
|
summary: ReviewSummary;
|
|
67
|
+
nextActions: ReviewAction[];
|
|
67
68
|
sourceReports: string[];
|
|
68
69
|
checks: {
|
|
69
70
|
renderFound: boolean;
|
|
@@ -75,6 +76,7 @@ export interface RenderInspectResult {
|
|
|
75
76
|
height?: number;
|
|
76
77
|
expectedAspect?: string;
|
|
77
78
|
hasAudio?: boolean;
|
|
79
|
+
expectedAudio?: boolean;
|
|
78
80
|
blackFrames: TimeRange[];
|
|
79
81
|
staticFrames: TimeRange[];
|
|
80
82
|
silences: TimeRange[];
|
|
@@ -101,4 +103,5 @@ export declare function aiReviewSeverity(score: number): ReviewSeverity;
|
|
|
101
103
|
export declare function mapAiReviewFeedbackToIssues(feedback: VideoReviewFeedback, videoPath?: string): ReviewIssue[];
|
|
102
104
|
export declare function scoreRenderReview(issues: ReviewIssue[], aiOverallScore?: number): number;
|
|
103
105
|
export declare function inspectRender(opts: RenderInspectOptions): Promise<RenderInspectResult>;
|
|
106
|
+
export declare function renderExpectsAudio(projectDir: string, beatId?: string): Promise<boolean>;
|
|
104
107
|
export declare function resolveRenderVideoPath(projectDir: string, explicit?: string, beatId?: string): Promise<string | null>;
|
|
@@ -2,6 +2,21 @@ export type ReviewSeverity = "error" | "warning" | "info";
|
|
|
2
2
|
export type ReviewStatus = "pass" | "warn" | "fail";
|
|
3
3
|
export type ReviewMode = "project" | "render";
|
|
4
4
|
export type ReviewFixOwner = "vibe" | "host-agent";
|
|
5
|
+
export type ReviewActionKind = "command" | "agent" | "manual";
|
|
6
|
+
export type ReviewActionCostTier = "free" | "low" | "high" | "very-high" | "unknown";
|
|
7
|
+
export interface ReviewAction {
|
|
8
|
+
id: string;
|
|
9
|
+
kind: ReviewActionKind;
|
|
10
|
+
label: string;
|
|
11
|
+
command?: string;
|
|
12
|
+
agentPrompt?: string;
|
|
13
|
+
fixOwner: ReviewFixOwner;
|
|
14
|
+
costTier: ReviewActionCostTier;
|
|
15
|
+
safeToAutoRun: boolean;
|
|
16
|
+
requiresConfirmation: boolean;
|
|
17
|
+
reason: string;
|
|
18
|
+
sourceIssueCodes?: string[];
|
|
19
|
+
}
|
|
5
20
|
export interface ReviewIssue {
|
|
6
21
|
severity: ReviewSeverity;
|
|
7
22
|
code: string;
|
|
@@ -19,6 +34,7 @@ export interface ReviewIssue {
|
|
|
19
34
|
audioCoverageRatio?: number;
|
|
20
35
|
fixOwner?: ReviewFixOwner;
|
|
21
36
|
suggestedFix?: string;
|
|
37
|
+
actions?: ReviewAction[];
|
|
22
38
|
}
|
|
23
39
|
export interface ReviewSummary {
|
|
24
40
|
issueCount: number;
|
|
@@ -40,6 +56,7 @@ export interface ReviewReport {
|
|
|
40
56
|
score: number;
|
|
41
57
|
issues: ReviewIssue[];
|
|
42
58
|
summary: ReviewSummary;
|
|
59
|
+
nextActions: ReviewAction[];
|
|
43
60
|
retryWith: string[];
|
|
44
61
|
sourceReports: string[];
|
|
45
62
|
reportPath?: string;
|
|
@@ -47,8 +64,40 @@ export interface ReviewReport {
|
|
|
47
64
|
export declare function statusFromIssues(issues: ReviewIssue[]): ReviewStatus;
|
|
48
65
|
export declare function scoreIssues(issues: ReviewIssue[]): number;
|
|
49
66
|
export declare function uniqueRetryWith(items: Array<string | undefined | null>): string[];
|
|
67
|
+
export declare function commandReviewAction(command: string, opts: {
|
|
68
|
+
label?: string;
|
|
69
|
+
fixOwner?: ReviewFixOwner;
|
|
70
|
+
reason: string;
|
|
71
|
+
sourceIssueCodes?: string[];
|
|
72
|
+
costTier?: ReviewActionCostTier;
|
|
73
|
+
safeToAutoRun?: boolean;
|
|
74
|
+
requiresConfirmation?: boolean;
|
|
75
|
+
}): ReviewAction;
|
|
76
|
+
export declare function agentReviewAction(opts: {
|
|
77
|
+
label: string;
|
|
78
|
+
agentPrompt: string;
|
|
79
|
+
reason: string;
|
|
80
|
+
sourceIssueCodes?: string[];
|
|
81
|
+
}): ReviewAction;
|
|
82
|
+
export declare function manualReviewAction(opts: {
|
|
83
|
+
label: string;
|
|
84
|
+
reason: string;
|
|
85
|
+
fixOwner?: ReviewFixOwner;
|
|
86
|
+
sourceIssueCodes?: string[];
|
|
87
|
+
}): ReviewAction;
|
|
88
|
+
export declare function reviewActionsFromRetryWith(retryWith: string[], sourceIssueCodes?: string[]): ReviewAction[];
|
|
89
|
+
export declare function normalizeReviewActions(actions: ReviewAction[]): ReviewAction[];
|
|
90
|
+
export declare function deriveNextReviewActions(opts: {
|
|
91
|
+
issues: ReviewIssue[];
|
|
92
|
+
retryWith: string[];
|
|
93
|
+
projectDir?: string;
|
|
94
|
+
}): ReviewAction[];
|
|
50
95
|
export declare function fixOwnerForIssue(issue: Pick<ReviewIssue, "code" | "fixOwner">): ReviewFixOwner;
|
|
51
|
-
export declare function normalizeReviewIssues(issues: ReviewIssue[],
|
|
96
|
+
export declare function normalizeReviewIssues(issues: ReviewIssue[], opts?: ReviewFixOwner | {
|
|
97
|
+
fallbackOwner?: ReviewFixOwner;
|
|
98
|
+
projectDir?: string;
|
|
99
|
+
retryWith?: string[];
|
|
100
|
+
}): ReviewIssue[];
|
|
52
101
|
export declare function summarizeReviewIssues(issues: ReviewIssue[]): ReviewSummary;
|
|
53
102
|
export declare function buildReviewReport(opts: {
|
|
54
103
|
project: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -34,6 +34,19 @@ export type BuildImageProvider = "openai" | "gemini" | "grok";
|
|
|
34
34
|
export type SceneBuildProgressEvent = {
|
|
35
35
|
type: "phase-start";
|
|
36
36
|
phase: "primitives" | "compose" | "render";
|
|
37
|
+
} | {
|
|
38
|
+
type: "character-cached";
|
|
39
|
+
name: string;
|
|
40
|
+
path: string;
|
|
41
|
+
} | {
|
|
42
|
+
type: "character-generated";
|
|
43
|
+
name: string;
|
|
44
|
+
path: string;
|
|
45
|
+
provider: string;
|
|
46
|
+
} | {
|
|
47
|
+
type: "character-failed";
|
|
48
|
+
name: string;
|
|
49
|
+
error: string;
|
|
37
50
|
} | {
|
|
38
51
|
type: "narration-cached";
|
|
39
52
|
beatId: string;
|
|
@@ -46,7 +46,7 @@ export interface LottieOverlayInput {
|
|
|
46
46
|
loop?: boolean;
|
|
47
47
|
}
|
|
48
48
|
export interface EmitSceneInput {
|
|
49
|
-
/** Kebab-case
|
|
49
|
+
/** Kebab-case beat id; emitted composition id is `scene-<id>` to match root-sync. */
|
|
50
50
|
id: string;
|
|
51
51
|
preset: ScenePreset;
|
|
52
52
|
/** Canvas width in px (must match the root composition). */
|
|
@@ -80,6 +80,8 @@ export interface EmitSceneInput {
|
|
|
80
80
|
*/
|
|
81
81
|
lottie?: LottieOverlayInput;
|
|
82
82
|
}
|
|
83
|
+
/** Root-sync's canonical composition id for a storyboard beat id. */
|
|
84
|
+
export declare function sceneCompositionId(beatId: string): string;
|
|
83
85
|
/**
|
|
84
86
|
* Slugify a free-form scene name to a kebab-case id usable in HTML attributes
|
|
85
87
|
* and filenames. Strips diacritics, collapses whitespace, lowercases.
|
|
@@ -133,7 +135,7 @@ export declare function emitSceneHtml(input: EmitSceneInput): string;
|
|
|
133
135
|
*/
|
|
134
136
|
export declare function nextSceneStart(rootHtml: string, overlap?: number): number;
|
|
135
137
|
export interface ClipReferenceInput {
|
|
136
|
-
/**
|
|
138
|
+
/** Beat id — used to derive `scene-<id>` composition id and src path. */
|
|
137
139
|
id: string;
|
|
138
140
|
start: number;
|
|
139
141
|
duration: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReviewIssue, type ReviewSummary, type ReviewStatus } from "./review-report.js";
|
|
1
|
+
import { type ReviewAction, type ReviewIssue, type ReviewSummary, type ReviewStatus } from "./review-report.js";
|
|
2
2
|
export interface ProjectInspectOptions {
|
|
3
3
|
projectDir: string;
|
|
4
4
|
beatId?: string;
|
|
@@ -15,6 +15,7 @@ export interface ProjectInspectResult {
|
|
|
15
15
|
score: number;
|
|
16
16
|
issues: ReviewIssue[];
|
|
17
17
|
summary: ReviewSummary;
|
|
18
|
+
nextActions: ReviewAction[];
|
|
18
19
|
sourceReports: string[];
|
|
19
20
|
checks: {
|
|
20
21
|
files: Record<string, boolean>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BuildAssetKind } from "./build-cache.js";
|
|
2
|
+
import type { ReviewAction } from "./review-report.js";
|
|
2
3
|
export type JobStatus = "queued" | "running" | "completed" | "failed" | "cancelled" | "unknown";
|
|
3
4
|
/**
|
|
4
5
|
* `generate-video` / `generate-music` are provider-backed jobs refreshed by
|
|
@@ -127,6 +128,7 @@ export interface ProjectStatusResult {
|
|
|
127
128
|
latest: JobSummary[];
|
|
128
129
|
};
|
|
129
130
|
warnings: string[];
|
|
131
|
+
nextActions: ReviewAction[];
|
|
130
132
|
retryWith: string[];
|
|
131
133
|
}
|
|
132
134
|
export interface BuildSummary {
|
|
@@ -161,6 +163,7 @@ export interface ReviewSummary {
|
|
|
161
163
|
};
|
|
162
164
|
sourceReports: string[];
|
|
163
165
|
updatedAt?: string;
|
|
166
|
+
nextActions: ReviewAction[];
|
|
164
167
|
retryWith: string[];
|
|
165
168
|
}
|
|
166
169
|
export interface JobSummary {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Beat } from "./storyboard-parse.js";
|
|
2
|
-
export declare const STORYBOARD_CUE_KEYS: readonly ["duration", "narration", "backdrop", "video", "motion", "voice", "music", "asset"];
|
|
2
|
+
export declare const STORYBOARD_CUE_KEYS: readonly ["duration", "narration", "backdrop", "video", "motion", "voice", "music", "asset", "characters"];
|
|
3
3
|
export type StoryboardCueKey = (typeof STORYBOARD_CUE_KEYS)[number];
|
|
4
4
|
export interface StoryboardValidationIssue {
|
|
5
5
|
severity: "error" | "warning";
|
|
@@ -12,10 +12,24 @@ export interface StoryboardValidationResult {
|
|
|
12
12
|
beats: Beat[];
|
|
13
13
|
issues: StoryboardValidationIssue[];
|
|
14
14
|
}
|
|
15
|
+
export type StoryboardBeatUpsertAction = "replaced-starter" | "appended" | "updated";
|
|
16
|
+
export interface StoryboardBeatUpsertInput {
|
|
17
|
+
beatId: string;
|
|
18
|
+
title?: string;
|
|
19
|
+
duration?: number;
|
|
20
|
+
narration?: string;
|
|
21
|
+
backdrop?: string;
|
|
22
|
+
body?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface StoryboardBeatUpsertResult {
|
|
25
|
+
markdown: string;
|
|
26
|
+
action: StoryboardBeatUpsertAction;
|
|
27
|
+
}
|
|
15
28
|
/** Beats beyond this render as static, overstuffed scenes. */
|
|
16
29
|
export declare const MAX_RECOMMENDED_BEAT_SEC = 15;
|
|
17
30
|
export declare function validateStoryboardMarkdown(markdown: string): StoryboardValidationResult;
|
|
18
31
|
export declare function getStoryboardBeat(markdown: string, beatId: string): Beat | null;
|
|
32
|
+
export declare function upsertStoryboardBeat(markdown: string, opts: StoryboardBeatUpsertInput): StoryboardBeatUpsertResult;
|
|
19
33
|
export declare function setStoryboardCue(markdown: string, opts: {
|
|
20
34
|
beatId: string;
|
|
21
35
|
key: string;
|
|
@@ -65,8 +65,35 @@ export interface ProjectFrontmatter {
|
|
|
65
65
|
defaultDuration?: number;
|
|
66
66
|
/** Visual identity preset hint (informational; e.g. "Swiss Pulse"). */
|
|
67
67
|
style?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Reusable character pool. Each entry is either a generation prompt
|
|
70
|
+
* (string → build renders a turnaround sheet at `assets/character-<name>.png`)
|
|
71
|
+
* or an object with `description` (same, explicit) and/or `image` (a
|
|
72
|
+
* bring-your-own reference path, which skips generation). Beats reference
|
|
73
|
+
* these by name via the `characters:` cue to drive reference-to-video.
|
|
74
|
+
*/
|
|
75
|
+
characters?: Record<string, CharacterSpec>;
|
|
68
76
|
[key: string]: unknown;
|
|
69
77
|
}
|
|
78
|
+
/** A character pool entry — a prompt string or a structured spec. */
|
|
79
|
+
export type CharacterSpec = string | {
|
|
80
|
+
description?: string;
|
|
81
|
+
image?: string;
|
|
82
|
+
};
|
|
83
|
+
/** Normalized character ready for build: generation prompt and/or supplied image. */
|
|
84
|
+
export interface ResolvedCharacter {
|
|
85
|
+
name: string;
|
|
86
|
+
/** Generation prompt when the sheet should be rendered (absent if `image` given). */
|
|
87
|
+
prompt?: string;
|
|
88
|
+
/** Bring-your-own reference image path, relative to the project dir. */
|
|
89
|
+
imagePath?: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Flatten the frontmatter `characters` map into build-ready specs. A string or
|
|
93
|
+
* `{ description }` becomes a generation prompt; `{ image }` is used as-is
|
|
94
|
+
* (generation skipped). Entries with neither are dropped.
|
|
95
|
+
*/
|
|
96
|
+
export declare function resolveCharacters(frontmatter: ProjectFrontmatter | undefined): ResolvedCharacter[];
|
|
70
97
|
/**
|
|
71
98
|
* Per-beat cues extracted from the first ```yaml fenced block inside a beat
|
|
72
99
|
* body. The driver passes these to TTS / image / compose calls so the
|
|
@@ -81,8 +108,15 @@ export interface BeatCues {
|
|
|
81
108
|
duration?: number;
|
|
82
109
|
/** Voice override for this beat (overrides project frontmatter `voice`). */
|
|
83
110
|
voice?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Character pool names whose reference sheets drive this beat's
|
|
113
|
+
* reference-to-video generation. A single name or a list.
|
|
114
|
+
*/
|
|
115
|
+
characters?: string | string[];
|
|
84
116
|
[key: string]: unknown;
|
|
85
117
|
}
|
|
118
|
+
/** Normalize a beat's `characters` cue to a clean string[] (single or list). */
|
|
119
|
+
export declare function beatCharacterNames(cues: BeatCues | undefined): string[];
|
|
86
120
|
export interface Beat {
|
|
87
121
|
/**
|
|
88
122
|
* Stable id for the beat. Derivation order:
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file error-envelopes.test.ts
|
|
3
|
+
*
|
|
4
|
+
* Contract/drift detection for the CLI's STRUCTURED ERROR envelope — the JSON
|
|
5
|
+
* that `exitWithError()` (commands/output.ts) writes to stderr when a command
|
|
6
|
+
* fails. Companion to `envelope-snapshots.test.ts`, which only covers the
|
|
7
|
+
* SUCCESS envelope (`outputSuccess`) and `--describe` schemas; the error
|
|
8
|
+
* envelope was previously untested.
|
|
9
|
+
*
|
|
10
|
+
* Why:
|
|
11
|
+
* - Agents and MCP hosts parse the error envelope (`code`, `exitCode`,
|
|
12
|
+
* `retryWith`, `recoverable`) to decide recovery. A regression that renames
|
|
13
|
+
* or drops a field, or changes a code/exit-code, silently breaks that
|
|
14
|
+
* contract. Snapshots make it visible in PR review.
|
|
15
|
+
* - This test also guards against fabricated contracts: the real envelope has
|
|
16
|
+
* no `hint` field and uses SCREAMING_SNAKE codes with no `E_` prefix.
|
|
17
|
+
*
|
|
18
|
+
* The asserted codes/exit-codes were verified by running the built CLI:
|
|
19
|
+
* NOT_FOUND=3, USAGE_ERROR=2, API_ERROR=5, ERROR=1 (the ExitCode enum in
|
|
20
|
+
* commands/output.ts).
|
|
21
|
+
*
|
|
22
|
+
* Maintenance:
|
|
23
|
+
* - Intentional envelope change → update with `pnpm -F @vibeframe/cli exec
|
|
24
|
+
* vitest run -u` and review the diff.
|
|
25
|
+
*/
|
|
26
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/commands/scene.d.ts
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import { Command } from "commander";
|
|
20
20
|
import { type TtsProviderName } from "./_shared/tts-resolve.js";
|
|
21
21
|
import { type ScenePreset, type LottieOverlayInput } from "./_shared/scene-html-emit.js";
|
|
22
|
+
import { type StoryboardBeatUpsertAction } from "./_shared/storyboard-edit.js";
|
|
22
23
|
export declare const sceneCommand: Command;
|
|
23
24
|
export interface SceneAddOptions {
|
|
24
25
|
name: string;
|
|
@@ -43,6 +44,11 @@ export interface SceneAddOptions {
|
|
|
43
44
|
projectDir?: string;
|
|
44
45
|
/** Filename of the root composition (relative to projectDir). */
|
|
45
46
|
insertInto?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Sync STORYBOARD.md when present, then rebuild root refs via root-sync.
|
|
49
|
+
* Defaults to true; pass false for the legacy root-only quick-draft path.
|
|
50
|
+
*/
|
|
51
|
+
syncStoryboard?: boolean;
|
|
46
52
|
/** "gemini" | "openai". */
|
|
47
53
|
imageProvider?: string;
|
|
48
54
|
/** TTS provider preference. Defaults to `"auto"` (ElevenLabs if key set, else Kokoro). */
|
|
@@ -86,6 +92,12 @@ export interface SceneAddResult {
|
|
|
86
92
|
/** Number of word entries emitted into the transcript JSON. */
|
|
87
93
|
transcriptWordCount?: number;
|
|
88
94
|
lottiePath?: string;
|
|
95
|
+
/** Project-relative path to STORYBOARD.md when the command synced it. */
|
|
96
|
+
storyboardPath?: string;
|
|
97
|
+
/** Whether STORYBOARD.md was used as the root-sync source of truth. */
|
|
98
|
+
storyboardSynced?: boolean;
|
|
99
|
+
/** How STORYBOARD.md was changed, or "skipped" when root-only behavior was used. */
|
|
100
|
+
storyboardAction?: "skipped" | StoryboardBeatUpsertAction;
|
|
89
101
|
error?: string;
|
|
90
102
|
}
|
|
91
103
|
export declare function executeSceneAdd(opts: SceneAddOptions): Promise<SceneAddResult>;
|