@koda-sl/baker-cli 0.495.0-dev.c2b64ccca → 0.498.0-dev.e2ca08ce6

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.
Files changed (79) hide show
  1. package/dist/{brief-B7C3SYDP.js → brief-ECEIKJFK.js} +5 -5
  2. package/dist/{canvas-XCP2WPYO.js → canvas-MNZLQZ74.js} +12 -12
  3. package/dist/{check-NDPR32FH.js → check-R7IMU36G.js} +3 -3
  4. package/dist/{chunk-7XH4UQWS.js → chunk-5OAFKP6L.js} +5 -2
  5. package/dist/{chunk-7XH4UQWS.js.map → chunk-5OAFKP6L.js.map} +1 -1
  6. package/dist/{chunk-SQQ4VBNI.js → chunk-5OLCELV7.js} +2 -2
  7. package/dist/{chunk-IGOOLUE2.js → chunk-A7MTWTMM.js} +3 -3
  8. package/dist/{chunk-WZDKROPU.js → chunk-FHYUIYU5.js} +2 -2
  9. package/dist/{chunk-PPMSWLQC.js → chunk-GPWT42O3.js} +2 -2
  10. package/dist/{chunk-G2AZCDX4.js → chunk-HGTLGFKV.js} +3 -3
  11. package/dist/{chunk-QAOEVZYY.js → chunk-HY6DIWDV.js} +4 -4
  12. package/dist/{chunk-7FDDOOM4.js → chunk-IBJA2A4E.js} +2 -2
  13. package/dist/{chunk-OFTU5XBQ.js → chunk-MKL7CL4P.js} +2 -2
  14. package/dist/{chunk-3AOMKBDC.js → chunk-NDIBFOFB.js} +8 -8
  15. package/dist/{chunk-72QBQS63.js → chunk-OTLYELOW.js} +2 -2
  16. package/dist/{chunk-T5HB6R4I.js → chunk-T235G4C7.js} +2 -2
  17. package/dist/{chunk-BVMXTD4B.js → chunk-ZPMGYAYZ.js} +3 -3
  18. package/dist/{chunk-BVMXTD4B.js.map → chunk-ZPMGYAYZ.js.map} +1 -1
  19. package/dist/cli.js +3 -3
  20. package/dist/{creatives-NJ7SZ3S4.js → creatives-NHH4J2XW.js} +9 -9
  21. package/dist/{critique-LINKOKOE.js → critique-7OGWN5Q4.js} +4 -4
  22. package/dist/{feedback-HT2M63QW.js → feedback-XF2TOS4P.js} +2 -2
  23. package/dist/{feedback-record-V7UU6CG3.js → feedback-record-YPNGCJWS.js} +6 -6
  24. package/dist/{fit-S5ZGPNE3.js → fit-INDYA6KP.js} +3 -3
  25. package/dist/{ideas-HHTLPC6Y.js → ideas-ZFODHYVK.js} +3 -3
  26. package/dist/{make-4XCSN76S.js → make-GJPQRROG.js} +10 -10
  27. package/dist/{rerun-NWOGRYHU.js → rerun-77XP2DAH.js} +9 -9
  28. package/dist/{rules-DSLE6LVU.js → rules-HJGFA6OT.js} +4 -4
  29. package/dist/{rules-add-NBOMKFAI.js → rules-add-3YBX7UGL.js} +7 -5
  30. package/dist/rules-add-3YBX7UGL.js.map +1 -0
  31. package/dist/{run-IRJWKZ3K.js → run-WBFKGA42.js} +9 -9
  32. package/dist/{scaffold-ad-3BSA7BWT.js → scaffold-ad-6YO574PA.js} +6 -6
  33. package/dist/{scaffold-static-ad-Q26LLBWQ.js → scaffold-static-ad-WBC2U5U4.js} +11 -11
  34. package/dist/{scaffold-video-WE52C7YZ.js → scaffold-video-2ZJMQMEZ.js} +6 -6
  35. package/dist/{select-4IQQNKLN.js → select-ONK2GLKS.js} +6 -6
  36. package/dist/{set-prompt-DE4TD2V7.js → set-prompt-KQSUL77B.js} +4 -4
  37. package/dist/{stale-E34H24C3.js → stale-G25M2P7Q.js} +5 -5
  38. package/dist/{sync-definition-DTWEW6ZC.js → sync-definition-PGVMZTOX.js} +6 -6
  39. package/dist/{translate-V6XPDX4M.js → translate-SI6LSIY6.js} +8 -8
  40. package/dist/{validate-VTAKQGD5.js → validate-QNBI74BM.js} +4 -4
  41. package/dist/{viewer-check-3T2EZOSH.js → viewer-check-TEQ3WP2N.js} +4 -4
  42. package/dist/{winning-ads-F765TFLS.js → winning-ads-EVOFUO3N.js} +2 -2
  43. package/package.json +1 -1
  44. package/dist/rules-add-NBOMKFAI.js.map +0 -1
  45. /package/dist/{brief-B7C3SYDP.js.map → brief-ECEIKJFK.js.map} +0 -0
  46. /package/dist/{canvas-XCP2WPYO.js.map → canvas-MNZLQZ74.js.map} +0 -0
  47. /package/dist/{check-NDPR32FH.js.map → check-R7IMU36G.js.map} +0 -0
  48. /package/dist/{chunk-SQQ4VBNI.js.map → chunk-5OLCELV7.js.map} +0 -0
  49. /package/dist/{chunk-IGOOLUE2.js.map → chunk-A7MTWTMM.js.map} +0 -0
  50. /package/dist/{chunk-WZDKROPU.js.map → chunk-FHYUIYU5.js.map} +0 -0
  51. /package/dist/{chunk-PPMSWLQC.js.map → chunk-GPWT42O3.js.map} +0 -0
  52. /package/dist/{chunk-G2AZCDX4.js.map → chunk-HGTLGFKV.js.map} +0 -0
  53. /package/dist/{chunk-QAOEVZYY.js.map → chunk-HY6DIWDV.js.map} +0 -0
  54. /package/dist/{chunk-7FDDOOM4.js.map → chunk-IBJA2A4E.js.map} +0 -0
  55. /package/dist/{chunk-OFTU5XBQ.js.map → chunk-MKL7CL4P.js.map} +0 -0
  56. /package/dist/{chunk-3AOMKBDC.js.map → chunk-NDIBFOFB.js.map} +0 -0
  57. /package/dist/{chunk-72QBQS63.js.map → chunk-OTLYELOW.js.map} +0 -0
  58. /package/dist/{chunk-T5HB6R4I.js.map → chunk-T235G4C7.js.map} +0 -0
  59. /package/dist/{creatives-NJ7SZ3S4.js.map → creatives-NHH4J2XW.js.map} +0 -0
  60. /package/dist/{critique-LINKOKOE.js.map → critique-7OGWN5Q4.js.map} +0 -0
  61. /package/dist/{feedback-HT2M63QW.js.map → feedback-XF2TOS4P.js.map} +0 -0
  62. /package/dist/{feedback-record-V7UU6CG3.js.map → feedback-record-YPNGCJWS.js.map} +0 -0
  63. /package/dist/{fit-S5ZGPNE3.js.map → fit-INDYA6KP.js.map} +0 -0
  64. /package/dist/{ideas-HHTLPC6Y.js.map → ideas-ZFODHYVK.js.map} +0 -0
  65. /package/dist/{make-4XCSN76S.js.map → make-GJPQRROG.js.map} +0 -0
  66. /package/dist/{rerun-NWOGRYHU.js.map → rerun-77XP2DAH.js.map} +0 -0
  67. /package/dist/{rules-DSLE6LVU.js.map → rules-HJGFA6OT.js.map} +0 -0
  68. /package/dist/{run-IRJWKZ3K.js.map → run-WBFKGA42.js.map} +0 -0
  69. /package/dist/{scaffold-ad-3BSA7BWT.js.map → scaffold-ad-6YO574PA.js.map} +0 -0
  70. /package/dist/{scaffold-static-ad-Q26LLBWQ.js.map → scaffold-static-ad-WBC2U5U4.js.map} +0 -0
  71. /package/dist/{scaffold-video-WE52C7YZ.js.map → scaffold-video-2ZJMQMEZ.js.map} +0 -0
  72. /package/dist/{select-4IQQNKLN.js.map → select-ONK2GLKS.js.map} +0 -0
  73. /package/dist/{set-prompt-DE4TD2V7.js.map → set-prompt-KQSUL77B.js.map} +0 -0
  74. /package/dist/{stale-E34H24C3.js.map → stale-G25M2P7Q.js.map} +0 -0
  75. /package/dist/{sync-definition-DTWEW6ZC.js.map → sync-definition-PGVMZTOX.js.map} +0 -0
  76. /package/dist/{translate-V6XPDX4M.js.map → translate-SI6LSIY6.js.map} +0 -0
  77. /package/dist/{validate-VTAKQGD5.js.map → validate-QNBI74BM.js.map} +0 -0
  78. /package/dist/{viewer-check-3T2EZOSH.js.map → viewer-check-TEQ3WP2N.js.map} +0 -0
  79. /package/dist/{winning-ads-F765TFLS.js.map → winning-ads-EVOFUO3N.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine/creative-context/ad-words.ts","../src/commands/creatives/cast-inventory.ts","../src/commands/canvas/rule-gate.ts"],"sourcesContent":["/**\n * What one ad says, as the company's wording rules are checked on it: a static's printed words, or\n * a video's script, every spoken line and every word on screen (its subtitles are its spoken\n * words); the language it is in, the product it sells and the rules it waives.\n */\nimport { readdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { frontmatterOf } from \"../../commands/creatives/ideas-model.ts\";\nimport { nativeCopy } from \"../scaffold/native-surface.ts\";\nimport { isAdSpec, readAdSpec } from \"../scaffold/static-ad-spec.ts\";\n\nexport type AdWords = {\n kind: \"static\" | \"video\";\n lines: string[];\n /** The language its words are in (a BCP-47 tag), when the ad or its definition says. */\n language?: string;\n product?: string;\n /** The platform it runs on, as its definition names it: a platform's rules hold for it. */\n platform?: string;\n /** The rules the person asked this ad to depart from (`waive`). */\n waived: string[];\n};\n\nconst json = (file: string): Promise<unknown> =>\n readFile(file, \"utf8\")\n .then((raw): unknown => JSON.parse(raw))\n .catch(() => null);\n\nconst text = (value: unknown): string | undefined =>\n typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n\n/** The rules a spec waives, by id. Pure. */\nfunction waivedOf(spec: unknown): string[] {\n const waive = (spec as { waive?: unknown } | null)?.waive;\n return Array.isArray(waive) ? waive.flatMap((w) => text((w as { rule?: unknown } | null)?.rule) ?? []) : [];\n}\n\n/** A video scene's spoken lines and on-screen words. Pure. */\nfunction sceneWords(scene: unknown): string[] {\n const s = (scene ?? {}) as { dialogue?: unknown; overlays?: unknown };\n const spoken = Array.isArray(s.dialogue)\n ? s.dialogue.flatMap((d) => text((d as { line?: unknown })?.line) ?? [])\n : [];\n const shown = Array.isArray(s.overlays) ? s.overlays.flatMap((o) => text((o as { text?: unknown })?.text) ?? []) : [];\n return [...spoken, ...shown];\n}\n\n/** A video's scene files, in order. */\nasync function sceneFiles(creativeDir: string): Promise<unknown[]> {\n const dir = path.join(creativeDir, \"scenes\");\n const files = (await readdir(dir).catch(() => [] as string[])).filter((f) => f.endsWith(\".json\")).sort();\n return await Promise.all(files.map((f) => json(path.join(dir, f))));\n}\n\n/** The language a video is spoken in: its definition's, else its beats spec's voice. */\nasync function videoLanguage(creativeDir: string): Promise<string | undefined> {\n const definition = frontmatterOf(await readFile(path.join(creativeDir, \"_definition.md\"), \"utf8\").catch(() => \"\"));\n const beats = (await json(path.join(creativeDir, \"ad.spec.json\"))) as { voice?: { language?: unknown } } | null;\n return text(definition?.language) ?? text(beats?.voice?.language);\n}\n\n/** A video's script, spoken lines and on-screen words, and the language it is spoken in. */\nasync function videoWords(raw: Record<string, unknown>, creativeDir: string): Promise<Omit<AdWords, \"waived\">> {\n const global = (raw.global ?? {}) as { transcript?: unknown };\n const transcript = text(global.transcript);\n const scenes = [...(Array.isArray(raw.scenes) ? raw.scenes : []), ...(await sceneFiles(creativeDir))];\n const lines = [...new Set([...(transcript ? [transcript] : []), ...scenes.flatMap(sceneWords)])];\n const language = await videoLanguage(creativeDir);\n return { kind: \"video\", lines, ...(language ? { language } : {}) };\n}\n\n/** A static's printed words and the language its viewer reads; null when it is not an ad spec. Pure. */\nfunction staticWords(raw: unknown): Omit<AdWords, \"waived\"> | null {\n try {\n const spec = readAdSpec(raw);\n const lines = spec.native ? nativeCopy(spec.native) : spec.copy.map((l) => l.text);\n const language = spec.viewer?.market?.language;\n return { kind: \"static\", lines, ...(language ? { language } : {}) };\n } catch {\n return null;\n }\n}\n\n/** One creative folder's words for the wording rules; null when it has no ad written yet. */\nexport async function readAdWords(creativeDir: string): Promise<AdWords | null> {\n const raw = (await json(path.join(creativeDir, \"prompt.json\"))) as Record<string, unknown> | null;\n if (!raw || typeof raw !== \"object\") return null;\n const video = !isAdSpec(raw) && (\"global\" in raw || \"scenes\" in raw);\n const words = video ? await videoWords(raw, creativeDir) : staticWords(raw);\n if (!words) return null;\n const product = text(raw.product);\n const definition = frontmatterOf(await readFile(path.join(creativeDir, \"_definition.md\"), \"utf8\").catch(() => \"\"));\n const platform = text(definition?.platform);\n return { ...words, ...(product ? { product } : {}), ...(platform ? { platform } : {}), waived: waivedOf(raw) };\n}\n","/**\n * What the company has to cast and show in an ad, read before anyone is cast: its Avatars (real\n * people and ones made for a role), customers' own words for this message, and its logos. A media\n * buyer starts from the material in hand; production chats started from the image model.\n */\nimport { readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { AvatarsListResponse, TestimonialsSearchResponse } from \"@baker/api\";\nimport { apiPost } from \"../../client.ts\";\nimport { readAvatars } from \"../avatars/transport.ts\";\n\nexport type CastInventory = {\n /** Ready Avatars: `real` when built from a real person's own pictures or profile. */\n avatars: { handle: string; real: boolean; who: string }[];\n /** Customers' own words for this message, best first. */\n customers: { name?: string; words: string; source: string; photo: boolean }[];\n /** The brand's logo files, workspace-relative. */\n logos: string[];\n /** The company's name, for finding its founder. */\n company?: string;\n};\n\nconst short = (text: string, max: number) => (text.length > max ? `${text.slice(0, max - 1).trimEnd()}…` : text);\n\n/** The ready Avatars, as the inventory lists them. Pure. */\nexport function avatarsOf(response: AvatarsListResponse): CastInventory[\"avatars\"] {\n return response.avatars\n .filter((a) => a.status === \"ready\")\n .map((a) => {\n const real = a.likeness === \"licensed\" || Boolean(a.person);\n const role = [a.person?.role, a.person?.company].filter(Boolean).join(\" at \");\n return { handle: a.handle, real, who: short(role || a.subjectDescription || a.name, 90) };\n });\n}\n\n/** Customers' words for this message, the ones with something to say first, at most three. Pure. */\nexport function customersOf(found: TestimonialsSearchResponse): CastInventory[\"customers\"] {\n return found\n .filter((t) => t.sentiment !== \"negative\" && (t.highlight || t.reviewText).trim())\n .slice(0, 3)\n .map((t) => ({\n ...(t.reviewerName ? { name: t.reviewerName } : {}),\n words: short((t.highlight || t.reviewText).trim().replace(/\\s+/g, \" \"), 140),\n source: t.sourceType,\n photo: Boolean(t.reviewerImageUrl || t.reviewerImageId || t.imageIds?.length || t.videoIds?.length),\n }));\n}\n\nconst LOGO_FILE = /\\.(svg|png|webp|jpe?g)$/i;\n\n/** Everything the company has to build with; each part empty when it cannot be read. */\nexport async function castInventory(root: string, message: string, company?: string): Promise<CastInventory> {\n const [avatars, customers, logos] = await Promise.all([\n readAvatars<AvatarsListResponse>(\"/api/avatars\", { status: \"ready\" }).then(avatarsOf, () => []),\n apiPost<TestimonialsSearchResponse>(\"/api/testimonials/search\", { query: message, limit: 6 }).then(\n customersOf,\n () => [],\n ),\n readdir(path.join(root, \"src\", \"brand\", \"logos\")).then(\n (files) => files.filter((f) => LOGO_FILE.test(f)).map((f) => `src/brand/logos/${f}`),\n () => [],\n ),\n ]);\n return { avatars, customers, logos, ...(company ? { company } : {}) };\n}\n","/**\n * The company's wording rules, held before a render: an ad whose words break a never or a must\n * (a phrase it bans, or one every ad must say) is refused, free, naming the line, the rule and the\n * person's own words. Prod, Oct 2026: '\"100 % online\", no \"online\"' was rejected on five ads of one\n * company in one day, each after it had rendered. A person's explicit ask keeps the words: the ad\n * waives the rule in its prompt.json, visibly.\n */\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { type AdWords, readAdWords } from \"../../engine/creative-context/ad-words.ts\";\nimport type { CreativeRule } from \"../../engine/creative-rules/schema.ts\";\nimport { readCreativeContext, workspaceOfCreative } from \"../../engine/creative-context/index.ts\";\nimport { type RuleTell, ruleTells } from \"../../engine/copy-tells/rule-tells.ts\";\nimport { marketFromCompanyDoc } from \"../../viewer-profile.ts\";\nimport { findWorkspaceRoot } from \"./normalize-paths.ts\";\nimport { readAvatars } from \"../avatars/transport.ts\";\nimport { avatarsOf } from \"../creatives/cast-inventory.ts\";\nimport type { RealPeopleOnly } from \"../creatives/cast-decision.ts\";\nimport type { AvatarsListResponse } from \"@baker/api\";\n\nexport type RuleRefusal = { problems: string[]; fix: string };\n\n/** One broken rule, as the refusal names it. Pure. */\nfunction tellLine(tell: RuleTell): string {\n const where =\n tell.kind === \"forbidden\" ? `\"${tell.line ?? \"\"}\" says \"${tell.phrase}\"` : `No line says \"${tell.phrase}\"`;\n const words = tell.quote ? ` Their words: ${tell.quote}` : \"\";\n return `${where}: ${tell.rule} (${tell.strength}) — ${tell.text}${words}`;\n}\n\n/** The refusal for the rules an ad's words break; null when they break none. Pure. */\nexport function ruleRefusal(tells: readonly RuleTell[]): RuleRefusal | null {\n if (tells.length === 0) return null;\n return {\n problems: tells.map(tellLine),\n fix: 'Rewrite each line named above within its rule (a static: its `copy` in prompt.json; a video: its scene files and ad.spec.json), then re-run. Only when the person explicitly asked for these words in this ad, keep them and add to prompt.json `\"waive\": [{\"rule\": \"<id>\", \"why\": \"<their ask>\"}]`.',\n };\n}\n\n/** The Avatars on the company's roster, each real or made for a role; null when it cannot be read. */\nexport type ReadRoster = () => Promise<ReadonlyArray<{ handle: string; real: boolean }> | null>;\n\nconst liveRoster: ReadRoster = () =>\n readAvatars<AvatarsListResponse>(\"/api/avatars\", { status: \"ready\" }).then(avatarsOf, () => null);\n\n/** The rules that hold the ad in `creativeDir` and the language its words are in (else the company market's). */\nexport async function heldRules(\n creativeDir: string,\n ad?: AdWords | null,\n): Promise<{ rules: CreativeRule[]; language?: string }> {\n const words = ad === undefined ? await readAdWords(creativeDir) : ad;\n const root = findWorkspaceRoot(creativeDir) ?? workspaceOfCreative(creativeDir);\n const context = await readCreativeContext(\n root,\n {\n ...(words ? { kind: words.kind } : {}),\n ...(words?.product ? { product: words.product } : {}),\n ...(words?.platform ? { platform: words.platform } : {}),\n },\n { waived: words?.waived ?? [] },\n );\n const language =\n words?.language ??\n marketFromCompanyDoc(await readFile(path.join(root, \"COMPANY.md\"), \"utf8\").catch(() => null))?.language;\n return { rules: context.rules, ...(language ? { language } : {}) };\n}\n\n/**\n * The company's rules as they hold the ad in `creativeDir`, read from the workspace as it stands:\n * the wording rules its words break (`broken`), and the rule that only real people appear, with the\n * roster to hold its cast to (`realOnly`, read only when such a rule holds).\n */\nexport async function ruleGate(\n creativeDir: string,\n roster: ReadRoster = liveRoster,\n): Promise<{ broken: RuleRefusal | null; realOnly: RealPeopleOnly | null }> {\n const ad = await readAdWords(creativeDir);\n if (!ad) return { broken: null, realOnly: null };\n const { rules, language } = await heldRules(creativeDir, ad);\n const people = rules.find((r) => r.check?.people === \"real\" && r.strength !== \"prefer\");\n return {\n broken: ruleRefusal(ruleTells(ad.lines, rules, language)),\n realOnly: people\n ? {\n rule: { id: people.id, text: people.text, ...(people.source.quote ? { quote: people.source.quote } : {}) },\n avatars: await roster().catch(() => null),\n }\n : null,\n };\n}\n"],"mappings":"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","names":["readdir","path","text","readdir","path","readFile","path","readFile","path"]}
