@koda-sl/baker-cli 0.377.0 → 0.378.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.
package/README.md CHANGED
@@ -905,6 +905,9 @@ baker ads meta leads --form-id 987654321 --full # raw conta
905
905
  baker ads meta campaigns --account-id act_123 # ACTIVE only by default
906
906
  baker ads meta ads --account-id act_123 --all-statuses # widen to everything
907
907
 
908
+ # "Find the October ad" — Meta matches the name, so only that row is read
909
+ baker ads meta ads --account-id act_123 --all-statuses --name-contains octubre --fields id,name,adset_id,creative_id
910
+
908
911
  # "Tell me about ad 9988"
909
912
  baker ads meta creatives --creative-id 9988
910
913
  baker ads meta preview --creative-id 9988 --ad-format MOBILE_FEED_STANDARD --out-file /tmp/p.html
@@ -984,6 +987,8 @@ Status changes are `pause|resume|archive` subcommands on `campaigns`/`adsets`/`a
984
987
 
985
988
  **Listing rows (`campaigns`/`adsets`/`ads`/`activities`)** print a table of compact rows by default — the fields you decide with (id, name, `effective_status`, budgets, goal; for activities who/when/what and a one-line `change`). `--fields a,b.c` returns exactly those dotted paths, `--full` returns every field Meta sent (targeting, tracking specs, raw `extra_data`), and `--output json` returns the rows in the `{ ok, data }` envelope.
986
989
 
990
+ To find one entity by name, pass `--name-contains <text>` to `campaigns`, `adsets` or `ads`: Meta matches it server-side (case-insensitive), so only the matching rows are read instead of the whole account.
991
+
987
992
  **Pagination** is auto-drained (no manual cursor handling).
988
993
 
989
994
  #### Full command surface
@@ -87,6 +87,10 @@ function daysAgoIso(days) {
87
87
  function csvOrJson(args) {
88
88
  return args.output ?? "json";
89
89
  }
90
+ var NAME_CONTAINS_ARG = {
91
+ type: "string",
92
+ 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"
93
+ };
90
94
  function resolveEffectiveStatus(args) {
91
95
  if (args["all-statuses"]) {
92
96
  return void 0;
@@ -117,7 +121,8 @@ export {
117
121
  todayIso,
118
122
  daysAgoIso,
119
123
  csvOrJson,
124
+ NAME_CONTAINS_ARG,
120
125
  resolveEffectiveStatus,
121
126
  statusFilterHints
122
127
  };
123
- //# sourceMappingURL=chunk-WKGKDYX3.js.map
128
+ //# sourceMappingURL=chunk-VLUGGVJL.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/ads/meta/shared.ts"],"sourcesContent":["import { ApiError } from \"../../../client.ts\";\nimport { getEnv } from \"../../../env.ts\";\nimport { handleConnectionError, needsConnectionFix } from \"../../../error-handler.ts\";\nimport { writeAdsJson } from \"../output.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 * 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\n/**\n * An empty listing under a status filter reads exactly like \"nothing exists\":\n * a paused campaign's ad sets are CAMPAIGN_PAUSED, so the ACTIVE default hides\n * every one of them. Say which filter produced the empty list and how to widen it.\n */\nexport function statusFilterHints(\n rows: ReadonlyArray<unknown>,\n effectiveStatus: string | undefined,\n noun: string,\n): string[] {\n if (rows.length > 0 || effectiveStatus === undefined) return [];\n if (effectiveStatus === \"ACTIVE\") {\n return [\n `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.`,\n ];\n }\n return [\n `No ${noun} with effective_status ${effectiveStatus}. Re-run with --all-statuses to see every status before concluding there are none.`,\n ];\n}\n"],"mappings":";;;;;;;;;;;;;AAMA,IAAM,SAAS;AAaR,SAAS,iBAAiB,SAA2B;AAC1D,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,aAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,MAAM;AAAA,EACf;AACF;AAEO,SAAS,gBAAgB,KAAqB;AACnD,MAAI,eAAe,UAAU;AAC3B,QAAI,mBAAmB,IAAI,MAAM,IAAI,OAAO,GAAG;AAC7C,4BAAsB,YAAY,IAAI,OAAO;AAAA,IAC/C;AACA,UAAM,WAA6B;AAAA,MACjC,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM,IAAI;AAAA,QACV,SAAS,IAAI;AAAA,QACb,KAAK,IAAI,SAAS,cAAc,iBAAiB,IAAI,OAAO,IAAI,EAAE,QAAQ,UAAU,aAAa,IAAI,QAAQ;AAAA,QAC7G,WAAW,IAAI,SAAS,kBAAkB,IAAI,SAAS,iBAAiB,IAAI,SAAS;AAAA,MACvF;AAAA,IACF;AACA,iBAAa,QAAQ;AACrB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAa,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,iBAAiB,QAAQ,EAAE,CAAC;AACrE,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,gBAAgB;AAGf,SAAS,oBAAoB,MAAuC;AACzE,QAAM,WAAW,KAAK,YAAY;AAClC,QAAM,KAAK,YAAY,OAAO,EAAE;AAChC,MAAI,CAAC,IAAI;AACP,iBAAa;AAAA,MACX,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,CAAC,cAAc,KAAK,EAAE,GAAG;AAC3B,iBAAa;AAAA,MACX,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS,uBAAuB,EAAE;AAAA,MACpC;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO,GAAG,WAAW,MAAM,IAAI,KAAK,OAAO,EAAE;AAC/C;AAEO,SAAS,aAAa,MAAwF;AACnH,QAAM,aAAa,KAAK,aAAa;AACrC,QAAM,QAAQ,KAAK;AACnB,QAAM,QAAQ,KAAK;AACnB,MAAI,SAAS,MAAO,QAAO,EAAE,OAAO,MAAM;AAC1C,SAAO,EAAE,YAAY,cAAc,UAAU;AAC/C;AAEO,SAAS,WAAmB;AACjC,UAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAC7C;AAEO,SAAS,WAAW,MAAsB;AAC/C,SAAO,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACvE;AAEO,SAAS,UAAU,MAAuC;AAC/D,SAAQ,KAAK,UAAiC;AAChD;AAOO,SAAS,uBAAuB,MAAmD;AACxF,MAAI,KAAK,cAAc,GAAG;AACxB,WAAO;AAAA,EACT;AACA,QAAM,WAAW,KAAK,kBAAkB;AACxC,MAAI,UAAU;AACZ,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOO,SAAS,kBACd,MACA,iBACA,MACU;AACV,MAAI,KAAK,SAAS,KAAK,oBAAoB,OAAW,QAAO,CAAC;AAC9D,MAAI,oBAAoB,UAAU;AAChC,WAAO;AAAA,MACL,aAAa,IAAI;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM,IAAI,0BAA0B,eAAe;AAAA,EACrD;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/commands/ads/meta/shared.ts"],"sourcesContent":["import { ApiError } from \"../../../client.ts\";\nimport { getEnv } from \"../../../env.ts\";\nimport { handleConnectionError, needsConnectionFix } from \"../../../error-handler.ts\";\nimport { writeAdsJson } from \"../output.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\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\n/**\n * An empty listing under a status filter reads exactly like \"nothing exists\":\n * a paused campaign's ad sets are CAMPAIGN_PAUSED, so the ACTIVE default hides\n * every one of them. Say which filter produced the empty list and how to widen it.\n */\nexport function statusFilterHints(\n rows: ReadonlyArray<unknown>,\n effectiveStatus: string | undefined,\n noun: string,\n): string[] {\n if (rows.length > 0 || effectiveStatus === undefined) return [];\n if (effectiveStatus === \"ACTIVE\") {\n return [\n `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.`,\n ];\n }\n return [\n `No ${noun} with effective_status ${effectiveStatus}. Re-run with --all-statuses to see every status before concluding there are none.`,\n ];\n}\n"],"mappings":"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","names":[]}
package/dist/cli.js CHANGED
@@ -72,6 +72,7 @@ import {
72
72
  ytDlpBlockSignal
73
73
  } from "./chunk-FGHMWBUD.js";
74
74
  import {
75
+ NAME_CONTAINS_ARG,
75
76
  csvOrJson,
76
77
  daysAgoIso,
77
78
  getDateRange,
@@ -80,7 +81,7 @@ import {
80
81
  resolveEffectiveStatus,
81
82
  statusFilterHints,
82
83
  todayIso
83
- } from "./chunk-WKGKDYX3.js";
84
+ } from "./chunk-VLUGGVJL.js";
84
85
  import {
85
86
  buildQueryCacheKey,
86
87
  cacheGet,
@@ -26835,7 +26836,7 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
26835
26836
  const { apiPost: apiPost2 } = await import("./client-GR6YL3YX.js");
26836
26837
  const { requireChatId: requireChatId2 } = await import("./env-4P5HOGNA.js");
26837
26838
  const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-NMQXZF3Z.js");
26838
- const { handleMetaError: handleMetaError2 } = await import("./shared-VAA3SCQR.js");
26839
+ const { handleMetaError: handleMetaError2 } = await import("./shared-J7DQZ2ED.js");
26839
26840
  try {
26840
26841
  const accountId = bareAccountId2(args5);
26841
26842
  const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
@@ -26983,7 +26984,7 @@ function duplicateCommand2(entity, label) {
26983
26984
  const { apiPost: apiPost2 } = await import("./client-GR6YL3YX.js");
26984
26985
  const { requireChatId: requireChatId2 } = await import("./env-4P5HOGNA.js");
26985
26986
  const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-NMQXZF3Z.js");
26986
- const { handleMetaError: handleMetaError2 } = await import("./shared-VAA3SCQR.js");
26987
+ const { handleMetaError: handleMetaError2 } = await import("./shared-J7DQZ2ED.js");
26987
26988
  try {
26988
26989
  const accountId = bareAccountId2(args5);
26989
26990
  const chatId = requireChatId2();
@@ -27022,6 +27023,7 @@ var listArgs5 = {
27022
27023
  "campaign-id": { type: "string", description: "Filter to one campaign" },
27023
27024
  "effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
27024
27025
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
27026
+ "name-contains": NAME_CONTAINS_ARG,
27025
27027
  limit: { type: "string", description: "Max rows (default 1000)" },
27026
27028
  "no-cache": NO_CACHE_ARG,
27027
27029
  ...META_LIST_SHAPE_ARGS
@@ -27045,6 +27047,7 @@ var listCommand4 = defineCommand58({
27045
27047
  if (args5["adset-id"]) params["adset-id"] = args5["adset-id"];
27046
27048
  if (args5["campaign-id"]) params["campaign-id"] = args5["campaign-id"];
27047
27049
  if (effectiveStatus) params["effective-status"] = effectiveStatus;
27050
+ if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
27048
27051
  if (args5.limit) params.limit = args5.limit;
27049
27052
  if (args5["no-cache"]) params["skip-cache"] = "true";
27050
27053
  const data = await apiGet("/api/ads/meta/ads", params);
@@ -27070,6 +27073,7 @@ preview_shareable_link); --full returns every field; --output json returns the r
27070
27073
  Examples:
27071
27074
  baker ads meta ads --account-id act_123
27072
27075
  baker ads meta ads --adset-id 6123
27076
+ 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
27073
27077
  baker ads meta ads --adset-id 6123 --fields id,name,preview_shareable_link
27074
27078
  baker ads meta ads create --name "Ad 1" --adset meta_temp_as01 --creative meta_temp_cr01
27075
27079
  baker ads meta ads pause 6123 --account-id act_123
@@ -27100,6 +27104,7 @@ var listArgs6 = {
27100
27104
  "campaign-id": { type: "string", description: "Filter to one campaign" },
27101
27105
  "effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
27102
27106
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
27107
+ "name-contains": NAME_CONTAINS_ARG,
27103
27108
  limit: { type: "string", description: "Max rows (default 1000)" },
27104
27109
  "no-cache": NO_CACHE_ARG,
27105
27110
  ...META_LIST_SHAPE_ARGS
@@ -27122,6 +27127,7 @@ var listCommand5 = defineCommand59({
27122
27127
  const params = { "account-id": accountId };
27123
27128
  if (args5["campaign-id"]) params["campaign-id"] = args5["campaign-id"];
27124
27129
  if (effectiveStatus) params["effective-status"] = effectiveStatus;
27130
+ if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
27125
27131
  if (args5.limit) params.limit = args5.limit;
27126
27132
  if (args5["no-cache"]) params["skip-cache"] = "true";
27127
27133
  const data = await apiGet("/api/ads/meta/adsets", params);
@@ -27145,6 +27151,7 @@ is not in the compact row \u2014 ask for it with --fields (dotted paths) or --fu
27145
27151
  Examples:
27146
27152
  baker ads meta adsets --account-id act_123
27147
27153
  baker ads meta adsets --campaign-id 6123456789
27154
+ baker ads meta adsets --account-id act_123 --all-statuses --name-contains retargeting \u2014 find one ad set by name
27148
27155
  baker ads meta adsets --campaign-id 6123456789 --fields id,name,targeting.geo_locations
27149
27156
  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`
