@koda-sl/baker-cli 0.526.0 → 0.528.0

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 (101) hide show
  1. package/README.md +2 -0
  2. package/dist/{account-APMJVG2F.js → account-CQJFUII3.js} +3 -3
  3. package/dist/{account-APMJVG2F.js.map → account-CQJFUII3.js.map} +1 -1
  4. package/dist/{account-assets-TAUEBCY5.js → account-assets-IDVG4DGK.js} +12 -12
  5. package/dist/account-assets-IDVG4DGK.js.map +1 -0
  6. package/dist/{account-level-2MYDHOID.js → account-level-GK7M2MMQ.js} +14 -14
  7. package/dist/account-level-GK7M2MMQ.js.map +1 -0
  8. package/dist/{accounts-VIAQC3PA.js → accounts-KRW3JNCW.js} +2 -2
  9. package/dist/{activities-MJMAV3SI.js → activities-2RAJXP3J.js} +3 -3
  10. package/dist/{activities-MJMAV3SI.js.map → activities-2RAJXP3J.js.map} +1 -1
  11. package/dist/{ads-O4RL4JXD.js → ads-6ESCXPHK.js} +3 -3
  12. package/dist/{ads-NNKUR4HG.js → ads-JVBLNTBF.js} +20 -15
  13. package/dist/ads-JVBLNTBF.js.map +1 -0
  14. package/dist/{adsets-VO5C7PDM.js → adsets-FN5ZWSYF.js} +11 -11
  15. package/dist/adsets-FN5ZWSYF.js.map +1 -0
  16. package/dist/{asset-writes-PQNENVYY.js → asset-writes-SSI3CO2A.js} +4 -4
  17. package/dist/{audience-writes-QDDADCYE.js → audience-writes-G64754LR.js} +6 -6
  18. package/dist/audience-writes-G64754LR.js.map +1 -0
  19. package/dist/{audiences-TQ5ZEWIR.js → audiences-JAVNJ5NC.js} +8 -8
  20. package/dist/audiences-JAVNJ5NC.js.map +1 -0
  21. package/dist/{businesses-CW4RB36R.js → businesses-DXRDQIFP.js} +2 -2
  22. package/dist/{campaigns-IQYYYD2S.js → campaigns-GQWFSKGC.js} +11 -11
  23. package/dist/campaigns-GQWFSKGC.js.map +1 -0
  24. package/dist/{catalogs-PLBY32BE.js → catalogs-TBRONC2D.js} +15 -15
  25. package/dist/catalogs-TBRONC2D.js.map +1 -0
  26. package/dist/{chunk-OEJNZSJG.js → chunk-4XXA4WCS.js} +4 -4
  27. package/dist/chunk-4XXA4WCS.js.map +1 -0
  28. package/dist/{chunk-HPAGYPAF.js → chunk-BN4TDL5L.js} +65 -23
  29. package/dist/chunk-BN4TDL5L.js.map +1 -0
  30. package/dist/{chunk-5LN7GWRE.js → chunk-GEFZVG4P.js} +10 -10
  31. package/dist/chunk-GEFZVG4P.js.map +1 -0
  32. package/dist/{chunk-XB2FODWU.js → chunk-TKDOVFO6.js} +2 -2
  33. package/dist/cli.js +1 -1
  34. package/dist/{copy-writes-GZ744FHU.js → copy-writes-EUFEVWDW.js} +5 -5
  35. package/dist/{copy-writes-GZ744FHU.js.map → copy-writes-EUFEVWDW.js.map} +1 -1
  36. package/dist/{creatives-GTRQAZSB.js → creatives-6VJDUHEY.js} +6 -6
  37. package/dist/creatives-6VJDUHEY.js.map +1 -0
  38. package/dist/{custom-conversions-VQ3LBWYV.js → custom-conversions-NDY5RHSM.js} +6 -6
  39. package/dist/{custom-conversions-VQ3LBWYV.js.map → custom-conversions-NDY5RHSM.js.map} +1 -1
  40. package/dist/{draft-ME4TNPO7.js → draft-G432FJ7N.js} +2 -2
  41. package/dist/{insights-INIFHYR7.js → insights-IVW6W5CP.js} +2 -2
  42. package/dist/{instant-experiences-NMJUWNP3.js → instant-experiences-6F6GXZ67.js} +5 -5
  43. package/dist/{instant-experiences-NMJUWNP3.js.map → instant-experiences-6F6GXZ67.js.map} +1 -1
  44. package/dist/{leads-QBWR7FKT.js → leads-CJKRKB2Q.js} +6 -6
  45. package/dist/{leads-QBWR7FKT.js.map → leads-CJKRKB2Q.js.map} +1 -1
  46. package/dist/{media-23IW442U.js → media-HDHZULQ7.js} +3 -3
  47. package/dist/{meta-H3KBPU33.js → meta-MOSJVYIE.js} +38 -38
  48. package/dist/{page-photos-SHIGXDYE.js → page-photos-4JTIKXAW.js} +5 -5
  49. package/dist/page-photos-4JTIKXAW.js.map +1 -0
  50. package/dist/{pages-XJF3FBOJ.js → pages-BAUS7LQM.js} +2 -2
  51. package/dist/{performance-L3Q57H4H.js → performance-6XFKDJGY.js} +11 -2
  52. package/dist/performance-6XFKDJGY.js.map +1 -0
  53. package/dist/{pixels-AZCIWWXK.js → pixels-QOSEYXCP.js} +3 -3
  54. package/dist/pixels-QOSEYXCP.js.map +1 -0
  55. package/dist/{preview-BIEVHIDJ.js → preview-X6EJGPAY.js} +2 -2
  56. package/dist/{rule-writes-QLZNJ7CT.js → rule-writes-A4BFYHPA.js} +7 -7
  57. package/dist/rule-writes-A4BFYHPA.js.map +1 -0
  58. package/dist/{rules-FJHYG4SJ.js → rules-HLREXY2M.js} +11 -11
  59. package/dist/rules-HLREXY2M.js.map +1 -0
  60. package/dist/{shared-HY2VP7PT.js → shared-I3SB77VH.js} +2 -2
  61. package/dist/{studies-Z2ZIWLTO.js → studies-IGOCWM7F.js} +7 -7
  62. package/dist/{studies-Z2ZIWLTO.js.map → studies-IGOCWM7F.js.map} +1 -1
  63. package/dist/{study-writes-V7BXLTQG.js → study-writes-Z5P2W7JH.js} +6 -6
  64. package/dist/study-writes-Z5P2W7JH.js.map +1 -0
  65. package/dist/{targeting-YBIWD27C.js → targeting-7HXKBXWY.js} +12 -12
  66. package/dist/targeting-7HXKBXWY.js.map +1 -0
  67. package/dist/{write-commands-R5SN6CVQ.js → write-commands-CY734U34.js} +22 -22
  68. package/dist/write-commands-CY734U34.js.map +1 -0
  69. package/package.json +1 -1
  70. package/dist/account-assets-TAUEBCY5.js.map +0 -1
  71. package/dist/account-level-2MYDHOID.js.map +0 -1
  72. package/dist/ads-NNKUR4HG.js.map +0 -1
  73. package/dist/adsets-VO5C7PDM.js.map +0 -1
  74. package/dist/audience-writes-QDDADCYE.js.map +0 -1
  75. package/dist/audiences-TQ5ZEWIR.js.map +0 -1
  76. package/dist/campaigns-IQYYYD2S.js.map +0 -1
  77. package/dist/catalogs-PLBY32BE.js.map +0 -1
  78. package/dist/chunk-5LN7GWRE.js.map +0 -1
  79. package/dist/chunk-HPAGYPAF.js.map +0 -1
  80. package/dist/chunk-OEJNZSJG.js.map +0 -1
  81. package/dist/creatives-GTRQAZSB.js.map +0 -1
  82. package/dist/page-photos-SHIGXDYE.js.map +0 -1
  83. package/dist/performance-L3Q57H4H.js.map +0 -1
  84. package/dist/pixels-AZCIWWXK.js.map +0 -1
  85. package/dist/rule-writes-QLZNJ7CT.js.map +0 -1
  86. package/dist/rules-FJHYG4SJ.js.map +0 -1
  87. package/dist/study-writes-V7BXLTQG.js.map +0 -1
  88. package/dist/targeting-YBIWD27C.js.map +0 -1
  89. package/dist/write-commands-R5SN6CVQ.js.map +0 -1
  90. /package/dist/{accounts-VIAQC3PA.js.map → accounts-KRW3JNCW.js.map} +0 -0
  91. /package/dist/{ads-O4RL4JXD.js.map → ads-6ESCXPHK.js.map} +0 -0
  92. /package/dist/{asset-writes-PQNENVYY.js.map → asset-writes-SSI3CO2A.js.map} +0 -0
  93. /package/dist/{businesses-CW4RB36R.js.map → businesses-DXRDQIFP.js.map} +0 -0
  94. /package/dist/{chunk-XB2FODWU.js.map → chunk-TKDOVFO6.js.map} +0 -0
  95. /package/dist/{draft-ME4TNPO7.js.map → draft-G432FJ7N.js.map} +0 -0
  96. /package/dist/{insights-INIFHYR7.js.map → insights-IVW6W5CP.js.map} +0 -0
  97. /package/dist/{media-23IW442U.js.map → media-HDHZULQ7.js.map} +0 -0
  98. /package/dist/{meta-H3KBPU33.js.map → meta-MOSJVYIE.js.map} +0 -0
  99. /package/dist/{pages-XJF3FBOJ.js.map → pages-BAUS7LQM.js.map} +0 -0
  100. /package/dist/{preview-BIEVHIDJ.js.map → preview-X6EJGPAY.js.map} +0 -0
  101. /package/dist/{shared-HY2VP7PT.js.map → shared-I3SB77VH.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/ads/meta/write-commands.ts","../src/commands/ads/meta/creative-flags.ts"],"sourcesContent":["import { buildCustomConversionRule } from \"@baker/api/ads-meta\";\nimport { defineCommand } from \"citty\";\nimport { repeatedValues } from \"../../../lib/repeatedFlags.ts\";\nimport {\n carouselFlags,\n conversationAndAppCta,\n creativeEnhancementsFromFlags,\n welcomeMessageFromFlags,\n} from \"./creative-flags.ts\";\nimport {\n adSetDeliveryArgs,\n adSetDeliveryFromFlags,\n boostEditArgs,\n boostEditsFromFlags,\n budgetBoostArg,\n budgetBoostsFromFlags,\n clearArg,\n clearFromFlags,\n} from \"./delivery-flags.ts\";\nimport {\n bareAccountId,\n failWriteValidation,\n listFlag,\n loadJsonFileArg,\n mergePayload,\n numberFlag,\n parseDateFlag,\n parseMoneyFlag,\n refuseDeleteByUpdate,\n repeatedListFlag,\n requireTarget,\n stageOp,\n stageStatusChange,\n upper,\n} from \"./write-shared.ts\";\n\n/**\n * Staged Meta write subcommands. None of these touch the Meta Graph API — they\n * stage ops on this chat's draft; ops appear in the dashboard as pending Meta\n * changes and apply sequentially when the chat is published. Review with\n * `baker ads meta draft`, undo with `draft remove <ref>`.\n *\n * Full object graph: campaign → ad set → ad creative → ad, plus custom\n * audiences and media uploads. Chain creates with meta_temp_* refs.\n */\n\nconst STAGED_NOTE = \"Staged until publish — review with `baker ads meta draft`.\";\n\nconst accountArgs = {\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n} as const;\n\n// --- Campaigns ---\n\nfunction campaignPayloadFromFlags(args: Record<string, unknown>): Record<string, unknown> {\n return {\n name: args.name,\n objective: upper(args.objective),\n status: upper(args.status),\n special_ad_categories: listFlag(args[\"special-ad-categories\"])?.map((c) => c.toUpperCase()),\n special_ad_category_country: listFlag(args[\"special-ad-category-country\"])?.map((c) => c.toUpperCase()),\n buying_type: upper(args[\"buying-type\"]),\n bid_strategy: upper(args[\"bid-strategy\"]),\n dailyBudget: parseMoneyFlag(args[\"daily-budget\"], args.currency, \"--daily-budget\"),\n lifetimeBudget: parseMoneyFlag(args[\"lifetime-budget\"], args.currency, \"--lifetime-budget\"),\n spendCap: parseMoneyFlag(args[\"spend-cap\"], args.currency, \"--spend-cap\"),\n adSetBudgetSharing: args[\"adset-budget-sharing\"] === undefined ? undefined : Boolean(args[\"adset-budget-sharing\"]),\n start_time: parseDateFlag(args.start, \"--start\"),\n stop_time: parseDateFlag(args.stop, \"--stop\"),\n promoted_object: args[\"catalog-id\"] ? { product_catalog_id: String(args[\"catalog-id\"]) } : undefined,\n };\n}\n\nconst campaignBudgetArgs = {\n \"daily-budget\": { type: \"string\", description: \"Daily budget (Advantage campaign budget / CBO)\" },\n \"lifetime-budget\": { type: \"string\", description: \"Lifetime budget\" },\n \"spend-cap\": { type: \"string\", description: \"Campaign spend cap\" },\n currency: { type: \"string\", description: \"3-letter currency (defaults to the account currency)\" },\n \"bid-strategy\": {\n type: \"string\",\n description: \"LOWEST_COST_WITHOUT_CAP|LOWEST_COST_WITH_BID_CAP|COST_CAP|LOWEST_COST_WITH_MIN_ROAS\",\n },\n start: { type: \"string\", description: \"Start time (ISO date or epoch ms)\" },\n stop: { type: \"string\", description: \"Stop time\" },\n ...budgetBoostArg,\n} as const;\n\nexport const campaignsCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a new campaign. ${STAGED_NOTE}\nExample: baker ads meta campaigns create --name \"Q3 Prospecting\" --objective OUTCOME_LEADS --daily-budget 50\nAdvantage+ (Meta's own \"Advantage+ campaign\" state) is not a setting: it follows from a campaign budget here, Advantage+ audience (targeting_automation.advantage_audience 1) and automatic placements (no placement lists) on every ad set. Read it back with \\`baker ads meta campaigns --fields id,name,advantage_state_info\\`.\nBlack Friday boost: baker ads meta campaigns create --name \"BF\" --objective OUTCOME_SALES --daily-budget 50 --budget-boost 2027-11-27T00:00Z..2027-11-28T00:00Z=+100%`,\n },\n args: {\n ...accountArgs,\n name: { type: \"string\", description: \"Campaign name\" },\n objective: {\n type: \"string\",\n description:\n \"OUTCOME_TRAFFIC|OUTCOME_ENGAGEMENT|OUTCOME_LEADS|OUTCOME_SALES|OUTCOME_AWARENESS|OUTCOME_APP_PROMOTION\",\n },\n status: { type: \"string\", description: \"ACTIVE|PAUSED (default PAUSED)\" },\n \"special-ad-categories\": { type: \"string\", description: \"CSV: NONE|HOUSING|EMPLOYMENT|CREDIT|… (default NONE)\" },\n \"special-ad-category-country\": { type: \"string\", description: \"CSV of 2-letter country codes\" },\n \"buying-type\": { type: \"string\", description: \"AUCTION|RESERVED (default AUCTION)\" },\n \"adset-budget-sharing\": {\n type: \"boolean\",\n description:\n \"Let ad sets lend up to 20% of their budget to each other (off unless set; ignored with a campaign budget)\",\n },\n ...campaignBudgetArgs,\n \"catalog-id\": {\n type: \"string\",\n description:\n \"Advantage+ catalog ads: the product catalog the campaign sells from (OUTCOME_SALES) — from `baker ads meta catalogs`. Fixed at creation; each ad set then names one of its product sets with --product-set-id\",\n },\n file: { type: \"string\", description: \"JSON file with the full payload; flags override file keys\" },\n },\n run: async ({ args, rawArgs }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const payload = mergePayload(loadJsonFileArg(args.file), {\n ...campaignPayloadFromFlags(args as Record<string, unknown>),\n budgetSchedules: budgetBoostsFromFlags(args as Record<string, unknown>, rawArgs),\n });\n await stageOp({ kind: \"campaign.create\", accountId, payload });\n },\n});\n\nexport const campaignsUpdateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: `Stage changes to a campaign. ${STAGED_NOTE}\nPass a meta_temp_* ref to amend a campaign staged in this chat. Example: baker ads meta campaigns update 6123 --daily-budget 80\nBudget boosts on a live campaign need its daily budget restated in the same command (Meta reads it from the request): baker ads meta campaigns update 6123 --daily-budget 50 --budget-boost 2027-11-27T00:00Z..2027-11-28T00:00Z=+25\nA boost is ADDED to the ones the campaign has (Meta keeps them, even overlapping); take them all away with --clear boosts, or one at a time with --remove-boost / --move-boost (ids from \\`baker ads meta high-demand-periods --campaign-id 6123\\`): baker ads meta campaigns update 6123 --move-boost 1633135568548763=2027-11-27T06:00Z..2027-11-27T12:00Z`,\n },\n args: {\n id: { type: \"positional\", description: \"Campaign id or meta_temp_* ref\", required: true },\n ...accountArgs,\n name: { type: \"string\", description: \"New name\" },\n status: { type: \"string\", description: \"ACTIVE|PAUSED|ARCHIVED\" },\n ...campaignBudgetArgs,\n clear: { type: \"string\", description: \"boosts — take away every budget boost the campaign has now\" },\n ...boostEditArgs,\n file: { type: \"string\", description: \"JSON file with fields to change\" },\n },\n run: async ({ args, rawArgs }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const payload = mergePayload(loadJsonFileArg(args.file), {\n name: args.name,\n status: upper(args.status),\n budgetSchedules: budgetBoostsFromFlags(args as Record<string, unknown>, rawArgs),\n clear: clearOrFail(rawArgs, \"campaign\"),\n ...boostEditsFromFlags(args as Record<string, unknown>, rawArgs),\n bid_strategy: upper(args[\"bid-strategy\"]),\n dailyBudget: parseMoneyFlag(args[\"daily-budget\"], args.currency, \"--daily-budget\"),\n lifetimeBudget: parseMoneyFlag(args[\"lifetime-budget\"], args.currency, \"--lifetime-budget\"),\n spendCap: parseMoneyFlag(args[\"spend-cap\"], args.currency, \"--spend-cap\"),\n start_time: parseDateFlag(args.start, \"--start\"),\n stop_time: parseDateFlag(args.stop, \"--stop\"),\n });\n refuseDeleteByUpdate(payload, \"campaigns\");\n await stageOp({\n kind: \"campaign.update\",\n accountId,\n target: requireTarget(args as Record<string, unknown>, \"campaign\"),\n payload,\n });\n },\n});\n\n// --- Ad sets ---\n\nfunction clearOrFail(rawArgs: readonly string[] | undefined, entity: \"adSet\" | \"campaign\"): string[] | undefined {\n try {\n return clearFromFlags(rawArgs, entity);\n } catch (err) {\n failWriteValidation(err instanceof Error ? err.message : String(err));\n }\n}\n\nfunction adSetPayloadFromFlags(\n args: Record<string, unknown>,\n rawArgs: readonly string[] | undefined,\n file: Record<string, unknown>,\n): Record<string, unknown> {\n const promotedObject = args[\"promoted-object-file\"]\n ? loadJsonFileArg(args[\"promoted-object-file\"])\n : buildPromotedObject(args);\n return {\n ...adSetDeliveryFromFlags(args, rawArgs),\n budgetSchedules: budgetBoostsFromFlags(args, rawArgs),\n name: args.name,\n campaign_id: args.campaign,\n status: upper(args.status),\n optimization_goal: upper(args[\"optimization-goal\"]),\n billing_event: upper(args[\"billing-event\"]),\n destination_type: upper(args[\"destination-type\"]),\n dailyBudget: parseMoneyFlag(args[\"daily-budget\"], args.currency, \"--daily-budget\"),\n lifetimeBudget: parseMoneyFlag(args[\"lifetime-budget\"], args.currency, \"--lifetime-budget\"),\n bidAmount: parseMoneyFlag(args[\"bid-amount\"], args.currency, \"--bid-amount\"),\n bid_strategy: upper(args[\"bid-strategy\"]),\n start_time: parseDateFlag(args.start, \"--start\"),\n end_time: parseDateFlag(args.end, \"--end\"),\n targeting: targetingFromFlags(args, rawArgs, targetingOf(file)),\n rf_prediction_id: args.reservation,\n promoted_object: promotedObject && Object.keys(promotedObject).length > 0 ? promotedObject : undefined,\n };\n}\n\nfunction targetingOf(file: Record<string, unknown>): Record<string, unknown> | undefined {\n const targeting = file.targeting;\n return targeting && typeof targeting === \"object\" && !Array.isArray(targeting)\n ? (targeting as Record<string, unknown>)\n : undefined;\n}\n\n/**\n * The targeting file — or else the `--file` payload's own targeting — with the\n * brand-safety flags laid over it (`brandSafety.ts`), so a safety flag joins the\n * audience rather than replacing it with safety keys alone.\n */\nexport function targetingFromFlags(\n args: Record<string, unknown>,\n rawArgs: readonly string[] | undefined,\n fileTargeting?: Record<string, unknown>,\n): Record<string, unknown> | undefined {\n const file = args[\"targeting-file\"] ? loadJsonFileArg(args[\"targeting-file\"]) : undefined;\n const base = file ?? fileTargeting;\n const lists = repeatedValues(rawArgs, \"block-list\", args[\"block-list\"]);\n const filters = repeatedValues(rawArgs, \"content-filter\", args[\"content-filter\"]).map((value) => value.toUpperCase());\n const categories = repeatedValues(rawArgs, \"exclude-publisher-category\", args[\"exclude-publisher-category\"]).map(\n (value) => value.toLowerCase(),\n );\n const safety = {\n ...(lists.length > 0 ? { excluded_publisher_list_ids: lists } : {}),\n ...(filters.length > 0 ? { brand_safety_content_filter_levels: filters } : {}),\n ...(categories.length > 0 ? { excluded_publisher_categories: categories } : {}),\n };\n if (Object.keys(safety).length === 0) return file;\n return { ...(base ?? {}), ...safety };\n}\n\nfunction buildPromotedObject(args: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (args[\"page-id\"]) out.page_id = String(args[\"page-id\"]);\n if (args[\"pixel-id\"]) out.pixel_id = String(args[\"pixel-id\"]);\n if (args[\"custom-event-type\"]) out.custom_event_type = upper(args[\"custom-event-type\"]);\n if (args[\"custom-conversion-id\"]) out.custom_conversion_id = String(args[\"custom-conversion-id\"]);\n if (args[\"product-set-id\"]) out.product_set_id = String(args[\"product-set-id\"]);\n if (args[\"app-id\"]) out.application_id = String(args[\"app-id\"]);\n if (args[\"app-store-url\"]) out.object_store_url = String(args[\"app-store-url\"]);\n if (args[\"whatsapp-number\"]) out.whatsapp_phone_number = String(args[\"whatsapp-number\"]);\n return out;\n}\n\n// --- Custom conversions ---\n\n/**\n * The rule, from the flags that cover the conversion people actually create.\n *\n * `--url-contains` is the whole common case (\"count a Lead when somebody\n * reaches /gracias\") and produces the exact shape Events Manager writes.\n * `--rule-file` is the escape hatch for anything Meta's filter language can\n * express and these flags cannot. Requiring one and refusing both keeps a\n * half-specified conversion — which Meta accepts, and which then counts\n * everything or nothing — off the draft.\n */\nexport function customConversionRuleFromFlags(args: Record<string, unknown>): Record<string, unknown> {\n const urlContains = args[\"url-contains\"];\n const ruleFile = args[\"rule-file\"];\n if (urlContains && ruleFile) {\n failWriteValidation(\n \"pass either --url-contains or --rule-file, not both — they are two ways to say the same thing\",\n );\n }\n if (ruleFile) {\n return loadJsonFileArg(ruleFile);\n }\n if (!urlContains) {\n failWriteValidation(\n \"a custom conversion needs a rule — pass --url-contains '/thank-you' (the common case), or --rule-file with Meta's filter JSON\",\n );\n }\n return buildCustomConversionRule({\n event: args.event ? String(args.event) : undefined,\n urlContains: String(urlContains),\n });\n}\n\nexport const customConversionsCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a new Custom Conversion — a pixel event narrowed by a rule, which an ad set can then optimize toward. ${STAGED_NOTE}\nMeta caps an account at 100 and its delete only archives one, so a duplicate is permanent: check \\`baker ads meta custom-conversions\\` first.\nChain an ad set to it in the same chat with --custom-conversion-id meta_temp_*.\nExample: baker ads meta custom-conversions create --name \"Lead formulario\" --pixel-id 645971030024859 --custom-event-type LEAD --url-contains \"/gracias\"`,\n },\n args: {\n ...accountArgs,\n name: { type: \"string\", description: \"What the marketer will see in Events Manager and in reports\" },\n \"pixel-id\": { type: \"string\", description: \"The pixel it counts from — from `baker ads meta pixels`\" },\n \"custom-event-type\": {\n type: \"string\",\n description: \"Event category Meta files it under: LEAD|PURCHASE|COMPLETE_REGISTRATION|CONTACT|…\",\n },\n \"url-contains\": {\n type: \"string\",\n description: \"Count the event when the URL contains this, e.g. '/gracias'. The common case.\",\n },\n event: { type: \"string\", description: \"Pixel event the URL narrows (default PageView)\" },\n \"rule-file\": { type: \"string\", description: \"JSON file with Meta's raw filter, instead of --url-contains\" },\n description: { type: \"string\", description: \"Free-text note shown in Events Manager\" },\n value: { type: \"string\", description: \"Default value of one conversion, when the site sends no value\" },\n },\n run: async ({ args }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n await stageOp({\n kind: \"customConversion.create\",\n accountId,\n payload: {\n name: args.name,\n description: args.description,\n pixel_id: args[\"pixel-id\"] ? String(args[\"pixel-id\"]) : undefined,\n custom_event_type: upper(args[\"custom-event-type\"]),\n rule: customConversionRuleFromFlags(args as Record<string, unknown>),\n default_conversion_value: numberFlag(args.value, \"--value\"),\n },\n });\n },\n});\n\nconst adSetWriteArgs = {\n ...accountArgs,\n name: { type: \"string\", description: \"Ad set name\" },\n status: { type: \"string\", description: \"ACTIVE|PAUSED|ARCHIVED\" },\n \"optimization-goal\": { type: \"string\", description: \"LINK_CLICKS|OFFSITE_CONVERSIONS|REACH|LEAD_GENERATION|…\" },\n \"billing-event\": { type: \"string\", description: \"IMPRESSIONS|LINK_CLICKS|THRUPLAY|…\" },\n \"destination-type\": { type: \"string\", description: \"WEBSITE|APP|MESSENGER|ON_AD|WHATSAPP|…\" },\n \"daily-budget\": { type: \"string\", description: \"Daily budget (ABO; omit if the campaign uses CBO)\" },\n \"lifetime-budget\": { type: \"string\", description: \"Lifetime budget (needs --end)\" },\n \"bid-amount\": { type: \"string\", description: \"Bid amount (required for COST_CAP / bid-cap strategies)\" },\n \"bid-strategy\": {\n type: \"string\",\n description:\n \"LOWEST_COST_WITHOUT_CAP (auto-bid) | LOWEST_COST_WITH_BID_CAP | COST_CAP — needs --bid-amount | LOWEST_COST_WITH_MIN_ROAS — needs --min-roas. Omit and Baker sets auto-bid (or min-ROAS when --min-roas is given); never leave it to Meta, whose default is a bid cap that then fails without an amount.\",\n },\n ...adSetDeliveryArgs,\n currency: { type: \"string\", description: \"3-letter currency (defaults to the account currency)\" },\n start: { type: \"string\", description: \"Start time\" },\n end: { type: \"string\", description: \"End time\" },\n \"targeting-file\": {\n type: \"string\",\n description:\n \"JSON file with the full Meta targeting spec. Ids, never names: look them up with `baker ads meta targeting search|geo|locales` and size it with `targeting estimate`\",\n },\n \"block-list\": {\n type: \"string\",\n description:\n \"Repeatable. Keep the ad set off a publisher block list — an id from `baker ads meta block-lists` or a meta_temp_* ref. On update without --targeting-file, the rest of the live targeting is kept\",\n },\n \"content-filter\": {\n type: \"string\",\n description:\n \"Repeatable, one per family: FEED_|FACEBOOK_|AN_ + RELAXED|STANDARD|STRICT — how strict Meta's content filter next to the ad is (feeds, in-stream/Reels, Audience Network)\",\n },\n \"exclude-publisher-category\": {\n type: \"string\",\n description:\n \"Repeatable: dating|gambling (and, for Audience Network / in-stream, debated_social_issues|mature_audiences|tragedy_and_conflict)\",\n },\n reservation: {\n type: \"string\",\n description:\n \"Create only: a reach-and-frequency reservation this ad set is bought on (id or meta_temp_* from `reach-frequency reserve`); its campaign is --buying-type RESERVED and it takes no budget\",\n },\n \"promoted-object-file\": { type: \"string\", description: \"JSON file with the promoted_object\" },\n \"page-id\": {\n type: \"string\",\n description: \"promoted_object.page_id shortcut (required for LEAD_GENERATION / QUALITY_LEAD / PAGE_LIKES goals)\",\n },\n \"pixel-id\": { type: \"string\", description: \"promoted_object.pixel_id shortcut\" },\n \"custom-event-type\": { type: \"string\", description: \"promoted_object.custom_event_type (PURCHASE|LEAD|…)\" },\n \"custom-conversion-id\": {\n type: \"string\",\n description:\n \"Optimize toward a Custom Conversion — the id from `baker ads meta custom-conversions`. Use it instead of --pixel-id/--custom-event-type, not alongside: Baker reads the conversion off Meta and fills its pixel, event category and rule.\",\n },\n \"product-set-id\": {\n type: \"string\",\n description:\n \"Advantage+ catalog ads: the product set this ad set shows (promoted_object.product_set_id) — from `baker ads meta catalogs --catalog-id <id>`. With OFFSITE_CONVERSIONS pass --custom-event-type (PURCHASE, ADD_TO_CART…); no pixel needed\",\n },\n \"app-id\": {\n type: \"string\",\n description:\n \"App ads: the app to promote (promoted_object.application_id) — from `baker ads meta apps`; needs --app-store-url\",\n },\n \"app-store-url\": {\n type: \"string\",\n description: \"App ads: the app's App Store / Google Play page (promoted_object.object_store_url)\",\n },\n \"whatsapp-number\": {\n type: \"string\",\n description:\n \"Click-to-WhatsApp: the WhatsApp Business number connected to the Page (promoted_object.whatsapp_phone_number)\",\n },\n file: { type: \"string\", description: \"JSON file with the full payload; flags override\" },\n} as const;\n\nexport const adSetsCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a new ad set. ${STAGED_NOTE}\nChain to a campaign with --campaign (real id or meta_temp_* ref).\nLead-form goals (LEAD_GENERATION, QUALITY_LEAD) and PAGE_LIKES need --page-id (the Facebook Page the leads/likes belong to).\nConversion goals take EITHER --pixel-id + --custom-event-type (a standard event) OR --custom-conversion-id (the marketer's own conversion, from 'baker ads meta custom-conversions').\nExample: baker ads meta adsets create --campaign meta_temp_ab12 --name \"US 25-54\" --optimization-goal LINK_CLICKS --billing-event IMPRESSIONS --daily-budget 50 --targeting-file t.json\nDelivery controls: --min-roas (ROAS goal bidding), --frequency-cap 2/7 (REACH/THRUPLAY), --schedule \"Mon-Fri 09-18\" (dayparting, lifetime budget only), --pacing no_pacing (bid cap only), --daily-spend-cap/--daily-min-spend (an ad set's share of a campaign budget), --budget-boost (high-demand periods), --attribution 7d_click,1d_view, --dynamic-creative (create only).\nExample: baker ads meta adsets create --campaign 6123 --name \"Reach ES\" --optimization-goal REACH --billing-event IMPRESSIONS --lifetime-budget 300 --end 2027-02-01 --frequency-cap 2/7 --schedule \"Mon-Fri 09-18\" --targeting-file t.json`,\n },\n args: {\n campaign: { type: \"string\", description: \"Parent campaign id or meta_temp_* ref\" },\n ...adSetWriteArgs,\n \"budget-boost\": {\n type: \"string\",\n description:\n \"Raise this ad set's daily budget for a high-demand period, repeatable (on a live ad set, `adsets update --budget-boost` adds one beside those it has): START..END=+AMOUNT or START..END=+PERCENT% (max 800%), at least 3 hours, on quarter hours, all amounts or all percentages. Needs --daily-budget. Example: --budget-boost 2027-11-27T00:00Z..2027-11-28T00:00Z=+50%\",\n },\n \"dynamic-creative\": {\n type: \"boolean\",\n description:\n \"Make this a Dynamic Creative ad set: its ONE ad runs a creativeType dynamic creative (Meta mixes the images, videos and texts). Create-only — Meta fixes it for the ad set's life.\",\n },\n \"saved-audience\": {\n type: \"string\",\n description:\n \"Start from a saved audience's targeting (id from `baker ads meta audiences saved`) — copied into the ad set; instead of --targeting-file, and --block-list / --content-filter / --exclude-publisher-category join it\",\n },\n },\n run: async ({ args, rawArgs }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const file = loadJsonFileArg(args.file);\n const payload = mergePayload(file, adSetPayloadFromFlags(args as Record<string, unknown>, rawArgs, file));\n if (args[\"saved-audience\"]) {\n const { savedAudienceTargeting, targetingFromSavedAudience } = await import(\"./audience-writes.ts\");\n const saved = await savedAudienceTargeting(accountId, String(args[\"saved-audience\"]));\n const merged = targetingFromSavedAudience(saved, payload.targeting as Record<string, unknown> | undefined);\n if (\"refusal\" in merged) failWriteValidation(merged.refusal);\n payload.targeting = merged.targeting;\n }\n await stageOp({ kind: \"adSet.create\", accountId, payload });\n },\n});\n\nexport const adSetsUpdateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: `Stage changes to an ad set. ${STAGED_NOTE}\nSwitching --optimization-goal to a lead-form goal (LEAD_GENERATION, QUALITY_LEAD) or PAGE_LIKES needs --page-id in the same change.\nTake a control away with --clear: baker ads meta adsets update 6123 --clear daily-spend-cap,schedule\nBudget boosts on a live ad set with its own daily budget: add with --budget-boost, take one away with --remove-boost, re-time one with --move-boost (ids from \\`baker ads meta high-demand-periods --campaign-id <ad set id>\\`).\nExample: baker ads meta adsets update 6123 --daily-budget 80`,\n },\n args: {\n id: { type: \"positional\", description: \"Ad set id or meta_temp_* ref\", required: true },\n ...adSetWriteArgs,\n \"budget-boost\": {\n type: \"string\",\n description:\n \"Add a budget boost to this ad set (its own daily budget is raised for a high-demand period), repeatable: START..END=+AMOUNT or START..END=+PERCENT% (max 800%), at least 3 hours, on quarter hours. Sent to Meta's boost list for the ad set, so the budget need not be restated. Example: --budget-boost 2027-11-27T00:00Z..2027-11-28T00:00Z=+50%\",\n },\n ...boostEditArgs,\n ...clearArg,\n },\n run: async ({ args, rawArgs }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const file = loadJsonFileArg(args.file);\n const {\n campaign_id: _drop,\n billing_event: _be,\n ...payload\n } = adSetPayloadFromFlags(args as Record<string, unknown>, rawArgs, file);\n const merged = mergePayload(file, {\n ...payload,\n ...boostEditsFromFlags(args as Record<string, unknown>, rawArgs),\n clear: clearOrFail(rawArgs, \"adSet\"),\n });\n refuseDeleteByUpdate(merged, \"adsets\");\n await stageOp({\n kind: \"adSet.update\",\n accountId,\n target: requireTarget(args as Record<string, unknown>, \"ad set\"),\n payload: merged,\n });\n },\n});\n\n// --- Ad creatives ---\n\nfunction creativePayloadFromFlags(args: Record<string, unknown>, rawArgs: readonly string[]): Record<string, unknown> {\n const enhancements = creativeEnhancementsFromFlags(args, rawArgs);\n return {\n // Leave undefined when --type is omitted so a --file's creativeType survives\n // mergePayload (any defined flag overrides the file). Defaulted after merge.\n creativeType: args.type ? String(args.type) : undefined,\n name: args.name,\n page_id: args.page,\n instagram_user_id: args[\"instagram-user\"],\n message: args.message,\n link: args.link,\n headline: args.headline,\n description: args.description,\n caption: args.caption,\n call_to_action: creativeCta(args),\n welcome_message: welcomeMessageFromFlags(args, rawArgs),\n applink_treatment: args[\"applink-treatment\"],\n product_set_id: args[\"product-set-id\"],\n canvas_id: args[\"canvas-id\"],\n format: args.format,\n imageHash: args[\"image-hash\"],\n imageRef: args[\"image-ref\"],\n videoId: args[\"video-id\"],\n videoRef: args[\"video-ref\"],\n thumbnailHash: args[\"thumbnail-hash\"],\n thumbnailRef: args[\"thumbnail-ref\"],\n url_tags: args[\"url-tags\"],\n shop_destination: args[\"shop-destination\"],\n multi_advertiser: args[\"multi-advertiser\"],\n partner: partnerFromFlags(args),\n object_story_id: args[\"post-id\"],\n source_instagram_media_id: args[\"instagram-media-id\"],\n instagram_ad_code: args[\"ad-code\"],\n collection_thumbnails: collectionThumbnailsFromFlags(rawArgs, args[\"collection-thumbnail\"]),\n enhancements,\n ...carouselFlags(args),\n };\n}\n\n/** `--collection-thumbnail <element id>[:<product index>]`, repeatable — the four pictures under a collection's hero. */\nexport function collectionThumbnailsFromFlags(\n rawArgs: readonly string[] | undefined,\n parsed: unknown,\n): Array<{ element_id: string; element_child_index?: number }> | undefined {\n const values = repeatedValues(rawArgs, \"collection-thumbnail\", parsed);\n if (values.length === 0) return undefined;\n return values.map((value) => {\n const [elementId = \"\", index] = value.split(\":\");\n return index === undefined\n ? { element_id: elementId }\n : { element_id: elementId, element_child_index: Number(index) };\n });\n}\n\n/** A partnership ad's second identity, from `--partner-page` / `--partner-instagram` / `--partner-format`. */\nexport function partnerFromFlags(args: Record<string, unknown>): Record<string, unknown> | undefined {\n const partner = {\n facebook_page_id: args[\"partner-page\"],\n instagram_user_id: args[\"partner-instagram\"],\n ad_format: args[\"partner-format\"],\n };\n return Object.values(partner).some((value) => value !== undefined) ? partner : undefined;\n}\n\n/**\n * Only the call-to-action fields the caller actually named. `--lead-form` is the\n * only way to name an instant form: the ad set says leads are collected on the\n * ad but never WHICH form, so a creative without this makes Meta reject every ad\n * in that ad set.\n *\n * Partial on purpose. On `update` this becomes a patch over the creative already\n * staged, and a complete object here would silently undo the other half —\n * `--cta LEARN_MORE` would drop a form the creative already names (re-creating\n * the very publish failure this exists to stop), and `--lead-form <id>` would\n * rewrite an already-chosen button to SIGN_UP.\n */\nexport function ctaPatchFromFlags(args: Record<string, unknown>): Record<string, string> | undefined {\n const patch = {\n ...(args.cta ? { type: String(upper(args.cta)) } : {}),\n ...(args[\"lead-form\"] === undefined ? {} : { lead_gen_form_id: String(args[\"lead-form\"]) }),\n ...conversationAndAppCta(args),\n };\n return Object.keys(patch).length > 0 ? patch : undefined;\n}\n\n/**\n * The call-to-action for a NEW creative, where there is nothing to patch over.\n * Defaults the type to SIGN_UP when a form is named and no --cta is: an\n * instant-form ad has to have a button, and that is the one Meta suggests.\n */\nexport function creativeCta(args: Record<string, unknown>): Record<string, string> | undefined {\n const patch = ctaPatchFromFlags(args);\n if (!patch) return undefined;\n // An instant form's button defaults to SIGN_UP; a conversation's, to the one that opens it.\n const opener = Object.entries({\n MESSENGER: \"MESSAGE_PAGE\",\n WHATSAPP: \"WHATSAPP_MESSAGE\",\n INSTAGRAM_DIRECT: \"INSTAGRAM_MESSAGE\",\n }).find(([app]) => app === patch.app_destination)?.[1];\n return { type: opener ?? (patch.app_link || patch.application ? \"INSTALL_MOBILE_APP\" : \"SIGN_UP\"), ...patch };\n}\n\n/**\n * The content patch for `creatives update`, merged rather than assigned at both\n * levels. `mergePayload` and the backend's `mergeAmendPayload` are both shallow\n * top-level merges, so building a fresh `content` here would throw away every\n * other field a `--file` supplied — silently, which is the failure shape this\n * whole change is about.\n */\nexport function creativeContentPatch(file: Record<string, unknown>, args: Record<string, unknown>): unknown {\n const cta = ctaPatchFromFlags(args);\n if (!cta) {\n return undefined;\n }\n const fileContent = (file.content ?? {}) as Record<string, unknown>;\n const fileCta = (fileContent.call_to_action ?? {}) as Record<string, unknown>;\n return { ...fileContent, call_to_action: { ...fileCta, ...cta } };\n}\n\nexport const adCreativesCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a new ad creative. ${STAGED_NOTE}\nSingle-image/video via flags; carousel/dynamic via --file (creativeType carousel|dynamic).\nClick-to-message: --cta MESSAGE_PAGE|WHATSAPP_MESSAGE|INSTAGRAM_MESSAGE (opens Messenger|WhatsApp|Instagram Direct) + --greeting \"Hi!\" --ice-breaker \"Prices? => From 99 EUR.\" (ad set: --destination-type MESSENGER --optimization-goal CONVERSATIONS --page-id).\nApp ads: --link <App Store / Google Play URL> --cta INSTALL_MOBILE_APP|USE_MOBILE_APP --deep-link myapp://x --app-id <id> --applink-treatment deeplink_with_appstore_fallback.\nCatalog (Advantage+ catalog ads): --type catalog --product-set-id <id> --message \"{{product.name}}\" --headline \"{{product.price}}\" --link https://shop.example --format carousel|single|slideshow.\nInstant Experience / collection: --type instant_experience --canvas-id <id or meta_temp_*> --message … --image-hash … [--format collection] (build one with \\`baker ads meta instant-experiences create\\`).\nReference media by --image-hash (already on Meta) or --image-ref meta_temp_* (a staged media upload).\nExample: baker ads meta creatives create --page 555 --message \"Save now\" --link https://x.com --headline \"Best cover\" --image-hash abc123… --cta SHOP_NOW`,\n },\n args: {\n ...accountArgs,\n type: {\n type: \"string\",\n description: \"single|carousel|dynamic|existing_post|catalog|instant_experience (default single)\",\n },\n \"product-set-id\": {\n type: \"string\",\n description:\n \"--type catalog: the product set the template shows — from `baker ads meta catalogs --catalog-id <id>`\",\n },\n \"canvas-id\": {\n type: \"string\",\n description:\n \"--type instant_experience: the Instant Experience the ad opens — an id from `baker ads meta instant-experiences --page-id <id>` (published) or the meta_temp_* ref of one this chat creates\",\n },\n format: {\n type: \"string\",\n description:\n \"--type catalog: carousel (default) | single (one product per ad) | slideshow. --type instant_experience: standard (default) | collection (products or photos under the ad)\",\n },\n greeting: {\n type: \"string\",\n description: \"Click-to-message: the first message the person reads when the conversation opens (≤300 chars)\",\n },\n \"ice-breaker\": {\n type: \"string\",\n description:\n 'Click-to-message, repeatable (max 4): a question the person can tap and your answer — \"Question => Answer\"',\n },\n autofill: {\n type: \"string\",\n description: \"Click-to-message (instead of ice breakers): a message pre-filled for the person to send\",\n },\n \"app-destination\": {\n type: \"string\",\n description:\n \"Click-to-message: MESSENGER|WHATSAPP|INSTAGRAM_DIRECT — implied by --cta MESSAGE_PAGE|WHATSAPP_MESSAGE|INSTAGRAM_MESSAGE\",\n },\n \"deep-link\": {\n type: \"string\",\n description:\n \"App ads: where the button opens inside the installed app (e.g. myapp://product/12). --link must be the App Store / Google Play page\",\n },\n \"app-id\": {\n type: \"string\",\n description: \"App ads: the app the button installs or opens — from `baker ads meta apps`\",\n },\n \"applink-treatment\": {\n type: \"string\",\n description:\n \"App ads: how a deep link opens — deeplink_with_web_fallback|deeplink_with_appstore_fallback|web_only|automatic\",\n },\n name: { type: \"string\", description: \"Creative name\" },\n page: { type: \"string\", description: \"Facebook Page id (identity)\" },\n \"instagram-user\": {\n type: \"string\",\n description: \"Instagram account id for IG placements — from `baker ads meta instagram-accounts`\",\n },\n message: { type: \"string\", description: \"Primary text\" },\n link: { type: \"string\", description: \"Destination URL (https)\" },\n headline: { type: \"string\", description: \"Headline\" },\n description: { type: \"string\", description: \"Description\" },\n caption: { type: \"string\", description: \"Display URL / caption\" },\n cta: { type: \"string\", description: \"Call-to-action type (SHOP_NOW|LEARN_MORE|SIGN_UP|…)\" },\n \"lead-form\": {\n type: \"string\",\n description:\n \"Instant form id or meta_temp_* ref from `baker ads meta lead-forms create` — REQUIRED for an ad set that collects leads on the ad. With a form, --cta must be APPLY_NOW|DOWNLOAD|GET_QUOTE|LEARN_MORE|SIGN_UP|SUBSCRIBE\",\n },\n \"image-hash\": { type: \"string\", description: \"Meta ad-image hash (already uploaded)\" },\n \"image-ref\": { type: \"string\", description: \"meta_temp_* ref of a staged media upload\" },\n \"video-id\": { type: \"string\", description: \"Meta video id (already uploaded)\" },\n \"video-ref\": { type: \"string\", description: \"meta_temp_* ref of a staged video upload\" },\n \"thumbnail-hash\": {\n type: \"string\",\n description:\n \"Cover for a video ad: a picture hash already in the ad account (Meta's own frame is used when no cover is given)\",\n },\n \"thumbnail-ref\": {\n type: \"string\",\n description:\n \"Cover for a video ad: meta_temp_* ref of a staged `media upload --kind image` — how a cover picked from the library is used\",\n },\n \"url-tags\": { type: \"string\", description: \"URL tracking params (utm_source=fb&…)\" },\n \"shop-destination\": {\n type: \"string\",\n description:\n \"website_only keeps a shop advertiser's ad on the website (Meta's v26 default also sends it to the shop); website_and_shop asks for both\",\n },\n \"standard-enhancements\": {\n type: \"string\",\n description: \"Meta's suggestions to the ad's TEXT on|off — never changes the picture or video\",\n },\n \"multi-advertiser\": {\n type: \"string\",\n description:\n \"opt_out keeps the ad from being shown beside other advertisers' ads after someone engages (Meta opts every new ad IN by default); opt_in asks for it\",\n },\n \"partner-page\": {\n type: \"string\",\n description:\n \"Partnership ad: the partner's (creator's or other brand's) Facebook Page id, shown beside yours. Needs --instagram-user on the ad and the partner's approval before it runs\",\n },\n \"partner-instagram\": { type: \"string\", description: \"Partnership ad: the partner's Instagram account id\" },\n \"partner-format\": {\n type: \"string\",\n description: \"Partnership ad: both (default — both identities) | first_only | auto (Meta picks, Instagram only)\",\n },\n \"collection-thumbnail\": {\n type: \"string\",\n description:\n \"--format collection over a photo experience, repeat 4 times: an element id of the live experience (`instant-experiences --page-id`), or <product-set element id>:<product index>\",\n },\n \"post-id\": {\n type: \"string\",\n description:\n \"--type existing_post: the Facebook post to boost, <page_id>_<post_id> — from `baker ads meta page-posts --page-id <id>`\",\n },\n \"instagram-media-id\": {\n type: \"string\",\n description:\n \"--type existing_post: the Instagram post to boost (with --page and --instagram-user) — from `baker ads meta instagram-media`\",\n },\n \"ad-code\": {\n type: \"string\",\n description: \"--type existing_post: a creator's partnership ad code for their Instagram post (with --page)\",\n },\n \"card-order\": {\n type: \"string\",\n description:\n \"Carousel only: fixed (default — every card, in the order built) or optimized (Meta reorders by performance and may show only the top 5)\",\n },\n \"end-card\": {\n type: \"string\",\n description: \"Carousel only: on adds Meta's card linking to the Page after the last card (default off)\",\n },\n \"visual-enhancement\": {\n type: \"string\",\n description:\n \"Repeatable. Let Meta change the media with this feature (e.g. image_uncrop, image_animation, music_generation) — ONLY when the user asked for it by name; every such feature is off otherwise\",\n },\n file: { type: \"string\", description: \"JSON file with the full creative payload (carousel cards / dynamic assets)\" },\n },\n run: async ({ args, rawArgs }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const payload = mergePayload(\n loadJsonFileArg(args.file),\n creativePayloadFromFlags(args as Record<string, unknown>, rawArgs),\n );\n // Flag-only creatives default to a single-image ad; a --file that declares\n // its own creativeType (carousel/dynamic/existing_post) is left untouched.\n if (payload.creativeType === undefined) {\n payload.creativeType = \"single\";\n }\n await stageOp({ kind: \"adCreative.create\", accountId, payload });\n },\n});\n\nexport const adCreativesUpdateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: `Stage name/status changes to an ad creative. ${STAGED_NOTE}\nMeta creatives are immutable — to change content, stage a new creative and repoint the ad.\nAmending a staged (meta_temp_*) creative merges fields into the create. Example: baker ads meta creatives update 998 --name \"Renamed\"`,\n },\n args: {\n id: { type: \"positional\", description: \"Creative id or meta_temp_* ref\", required: true },\n ...accountArgs,\n name: { type: \"string\", description: \"New name\" },\n status: { type: \"string\", description: \"ACTIVE|PAUSED|ARCHIVED\" },\n cta: { type: \"string\", description: \"Call-to-action type (staged creatives only)\" },\n \"lead-form\": {\n type: \"string\",\n description: \"Instant form id the button opens (staged creatives only) — `baker ads meta lead-forms` lists them\",\n },\n file: {\n type: \"string\",\n description: \"JSON file with fields to change (content only merges into a staged creative)\",\n },\n },\n run: async ({ args }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const file = loadJsonFileArg(args.file);\n const payload = mergePayload(file, {\n name: args.name,\n status: upper(args.status),\n // A creative's content is immutable on Meta, so this only ever lands on a\n // creative still staged in this chat — which is exactly the fix path when\n // staging an ad refuses it for naming no instant form.\n content: creativeContentPatch(file, args as Record<string, unknown>),\n });\n if (payload.status === \"DELETED\") {\n failWriteValidation(\n \"update does not delete — use `baker ads meta creatives delete <id>` if the user asked to delete it\",\n );\n }\n await stageOp({\n kind: \"adCreative.update\",\n accountId,\n target: requireTarget(args as Record<string, unknown>, \"creative\"),\n payload,\n });\n },\n});\n\n// --- Ads ---\n\nexport const adsCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a new ad linking an ad set to a creative. ${STAGED_NOTE}\nExample: baker ads meta ads create --name \"Ad 1\" --adset meta_temp_as01 --creative meta_temp_cr01`,\n },\n args: {\n ...accountArgs,\n name: { type: \"string\", description: \"Ad name\" },\n adset: { type: \"string\", description: \"Ad set id or meta_temp_* ref\" },\n creative: { type: \"string\", description: \"Creative id or meta_temp_* ref\" },\n status: { type: \"string\", description: \"ACTIVE|PAUSED (default PAUSED)\" },\n \"tracking-file\": { type: \"string\", description: \"JSON file with tracking_specs\" },\n \"conversion-domain\": {\n type: \"string\",\n description:\n \"The website domain conversions are counted on (example.com — no www., no https://). Meta fills it from the link when left out; set it when the site and the pixel's domain differ\",\n },\n file: { type: \"string\", description: \"JSON file with the full payload\" },\n },\n run: async ({ args }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const tracking = args[\"tracking-file\"] ? loadJsonFileArg(args[\"tracking-file\"]).tracking_specs : undefined;\n const payload = mergePayload(loadJsonFileArg(args.file), {\n name: args.name,\n adset_id: args.adset,\n creative: args.creative ? { creative_id: String(args.creative) } : undefined,\n status: upper(args.status),\n tracking_specs: tracking,\n conversion_domain: args[\"conversion-domain\"],\n });\n await stageOp({ kind: \"ad.create\", accountId, payload });\n },\n});\n\nexport const adsUpdateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: `Stage changes to an ad (name/status, or swap its creative). ${STAGED_NOTE}\nExample: baker ads meta ads update 6123 --creative meta_temp_cr02`,\n },\n args: {\n id: { type: \"positional\", description: \"Ad id or meta_temp_* ref\", required: true },\n ...accountArgs,\n name: { type: \"string\", description: \"New name\" },\n status: { type: \"string\", description: \"ACTIVE|PAUSED|ARCHIVED\" },\n creative: { type: \"string\", description: \"New creative id or meta_temp_* ref\" },\n file: { type: \"string\", description: \"JSON file with fields to change\" },\n },\n run: async ({ args }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const payload = mergePayload(loadJsonFileArg(args.file), {\n name: args.name,\n status: upper(args.status),\n creative: args.creative ? { creative_id: String(args.creative) } : undefined,\n });\n refuseDeleteByUpdate(payload, \"ads\");\n await stageOp({\n kind: \"ad.update\",\n accountId,\n target: requireTarget(args as Record<string, unknown>, \"ad\"),\n payload,\n });\n },\n});\n\nexport const adsRetagCommand = defineCommand({\n meta: {\n name: \"retag\",\n description: `Stage new URL tracking parameters on a LIVE ad — the fix for a wrong utm_medium, a missing ad id, or any tag already running. ${STAGED_NOTE}\nStart here when a report attributes paid traffic to the wrong channel: --set rewrites only the keys you name and leaves the rest of the string alone.\nBaker clones the ad's own creative behind the scenes, so every button, text variant and enhancement is carried across exactly as Meta holds them — nothing is retyped.\nExample: baker ads meta ads retag 120252158038400247 --set \"utm_medium=paid-social&utm_placement={{placement}}\"\nExample: baker ads meta ads retag 120252158038400247 --url-tags \"utm_source={{site_source_name}}&utm_medium=paid-social&ad_id={{ad.id}}\"`,\n },\n args: {\n id: { type: \"positional\", description: \"Ad id (a live ad — not a meta_temp_* ref)\", required: true },\n ...accountArgs,\n \"url-tags\": { type: \"string\", description: \"Replace the WHOLE tracking string\" },\n set: {\n type: \"string\",\n description:\n 'Rewrite only these keys, keeping the rest: \"utm_medium=paid-social&ad_id={{ad.id}}\" (repeatable: --set a=1 --set b=2)',\n },\n },\n run: async ({ args, rawArgs }) => {\n const { apiPost } = await import(\"../../../client.ts\");\n const { requireChatId } = await import(\"../../../env.ts\");\n const { writeJsonEnvelope } = await import(\"../output.ts\");\n const { handleMetaError } = await import(\"./shared.ts\");\n try {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const urlTags = typeof args[\"url-tags\"] === \"string\" ? args[\"url-tags\"] : undefined;\n const setRaw = typeof args.set === \"string\" ? args.set : undefined;\n if ((urlTags === undefined) === (setRaw === undefined)) {\n failWriteValidation(\"pass either --url-tags (the whole string) or --set (the keys to change), not both\");\n }\n const response = await apiPost(\"/api/ads/meta/draft/retag\", {\n chatId: requireChatId(),\n accountId,\n adId: requireTarget(args as Record<string, unknown>, \"ad\"),\n urlTags,\n set: setRaw === undefined ? undefined : retagSetPairs(rawArgs, setRaw),\n });\n writeJsonEnvelope(response as Record<string, unknown>);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\n/**\n * Every `--set`, whether joined by `&` or given as the flag repeated. citty keeps\n * only a repeated flag's last value, and a retag that silently loses all but one\n * key still publishes — so the command line is read directly.\n */\nexport function retagSetPairs(rawArgs: readonly string[] | undefined, parsed: unknown): Record<string, string> {\n return parseSetPairs(repeatedValues(rawArgs, \"set\", parsed).join(\"&\"));\n}\n\nfunction parseSetPairs(raw: string): Record<string, string> {\n const pairs: Record<string, string> = {};\n for (const part of raw.replace(/^[?&]+/, \"\").split(\"&\")) {\n if (part.length === 0) continue;\n const eq = part.indexOf(\"=\");\n if (eq <= 0) {\n failWriteValidation(`--set expects key=value pairs joined by & — could not read \"${part}\"`);\n }\n pairs[part.slice(0, eq)] = part.slice(eq + 1);\n }\n if (Object.keys(pairs).length === 0) {\n failWriteValidation(\"--set needs at least one key=value pair\");\n }\n return pairs;\n}\n\n// --- Custom audiences ---\n\nexport const audiencesCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a new custom audience. ${STAGED_NOTE}\nInline customer list: --subtype CUSTOM --file with \"members\": [{\"email\",\"phone\",\"country\"}] (up to 2,000 people, hashed before storage, uploaded after creation at Publish).\nCustomer list: --subtype CUSTOM --customer-file-source USER_PROVIDED_ONLY, then put people in it with \\`audiences members add <ref> --file list.csv\\` (hashed on this machine). --value-based for a list where each person carries a value (needs the account's value-based terms).\nLookalike: --subtype LOOKALIKE --lookalike-of <seed audience> --ratio 0.02 --country ES (or --countries ES,PT; --starting-ratio 0.01 for the 1%–2% band). The seed needs 100+ people in those countries. Or seed it from the people who converted in live campaigns: --lookalike-of-conversions <campaign or ad set id,…>.\nWEBSITE/ENGAGEMENT: the rule via --file. A rule carries its own window in retention_seconds, so --retention-days is refused next to one, and one audience covers one kind of event source (a Page and an Instagram profile are two audiences).\nExample: baker ads meta audiences create --name \"Site visitors 30d\" --subtype WEBSITE --file rule.json\nExample: baker ads meta audiences create --name \"Customers\" --subtype CUSTOM --customer-file-source USER_PROVIDED_ONLY`,\n },\n args: {\n ...accountArgs,\n name: { type: \"string\", description: \"Audience name\" },\n subtype: { type: \"string\", description: \"CUSTOM|WEBSITE|ENGAGEMENT|LOOKALIKE\" },\n description: { type: \"string\", description: \"Description\" },\n \"retention-days\": {\n type: \"string\",\n description: \"Retention window in days — customer-file audiences only; a rule carries its own retention_seconds\",\n },\n \"customer-file-source\": {\n type: \"string\",\n description:\n \"Customer list: where its people came from — USER_PROVIDED_ONLY (collected from customers directly) | PARTNER_PROVIDED_ONLY | BOTH_USER_AND_PARTNER_PROVIDED\",\n },\n \"value-based\": {\n type: \"boolean\",\n description: \"Customer list where each person carries a value (LOOKALIKE_VALUE column)\",\n },\n \"lookalike-of\": {\n type: \"string\",\n description: \"Lookalike: the seed audience id (a live audience — one this chat creates cannot be a seed yet)\",\n },\n \"lookalike-of-conversions\": {\n type: \"string\",\n description:\n \"Lookalike seeded from the people who converted in live campaigns or ad sets (ids, comma-separated or repeated) instead of an audience. Meta wants 100+ conversions in the lookalike's countries.\",\n },\n ratio: { type: \"string\", description: \"Lookalike size: 0.01–0.20 of the country, in 0.01 steps\" },\n \"starting-ratio\": {\n type: \"string\",\n description: \"Lookalike band start, below --ratio (0.01 with --ratio 0.03 = the 1%–3% band)\",\n },\n country: { type: \"string\", description: \"Lookalike: one country (ES)\" },\n countries: { type: \"string\", description: \"Lookalike: several countries (ES,PT — comma-separated or repeated)\" },\n \"allow-international-seeds\": {\n type: \"boolean\",\n description: \"Lookalike: let Meta use seed people from other countries when the seed is thin in these\",\n },\n file: {\n type: \"string\",\n description: \"JSON (a path, or inline) with lookalike_spec / rule / members / full payload\",\n },\n },\n run: async ({ args, rawArgs }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const file = loadJsonFileArg(args.file);\n const payload = mergePayload(file, {\n name: args.name,\n subtype: upper(args.subtype),\n description: args.description,\n retention_days: numberFlag(args[\"retention-days\"], \"--retention-days\"),\n customer_file_source: upper(args[\"customer-file-source\"]),\n is_value_based: args[\"value-based\"] ? true : undefined,\n lookalike_spec: lookalikeSpecFromFlags(args as Record<string, unknown>, file.lookalike_spec, rawArgs),\n });\n await stageOp({ kind: \"customAudience.create\", accountId, payload });\n },\n});\n\n/** The lookalike flags folded over a spec from --file; undefined when neither names one. */\nexport function lookalikeSpecFromFlags(\n args: Record<string, unknown>,\n fromFile: unknown,\n rawArgs?: readonly string[],\n): Record<string, unknown> | undefined {\n const base = fromFile && typeof fromFile === \"object\" ? (fromFile as Record<string, unknown>) : {};\n const flags = {\n origin: typeof args[\"lookalike-of\"] === \"string\" ? [{ id: args[\"lookalike-of\"] }] : undefined,\n conversions_of: repeatedListFlag(rawArgs, \"lookalike-of-conversions\", args[\"lookalike-of-conversions\"]),\n ratio: numberFlag(args.ratio, \"--ratio\"),\n starting_ratio: numberFlag(args[\"starting-ratio\"], \"--starting-ratio\"),\n country: typeof args.country === \"string\" ? args.country.toUpperCase() : undefined,\n countries: repeatedListFlag(rawArgs, \"countries\", args.countries)?.map((code) => code.toUpperCase()),\n allow_international_seeds: args[\"allow-international-seeds\"] ? true : undefined,\n };\n const merged = mergePayload(base, flags);\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\nexport const audiencesUpdateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: `Stage changes to a custom audience: name, description, where a customer list came from, its opt-out link, or a website/engagement rule (--file {\"rule\": …}). A customer list's retention and a lookalike's seed and size are fixed — a different one is a new audience. Delete with \\`audiences delete\\`. ${STAGED_NOTE}`,\n },\n args: {\n id: { type: \"positional\", description: \"Audience id or meta_temp_* ref\", required: true },\n ...accountArgs,\n name: { type: \"string\", description: \"New name\" },\n description: { type: \"string\", description: \"New description\" },\n \"customer-file-source\": {\n type: \"string\",\n description: \"USER_PROVIDED_ONLY | PARTNER_PROVIDED_ONLY | BOTH_USER_AND_PARTNER_PROVIDED\",\n },\n \"opt-out-link\": { type: \"string\", description: \"https link where people can opt out of this audience\" },\n file: { type: \"string\", description: \"JSON file with fields to change (rule for a website/engagement audience)\" },\n },\n run: async ({ args }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const payload = mergePayload(loadJsonFileArg(args.file), {\n name: args.name,\n description: args.description,\n customer_file_source: upper(args[\"customer-file-source\"]),\n opt_out_link: args[\"opt-out-link\"],\n });\n if (payload.status === \"DELETED\") {\n failWriteValidation(\n \"update does not delete — use `baker ads meta audiences delete <id>` if the user asked to delete it\",\n );\n }\n await stageOp({\n kind: \"customAudience.update\",\n accountId,\n target: requireTarget(args as Record<string, unknown>, \"audience\"),\n payload,\n });\n },\n});\n\n// --- Media upload ---\n\nexport const mediaUploadCommand = defineCommand({\n meta: {\n name: \"upload\",\n description: `Stage a Baker library image/video upload to Meta. Publishes the hash/id a creative references by --image-ref/--video-ref. ${STAGED_NOTE}\nExample: baker ads meta media upload --kind image --image-id <bakerImageId>`,\n },\n args: {\n ...accountArgs,\n kind: { type: \"string\", description: \"image|video\" },\n \"image-id\": { type: \"string\", description: \"Baker library image id (for --kind image)\" },\n \"video-id\": { type: \"string\", description: \"Baker library video id (for --kind video)\" },\n name: { type: \"string\", description: \"Display name / filename hint\" },\n },\n run: async ({ args }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const kind = String(args.kind ?? \"\").toLowerCase();\n if (kind !== \"image\" && kind !== \"video\") {\n failWriteValidation(\"--kind must be image or video\");\n }\n await stageOp({\n kind: \"media.upload\",\n accountId,\n payload: { kind, bakerImageId: args[\"image-id\"], bakerVideoId: args[\"video-id\"], name: args.name },\n });\n },\n});\n\n// --- Status-change + duplicate factories ---\n\ntype StatusKind = \"campaign.update\" | \"adSet.update\" | \"ad.update\";\n\nconst STATUS_BY_COMMAND = { pause: \"PAUSED\", resume: \"ACTIVE\", archive: \"ARCHIVED\", delete: \"DELETED\" } as const;\n\nconst STATUS_COMMAND_NOTE: Partial<Record<keyof typeof STATUS_BY_COMMAND, string>> = {\n archive: \"Archived stays readable in Ads Manager and can be found with --effective-status ARCHIVED.\",\n delete:\n \"Deleting is permanent and cannot be undone — Meta removes it and everything under it. Prefer pause or archive unless the user asked to delete.\",\n};\n\nfunction statusCommand(name: keyof typeof STATUS_BY_COMMAND, kind: StatusKind, label: string) {\n const status = STATUS_BY_COMMAND[name];\n const note = STATUS_COMMAND_NOTE[name];\n return defineCommand({\n meta: { name, description: `Stage ${name} for a ${label}. ${note ? `${note} ` : \"\"}${STAGED_NOTE}` },\n args: { id: { type: \"positional\", description: `${label} id`, required: true }, ...accountArgs },\n run: async ({ args }) => {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n await stageStatusChange({\n kind,\n accountId,\n target: requireTarget(args as Record<string, unknown>, label),\n status,\n });\n },\n });\n}\n\nfunction duplicateCommand(entity: \"campaign\" | \"adSet\" | \"ad\", label: string) {\n return defineCommand({\n meta: {\n name: \"duplicate\",\n description: `Stage a paused copy of an existing ${label} (reconstructed from its live snapshot). ${STAGED_NOTE}\n--replace also stages a pause of the original, gated on the copy publishing.`,\n },\n args: {\n id: { type: \"positional\", description: `Source ${label} id`, required: true },\n ...accountArgs,\n name: { type: \"string\", description: \"Override the copy's name\" },\n replace: { type: \"boolean\", description: \"Pause the original once the copy publishes\" },\n },\n run: async ({ args }) => {\n const { apiPost } = await import(\"../../../client.ts\");\n const { requireChatId } = await import(\"../../../env.ts\");\n const { writeJsonEnvelope } = await import(\"../output.ts\");\n const { handleMetaError } = await import(\"./shared.ts\");\n try {\n const accountId = await bareAccountId(args as Record<string, unknown>);\n const chatId = requireChatId();\n const response = await apiPost(\"/api/ads/meta/draft/duplicate\", {\n chatId,\n accountId,\n entity,\n sourceId: requireTarget(args as Record<string, unknown>, label),\n overrides: args.name ? { name: args.name } : undefined,\n replace: Boolean(args.replace),\n });\n writeJsonEnvelope(response as Record<string, unknown>);\n } catch (err) {\n handleMetaError(err);\n }\n },\n });\n}\n\nexport const campaignsPauseCommand = statusCommand(\"pause\", \"campaign.update\", \"campaign\");\nexport const campaignsResumeCommand = statusCommand(\"resume\", \"campaign.update\", \"campaign\");\nexport const campaignsArchiveCommand = statusCommand(\"archive\", \"campaign.update\", \"campaign\");\nexport const campaignsDeleteCommand = statusCommand(\"delete\", \"campaign.update\", \"campaign\");\nexport const campaignsDuplicateCommand = duplicateCommand(\"campaign\", \"campaign\");\n\nexport const adSetsPauseCommand = statusCommand(\"pause\", \"adSet.update\", \"ad set\");\nexport const adSetsResumeCommand = statusCommand(\"resume\", \"adSet.update\", \"ad set\");\nexport const adSetsArchiveCommand = statusCommand(\"archive\", \"adSet.update\", \"ad set\");\nexport const adSetsDeleteCommand = statusCommand(\"delete\", \"adSet.update\", \"ad set\");\nexport const adSetsDuplicateCommand = duplicateCommand(\"adSet\", \"ad set\");\n\nexport const adsPauseCommand = statusCommand(\"pause\", \"ad.update\", \"ad\");\nexport const adsResumeCommand = statusCommand(\"resume\", \"ad.update\", \"ad\");\nexport const adsArchiveCommand = statusCommand(\"archive\", \"ad.update\", \"ad\");\nexport const adsDeleteCommand = statusCommand(\"delete\", \"ad.update\", \"ad\");\nexport const adsDuplicateCommand = duplicateCommand(\"ad\", \"ad\");\n","import { VISUAL_ENHANCEMENT_FEATURES } from \"@baker/api/ads-meta/limits\";\nimport { repeatedValues } from \"../../../lib/repeatedFlags.ts\";\nimport { failWriteValidation } from \"./write-shared.ts\";\n\ntype Args = Record<string, unknown>;\n\nfunction parseEnroll(value: unknown): \"OPT_IN\" | \"OPT_OUT\" {\n const raw = String(value).toLowerCase();\n if (raw === \"on\" || raw === \"true\" || raw === \"opt_in\") return \"OPT_IN\";\n if (raw === \"off\" || raw === \"false\" || raw === \"opt_out\") return \"OPT_OUT\";\n failWriteValidation(\"--standard-enhancements must be on|off\");\n}\n\n/**\n * The creative's Advantage+ enhancements from its flags. `--standard-enhancements`\n * is Meta's suggestions to the text; every feature that changes the picture or\n * video stays off unless named with `--visual-enhancement <feature>`.\n */\nexport function creativeEnhancementsFromFlags(\n args: Args,\n rawArgs: readonly string[] | undefined,\n): { standardEnhancements?: \"OPT_IN\" | \"OPT_OUT\"; features?: Record<string, \"OPT_IN\"> } | undefined {\n const visual = repeatedValues(rawArgs, \"visual-enhancement\", args[\"visual-enhancement\"]);\n const unknown = visual.filter((feature) => !(feature in VISUAL_ENHANCEMENT_FEATURES));\n if (unknown.length > 0) {\n failWriteValidation(\n `--visual-enhancement ${unknown.join(\", \")} is not a feature that changes the media — one of ${Object.keys(VISUAL_ENHANCEMENT_FEATURES).join(\", \")}`,\n );\n }\n const standard = args[\"standard-enhancements\"] !== undefined ? parseEnroll(args[\"standard-enhancements\"]) : undefined;\n if (!standard && visual.length === 0) return undefined;\n return {\n ...(standard ? { standardEnhancements: standard } : {}),\n ...(visual.length > 0\n ? { features: Object.fromEntries(visual.map((feature) => [feature, \"OPT_IN\" as const])) }\n : {}),\n };\n}\n\n/** A carousel's card order and end card — Meta's `multi_share_optimized` / `multi_share_end_card`. */\nexport function carouselFlags(args: Args): { card_order?: string; end_card?: boolean } {\n const order = args[\"card-order\"];\n if (order !== undefined && order !== \"fixed\" && order !== \"optimized\") {\n failWriteValidation(\"--card-order must be fixed (the order you built) or optimized (Meta reorders)\");\n }\n const endCard = args[\"end-card\"];\n return {\n ...(order !== undefined ? { card_order: String(order) } : {}),\n ...(endCard !== undefined ? { end_card: parseEnroll(endCard) === \"OPT_IN\" } : {}),\n };\n}\n\n/**\n * A click-to-message greeting from `--greeting`, every `--ice-breaker\n * \"Question => Answer\"` (repeatable) and `--autofill`.\n */\nexport function welcomeMessageFromFlags(\n args: Args,\n rawArgs: readonly string[] | undefined,\n): { greeting?: string; iceBreakers?: { question: string; answer: string }[]; autofill?: string } | undefined {\n const breakers = repeatedValues(rawArgs, \"ice-breaker\", args[\"ice-breaker\"]).map((entry) => {\n const [question, ...rest] = entry.split(\"=>\");\n const answer = rest.join(\"=>\").trim();\n if (!question?.trim() || !answer) {\n failWriteValidation(`--ice-breaker takes \"Question => Answer\" — got \"${entry}\"`);\n }\n return { question: question.trim(), answer };\n });\n if (args.greeting === undefined && breakers.length === 0 && args.autofill === undefined) return undefined;\n return {\n ...(args.greeting !== undefined ? { greeting: String(args.greeting) } : {}),\n ...(breakers.length > 0 ? { iceBreakers: breakers } : {}),\n ...(args.autofill !== undefined ? { autofill: String(args.autofill) } : {}),\n };\n}\n\n/** The app each messaging button opens (Meta's click-to-* guides). */\nconst BUTTON_OPENS: Record<string, string> = {\n MESSAGE_PAGE: \"MESSENGER\",\n WHATSAPP_MESSAGE: \"WHATSAPP\",\n INSTAGRAM_MESSAGE: \"INSTAGRAM_DIRECT\",\n};\n\n/**\n * The button fields of a click-to-message or app ad: which app a conversation\n * opens in (`--app-destination`, implied by a messaging `--cta`), the deep link\n * (`--deep-link`) and the app (`--app-id`).\n */\nexport function conversationAndAppCta(args: Args): Record<string, string> {\n const cta = args.cta === undefined ? undefined : String(args.cta).toUpperCase();\n const destination =\n args[\"app-destination\"] !== undefined\n ? String(args[\"app-destination\"]).toUpperCase()\n : cta\n ? BUTTON_OPENS[cta]\n : undefined;\n return {\n ...(destination ? { app_destination: destination } : {}),\n ...(args[\"deep-link\"] !== undefined ? { app_link: String(args[\"deep-link\"]) } : {}),\n ...(args[\"app-id\"] !== undefined ? { application: String(args[\"app-id\"]) } : {}),\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koda-sl/baker-cli",
3
- "version": "0.526.0",
3
+ "version": "0.528.0",
4
4
  "description": "AI-agent-first CLI for interacting with Baker, including the Baker creative canvas.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/ads/meta/account-assets.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { writeAdsOutput, writeJsonEnvelope } from \"../output.ts\";\nimport { csvOrJson, handleMetaError, resolveAccountIdArg } from \"./shared.ts\";\n\n/**\n * The account's identities and libraries an ad is built from — reads that used\n * to exist only as backend routes. They were left off the CLI as \"rarely\n * needed in isolation\", but each answers a question staging otherwise answers\n * with a refusal: which Instagram account an ad can run as, which apps it can\n * promote, whom an EU ad names, what an image hash or label id is, which\n * product sets a catalog ad can use, what an A/B test found.\n */\n\ntype Row = Record<string, unknown>;\ntype Args = Record<string, unknown>;\n\nfunction emit(rows: Row[], args: Args, hints: string[]): void {\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(rows, fmt, undefined, hints);\n return;\n }\n writeJsonEnvelope(hints.length > 0 ? { ok: true, data: rows, hints } : { ok: true, data: rows });\n}\n\nasync function read<T>(path: string, params: Record<string, string>, args: Args): Promise<T> {\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n return await apiGet<T>(path, params);\n}\n\nconst outputArg = { type: \"string\", description: \"json|csv|jsonl|md\", default: \"json\" } as const;\nconst accountArg = { type: \"string\", description: \"Meta ad account ID (act_...)\" } as const;\nconst schemaAccount = { type: \"string\", description: \"Meta ad account ID (act_123)\", required: false };\nconst schemaNoCache = { type: \"boolean\", description: \"Bypass the cache\", required: false };\nconst schemaOutput = { type: \"string\", description: \"json|csv|jsonl|md\", required: false, default: \"json\" };\n\n// --- Instagram identities ---\n\nexport interface MetaInstagramIdentity {\n id: string;\n username?: string;\n sources: Array<\"ad_account\" | \"connected\" | \"page\" | \"page_backed\">;\n pageId?: string;\n pageName?: string;\n}\n\nexport function instagramIdentityHints(rows: readonly MetaInstagramIdentity[]): string[] {\n if (rows.length === 0) {\n return [\n \"No Instagram account is linked to this ad account or its Pages. A creative without --instagram-user cannot run in Instagram feeds, Stories or Reels — the account owner links one in Meta Business settings (Accounts → Instagram accounts) and assigns it to the ad account.\",\n ];\n }\n const listed = rows.filter((row) => row.sources.includes(\"ad_account\") || row.sources.includes(\"connected\"));\n const hints = [\"Pass the id as `creatives create --instagram-user <id>`.\"];\n if (listed.length > 0 && listed.length < rows.length) {\n hints.push(\n `Use one listed on the ad account (${listed.map((row) => row.username ?? row.id).join(\", \")}): when the account lists any, staging refuses an identity it does not list.`,\n );\n } else if (listed.length === 0) {\n hints.push(\n \"Only Page identities are listed (page = the Page's linked Instagram account, page_backed = an Instagram presence Meta made for a Page with none). Meta accepts either as --instagram-user; a page_backed one shows the Page's name and picture on Instagram.\",\n );\n }\n if (new Set(rows.map((row) => row.pageId).filter(Boolean)).size > 1) {\n hints.push(\"Several Pages are involved — use the identity of the Page the creative runs from (--page).\");\n }\n return hints;\n}\n\nregisterSchema({\n command: \"ads.meta.instagram-accounts\",\n description:\n \"The Instagram accounts an ad on this account can run as — the id `creatives create --instagram-user` takes. Lists accounts assigned or connected to the ad account and each promotable Page's linked or page-backed one.\",\n args: {\n \"account-id\": schemaAccount,\n \"no-cache\": schemaNoCache,\n output: { type: \"string\", description: \"json|csv\", required: false, default: \"json\" },\n },\n});\n\nexport const instagramAccountsCommand = defineCommand({\n meta: {\n name: \"instagram-accounts\",\n description:\n \"Instagram identities an ad can run as (the --instagram-user id). Start here before creatives create: baker ads meta instagram-accounts --account-id act_123\",\n },\n args: { \"account-id\": accountArg, \"no-cache\": NO_CACHE_ARG, output: outputArg },\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const rows = await read<MetaInstagramIdentity[]>(\n \"/api/ads/meta/instagram-accounts\",\n { \"account-id\": accountId },\n args,\n );\n emit(\n rows.map((row) => ({ ...row, sources: row.sources.join(\",\") })),\n args,\n instagramIdentityHints(rows),\n );\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\n// --- Apps ---\n\nregisterSchema({\n command: \"ads.meta.apps\",\n description:\n \"The apps this ad account can promote (app installs / app engagement), with their store URLs — the application_id and object_store_url an app ad set's promoted_object takes.\",\n args: { \"account-id\": schemaAccount, \"no-cache\": schemaNoCache, output: schemaOutput },\n});\n\nexport const appsCommand = defineCommand({\n meta: {\n name: \"apps\",\n description:\n \"Apps the ad account can promote, for an app ad set's promoted_object. Example: baker ads meta apps --account-id act_123\",\n },\n args: { \"account-id\": accountArg, \"no-cache\": NO_CACHE_ARG, output: outputArg },\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const rows = await read<Array<{ id: string; name?: string; object_store_urls?: Record<string, string> }>>(\n \"/api/ads/meta/apps\",\n { \"account-id\": accountId },\n args,\n );\n emit(\n rows.map((row) => ({ ...row })),\n args,\n rows.length > 0\n ? [\n 'An app ad set promotes one: promoted_object {\"application_id\":\"<id>\",\"object_store_url\":\"<store url>\"}. Use a real store URL (itunes / google_play); fb_canvas and instant_game are not app stores.',\n ]\n : [\n \"No promotable apps. The app has to be registered in Meta for Developers and its owner has to add this ad account under the app's Advanced settings → Advertising accounts.\",\n ],\n );\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\n// --- DSA ---\n\nregisterSchema({\n command: \"ads.meta.dsa-recommendations\",\n description:\n \"Names Meta suggests for the EU Digital Services Act disclosure (who benefits from and who pays for an ad) on this account.\",\n args: { \"account-id\": schemaAccount, \"no-cache\": schemaNoCache },\n});\n\nexport const dsaRecommendationsCommand = defineCommand({\n meta: {\n name: \"dsa-recommendations\",\n description:\n \"Meta's suggested DSA beneficiary/payor names for EU ad sets. Example: baker ads meta dsa-recommendations --account-id act_123\",\n },\n args: { \"account-id\": accountArg, \"no-cache\": NO_CACHE_ARG },\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const names = await read<string[]>(\"/api/ads/meta/dsa-recommendations\", { \"account-id\": accountId }, args);\n writeJsonEnvelope({\n ok: true,\n data: names,\n hints: [\n \"An ad set reaching the EU needs dsa_beneficiary and dsa_payor. When they are missing Baker fills both from the ad account's saved EU advertiser and payer, else the first of these, else the business name; pass one of these instead when the user names someone else (an agency paying for a client).\",\n ],\n });\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\n// --- Images and labels ---\n\nfunction compactImage(row: Row): Row {\n return {\n hash: row.hash,\n name: row.name,\n width: row.width,\n height: row.height,\n status: row.status,\n created_time: row.created_time,\n };\n}\n\nregisterSchema({\n command: \"ads.meta.images\",\n description:\n \"The ad account's image library — each image_hash a creative can reuse without uploading again. --hash looks one up.\",\n args: {\n \"account-id\": schemaAccount,\n hash: { type: \"string\", description: \"One image hash\", required: false },\n limit: { type: \"string\", description: \"Max rows (default 500)\", required: false },\n full: { type: \"boolean\", description: \"URLs, permalink and which creatives use it\", required: false },\n \"no-cache\": schemaNoCache,\n output: schemaOutput,\n },\n});\n\nexport const imagesCommand = defineCommand({\n meta: {\n name: \"images\",\n description:\n \"Image library of the ad account (image hashes). Example: baker ads meta images --account-id act_123 --limit 20; --hash <hash> for one\",\n },\n args: {\n \"account-id\": accountArg,\n hash: { type: \"string\", description: \"Look up one image hash\" },\n limit: { type: \"string\", description: \"Max rows (default 500)\" },\n full: { type: \"boolean\", description: \"Every field: url, permalink_url, creatives\" },\n \"no-cache\": NO_CACHE_ARG,\n output: outputArg,\n },\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n const params: Record<string, string> = { \"account-id\": accountId };\n if (args.hash) params.hash = args.hash as string;\n if (args.limit) params.limit = args.limit as string;\n try {\n const rows = await read<Row[]>(\"/api/ads/meta/images\", params, args);\n emit(args.full ? rows : rows.map(compactImage), args, [\n \"A creative reuses one with its hash (the `image_hash` of a creative file). To push a Baker-library image, stage `media upload` instead.\",\n ]);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.labels\",\n description: \"Ad labels defined on the account (Meta's tags for campaigns, ad sets, ads and creatives).\",\n args: { \"account-id\": schemaAccount, \"no-cache\": schemaNoCache, output: schemaOutput },\n});\n\nconst labelsListArgs = { \"account-id\": accountArg, \"no-cache\": NO_CACHE_ARG, output: outputArg };\n\nexport const labelsCommand = defineCommand({\n meta: {\n name: \"labels\",\n description: `Ad labels on the account (list), or stage label writes: create, rename, delete, attach (file campaigns/ad sets/ads/creatives under one), detach.\n baker ads meta labels --account-id act_123\n baker ads meta labels create --name \"Q4 launch\"\n baker ads meta labels attach <labelId|meta_temp_…> --campaigns 6123,6124 --ads 6125`,\n },\n subCommands: {\n list: () => labelsListCommand,\n create: () => import(\"./asset-writes.ts\").then((m) => m.labelsCreateCommand),\n rename: () => import(\"./asset-writes.ts\").then((m) => m.labelsRenameCommand),\n delete: () => import(\"./asset-writes.ts\").then((m) => m.labelsDeleteCommand),\n attach: () => import(\"./asset-writes.ts\").then((m) => m.labelsAttachCommand),\n detach: () => import(\"./asset-writes.ts\").then((m) => m.labelsDetachCommand),\n },\n args: labelsListArgs,\n default: \"list\",\n});\n\nconst labelsListCommand = defineCommand({\n meta: {\n name: \"list\",\n description: \"Ad labels on the account. Runs by default. Example: baker ads meta labels --account-id act_123\",\n },\n args: labelsListArgs,\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const rows = await read<Row[]>(\"/api/ads/meta/labels\", { \"account-id\": accountId }, args);\n emit(rows, args, rows.length === 0 ? [\"This account has no ad labels.\"] : []);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\n// --- High-demand periods ---\n\nregisterSchema({\n command: \"ads.meta.high-demand-periods\",\n description: \"The budget boosts (high-demand periods) set on a campaign or ad set: when each runs and by how much.\",\n args: {\n \"campaign-id\": { type: \"string\", description: \"Campaign or ad set ID\", required: true },\n \"no-cache\": schemaNoCache,\n output: schemaOutput,\n },\n});\n\nexport const highDemandPeriodsCommand = defineCommand({\n meta: {\n name: \"high-demand-periods\",\n description:\n \"Budget boosts on a campaign or ad set. Example: baker ads meta high-demand-periods --campaign-id 6123 (stage new ones with --budget-boost on campaigns or adsets create|update)\",\n },\n args: {\n \"campaign-id\": { type: \"string\", description: \"Campaign (or ad set) ID\", required: true },\n \"no-cache\": NO_CACHE_ARG,\n output: outputArg,\n },\n run: async ({ args }) => {\n try {\n const rows = await read<Row[]>(\n \"/api/ads/meta/high-demand-periods\",\n { \"campaign-id\": args[\"campaign-id\"] as string },\n args,\n );\n emit(rows, args, rows.length === 0 ? [\"No budget boosts on this campaign.\"] : []);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/ads/meta/account-level.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { apiGet, apiPost } from \"../../../client.ts\";\nimport { repeatedValues } from \"../../../lib/repeatedFlags.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { writeJsonEnvelope } from \"../output.ts\";\nimport { dayPartingFromFlags } from \"./delivery-flags.ts\";\nimport { handleMetaError } from \"./shared.ts\";\nimport {\n bareAccountId,\n failWriteValidation,\n loadJsonFileArg,\n numberFlag,\n requireTarget,\n stageOp,\n} from \"./write-shared.ts\";\n\n/**\n * What belongs to the ad account itself rather than to a campaign: its own\n * settings (name, account spending limit), its publisher block lists, and its\n * reach-and-frequency quotes and reservations — plus the posts an ad can boost\n * and the comments on an ad's post. Changes stage on this chat's draft and are\n * made at publish; reads are live.\n */\n\ntype Row = Record<string, unknown>;\ntype Args = Record<string, unknown>;\n\nconst STAGED_NOTE = \"Staged until publish — review with `baker ads meta draft`.\";\nconst schemaAccount = { type: \"string\", description: \"Numeric account ID or act_N\", required: false };\n\nfunction emit(data: unknown, hints: string[] = []): void {\n writeJsonEnvelope(hints.length > 0 ? { ok: true, data, hints } : { ok: true, data });\n}\n\nasync function readEdge(params: Record<string, string>): Promise<Row[]> {\n return await apiGet<Row[]>(\"/api/ads/meta/account-edges\", params);\n}\n\n// --- Account settings ---\n\nregisterSchema({\n command: \"ads.meta.account-settings\",\n description:\n \"Stage a change to the ad account's own settings: its name or its account spending limit (set, remove, or count again from zero). Made at publish.\",\n args: {\n \"account-id\": schemaAccount,\n name: { type: \"string\", description: \"New account name\", required: false },\n \"spending-limit\": {\n type: \"string\",\n description: \"Account spending limit, major units (e.g. 5000)\",\n required: false,\n },\n \"remove-spending-limit\": { type: \"boolean\", description: \"Remove the spending limit\", required: false },\n \"reset-spending-limit\": { type: \"boolean\", description: \"Count toward the limit again from zero\", required: false },\n \"default-eu-advertiser\": {\n type: \"string\",\n description: \"Default EU (DSA) advertiser — who the ads are for — for new ad sets; pass with --default-eu-payer\",\n required: false,\n },\n \"default-eu-payer\": {\n type: \"string\",\n description: \"Default EU (DSA) payer for new ad sets; pass with --default-eu-advertiser\",\n required: false,\n },\n \"clear-default-eu\": {\n type: \"boolean\",\n description: \"Clear both the default EU advertiser and payer\",\n required: false,\n },\n },\n});\n\nexport const accountSettingsCommand = defineCommand({\n meta: {\n name: \"account-settings\",\n description: `Change the ad account's own settings — its name or its account spending limit. ${STAGED_NOTE}\nThe limit counts spend from the moment it is set (Meta starts the count again), and every campaign on the account stops when it is reached. Ask the user before touching it — it is account-wide.\nStart here: baker ads meta account --account-id act_123 (shows spend_cap and amount_spent, in minor units)\nExample: baker ads meta account-settings --account-id act_123 --spending-limit 5000\n baker ads meta account-settings --account-id act_123 --remove-spending-limit\nThe EU (DSA) advertiser and payer new ad sets start with — both together, names from \\`baker ads meta dsa-recommendations\\` confirmed with the user:\n baker ads meta account-settings --account-id act_123 --default-eu-advertiser \"Acme SL\" --default-eu-payer \"Acme SL\"`,\n },\n args: {\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N — the account itself\" },\n name: { type: \"string\", description: \"New account name\" },\n \"spending-limit\": { type: \"string\", description: \"Account spending limit in the account currency, e.g. 5000\" },\n \"remove-spending-limit\": { type: \"boolean\", description: \"Take the account spending limit away\" },\n \"reset-spending-limit\": { type: \"boolean\", description: \"Keep the limit and count spend toward it from zero\" },\n \"default-eu-advertiser\": {\n type: \"string\",\n description: \"Default EU (DSA) advertiser for new ad sets — with --default-eu-payer (Meta keeps both or neither)\",\n },\n \"default-eu-payer\": { type: \"string\", description: \"Default EU (DSA) payer for new ad sets\" },\n \"clear-default-eu\": { type: \"boolean\", description: \"Clear both the default EU advertiser and payer\" },\n },\n run: async ({ args }) => {\n const accountId = bareAccountId(args as Args);\n if (args[\"remove-spending-limit\"] && args[\"reset-spending-limit\"]) {\n failWriteValidation(\"pass --remove-spending-limit OR --reset-spending-limit\");\n }\n const action = args[\"remove-spending-limit\"] ? \"remove\" : args[\"reset-spending-limit\"] ? \"reset\" : undefined;\n await stageOp({\n kind: \"adAccount.update\",\n accountId,\n target: accountId,\n payload: {\n name: args.name,\n spendCap: args[\"spending-limit\"] ? { amount: String(args[\"spending-limit\"]) } : undefined,\n spendCapAction: action,\n defaultDsaBeneficiary: args[\"default-eu-advertiser\"],\n defaultDsaPayor: args[\"default-eu-payer\"],\n clearDefaultDsa: args[\"clear-default-eu\"] ? true : undefined,\n },\n });\n },\n});\n\n// --- Block lists ---\n\nregisterSchema({\n command: \"ads.meta.block-lists\",\n description:\n \"The ad account's publisher block lists — websites and apps its ads stay off (Audience Network, in-stream). --full lists each list's sites.\",\n args: {\n \"account-id\": schemaAccount,\n full: { type: \"boolean\", description: \"Include each list's sites and apps\", required: false },\n },\n});\n\nconst blockListsListCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"Block lists on the ad account. Runs by default. Example: baker ads meta block-lists --account-id act_123 --full\",\n },\n args: {\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n full: { type: \"boolean\", description: \"Include each list's sites and apps\" },\n },\n run: async ({ args }) => {\n try {\n const params: Record<string, string> = { edge: \"block-lists\", \"account-id\": bareAccountId(args as Args) };\n if (args.full) params.full = \"true\";\n const rows = await readEdge(params);\n emit(rows, [\n \"Keep an ad set off a list with `adsets create|update --block-list <id>` (repeatable); add sites with `block-lists add <id> --url …`. Meta takes no site off a list and renames none — make a new list instead.\",\n ]);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.block-lists.create\",\n description: \"Stage a new publisher block list on the ad account, with its sites and apps. Made at publish.\",\n args: {\n \"account-id\": schemaAccount,\n name: { type: \"string\", description: \"List name\", required: true },\n url: { type: \"string\", description: \"A site (example.com) or app store address — repeatable\", required: false },\n file: { type: \"string\", description: 'JSON file {\"urls\": [...]} for long lists', required: false },\n },\n});\n\nfunction urlsFrom(args: Args, rawArgs: readonly string[]): string[] {\n const file = loadJsonFileArg(args.file);\n const fromFile = Array.isArray(file.urls) ? file.urls.filter((u): u is string => typeof u === \"string\") : [];\n const urls = [...repeatedValues(rawArgs, \"url\", args.url), ...fromFile];\n if (urls.length === 0) failWriteValidation('pass --url (repeatable) or --file with {\"urls\": [...]}');\n return urls;\n}\n\nconst blockListsCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Create a publisher block list. ${STAGED_NOTE}\nExample: baker ads meta block-lists create --account-id act_123 --name \"No gambling sites\" --url casino.example --url bets.example\nThen keep ad sets off it: baker ads meta adsets update <id> --block-list meta_temp_…`,\n },\n args: {\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n name: { type: \"string\", description: \"List name\", required: true },\n url: { type: \"string\", description: \"A site (example.com) or app store address — repeatable\" },\n file: { type: \"string\", description: 'JSON file {\"urls\": [...]} for a long list (up to 10,000)' },\n },\n run: async ({ args, rawArgs }) => {\n await stageOp({\n kind: \"publisherBlockList.create\",\n accountId: bareAccountId(args as Args),\n payload: { name: args.name, urls: urlsFrom(args as Args, rawArgs) },\n });\n },\n});\n\nregisterSchema({\n command: \"ads.meta.block-lists.add\",\n description: \"Stage adding sites and apps to a block list. Meta takes none off a list.\",\n args: {\n id: { type: \"positional\", description: \"Block list id\", required: true },\n \"account-id\": schemaAccount,\n url: { type: \"string\", description: \"A site or app store address — repeatable\", required: false },\n file: { type: \"string\", description: 'JSON file {\"urls\": [...]}', required: false },\n },\n});\n\nconst blockListsAddCommand = defineCommand({\n meta: {\n name: \"add\",\n description: `Add sites and apps to a block list. ${STAGED_NOTE}\nExample: baker ads meta block-lists add 120249500506120208 --account-id act_123 --url spam.example`,\n },\n args: {\n id: { type: \"positional\", description: \"Block list id\", required: true },\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n url: { type: \"string\", description: \"A site or app store address — repeatable\" },\n file: { type: \"string\", description: 'JSON file {\"urls\": [...]}' },\n },\n run: async ({ args, rawArgs }) => {\n await stageOp({\n kind: \"publisherBlockList.update\",\n accountId: bareAccountId(args as Args),\n target: requireTarget(args as Args, \"block list\"),\n payload: { addUrls: urlsFrom(args as Args, rawArgs) },\n });\n },\n});\n\nregisterSchema({\n command: \"ads.meta.block-lists.delete\",\n description: \"Stage deleting a block list. Ad sets that used it can show on its sites again.\",\n args: { id: { type: \"positional\", description: \"Block list id\", required: true }, \"account-id\": schemaAccount },\n});\n\nconst blockListsDeleteCommand = defineCommand({\n meta: {\n name: \"delete\",\n description: `Delete a block list — ad sets that used it can show on its sites and apps again. ${STAGED_NOTE}\nExample: baker ads meta block-lists delete 120249500506120208 --account-id act_123`,\n },\n args: {\n id: { type: \"positional\", description: \"Block list id\", required: true },\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n },\n run: async ({ args }) => {\n await stageOp({\n kind: \"publisherBlockList.update\",\n accountId: bareAccountId(args as Args),\n target: requireTarget(args as Args, \"block list\"),\n payload: { status: \"DELETED\" },\n });\n },\n});\n\nexport const blockListsCommand = defineCommand({\n meta: {\n name: \"block-lists\",\n description: `Publisher block lists — websites and apps the ad account's ads stay off (Audience Network, in-stream).\n baker ads meta block-lists --account-id act_123 [--full]\n baker ads meta block-lists create --name … --url … | add <id> --url … | delete <id>\nAn ad set uses a list with \\`adsets create|update --block-list <id>\\`; \\`--content-filter FEED_STRICT\\` and \\`--exclude-publisher-category gambling\\` set the rest of its brand safety.`,\n },\n subCommands: {\n list: blockListsListCommand,\n create: blockListsCreateCommand,\n add: blockListsAddCommand,\n delete: blockListsDeleteCommand,\n },\n args: {\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n full: { type: \"boolean\", description: \"Include each list's sites and apps\" },\n },\n default: \"list\",\n});\n\n// --- Reach and frequency ---\n\nregisterSchema({\n command: \"ads.meta.reach-frequency\",\n description:\n \"The ad account's reach-and-frequency quotes and reservations: reach, budget, dates, frequency cap, whether reserved and until when.\",\n args: { \"account-id\": schemaAccount },\n});\n\nconst reachFrequencyListCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"Reach-and-frequency quotes on the ad account (reservation_status 1 = reserved, until expiration_time). Runs by default. Example: baker ads meta reach-frequency --account-id act_123\",\n },\n args: { \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" } },\n run: async ({ args }) => {\n try {\n const rows = await readEdge({ edge: \"reach-frequency\", \"account-id\": bareAccountId(args as Args) });\n emit(rows, [\n \"Budgets here are in the account currency's minor units (cents). Reserve a quote with `reach-frequency reserve <id>`; a reserved campaign is `campaigns create --buying-type RESERVED` and its ad set `adsets create --reservation <reservation id>`.\",\n ]);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.reach-frequency.predict\",\n description:\n \"Ask Meta for a reach-and-frequency quote: how many people a budget reaches (or what a reach costs) over fixed dates in one country, at a frequency cap. A forecast — holds nothing and spends nothing.\",\n args: {\n \"account-id\": schemaAccount,\n \"page-id\": { type: \"string\", description: \"Facebook Page the ads run as\", required: true },\n budget: { type: \"string\", description: \"Lifetime budget, major units (solves for reach)\", required: false },\n reach: { type: \"string\", description: \"People to reach (solves for budget)\", required: false },\n start: { type: \"string\", description: \"Start, ISO date-time\", required: true },\n end: { type: \"string\", description: \"End, ISO date-time\", required: true },\n \"frequency-cap\": {\n type: \"string\",\n description: \"Most times one person sees it per --frequency-days\",\n required: false,\n },\n \"frequency-days\": { type: \"string\", description: \"Days the cap counts over (default 7)\", required: false },\n objective: { type: \"string\", description: \"REACH (default) | BRAND_AWARENESS | VIDEO_VIEWS | …\", required: false },\n \"optimization-goal\": { type: \"string\", description: \"Optional optimization goal\", required: false },\n \"instagram-user\": { type: \"string\", description: \"Instagram account the ads run as\", required: false },\n \"targeting-file\": { type: \"string\", description: \"Targeting JSON — ONE country\", required: true },\n schedule: { type: \"string\", description: 'Hours to run in, repeatable: \"Mon-Fri 09-18\"', required: false },\n \"target-frequency\": {\n type: \"string\",\n description: \"Balanced frequency: views per person per --target-frequency-days (OUTCOME_AWARENESS + REACH)\",\n required: false,\n },\n \"target-frequency-days\": {\n type: \"string\",\n description: \"Days the target counts over (default 7)\",\n required: false,\n },\n \"instream-package\": {\n type: \"string\",\n description: \"In-stream video packages, repeatable: NORMAL | PREMIUM | SPORTS | …\",\n required: false,\n },\n },\n});\n\nfunction unixSeconds(value: unknown, flag: string): number {\n const ms = typeof value === \"string\" ? Date.parse(value) : Number.NaN;\n if (!Number.isFinite(ms)) failWriteValidation(`${flag} takes an ISO date-time, e.g. 2026-11-01T00:00:00Z`);\n return Math.floor(ms / 1000);\n}\n\nconst reachFrequencyPredictCommand = defineCommand({\n meta: {\n name: \"predict\",\n description: `Ask Meta what a reach-and-frequency buy would reach (or cost). A forecast: nothing is held or spent, and the quote expires on its own.\nStart here: baker ads meta account --account-id act_123 (the account needs CAN_USE_REACH_AND_FREQUENCY; Meta's floor is about 200,000 people per country)\nExample: baker ads meta reach-frequency predict --account-id act_123 --page-id 904238019441800 --budget 1000 --start 2026-11-01T00:00:00Z --end 2026-11-08T00:00:00Z --frequency-cap 2 --targeting-file t.json`,\n },\n args: {\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n \"page-id\": { type: \"string\", description: \"Facebook Page the ads run as — from `baker ads meta pages`\" },\n \"instagram-user\": { type: \"string\", description: \"Instagram account the ads run as\" },\n budget: { type: \"string\", description: \"Lifetime budget in the account currency (solves for reach)\" },\n reach: { type: \"string\", description: \"People to reach (solves for budget)\" },\n start: { type: \"string\", description: \"Start, ISO date-time\" },\n end: { type: \"string\", description: \"End, ISO date-time (at most 90 days after the start)\" },\n \"frequency-cap\": { type: \"string\", description: \"Most times one person sees the ads per --frequency-days\" },\n \"frequency-days\": { type: \"string\", description: \"Days the cap counts over (default 7)\" },\n objective: {\n type: \"string\",\n description:\n \"REACH (default) | BRAND_AWARENESS | VIDEO_VIEWS | POST_ENGAGEMENT | LINK_CLICKS | OUTCOME_AWARENESS | OUTCOME_ENGAGEMENT\",\n },\n \"optimization-goal\": { type: \"string\", description: \"Optional optimization goal\" },\n \"targeting-file\": { type: \"string\", description: \"Targeting JSON (as for adsets create) — ONE country\" },\n schedule: {\n type: \"string\",\n description:\n 'Run only in these hours, repeatable: \"<days> <from>-<to>\", e.g. \"Mon-Fri 09-18\". Live, Meta stored day-parted quotes but answered status 18 (no reach) for them',\n },\n \"target-frequency\": {\n type: \"string\",\n description:\n \"Balanced frequency: aim each person at this many views per --target-frequency-days (default 7) instead of a cap — needs --objective OUTCOME_AWARENESS and --optimization-goal REACH\",\n },\n \"target-frequency-days\": { type: \"string\", description: \"Days the target frequency counts over (default 7)\" },\n \"instream-package\": {\n type: \"string\",\n description:\n \"In-stream video packages the ads may run in, repeatable: NORMAL | PREMIUM | SPORTS | ENTERTAINMENT | …\",\n },\n },\n run: async ({ args, rawArgs }) => {\n if (!args[\"targeting-file\"]) failWriteValidation(\"pass --targeting-file (one country)\");\n const reach = numberFlag(args.reach, \"--reach\");\n const instreamPackages = repeatedValues(rawArgs, \"instream-package\", args[\"instream-package\"])\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim().toUpperCase())\n .filter(Boolean);\n const body = {\n accountId: bareAccountId(args as Args),\n solveFor: reach !== undefined ? \"budget\" : \"reach\",\n budget: args.budget,\n reach,\n start_time: unixSeconds(args.start, \"--start\"),\n end_time: unixSeconds(args.end, \"--end\"),\n frequencyCap: numberFlag(args[\"frequency-cap\"], \"--frequency-cap\"),\n frequencyCapDays: numberFlag(args[\"frequency-days\"], \"--frequency-days\"),\n objective: args.objective,\n optimization_goal: args[\"optimization-goal\"],\n page_id: args[\"page-id\"],\n instagram_user_id: args[\"instagram-user\"],\n targeting: loadJsonFileArg(args[\"targeting-file\"]),\n targetFrequency: numberFlag(args[\"target-frequency\"], \"--target-frequency\"),\n targetFrequencyDays: numberFlag(args[\"target-frequency-days\"], \"--target-frequency-days\"),\n day_parting_schedule: dayPartingFromFlags(args as Args, rawArgs),\n instream_packages: instreamPackages.length > 0 ? instreamPackages : undefined,\n };\n try {\n const quote = await apiPost<Row>(\"/api/ads/meta/reach-frequency/predict\", body);\n const unanswered =\n quote.status === 1\n ? []\n : [\n `Meta did not quote this (status ${String(quote.status)}, reach 0) — nothing to reserve. Live, a run ending before 6 AM account time on its last day came back this way: move --end later in the day, or widen the audience (Meta's floor is about 200,000 people), and ask again.`,\n ];\n emit(quote, [\n ...unanswered,\n \"external_reach / external_impression are what Meta forecasts; external_budget and the min/max bounds are in minor units (cents). To hold this price, `reach-frequency reserve <id>` (staged, made at publish).\",\n ]);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.reach-frequency.reserve\",\n description:\n \"Stage reserving a reach-and-frequency quote: Meta holds its price for about two weeks. Made at publish.\",\n args: { id: { type: \"positional\", description: \"Quote id\", required: true }, \"account-id\": schemaAccount },\n});\n\nconst reachFrequencyReserveCommand = defineCommand({\n meta: {\n name: \"reserve\",\n description: `Reserve a reach-and-frequency quote — Meta holds its price until the reservation expires. ${STAGED_NOTE}\nThen buy on it: campaigns create --buying-type RESERVED …, adsets create --reservation meta_temp_… (no budget — it comes from the quote).\nExample: baker ads meta reach-frequency reserve 120249500564540208 --account-id act_123`,\n },\n args: {\n id: { type: \"positional\", description: \"Quote id (from `reach-frequency predict` or the list)\", required: true },\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n },\n run: async ({ args }) => {\n await stageOp({\n kind: \"reachFrequencyReservation.create\",\n accountId: bareAccountId(args as Args),\n payload: { prediction_id: requireTarget(args as Args, \"quote\") },\n });\n },\n});\n\nregisterSchema({\n command: \"ads.meta.reach-frequency.cancel\",\n description: \"Stage cancelling a reach-and-frequency reservation, releasing its price. Made at publish.\",\n args: { id: { type: \"positional\", description: \"Reservation id\", required: true }, \"account-id\": schemaAccount },\n});\n\nconst reachFrequencyCancelCommand = defineCommand({\n meta: {\n name: \"cancel\",\n description: `Cancel a reach-and-frequency reservation. ${STAGED_NOTE}\nExample: baker ads meta reach-frequency cancel 120249500569290208 --account-id act_123`,\n },\n args: {\n id: { type: \"positional\", description: \"Reservation id\", required: true },\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n },\n run: async ({ args }) => {\n await stageOp({\n kind: \"reachFrequencyReservation.update\",\n accountId: bareAccountId(args as Args),\n target: requireTarget(args as Args, \"reservation\"),\n payload: { status: \"CANCELLED\" },\n });\n },\n});\n\nexport const reachFrequencyCommand = defineCommand({\n meta: {\n name: \"reach-frequency\",\n description: `Reach and frequency buying (Reservation): a fixed reach at a fixed price over fixed dates.\n baker ads meta reach-frequency --account-id act_123 — quotes and reservations\n baker ads meta reach-frequency predict --budget 1000 --start … --end … --targeting-file t.json — a quote (holds nothing)\n baker ads meta reach-frequency reserve <quote id> | cancel <reservation id> — staged, made at publish`,\n },\n subCommands: {\n list: reachFrequencyListCommand,\n predict: reachFrequencyPredictCommand,\n reserve: reachFrequencyReserveCommand,\n cancel: reachFrequencyCancelCommand,\n },\n args: { \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" } },\n default: \"list\",\n});\n\n// --- Posts an ad can boost, and comments on ads ---\n\nregisterSchema({\n command: \"ads.meta.page-posts\",\n description:\n \"A Facebook Page's recent posts, with is_eligible_for_promotion — the posts a `creatives create --type existing_post --post-id` can boost.\",\n args: { \"page-id\": { type: \"string\", description: \"Facebook Page id\", required: true } },\n});\n\nexport const pagePostsCommand = defineCommand({\n meta: {\n name: \"page-posts\",\n description: `A Facebook Page's recent posts, for boosting one as an ad (keeps its likes and comments).\nExample: baker ads meta page-posts --page-id 904238019441800\nThen: baker ads meta creatives create --type existing_post --post-id <id> (only a post with is_eligible_for_promotion: true)`,\n },\n args: { \"page-id\": { type: \"string\", description: \"Facebook Page id — from `baker ads meta pages`\" } },\n run: async ({ args }) => {\n if (!args[\"page-id\"]) failWriteValidation(\"pass --page-id (from `baker ads meta pages`)\");\n try {\n const rows = await readEdge({ edge: \"page-posts\", \"page-id\": String(args[\"page-id\"]) });\n emit(rows, [\n \"Boost one with `creatives create --type existing_post --post-id <id>`; is_eligible_for_promotion false means Meta will not run it as an ad.\",\n ]);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.instagram-media\",\n description:\n \"An Instagram account's posts, for boosting one as an ad (`creatives create --type existing_post --instagram-media-id`).\",\n args: { \"instagram-user\": { type: \"string\", description: \"Instagram account id\", required: true } },\n});\n\nexport const instagramMediaCommand = defineCommand({\n meta: {\n name: \"instagram-media\",\n description: `An Instagram account's posts, for boosting one as an ad.\nExample: baker ads meta instagram-media --instagram-user 17841478810711864\nThen: baker ads meta creatives create --type existing_post --instagram-media-id <id> --page <brand page> --instagram-user <id>`,\n },\n args: {\n \"instagram-user\": {\n type: \"string\",\n description: \"Instagram account id — from `baker ads meta instagram-accounts`\",\n },\n },\n run: async ({ args }) => {\n if (!args[\"instagram-user\"])\n failWriteValidation(\"pass --instagram-user (from `baker ads meta instagram-accounts`)\");\n try {\n emit(await readEdge({ edge: \"instagram-media\", \"instagram-user\": String(args[\"instagram-user\"]) }));\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.comments\",\n description:\n \"The comments on an ad's post (Facebook). Needs Meta permissions the connection may not hold — a refusal says so; moderation then happens in Meta Business Suite.\",\n args: {\n \"ad-id\": { type: \"string\", description: \"Ad id\", required: true },\n full: { type: \"boolean\", description: \"Include who wrote each and its replies count\", required: false },\n },\n});\n\nexport const commentsCommand = defineCommand({\n meta: {\n name: \"comments\",\n description: `The comments people left on an ad's post.\nExample: baker ads meta comments --ad-id 120211234567890\nReading needs a Meta permission Baker's connection does not ask for yet; when Meta refuses, say moderation happens in Meta Business Suite and carry on.`,\n },\n args: {\n \"ad-id\": { type: \"string\", description: \"Ad id — from `baker ads meta ads`\" },\n full: { type: \"boolean\", description: \"Include who wrote each comment\" },\n },\n run: async ({ args }) => {\n if (!args[\"ad-id\"]) failWriteValidation(\"pass --ad-id (from `baker ads meta ads`)\");\n try {\n const params: Record<string, string> = { \"ad-id\": String(args[\"ad-id\"]) };\n if (args.full) params.full = \"true\";\n emit(await apiGet<Row[]>(\"/api/ads/meta/ad-comments\", params));\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\n// --- What else hangs off the account (reads) ---\n\nconst ACCOUNT_DETAILS = {\n recommendations: \"Meta's suggestions for the account (often empty)\",\n users: \"the people on the account and their tasks (MANAGE, ADVERTISE, ANALYZE, DRAFT) — read only\",\n \"account-controls\":\n \"account-wide Advantage+ controls: the minimum age, locations and placements every Advantage+ campaign keeps to — read only\",\n playables: \"playable ads (HTML) uploaded for app ads — read only\",\n \"place-page-sets\": \"store-location page sets for local ads — read only\",\n} as const;\ntype AccountDetail = keyof typeof ACCOUNT_DETAILS;\n\nregisterSchema({\n command: \"ads.meta.account-details\",\n description: `What else belongs to the ad account, read live — --show one of: ${Object.entries(ACCOUNT_DETAILS)\n .map(([name, what]) => `${name} (${what})`)\n .join(\"; \")}.`,\n args: {\n \"account-id\": schemaAccount,\n show: { type: \"string\", description: Object.keys(ACCOUNT_DETAILS).join(\"|\"), required: true },\n },\n});\n\nexport const accountDetailsCommand = defineCommand({\n meta: {\n name: \"account-details\",\n description: `What else belongs to the ad account, read live. Nothing here is changed by Baker.\nExample: baker ads meta account-details --account-id act_123 --show users\n--show ${Object.keys(ACCOUNT_DETAILS).join(\" | \")}`,\n },\n args: {\n \"account-id\": { type: \"string\", description: \"Numeric account ID or act_N\" },\n show: { type: \"string\", description: Object.keys(ACCOUNT_DETAILS).join(\" | \") },\n },\n run: async ({ args }) => {\n const show = String(args.show ?? \"\");\n if (!(show in ACCOUNT_DETAILS)) {\n failWriteValidation(`--show takes ${Object.keys(ACCOUNT_DETAILS).join(\", \")}`);\n }\n try {\n const rows = await readEdge({ edge: show as AccountDetail, \"account-id\": bareAccountId(args as Args) });\n emit(rows, rows.length === 0 ? [`No ${show} on this ad account.`] : []);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/ads/meta/ads.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport { META_LIST_SHAPE_ARGS, registerMetaListSchema, shapeMetaListRows, writeMetaListRows } from \"./list-rows.ts\";\nimport {\n csvOrJson,\n handleMetaError,\n NAME_CONTAINS_ARG,\n resolveAccountIdArg,\n resolveEffectiveStatus,\n statusFilterHints,\n} from \"./shared.ts\";\n\nconst listArgs = {\n \"account-id\": { type: \"string\", description: \"Meta ad account ID\" },\n \"adset-id\": { type: \"string\", description: \"Filter to one adset\" },\n \"campaign-id\": { type: \"string\", description: \"Filter to one campaign\" },\n \"effective-status\": { type: \"string\", description: \"Comma-separated effective_status filter (overrides default)\" },\n \"all-statuses\": { type: \"boolean\", description: \"Drop the default ACTIVE filter\" },\n \"name-contains\": NAME_CONTAINS_ARG,\n limit: { type: \"string\", description: \"Max rows (default 1000)\" },\n \"no-cache\": NO_CACHE_ARG,\n ...META_LIST_SHAPE_ARGS,\n} as const;\n\nregisterMetaListSchema(\n \"ads\",\n \"List ads in a Meta ad account, as a table by default: id, name, adset_id, campaign_id, effective_status, creative_id, issues (why an ad is WITH_ISSUES), created_time. Start here: baker ads meta ads --adset-id 6123. --fields takes dotted paths (e.g. id,tracking_specs); --full returns every field Meta sent; --output json returns the rows in the envelope.\",\n listArgs,\n);\n\nconst listCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"List ads in a Meta ad account. Runs by default when no subcommand is given. Example: baker ads meta ads --account-id act_123\",\n },\n args: listArgs,\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n const effectiveStatus = resolveEffectiveStatus(args);\n try {\n const params: Record<string, string> = { \"account-id\": accountId };\n if (args[\"adset-id\"]) params[\"adset-id\"] = args[\"adset-id\"] as string;\n if (args[\"campaign-id\"]) params[\"campaign-id\"] = args[\"campaign-id\"] as string;\n if (effectiveStatus) params[\"effective-status\"] = effectiveStatus;\n if (args[\"name-contains\"]) params[\"name-contains\"] = args[\"name-contains\"] as string;\n if (args.limit) params.limit = args.limit as string;\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<Array<Record<string, unknown>>>(\"/api/ads/meta/ads\", params);\n const shaped = shapeMetaListRows(\"ads\", data, args);\n writeMetaListRows(\"ads\", shaped, csvOrJson(args), statusFilterHints(data, effectiveStatus, \"ads\"));\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nexport const adsListCommand = defineCommand({\n meta: {\n name: \"ads\",\n description: `List ads in a Meta ad account, or stage writes (create/update/pause/resume/archive/delete/duplicate/copy/retag).\nDefaults to ACTIVE only — pass --all-statuses to widen. Write subcommands stage ops on this chat's draft.\n\nThe dashboard shows effective_status (e.g. WITH_ISSUES, PENDING_REVIEW, DISAPPROVED, ADSET_PAUSED), not status.\n\nListings print a table by default: id, name, adset_id, campaign_id, effective_status, creative_id, issues\n(why an ad is WITH_ISSUES), created_time. --fields takes dotted paths (e.g. tracking_specs,\npreview_shareable_link); --full returns every field; --output json returns the rows as JSON.\n\nExamples:\n baker ads meta ads --account-id act_123\n baker ads meta ads --adset-id 6123\n baker ads meta ads --account-id act_123 --all-statuses --name-contains octubre --fields id,name,adset_id,creative_id — find one ad by name\n baker ads meta ads --adset-id 6123 --fields id,name,preview_shareable_link\n baker ads meta ads create --name \"Ad 1\" --adset meta_temp_as01 --creative meta_temp_cr01\n baker ads meta ads pause 6123 --account-id act_123\n baker ads meta ads retag 6123 --set \"utm_medium=paid-social\" — fix tracking on a LIVE ad, keeping everything else`,\n },\n subCommands: {\n list: listCommand,\n create: () => import(\"./write-commands.ts\").then((m) => m.adsCreateCommand),\n update: () => import(\"./write-commands.ts\").then((m) => m.adsUpdateCommand),\n pause: () => import(\"./write-commands.ts\").then((m) => m.adsPauseCommand),\n resume: () => import(\"./write-commands.ts\").then((m) => m.adsResumeCommand),\n archive: () => import(\"./write-commands.ts\").then((m) => m.adsArchiveCommand),\n delete: () => import(\"./write-commands.ts\").then((m) => m.adsDeleteCommand),\n duplicate: () => import(\"./write-commands.ts\").then((m) => m.adsDuplicateCommand),\n copy: () => import(\"./copy-writes.ts\").then((m) => m.adsCopyCommand),\n retag: () => import(\"./write-commands.ts\").then((m) => m.adsRetagCommand),\n },\n // `args` stays even though the parent has no `run`: citty scans rawArgs for the\n // subcommand name using THIS command's arg defs, so without them `--account-id act_1`\n // would read `act_1` as a subcommand. `default` (not `run`) dispatches the bare\n // invocation — citty falls through to `run` after a subcommand, double-executing it.\n args: listArgs,\n default: \"list\",\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAa9B,IAAM,WAAW;AAAA,EACf,cAAc,EAAE,MAAM,UAAU,aAAa,qBAAqB;AAAA,EAClE,YAAY,EAAE,MAAM,UAAU,aAAa,sBAAsB;AAAA,EACjE,eAAe,EAAE,MAAM,UAAU,aAAa,yBAAyB;AAAA,EACvE,oBAAoB,EAAE,MAAM,UAAU,aAAa,8DAA8D;AAAA,EACjH,gBAAgB,EAAE,MAAM,WAAW,aAAa,iCAAiC;AAAA,EACjF,iBAAiB;AAAA,EACjB,OAAO,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,EAChE,YAAY;AAAA,EACZ,GAAG;AACL;AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,cAAc,cAAc;AAAA,EAChC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,MAAM;AAAA,EACN,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,YAAY,oBAAoB,IAAI;AAC1C,UAAM,kBAAkB,uBAAuB,IAAI;AACnD,QAAI;AACF,YAAM,SAAiC,EAAE,cAAc,UAAU;AACjE,UAAI,KAAK,UAAU,EAAG,QAAO,UAAU,IAAI,KAAK,UAAU;AAC1D,UAAI,KAAK,aAAa,EAAG,QAAO,aAAa,IAAI,KAAK,aAAa;AACnE,UAAI,gBAAiB,QAAO,kBAAkB,IAAI;AAClD,UAAI,KAAK,eAAe,EAAG,QAAO,eAAe,IAAI,KAAK,eAAe;AACzE,UAAI,KAAK,MAAO,QAAO,QAAQ,KAAK;AACpC,UAAI,KAAK,UAAU,EAAG,QAAO,YAAY,IAAI;AAC7C,YAAM,OAAO,MAAM,OAAuC,qBAAqB,MAAM;AACrF,YAAM,SAAS,kBAAkB,OAAO,MAAM,IAAI;AAClD,wBAAkB,OAAO,QAAQ,UAAU,IAAI,GAAG,kBAAkB,MAAM,iBAAiB,KAAK,CAAC;AAAA,IACnG,SAAS,KAAK;AACZ,sBAAgB,GAAG;AAAA,IACrB;AAAA,EACF;AACF,CAAC;AAEM,IAAM,iBAAiB,cAAc;AAAA,EAC1C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBf;AAAA,EACA,aAAa;AAAA,IACX,MAAM;AAAA,IACN,QAAQ,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,gBAAgB;AAAA,IAC1E,QAAQ,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,gBAAgB;AAAA,IAC1E,OAAO,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,eAAe;AAAA,IACxE,QAAQ,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,gBAAgB;AAAA,IAC1E,SAAS,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,iBAAiB;AAAA,IAC5E,QAAQ,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,gBAAgB;AAAA,IAC1E,WAAW,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,mBAAmB;AAAA,IAChF,MAAM,MAAM,OAAO,2BAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,cAAc;AAAA,IACnE,OAAO,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,eAAe;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM;AAAA,EACN,SAAS;AACX,CAAC;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/ads/meta/adsets.ts"],"sourcesContent":["import path from \"node:path\";\nimport { defineCommand } from \"citty\";\nimport { readAudienceNames } from \"../../../audience-names.ts\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport { rememberedJev } from \"../../../engine/lib/remembered-nouls.ts\";\nimport type { ReviewUsage } from \"../../../engine/nodes/local/lib/render-review.ts\";\nimport { findWorkspaceRoot } from \"../../canvas/normalize-paths.ts\";\nimport { holdUnbilledSpend } from \"../../canvas/unbilled-spend.ts\";\nimport { writeAdsOutput } from \"../output.ts\";\nimport { adSetViewerRows, audienceNamesOf, flattenViewerRows, VIEWER_TABLE_COLUMNS } from \"./adset-viewers.ts\";\nimport {\n budgetUnitHints,\n META_LIST_SHAPE_ARGS,\n registerMetaListSchema,\n shapeMetaListRows,\n writeMetaListRows,\n} from \"./list-rows.ts\";\nimport {\n csvOrJson,\n handleMetaError,\n NAME_CONTAINS_ARG,\n resolveAccountIdArg,\n resolveEffectiveStatus,\n statusFilterHints,\n} from \"./shared.ts\";\n\nconst listArgs = {\n \"account-id\": { type: \"string\", description: \"Meta ad account ID\" },\n \"campaign-id\": { type: \"string\", description: \"Filter to one campaign\" },\n \"effective-status\": { type: \"string\", description: \"Comma-separated effective_status filter (overrides default)\" },\n \"all-statuses\": { type: \"boolean\", description: \"Drop the default ACTIVE filter\" },\n \"name-contains\": NAME_CONTAINS_ARG,\n limit: { type: \"string\", description: \"Max rows (default 1000)\" },\n \"no-cache\": NO_CACHE_ARG,\n audience: {\n type: \"boolean\",\n description:\n \"Who each ad set reaches, instead of the compact row: a viewer per ad set — temperature (cold|warm|hot), what they already know (brand/offer/product), placements, and the reasons, read from its targeting, the account's audiences and the campaign objective. Start here before writing an ad for an ad set: baker ads meta adsets --campaign-id 6123 --audience --output json\",\n },\n ...META_LIST_SHAPE_ARGS,\n} as const;\n\ntype MetaRow = Record<string, unknown>;\n\n/**\n * The audience list and the campaign objectives only sharpen the read: without them\n * each audience is read from its name and the objective is left out, so a refused\n * read degrades the viewer rather than failing the listing.\n */\nasync function readOrEmpty(path: string, params: Record<string, string>, label: string, hints: string[]) {\n try {\n return await apiGet<MetaRow[]>(path, params);\n } catch (err) {\n const message = err instanceof Error ? err.message : \"unknown error\";\n hints.push(`Could not read the account's ${label} (${message}); the viewer was read without them.`);\n return [];\n }\n}\n\nasync function writeAdSetViewers(\n adSets: MetaRow[],\n accountParams: Record<string, string>,\n format: string,\n hints: string[],\n): Promise<void> {\n const [audiences, campaigns] = await Promise.all([\n readOrEmpty(\"/api/ads/meta/audiences\", accountParams, \"audiences\", hints),\n readOrEmpty(\"/api/ads/meta/campaigns\", accountParams, \"campaigns\", hints),\n ]);\n const root = findWorkspaceRoot(process.cwd()) ?? process.cwd();\n const cacheDir = path.join(root, \"canvas\", \".cache\");\n const spent: ReviewUsage[] = [];\n const readName = await readAudienceNames(\n audienceNamesOf(adSets, audiences),\n rememberedJev(path.join(cacheDir, \"audience-names.json\"), (u) => spent.push(u)),\n );\n await holdUnbilledSpend(cacheDir, spent).catch(() => undefined);\n const rows = adSetViewerRows(adSets, audiences, campaigns, readName);\n if (rows.length > 0) {\n hints.push(\n 'Write each ad for the viewer of the ad set it will run in, then record it in the creative\\'s _definition.md: targetAdSet: \"<ad set id>\" and viewer: { temperature, knows, placements, source }.',\n );\n }\n if (format === \"md\" || format === \"csv\") {\n writeAdsOutput(flattenViewerRows(rows), format, [...VIEWER_TABLE_COLUMNS], hints);\n return;\n }\n writeAdsOutput(rows as unknown as MetaRow[], format, undefined, hints);\n}\n\nregisterMetaListSchema(\n \"adsets\",\n \"List ad sets in a Meta ad account, as a table by default: id, name, campaign_id, effective_status, optimization_goal, billing_event, bid_strategy, budgets, destination_type, is_dynamic_creative, learning_stage, end_time, created_time. Targeting is not in the compact row — ask for it with --fields id,name,targeting (or --full). --audience replaces the row with who each ad set reaches (a viewer: temperature, what they already know, placements, reasons) — read it before writing an ad for an ad set. Start here: baker ads meta adsets --campaign-id 6123 --all-statuses. --output json returns the rows in the envelope.\",\n listArgs,\n);\n\nconst listCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"List ad sets in a Meta ad account. Runs by default when no subcommand is given. Example: baker ads meta adsets --account-id act_123\",\n },\n args: listArgs,\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n const effectiveStatus = resolveEffectiveStatus(args);\n try {\n const params: Record<string, string> = { \"account-id\": accountId };\n if (args[\"campaign-id\"]) params[\"campaign-id\"] = args[\"campaign-id\"] as string;\n if (effectiveStatus) params[\"effective-status\"] = effectiveStatus;\n if (args[\"name-contains\"]) params[\"name-contains\"] = args[\"name-contains\"] as string;\n if (args.limit) params.limit = args.limit as string;\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<Array<Record<string, unknown>>>(\"/api/ads/meta/adsets\", params);\n if (args.audience) {\n const hints = statusFilterHints(data, effectiveStatus, \"ad sets\");\n const accountParams: Record<string, string> = { \"account-id\": accountId };\n if (args[\"no-cache\"]) accountParams[\"skip-cache\"] = \"true\";\n await writeAdSetViewers(data, accountParams, csvOrJson(args), hints);\n return;\n }\n const shaped = shapeMetaListRows(\"adsets\", data, args);\n writeMetaListRows(\"adsets\", shaped, csvOrJson(args), [\n ...statusFilterHints(data, effectiveStatus, \"ad sets\"),\n ...budgetUnitHints(data),\n ]);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nexport const adsetsCommand = defineCommand({\n meta: {\n name: \"adsets\",\n description: `List ad sets in a Meta ad account, or stage writes (create/update/pause/resume/archive/delete/duplicate/copy).\nDefaults to ACTIVE only. Write subcommands stage ops on this chat's draft.\n\nListings print a table by default: id, name, campaign_id, effective_status, optimization_goal, billing_event,\nbid_strategy, budgets, destination_type, is_dynamic_creative, learning_stage, end_time, created_time. Targeting\nis not in the compact row — ask for it with --fields (dotted paths) or --full. --output json returns the rows as JSON.\n\nExamples:\n baker ads meta adsets --account-id act_123\n baker ads meta adsets --campaign-id 6123456789\n baker ads meta adsets --account-id act_123 --all-statuses --name-contains retargeting — find one ad set by name\n baker ads meta adsets --campaign-id 6123456789 --fields id,name,targeting.geo_locations\n baker ads meta adsets --campaign-id 6123456789 --audience --output json — who each ad set reaches (viewer per ad set)\n baker ads meta adsets create --campaign meta_temp_ab12 --name \"US 25-54\" --optimization-goal LINK_CLICKS --billing-event IMPRESSIONS --daily-budget 50 --targeting-file t.json`,\n },\n subCommands: {\n list: listCommand,\n create: () => import(\"./write-commands.ts\").then((m) => m.adSetsCreateCommand),\n update: () => import(\"./write-commands.ts\").then((m) => m.adSetsUpdateCommand),\n pause: () => import(\"./write-commands.ts\").then((m) => m.adSetsPauseCommand),\n resume: () => import(\"./write-commands.ts\").then((m) => m.adSetsResumeCommand),\n archive: () => import(\"./write-commands.ts\").then((m) => m.adSetsArchiveCommand),\n delete: () => import(\"./write-commands.ts\").then((m) => m.adSetsDeleteCommand),\n duplicate: () => import(\"./write-commands.ts\").then((m) => m.adSetsDuplicateCommand),\n copy: () => import(\"./copy-writes.ts\").then((m) => m.adSetsCopyCommand),\n },\n // `args` stays even though the parent has no `run`: citty scans rawArgs for the\n // subcommand name using THIS command's arg defs, so without them `--account-id act_1`\n // would read `act_1` as a subcommand. `default` (not `run`) dispatches the bare\n // invocation — citty falls through to `run` after a subcommand, double-executing it.\n args: listArgs,\n default: \"list\",\n});\n"],"mappings":"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","names":["path"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/ads/meta/audience-writes.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { brandSafetyTargetingFields } from \"@baker/api/ads-meta/brandSafety\";\nimport {\n CUSTOMER_LIST_BATCH_ROWS,\n CUSTOMER_LIST_MAX_BATCHES,\n type CustomerListAction,\n type CustomerListBatchResponse,\n} from \"@baker/api/ads-meta/customerList\";\nimport { defineCommand } from \"citty\";\nimport { apiGet, apiPost } from \"../../../client.ts\";\nimport { requireChatId } from \"../../../env.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { writeAdsOutput, writeJsonEnvelope } from \"../output.ts\";\nimport {\n customerListBatches,\n customerListFromFile,\n customerListUploadRefusal,\n DATE_ORDERS,\n type DateOrder,\n type HashedCustomerList,\n} from \"./customer-list.ts\";\nimport { csvOrJson, handleMetaError, resolveAccountIdArg } from \"./shared.ts\";\nimport { bareAccountId, failWriteValidation, repeatedListFlag, requireTarget, stageOp } from \"./write-shared.ts\";\n\n/**\n * Staged writes on who is in a customer list, deleting an audience, and the\n * saved audiences an ad set can copy. The people are read from a file in the\n * workspace and hashed here; only their digests are held by Baker until the\n * chat publishes, and only counts are ever printed.\n */\n\nconst STAGED_NOTE = \"Staged until publish — review with `baker ads meta draft`.\";\n\nconst membersArgs = {\n id: {\n type: \"positional\",\n description: \"Customer-list audience id, or a meta_temp_* ref created in this chat\",\n required: true,\n },\n \"account-id\": { type: \"string\", description: \"Meta ad account ID (act_123)\" },\n file: {\n type: \"string\",\n description:\n \"CSV (or ;/tab separated) in the workspace with a header row: email, phone, first name, last name, city, state, zip, country, birthday, gender, madid, external id\",\n },\n country: {\n type: \"string\",\n description:\n \"Two-letter country for phones written without their country code (when the row has no country column)\",\n },\n \"value-column\": {\n type: \"string\",\n description: \"Value-based list only: the column with each person's value (e.g. revenue)\",\n },\n columns: {\n type: \"string\",\n description:\n \"For a file without a header row: what each column is, in order (email,phone,country — comma-separated or repeated)\",\n },\n \"date-format\": {\n type: \"string\",\n description:\n \"How birthdays like 03/07/1990 are written: DMY (day first) or MDY (month first, US). Needed only when no date in the file shows it\",\n },\n} as const;\n\nfunction schemaArgs<T extends Record<string, { type: string; description: string; required?: boolean }>>(args: T) {\n return Object.fromEntries(\n Object.entries(args).map(([key, arg]) => [\n key,\n { type: arg.type, description: arg.description, required: arg.required === true },\n ]),\n );\n}\n\nconst ACTION_NOTES: Record<CustomerListAction, string> = {\n add: \"Adds the people in the file to the list; those already in it stay.\",\n remove: \"Removes the people in the file from the list.\",\n replace:\n \"Replaces the whole list with the file — everyone not in it leaves. Runs alone: not beside another change to the same list in this chat.\",\n};\n\nfunction dateFormatFlag(value: unknown): DateOrder | undefined {\n if (value === undefined) return undefined;\n const upperValue = String(value).toUpperCase();\n if (!(DATE_ORDERS as readonly string[]).includes(upperValue)) {\n failWriteValidation(`--date-format takes ${DATE_ORDERS.join(\" or \")}, not ${String(value)}`);\n }\n return upperValue as DateOrder;\n}\n\nfunction readList(args: Record<string, unknown>, rawArgs: readonly string[] | undefined): HashedCustomerList {\n const path = typeof args.file === \"string\" ? args.file : \"\";\n if (!path) {\n failWriteValidation(\"pass --file with the customer list (CSV in the workspace)\");\n }\n let content: string;\n try {\n content = readFileSync(path, \"utf8\");\n } catch (err) {\n failWriteValidation(`could not read ${path}: ${err instanceof Error ? err.message : String(err)}`);\n }\n try {\n return customerListFromFile(content, {\n defaultCountry: typeof args.country === \"string\" ? args.country : undefined,\n valueColumn: typeof args[\"value-column\"] === \"string\" ? args[\"value-column\"] : undefined,\n columns: repeatedListFlag(rawArgs, \"columns\", args.columns),\n dateFormat: dateFormatFlag(args[\"date-format\"]),\n });\n } catch (err) {\n failWriteValidation(err instanceof Error ? err.message : String(err));\n }\n}\n\n/** What the agent learns about the file: counts only. */\nfunction listHints(list: HashedCustomerList): string[] {\n const hints = [`${list.rows.length.toLocaleString(\"en-US\")} people read from the file, hashed before upload`];\n const unreadable = Object.entries(list.unreadable).map(([key, count]) => `${count} ${key}`);\n if (unreadable.length > 0) {\n hints.push(`values that could not be read and were left out: ${unreadable.join(\", \")}`);\n }\n if (list.skippedRows > 0) {\n hints.push(\n `${list.skippedRows} rows had nothing Meta can match on (no readable email, phone or id${list.schema.includes(\"LOOKALIKE_VALUE\") ? \", or no readable value\" : \"\"}) and were left out`,\n );\n }\n if (list.ignoredColumns.length > 0) {\n hints.push(`columns not sent (Meta does not match on them): ${list.ignoredColumns.join(\", \")}`);\n }\n if (list.rows.length < 100) {\n hints.push(\"Meta needs about 100 matched people before a list can be used for ads or as a lookalike seed\");\n }\n return hints;\n}\n\nasync function stageMembers(\n action: CustomerListAction,\n args: Record<string, unknown>,\n rawArgs: readonly string[] | undefined,\n): Promise<void> {\n const accountId = bareAccountId(args);\n const audienceId = requireTarget(args, \"audience\");\n const list = readList(args, rawArgs);\n if (list.rows.length === 0) {\n failWriteValidation(\"no one in this file can be matched — check the columns (email, phone, …) and their values\");\n }\n const batches = customerListBatches(list);\n if (batches.length > CUSTOMER_LIST_MAX_BATCHES) {\n failWriteValidation(\n `this file holds ${list.rows.length.toLocaleString(\"en-US\")} people; one change carries at most ${(CUSTOMER_LIST_BATCH_ROWS * CUSTOMER_LIST_MAX_BATCHES).toLocaleString(\"en-US\")} — split the file and stage one add per part`,\n );\n }\n const refusal = customerListUploadRefusal(audienceId, action, list);\n if (refusal) {\n failWriteValidation(refusal);\n }\n const stored: CustomerListBatchResponse[] = [];\n try {\n const chatId = requireChatId();\n for (const batch of batches) {\n const response = await apiPost<{ ok: true; data: CustomerListBatchResponse }>(\n \"/api/ads/meta/draft/customer-list-batch\",\n { chatId, accountId, batch },\n { timeoutMs: 120_000 },\n );\n stored.push(response.data);\n }\n } catch (err) {\n handleMetaError(err);\n }\n await stageOp(\n {\n kind: \"customAudience.members\",\n accountId,\n payload: { audience_id: audienceId, action, schema: list.schema, batches: stored },\n },\n listHints(list),\n );\n}\n\nfunction membersCommand(action: CustomerListAction) {\n registerSchema({\n command: `ads.meta.audiences.members.${action}`,\n description: `Stage ${action === \"add\" ? \"adding people to\" : action === \"remove\" ? \"removing people from\" : \"replacing everyone in\"} a Meta customer list from a CSV in the workspace. ${ACTION_NOTES[action]} Every value is normalized and SHA-256 hashed on this machine before upload, as Meta asks, with a masked copy of each person (l***@empresa.com) for the review; only counts are printed. Applied at publish; Meta takes up to 24h to match.`,\n args: schemaArgs(membersArgs),\n });\n return defineCommand({\n meta: {\n name: action,\n description: `${ACTION_NOTES[action]} ${STAGED_NOTE}\nExample: baker ads meta audiences members ${action} 120249492603650208 --file customers.csv --country ES`,\n },\n args: membersArgs,\n run: async ({ args, rawArgs }) => {\n await stageMembers(action, args as Record<string, unknown>, rawArgs);\n },\n });\n}\n\nexport const audiencesMembersCommand = defineCommand({\n meta: {\n name: \"members\",\n description: `Change who is in a customer-list audience, from a CSV in the workspace. Hashed here before upload. ${STAGED_NOTE}\n baker ads meta audiences members add <audienceId|meta_temp_…> --file customers.csv [--country ES]\n baker ads meta audiences members remove <audienceId> --file unsubscribed.csv\n baker ads meta audiences members replace <audienceId> --file customers.csv\n value-based list: add --value-column revenue`,\n },\n subCommands: {\n add: membersCommand(\"add\"),\n remove: membersCommand(\"remove\"),\n replace: membersCommand(\"replace\"),\n },\n});\n\n// --- Delete ---\n\nregisterSchema({\n command: \"ads.meta.audiences.delete\",\n description:\n \"Stage deleting a Meta custom audience — permanent, applied at publish. Every ad that targets it stops and cannot be restarted; Meta refuses while a lookalike is built from it (delete the lookalike first).\",\n args: {\n id: { type: \"positional\", description: \"Audience id\", required: true },\n \"account-id\": { type: \"string\", description: \"Meta ad account ID (act_123)\", required: false },\n },\n});\n\nexport const audiencesDeleteCommand = defineCommand({\n meta: {\n name: \"delete\",\n description: `Stage deleting an audience — permanent: ads that target it stop for good. Only when the user asked to delete it. ${STAGED_NOTE}`,\n },\n args: {\n id: { type: \"positional\", description: \"Audience id\", required: true },\n \"account-id\": { type: \"string\", description: \"Meta ad account ID (act_123)\" },\n },\n run: async ({ args }) => {\n await stageOp({\n kind: \"customAudience.update\",\n accountId: bareAccountId(args as Record<string, unknown>),\n target: requireTarget(args as Record<string, unknown>, \"audience\"),\n payload: { status: \"DELETED\" },\n });\n },\n});\n\n// --- Saved audiences ---\n\nregisterSchema({\n command: \"ads.meta.audiences.saved\",\n description:\n \"List the ad account's saved audiences (targeting saved in Ads Manager), or one with --saved-audience-id. Read-only — Meta's API cannot create or change one. Use one on a new ad set with `adsets create --saved-audience <id>`.\",\n args: {\n \"account-id\": { type: \"string\", description: \"Meta ad account ID (act_123)\", required: false },\n \"saved-audience-id\": {\n type: \"string\",\n description: \"One saved audience, with its full targeting\",\n required: false,\n },\n full: { type: \"boolean\", description: \"Include each audience's whole targeting spec\", required: false },\n output: { type: \"string\", description: \"json|csv|jsonl|md\", required: false, default: \"json\" },\n },\n});\n\nexport const savedAudiencesCommand = defineCommand({\n meta: {\n name: \"saved\",\n description:\n \"Saved audiences on the account (read-only). Example: baker ads meta audiences saved --account-id act_123; use one with `adsets create --saved-audience <id>`\",\n },\n args: {\n \"account-id\": { type: \"string\", description: \"Meta ad account ID (act_123)\" },\n \"saved-audience-id\": { type: \"string\", description: \"One saved audience, with its full targeting\" },\n full: { type: \"boolean\", description: \"Include each audience's whole targeting spec\" },\n output: { type: \"string\", description: \"json|csv|jsonl|md\", default: \"json\" },\n },\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const params: Record<string, string> = { \"account-id\": accountId };\n if (args[\"saved-audience-id\"]) params[\"saved-audience-id\"] = String(args[\"saved-audience-id\"]);\n const rows = await apiGet<Array<Record<string, unknown>>>(\"/api/ads/meta/saved-audiences\", params);\n const shown =\n args.full || args[\"saved-audience-id\"] ? rows : rows.map(({ targeting: _targeting, ...row }) => row);\n const hints =\n rows.length === 0\n ? [\n \"This account has no saved audiences — Meta's API cannot create one; build the targeting on the ad set instead.\",\n ]\n : [\n \"Use one on a new ad set: `baker ads meta adsets create … --saved-audience <id>` (its targeting is copied).\",\n ];\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(shown, fmt, undefined, hints);\n return;\n }\n writeJsonEnvelope({ ok: true, data: shown, hints });\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\n/**\n * A saved audience's targeting with the command's own targeting laid over it:\n * the brand-safety flags (`--block-list`, …) join it, while a targeting file\n * would replace it whole, so the two are refused together.\n */\nexport function targetingFromSavedAudience(\n saved: Record<string, unknown>,\n flagged: Record<string, unknown> | undefined,\n): { targeting: Record<string, unknown> } | { refusal: string } {\n if (flagged === undefined) return { targeting: saved };\n if (!Object.keys(flagged).every((key) => key in brandSafetyTargetingFields)) {\n return { refusal: \"--saved-audience brings the targeting — pass it or --targeting-file, not both\" };\n }\n return { targeting: { ...saved, ...flagged } };\n}\n\n/** A saved audience's targeting, to start an ad set from. */\nexport async function savedAudienceTargeting(\n accountId: string,\n savedAudienceId: string,\n): Promise<Record<string, unknown>> {\n try {\n const rows = await apiGet<Array<{ targeting?: Record<string, unknown> }>>(\"/api/ads/meta/saved-audiences\", {\n \"account-id\": accountId,\n \"saved-audience-id\": savedAudienceId,\n });\n const targeting = rows[0]?.targeting;\n if (!targeting) {\n failWriteValidation(`saved audience ${savedAudienceId} has no targeting to copy`);\n }\n return targeting;\n } catch (err) {\n handleMetaError(err);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,oBAAoB;AAQ7B,SAAS,qBAAqB;AAuB9B,IAAM,cAAc;AAEpB,IAAM,cAAc;AAAA,EAClB,IAAI;AAAA,IACF,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA,cAAc,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,EAC5E,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,gBAAgB;AAAA,IACd,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,eAAe;AAAA,IACb,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AACF;AAEA,SAAS,WAAgG,MAAS;AAChH,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM;AAAA,MACvC;AAAA,MACA,EAAE,MAAM,IAAI,MAAM,aAAa,IAAI,aAAa,UAAU,IAAI,aAAa,KAAK;AAAA,IAClF,CAAC;AAAA,EACH;AACF;AAEA,IAAM,eAAmD;AAAA,EACvD,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,SACE;AACJ;AAEA,SAAS,eAAe,OAAuC;AAC7D,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,aAAa,OAAO,KAAK,EAAE,YAAY;AAC7C,MAAI,CAAE,YAAkC,SAAS,UAAU,GAAG;AAC5D,wBAAoB,uBAAuB,YAAY,KAAK,MAAM,CAAC,SAAS,OAAO,KAAK,CAAC,EAAE;AAAA,EAC7F;AACA,SAAO;AACT;AAEA,SAAS,SAAS,MAA+B,SAA4D;AAC3G,QAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AACzD,MAAI,CAAC,MAAM;AACT,wBAAoB,2DAA2D;AAAA,EACjF;AACA,MAAI;AACJ,MAAI;AACF,cAAU,aAAa,MAAM,MAAM;AAAA,EACrC,SAAS,KAAK;AACZ,wBAAoB,kBAAkB,IAAI,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,EACnG;AACA,MAAI;AACF,WAAO,qBAAqB,SAAS;AAAA,MACnC,gBAAgB,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;AAAA,MAClE,aAAa,OAAO,KAAK,cAAc,MAAM,WAAW,KAAK,cAAc,IAAI;AAAA,MAC/E,SAAS,iBAAiB,SAAS,WAAW,KAAK,OAAO;AAAA,MAC1D,YAAY,eAAe,KAAK,aAAa,CAAC;AAAA,IAChD,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,wBAAoB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACtE;AACF;AAGA,SAAS,UAAU,MAAoC;AACrD,QAAM,QAAQ,CAAC,GAAG,KAAK,KAAK,OAAO,eAAe,OAAO,CAAC,kDAAkD;AAC5G,QAAM,aAAa,OAAO,QAAQ,KAAK,UAAU,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,EAAE;AAC1F,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,KAAK,oDAAoD,WAAW,KAAK,IAAI,CAAC,EAAE;AAAA,EACxF;AACA,MAAI,KAAK,cAAc,GAAG;AACxB,UAAM;AAAA,MACJ,GAAG,KAAK,WAAW,sEAAsE,KAAK,OAAO,SAAS,iBAAiB,IAAI,2BAA2B,EAAE;AAAA,IAClK;AAAA,EACF;AACA,MAAI,KAAK,eAAe,SAAS,GAAG;AAClC,UAAM,KAAK,mDAAmD,KAAK,eAAe,KAAK,IAAI,CAAC,EAAE;AAAA,EAChG;AACA,MAAI,KAAK,KAAK,SAAS,KAAK;AAC1B,UAAM,KAAK,8FAA8F;AAAA,EAC3G;AACA,SAAO;AACT;AAEA,eAAe,aACb,QACA,MACA,SACe;AACf,QAAM,YAAY,cAAc,IAAI;AACpC,QAAM,aAAa,cAAc,MAAM,UAAU;AACjD,QAAM,OAAO,SAAS,MAAM,OAAO;AACnC,MAAI,KAAK,KAAK,WAAW,GAAG;AAC1B,wBAAoB,qGAA2F;AAAA,EACjH;AACA,QAAM,UAAU,oBAAoB,IAAI;AACxC,MAAI,QAAQ,SAAS,2BAA2B;AAC9C;AAAA,MACE,mBAAmB,KAAK,KAAK,OAAO,eAAe,OAAO,CAAC,wCAAwC,2BAA2B,2BAA2B,eAAe,OAAO,CAAC;AAAA,IAClL;AAAA,EACF;AACA,QAAM,UAAU,0BAA0B,YAAY,QAAQ,IAAI;AAClE,MAAI,SAAS;AACX,wBAAoB,OAAO;AAAA,EAC7B;AACA,QAAM,SAAsC,CAAC;AAC7C,MAAI;AACF,UAAM,SAAS,cAAc;AAC7B,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,QACA,EAAE,QAAQ,WAAW,MAAM;AAAA,QAC3B,EAAE,WAAW,KAAQ;AAAA,MACvB;AACA,aAAO,KAAK,SAAS,IAAI;AAAA,IAC3B;AAAA,EACF,SAAS,KAAK;AACZ,oBAAgB,GAAG;AAAA,EACrB;AACA,QAAM;AAAA,IACJ;AAAA,MACE,MAAM;AAAA,MACN;AAAA,MACA,SAAS,EAAE,aAAa,YAAY,QAAQ,QAAQ,KAAK,QAAQ,SAAS,OAAO;AAAA,IACnF;AAAA,IACA,UAAU,IAAI;AAAA,EAChB;AACF;AAEA,SAAS,eAAe,QAA4B;AAClD,iBAAe;AAAA,IACb,SAAS,8BAA8B,MAAM;AAAA,IAC7C,aAAa,SAAS,WAAW,QAAQ,qBAAqB,WAAW,WAAW,yBAAyB,uBAAuB,sDAAsD,aAAa,MAAM,CAAC;AAAA,IAC9M,MAAM,WAAW,WAAW;AAAA,EAC9B,CAAC;AACD,SAAO,cAAc;AAAA,IACnB,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa,GAAG,aAAa,MAAM,CAAC,IAAI,WAAW;AAAA,4CACb,MAAM;AAAA,IAC9C;AAAA,IACA,MAAM;AAAA,IACN,KAAK,OAAO,EAAE,MAAM,QAAQ,MAAM;AAChC,YAAM,aAAa,QAAQ,MAAiC,OAAO;AAAA,IACrE;AAAA,EACF,CAAC;AACH;AAEO,IAAM,0BAA0B,cAAc;AAAA,EACnD,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,sGAAsG,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhI;AAAA,EACA,aAAa;AAAA,IACX,KAAK,eAAe,KAAK;AAAA,IACzB,QAAQ,eAAe,QAAQ;AAAA,IAC/B,SAAS,eAAe,SAAS;AAAA,EACnC;AACF,CAAC;AAID,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aACE;AAAA,EACF,MAAM;AAAA,IACJ,IAAI,EAAE,MAAM,cAAc,aAAa,eAAe,UAAU,KAAK;AAAA,IACrE,cAAc,EAAE,MAAM,UAAU,aAAa,gCAAgC,UAAU,MAAM;AAAA,EAC/F;AACF,CAAC;AAEM,IAAM,yBAAyB,cAAc;AAAA,EAClD,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa,yHAAoH,WAAW;AAAA,EAC9I;AAAA,EACA,MAAM;AAAA,IACJ,IAAI,EAAE,MAAM,cAAc,aAAa,eAAe,UAAU,KAAK;AAAA,IACrE,cAAc,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,EAC9E;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,QAAQ;AAAA,MACZ,MAAM;AAAA,MACN,WAAW,cAAc,IAA+B;AAAA,MACxD,QAAQ,cAAc,MAAiC,UAAU;AAAA,MACjE,SAAS,EAAE,QAAQ,UAAU;AAAA,IAC/B,CAAC;AAAA,EACH;AACF,CAAC;AAID,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aACE;AAAA,EACF,MAAM;AAAA,IACJ,cAAc,EAAE,MAAM,UAAU,aAAa,gCAAgC,UAAU,MAAM;AAAA,IAC7F,qBAAqB;AAAA,MACnB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,MAAM,EAAE,MAAM,WAAW,aAAa,gDAAgD,UAAU,MAAM;AAAA,IACtG,QAAQ,EAAE,MAAM,UAAU,aAAa,qBAAqB,UAAU,OAAO,SAAS,OAAO;AAAA,EAC/F;AACF,CAAC;AAEM,IAAM,wBAAwB,cAAc;AAAA,EACjD,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,MAAM;AAAA,IACJ,cAAc,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,IAC5E,qBAAqB,EAAE,MAAM,UAAU,aAAa,8CAA8C;AAAA,IAClG,MAAM,EAAE,MAAM,WAAW,aAAa,+CAA+C;AAAA,IACrF,QAAQ,EAAE,MAAM,UAAU,aAAa,qBAAqB,SAAS,OAAO;AAAA,EAC9E;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,YAAY,oBAAoB,IAAI;AAC1C,QAAI;AACF,YAAM,SAAiC,EAAE,cAAc,UAAU;AACjE,UAAI,KAAK,mBAAmB,EAAG,QAAO,mBAAmB,IAAI,OAAO,KAAK,mBAAmB,CAAC;AAC7F,YAAM,OAAO,MAAM,OAAuC,iCAAiC,MAAM;AACjG,YAAM,QACJ,KAAK,QAAQ,KAAK,mBAAmB,IAAI,OAAO,KAAK,IAAI,CAAC,EAAE,WAAW,YAAY,GAAG,IAAI,MAAM,GAAG;AACrG,YAAM,QACJ,KAAK,WAAW,IACZ;AAAA,QACE;AAAA,MACF,IACA;AAAA,QACE;AAAA,MACF;AACN,YAAM,MAAM,UAAU,IAAI;AAC1B,UAAI,QAAQ,QAAQ;AAClB,uBAAe,OAAO,KAAK,QAAW,KAAK;AAC3C;AAAA,MACF;AACA,wBAAkB,EAAE,IAAI,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,IACpD,SAAS,KAAK;AACZ,sBAAgB,GAAG;AAAA,IACrB;AAAA,EACF;AACF,CAAC;AAOM,SAAS,2BACd,OACA,SAC8D;AAC9D,MAAI,YAAY,OAAW,QAAO,EAAE,WAAW,MAAM;AACrD,MAAI,CAAC,OAAO,KAAK,OAAO,EAAE,MAAM,CAAC,QAAQ,OAAO,0BAA0B,GAAG;AAC3E,WAAO,EAAE,SAAS,qFAAgF;AAAA,EACpG;AACA,SAAO,EAAE,WAAW,EAAE,GAAG,OAAO,GAAG,QAAQ,EAAE;AAC/C;AAGA,eAAsB,uBACpB,WACA,iBACkC;AAClC,MAAI;AACF,UAAM,OAAO,MAAM,OAAuD,iCAAiC;AAAA,MACzG,cAAc;AAAA,MACd,qBAAqB;AAAA,IACvB,CAAC;AACD,UAAM,YAAY,KAAK,CAAC,GAAG;AAC3B,QAAI,CAAC,WAAW;AACd,0BAAoB,kBAAkB,eAAe,2BAA2B;AAAA,IAClF;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,oBAAgB,GAAG;AAAA,EACrB;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/ads/meta/audiences.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport { writeAdsJson, writeAdsOutput } from \"../output.ts\";\nimport { csvOrJson, handleMetaError, resolveAccountIdArg } from \"./shared.ts\";\n\nconst listArgs = {\n \"account-id\": { type: \"string\", description: \"Meta ad account ID\" },\n limit: { type: \"string\", description: \"Max rows\" },\n \"no-cache\": NO_CACHE_ARG,\n output: { type: \"string\", description: \"Output format\", default: \"json\" },\n} as const;\n\nconst listCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"List custom audiences. Runs by default when no subcommand is given. Example: baker ads meta audiences --account-id act_123\",\n },\n args: listArgs,\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n try {\n const params: Record<string, string> = { \"account-id\": accountId };\n if (args.limit) params.limit = args.limit as string;\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<Array<Record<string, unknown>>>(\"/api/ads/meta/audiences\", params);\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(data, fmt);\n return;\n }\n writeAdsJson({ ok: true, data });\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nexport const audiencesCommand = defineCommand({\n meta: {\n name: \"audiences\",\n description: `List custom audiences, or stage writes (create/update/delete, members add|remove|replace). Write subcommands stage ops on this chat's draft.\nIncludes lookalikes, website-pixel audiences, customer-file audiences. Meta hides exact size when count < 1000.\n\nExamples:\n baker ads meta audiences --account-id act_123\n baker ads meta audiences create --name \"Site 30d\" --subtype WEBSITE --file rule.json\n baker ads meta audiences create --name \"Past buyers\" --subtype CUSTOM --file buyers.json # {\"members\":[{\"email\":\"…\"}]}\n baker ads meta audiences create --name \"Customers\" --subtype CUSTOM --customer-file-source USER_PROVIDED_ONLY\n baker ads meta audiences members add meta_temp_ab12 --file customers.csv --country ES\n baker ads meta audiences saved --account-id act_123 — saved audiences (read-only)`,\n },\n subCommands: {\n list: listCommand,\n create: () => import(\"./write-commands.ts\").then((m) => m.audiencesCreateCommand),\n update: () => import(\"./write-commands.ts\").then((m) => m.audiencesUpdateCommand),\n delete: () => import(\"./audience-writes.ts\").then((m) => m.audiencesDeleteCommand),\n members: () => import(\"./audience-writes.ts\").then((m) => m.audiencesMembersCommand),\n saved: () => import(\"./audience-writes.ts\").then((m) => m.savedAudiencesCommand),\n },\n // `args` stays even though the parent has no `run`: citty scans rawArgs for the\n // subcommand name using THIS command's arg defs, so without them `--account-id act_1`\n // would read `act_1` as a subcommand. `default` (not `run`) dispatches the bare\n // invocation — citty falls through to `run` after a subcommand, double-executing it.\n args: listArgs,\n default: \"list\",\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAM9B,IAAM,WAAW;AAAA,EACf,cAAc,EAAE,MAAM,UAAU,aAAa,qBAAqB;AAAA,EAClE,OAAO,EAAE,MAAM,UAAU,aAAa,WAAW;AAAA,EACjD,YAAY;AAAA,EACZ,QAAQ,EAAE,MAAM,UAAU,aAAa,iBAAiB,SAAS,OAAO;AAC1E;AAEA,IAAM,cAAc,cAAc;AAAA,EAChC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,MAAM;AAAA,EACN,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,YAAY,oBAAoB,IAAI;AAC1C,QAAI;AACF,YAAM,SAAiC,EAAE,cAAc,UAAU;AACjE,UAAI,KAAK,MAAO,QAAO,QAAQ,KAAK;AACpC,UAAI,KAAK,UAAU,EAAG,QAAO,YAAY,IAAI;AAC7C,YAAM,OAAO,MAAM,OAAuC,2BAA2B,MAAM;AAC3F,YAAM,MAAM,UAAU,IAAI;AAC1B,UAAI,QAAQ,QAAQ;AAClB,uBAAe,MAAM,GAAG;AACxB;AAAA,MACF;AACA,mBAAa,EAAE,IAAI,MAAM,KAAK,CAAC;AAAA,IACjC,SAAS,KAAK;AACZ,sBAAgB,GAAG;AAAA,IACrB;AAAA,EACF;AACF,CAAC;AAEM,IAAM,mBAAmB,cAAc;AAAA,EAC5C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUf;AAAA,EACA,aAAa;AAAA,IACX,MAAM;AAAA,IACN,QAAQ,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,sBAAsB;AAAA,IAChF,QAAQ,MAAM,OAAO,8BAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,sBAAsB;AAAA,IAChF,QAAQ,MAAM,OAAO,+BAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,sBAAsB;AAAA,IACjF,SAAS,MAAM,OAAO,+BAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,uBAAuB;AAAA,IACnF,OAAO,MAAM,OAAO,+BAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,qBAAqB;AAAA,EACjF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM;AAAA,EACN,SAAS;AACX,CAAC;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/ads/meta/campaigns.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport {\n budgetUnitHints,\n META_LIST_SHAPE_ARGS,\n registerMetaListSchema,\n shapeMetaListRows,\n writeMetaListRows,\n} from \"./list-rows.ts\";\nimport {\n csvOrJson,\n handleMetaError,\n NAME_CONTAINS_ARG,\n resolveAccountIdArg,\n resolveEffectiveStatus,\n statusFilterHints,\n} from \"./shared.ts\";\n\n/**\n * Which listed campaigns Meta counts as Advantage+, read off the derived\n * `advantage_state_info` — a hint rather than a column, so the compact row of a\n * 100-campaign account stays small. Advantage+ is not a switch: it follows from\n * a campaign budget, Advantage+ audience and automatic placements.\n */\nexport function advantagePlusHints(rows: ReadonlyArray<Record<string, unknown>>): string[] {\n const named = rows.flatMap((row) => {\n const info = row.advantage_state_info as { advantage_state?: unknown } | undefined;\n const state = info?.advantage_state;\n return typeof state === \"string\" && state.startsWith(\"ADVANTAGE_PLUS_\")\n ? [`${String(row.id)} (${state.slice(\"ADVANTAGE_PLUS_\".length).toLowerCase()})`]\n : [];\n });\n return named.length > 0\n ? [\n `Advantage+ campaigns: ${named.join(\", \")}. Per-lever states (budget, audience, placements): --fields id,name,advantage_state_info.`,\n ]\n : [];\n}\n\nconst listArgs = {\n \"account-id\": { type: \"string\", description: \"Meta ad account ID\" },\n \"effective-status\": { type: \"string\", description: \"Comma-separated effective_status filter (overrides default)\" },\n \"all-statuses\": { type: \"boolean\", description: \"Drop the default ACTIVE filter and return everything\" },\n \"name-contains\": NAME_CONTAINS_ARG,\n limit: { type: \"string\", description: \"Max rows (default 1000)\" },\n \"no-cache\": NO_CACHE_ARG,\n ...META_LIST_SHAPE_ARGS,\n} as const;\n\nregisterMetaListSchema(\n \"campaigns\",\n \"List campaigns in a Meta ad account, as a table by default: id, name, effective_status, daily_budget, lifetime_budget, created_date. ACTIVE only unless --all-statuses. Start here: baker ads meta campaigns --account-id act_123 --all-statuses. --fields takes dotted paths for anything else (e.g. id,name,objective,bid_strategy,special_ad_categories,advantage_state_info); --full returns every field Meta sent; --output json returns the rows in the envelope. A hint names the campaigns Meta counts as Advantage+.\",\n listArgs,\n);\n\nconst listCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"List campaigns for a Meta ad account. Runs by default when no subcommand is given. Example: baker ads meta campaigns --account-id act_123\",\n },\n args: listArgs,\n run: async ({ args }) => {\n const accountId = resolveAccountIdArg(args);\n const effectiveStatus = resolveEffectiveStatus(args);\n try {\n const params: Record<string, string> = { \"account-id\": accountId };\n if (effectiveStatus) params[\"effective-status\"] = effectiveStatus;\n if (args[\"name-contains\"]) params[\"name-contains\"] = args[\"name-contains\"] as string;\n if (args.limit) params.limit = args.limit as string;\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<Array<Record<string, unknown>>>(\"/api/ads/meta/campaigns\", params);\n const shaped = shapeMetaListRows(\"campaigns\", data, args);\n writeMetaListRows(\"campaigns\", shaped, csvOrJson(args), [\n ...statusFilterHints(data, effectiveStatus, \"campaigns\"),\n ...advantagePlusHints(data),\n ...budgetUnitHints(data),\n ]);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nexport const campaignsCommand = defineCommand({\n meta: {\n name: \"campaigns\",\n description: `List campaigns for a Meta ad account, or stage writes (create/update/pause/resume/archive/delete/duplicate/copy).\nDefaults to ACTIVE only — pass --all-statuses to widen. Write subcommands stage ops on this chat's draft and\napply only when the chat is published.\n\nIn Meta's API \"campaign\" is the top-of-tree object (what marketers usually call a campaign group).\nThe dashboard shows effective_status: ACTIVE, PAUSED, DELETED, ARCHIVED, IN_PROCESS, WITH_ISSUES, etc.\n\nListings print a table by default: id, name, effective_status, daily/lifetime budget, created_date.\n--fields takes dotted paths for anything else (objective, bid_strategy, special_ad_categories, created_time,\nadvantage_state_info). A hint names the campaigns Meta counts as Advantage+ — a state Meta derives from a\ncampaign budget, Advantage+ audience and automatic placements on every ad set, not a setting;\n--full returns every field; --output json returns the same rows in the { ok, data } envelope.\n\nExamples:\n baker ads meta campaigns --account-id act_123 # ACTIVE only\n baker ads meta campaigns --account-id act_123 --all-statuses # everything\n baker ads meta campaigns --account-id act_123 --all-statuses --name-contains Q3 # find one by name\n baker ads meta campaigns --account-id act_123 --fields id,name,objective,bid_strategy,special_ad_categories\n baker ads meta campaigns --account-id act_123 --output json # rows as JSON\n baker ads meta campaigns create --account-id act_123 --name \"Q3\" --objective OUTCOME_LEADS --daily-budget 50\n baker ads meta campaigns pause 6123 --account-id act_123`,\n },\n subCommands: {\n list: listCommand,\n create: () => import(\"./write-commands.ts\").then((m) => m.campaignsCreateCommand),\n update: () => import(\"./write-commands.ts\").then((m) => m.campaignsUpdateCommand),\n pause: () => import(\"./write-commands.ts\").then((m) => m.campaignsPauseCommand),\n resume: () => import(\"./write-commands.ts\").then((m) => m.campaignsResumeCommand),\n archive: () => import(\"./write-commands.ts\").then((m) => m.campaignsArchiveCommand),\n delete: () => import(\"./write-commands.ts\").then((m) => m.campaignsDeleteCommand),\n duplicate: () => import(\"./write-commands.ts\").then((m) => m.campaignsDuplicateCommand),\n copy: () => import(\"./copy-writes.ts\").then((m) => m.campaignsCopyCommand),\n },\n // `args` stays even though the parent has no `run`: citty scans rawArgs for the\n // subcommand name using THIS command's arg defs, so without them `--account-id act_1`\n // would read `act_1` as a subcommand. `default` (not `run`) dispatches the bare\n // invocation — citty falls through to `run` after a subcommand, double-executing it.\n args: listArgs,\n default: \"list\",\n});\n"],"mappings":"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","names":[]}