1
+ {"version":3,"sources":["../src/engine/creative-context/ad-words.ts","../src/commands/creatives/cast-inventory.ts","../src/commands/canvas/rule-gate.ts"],"sourcesContent":["/**\n * What one ad says, as the company's wording rules are checked on it: a static's printed words, or\n * a video's script, every spoken line and every word on screen (its subtitles are its spoken\n * words); the language it is in, the product it sells and the rules it waives.\n */\nimport { readdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { frontmatterOf } from \"../../commands/creatives/ideas-model.ts\";\nimport { nativeCopy } from \"../scaffold/native-surface.ts\";\nimport { isAdSpec, readAdSpec } from \"../scaffold/static-ad-spec.ts\";\n\nexport type AdWords = {\n kind: \"static\" | \"video\";\n lines: string[];\n /** The language its words are in (a BCP-47 tag), when the ad or its definition says. */\n language?: string;\n product?: string;\n /** The platform it runs on, as its definition names it: a platform's rules hold for it. */\n platform?: string;\n /** The rules the person asked this ad to depart from (`waive`). */\n waived: string[];\n};\n\nconst json = (file: string): Promise<unknown> =>\n readFile(file, \"utf8\")\n .then((raw): unknown => JSON.parse(raw))\n .catch(() => null);\n\nconst text = (value: unknown): string | undefined =>\n typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n\n/** The rules a spec waives, by id. Pure. */\nfunction waivedOf(spec: unknown): string[] {\n const waive = (spec as { waive?: unknown } | null)?.waive;\n return Array.isArray(waive) ? waive.flatMap((w) => text((w as { rule?: unknown } | null)?.rule) ?? []) : [];\n}\n\n/** A video scene's spoken lines and on-screen words. Pure. */\nfunction sceneWords(scene: unknown): string[] {\n const s = (scene ?? {}) as { dialogue?: unknown; overlays?: unknown };\n const spoken = Array.isArray(s.dialogue)\n ? s.dialogue.flatMap((d) => text((d as { line?: unknown })?.line) ?? [])\n : [];\n const shown = Array.isArray(s.overlays) ? s.overlays.flatMap((o) => text((o as { text?: unknown })?.text) ?? []) : [];\n return [...spoken, ...shown];\n}\n\n/** A video's scene files, in order. */\nasync function sceneFiles(creativeDir: string): Promise<unknown[]> {\n const dir = path.join(creativeDir, \"scenes\");\n const files = (await readdir(dir).catch(() => [] as string[])).filter((f) => f.endsWith(\".json\")).sort();\n return await Promise.all(files.map((f) => json(path.join(dir, f))));\n}\n\n/** The language a video is spoken in: its definition's, else its beats spec's voice. */\nasync function videoLanguage(creativeDir: string): Promise<string | undefined> {\n const definition = frontmatterOf(await readFile(path.join(creativeDir, \"_definition.md\"), \"utf8\").catch(() => \"\"));\n const beats = (await json(path.join(creativeDir, \"ad.spec.json\"))) as { voice?: { language?: unknown } } | null;\n return text(definition?.language) ?? text(beats?.voice?.language);\n}\n\n/** A video's script, spoken lines and on-screen words, and the language it is spoken in. */\nasync function videoWords(raw: Record<string, unknown>, creativeDir: string): Promise<Omit<AdWords, \"waived\">> {\n const global = (raw.global ?? {}) as { transcript?: unknown };\n const transcript = text(global.transcript);\n const scenes = [...(Array.isArray(raw.scenes) ? raw.scenes : []), ...(await sceneFiles(creativeDir))];\n const lines = [...new Set([...(transcript ? [transcript] : []), ...scenes.flatMap(sceneWords)])];\n const language = await videoLanguage(creativeDir);\n return { kind: \"video\", lines, ...(language ? { language } : {}) };\n}\n\n/** A static's printed words and the language its viewer reads; null when it is not an ad spec. Pure. */\nfunction staticWords(raw: unknown): Omit<AdWords, \"waived\"> | null {\n try {\n const spec = readAdSpec(raw);\n const lines = spec.native ? nativeCopy(spec.native) : spec.copy.map((l) => l.text);\n const language = spec.viewer?.market?.language;\n return { kind: \"static\", lines, ...(language ? { language } : {}) };\n } catch {\n return null;\n }\n}\n\n/** One creative folder's words for the wording rules; null when it has no ad written yet. */\nexport async function readAdWords(creativeDir: string): Promise<AdWords | null> {\n const raw = (await json(path.join(creativeDir, \"prompt.json\"))) as Record<string, unknown> | null;\n if (!raw || typeof raw !== \"object\") return null;\n const video = !isAdSpec(raw) && (\"global\" in raw || \"scenes\" in raw);\n const words = video ? await videoWords(raw, creativeDir) : staticWords(raw);\n if (!words) return null;\n const product = text(raw.product);\n const definition = frontmatterOf(await readFile(path.join(creativeDir, \"_definition.md\"), \"utf8\").catch(() => \"\"));\n const platform = text(definition?.platform);\n return { ...words, ...(product ? { product } : {}), ...(platform ? { platform } : {}), waived: waivedOf(raw) };\n}\n","/**\n * What the company has to cast and show in an ad, read before anyone is cast: its Avatars (real\n * people and ones made for a role), customers' own words for this message, and its logos. A media\n * buyer starts from the material in hand; production chats started from the image model.\n */\nimport { readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { AvatarsListResponse, TestimonialsSearchResponse } from \"@baker/api\";\nimport { apiPost } from \"../../client.ts\";\nimport { readAvatars } from \"../avatars/transport.ts\";\n\nexport type CastInventory = {\n /** Ready Avatars: `real` when built from a real person's own pictures or profile. */\n avatars: { handle: string; real: boolean; who: string }[];\n /** Customers' own words for this message, best first. */\n customers: { name?: string; words: string; source: string; photo: boolean }[];\n /** The brand's logo files, workspace-relative. */\n logos: string[];\n /** The company's name, for finding its founder. */\n company?: string;\n};\n\nconst short = (text: string, max: number) => (text.length > max ? `${text.slice(0, max - 1).trimEnd()}…` : text);\n\n/** The ready Avatars, as the inventory lists them. Pure. */\nexport function avatarsOf(response: AvatarsListResponse): CastInventory[\"avatars\"] {\n return response.avatars\n .filter((a) => a.status === \"ready\")\n .map((a) => {\n const real = a.likeness === \"licensed\" || Boolean(a.person);\n const role = [a.person?.role, a.person?.company].filter(Boolean).join(\" at \");\n return { handle: a.handle, real, who: short(role || a.subjectDescription || a.name, 90) };\n });\n}\n\n/** Customers' words for this message, the ones with something to say first, at most three. Pure. */\nexport function customersOf(found: TestimonialsSearchResponse): CastInventory[\"customers\"] {\n return found\n .filter((t) => t.sentiment !== \"negative\" && (t.highlight || t.reviewText).trim())\n .slice(0, 3)\n .map((t) => ({\n ...(t.reviewerName ? { name: t.reviewerName } : {}),\n words: short((t.highlight || t.reviewText).trim().replace(/\\s+/g, \" \"), 140),\n source: t.sourceType,\n photo: Boolean(t.reviewerImageUrl || t.reviewerImageId || t.imageIds?.length || t.videoIds?.length),\n }));\n}\n\nconst LOGO_FILE = /\\.(svg|png|webp|jpe?g)$/i;\n\n/** Everything the company has to build with; each part empty when it cannot be read. */\nexport async function castInventory(root: string, message: string, company?: string): Promise<CastInventory> {\n const [avatars, customers, logos] = await Promise.all([\n readAvatars<AvatarsListResponse>(\"/api/avatars\", { status: \"ready\" }).then(avatarsOf, () => []),\n apiPost<TestimonialsSearchResponse>(\"/api/testimonials/search\", { query: message, limit: 6 }).then(\n customersOf,\n () => [],\n ),\n readdir(path.join(root, \"src\", \"brand\", \"logos\")).then(\n (files) => files.filter((f) => LOGO_FILE.test(f)).map((f) => `src/brand/logos/${f}`),\n () => [],\n ),\n ]);\n return { avatars, customers, logos, ...(company ? { company } : {}) };\n}\n","/**\n * The company's wording rules, held before a render: an ad whose words break a never or a must\n * (a phrase it bans, or one every ad must say) is refused, free, naming the line, the rule and the\n * person's own words. Prod, Oct 2026: '\"100 % online\", no \"online\"' was rejected on five ads of one\n * company in one day, each after it had rendered. A person's explicit ask keeps the words: the ad\n * waives the rule in its prompt.json, visibly.\n */\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { type AdWords, readAdWords } from \"../../engine/creative-context/ad-words.ts\";\nimport type { CreativeRule } from \"../../engine/creative-rules/schema.ts\";\nimport { readCreativeContext, workspaceOfCreative } from \"../../engine/creative-context/index.ts\";\nimport { type RuleTell, ruleTells } from \"../../engine/copy-tells/rule-tells.ts\";\nimport { marketFromCompanyDoc } from \"../../viewer-profile.ts\";\nimport { findWorkspaceRoot } from \"./normalize-paths.ts\";\nimport { readAvatars } from \"../avatars/transport.ts\";\nimport { avatarsOf } from \"../creatives/cast-inventory.ts\";\nimport type { RealPeopleOnly } from \"../creatives/cast-decision.ts\";\nimport type { AvatarsListResponse } from \"@baker/api\";\n\nexport type RuleRefusal = { problems: string[]; fix: string };\n\n/** One broken rule, as the refusal names it. Pure. */\nfunction tellLine(tell: RuleTell): string {\n const where =\n tell.kind === \"forbidden\" ? `\"${tell.line ?? \"\"}\" says \"${tell.phrase}\"` : `No line says \"${tell.phrase}\"`;\n const words = tell.quote ? ` Their words: ${tell.quote}` : \"\";\n return `${where}: ${tell.rule} (${tell.strength}) — ${tell.text}${words}`;\n}\n\n/** The refusal for the rules an ad's words break; null when they break none. Pure. */\nexport function ruleRefusal(tells: readonly RuleTell[]): RuleRefusal | null {\n if (tells.length === 0) return null;\n return {\n problems: [...new Set(tells.map(tellLine))],\n fix: 'Rewrite each line named above within its rule (a static: its `copy` in prompt.json; a video: its scene files and ad.spec.json), then re-run. Only when the person explicitly asked for these words in this ad, keep them and add to prompt.json `\"waive\": [{\"rule\": \"<id>\", \"why\": \"<their ask>\"}]`.',\n };\n}\n\n/** The Avatars on the company's roster, each real or made for a role; null when it cannot be read. */\nexport type ReadRoster = () => Promise<ReadonlyArray<{ handle: string; real: boolean }> | null>;\n\nconst liveRoster: ReadRoster = () =>\n readAvatars<AvatarsListResponse>(\"/api/avatars\", { status: \"ready\" }).then(avatarsOf, () => null);\n\n/** The rules that hold the ad in `creativeDir` and the language its words are in (else the company market's). */\nexport async function heldRules(\n creativeDir: string,\n ad?: AdWords | null,\n): Promise<{ rules: CreativeRule[]; language?: string }> {\n const words = ad === undefined ? await readAdWords(creativeDir) : ad;\n const root = findWorkspaceRoot(creativeDir) ?? workspaceOfCreative(creativeDir);\n const context = await readCreativeContext(\n root,\n {\n ...(words ? { kind: words.kind } : {}),\n ...(words?.product ? { product: words.product } : {}),\n ...(words?.platform ? { platform: words.platform } : {}),\n },\n { waived: words?.waived ?? [] },\n );\n const language =\n words?.language ??\n marketFromCompanyDoc(await readFile(path.join(root, \"COMPANY.md\"), \"utf8\").catch(() => null))?.language;\n return { rules: context.rules, ...(language ? { language } : {}) };\n}\n\n/**\n * The company's rules as they hold the ad in `creativeDir`, read from the workspace as it stands:\n * the wording rules its words break (`broken`), and the rule that only real people appear, with the\n * roster to hold its cast to (`realOnly`, read only when such a rule holds).\n */\nexport async function ruleGate(\n creativeDir: string,\n roster: ReadRoster = liveRoster,\n): Promise<{ broken: RuleRefusal | null; realOnly: RealPeopleOnly | null }> {\n const ad = await readAdWords(creativeDir);\n if (!ad) return { broken: null, realOnly: null };\n const { rules, language } = await heldRules(creativeDir, ad);\n const people = rules.find((r) => r.check?.people === \"real\" && r.strength !== \"prefer\");\n return {\n broken: ruleRefusal(ruleTells(ad.lines, rules, language)),\n realOnly: people\n ? {\n rule: { id: people.id, text: people.text, ...(people.source.quote ? { quote: people.source.quote } : {}) },\n avatars: await roster().catch(() => null),\n }\n : null,\n };\n}\n"],"mappings":"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","names":["readdir","path","text","readdir","path","readFile","path","readFile","path"]}
package/dist/cli.js CHANGED
@@ -118,7 +118,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
118
118
  gsc: () => import("./gsc-WHMPFTYA.js").then((m) => m.gscCommand),