27150
27157
  },
@@ -27257,6 +27264,7 @@ var listArgs8 = {
27257
27264
  "account-id": { type: "string", description: "Meta ad account ID" },
27258
27265
  "effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
27259
27266
  "all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter and return everything" },
27267
+ "name-contains": NAME_CONTAINS_ARG,
27260
27268
  limit: { type: "string", description: "Max rows (default 1000)" },
27261
27269
  "no-cache": NO_CACHE_ARG,
27262
27270
  ...META_LIST_SHAPE_ARGS
@@ -27278,6 +27286,7 @@ var listCommand7 = defineCommand62({
27278
27286
  try {
27279
27287
  const params = { "account-id": accountId };
27280
27288
  if (effectiveStatus) params["effective-status"] = effectiveStatus;
27289
+ if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
27281
27290
  if (args5.limit) params.limit = args5.limit;
27282
27291
  if (args5["no-cache"]) params["skip-cache"] = "true";
27283
27292
  const data = await apiGet("/api/ads/meta/campaigns", params);
@@ -27305,6 +27314,7 @@ Listings print a table by default: id, name, effective_status, daily/lifetime bu
27305
27314
  Examples:
27306
27315
  baker ads meta campaigns --account-id act_123 # ACTIVE only
27307
27316
  baker ads meta campaigns --account-id act_123 --all-statuses # everything
27317
+ baker ads meta campaigns --account-id act_123 --all-statuses --name-contains Q3 # find one by name
27308
27318
  baker ads meta campaigns --account-id act_123 --fields id,name,objective,bid_strategy,special_ad_categories
27309
27319
  baker ads meta campaigns --account-id act_123 --output json # rows as JSON
27310
27320
  baker ads meta campaigns create --account-id act_123 --name "Q3" --objective OUTCOME_LEADS --daily-budget 50