@koda-sl/baker-cli 0.353.0-dev.f5f2d3146 → 0.354.0-dev.7687bbeae

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
@@ -238,10 +238,6 @@ baker ads google query --preset campaign-performance --customer-id 1234567890
238
238
  # its target instead of holding its recent actual cost, so a target above actual raises cost.
239
239
  baker ads google query --preset budget-limited --customer-id 1234567890
240
240
 
241
- # Which target each ad group actually bids to: its own, or its campaign's / portfolio's.
242
- # A campaign or portfolio target change does not reach an ad group whose source is AD_GROUP.
243
- baker ads google query --preset bid-targets --customer-id 1234567890
244
-
245
241
  # Include paused entities too (default is serving-only)
246
242
  baker ads google query --preset ad-copy-performance --customer-id 1234567890 --include-paused
247
243
 
@@ -700,7 +696,7 @@ Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remo
700
696
 
701
697
  **Retiring a conversion action** — `status` accepts `ENABLED` and `REMOVED` only. Google denies `HIDDEN` on every conversion-action write, so to stop bidding toward an action while it keeps measuring use `--no-primary`, and to stop it counting at all use `"status": "REMOVED"`. Conversion actions **Google owns** cannot be changed at all — Smart campaign call/directions actions, the in-ad lead form's submit, YouTube subscriptions and follow-on views, Floodlight and Search Ads 360 imports, store visits, codeless webpage actions. Staging any edit to one, a rename included, is refused up front; there is no manual route either, since the Google Ads interface will not change them.
702
698
 
703
- **Reviewing the draft** — `baker ads google draft list` renders everything you've staged as a grouped campaign ▸ ad group ▸ ad tree (with non-blocking completeness advisories), the CLI counterpart to the dashboard's Google Ads tab. Pass `--json` for the raw envelope. Once the chat has published it reports the outcome instead — `published · N applied, M failed`, with a `✗` line naming each op that did not land and why. Aim for a fully built campaign — 2–4 ad groups, ≥5 keywords each, 2–4 RSAs with 8–12 headlines, ≥4 sitelinks / ≥3 callouts / ≥1 structured snippet, and ≥1 shared negative list; the advisories flag what's still thin.
699
+ **Reviewing the draft** — `baker ads google draft list` renders everything you've staged as a grouped campaign ▸ ad group ▸ ad tree (with non-blocking completeness advisories), the CLI counterpart to the dashboard's Google Ads tab. Pass `--json` for the raw envelope. Once the chat has published it reports the outcome instead — `published · N applied, M failed`, with a `✗` line naming each op that did not land and why — and every row reads what Google did and the status it left, `Created · Paused`, `Failed to create` or `Created · Enabled · 1 change failed` when a keyword under it did not land, where before publish it reads `Creating · Paused`. Aim for a fully built campaign — 2–4 ad groups, ≥5 keywords each, 2–4 RSAs with 8–12 headlines, ≥4 sitelinks / ≥3 callouts / ≥1 structured snippet, and ≥1 shared negative list; the advisories flag what's still thin.
704
700
 
705
701
  **Amending a staged op** — `draft amend <ref> (--file patch.json | --patch '<json>')` merges a JSON patch into an already-staged op's payload (objects deep-merge, `null` deletes a key, arrays/scalars replace) and re-validates it in full. Always prefer this over removing and re-staging — it preserves the op's ref (so dependents don't break) and its position in the draft. `draft show <ref>` prints the full staged payload (including warnings/annotations) so you can verify a change looks right before publish.
706
702
 
package/dist/cli.js CHANGED
@@ -3569,7 +3569,10 @@ var googleDraftStatusNodeSchema = z6.lazy(
3569
3569
  existing: z6.boolean(),
3570
3570
  collections: z6.array(googleDraftStatusCollectionSchema),
3571
3571
  children: z6.array(googleDraftStatusNodeSchema),
3572
- warnings: z6.array(z6.string()).optional()
3572
+ warnings: z6.array(z6.string()).optional(),
3573
+ result: googleDraftOpResultSchema.shape.status.optional(),
3574
+ foldedNotApplied: z6.object({ failed: z6.number(), skipped: z6.number() }).optional(),
3575
+ status: z6.string().optional()
3573
3576
  })
3574
3577
  );