119
119
  research: () => import("./research-XRVD2GSG.js").then((m) => m.researchCommand),
120
120
  decide: () => import("./decide-ZODJU7DY.js").then((m) => m.decideCommand),
121
- creatives: () => import("./creatives-NJ7SZ3S4.js").then((m) => m.creativesCommand),
121
+ creatives: () => import("./creatives-NHH4J2XW.js").then((m) => m.creativesCommand),
122
122
  flows: () => import("./flows-5SXT5F22.js").then((m) => m.flowsCommand),
123
123
  funnel: () => import("./funnel-QDYX3UH5.js").then((m) => m.funnelCommand),
124
124
  images: () => import("./images-PV6TZQLL.js").then((m) => m.imagesCommand),
@@ -127,7 +127,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
127
127
  landing: () => import("./landing-4V7HMYCZ.js").then((m) => m.landingCommand),
128
128
  videos: () => import("./videos-M6VK66NI.js").then((m) => m.videosCommand),
129
129
  testimonials: () => import("./testimonials-PA2FUV4H.js").then((m) => m.testimonialsCommand),
130
- canvas: () => import("./canvas-XCP2WPYO.js").then((m) => m.canvasCommand),
130
+ canvas: () => import("./canvas-MNZLQZ74.js").then((m) => m.canvasCommand),
131
131
  tags: () => import("./tags-DOJUSHJB.js").then((m) => m.tagsCommand),
132
132
  "tag-manager": () => import("./tag-manager-ARFZU46G.js").then((m) => m.tagManagerCommand),
133
133
  chats: () => import("./chats-JKCUA26S.js").then((m) => m.chatsCommand),
@@ -136,7 +136,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
136
136
  hubspot: () => import("./hubspot-B4IUIOYX.js").then((m) => m.hubspotCommand),
137
137
  activecampaign: () => import("./activecampaign-77V5X3FQ.js").then((m) => m.activecampaignCommand),
138
138
  accounts: () => import("./accounts-GBRGCLE3.js").then((m) => m.accountsCommand),
139
- "winning-ads": () => import("./winning-ads-F765TFLS.js").then((m) => m.winningAdsCommand),
139
+ "winning-ads": () => import("./winning-ads-EVOFUO3N.js").then((m) => m.winningAdsCommand),
140
140
  "media-sources": () => import("./media-sources-ZLBIC4RM.js").then((m) => m.mediaSourcesCommand),
141
141
  site: () => import("./site-VTJU5CRE.js").then((m) => m.siteCommand),
142
142
  mcp: () => import("./mcp-RQJAEJCJ.js").then((m) => m.mcpCommand),
