@koda-sl/baker-cli 0.187.0-dev.720190ec6 → 0.188.0-dev.c3208f911

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
@@ -491,7 +491,7 @@ baker ads google keywords metrics --customer-id 1234567890 --keywords "running s
491
491
 
492
492
  ### Staged writes (`baker ads google budgets|campaigns|...`)
493
493
 
494
- Write commands **never touch the Google Ads API at stage time**. Each command stages a create/update/pause/resume/remove op against the current chat's draft (`BAKER_CHAT_ID`); the dashboard shows it as a pending "Google Ads" change, and the whole draft applies as one atomic `GoogleAdsService.Mutate` when the chat is published. Feature-flagged per company (`companies.googleAdsWriteEnabled`) — off by default = a fully simulated publish with zero real API calls.
494
+ Write commands **never touch the Google Ads API at stage time**. Each command stages a create/update/pause/resume/remove op against the current chat's draft (`BAKER_CHAT_ID`); the dashboard shows it as a pending "Google Ads" change, and the whole draft applies as one atomic `GoogleAdsService.Mutate` when the chat is published. **That publish reaches the real account for every company**Google Ads writes are generally available, with no per-company flag to turn them on or off. Discarding the chat before it completes is what undoes a staged change.
495
495
 
496
496
  Reference not-yet-created resources with `g_temp_*` refs returned by earlier `create` commands (they map to Google's temporary negative-ID resource names inside one atomic batch).
497
497
 
@@ -596,7 +596,7 @@ baker actions draft --chat <chat-id>
596
596
 
597
597
  Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remove), `negative-keywords`, `keyword-lists`, `ads`, `assets` (create/update/attach/detach), `asset-groups` (create/update/attach/detach — Performance Max), `audiences`, `conversions` (create/update/goal), `bidding-strategies`, `labels`, `campaign-criteria` (add/update/remove), and `draft`. Amounts are in major currency units (converted to micros). Money/bids: `--amount`, `--cpc-bid`, `--target-cpa`, `--max-cpc` take major units; `--target-roas` a ratio. `--max-cpc` sets the max CPC bid ceiling for `TARGET_IMPRESSION_SHARE` / `TARGET_SPEND` / `PERCENT_CPC` and must be paired with `--bidding-strategy`. Less-common ops accept a `--file <payload.json>` (flags override file keys). Updates target a resource name or bare id as the positional argument; a target that names an op staged earlier **amends it in place**.
598
598
 
599
- **Device targeting is adjusted, never added or removed** — Google keeps a criterion for every device on every campaign, so `campaign-criteria remove` on one is rejected (and refused before publish). Use `campaign-criteria update customers/<cid>/campaignCriteria/<campaignId>~<criterionId> --bid-modifier <n>`: `1` for no adjustment, `1.25` to bid 25% more, `0.9` to bid 10% less, `0` to stop serving on that device. Locations, languages and ad schedules remove normally.
599
+ **A device criterion can be added, but never removed** — `campaign-criteria add` with a device criterion works, but Google then rejects `campaign-criteria remove` on it forever, including on a criterion you added yourself (and Baker refuses the removal before publish). Adjust it instead with `campaign-criteria update customers/<cid>/campaignCriteria/<campaignId>~<criterionId> --bid-modifier <n>`: `1` for no adjustment, `1.25` to bid 25% more, `0.9` to bid 10% less, `0` to stop serving on that device. Locations, languages and ad schedules remove normally.
600
600
 
601
601
  **Primary vs secondary conversion actions** — `conversions update <id> --primary` makes an action a primary action (automated bidding optimizes toward it); `--no-primary` (or `--primary=false`) demotes it to secondary (reported only) — the spaced form `--primary false` is rejected, since a boolean flag written with a space is set to true and the word dropped. `conversions create` stages a new action as **secondary** unless its `--file` payload sets `"primaryForGoal": true`, so a new action never silently joins the bidding target of a Maximize Conversions or Target CPA campaign. The staged card shows an "Action optimization" row with the before/after role.
602
602
 
@@ -604,7 +604,7 @@ Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remo
604
604
 
605
605
  **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.
606
606
 
607
- **Reviewing the draft** — `baker ads google draft list` renders everything you've staged as a grouped campaign ▸ ad group ▸ ad tree (with the simulated/live mode banner and non-blocking completeness advisories), the CLI counterpart to the dashboard's Google Ads tab. Pass `--json` for the raw envelope. 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.
607
+ **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. 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.
608
608
 
609
609
  **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.
610
610
 
@@ -2139,6 +2139,17 @@ baker images get j571abc123def
2139
2139
  baker images get j571abc123def --full
2140
2140
  ```
2141
2141
 
2142
+ ### `baker images group <id>`
2143
+
2144
+ List every image that arrived in the same set — the slides of one Instagram carousel, the images pulled off one scraped page. Carousel slides are authored to be read in order and usually only make sense together, so pull the set before using any one slide on its own.
2145
+
2146
+ ```bash
2147
+ baker images group j571abc123def
2148
+ baker images group --group-key "instagram:Cx7Ab9"
2149
+ ```
2150
+
2151
+ Returns the set's shared caption or page title, a link back to the original post/page, and the members in order — as both `images` and `videos`, since a carousel can mix stills and clips across the two libraries. Accepts an **image or a video id**, for the same reason: `baker videos group` is the same lookup from the other side.
2152
+
2142
2153
  ### `baker images upload <file|url>`
2143
2154
 
2144
2155
  Add an image to the library — accepts a **local file path** or a **remote `http(s)://` URL**. The positional arg is sniffed: if it starts with `http://` or `https://`, the call dispatches to `/api/images/ingest` (hash-deduped on bytes + externalId, byte-fetch happens server-side); otherwise the local file is read, base64-encoded, and sent to `/api/images/upload`.
@@ -2322,10 +2333,25 @@ Upload a video file via Mux direct upload.
2322
2333
  ```bash
2323
2334
  baker videos upload ./demo.mp4
2324
2335
  baker videos upload ./demo.mp4 --dry-run
2336
+ baker videos upload ./testimonial-maria.mp4 \
2337
+ --context "Testimonial from Maria, a real customer, filmed on her phone for the autumn campaign"
2325
2338
  ```
2326
2339
 
2327
2340
  Supported extensions: `.mp4`, `.mov`, `.webm`, `.avi`, `.mkv`
2328
2341
 
2342
+ `--context` describes what the clip is and what it's for. The analysis watches the frames and hears the audio, but it can't know which campaign a clip belongs to or whether the person on camera is a real customer or a hired actor — and those are what you'll search on later. The filename is sent automatically as a weaker hint.
2343
+
2344
+ ### `baker videos group <id>`
2345
+
2346
+ List every asset that arrived in the same set as this clip — the other slides of the Instagram post it came from, stills included. A carousel is authored to be read in order, so a clip lifted out of one is usually missing half its meaning.
2347
+
2348
+ ```bash
2349
+ baker videos group xd7abc123def
2350
+ baker videos group --group-key "instagram:Cx7Ab9"
2351
+ ```
2352
+
2353
+ Same lookup as `baker images group` and takes either kind of id; the two exist so the noun you happen to hold does not decide whether you can ask.
2354
+
2329
2355
  ### `baker videos delete <id>`
2330
2356
 
2331
2357
  Delete a video by ID.