diff --git a/docs/guides/media.mdx b/docs/guides/media.mdx index 3e13dae9ed5..71c33128e3b 100644 --- a/docs/guides/media.mdx +++ b/docs/guides/media.mdx @@ -63,6 +63,16 @@ Watch once from beginning to end and check: - voice clarity on ordinary headphones and laptop speakers; - missing files, temporary URLs, and late-loading media. +## Reuse an approved recipe + +Ask the agent to save an approved video's design and storyboard as a named +recipe for later projects. Saving the same name again creates a new version +and archives the previous project version. + +If the new version has no `BRIEF.md`, importing that recipe into another +project does not restore the older brief. The earlier brief remains available +in the archived version. + ## Choose a media task diff --git a/packages/cli/src/media-use/lib/recipe-store.mjs b/packages/cli/src/media-use/lib/recipe-store.mjs index 44b95ecafe2..9e1ac57487c 100644 --- a/packages/cli/src/media-use/lib/recipe-store.mjs +++ b/packages/cli/src/media-use/lib/recipe-store.mjs @@ -283,6 +283,7 @@ export function freezeRecipe({ projectDir, name, workflow, blocks }) { const userDir = join(userRecipesDir(), slug); mkdirSync(userDir, { recursive: true }); cpSync(dir, userDir, NON_ASCII_SAFE_DIR_COPY); + if (!briefSkeleton) rmSync(join(userDir, "brief-skeleton.md"), { force: true }); } catch { // The project-tier freeze already landed. } diff --git a/packages/cli/src/media-use/lib/recipe-store.test.mjs b/packages/cli/src/media-use/lib/recipe-store.test.mjs index 2bf751dca8e..e33fa78fa5f 100644 --- a/packages/cli/src/media-use/lib/recipe-store.test.mjs +++ b/packages/cli/src/media-use/lib/recipe-store.test.mjs @@ -318,6 +318,30 @@ test("re-freezing bumps the version and archives the old folder", () => { }); }); +test("re-freezing without a brief does not import the previous version's brief", () => { + withSandbox(({ project, root }) => { + writeFileSync(join(project, "BRIEF.md"), BRIEF); + freezeRecipe({ projectDir: project, name: "promo" }); + + rmSync(join(project, "BRIEF.md")); + const frozen = freezeRecipe({ + projectDir: project, + name: "promo", + workflow: "product-launch-video", + }); + assert.equal(frozen.version, 2); + assert.equal(frozen.briefSkeleton, false); + assert.ok(existsSync(join(project, ".media/recipes/promo@v1/brief-skeleton.md"))); + + const fresh = join(root, "fresh-project"); + mkdirSync(fresh, { recursive: true }); + const used = useRecipe({ projectDir: fresh, name: "promo" }); + assert.equal(used.recipe.version, 2); + assert.equal(used.briefSkeletonPath, undefined); + assert.ok(!existsSync(join(fresh, ".media/recipes/promo/brief-skeleton.md"))); + }); +}); + test("list merges tiers (project wins), filters by workflow, skips archives", () => { withSandbox(({ project, root }) => { freezeRecipe({ projectDir: project, name: "promo", workflow: "product-launch-video" }); diff --git a/skills-manifest.json b/skills-manifest.json index 75aabb96626..43ab65ba261 100644 --- a/skills-manifest.json +++ b/skills-manifest.json @@ -18,7 +18,7 @@ "files": 13 }, "media-use": { - "hash": "6550641984b19843", + "hash": "a1e407b34da1e96a", "files": 116 }, "remotion-to-hyperframes": { diff --git a/skills/media-use/scripts/lib/recipe-store.mjs b/skills/media-use/scripts/lib/recipe-store.mjs index 44b95ecafe2..9e1ac57487c 100644 --- a/skills/media-use/scripts/lib/recipe-store.mjs +++ b/skills/media-use/scripts/lib/recipe-store.mjs @@ -283,6 +283,7 @@ export function freezeRecipe({ projectDir, name, workflow, blocks }) { const userDir = join(userRecipesDir(), slug); mkdirSync(userDir, { recursive: true }); cpSync(dir, userDir, NON_ASCII_SAFE_DIR_COPY); + if (!briefSkeleton) rmSync(join(userDir, "brief-skeleton.md"), { force: true }); } catch { // The project-tier freeze already landed. }