@@ -39,15 +39,15 @@ How published creatives are doing in live Meta ads (results, fatigue, angle; hoo
39
39
  Full guide: __tooling__/docs/tools/baker/creatives.md`
40
40
  },
41
41
  subCommands: {
42
- brief: () => import("./brief-B7C3SYDP.js").then((m) => m.briefCommand),
43
- ideas: () => import("./ideas-HHTLPC6Y.js").then((m) => m.ideasCommand),
44
- make: () => import("./make-4XCSN76S.js").then((m) => m.makeCommand),
45
- translate: () => import("./translate-V6XPDX4M.js").then((m) => m.translateCommand),
42
+ brief: () => import("./brief-ECEIKJFK.js").then((m) => m.briefCommand),
43
+ ideas: () => import("./ideas-ZFODHYVK.js").then((m) => m.ideasCommand),
44
+ make: () => import("./make-GJPQRROG.js").then((m) => m.makeCommand),
45
+ translate: () => import("./translate-SI6LSIY6.js").then((m) => m.translateCommand),
46
46
  learn: () => import("./learn-RL66WKHT.js").then((m) => m.learnCommand),
47
- feedback: () => import("./feedback-HT2M63QW.js").then((m) => m.feedbackCommand),
48
- rules: () => import("./rules-DSLE6LVU.js").then((m) => m.rulesCommand),
49
- check: () => import("./check-NDPR32FH.js").then((m) => m.checkCommand),
50
- select: () => import("./select-4IQQNKLN.js").then((m) => m.selectCommand),
47
+ feedback: () => import("./feedback-XF2TOS4P.js").then((m) => m.feedbackCommand),
48
+ rules: () => import("./rules-HJGFA6OT.js").then((m) => m.rulesCommand),
49
+ check: () => import("./check-R7IMU36G.js").then((m) => m.checkCommand),
50
+ select: () => import("./select-ONK2GLKS.js").then((m) => m.selectCommand),
51
51
  publish: () => import("./publish-U73OR33K.js").then((m) => m.publishCommand),
52
52
  performance: () => import("./performance-BQSWGNFO.js").then((m) => m.performanceCommand)
53
53
  }
@@ -55,4 +55,4 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
55
55
  export {
56
56
  creativesCommand
57
57
  };
58
- //# sourceMappingURL=creatives-NJ7SZ3S4.js.map
58
+ //# sourceMappingURL=creatives-NHH4J2XW.js.map
@@ -2,11 +2,11 @@ import {
2
2
  FRAME_PLACEHOLDER_NOTE,
3
3
  exitOnPrepareError,
4
4
  prepareCanvas
5
- } from "./chunk-WZDKROPU.js";
5
+ } from "./chunk-FHYUIYU5.js";
6
6
  import "./chunk-B2SAOVMU.js";
7
- import "./chunk-BVMXTD4B.js";
7
+ import "./chunk-ZPMGYAYZ.js";
8
8
  import "./chunk-AN7CMLYY.js";
9
- import "./chunk-7XH4UQWS.js";
9
+ import "./chunk-5OAFKP6L.js";
10
10
  import "./chunk-S4ROJTDY.js";
11
11
  import "./chunk-YJAQWTS6.js";
12
12
  import "./chunk-MNPBPU3G.js";
@@ -217,4 +217,4 @@ var critiqueCommand = defineCommand({
217
217
  export {
218
218
  critiqueCommand
219
219
  };
220
- //# sourceMappingURL=critique-LINKOKOE.js.map
220
+ //# sourceMappingURL=critique-7OGWN5Q4.js.map
@@ -51,7 +51,7 @@ var feedbackCommand = defineCommand({
51
51
  meta: { name: "feedback", description: DESCRIPTION },
52
52
  subCommands: {
53
53
  read: feedbackReadCommand,
54
- record: () => import("./feedback-record-V7UU6CG3.js").then((m) => m.feedbackRecordCommand)
54
+ record: () => import("./feedback-record-YPNGCJWS.js").then((m) => m.feedbackRecordCommand)
55
55
  },
56
56
  // `args` stays although the parent has no `run`: citty finds the subcommand
57
57
  // name with THIS command's arg defs, so without them `--slug spring-offer`
@@ -63,4 +63,4 @@ var feedbackCommand = defineCommand({
63
63
  export {
64
64
  feedbackCommand
65
65
  };
66
- //# sourceMappingURL=feedback-HT2M63QW.js.map
66
+ //# sourceMappingURL=feedback-XF2TOS4P.js.map
@@ -7,13 +7,13 @@ import {
7
7
  } from "./chunk-ELYP6BOS.js";
8
8
  import {
9
9
  versionOf
10
- } from "./chunk-7FDDOOM4.js";
11
- import "./chunk-72QBQS63.js";
12
- import "./chunk-WZDKROPU.js";
10
+ } from "./chunk-IBJA2A4E.js";
11
+ import "./chunk-OTLYELOW.js";
12
+ import "./chunk-FHYUIYU5.js";
13
13
  import "./chunk-B2SAOVMU.js";
14
- import "./chunk-BVMXTD4B.js";
14
+ import "./chunk-ZPMGYAYZ.js";
15
15
  import "./chunk-AN7CMLYY.js";
16
- import "./chunk-7XH4UQWS.js";
16
+ import "./chunk-5OAFKP6L.js";
17
17
  import {
18
18
  frontmatterOf
19
19
  } from "./chunk-S4ROJTDY.js";
@@ -243,4 +243,4 @@ var feedbackRecordCommand = defineCommand({
243
243
  export {
244
244
  feedbackRecordCommand
245
245
  };
246
- //# sourceMappingURL=feedback-record-V7UU6CG3.js.map
246
+ //# sourceMappingURL=feedback-record-YPNGCJWS.js.map
@@ -12,8 +12,8 @@ import {
12
12
  readCachedFit,
13
13
  readKnowledge,
14
14
  reviewsForFit
15
- } from "./chunk-T5HB6R4I.js";
16
- import "./chunk-7XH4UQWS.js";
15
+ } from "./chunk-T235G4C7.js";
16
+ import "./chunk-5OAFKP6L.js";
17
17
  import "./chunk-S4ROJTDY.js";
18
18
  import "./chunk-WJNLQEOZ.js";
19
19
  import "./chunk-6FHP2HIK.js";
@@ -53,4 +53,4 @@ export {
53
53
  readKnowledge,
54
54
  reviewsForFit
55
55
  };
56
- //# sourceMappingURL=fit-S5ZGPNE3.js.map
56
+ //# sourceMappingURL=fit-INDYA6KP.js.map
@@ -4,9 +4,9 @@ import {
4
4
  ideasCommand,
5
5
  ideasHints,
6
6
  ideasReport
7
- } from "./chunk-PPMSWLQC.js";
7
+ } from "./chunk-GPWT42O3.js";
8
8
  import "./chunk-B2SAOVMU.js";
9
- import "./chunk-7XH4UQWS.js";
9
+ import "./chunk-5OAFKP6L.js";
10
10
  import "./chunk-S4ROJTDY.js";
11
11
  import "./chunk-WJNLQEOZ.js";
12
12
  import "./chunk-MMU6XHCH.js";
@@ -36,4 +36,4 @@ export {
36
36
  ideasHints,
37
37
  ideasReport
38
38
  };
39
- //# sourceMappingURL=ideas-HHTLPC6Y.js.map
39
+ //# sourceMappingURL=ideas-ZFODHYVK.js.map
@@ -10,24 +10,24 @@ import {
10
10
  notADesignReference,
11
11
  pictureOf,
12
12
  resolveSourcePlatform
13
- } from "./chunk-T5HB6R4I.js";
13
+ } from "./chunk-T235G4C7.js";
14
14
  import {
15
15
  makeSeriesAd,
16
16
  seriesMadeEnvelope
17
- } from "./chunk-OFTU5XBQ.js";
17
+ } from "./chunk-MKL7CL4P.js";
18
18
  import "./chunk-WDAWTHQK.js";
19
19
  import {
20
20
  runBaker
21
- } from "./chunk-QAOEVZYY.js";
21
+ } from "./chunk-HY6DIWDV.js";
22
22
  import {
23
23
  parseDefinitionSourceFields
24
- } from "./chunk-SQQ4VBNI.js";
25
- import "./chunk-72QBQS63.js";
24
+ } from "./chunk-5OLCELV7.js";
25
+ import "./chunk-OTLYELOW.js";
26
26
  import {
27
27
  projectStaticBriefs,
28
28
  thinkingOutline,
29
29
  withThinking
30
- } from "./chunk-WZDKROPU.js";
30
+ } from "./chunk-FHYUIYU5.js";
31
31
  import "./chunk-L44WSWSZ.js";
32
32
  import {
33
33
  audienceQuery,
@@ -61,16 +61,16 @@ import {
61
61
  import {
62
62
  liveViewerLookups,
63
63
  readPersonas
64
- } from "./chunk-IGOOLUE2.js";
64
+ } from "./chunk-A7MTWTMM.js";
65
65
  import {
66
66
  castInventory
67
- } from "./chunk-BVMXTD4B.js";
67
+ } from "./chunk-ZPMGYAYZ.js";
68
68
  import "./chunk-AN7CMLYY.js";
69
69
  import {
70
70
  avoidOf,
71
71
  readCompanyReading,
72
72
  readCreativeContext
73
- } from "./chunk-7XH4UQWS.js";
73
+ } from "./chunk-5OAFKP6L.js";
74
74
  import {
75
75
  checkIdeas,
76
76
  sourcesClaims
@@ -1134,4 +1134,4 @@ export {
1134
1134
  seedConcept,
1135
1135
  unbuiltReference
1136
1136
  };
1137
- //# sourceMappingURL=make-4XCSN76S.js.map
1137
+ //# sourceMappingURL=make-GJPQRROG.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  executeCanvasRun
3
- } from "./chunk-3AOMKBDC.js";
3
+ } from "./chunk-NDIBFOFB.js";
4
4
  import "./chunk-IVRXPYQ7.js";
5
5
  import "./chunk-3PL2QRF2.js";
6
6
  import "./chunk-WN4KX7GE.js";
@@ -10,16 +10,16 @@ import "./chunk-IOGKJZ4Z.js";
10
10
  import "./chunk-Q6ULQMWG.js";
11
11
  import "./chunk-KKJ4KJCW.js";
12
12
  import "./chunk-3ACMDRSE.js";
13
- import "./chunk-QAOEVZYY.js";
14
- import "./chunk-SQQ4VBNI.js";
15
- import "./chunk-72QBQS63.js";
16
- import "./chunk-WZDKROPU.js";
13
+ import "./chunk-HY6DIWDV.js";
14
+ import "./chunk-5OLCELV7.js";
15
+ import "./chunk-OTLYELOW.js";
16
+ import "./chunk-FHYUIYU5.js";
17
17
  import "./chunk-L44WSWSZ.js";
18
18
  import "./chunk-B2SAOVMU.js";
19
- import "./chunk-IGOOLUE2.js";
20
- import "./chunk-BVMXTD4B.js";
19
+ import "./chunk-A7MTWTMM.js";
20
+ import "./chunk-ZPMGYAYZ.js";
21
21
  import "./chunk-AN7CMLYY.js";
22
- import "./chunk-7XH4UQWS.js";
22
+ import "./chunk-5OAFKP6L.js";
23
23
  import "./chunk-S4ROJTDY.js";
24
24
  import "./chunk-YJAQWTS6.js";
25
25
  import "./chunk-MNPBPU3G.js";
@@ -86,4 +86,4 @@ var rerunCommand = defineCommand({
86
86
  export {
87
87
  rerunCommand
88
88
  };
89
- //# sourceMappingURL=rerun-NWOGRYHU.js.map
89
+ //# sourceMappingURL=rerun-77XP2DAH.js.map
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-QVQKCVP7.js";
7
7
  import {
8
8
  readAllRules
9
- } from "./chunk-7XH4UQWS.js";
9
+ } from "./chunk-5OAFKP6L.js";
10
10
  import "./chunk-S4ROJTDY.js";
11
11
  import "./chunk-WJNLQEOZ.js";
12
12
  import "./chunk-6FHP2HIK.js";
@@ -84,12 +84,12 @@ var rulesCommand = defineCommand({
84
84
  },
85
85
  subCommands: {
86
86
  list: listCommand,
87
- add: () => import("./rules-add-NBOMKFAI.js").then((m) => m.rulesAddCommand),
88
- retire: () => import("./rules-add-NBOMKFAI.js").then((m) => m.rulesRetireCommand)
87
+ add: () => import("./rules-add-3YBX7UGL.js").then((m) => m.rulesAddCommand),
88
+ retire: () => import("./rules-add-3YBX7UGL.js").then((m) => m.rulesRetireCommand)
89
89
  },
90
90
  default: "list"
91
91
  });
92
92
  export {
93
93
  rulesCommand
94
94
  };
95
- //# sourceMappingURL=rules-DSLE6LVU.js.map
95
+ //# sourceMappingURL=rules-HJGFA6OT.js.map
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-L44WSWSZ.js";
10
10
  import {
11
11
  readAllRules
12
- } from "./chunk-7XH4UQWS.js";
12
+ } from "./chunk-5OAFKP6L.js";
13
13
  import {
14
14
  RULES_DIR,
15
15
  RULE_APPLIES,
@@ -325,6 +325,9 @@ var ADD_ARGS = {
325
325
  }
326
326
  };
327
327
  registerSchema({ command: "creatives.rules.add", description: ADD_DESCRIPTION, args: ADD_ARGS });
328
+ function brandMdHint(declared, relation) {
329
+ return relation === "same" ? `BRAND.md states this too ("${declared.text}"): now the person confirmed it, every finished ad is checked against it.` : `BRAND.md says otherwise ("${declared.text}"): tell the person, and change only that line of BRAND.md (/brand-build) so it no longer says otherwise; never write the rule itself into BRAND.md, or retiring it would leave it in force.`;
330
+ }
328
331
  var rulesAddCommand = defineCommand({
329
332
  meta: { name: "add", description: ADD_DESCRIPTION },
330
333
  args: ADD_ARGS,
@@ -405,9 +408,7 @@ var rulesAddCommand = defineCommand({
405
408
  ...compared.judged ? [] : [
406
409
  "Whether it repeats or contradicts another rule could not be read (the decision model did not answer): look at `baker creatives rules list`."
407
410
  ],
408
- ...declared.map(
409
- (r) => compared.same.includes(r) ? `BRAND.md states this too ("${r.text}"): now the person confirmed it, every finished ad is checked against it.` : `BRAND.md says otherwise ("${r.text}"): tell the person, and update BRAND.md so the two agree (/brand-build).`
410
- )
411
+ ...declared.map((r) => brandMdHint(r, compared.same.includes(r) ? "same" : "conflict"))
411
412
  ]
412
413
  });
413
414
  }
@@ -439,8 +440,9 @@ var rulesRetireCommand = defineCommand({
439
440
  }
440
441
  });
441
442
  export {
443
+ brandMdHint,
442
444
  ruleFromInputs,
443
445
  rulesAddCommand,
444
446
  rulesRetireCommand
445
447
  };
446
- //# sourceMappingURL=rules-add-NBOMKFAI.js.map
448
+ //# sourceMappingURL=rules-add-3YBX7UGL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/creatives/rules-add.ts","../src/engine/creative-rules/admission.ts","../src/engine/creative-rules/compare.ts","../src/engine/creative-rules/write.ts"],"sourcesContent":["/**\n * `baker creatives rules add` and `retire`: a rule a person agreed to, saved for every ad from now\n * on as one file in src/content/creative-rules/ (staged in the Session and published with it), and\n * a rule retired, never deleted. A rule is saved only when it is not one the company already has,\n * contradicts none without the person picking the winner, catches the version it came from and\n * blocks none the person approved.\n */\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { CreativesFeedbackResponse } from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport sharp from \"sharp\";\nimport { apiPost } from \"../../client.ts\";\nimport { readAllRules } from \"../../engine/creative-context/index.ts\";\nimport {\n type Admission,\n admissionRefusal,\n admissionTest,\n type ReviewedVersion,\n} from \"../../engine/creative-rules/admission.ts\";\nimport { compareRule, jevPairs } from \"../../engine/creative-rules/compare.ts\";\nimport { parseRuleFile, RULES_DIR } from \"../../engine/creative-rules/read.ts\";\nimport {\n type CreativeRule,\n RULE_APPLIES,\n RULE_KINDS,\n RULE_STRENGTHS,\n type RuleCheck,\n type RuleScope,\n} from \"../../engine/creative-rules/schema.ts\";\nimport { ruleFileText, ruleSlug } from \"../../engine/creative-rules/write.ts\";\nimport { reviewAgainstRules } from \"../../engine/nodes/local/lib/rules-review.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { findWorkspaceRoot } from \"../canvas/normalize-paths.ts\";\nimport { fetchRunRecord } from \"../canvas/run-history.ts\";\nimport { holdWorkspaceSpend } from \"../canvas/unbilled-spend.ts\";\nimport { loadCandidate, type SavedCandidate } from \"./rule-candidate.ts\";\nimport { rulesView } from \"./rules-view.ts\";\n\n/** What the flags say of the rule; each overrides the candidate's. */\nexport type RuleFlags = {\n text?: string;\n strength?: string;\n applies?: string;\n forbid?: string[];\n require?: string[];\n allow?: string[];\n people?: string;\n kinds?: string[];\n products?: string[];\n platforms?: string[];\n language?: string;\n quote?: string;\n slug?: string;\n run?: string;\n why?: string;\n id?: string;\n};\n\nconst oneOf = <T extends string>(values: readonly T[], value: string | undefined): T | undefined =>\n value && (values as readonly string[]).includes(value) ? (value as T) : undefined;\n\nconst defined = <T extends object>(value: T): T =>\n Object.fromEntries(\n Object.entries(value).filter(([, v]) => v !== undefined && !(Array.isArray(v) && v.length === 0)),\n ) as T;\n\n/** Where the rule holds: the flags over the candidate's. Pure. */\nfunction scopeOf(f: RuleFlags, c: SavedCandidate | undefined): RuleScope {\n return defined<RuleScope>({\n kinds: (f.kinds ?? c?.kinds)?.flatMap((k) => oneOf(RULE_KINDS, k) ?? []),\n products: f.products,\n platforms: f.platforms ?? c?.platforms,\n language: f.language ?? c?.language,\n });\n}\n\n/** What code decides of the rule: the flags over the candidate's. Pure. */\nfunction checkOf(f: RuleFlags, c: SavedCandidate | undefined): RuleCheck {\n const realPeople = f.people === undefined ? c?.people === \"real\" : f.people === \"real\";\n return defined<RuleCheck>({\n forbid: f.forbid ?? c?.forbid,\n require: f.require ?? c?.require,\n allow: f.allow ?? c?.allow,\n people: realPeople ? \"real\" : undefined,\n });\n}\n\n/** The rule to save, from a drafted candidate and the flags over it; what is missing when there is none. Pure. */\nexport function ruleFromInputs(\n inputs: { candidate?: SavedCandidate; flags?: RuleFlags },\n at: { today: string; taken: readonly string[] },\n): CreativeRule | { error: string } {\n const c = inputs.candidate;\n const f = inputs.flags ?? {};\n const text = (f.text ?? c?.text)?.trim();\n if (!text) return { error: \"--text: the rule, in the person's words (or --candidate <id> from `feedback record`).\" };\n const check = checkOf(f, c);\n const source = defined({\n kind: c ? (\"feedback\" as const) : (\"user\" as const),\n slug: f.slug ?? c?.source.slug,\n runId: f.run ?? c?.source.runId,\n quote: f.quote ?? c?.source.quote,\n date: at.today,\n });\n return {\n id: ruleSlug(f.id ?? text, at.taken),\n origin: \"learned\",\n strength: oneOf(RULE_STRENGTHS, f.strength) ?? c?.strength ?? \"must\",\n applies: oneOf(RULE_APPLIES, f.applies) ?? c?.applies ?? \"any\",\n scope: scopeOf(f, c),\n ...(Object.keys(check).length > 0 ? { check } : {}),\n text,\n ...(f.why ? { why: f.why } : {}),\n source,\n status: \"active\",\n };\n}\n\n/** One version's finished sizes as review stills, from the run history; null when it has no picture. */\nasync function versionOf(runId: string): Promise<ReviewedVersion | null> {\n const record = await fetchRunRecord(runId).catch(() => null);\n const images = (record?.finalOutputs ?? []).filter((o) => o.kind === \"image\" && o.url);\n const stills = await Promise.all(\n images.map(async (o) => {\n const response = await fetch(o.url as string).catch(() => null);\n if (!response?.ok) return null;\n const bytes = Buffer.from(await response.arrayBuffer());\n return (await sharp(bytes).resize({ width: 1024 }).jpeg({ quality: 85 }).toBuffer()).toString(\"base64\");\n }),\n );\n const kept = images.flatMap((o, i) =>\n stills[i] ? [{ still: stills[i] as string, format: o.label ?? \"image\" }] : [],\n );\n return kept.length > 0 ? { runId, stills: kept.map((k) => k.still), formats: kept.map((k) => k.format) } : null;\n}\n\n/** How many approved versions a rule is tested against: a few, other creatives' first. */\nconst APPROVED_VERSIONS = 3;\n\n/** The company's approved versions to test a rule against, other creatives' first. */\nasync function approvedVersions(except: string | undefined, slug: string | undefined): Promise<ReviewedVersion[]> {\n const feedback = await apiPost<CreativesFeedbackResponse>(\"/api/creatives/feedback\", { full: true }).catch(\n () => null,\n );\n const approved = (feedback?.data.recent ?? []).filter((e) => e.verdict === \"approved\" && e.runId !== except);\n const ordered = [...approved.filter((e) => e.creative !== slug), ...approved.filter((e) => e.creative === slug)];\n const runIds = [...new Set(ordered.map((e) => e.runId))];\n const versions: ReviewedVersion[] = [];\n for (const runId of runIds) {\n if (versions.length === APPROVED_VERSIONS) break;\n const version = await versionOf(runId);\n if (version) versions.push(version);\n }\n return versions;\n}\n\n/** The rule on the version it came from and on the company's approved ones (`admissionTest`). */\nasync function admit(rule: CreativeRule): Promise<Admission> {\n const spent: Parameters<typeof holdWorkspaceSpend>[0][number][] = [];\n const review = (version: ReviewedVersion, rules: CreativeRule[]) =>\n reviewAgainstRules({ ...version, rules, onSpend: (u) => spent.push(u) });\n const [origin, approved] = await Promise.all([\n rule.source.runId ? versionOf(rule.source.runId) : Promise.resolve(null),\n approvedVersions(rule.source.runId, rule.source.slug),\n ]);\n const admission = await admissionTest(rule, origin, approved, review);\n await holdWorkspaceSpend(spent);\n return admission;\n}\n\n/** A learned rule's file, retired by `by`; null when there is no such file. */\nasync function retireFile(root: string, id: string, by: string | undefined): Promise<CreativeRule | null> {\n const file = path.join(root, RULES_DIR, `${id}.md`);\n const rule = parseRuleFile(id, await readFile(file, \"utf8\").catch(() => \"\"));\n if (!rule) return null;\n const retired: CreativeRule = { ...rule, status: \"retired\", ...(by ? { retiredBy: by } : {}) };\n await writeFile(file, ruleFileText(retired), \"utf8\");\n return retired;\n}\n\nfunction fail(code: string, message: string, fix?: string, extra: Record<string, unknown> = {}): never {\n writeJson({ ok: false, error: { code, message, ...(fix ? { fix } : {}), ...extra } });\n process.exit(1);\n}\n\nconst list = (value: unknown): string[] | undefined =>\n typeof value === \"string\" && value.trim()\n ? value\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean)\n : undefined;\nconst text = (value: unknown): string | undefined =>\n typeof value === \"string\" && value.trim() ? value.trim() : undefined;\n\nconst ADD_DESCRIPTION = `Save a rule the person agreed to, for every ad from now on: one file in src/content/creative-rules/, published with the Session. Only after they said yes to \"make this a rule for every ad?\".\nStart here: baker creatives rules add --candidate rc-1a2b3c4d # a rule \\`feedback record\\` drafted from their words\n baker creatives rules add --text \"No AI-generated people.\" --strength never --applies cast --people real --quote \"<their words>\" --slug <ad> --run <r_…>\nIt is refused when the company already has it (DUPLICATE_RULE), when it contradicts one (RULE_CONFLICT: ask which wins, then --replaces <id>), when it does not catch the version it came from (RULE_MISSES_ITS_AD), or would block versions the person approved (RULE_BLOCKS_APPROVED): ask the person, never save it anyway.`;\n\nconst ADD_ARGS = {\n candidate: {\n type: \"string\",\n description: \"A rule `feedback record` drafted (rc-…): the flags below override its parts\",\n required: false,\n },\n text: {\n type: \"string\",\n description: \"The rule, one sentence, in the person's own language and words\",\n required: false,\n },\n strength: {\n type: \"string\",\n description: `${RULE_STRENGTHS.join(\" | \")}: never and must are checked and block; prefer is a note`,\n required: false,\n },\n applies: { type: \"string\", description: `What of the ad it is about: ${RULE_APPLIES.join(\", \")}`, required: false },\n forbid: {\n type: \"string\",\n description: 'Words it bans, comma-separated, only when a word decides it (\"online\")',\n required: false,\n },\n allow: { type: \"string\", description: 'The right phrase that holds a banned word (\"100 % online\")', required: false },\n require: { type: \"string\", description: \"Words every ad must say, comma-separated (rare)\", required: false },\n people: {\n type: \"string\",\n description: \"real: only real people appear (a real person's Avatar, a customer, footage or nobody)\",\n required: false,\n },\n kinds: { type: \"string\", description: \"static,video: only ads of these kinds\", required: false },\n products: { type: \"string\", description: \"Product slugs (a business unit): only ads of these\", required: false },\n platforms: { type: \"string\", description: \"meta,linkedin,…: only ads for these\", required: false },\n language: {\n type: \"string\",\n description: \"The language its words are in (es): its banned words are checked only in ads in it\",\n required: false,\n },\n quote: { type: \"string\", description: \"The person's own words it came from, verbatim\", required: false },\n slug: { type: \"string\", description: \"The creative they said it about\", required: false },\n run: { type: \"string\", description: \"The version they said it about (r_…): the rule must catch it\", required: false },\n why: { type: \"string\", description: \"Why, in a sentence, when the person said\", required: false },\n id: { type: \"string\", description: \"The rule's id (its file name); default: from its words\", required: false },\n replaces: {\n type: \"string\",\n description: \"A rule of the person's it contradicts and wins over: retired, never deleted\",\n required: false,\n },\n} as const;\n\nregisterSchema({ command: \"creatives.rules.add\", description: ADD_DESCRIPTION, args: ADD_ARGS });\n\n/**\n * What to do about a BRAND.md rule the new one repeats or contradicts. The rule a person taught lives\n * in its own file only: a copy in BRAND.md would stay in force after it is retired. Pure.\n */\nexport function brandMdHint(declared: Pick<CreativeRule, \"text\">, relation: \"same\" | \"conflict\"): string {\n return relation === \"same\"\n ? `BRAND.md states this too (\"${declared.text}\"): now the person confirmed it, every finished ad is checked against it.`\n : `BRAND.md says otherwise (\"${declared.text}\"): tell the person, and change only that line of BRAND.md (/brand-build) so it no longer says otherwise; never write the rule itself into BRAND.md, or retiring it would leave it in force.`;\n}\n\nexport const rulesAddCommand = defineCommand({\n meta: { name: \"add\", description: ADD_DESCRIPTION },\n args: ADD_ARGS,\n async run({ args }) {\n const root = findWorkspaceRoot(process.cwd()) ?? process.cwd();\n const cacheDir = path.join(root, \"canvas\", \".cache\");\n const candidateId = text(args.candidate);\n const candidate = candidateId ? await loadCandidate(cacheDir, candidateId) : undefined;\n if (candidateId && !candidate) {\n fail(\n \"VALIDATION_ERROR\",\n `No drafted rule ${candidateId} here.`,\n \"Use the id `feedback record` printed in this chat, or pass --text.\",\n );\n }\n const all = await readAllRules(root);\n const rule = ruleFromInputs(\n {\n ...(candidate ? { candidate } : {}),\n flags: {\n text: text(args.text),\n strength: text(args.strength),\n applies: text(args.applies),\n forbid: list(args.forbid),\n allow: list(args.allow),\n require: list(args.require),\n people: text(args.people),\n kinds: list(args.kinds),\n products: list(args.products),\n platforms: list(args.platforms),\n language: text(args.language),\n quote: text(args.quote),\n slug: text(args.slug),\n run: text(args.run),\n why: text(args.why),\n id: text(args.id),\n },\n },\n { today: new Date().toISOString().slice(0, 10), taken: all.map((r) => r.id) },\n );\n if (\"error\" in rule) fail(\"VALIDATION_ERROR\", rule.error);\n const replaces = text(args.replaces);\n const compared = await compareRule(rule, all, jevPairs());\n const sameTaught = compared.same.filter((r) => r.origin === \"learned\");\n if (sameTaught.length > 0) {\n fail(\n \"DUPLICATE_RULE\",\n `The company already has this rule: ${sameTaught.map((r) => `${r.id} (\"${r.text}\")`).join(\"; \")}.`,\n \"Nothing to add. If the person wants it worded otherwise, retire that one and add this.\",\n );\n }\n const conflicts = compared.conflicts.filter((r) => r.origin === \"learned\" && r.id !== replaces);\n if (conflicts.length > 0) {\n fail(\n \"RULE_CONFLICT\",\n `It contradicts ${conflicts.map((r) => `${r.id} (\"${r.text}\")`).join(\"; \")}.`,\n \"Ask the person which one wins. This one: add it again with --replaces <id> (that rule is retired, never deleted). The other: do not add this one.\",\n );\n }\n const admission = await admit(rule);\n const refusal = admissionRefusal(rule, admission);\n if (refusal) fail(refusal.code, refusal.message, refusal.fix, { admission });\n await mkdir(path.join(root, RULES_DIR), { recursive: true });\n const file = path.join(RULES_DIR, `${rule.id}.md`);\n await writeFile(path.join(root, file), ruleFileText(rule), \"utf8\");\n const retired = replaces ? await retireFile(root, replaces, rule.id) : null;\n const declared = [...compared.same, ...compared.conflicts].filter((r) => r.origin === \"declared\");\n writeJson({\n ok: true,\n data: {\n rule: rulesView([rule], { full: true })[0],\n file,\n admission,\n ...(retired ? { retired: retired.id } : {}),\n },\n hints: [\n `Saved for every ad from now on${admission.origin === \"untested\" ? \" (not tested on a version: nothing a picture shows decides it, or the version had no picture)\" : \"\"}. Tell the person in one line, then run \\`baker creatives check\\`: which ads already made break it.`,\n ...(compared.judged\n ? []\n : [\n \"Whether it repeats or contradicts another rule could not be read (the decision model did not answer): look at `baker creatives rules list`.\",\n ]),\n ...declared.map((r) => brandMdHint(r, compared.same.includes(r) ? \"same\" : \"conflict\")),\n ],\n });\n },\n});\n\nconst RETIRE_DESCRIPTION = `Retire a rule a person taught, when they say it no longer holds or another replaces it: it stays in its file as retired, never deleted, and no ad is held to it.\nStart here: baker creatives rules retire cien-por-cien-online [--by <rule id>|BRAND.md]\nA rule of BRAND.md is changed in BRAND.md (/brand-build).`;\n\nconst RETIRE_ARGS = {\n id: { type: \"positional\", description: \"The rule's id (`baker creatives rules list`)\", required: true },\n by: { type: \"string\", description: \"What replaces it: another rule's id, or BRAND.md\", required: false },\n} as const;\n\nregisterSchema({ command: \"creatives.rules.retire\", description: RETIRE_DESCRIPTION, args: RETIRE_ARGS });\n\nexport const rulesRetireCommand = defineCommand({\n meta: { name: \"retire\", description: RETIRE_DESCRIPTION },\n args: RETIRE_ARGS,\n async run({ args }) {\n const root = findWorkspaceRoot(process.cwd()) ?? process.cwd();\n const id = String(args.id);\n if (/^brand-[0-9a-f]{8}$/.test(id)) {\n fail(\"VALIDATION_ERROR\", `${id} is a rule of BRAND.md.`, \"Change it in BRAND.md with /brand-build.\");\n }\n const retired = await retireFile(root, id, text(args.by));\n if (!retired) fail(\"NOT_FOUND\", `No rule ${id} in ${RULES_DIR}.`, \"See `baker creatives rules list --all`.\");\n writeJson({\n ok: true,\n data: { rule: rulesView([retired], { full: true })[0] },\n hints: [\"Retired: no ad is held to it from now on.\"],\n });\n },\n});\n","/**\n * A rule's admission test, before it is saved for every ad: it must catch the version it came from\n * (the rejected one), and stay silent on versions of the company the person approved. A rule that\n * misses its own ad is worded for something else; one that would block approved ads is stricter\n * than the person. Either way the person is asked again, never the rule saved as drafted. Only the\n * rules the finished-ad review holds an ad to by eye are tested (`reviewedRules`); a voice or a\n * sound needs the video playing, and is saved untested, saying so.\n */\nimport type { RenderFinding } from \"../nodes/local/lib/render-review.ts\";\nimport { reviewedRules } from \"../nodes/local/lib/rules-findings.ts\";\nimport type { CreativeRule } from \"./schema.ts\";\n\n/** One version as the rules review looks at it: its sizes as base64 JPEG, in `formats` order. */\nexport type ReviewedVersion = { runId: string; stills: string[]; formats: string[] };\n\n/** The rules review on one version (`reviewAgainstRules`); null when nobody looked. */\nexport type ReviewVersion = (version: ReviewedVersion, rules: CreativeRule[]) => Promise<RenderFinding[] | null>;\n\nexport type Admission = {\n origin: \"caught\" | \"missed\" | \"untested\";\n approved: { checked: number; blocked: Array<{ runId: string; what: string }> };\n};\n\n/** The rule's blocking findings on a version; null when nobody looked. */\nasync function breaks(\n rule: CreativeRule,\n version: ReviewedVersion,\n review: ReviewVersion,\n): Promise<RenderFinding[] | null> {\n const found = await review(version, [rule]).catch(() => null);\n return found === null ? null : found.filter((f) => f.kind?.rule === rule.id && f.severity === \"blocking\");\n}\n\n/** The rule on the version it came from and on up to a few the person approved. */\nexport async function admissionTest(\n rule: CreativeRule,\n origin: ReviewedVersion | null,\n approved: readonly ReviewedVersion[],\n review: ReviewVersion,\n): Promise<Admission> {\n const untested: Admission = { origin: \"untested\", approved: { checked: 0, blocked: [] } };\n // A prefer never blocks: it is tested as if it did, since the person reads it the same.\n const tested = { ...rule, strength: rule.strength === \"prefer\" ? (\"must\" as const) : rule.strength };\n if (reviewedRules([tested]).length === 0) return untested;\n const own = origin ? await breaks(tested, origin, review) : null;\n const results = await Promise.all(\n approved.map(async (v) => ({ runId: v.runId, found: await breaks(tested, v, review) })),\n );\n const looked = results.filter((r) => r.found !== null);\n return {\n origin: own === null ? \"untested\" : own.length > 0 ? \"caught\" : \"missed\",\n approved: {\n checked: looked.length,\n blocked: looked.flatMap((r) =>\n r.found?.[0] ? [{ runId: r.runId, what: r.found[0].what.replace(/^.*?\\): /, \"\") }] : [],\n ),\n },\n };\n}\n\n/** Why the rule is not saved as drafted, and what to ask the person; null when it passed or was not tested. Pure. */\nexport function admissionRefusal(\n rule: CreativeRule,\n admission: Admission,\n): { code: \"RULE_MISSES_ITS_AD\" | \"RULE_BLOCKS_APPROVED\"; message: string; fix: string } | null {\n if (admission.origin === \"missed\") {\n return {\n code: \"RULE_MISSES_ITS_AD\",\n message: `Not saved: \"${rule.text}\" does not catch the version it came from (${rule.source.runId ?? \"the rejected one\"}), so it is worded for something else.`,\n fix: \"Reword it to name exactly what was wrong on that version, in the person's words, and add it again; or ask the person what the rule is.\",\n };\n }\n const blocked = admission.approved.blocked;\n if (blocked.length > 0) {\n return {\n code: \"RULE_BLOCKS_APPROVED\",\n message: `Not saved: \"${rule.text}\" would block ${blocked.length} version${blocked.length === 1 ? \"\" : \"s\"} the person approved: ${blocked.map((b) => `${b.runId} (${b.what})`).join(\"; \")}.`,\n fix: \"Ask the person whether those approved ads break it. If they do not, reword the rule so it names only what they reject, and add it again.\",\n };\n }\n return null;\n}\n","/**\n * A new rule against the ones the company already has, read by the decision model in any language:\n * which say the same (a duplicate), and which it contradicts (an ad could not keep both). `rules add`\n * refuses a duplicate of a rule a person taught, and a contradiction until the person picks the winner;\n * the loser is retired, never deleted.\n */\nimport { askJev } from \"../nodes/local/lib/jev.ts\";\nimport type { ReviewUsage } from \"../nodes/local/lib/render-review.ts\";\nimport type { CreativeRule } from \"./schema.ts\";\n\nconst SAME =\n \"Do rules `a` and `b` ask the same thing of an ad, in any words or language, so that an ad keeping one keeps the other?\";\nconst CONFLICT =\n \"Do rules `a` and `b` contradict each other, so that no ad could keep both: following one breaks the other?\";\n\n/** Above these, two rules are the same or contradict: refusing a rule by mistake costs the person a rule. */\nconst SAME_BAND = 0.6;\nconst CONFLICT_BAND = 0.6;\n\nexport type RulePair = { a: string; b: string; question: \"same\" | \"conflict\" };\n\n/** Each pair's probability of yes, in order; null when the decision model did not answer. */\nexport type AskPairs = (pairs: readonly RulePair[]) => Promise<number[] | null>;\n\n/** The most questions one request carries. */\nconst BATCH = 40;\n\n/** The decision model asked about each pair, a batch at a time. */\nexport function jevPairs(onSpend?: (usage: ReviewUsage) => void): AskPairs {\n return async (pairs) => {\n const answers: number[] = [];\n for (let i = 0; i < pairs.length; i += BATCH) {\n const batch = pairs.slice(i, i + BATCH);\n const got = await askJev(\n batch.map((p) => ({ instructions: { a: p.a, b: p.b, question: p.question === \"same\" ? SAME : CONFLICT } })),\n onSpend,\n );\n if (!got) return null;\n answers.push(...got);\n }\n return answers;\n };\n}\n\nexport type Comparison = { same: CreativeRule[]; conflicts: CreativeRule[]; judged: boolean };\n\n/** The active rules `candidate` duplicates and the ones it contradicts. */\nexport async function compareRule(\n candidate: CreativeRule,\n existing: readonly CreativeRule[],\n ask: AskPairs,\n): Promise<Comparison> {\n const active = existing.filter((r) => r.status === \"active\" && r.id !== candidate.id);\n if (active.length === 0) return { same: [], conflicts: [], judged: true };\n const pairs = active.flatMap((r): RulePair[] => [\n { a: candidate.text, b: r.text, question: \"same\" },\n { a: candidate.text, b: r.text, question: \"conflict\" },\n ]);\n const answers = await ask(pairs).catch(() => null);\n if (!answers || answers.length !== pairs.length) return { same: [], conflicts: [], judged: false };\n return {\n same: active.filter((_, i) => (answers[2 * i] ?? 0) >= SAME_BAND),\n conflicts: active.filter((_, i) => (answers[2 * i + 1] ?? 0) >= CONFLICT_BAND),\n judged: true,\n };\n}\n","/**\n * A rule a person agreed to, as the file it lives in (`src/content/creative-rules/<slug>.md`): its\n * frontmatter (what decides it, where it came from) and its words, then why. The reader\n * (`parseRuleFile`) reads it back the same. Pure.\n */\nimport { stringify as stringifyYaml } from \"yaml\";\nimport type { CreativeRule } from \"./schema.ts\";\n\n/** The rule's file: frontmatter, its words, then why. Pure. */\nexport function ruleFileText(rule: CreativeRule): string {\n const frontmatter = {\n strength: rule.strength,\n applies: rule.applies,\n ...(Object.keys(rule.scope).length > 0 ? { scope: rule.scope } : {}),\n ...(rule.check && Object.keys(rule.check).length > 0 ? { check: rule.check } : {}),\n source: rule.source,\n status: rule.status,\n ...(rule.retiredBy ? { retiredBy: rule.retiredBy } : {}),\n };\n // Every string quoted: a date stays a date's words, and a quote with a colon stays one value.\n const yaml = stringifyYaml(frontmatter, { defaultStringType: \"QUOTE_DOUBLE\", defaultKeyType: \"PLAIN\", lineWidth: 0 });\n return `---\\n${yaml}---\\n${rule.text.trim()}\\n${rule.why ? `\\nWhy: ${rule.why.trim()}\\n` : \"\"}`;\n}\n\nconst SLUG_WORDS = 8;\n\n/** A file name from the rule's words, not one of `taken`. Pure. */\nexport function ruleSlug(text: string, taken: readonly string[]): string {\n const base =\n text\n .normalize(\"NFKD\")\n .replace(/\\p{M}/gu, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \" \")\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, SLUG_WORDS)\n .join(\"-\") || \"rule\";\n if (!taken.includes(base)) return base;\n let n = 2;\n while (taken.includes(`${base}-${n}`)) n++;\n return `${base}-${n}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,SAAS,OAAO,UAAU,iBAAiB;AAC3C,OAAO,UAAU;AAEjB,SAAS,qBAAqB;AAC9B,OAAO,WAAW;;;ACalB,eAAe,OACb,MACA,SACA,QACiC;AACjC,QAAM,QAAQ,MAAM,OAAO,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,MAAM,IAAI;AAC5D,SAAO,UAAU,OAAO,OAAO,MAAM,OAAO,CAAC,MAAM,EAAE,MAAM,SAAS,KAAK,MAAM,EAAE,aAAa,UAAU;AAC1G;AAGA,eAAsB,cACpB,MACA,QACA,UACA,QACoB;AACpB,QAAM,WAAsB,EAAE,QAAQ,YAAY,UAAU,EAAE,SAAS,GAAG,SAAS,CAAC,EAAE,EAAE;AAExF,QAAM,SAAS,EAAE,GAAG,MAAM,UAAU,KAAK,aAAa,WAAY,SAAmB,KAAK,SAAS;AACnG,MAAI,cAAc,CAAC,MAAM,CAAC,EAAE,WAAW,EAAG,QAAO;AACjD,QAAM,MAAM,SAAS,MAAM,OAAO,QAAQ,QAAQ,MAAM,IAAI;AAC5D,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,SAAS,IAAI,OAAO,OAAO,EAAE,OAAO,EAAE,OAAO,OAAO,MAAM,OAAO,QAAQ,GAAG,MAAM,EAAE,EAAE;AAAA,EACxF;AACA,QAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,EAAE,UAAU,IAAI;AACrD,SAAO;AAAA,IACL,QAAQ,QAAQ,OAAO,aAAa,IAAI,SAAS,IAAI,WAAW;AAAA,IAChE,UAAU;AAAA,MACR,SAAS,OAAO;AAAA,MAChB,SAAS,OAAO;AAAA,QAAQ,CAAC,MACvB,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,QAAQ,YAAY,EAAE,EAAE,CAAC,IAAI,CAAC;AAAA,MACxF;AAAA,IACF;AAAA,EACF;AACF;AAGO,SAAS,iBACd,MACA,WAC8F;AAC9F,MAAI,UAAU,WAAW,UAAU;AACjC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,eAAe,KAAK,IAAI,8CAA8C,KAAK,OAAO,SAAS,kBAAkB;AAAA,MACtH,KAAK;AAAA,IACP;AAAA,EACF;AACA,QAAM,UAAU,UAAU,SAAS;AACnC,MAAI,QAAQ,SAAS,GAAG;AACtB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,eAAe,KAAK,IAAI,iBAAiB,QAAQ,MAAM,WAAW,QAAQ,WAAW,IAAI,KAAK,GAAG,yBAAyB,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,KAAK,EAAE,IAAI,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA,MAC1L,KAAK;AAAA,IACP;AAAA,EACF;AACA,SAAO;AACT;;;ACvEA,IAAM,OACJ;AACF,IAAM,WACJ;AAGF,IAAM,YAAY;AAClB,IAAM,gBAAgB;AAQtB,IAAM,QAAQ;AAGP,SAAS,SAAS,SAAkD;AACzE,SAAO,OAAO,UAAU;AACtB,UAAM,UAAoB,CAAC;AAC3B,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,OAAO;AAC5C,YAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,KAAK;AACtC,YAAM,MAAM,MAAM;AAAA,QAChB,MAAM,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,UAAU,EAAE,aAAa,SAAS,OAAO,SAAS,EAAE,EAAE;AAAA,QAC1G;AAAA,MACF;AACA,UAAI,CAAC,IAAK,QAAO;AACjB,cAAQ,KAAK,GAAG,GAAG;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,YACpB,WACA,UACA,KACqB;AACrB,QAAM,SAAS,SAAS,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY,EAAE,OAAO,UAAU,EAAE;AACpF,MAAI,OAAO,WAAW,EAAG,QAAO,EAAE,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,QAAQ,KAAK;AACxE,QAAM,QAAQ,OAAO,QAAQ,CAAC,MAAkB;AAAA,IAC9C,EAAE,GAAG,UAAU,MAAM,GAAG,EAAE,MAAM,UAAU,OAAO;AAAA,IACjD,EAAE,GAAG,UAAU,MAAM,GAAG,EAAE,MAAM,UAAU,WAAW;AAAA,EACvD,CAAC;AACD,QAAM,UAAU,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AACjD,MAAI,CAAC,WAAW,QAAQ,WAAW,MAAM,OAAQ,QAAO,EAAE,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,QAAQ,MAAM;AACjG,SAAO;AAAA,IACL,MAAM,OAAO,OAAO,CAAC,GAAG,OAAO,QAAQ,IAAI,CAAC,KAAK,MAAM,SAAS;AAAA,IAChE,WAAW,OAAO,OAAO,CAAC,GAAG,OAAO,QAAQ,IAAI,IAAI,CAAC,KAAK,MAAM,aAAa;AAAA,IAC7E,QAAQ;AAAA,EACV;AACF;;;AC5DA,SAAS,aAAa,qBAAqB;AAIpC,SAAS,aAAa,MAA4B;AACvD,QAAM,cAAc;AAAA,IAClB,UAAU,KAAK;AAAA,IACf,SAAS,KAAK;AAAA,IACd,GAAI,OAAO,KAAK,KAAK,KAAK,EAAE,SAAS,IAAI,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,IAClE,GAAI,KAAK,SAAS,OAAO,KAAK,KAAK,KAAK,EAAE,SAAS,IAAI,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,IAChF,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,IACb,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,EACxD;AAEA,QAAM,OAAO,cAAc,aAAa,EAAE,mBAAmB,gBAAgB,gBAAgB,SAAS,WAAW,EAAE,CAAC;AACpH,SAAO;AAAA,EAAQ,IAAI;AAAA,EAAQ,KAAK,KAAK,KAAK,CAAC;AAAA,EAAK,KAAK,MAAM;AAAA,OAAU,KAAK,IAAI,KAAK,CAAC;AAAA,IAAO,EAAE;AAC/F;AAEA,IAAM,aAAa;AAGZ,SAAS,SAASA,OAAc,OAAkC;AACvE,QAAM,OACJA,MACG,UAAU,MAAM,EAChB,QAAQ,WAAC,UAAM,IAAE,GAAE,EAAE,EACrB,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,KAAK,EACL,MAAM,KAAK,EACX,OAAO,OAAO,EACd,MAAM,GAAG,UAAU,EACnB,KAAK,GAAG,KAAK;AAClB,MAAI,CAAC,MAAM,SAAS,IAAI,EAAG,QAAO;AAClC,MAAI,IAAI;AACR,SAAO,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,EAAE,EAAG;AACvC,SAAO,GAAG,IAAI,IAAI,CAAC;AACrB;;;AHiBA,IAAM,QAAQ,CAAmB,QAAsB,UACrD,SAAU,OAA6B,SAAS,KAAK,IAAK,QAAc;AAE1E,IAAM,UAAU,CAAmB,UACjC,OAAO;AAAA,EACL,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,UAAa,EAAE,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE;AAClG;AAGF,SAAS,QAAQ,GAAc,GAA0C;AACvE,SAAO,QAAmB;AAAA,IACxB,QAAQ,EAAE,SAAS,GAAG,QAAQ,QAAQ,CAAC,MAAM,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;AAAA,IACvE,UAAU,EAAE;AAAA,IACZ,WAAW,EAAE,aAAa,GAAG;AAAA,IAC7B,UAAU,EAAE,YAAY,GAAG;AAAA,EAC7B,CAAC;AACH;AAGA,SAAS,QAAQ,GAAc,GAA0C;AACvE,QAAM,aAAa,EAAE,WAAW,SAAY,GAAG,WAAW,SAAS,EAAE,WAAW;AAChF,SAAO,QAAmB;AAAA,IACxB,QAAQ,EAAE,UAAU,GAAG;AAAA,IACvB,SAAS,EAAE,WAAW,GAAG;AAAA,IACzB,OAAO,EAAE,SAAS,GAAG;AAAA,IACrB,QAAQ,aAAa,SAAS;AAAA,EAChC,CAAC;AACH;AAGO,SAAS,eACd,QACA,IACkC;AAClC,QAAM,IAAI,OAAO;AACjB,QAAM,IAAI,OAAO,SAAS,CAAC;AAC3B,QAAMC,SAAQ,EAAE,QAAQ,GAAG,OAAO,KAAK;AACvC,MAAI,CAACA,MAAM,QAAO,EAAE,OAAO,wFAAwF;AACnH,QAAM,QAAQ,QAAQ,GAAG,CAAC;AAC1B,QAAM,SAAS,QAAQ;AAAA,IACrB,MAAM,IAAK,aAAwB;AAAA,IACnC,MAAM,EAAE,QAAQ,GAAG,OAAO;AAAA,IAC1B,OAAO,EAAE,OAAO,GAAG,OAAO;AAAA,IAC1B,OAAO,EAAE,SAAS,GAAG,OAAO;AAAA,IAC5B,MAAM,GAAG;AAAA,EACX,CAAC;AACD,SAAO;AAAA,IACL,IAAI,SAAS,EAAE,MAAMA,OAAM,GAAG,KAAK;AAAA,IACnC,QAAQ;AAAA,IACR,UAAU,MAAM,gBAAgB,EAAE,QAAQ,KAAK,GAAG,YAAY;AAAA,IAC9D,SAAS,MAAM,cAAc,EAAE,OAAO,KAAK,GAAG,WAAW;AAAA,IACzD,OAAO,QAAQ,GAAG,CAAC;AAAA,IACnB,GAAI,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,EAAE,MAAM,IAAI,CAAC;AAAA,IACjD,MAAAA;AAAA,IACA,GAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC;AAAA,IAC9B;AAAA,IACA,QAAQ;AAAA,EACV;AACF;AAGA,eAAe,UAAU,OAAgD;AACvE,QAAM,SAAS,MAAM,eAAe,KAAK,EAAE,MAAM,MAAM,IAAI;AAC3D,QAAM,UAAU,QAAQ,gBAAgB,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG;AACrF,QAAM,SAAS,MAAM,QAAQ;AAAA,IAC3B,OAAO,IAAI,OAAO,MAAM;AACtB,YAAM,WAAW,MAAM,MAAM,EAAE,GAAa,EAAE,MAAM,MAAM,IAAI;AAC9D,UAAI,CAAC,UAAU,GAAI,QAAO;AAC1B,YAAM,QAAQ,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;AACtD,cAAQ,MAAM,MAAM,KAAK,EAAE,OAAO,EAAE,OAAO,KAAK,CAAC,EAAE,KAAK,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,QAAQ;AAAA,IACxG,CAAC;AAAA,EACH;AACA,QAAM,OAAO,OAAO;AAAA,IAAQ,CAAC,GAAG,MAC9B,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,OAAO,CAAC,GAAa,QAAQ,EAAE,SAAS,QAAQ,CAAC,IAAI,CAAC;AAAA,EAC9E;AACA,SAAO,KAAK,SAAS,IAAI,EAAE,OAAO,QAAQ,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,SAAS,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI;AAC7G;AAGA,IAAM,oBAAoB;AAG1B,eAAe,iBAAiB,QAA4B,MAAsD;AAChH,QAAM,WAAW,MAAM,QAAmC,2BAA2B,EAAE,MAAM,KAAK,CAAC,EAAE;AAAA,IACnG,MAAM;AAAA,EACR;AACA,QAAM,YAAY,UAAU,KAAK,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,YAAY,cAAc,EAAE,UAAU,MAAM;AAC3G,QAAM,UAAU,CAAC,GAAG,SAAS,OAAO,CAAC,MAAM,EAAE,aAAa,IAAI,GAAG,GAAG,SAAS,OAAO,CAAC,MAAM,EAAE,aAAa,IAAI,CAAC;AAC/G,QAAM,SAAS,CAAC,GAAG,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACvD,QAAM,WAA8B,CAAC;AACrC,aAAW,SAAS,QAAQ;AAC1B,QAAI,SAAS,WAAW,kBAAmB;AAC3C,UAAM,UAAU,MAAM,UAAU,KAAK;AACrC,QAAI,QAAS,UAAS,KAAK,OAAO;AAAA,EACpC;AACA,SAAO;AACT;AAGA,eAAe,MAAM,MAAwC;AAC3D,QAAM,QAA4D,CAAC;AACnE,QAAM,SAAS,CAAC,SAA0B,UACxC,mBAAmB,EAAE,GAAG,SAAS,OAAO,SAAS,CAAC,MAAM,MAAM,KAAK,CAAC,EAAE,CAAC;AACzE,QAAM,CAAC,QAAQ,QAAQ,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC3C,KAAK,OAAO,QAAQ,UAAU,KAAK,OAAO,KAAK,IAAI,QAAQ,QAAQ,IAAI;AAAA,IACvE,iBAAiB,KAAK,OAAO,OAAO,KAAK,OAAO,IAAI;AAAA,EACtD,CAAC;AACD,QAAM,YAAY,MAAM,cAAc,MAAM,QAAQ,UAAU,MAAM;AACpE,QAAM,mBAAmB,KAAK;AAC9B,SAAO;AACT;AAGA,eAAe,WAAW,MAAc,IAAY,IAAsD;AACxG,QAAM,OAAO,KAAK,KAAK,MAAM,WAAW,GAAG,EAAE,KAAK;AAClD,QAAM,OAAO,cAAc,IAAI,MAAM,SAAS,MAAM,MAAM,EAAE,MAAM,MAAM,EAAE,CAAC;AAC3E,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,UAAwB,EAAE,GAAG,MAAM,QAAQ,WAAW,GAAI,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC,EAAG;AAC7F,QAAM,UAAU,MAAM,aAAa,OAAO,GAAG,MAAM;AACnD,SAAO;AACT;AAEA,SAAS,KAAK,MAAc,SAAiB,KAAc,QAAiC,CAAC,GAAU;AACrG,YAAU,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,SAAS,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC,GAAI,GAAG,MAAM,EAAE,CAAC;AACpF,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,OAAO,CAAC,UACZ,OAAO,UAAU,YAAY,MAAM,KAAK,IACpC,MACG,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO,IACjB;AACN,IAAM,OAAO,CAAC,UACZ,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI;AAE7D,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAKxB,IAAM,WAAW;AAAA,EACf,WAAW;AAAA,IACT,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,aAAa,GAAG,eAAe,KAAK,KAAK,CAAC;AAAA,IAC1C,UAAU;AAAA,EACZ;AAAA,EACA,SAAS,EAAE,MAAM,UAAU,aAAa,+BAA+B,aAAa,KAAK,IAAI,CAAC,IAAI,UAAU,MAAM;AAAA,EAClH,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA,OAAO,EAAE,MAAM,UAAU,aAAa,8DAA8D,UAAU,MAAM;AAAA,EACpH,SAAS,EAAE,MAAM,UAAU,aAAa,mDAAmD,UAAU,MAAM;AAAA,EAC3G,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA,OAAO,EAAE,MAAM,UAAU,aAAa,yCAAyC,UAAU,MAAM;AAAA,EAC/F,UAAU,EAAE,MAAM,UAAU,aAAa,sDAAsD,UAAU,MAAM;AAAA,EAC/G,WAAW,EAAE,MAAM,UAAU,aAAa,4CAAuC,UAAU,MAAM;AAAA,EACjG,UAAU;AAAA,IACR,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA,OAAO,EAAE,MAAM,UAAU,aAAa,iDAAiD,UAAU,MAAM;AAAA,EACvG,MAAM,EAAE,MAAM,UAAU,aAAa,mCAAmC,UAAU,MAAM;AAAA,EACxF,KAAK,EAAE,MAAM,UAAU,aAAa,qEAAgE,UAAU,MAAM;AAAA,EACpH,KAAK,EAAE,MAAM,UAAU,aAAa,4CAA4C,UAAU,MAAM;AAAA,EAChG,IAAI,EAAE,MAAM,UAAU,aAAa,0DAA0D,UAAU,MAAM;AAAA,EAC7G,UAAU;AAAA,IACR,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AACF;AAEA,eAAe,EAAE,SAAS,uBAAuB,aAAa,iBAAiB,MAAM,SAAS,CAAC;AAMxF,SAAS,YAAY,UAAsC,UAAuC;AACvG,SAAO,aAAa,SAChB,8BAA8B,SAAS,IAAI,8EAC3C,6BAA6B,SAAS,IAAI;AAChD;AAEO,IAAM,kBAAkB,cAAc;AAAA,EAC3C,MAAM,EAAE,MAAM,OAAO,aAAa,gBAAgB;AAAA,EAClD,MAAM;AAAA,EACN,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,OAAO,kBAAkB,QAAQ,IAAI,CAAC,KAAK,QAAQ,IAAI;AAC7D,UAAM,WAAW,KAAK,KAAK,MAAM,UAAU,QAAQ;AACnD,UAAM,cAAc,KAAK,KAAK,SAAS;AACvC,UAAM,YAAY,cAAc,MAAM,cAAc,UAAU,WAAW,IAAI;AAC7E,QAAI,eAAe,CAAC,WAAW;AAC7B;AAAA,QACE;AAAA,QACA,mBAAmB,WAAW;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AACA,UAAM,MAAM,MAAM,aAAa,IAAI;AACnC,UAAM,OAAO;AAAA,MACX;AAAA,QACE,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,QACjC,OAAO;AAAA,UACL,MAAM,KAAK,KAAK,IAAI;AAAA,UACpB,UAAU,KAAK,KAAK,QAAQ;AAAA,UAC5B,SAAS,KAAK,KAAK,OAAO;AAAA,UAC1B,QAAQ,KAAK,KAAK,MAAM;AAAA,UACxB,OAAO,KAAK,KAAK,KAAK;AAAA,UACtB,SAAS,KAAK,KAAK,OAAO;AAAA,UAC1B,QAAQ,KAAK,KAAK,MAAM;AAAA,UACxB,OAAO,KAAK,KAAK,KAAK;AAAA,UACtB,UAAU,KAAK,KAAK,QAAQ;AAAA,UAC5B,WAAW,KAAK,KAAK,SAAS;AAAA,UAC9B,UAAU,KAAK,KAAK,QAAQ;AAAA,UAC5B,OAAO,KAAK,KAAK,KAAK;AAAA,UACtB,MAAM,KAAK,KAAK,IAAI;AAAA,UACpB,KAAK,KAAK,KAAK,GAAG;AAAA,UAClB,KAAK,KAAK,KAAK,GAAG;AAAA,UAClB,IAAI,KAAK,KAAK,EAAE;AAAA,QAClB;AAAA,MACF;AAAA,MACA,EAAE,QAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,GAAG,OAAO,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE;AAAA,IAC9E;AACA,QAAI,WAAW,KAAM,MAAK,oBAAoB,KAAK,KAAK;AACxD,UAAM,WAAW,KAAK,KAAK,QAAQ;AACnC,UAAM,WAAW,MAAM,YAAY,MAAM,KAAK,SAAS,CAAC;AACxD,UAAM,aAAa,SAAS,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS;AACrE,QAAI,WAAW,SAAS,GAAG;AACzB;AAAA,QACE;AAAA,QACA,sCAAsC,WAAW,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,QAC/F;AAAA,MACF;AAAA,IACF;AACA,UAAM,YAAY,SAAS,UAAU,OAAO,CAAC,MAAM,EAAE,WAAW,aAAa,EAAE,OAAO,QAAQ;AAC9F,QAAI,UAAU,SAAS,GAAG;AACxB;AAAA,QACE;AAAA,QACA,kBAAkB,UAAU,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,QAC1E;AAAA,MACF;AAAA,IACF;AACA,UAAM,YAAY,MAAM,MAAM,IAAI;AAClC,UAAM,UAAU,iBAAiB,MAAM,SAAS;AAChD,QAAI,QAAS,MAAK,QAAQ,MAAM,QAAQ,SAAS,QAAQ,KAAK,EAAE,UAAU,CAAC;AAC3E,UAAM,MAAM,KAAK,KAAK,MAAM,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAC3D,UAAM,OAAO,KAAK,KAAK,WAAW,GAAG,KAAK,EAAE,KAAK;AACjD,UAAM,UAAU,KAAK,KAAK,MAAM,IAAI,GAAG,aAAa,IAAI,GAAG,MAAM;AACjE,UAAM,UAAU,WAAW,MAAM,WAAW,MAAM,UAAU,KAAK,EAAE,IAAI;AACvE,UAAM,WAAW,CAAC,GAAG,SAAS,MAAM,GAAG,SAAS,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU;AAChG,cAAU;AAAA,MACR,IAAI;AAAA,MACJ,MAAM;AAAA,QACJ,MAAM,UAAU,CAAC,IAAI,GAAG,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;AAAA,QACzC;AAAA,QACA;AAAA,QACA,GAAI,UAAU,EAAE,SAAS,QAAQ,GAAG,IAAI,CAAC;AAAA,MAC3C;AAAA,MACA,OAAO;AAAA,QACL,iCAAiC,UAAU,WAAW,aAAa,kGAAkG,EAAE;AAAA,QACvK,GAAI,SAAS,SACT,CAAC,IACD;AAAA,UACE;AAAA,QACF;AAAA,QACJ,GAAG,SAAS,IAAI,CAAC,MAAM,YAAY,GAAG,SAAS,KAAK,SAAS,CAAC,IAAI,SAAS,UAAU,CAAC;AAAA,MACxF;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;AAED,IAAM,qBAAqB;AAAA;AAAA;AAI3B,IAAM,cAAc;AAAA,EAClB,IAAI,EAAE,MAAM,cAAc,aAAa,gDAAgD,UAAU,KAAK;AAAA,EACtG,IAAI,EAAE,MAAM,UAAU,aAAa,oDAAoD,UAAU,MAAM;AACzG;AAEA,eAAe,EAAE,SAAS,0BAA0B,aAAa,oBAAoB,MAAM,YAAY,CAAC;AAEjG,IAAM,qBAAqB,cAAc;AAAA,EAC9C,MAAM,EAAE,MAAM,UAAU,aAAa,mBAAmB;AAAA,EACxD,MAAM;AAAA,EACN,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,OAAO,kBAAkB,QAAQ,IAAI,CAAC,KAAK,QAAQ,IAAI;AAC7D,UAAM,KAAK,OAAO,KAAK,EAAE;AACzB,QAAI,sBAAsB,KAAK,EAAE,GAAG;AAClC,WAAK,oBAAoB,GAAG,EAAE,2BAA2B,0CAA0C;AAAA,IACrG;AACA,UAAM,UAAU,MAAM,WAAW,MAAM,IAAI,KAAK,KAAK,EAAE,CAAC;AACxD,QAAI,CAAC,QAAS,MAAK,aAAa,WAAW,EAAE,OAAO,SAAS,KAAK,yCAAyC;AAC3G,cAAU;AAAA,MACR,IAAI;AAAA,MACJ,MAAM,EAAE,MAAM,UAAU,CAAC,OAAO,GAAG,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC,EAAE;AAAA,MACtD,OAAO,CAAC,2CAA2C;AAAA,IACrD,CAAC;AAAA,EACH;AACF,CAAC;","names":["text","text"]}
@@ -3,7 +3,7 @@ import {
3
3
  executeCanvasRun,
4
4
  runCommand,
5
5
  stopBeforeKinds
6
- } from "./chunk-3AOMKBDC.js";
6
+ } from "./chunk-NDIBFOFB.js";
7
7
  import "./chunk-IVRXPYQ7.js";