3575
3578
  var googleDraftListResponseSchema = z6.object({
@@ -9184,13 +9187,6 @@ var FIELD_DESCRIPTIONS = {
9184
9187
  "ad_group.name": "Ad group display name",
9185
9188
  "ad_group.status": "ENABLED, PAUSED, or REMOVED",
9186
9189
  "ad_group.type": "Ad group type (SEARCH_STANDARD, DISPLAY_STANDARD, etc.)",
9187
- "ad_group.target_roas": "This ad group's own target ROAS (ratio), overriding its campaign's and portfolio's; 0 or omitted = none",
9188
- "ad_group.effective_target_roas": "The target ROAS this ad group actually bids to, from whichever level sets it",
9189
- "ad_group.effective_target_roas_source": "Which level the effective target ROAS comes from: AD_GROUP (its own \u2014 a campaign or portfolio change does not reach it) or CAMPAIGN_BIDDING_STRATEGY (the campaign's strategy, its own or a portfolio)",
9190
- "ad_group.target_cpa_micros": "This ad group's own target CPA in micros, overriding its campaign's and portfolio's; 0 or omitted = none",
9191
- "ad_group.effective_target_cpa_micros": "The target CPA (micros) this ad group actually bids to",
9192
- "ad_group.effective_target_cpa_source": "Which level the effective target CPA comes from: AD_GROUP (its own \u2014 a campaign or portfolio change does not reach it) or CAMPAIGN_BIDDING_STRATEGY (the campaign's strategy, its own or a portfolio)",
9193
- "campaign.bidding_strategy": "Resource name of the portfolio bidding strategy the campaign uses; blank = its own strategy",
9194
9190
  // Ad group ad
9195
9191
  "ad_group_ad.ad.id": "Unique ad identifier",
9196
9192
  "ad_group_ad.ad.final_urls": "Landing page URLs (array)",
@@ -11048,14 +11044,44 @@ var OPERATION_LABELS = {
11048
11044
  update: "Updating",
11049
11045
  pause: "Pausing",
11050
11046
  resume: "Resuming",
11051
- remove: "Removing"
11047
+ remove: "Removing",
11048
+ upload: "Uploading"
11052
11049
  };
11053
- function badge(node) {
11054
- const label = node.operation ? OPERATION_LABELS[node.operation] : void 0;
11055
- if (label) {
11056
- return label;
11050
+ var APPLIED_LABELS = {
11051
+ create: "Created",
11052
+ update: "Updated",
11053
+ pause: "Paused",
11054
+ resume: "Resumed",
11055
+ remove: "Removed",
11056
+ upload: "Uploaded"
11057
+ };
11058
+ function notAppliedText(node) {
11059
+ const { failed = 0, skipped = 0 } = node.foldedNotApplied ?? {};
11060
+ const changes = (n) => `${n} change${n === 1 ? "" : "s"}`;
11061
+ const parts = [
11062
+ ...failed > 0 ? [`${changes(failed)} failed`] : [],
11063
+ ...skipped > 0 ? [`${changes(skipped)} skipped`] : []
11064
+ ];
11065
+ return parts.length > 0 ? parts.join(", ") : void 0;
11066
+ }
11067
+ function outcomeBadge(node, result) {
11068
+ const verb = node.operation ?? "update";
11069
+ if (result === "applied") {
11070
+ return node.operation ? APPLIED_LABELS[verb] ?? "Applied" : "Changes applied";
11057
11071
  }
11058
- return node.existing ? "on Google Ads" : "staged";
11072
+ if (result === "simulated") {
11073
+ return `Simulated (${verb})`;
11074
+ }
11075
+ if (result === "failed") {
11076
+ return node.operation ? `Failed to ${verb}` : "Failed";
11077
+ }
11078
+ return "Skipped";
11079
+ }
11080
+ function badge(node) {
11081
+ const label = node.result ? outcomeBadge(node, node.result) : (node.operation ? OPERATION_LABELS[node.operation] : void 0) ?? (node.existing ? "on Google Ads" : "staged");
11082
+ const parts = [label, ...node.status && node.status !== label ? [node.status] : []];
11083
+ const notApplied = notAppliedText(node);
11084
+ return [...parts, ...notApplied ? [notApplied] : []].join(" \xB7 ");
11059
11085
  }
11060
11086
  function collectionLine(collection) {
11061
11087
  const parts = [];
@@ -11454,7 +11480,7 @@ var draftCommand2 = defineCommand22({
11454
11480
  list: defineCommand22({
11455
11481
  meta: {
11456
11482
  name: "list",
11457
- description: "Review everything staged as a campaign \u25B8 ad group \u25B8 ad tree (--json for the raw envelope)"
11483
+ description: "Review everything staged as a campaign \u25B8 ad group \u25B8 ad tree, each row with its status; after publish each row says what Google did (Created / Failed to create) (--json for the raw envelope)"
11458
11484
  },
11459
11485
  args: {
11460
11486
  json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable tree" },
@@ -12044,18 +12070,6 @@ var PRESETS = [
12044
12070
  defaultLimit: 200,
12045
12071
  statusFields: ["campaign.status"]
12046
12072
  },
12047
- {
12048
- // A target resolves ad group > campaign > portfolio strategy, so the campaign's or the portfolio's
12049
- // number is not necessarily the one bidding. `effective_target_*_source` names the level that is;
12050
- // a change staged anywhere else is inert for that ad group. Undated on purpose: an ad group that
12051
- // spent nothing in the window still carries its own target, and a dated read would drop its row.
12052
- name: "bid-targets",
12053
- description: "Which target each ad group actually bids to \u2014 its own target ROAS / CPA, the effective one and the level it comes from. Read it before changing any target: a campaign or portfolio change does not reach an ad group whose source is AD_GROUP",
12054
- gaqlTemplate: `SELECT campaign.id, campaign.name, campaign.status, campaign.bidding_strategy_type, campaign.bidding_strategy, ad_group.id, ad_group.name, ad_group.status, ad_group.target_roas, ad_group.effective_target_roas, ad_group.effective_target_roas_source, ad_group.target_cpa_micros, ad_group.effective_target_cpa_micros, ad_group.effective_target_cpa_source FROM ad_group WHERE campaign.bidding_strategy_type IN ('TARGET_ROAS', 'TARGET_CPA', 'MAXIMIZE_CONVERSION_VALUE', 'MAXIMIZE_CONVERSIONS'){statusScope} ORDER BY campaign.name LIMIT {limit}`,
12055
- defaultDateRange: "ALL_TIME",
12056
- defaultLimit: 200,
12057
- statusFields: ["campaign.status", "ad_group.status"]
12058
- },
12059
12073
  {
12060
12074
  name: "conversions-by-action",
12061
12075
  description: "Which conversion action each campaign's conversions actually are \u2014 the read that says whether two campaigns' conversion rates are measuring the same event",