@vibeframe/cli 0.113.11 → 0.113.26
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 +12 -11
- package/dist/commands/_shared/build-plan.d.ts +1 -1
- package/dist/commands/_shared/compose-aivideo.d.ts +82 -0
- package/dist/commands/_shared/compose-aivideo.test.d.ts +1 -0
- package/dist/commands/_shared/compose-prompts.d.ts +8 -0
- package/dist/commands/_shared/compose-scenes-skills.d.ts +16 -2
- package/dist/commands/_shared/design-parse.d.ts +26 -0
- package/dist/commands/_shared/design-parse.test.d.ts +1 -0
- package/dist/commands/_shared/frontmatter.d.ts +30 -0
- package/dist/commands/_shared/hf-skill-bundle/bundle.d.ts +8 -2
- package/dist/commands/_shared/init-templates.d.ts +2 -2
- package/dist/commands/_shared/install-skill.d.ts +47 -6
- package/dist/commands/_shared/project-config.d.ts +5 -1
- package/dist/commands/_shared/project-config.test.d.ts +1 -0
- package/dist/commands/_shared/root-sync.d.ts +25 -0
- package/dist/commands/_shared/scene-assemble.d.ts +47 -0
- package/dist/commands/_shared/scene-assemble.test.d.ts +1 -0
- package/dist/commands/_shared/scene-build.d.ts +6 -5
- package/dist/commands/_shared/scene-project.d.ts +47 -13
- package/dist/commands/_shared/scene-render.d.ts +6 -0
- package/dist/commands/_shared/storyboard-edit.d.ts +1 -1
- package/dist/commands/_shared/storyboard-parse.d.ts +6 -0
- package/dist/commands/ai-video.d.ts +1 -1
- package/dist/commands/assemble.d.ts +2 -0
- package/dist/commands/design.d.ts +2 -0
- package/dist/commands/export.d.ts +0 -2
- package/dist/commands/generate/video.d.ts +2 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/preview.d.ts +2 -0
- package/dist/commands/preview.test.d.ts +1 -0
- package/dist/index.js +2089 -1065
- package/dist/tools/define-tool.js +3 -0
- package/dist/tools/manifest/design.d.ts +10 -0
- package/dist/tools/manifest/design.test.d.ts +1 -0
- package/dist/tools/manifest/generate.d.ts +3 -3
- package/dist/tools/manifest/index.d.ts +2 -1
- package/dist/tools/manifest/index.js +2144 -1458
- package/package.json +3 -3
package/CONTEXT.md
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
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,
|
|
9
|
-
should own the outer loop: persistence,
|
|
8
|
+
For long-running video work, your host's agent loop (Claude Code, Codex,
|
|
9
|
+
Cursor, or another coding-agent host) should own the outer loop: persistence,
|
|
10
|
+
iteration, and stop decisions.
|
|
10
11
|
VibeFrame owns the video-specific command surface, JSON reports, cost gates,
|
|
11
12
|
deterministic repair, render inspection, and `retryWith` recovery hints.
|
|
12
13
|
|
|
@@ -15,21 +16,21 @@ For the full reference (every flag, default, enum), read
|
|
|
15
16
|
from `vibe schema --list`. This file is the _agent quickstart_: rules,
|
|
16
17
|
conventions, and discovery hooks.
|
|
17
18
|
|
|
18
|
-
##
|
|
19
|
+
## Host agent loop
|
|
19
20
|
|
|
20
|
-
Use
|
|
21
|
-
|
|
21
|
+
Use your host's agent loop as the outer loop rather than inventing a
|
|
22
|
+
VibeFrame-owned loop. The canonical loop is:
|
|
22
23
|
|
|
23
24
|
```text
|
|
24
|
-
|
|
25
|
+
host agent loop -> vibe context/schema -> plan dry-run -> build with budget
|
|
25
26
|
-> status polling -> inspect project -> render -> inspect render
|
|
26
27
|
-> repair/edit using nextActions/fixOwner -> repeat until stop rules pass
|
|
27
28
|
```
|
|
28
29
|
|
|
29
|
-
Copy-paste Codex
|
|
30
|
+
Copy-paste agent prompt (Codex) — a plain prompt, not a built-in command:
|
|
30
31
|
|
|
31
32
|
```text
|
|
32
|
-
|
|
33
|
+
Build my-video/ into a reviewed VibeFrame MP4. Use --json for every vibe
|
|
33
34
|
command, run --dry-run before paid operations, cap generated-asset spend with
|
|
34
35
|
--max-cost 5 where supported, and read build-report.json plus
|
|
35
36
|
review-report.json before deciding the next action. Prefer nextActions: run
|
|
@@ -43,10 +44,10 @@ AI review score is >= 90 when AI review is requested, and unresolved host-agent
|
|
|
43
44
|
accepted with a written reason, or reported as blocked.
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
Copy-paste Claude Code
|
|
47
|
+
Copy-paste agent prompt (Claude Code) — a plain prompt, not a built-in command:
|
|
47
48
|
|
|
48
49
|
```text
|
|
49
|
-
|
|
50
|
+
Finish the VibeFrame render for my-video/ using your host's agent loop as
|
|
50
51
|
the outer loop. Use vibe context/schema when unsure, --json everywhere,
|
|
51
52
|
dry-run before paid operations, --max-cost 5 for builds, nextActions before
|
|
52
53
|
custom recovery, and build-report.json/review-report.json as loop state.
|
|
@@ -223,7 +224,7 @@ Review report contract:
|
|
|
223
224
|
for storyboard/design/composition edits the host agent should make. Prefer
|
|
224
225
|
`nextActions` first: run only `safeToAutoRun:true` actions automatically, ask
|
|
225
226
|
before `requiresConfirmation:true`, and use `retryWith` only as the fallback.
|
|
226
|
-
|
|
227
|
+
The outer loop should not stop while `host-agent` issues remain unless
|
|
227
228
|
they are fixed, intentionally accepted with a written reason, or reported as
|
|
228
229
|
blocked.
|
|
229
230
|
|
|
@@ -2,7 +2,7 @@ import { type BuildAssetKind } from "./build-cache.js";
|
|
|
2
2
|
import { type AssetFreshness } from "./build-asset-metadata.js";
|
|
3
3
|
import { type LoadedProjectConfig } from "./project-config.js";
|
|
4
4
|
import { type StoryboardValidationIssue } from "./storyboard-edit.js";
|
|
5
|
-
export type BuildStage = "assets" | "compose" | "sync" | "render" | "all";
|
|
5
|
+
export type BuildStage = "assets" | "transcript" | "compose" | "sync" | "render" | "all";
|
|
6
6
|
export type BuildPlanStatus = "ready" | "invalid";
|
|
7
7
|
export type AssetPlanReason = "canonical-exists" | "canonical-stale" | "canonical-unknown" | "content-cache-hit" | "force" | "missing" | "referenced-asset" | "invalid-reference" | "stage-skipped";
|
|
8
8
|
export type ProviderResolutionKind = BuildAssetKind | "composer";
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type Beat } from "./storyboard-parse.js";
|
|
2
|
+
export interface AiVideoDesignTokens {
|
|
3
|
+
/** Headline + body text colour. */
|
|
4
|
+
primary: string;
|
|
5
|
+
/** Scrim / fade-to ground colour. */
|
|
6
|
+
ground: string;
|
|
7
|
+
/** Eyebrow rule + single accent. */
|
|
8
|
+
accent: string;
|
|
9
|
+
/** Headline / eyebrow font-family. */
|
|
10
|
+
headFont: string;
|
|
11
|
+
/** Sub-line (italic) font-family. */
|
|
12
|
+
bodyFont: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const DEFAULT_AIVIDEO_TOKENS: AiVideoDesignTokens;
|
|
15
|
+
/** Per-scene overlay copy derived from a beat heading + optional cues. */
|
|
16
|
+
export interface OverlayText {
|
|
17
|
+
kicker: string;
|
|
18
|
+
title: string;
|
|
19
|
+
sub: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Derive the lower-third copy for a beat. Authors override deterministically via
|
|
23
|
+
* `eyebrow`/`title`/`caption` cues; otherwise it falls back to the heading.
|
|
24
|
+
*/
|
|
25
|
+
export declare function beatOverlayText(beat: Beat): OverlayText;
|
|
26
|
+
/**
|
|
27
|
+
* ffmpeg args to concat clips into one uniform background video. Each input is
|
|
28
|
+
* scaled+cropped to fill {width}x{height} at {fps}, then concatenated (no
|
|
29
|
+
* audio — narration rides a separate track).
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildBgConcatArgs(clipPaths: string[], outPath: string, opts?: {
|
|
32
|
+
width?: number;
|
|
33
|
+
height?: number;
|
|
34
|
+
fps?: number;
|
|
35
|
+
crf?: number;
|
|
36
|
+
}): string[];
|
|
37
|
+
/**
|
|
38
|
+
* A transparent lower-third overlay scene. The root background video shows
|
|
39
|
+
* through; a bottom scrim keeps text legible. Entrances only (the producer
|
|
40
|
+
* cuts on `data-duration`); the final scene fades to ground.
|
|
41
|
+
*/
|
|
42
|
+
export declare function emitOverlayScene(opts: {
|
|
43
|
+
id: string;
|
|
44
|
+
text: OverlayText;
|
|
45
|
+
duration: number;
|
|
46
|
+
tokens?: AiVideoDesignTokens;
|
|
47
|
+
isLast?: boolean;
|
|
48
|
+
}): string;
|
|
49
|
+
/**
|
|
50
|
+
* Insert the single background `<video>` into `#root` (idempotent). Custom and
|
|
51
|
+
* managed elements are otherwise untouched; the bg video carries no
|
|
52
|
+
* `class="clip"`, so it is not subject to same-track clip scheduling and sits
|
|
53
|
+
* behind the scene overlays via `z-index`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function injectBgVideo(indexHtml: string, src: string, totalDuration: number): string;
|
|
56
|
+
export interface ComposeAiVideoResult {
|
|
57
|
+
bgVideoRel: string;
|
|
58
|
+
sceneFiles: string[];
|
|
59
|
+
totalDurationSec: number;
|
|
60
|
+
beats: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Orchestrate the deterministic compose: concat clips → bg-full.mp4, emit
|
|
64
|
+
* transparent overlay scenes, inject the bg video into index.html. Caller runs
|
|
65
|
+
* `root-sync` afterward to wire scene clip refs + narration.
|
|
66
|
+
*/
|
|
67
|
+
export declare function composeAiVideo(opts: {
|
|
68
|
+
projectDir: string;
|
|
69
|
+
tokens?: AiVideoDesignTokens;
|
|
70
|
+
/** Resolve the clip path for a beat (defaults to `assets/video-<id>.mp4`). */
|
|
71
|
+
clipRelFor?: (beat: Beat) => string;
|
|
72
|
+
}): Promise<ComposeAiVideoResult>;
|
|
73
|
+
/** Minimal root composition shell carrying the single bg video. The sync stage
|
|
74
|
+
* adds the `<!-- vibe-scene-build -->` block (scene clip refs + narration). */
|
|
75
|
+
export declare function buildRootShell(tokens: AiVideoDesignTokens, bgRel: string, totalDuration: number): string;
|
|
76
|
+
/**
|
|
77
|
+
* Map a DESIGN.md to background-video tokens. Named color tokens (front-matter
|
|
78
|
+
* `colors: { primary, ground, accent }` or descriptive keys) win; otherwise the
|
|
79
|
+
* palette is read by luminance (darkest → ground, lightest → primary) and the
|
|
80
|
+
* most-saturated remaining color becomes the accent.
|
|
81
|
+
*/
|
|
82
|
+
export declare function extractDesignTokens(designMd: string): AiVideoDesignTokens;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -73,6 +73,14 @@ export interface ComposePromptsResult {
|
|
|
73
73
|
projectDir: string;
|
|
74
74
|
/** Project-root-relative path to DESIGN.md (always "DESIGN.md"). */
|
|
75
75
|
designReference: string;
|
|
76
|
+
/**
|
|
77
|
+
* Project-root-relative path to the optional COMPOSITION.md structural
|
|
78
|
+
* contract (`"COMPOSITION.md"`), or `null` when the project doesn't have one.
|
|
79
|
+
* Parallel to {@link designReference}: DESIGN.md is the visual hard-gate,
|
|
80
|
+
* COMPOSITION.md is the structural hard-gate (layout system, GSAP timeline
|
|
81
|
+
* conventions, element/track rules). The host agent must honor it when present.
|
|
82
|
+
*/
|
|
83
|
+
compositionReference: string | null;
|
|
76
84
|
/** Project-root-relative path to STORYBOARD.md (always "STORYBOARD.md"). */
|
|
77
85
|
storyboardReference: string;
|
|
78
86
|
/**
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
* Lint feedback retry loop comes in C4 (extends this module).
|
|
26
26
|
*/
|
|
27
27
|
import { type LintFinding } from "./scene-lint.js";
|
|
28
|
+
/** Resolve the compose fan-out limit (env override, clamped to the beat count). */
|
|
29
|
+
export declare function composeConcurrency(beatCount: number): number;
|
|
28
30
|
import { type Beat } from "./storyboard-parse.js";
|
|
29
31
|
import { type ComposerProvider } from "./composer-resolve.js";
|
|
30
32
|
import type { SceneTranscriptWord } from "./scene-html-emit.js";
|
|
@@ -35,6 +37,13 @@ export interface ComposeBeatContext {
|
|
|
35
37
|
beat: Beat;
|
|
36
38
|
/** Project's `DESIGN.md` content (visual identity hard-gate). */
|
|
37
39
|
designMd: string;
|
|
40
|
+
/**
|
|
41
|
+
* Optional `COMPOSITION.md` content — the per-project STRUCTURAL contract
|
|
42
|
+
* (layout system, GSAP timeline conventions, element/track rules), parallel
|
|
43
|
+
* to DESIGN.md's visual contract. Injected into the system prompt as a
|
|
44
|
+
* hard-gate when present.
|
|
45
|
+
*/
|
|
46
|
+
compositionMd?: string;
|
|
38
47
|
/** Storyboard's global direction (everything before the first `## Beat`). */
|
|
39
48
|
storyboardGlobal: string;
|
|
40
49
|
/** Hyperframes skill bundle content + hash, from `loadHyperframesSkillBundle()`. */
|
|
@@ -101,8 +110,8 @@ export interface ComposeBeatResult {
|
|
|
101
110
|
/** Composer provider that produced this beat. */
|
|
102
111
|
provider: ComposerProvider;
|
|
103
112
|
}
|
|
104
|
-
/** Build the system prompt — skill bundle + DESIGN.md hard-gate. */
|
|
105
|
-
export declare function buildSystemPrompt(ctx: Pick<ComposeBeatContext, "skillBundle" | "designMd">): string;
|
|
113
|
+
/** Build the system prompt — skill bundle + DESIGN.md hard-gate (+ optional COMPOSITION.md). */
|
|
114
|
+
export declare function buildSystemPrompt(ctx: Pick<ComposeBeatContext, "skillBundle" | "designMd" | "compositionMd">): string;
|
|
106
115
|
/**
|
|
107
116
|
* Word-level timing entries above this count are downgraded to coarse,
|
|
108
117
|
* phrase-level anchors in the prompt. A token-budget guard: a 60s narration
|
|
@@ -267,6 +276,11 @@ export type ComposeProgressEvent = {
|
|
|
267
276
|
export interface ComposeScenesParams {
|
|
268
277
|
/** Path to DESIGN.md, relative to project root. */
|
|
269
278
|
design?: string;
|
|
279
|
+
/**
|
|
280
|
+
* Path to the optional COMPOSITION.md structural contract, relative to project
|
|
281
|
+
* root. Defaults to `COMPOSITION.md`; silently ignored when absent.
|
|
282
|
+
*/
|
|
283
|
+
composition?: string;
|
|
270
284
|
/** Path to STORYBOARD.md, relative to project root. */
|
|
271
285
|
storyboard?: string;
|
|
272
286
|
/** Scene project root, relative to outputDir. Defaults to outputDir. */
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface ParsedDesign {
|
|
2
|
+
/** `name:` from front-matter, if present. */
|
|
3
|
+
name?: string;
|
|
4
|
+
/** Color tokens — front-matter `colors:` map, else extracted from prose hexes. */
|
|
5
|
+
colors: Record<string, string>;
|
|
6
|
+
/** Typography tokens from front-matter `typography:` (shape left to the spec). */
|
|
7
|
+
typography: Record<string, unknown>;
|
|
8
|
+
/** `## ` section title → prose body (trimmed). */
|
|
9
|
+
sections: Record<string, string>;
|
|
10
|
+
/** Raw parsed front-matter object (`{}` when absent/invalid). */
|
|
11
|
+
frontmatter: Record<string, unknown>;
|
|
12
|
+
/** Original document. */
|
|
13
|
+
raw: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function parseDesign(md: string): ParsedDesign;
|
|
16
|
+
export interface DesignValidationIssue {
|
|
17
|
+
severity: "error" | "warning" | "info";
|
|
18
|
+
code: string;
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Lint a DESIGN.md for the soft contract: parseable front-matter, at least a
|
|
23
|
+
* couple of palette colors, and the core prose sections. Warnings/infos only —
|
|
24
|
+
* a thin DESIGN.md is valid, just less useful to the composer.
|
|
25
|
+
*/
|
|
26
|
+
export declare function validateDesignMarkdown(md: string): DesignValidationIssue[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module _shared/frontmatter
|
|
3
|
+
*
|
|
4
|
+
* One canonical "YAML frontmatter + markdown body" splitter for all VibeFrame
|
|
5
|
+
* `.md` files. Previously each consumer (storyboard, design, install-skill)
|
|
6
|
+
* declared its own `/^---\n…\n---/` regex + `yaml.parse` — this consolidates
|
|
7
|
+
* them.
|
|
8
|
+
*
|
|
9
|
+
* The shape matches Google's Open Knowledge Format (OKF) and Mintlify: a leading
|
|
10
|
+
* `---` YAML block, then a free-form markdown body. VibeFrame project files
|
|
11
|
+
* (STORYBOARD.md, DESIGN.md, CHARACTERS.md, …) are OKF concept documents; docs/
|
|
12
|
+
* pages carry OKF/Mintlify frontmatter (`type`, `title`, `description`, `tags`).
|
|
13
|
+
*/
|
|
14
|
+
/** Leading `---\n…\n---` block. Anchored to the start of the (normalized) text. */
|
|
15
|
+
export declare const FRONTMATTER_RE: RegExp;
|
|
16
|
+
export interface ExtractedFrontmatter {
|
|
17
|
+
/** Parsed frontmatter map, or `null` when absent / invalid / not a map. */
|
|
18
|
+
data: Record<string, unknown> | null;
|
|
19
|
+
/** Markdown body after the frontmatter block (or the whole doc when absent). */
|
|
20
|
+
body: string;
|
|
21
|
+
/** The full document, CRLF-normalized to LF. */
|
|
22
|
+
raw: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Split a leading YAML frontmatter block from the markdown body. CRLF is
|
|
26
|
+
* normalized to LF. Returns `data: null` (freeform) when there is no leading
|
|
27
|
+
* block, the YAML is invalid, or it is not a plain object — callers decide
|
|
28
|
+
* whether that means `undefined` or `{}`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function extractFrontmatter(md: string): ExtractedFrontmatter;
|
|
@@ -45,8 +45,14 @@ export declare const BUNDLE_VERSION = "970367f-2026-04-25";
|
|
|
45
45
|
*
|
|
46
46
|
* Side-effect free except for the optional `~/.claude/skills/hyperframes/`
|
|
47
47
|
* filesystem read.
|
|
48
|
+
*
|
|
49
|
+
* Async because the vendored snapshot content is loaded via a lazy
|
|
50
|
+
* `await import("./bundle-content.js")` (see {@link buildVendored}) so paths
|
|
51
|
+
* that never need it (agent-mode, template composer) don't pay to evaluate the
|
|
52
|
+
* ~52KB string. When an installed skill is present, the vendored content module
|
|
53
|
+
* is never imported at all.
|
|
48
54
|
*/
|
|
49
|
-
export declare function loadHyperframesSkillBundle(): {
|
|
55
|
+
export declare function loadHyperframesSkillBundle(): Promise<{
|
|
50
56
|
content: string;
|
|
51
57
|
/** "installed" (user has ~/.claude/skills/hyperframes/) or "vendored" (esbuild-inlined snapshot). */
|
|
52
58
|
source: "installed" | "vendored";
|
|
@@ -54,4 +60,4 @@ export declare function loadHyperframesSkillBundle(): {
|
|
|
54
60
|
hint: string;
|
|
55
61
|
/** Stable hash of (BUNDLE_VERSION + content). Used as cache-key input. */
|
|
56
62
|
hash: string;
|
|
57
|
-
}
|
|
63
|
+
}>;
|
|
@@ -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## 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";
|
|
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## Host agent loop\n\nFor long-running work, use your host's agent loop (Claude Code, Codex, Cursor,\nor another coding-agent host) as the outer loop. VibeFrame should not own a\ncompeting project-level agent loop. 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 agent prompt (Codex) \u2014 a plain prompt, not a built-in command:\n\n```text\nBuild 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 agent prompt (Claude Code) \u2014 a plain prompt, not a built-in command:\n\n```text\nFinish this VibeFrame render using your host's agent loop 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\nComposition rules live in the **Hyperframes skill** \u2014 framework rules, motion\nprinciples, type system, and visual-identity hard-gate. **Load that skill\nbefore authoring any scene composition HTML under `compositions/`.** The same\nrules govern `vibe scene lint`, so your authored HTML and the linter stay in\nagreement.\n\nWhere the skill comes from depends on your setup:\n\n- If the `hyperframes` skill is installed globally (e.g. Claude Code), your\n agent already has it \u2014 `vibe init` does **not** copy it into the project.\n- Otherwise `vibe init` writes a local copy: universal `SKILL.md` (with\n `references/*.md`) at the project root, plus host layouts\n (`.claude/skills/hyperframes/`, `.cursor/rules/hyperframes.mdc`).\n\nTo get editable per-project copies on demand, run\n`vibe scene install-skill [--host all]` (these copies are gitignored by\ndefault \u2014 see `.gitignore`).\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\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.).
|
|
@@ -47,7 +47,7 @@ export interface EnvExampleOptions {
|
|
|
47
47
|
*/
|
|
48
48
|
export declare function renderEnvExample(opts?: EnvExampleOptions): string;
|
|
49
49
|
/** Lines vibe init merges into the project's .gitignore (idempotent). */
|
|
50
|
-
export declare const GITIGNORE_ADDITIONS = "\n# VibeFrame\n.env\n.env.local\nrenders/\n.pipeline-state.yaml\n*.vibe.json\n.vibeframe/\n";
|
|
50
|
+
export declare const GITIGNORE_ADDITIONS = "\n# VibeFrame\n.env\n.env.local\nrenders/\n.pipeline-state.yaml\n*.vibe.json\n.vibeframe/\n\n# Vendored Hyperframes skill copies \u2014 regenerable via 'vibe scene install-skill'.\n# Delete these lines if you eject and want to commit per-project customizations.\n/SKILL.md\n/references/\n/.claude/skills/hyperframes/\n/.cursor/rules/hyperframes.mdc\n";
|
|
51
51
|
/**
|
|
52
52
|
* vibe.project.yaml minimal scaffold. Only written when no project
|
|
53
53
|
* config exists — `vibe init` never overwrites an existing file unless
|
|
@@ -22,16 +22,32 @@
|
|
|
22
22
|
* references/{house-style,...}.md
|
|
23
23
|
* .cursor/rules/hyperframes.mdc # if hosts includes "cursor"
|
|
24
24
|
*
|
|
25
|
-
* Codex + Aider are AGENTS.md-driven hosts; they
|
|
26
|
-
* SKILL.md
|
|
27
|
-
*
|
|
25
|
+
* Codex + Aider are AGENTS.md-driven hosts; they discover the project-root
|
|
26
|
+
* SKILL.md because AGENTS.md points at it in prose (the init-templates
|
|
27
|
+
* AGENTS_MD "Composition rules" section, not an `@`-import).
|
|
28
28
|
*
|
|
29
29
|
* The content is byte-identical to what `loadHyperframesSkillBundle()`
|
|
30
|
-
* uses — same vendored files, same `BUNDLE_VERSION`.
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* uses — same vendored files, same `BUNDLE_VERSION`. Build/render never read
|
|
31
|
+
* these project files (they use the vendored bundle); they exist only so host
|
|
32
|
+
* agents can read the rules and so users can edit them per project.
|
|
33
|
+
*
|
|
34
|
+
* Lean scaffolds: the automatic `vibe init` path passes `lean: true`, so when
|
|
35
|
+
* the Hyperframes skill is already installed globally
|
|
36
|
+
* (`hasGlobalHyperframesSkill()`) it skips the redundant copies — the
|
|
37
|
+
* `.claude/skills/hyperframes/` copy always, and the root `SKILL.md` +
|
|
38
|
+
* `references/` unless a root-reading host (codex/aider/gemini/opencode) needs
|
|
39
|
+
* them. Explicit `vibe scene install-skill` omits `lean`, fully materializing
|
|
40
|
+
* editable copies regardless (the "eject").
|
|
33
41
|
*/
|
|
34
42
|
import type { AgentHostId } from "../../utils/agent-host-detect.js";
|
|
43
|
+
/**
|
|
44
|
+
* True when the Hyperframes skill is installed at the user's global Claude
|
|
45
|
+
* skills dir (`~/.claude/skills/hyperframes/`). When present, materializing the
|
|
46
|
+
* skill into a project is redundant — the host agent already loads it globally —
|
|
47
|
+
* so `vibe init` keeps the scaffold lean and skips the copies. Explicit
|
|
48
|
+
* `vibe scene install-skill` ignores this (it's the opt-in "eject" path).
|
|
49
|
+
*/
|
|
50
|
+
export declare function hasGlobalHyperframesSkill(): boolean;
|
|
35
51
|
/** Hosts the install-skill command knows file layouts for. */
|
|
36
52
|
export type InstallSkillHost = "claude-code" | "cursor" | "all";
|
|
37
53
|
export interface InstallSkillOptions {
|
|
@@ -47,6 +63,24 @@ export interface InstallSkillOptions {
|
|
|
47
63
|
force?: boolean;
|
|
48
64
|
/** Don't write — just describe what would happen. */
|
|
49
65
|
dryRun?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Opt into redundancy gating: skip copies the globally-installed Hyperframes
|
|
68
|
+
* skill already provides. The automatic `vibe init` path sets this so the
|
|
69
|
+
* scaffold stays lean; the explicit `vibe scene install-skill` path leaves it
|
|
70
|
+
* false to fully materialize editable copies (the "eject"). Default false.
|
|
71
|
+
*/
|
|
72
|
+
lean?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Caller signals a root-reading host (codex / aider / gemini / opencode) is
|
|
75
|
+
* present, so the root `SKILL.md` + `references/` must be written even when
|
|
76
|
+
* the global Claude skill exists. Default false. Only consulted when `lean`.
|
|
77
|
+
*/
|
|
78
|
+
rootReaderHostPresent?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Override the global-skill probe (testing seam). Defaults to
|
|
81
|
+
* {@link hasGlobalHyperframesSkill}. Only consulted when `lean`.
|
|
82
|
+
*/
|
|
83
|
+
hasGlobalSkill?: boolean;
|
|
50
84
|
}
|
|
51
85
|
export type InstallSkillFileStatus = "wrote" | "skipped-exists" | "would-write" | "would-skip-exists";
|
|
52
86
|
export interface InstallSkillFileAction {
|
|
@@ -59,6 +93,13 @@ export interface InstallSkillResult {
|
|
|
59
93
|
bundleVersion: string;
|
|
60
94
|
files: InstallSkillFileAction[];
|
|
61
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Map an `AgentHostId[]` to whether a root-reading host is present. Codex,
|
|
98
|
+
* Aider, Gemini, and OpenCode read the project-root `SKILL.md` via AGENTS.md
|
|
99
|
+
* prose — they have no global-skill mechanism, so the root files must be
|
|
100
|
+
* written for them even when the global Claude skill exists.
|
|
101
|
+
*/
|
|
102
|
+
export declare function deriveRootReaderPresent(detected: AgentHostId[]): boolean;
|
|
62
103
|
/**
|
|
63
104
|
* Install Hyperframes skill files at the project + host-specific paths.
|
|
64
105
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SceneAspect } from "./scene-project.js";
|
|
1
|
+
import type { SceneAspect, SceneKind } from "./scene-project.js";
|
|
2
2
|
export declare const VIBE_CONFIG_FILENAME = "vibe.config.json";
|
|
3
3
|
export declare const LEGACY_VIBE_PROJECT_FILENAME = "vibe.project.yaml";
|
|
4
4
|
export type CompositionEngine = "hyperframes";
|
|
@@ -11,6 +11,8 @@ export interface VibeProjectConfigV1 {
|
|
|
11
11
|
schemaVersion: "1";
|
|
12
12
|
name: string;
|
|
13
13
|
aspect: SceneAspect;
|
|
14
|
+
/** Project kind — drives which pipeline stages run + the default composer. */
|
|
15
|
+
kind: SceneKind;
|
|
14
16
|
defaults: {
|
|
15
17
|
sceneDurationSec: number;
|
|
16
18
|
narrationPaddingSec: number;
|
|
@@ -49,12 +51,14 @@ export interface LoadedProjectConfig {
|
|
|
49
51
|
export declare function defaultProjectConfig(opts: {
|
|
50
52
|
name: string;
|
|
51
53
|
aspect?: SceneAspect;
|
|
54
|
+
kind?: SceneKind;
|
|
52
55
|
sceneDurationSec?: number;
|
|
53
56
|
}): VibeProjectConfigV1;
|
|
54
57
|
export declare function mergeProjectConfig(parsed: Partial<VibeProjectConfigV1> | null | undefined, fallback: VibeProjectConfigV1): VibeProjectConfigV1;
|
|
55
58
|
export declare function projectConfigJson(opts: {
|
|
56
59
|
name: string;
|
|
57
60
|
aspect?: SceneAspect;
|
|
61
|
+
kind?: SceneKind;
|
|
58
62
|
sceneDurationSec?: number;
|
|
59
63
|
}): string;
|
|
60
64
|
export declare function readProjectConfig(projectDir: string): Promise<LoadedProjectConfig>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -22,6 +22,19 @@ export interface RootSyncPlan {
|
|
|
22
22
|
nextHtml?: string;
|
|
23
23
|
totalDurationSec?: number;
|
|
24
24
|
}
|
|
25
|
+
export interface ExpectedRootSync {
|
|
26
|
+
block: string;
|
|
27
|
+
totalDurationSec: number;
|
|
28
|
+
audioRefs: Array<{
|
|
29
|
+
beatId: string;
|
|
30
|
+
kind: "narration" | "music";
|
|
31
|
+
src: string;
|
|
32
|
+
start: number;
|
|
33
|
+
duration: number;
|
|
34
|
+
trackIndex: number;
|
|
35
|
+
volume?: number;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
25
38
|
export declare function createRootSyncPlan(opts: {
|
|
26
39
|
projectDir: string;
|
|
27
40
|
beats: RootSyncBeatInput[];
|
|
@@ -58,3 +71,15 @@ export declare function resolveSyncedBeatDuration(opts: {
|
|
|
58
71
|
* {@link loadProjectRootSyncBeats}.
|
|
59
72
|
*/
|
|
60
73
|
export declare function resolveProjectBeatDurations(projectDir: string): Promise<Map<string, number>>;
|
|
74
|
+
/**
|
|
75
|
+
* The managed `<!-- vibe-scene-build -->` block is the SINGLE source of scene
|
|
76
|
+
* clip refs + narration/music audio. Custom elements (e.g. a `bg-video`,
|
|
77
|
+
* overlay decorations) are left untouched.
|
|
78
|
+
*
|
|
79
|
+
* Fast path: one clean block and no stray managed refs → in-place replace (no
|
|
80
|
+
* churn). Otherwise (zero/duplicate blocks, or stray `scene-*`/`narration-*`/
|
|
81
|
+
* `music-*` refs from a hand-edited root) → strip every managed block AND every
|
|
82
|
+
* stray managed ref, then insert exactly one block. This makes the sync
|
|
83
|
+
* idempotent and structurally unable to double-wire narration audio.
|
|
84
|
+
*/
|
|
85
|
+
export declare function applyRootSyncHtml(html: string, expected: ExpectedRootSync): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module _shared/scene-assemble
|
|
3
|
+
*
|
|
4
|
+
* The audio-assemble stage: lay a scene project's `<audio>` elements onto an
|
|
5
|
+
* already-rendered (silent) video in one FFmpeg pass. The Hyperframes producer
|
|
6
|
+
* emits silent video — sub-composition `<audio>` elements are not captured — so
|
|
7
|
+
* we scan the project ourselves and mux them in with `-c:v copy` (no re-encode).
|
|
8
|
+
*
|
|
9
|
+
* Extracted from `executeSceneRender` so the mux is a first-class, independently
|
|
10
|
+
* runnable step: `vibe render --silent` emits silent video, `vibe assemble` adds
|
|
11
|
+
* the audio. The default `vibe render` still renders + assembles in one shot.
|
|
12
|
+
*/
|
|
13
|
+
import type { RenderFormat } from "./scene-render.js";
|
|
14
|
+
export interface SceneAssembleOptions {
|
|
15
|
+
/** Project directory (the Hyperframes scene project). */
|
|
16
|
+
projectDir: string;
|
|
17
|
+
/** Root composition file relative to projectDir (default: "index.html"). */
|
|
18
|
+
root?: string;
|
|
19
|
+
/** The rendered (silent) video to mux audio into. Relative paths resolve against projectDir. */
|
|
20
|
+
videoPath: string;
|
|
21
|
+
format?: RenderFormat;
|
|
22
|
+
/**
|
|
23
|
+
* Known total video duration in seconds (e.g. `job.totalFrames / fps`). When
|
|
24
|
+
* omitted, it is ffprobed from {@link videoPath}; the mux uses it to cap audio.
|
|
25
|
+
*/
|
|
26
|
+
videoDuration?: number;
|
|
27
|
+
onProgress?: (pct: number, stage: string) => void;
|
|
28
|
+
}
|
|
29
|
+
export interface SceneAssembleResult {
|
|
30
|
+
success: boolean;
|
|
31
|
+
/** Number of `<audio>` elements found across the project. */
|
|
32
|
+
audioCount: number;
|
|
33
|
+
/** True when at least one audio track was muxed into the video. */
|
|
34
|
+
audioMuxApplied: boolean;
|
|
35
|
+
/** Non-fatal warning when the mux failed or threw (video left untouched). */
|
|
36
|
+
audioMuxWarning?: string;
|
|
37
|
+
/** Absolute path to the (in-place-updated) video. */
|
|
38
|
+
outputPath: string;
|
|
39
|
+
/** Set when {@link success} is false (missing inputs). */
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Scan the project's audio and mux it onto {@link SceneAssembleOptions.videoPath}
|
|
44
|
+
* in place. Best-effort on the mux itself: a scan/mux failure becomes a warning,
|
|
45
|
+
* not a hard error. Returns `success:false` only when a required input is missing.
|
|
46
|
+
*/
|
|
47
|
+
export declare function executeSceneAssemble(opts: SceneAssembleOptions): Promise<SceneAssembleResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -247,7 +247,7 @@ export interface SceneBuildOptions {
|
|
|
247
247
|
* based on env keys (claude > gemini > openai). Pass an explicit value
|
|
248
248
|
* to require that provider's key.
|
|
249
249
|
*/
|
|
250
|
-
composer?: ComposerProvider;
|
|
250
|
+
composer?: ComposerProvider | "template";
|
|
251
251
|
skipNarration?: boolean;
|
|
252
252
|
skipBackdrop?: boolean;
|
|
253
253
|
skipRender?: boolean;
|
|
@@ -302,9 +302,9 @@ export interface SceneBuildOptions {
|
|
|
302
302
|
* - `failed` — primitives, compose, or render errored. {@link error}
|
|
303
303
|
* carries the message; {@link beats} reflects partial state.
|
|
304
304
|
*/
|
|
305
|
-
export type SceneBuildPhase = "done" | "assets-only" | "pending-jobs" | "compose-only" | "sync-only" | "render-only" | "needs-author" | "failed";
|
|
305
|
+
export type SceneBuildPhase = "done" | "assets-only" | "transcript-only" | "pending-jobs" | "compose-only" | "sync-only" | "render-only" | "needs-author" | "failed";
|
|
306
306
|
export type BuildWorkflowStatus = "done" | "running" | "needs-author" | "failed" | "ready";
|
|
307
|
-
export type BuildCurrentStage = "assets" | "compose" | "sync" | "render" | "done";
|
|
307
|
+
export type BuildCurrentStage = "assets" | "transcript" | "compose" | "sync" | "render" | "done";
|
|
308
308
|
export interface BuildBeatSummary {
|
|
309
309
|
total: number;
|
|
310
310
|
assetsReady: number;
|
|
@@ -353,6 +353,7 @@ export interface SceneBuildResult {
|
|
|
353
353
|
composePrompts?: {
|
|
354
354
|
skillReference: string | null;
|
|
355
355
|
designReference: string;
|
|
356
|
+
compositionReference: string | null;
|
|
356
357
|
storyboardReference: string;
|
|
357
358
|
compositionsDir: string;
|
|
358
359
|
instructions: string[];
|
|
@@ -366,7 +367,7 @@ export interface SceneBuildResult {
|
|
|
366
367
|
beatSummary?: BuildBeatSummary;
|
|
367
368
|
estimatedCostUsd?: number;
|
|
368
369
|
costUsd?: number;
|
|
369
|
-
stageReports?: Record<"assets" | "compose" | "sync" | "render", StageReport>;
|
|
370
|
+
stageReports?: Record<"assets" | "transcript" | "compose" | "sync" | "render", StageReport>;
|
|
370
371
|
sceneRepair?: BuildSceneRepairSummary;
|
|
371
372
|
jobs?: JobRecord[];
|
|
372
373
|
warnings?: string[];
|
|
@@ -499,7 +500,7 @@ declare function toBuildReport(projectDir: string, result: SceneBuildResult): {
|
|
|
499
500
|
}[];
|
|
500
501
|
outputPath: string | undefined;
|
|
501
502
|
sceneRepair: BuildSceneRepairSummary;
|
|
502
|
-
stageReports: Record<"assets" | "compose" | "sync" | "render", StageReport> | undefined;
|
|
503
|
+
stageReports: Record<"assets" | "compose" | "sync" | "render" | "transcript", StageReport> | undefined;
|
|
503
504
|
warnings: string[];
|
|
504
505
|
retryWith: string[];
|
|
505
506
|
totalLatencyMs: number;
|