8
8
  import "./chunk-3PL2QRF2.js";
9
9
  import "./chunk-WN4KX7GE.js";
@@ -13,16 +13,16 @@ import "./chunk-IOGKJZ4Z.js";
13
13
  import "./chunk-Q6ULQMWG.js";
14
14
  import "./chunk-KKJ4KJCW.js";
15
15
  import "./chunk-3ACMDRSE.js";
16
- import "./chunk-QAOEVZYY.js";
17
- import "./chunk-SQQ4VBNI.js";
18
- import "./chunk-72QBQS63.js";
19
- import "./chunk-WZDKROPU.js";
16
+ import "./chunk-HY6DIWDV.js";
17
+ import "./chunk-5OLCELV7.js";
18
+ import "./chunk-OTLYELOW.js";
19
+ import "./chunk-FHYUIYU5.js";
20
20
  import "./chunk-L44WSWSZ.js";
21
21
  import "./chunk-B2SAOVMU.js";
22
- import "./chunk-IGOOLUE2.js";
23
- import "./chunk-BVMXTD4B.js";
22
+ import "./chunk-A7MTWTMM.js";
23
+ import "./chunk-ZPMGYAYZ.js";
24
24
  import "./chunk-AN7CMLYY.js";
25
- import "./chunk-7XH4UQWS.js";
25
+ import "./chunk-5OAFKP6L.js";
26
26
  import "./chunk-S4ROJTDY.js";
