@koda-sl/baker-cli 0.365.0 → 0.366.0-dev.1010f7728

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.
@@ -2,7 +2,7 @@ import {
2
2
  handleConnectionError,
3
3
  needsConnectionFix,
4
4
  writeAdsJson
5
- } from "./chunk-FXVELNAS.js";
5
+ } from "./chunk-A2LM5EDF.js";
6
6
  import {
7
7
  ApiError
8
8
  } from "./chunk-MZQC4LII.js";
@@ -10,6 +10,37 @@ import {
10
10
  getEnv
11
11
  } from "./chunk-2OKSJNLA.js";
12
12
 
13
+ // src/commands/ads/project-fields.ts
14
+ function asRecord(value) {
15
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
16
+ }
17
+ function readPath(row, path) {
18
+ let current = row;
19
+ for (const segment of path.split(".")) {
20
+ const record = asRecord(current);
21
+ if (!record) return void 0;
22
+ current = record[segment];
23
+ }
24
+ return current;
25
+ }
26
+ function projectFields(rows, paths) {
27
+ return rows.map((row) => {
28
+ const projected = {};
29
+ for (const path of paths) {
30
+ const value = readPath(row, path);
31
+ if (value !== void 0) {
32
+ projected[path] = value;
33
+ }
34
+ }
35
+ return projected;
36
+ });
37
+ }
38
+ function parseFieldsArg(value) {
39
+ if (typeof value !== "string") return void 0;
40
+ const paths = value.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
41
+ return paths.length > 0 ? paths : void 0;
42
+ }
43
+
13
44
  // src/commands/ads/meta/shared.ts
14
45
  var DAY_MS = 864e5;