27
27
  import "./chunk-YJAQWTS6.js";
28
28
  import "./chunk-MNPBPU3G.js";
@@ -61,4 +61,4 @@ export {
61
61
  runCommand,
62
62
  stopBeforeKinds
63
63
  };
64
- //# sourceMappingURL=run-IRJWKZ3K.js.map
64
+ //# sourceMappingURL=run-WBFKGA42.js.map
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-CCFZB42B.js";
8
8
  import {
9
9
  syncCreativeDefinitionBestEffort
10
- } from "./chunk-G2AZCDX4.js";
10
+ } from "./chunk-HGTLGFKV.js";
11
11
  import "./chunk-IVRXPYQ7.js";
12
12
  import {
13
13
  pinnedModelHint
@@ -21,7 +21,7 @@ import {
21
21
  resolveFormats,
22
22
  resolvePlatform,
23
23
  titleFromSlug
24
- } from "./chunk-SQQ4VBNI.js";
24
+ } from "./chunk-5OLCELV7.js";
25
25
  import {
26
26
  BRAND_DIR,
27
27
  REBUILD_FILE,
@@ -51,13 +51,13 @@ import {
51
51
  voiceGenderModel,
52
52
  webFontUrl,
53
53
  writeSceneFiles
54
- } from "./chunk-WZDKROPU.js";
54
+ } from "./chunk-FHYUIYU5.js";
55
55
  import "./chunk-B2SAOVMU.js";
56
- import "./chunk-BVMXTD4B.js";
56
+ import "./chunk-ZPMGYAYZ.js";
57
57
  import {
58
58
  readAvatars
59
59
  } from "./chunk-AN7CMLYY.js";
60
- import "./chunk-7XH4UQWS.js";
60
+ import "./chunk-5OAFKP6L.js";
61
61
  import "./chunk-S4ROJTDY.js";
62
62
  import {
63
63
  fetchJson,
@@ -1550,4 +1550,4 @@ async function stageBrandDisplayFace(outDir, compositionDir) {
1550
1550
  export {
1551
1551
  scaffoldAdCommand
1552
1552
  };
1553
- //# sourceMappingURL=scaffold-ad-3BSA7BWT.js.map
1553
+ //# sourceMappingURL=scaffold-ad-6YO574PA.js.map