15
46
  function metaForbiddenFix(message) {
@@ -87,6 +118,18 @@ function daysAgoIso(days) {
87
118
  function csvOrJson(args) {
88
119
  return args.output ?? "json";
89
120
  }
121
+ var NAME_CONTAINS_ARG = {
122
+ type: "string",
123
+ description: "Only rows whose name contains this text, matched by Meta before anything is returned. Start here to find one entity by name: --name-contains octubre --all-statuses"
124
+ };
125
+ var FIELDS_ARG = {
126
+ type: "string",
127
+ description: "Comma-separated fields to print instead of the whole row; nested ones by dotted path. Pair with --name-contains: --fields id,name,adset_id,creative.id"
128
+ };
129
+ function projectListRows(rows, args) {
130
+ const paths = parseFieldsArg(args.fields);
131
+ return paths ? { rows: projectFields(rows, paths), fields: paths } : { rows };
132
+ }
90
133
  function resolveEffectiveStatus(args) {
91
134
  if (args["all-statuses"]) {
92
135
  return void 0;
@@ -97,19 +140,10 @@ function resolveEffectiveStatus(args) {
97
140
  }
98
141
  return "ACTIVE";
99
142
  }
100
- function statusFilterHints(rows, effectiveStatus, noun) {
101
- if (rows.length > 0 || effectiveStatus === void 0) return [];
102
- if (effectiveStatus === "ACTIVE") {
103
- return [
104
- `No ACTIVE ${noun}. The ACTIVE filter hides paused, archived and in-review ones (under a paused campaign or ad set that is all of them), so this does NOT mean none exist. Re-run with --all-statuses before concluding there are none.`
105
- ];
106
- }
107
- return [
108
- `No ${noun} with effective_status ${effectiveStatus}. Re-run with --all-statuses to see every status before concluding there are none.`
109
- ];
110
- }
111
143
 
112
144
  export {
145
+ projectFields,
146
+ parseFieldsArg,
113
147
  metaForbiddenFix,
114
148
  handleMetaError,
115
149
  resolveAccountIdArg,
@@ -117,7 +151,9 @@ export {
117
151
  todayIso,
118
152
  daysAgoIso,
119
153
  csvOrJson,
120
- resolveEffectiveStatus,
121
- statusFilterHints
154
+ NAME_CONTAINS_ARG,
155
+ FIELDS_ARG,
156
+ projectListRows,
157
+ resolveEffectiveStatus
122
158
  };
123
- //# sourceMappingURL=chunk-L4QXAYIC.js.map
159
+ //# sourceMappingURL=chunk-WXSUOPOU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/ads/project-fields.ts","../src/commands/ads/meta/shared.ts"],"sourcesContent":["function asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** Reads one dotted path (`content.textAd.landingPage`) out of a record. */\nexport function readPath(row: Record<string, unknown>, path: string): unknown {\n let current: unknown = row;\n for (const segment of path.split(\".\")) {\n const record = asRecord(current);\n if (!record) return undefined;\n current = record[segment];\n }\n return current;\n}\n\nexport function projectFields(rows: Array<Record<string, unknown>>, paths: string[]): Array<Record<string, unknown>> {\n return rows.map((row) => {\n const projected: Record<string, unknown> = {};\n for (const path of paths) {\n const value = readPath(row, path);\n if (value !== undefined) {\n projected[path] = value;\n }\n }\n return projected;\n });\n}\n\n/** `--fields id, name,creative.id` → the dotted paths it names, or none when it names nothing. */\nexport function parseFieldsArg(value: unknown): string[] | undefined {\n if (typeof value !== \"string\") return undefined;\n const paths = value\n .split(\",\")\n .map((field) => field.trim())\n .filter((field) => field.length > 0);\n return paths.length > 0 ? paths : undefined;\n}\n","import { ApiError } from \"../../../client.ts\";\nimport { getEnv } from \"../../../env.ts\";\nimport { handleConnectionError, needsConnectionFix } from \"../../../error-handler.ts\";\nimport { writeAdsJson } from \"../output.ts\";\nimport { parseFieldsArg, projectFields } from \"../project-fields.ts\";\nimport type { AdsErrorEnvelope, QueryFix } from \"../types.ts\";\n\nconst DAY_MS = 86_400_000;\n\n/**\n * Meta answers a permission refusal (Graph codes 200/10/294) with a bare\n * \"Permissions error\" that covers two causes needing opposite remedies: a\n * consent grant the connection never got — nothing validates Meta's granted\n * scopes after connect, unlike HubSpot's `requireCapability` — or a role the\n * user lacks on one asset, since a Pixel/Dataset, Page or catalog lives in a\n * Business and is assigned separately from the ad account. Only the blast radius\n * separates them, so hand the agent that test rather than a verdict: guessing\n * \"reconnect\" wastes the user's time on an unassigned asset, and ruling it out\n * strands a connection that really is short a scope.\n */\nexport function metaForbiddenFix(message: string): QueryFix {\n return {\n action: \"reject\",\n explanation: [\n message,\n \"This is a permission refusal, not a dead connection, and Meta returns the same code for two causes with opposite remedies. Tell them apart by how much else works before you answer.\",\n \"If other reads on this account are ALSO refused (campaigns, ad sets, insights), the connection is short a permission it was never granted. Only the user can widen it, by reconnecting Meta from the dashboard.\",\n \"If those reads work and only this object is refused, the asset (pixel/dataset, Page, or catalog) belongs to a Business the connected user holds no role in. Ad-account access does not carry asset access and reconnecting cannot grant it — the client assigns that asset to the connected user or partner in Meta Business settings, under the asset's own section (Data sources → Datasets for a pixel).\",\n \"Either way do not retry the same call, and do not abort the wider job. Continue with what you can read, and state in your answer that this specific check could not run and why — never present the task as verified when this step was skipped.\",\n ].join(\"\\n\\n\"),\n };\n}\n\nexport function handleMetaError(err: unknown): never {\n if (err instanceof ApiError) {\n if (needsConnectionFix(err.code, err.message)) {\n handleConnectionError(\"meta_ads\", err.message);\n }\n const envelope: AdsErrorEnvelope = {\n ok: false,\n error: {\n code: err.code,\n message: err.message,\n fix: err.code === \"FORBIDDEN\" ? metaForbiddenFix(err.message) : { action: \"reject\", explanation: err.message },\n retryable: err.code === \"RATE_LIMITED\" || err.code === \"UNAVAILABLE\" || err.code === \"INTERNAL_ERROR\",\n },\n };\n writeAdsJson(envelope);\n process.exit(1);\n }\n const message = err instanceof Error ? err.message : \"Unexpected error\";\n writeAdsJson({ ok: false, error: { code: \"NETWORK_ERROR\", message } });\n process.exit(1);\n}\n\nconst ACCOUNT_ID_RE = /^(act_)?[0-9]+$/;\n\n/** Pull the default Meta ad account ID from `--account-id` arg or `BAKER_META_AD_ACCOUNT_ID` env. */\nexport function resolveAccountIdArg(args: Record<string, unknown>): string {\n const fromArgs = args[\"account-id\"] as string | undefined;\n const id = fromArgs || getEnv().BAKER_META_AD_ACCOUNT_ID;\n if (!id) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"MISSING_ACCOUNT_ID\",\n message: \"Pass --account-id or set BAKER_META_AD_ACCOUNT_ID. Run `baker ads meta accounts` to find IDs.\",\n },\n });\n process.exit(1);\n }\n if (!ACCOUNT_ID_RE.test(id)) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"INVALID_ACCOUNT_ID\",\n message: `Invalid account ID \"${id}\". Expected numeric ID, optionally prefixed with \"act_\".`,\n },\n });\n process.exit(1);\n }\n return id.startsWith(\"act_\") ? id : `act_${id}`;\n}\n\nexport function getDateRange(args: Record<string, unknown>): { datePreset?: string; since?: string; until?: string } {\n const datePreset = args[\"date-preset\"] as string | undefined;\n const since = args.since as string | undefined;\n const until = args.until as string | undefined;\n if (since && until) return { since, until };\n return { datePreset: datePreset ?? \"last_7d\" };\n}\n\nexport function todayIso(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nexport function daysAgoIso(days: number): string {\n return new Date(Date.now() - days * DAY_MS).toISOString().slice(0, 10);\n}\n\nexport function csvOrJson(args: Record<string, unknown>): string {\n return (args.output as string | undefined) ?? \"json\";\n}\n\n/**\n * Matched by Meta itself, so finding one entity by name reads only the rows that\n * match instead of the whole account.\n */\nexport const NAME_CONTAINS_ARG = {\n type: \"string\",\n description:\n \"Only rows whose name contains this text, matched by Meta before anything is returned. Start here to find one entity by name: --name-contains octubre --all-statuses\",\n} as const;\n\nexport const FIELDS_ARG = {\n type: \"string\",\n description:\n \"Comma-separated fields to print instead of the whole row; nested ones by dotted path. Pair with --name-contains: --fields id,name,adset_id,creative.id\",\n} as const;\n\n/**\n * The rows a campaigns/adsets/ads listing prints, plus the columns csv/md must\n * use. `--fields` keeps only the named paths, so a lookup prints a few hundred\n * bytes instead of every row's tracking and issue blocks.\n */\nexport function projectListRows(\n rows: Array<Record<string, unknown>>,\n args: Record<string, unknown>,\n): { rows: Array<Record<string, unknown>>; fields?: string[] } {\n const paths = parseFieldsArg(args.fields);\n return paths ? { rows: projectFields(rows, paths), fields: paths } : { rows };\n}\n\n/**\n * Default to ACTIVE-only on listings — that's almost always what an AI agent or\n * a human glance wants. Pass `--effective-status ACTIVE,PAUSED` to override, or\n * `--all-statuses` to drop the filter entirely.\n */\nexport function resolveEffectiveStatus(args: Record<string, unknown>): string | undefined {\n if (args[\"all-statuses\"]) {\n return undefined;\n }\n const explicit = args[\"effective-status\"] as string | undefined;\n if (explicit) {\n return explicit;\n }\n return \"ACTIVE\";\n}\n"],"mappings":"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","names":[]}
package/dist/cli.js CHANGED
@@ -69,17 +69,21 @@ import {
69
69
  validateCanvasDeep,
70
70
  withoutCastName,
71
71
  ytDlpBlockSignal
72
- } from "./chunk-AI4HWQVN.js";
72
+ } from "./chunk-K2IKLMCM.js";
73
73
  import {
74
+ FIELDS_ARG,
75
+ NAME_CONTAINS_ARG,
74
76
  csvOrJson,
75
77
  daysAgoIso,
76
78
  getDateRange,
77
79
  handleMetaError,
80
+ parseFieldsArg,
81
+ projectFields,
82
+ projectListRows,
78
83
  resolveAccountIdArg,
79
84
  resolveEffectiveStatus,
80
- statusFilterHints,
81
85
  todayIso
82
- } from "./chunk-L4QXAYIC.js";
86
+ } from "./chunk-WXSUOPOU.js";
83
87
  import {
84
88
  buildQueryCacheKey,
85
89
  cacheGet,
@@ -95,7 +99,7 @@ import {
95
99
  writeAdsJson,
96
100
  writeAdsOutput,
97
101
  writeJsonEnvelope
98
- } from "./chunk-FXVELNAS.js";
102
+ } from "./chunk-A2LM5EDF.js";
99
103
  import {
100
104
  ApiError,
101
105
  apiGet,
@@ -22999,27 +23003,6 @@ function compactRow(row) {
22999
23003
  ...destination.postUrn ? { postUrn: destination.postUrn } : {}
23000
23004
  };
23001
23005
  }
23002
- function readPath2(row, path48) {
23003
- let current = row;
23004
- for (const segment of path48.split(".")) {
23005
- const record = asRecord(current);
23006
- if (!record) return void 0;
23007
- current = record[segment];
23008
- }
23009
- return current;
23010
- }
23011
- function projectFields(rows, paths) {
23012
- return rows.map((row) => {
23013
- const projected = {};
23014
- for (const path48 of paths) {
23015
- const value = readPath2(row, path48);
23016
- if (value !== void 0) {
23017
- projected[path48] = value;
23018
- }
23019
- }
23020
- return projected;
23021
- });
23022
- }
23023
23006
  function unmappedShapeWarnings(rows, rawContentReturned) {
23024
23007
  const unmapped = rows.filter((row) => row.content && creativeDestination(row.content).format === "unknown");
23025
23008
  if (unmapped.length === 0) return [];
@@ -23033,12 +23016,9 @@ function unmappedShapeWarnings(rows, rawContentReturned) {
23033
23016
  }
23034
23017
  function shapeRows(rows, args5) {
23035
23018
  const raw = rows;
23036
- const fields = typeof args5.fields === "string" ? args5.fields : void 0;
23037
- if (fields) {
23038
- const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
23039
- if (paths.length > 0) {
23040
- return { rows: projectFields(raw, paths), fields: paths };
23041
- }
23019
+ const paths = parseFieldsArg(args5.fields);
23020
+ if (paths) {
23021
+ return { rows: projectFields(raw, paths), fields: paths };
23042
23022
  }
23043
23023
  if (args5.full) return { rows: raw };
23044
23024
  return { rows: rows.map(compactRow), fields: [...COMPACT_COLUMNS] };
@@ -26382,8 +26362,8 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
26382
26362
  run: async ({ args: args5 }) => {
26383
26363
  const { apiPost: apiPost2 } = await import("./client-3DGBQ2H3.js");
26384
26364
  const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
26385
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-AT5SRVH7.js");
26386
- const { handleMetaError: handleMetaError2 } = await import("./shared-HZ44PY2F.js");
26365
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-M2DBCZFG.js");
26366
+ const { handleMetaError: handleMetaError2 } = await import("./shared-3VVQPSFH.js");
26387
26367
  try {
26388
26368
  const accountId = bareAccountId2(args5);
26389
26369
  const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
@@ -26530,8 +26510,8 @@ function duplicateCommand2(entity, label) {
26530
26510
  run: async ({ args: args5 }) => {
26531
26511
  const { apiPost: apiPost2 } = await import("./client-3DGBQ2H3.js");
26532
26512
  const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
26533
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-AT5SRVH7.js");
26534
- const { handleMetaError: handleMetaError2 } = await import("./shared-HZ44PY2F.js");
26513
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-M2DBCZFG.js");
26514
+ const { handleMetaError: handleMetaError2 } = await import("./shared-3VVQPSFH.js");
26535
26515
  try {
26536
26516
  const accountId = bareAccountId2(args5);
26537
26517
  const chatId = requireChatId2();
@@ -26570,6 +26550,8 @@ var listArgs4 = {
26570
26550
  "campaign-id": { type: "string", description: "Filter to one campaign" },
26571
26551
  "effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
26572
26552
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
26553
+ "name-contains": NAME_CONTAINS_ARG,
26554
+ fields: FIELDS_ARG,
26573
26555
  limit: { type: "string", description: "Max rows (default 1000)" },
26574
26556
  "no-cache": NO_CACHE_ARG,
26575
26557
  output: { type: "string", description: "Output format", default: "json" }
@@ -26588,10 +26570,17 @@ var listCommand4 = defineCommand58({
26588
26570
  if (args5["adset-id"]) params["adset-id"] = args5["adset-id"];
26589
26571
  if (args5["campaign-id"]) params["campaign-id"] = args5["campaign-id"];
26590
26572
  if (effectiveStatus) params["effective-status"] = effectiveStatus;
26573
+ if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
26591
26574
  if (args5.limit) params.limit = args5.limit;
26592
26575
  if (args5["no-cache"]) params["skip-cache"] = "true";
26593
26576
  const data = await apiGet("/api/ads/meta/ads", params);
26594
- writeAdsOutput(data, csvOrJson(args5), void 0, statusFilterHints(data, effectiveStatus, "ads"));
26577
+ const { rows, fields } = projectListRows(data, args5);
26578
+ const fmt = csvOrJson(args5);
26579
+ if (fmt !== "json") {
26580
+ writeAdsOutput(rows, fmt, fields);
26581
+ return;
26582
+ }
26583
+ writeAdsJson({ ok: true, data: rows });
26595
26584
  } catch (err) {
26596
26585
  handleMetaError(err);
26597
26586
  }
@@ -26608,6 +26597,7 @@ The dashboard shows effective_status (e.g. WITH_ISSUES, PENDING_REVIEW, DISAPPRO
26608
26597
  Examples:
26609
26598
  baker ads meta ads --account-id act_123
26610
26599
  baker ads meta ads --adset-id 6123
26600
+ baker ads meta ads --account-id act_123 --all-statuses --name-contains octubre --fields id,name,adset_id,creative.id \u2014 find one ad by name
26611
26601
  baker ads meta ads create --name "Ad 1" --adset meta_temp_as01 --creative meta_temp_cr01
26612
26602
  baker ads meta ads pause 6123 --account-id act_123
26613
26603
  baker ads meta ads retag 6123 --set "utm_medium=paid-social" \u2014 fix tracking on a LIVE ad, keeping everything else`
@@ -26637,6 +26627,8 @@ var listArgs5 = {
26637
26627
  "campaign-id": { type: "string", description: "Filter to one campaign" },
26638
26628
  "effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
26639
26629
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
26630
+ "name-contains": NAME_CONTAINS_ARG,
26631
+ fields: FIELDS_ARG,
26640
26632
  limit: { type: "string", description: "Max rows (default 1000)" },
26641
26633
  "no-cache": NO_CACHE_ARG,
26642
26634
  output: { type: "string", description: "Output format", default: "json" }
@@ -26654,10 +26646,17 @@ var listCommand5 = defineCommand59({
26654
26646
  const params = { "account-id": accountId };
26655
26647
  if (args5["campaign-id"]) params["campaign-id"] = args5["campaign-id"];
26656
26648
  if (effectiveStatus) params["effective-status"] = effectiveStatus;
26649
+ if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
26657
26650
  if (args5.limit) params.limit = args5.limit;
26658
26651
  if (args5["no-cache"]) params["skip-cache"] = "true";
26659
26652
  const data = await apiGet("/api/ads/meta/adsets", params);
26660
- writeAdsOutput(data, csvOrJson(args5), void 0, statusFilterHints(data, effectiveStatus, "ad sets"));
26653
+ const { rows, fields } = projectListRows(data, args5);
26654
+ const fmt = csvOrJson(args5);
26655
+ if (fmt !== "json") {
26656
+ writeAdsOutput(rows, fmt, fields);
26657
+ return;
26658
+ }
26659
+ writeAdsJson({ ok: true, data: rows });
26661
26660
  } catch (err) {
26662
26661
  handleMetaError(err);
26663
26662
  }
@@ -26672,6 +26671,7 @@ Defaults to ACTIVE only. Write subcommands stage ops on this chat's draft.
26672
26671
  Examples:
26673
26672
  baker ads meta adsets --account-id act_123
26674
26673
  baker ads meta adsets --campaign-id 6123456789
26674
+ baker ads meta adsets --account-id act_123 --all-statuses --name-contains retargeting --fields id,name,campaign_id \u2014 find one ad set by name
26675
26675
  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`
26676
26676
  },
26677
26677
  subCommands: {
@@ -26783,6 +26783,8 @@ var listArgs7 = {
26783
26783
  "account-id": { type: "string", description: "Meta ad account ID" },
26784
26784
  "effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
26785
26785
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter and return everything" },
26786
+ "name-contains": NAME_CONTAINS_ARG,
26787
+ fields: FIELDS_ARG,
26786
26788
  limit: { type: "string", description: "Max rows (default 1000)" },
26787
26789
  "no-cache": NO_CACHE_ARG,
26788
26790
  output: { type: "string", description: "Output format", default: "json" }
@@ -26799,10 +26801,17 @@ var listCommand7 = defineCommand62({
26799
26801
  try {
26800
26802
  const params = { "account-id": accountId };
26801
26803
  if (effectiveStatus) params["effective-status"] = effectiveStatus;
26804
+ if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
26802
26805
  if (args5.limit) params.limit = args5.limit;
26803
26806
  if (args5["no-cache"]) params["skip-cache"] = "true";
26804
26807
  const data = await apiGet("/api/ads/meta/campaigns", params);
26805
- writeAdsOutput(data, csvOrJson(args5), void 0, statusFilterHints(data, effectiveStatus, "campaigns"));
26808
+ const { rows, fields } = projectListRows(data, args5);
26809
+ const fmt = csvOrJson(args5);
26810
+ if (fmt !== "json") {
26811
+ writeAdsOutput(rows, fmt, fields);
26812
+ return;
26813
+ }
26814
+ writeAdsJson({ ok: true, data: rows });
26806
26815
  } catch (err) {
26807
26816
  handleMetaError(err);
26808
26817
  }
@@ -26821,6 +26830,7 @@ The dashboard shows effective_status: ACTIVE, PAUSED, DELETED, ARCHIVED, IN_PROC
26821
26830
  Examples:
26822
26831
  baker ads meta campaigns --account-id act_123 # ACTIVE only
26823
26832
  baker ads meta campaigns --account-id act_123 --all-statuses # everything
26833
+ baker ads meta campaigns --account-id act_123 --all-statuses --name-contains Q3 --fields id,name,status # find one by name
26824
26834
  baker ads meta campaigns create --account-id act_123 --name "Q3" --objective OUTCOME_LEADS --daily-budget 50
26825
26835
  baker ads meta campaigns pause 6123 --account-id act_123`
26826
26836
  },