@koda-sl/baker-cli 0.422.0 → 0.423.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
@@ -167,8 +167,11 @@ List the Google Ads accounts selected for this company. Run this first to find a
167
167
 
168
168
  ```bash
169
169
  baker ads google accounts
170
+ baker ads google accounts --available
170
171
  ```
171
172
 
173
+ `--available` lists every account the connected login reaches instead, each `{ id, name, selected }`. Read-only: it never changes the selection. When the account the user means comes back `selected: false`, the hint names it and points at `request_connection` with `pick: true`, which opens the account picker in the chat. The same flag works on `ads meta accounts`, `ads linkedin accounts`, `ads x accounts`, `ga4 properties`, `gsc sites` and `tag-manager containers`.
174
+
172
175
  **Response:**
173
176
 
174
177
  ```json
@@ -1364,6 +1367,7 @@ baker analytics tracking # do the ad URLs carry the campaign, a
1364
1367
  baker analytics tracking --platform meta # the same for one platform, read from their own ad account
1365
1368
  baker analytics map --platform google --set kw=keyword # name a parameter, seen or not yet
1366
1369
  baker analytics map --platform google --remove kw # take that answer back
1370
+ baker analytics unstage --kind mapping --ref google/kw # take back what this chat staged (mapping|conversion|send|source), or --all
1367
1371
  baker analytics conversions # what counts, what each produced, and which Forms count nothing
1368
1372
  baker analytics conversions --candidates --output md # everything these pages do, and which of it is counted, as tables
1369
1373
  baker analytics conversions --candidates # the same as compact JSON: one line per page event, Form keys folded onto `flows`
@@ -1536,6 +1540,26 @@ baker experiment fold # make the page
1536
1540
 
1537
1541
  **`plan` before building anything.** At a 3% conversion rate a +20% lift needs roughly 14,000 visitors *per variant*; `plan` says how long that is at this page's traffic, lists what this page's visitors actually went on to do, and what a 14, 28, 56 or 90-day window could settle. The duration is a guide and never a finish line — the test ends when the numbers are clear, and a page with no traffic yet still runs, sized on a stand-in that `warning` names (`--baseline 0.05` states the rate to expect). What `plan` refuses is what cannot be measured: no conversion defined, or a goal the page has demonstrably never produced. `--lift` sets the smallest lift worth detecting (default `0.2`) — halving it roughly quadruples the traffic needed.
1538
1542
 
1543
+ ### Site settings (`baker site`)
1544
+
1545
+ The company's site settings — cookie consent, what Baker records, whether search engines show the site, the home page, the time zone, the landing download format, and custom domains. Every change stages on the chat and applies when the chat is published; discarding the chat drops it.
1546
+
1547
+ ```bash
1548
+ baker site show # settings after this chat publishes, and what it staged (before/after)
1549
+ baker site set --consent recovery # bypass | recovery | strict | external
1550
+ baker site set --collection aggregate # full | aggregate | off (+ --payloads on|off with full)
1551
+ baker site set --indexing off # on | off
1552
+ baker site set --home oferta --home-mode redirect # a landing slug (rewrite by default), or --home none
1553
+ baker site set --timezone Europe/Madrid # IANA name
1554
+ baker site set --export-profile @profile.json # landing download format, JSON or @file
1555
+ baker site domain add shop.acme.com # staged; the client adds CNAME shop.acme.com → customers.withbaker.com
1556
+ baker site domain list # status of every domain: staged, pending_verification, active, error
1557
+ baker site domain verify shop.acme.com # re-check a pending domain now
1558
+ baker site unstage consent # take back one staged setting (or --all)
1559
+ ```
1560
+
1561
+ `set` takes several flags in one call and stages all of them or none. A staged setting that cannot apply at publish — a home page whose landing is not published yet, a domain another company registered in the meantime — is skipped with its reason on the chat's row and in `baker chats view` → `effects.siteSettings`; everything else in the chat still publishes.
1562
+
1539
1563
  ### Google Analytics 4 (`baker ga4`)
1540
1564
 
1541
1565
  GA4 commands for multi-channel audits **and** for configuring what the property measures. Playbook-aligned report presets, property health audits, free-form Data API queries, and staged Admin API writes.
@@ -2342,15 +2366,17 @@ Each external source is its own subcommand. Pick the verb that matches the sourc
2342
2366
  | `baker images get <id>` | Single record | n/a |
2343
2367
  | `baker images upload <file\|url>` | Upload a local file OR remote URL to the library | always on |
2344
2368
  | `baker images delete <id>` | Delete a record | n/a |
2369
+ | `baker images retry <id>` | Process a failed image (status `error`) again | n/a |
2345
2370
  | `baker images describe <id>` | Correct a record's stored name / description / tags | n/a |
2346
2371
  | `baker images normalize <files>` | Local recolor + bg removal + trim + resize | n/a (operates on disk, no upload) |
2347
- | `baker images upscale <imageId>` | Real-ESRGAN super-resolution via backend ($0.05/image, cost-tracked) | n/a (operates on library image) |
2372
+ | `baker images upscale <imageId>` | Real-ESRGAN super-resolution via backend ($0.05/image, cost-tracked). `--remove` drops the upscaled copy and goes back to the original (free) | n/a (operates on library image) |
2348
2373
  | `baker images layerize <imageId>` | Split into editable layers — transparent cutouts per element plus baked-in copy recovered as editable text (costs credits) | n/a (operates on library image) |
2349
2374
  | `baker images layers <imageId>` | Read the layers of an already-split image (free) | n/a (operates on library image) |
2350
2375
  | `baker images crop <file>` | Coordinate-based rectangular extract — local file or URL | n/a |
2351
2376
  | `baker images dimensions <file\|url>` | Read width / height / aspect / format without decoding | n/a |
2352
2377
  | `baker images download <targets>` | Remote URLs and/or library ids → local files, so the local transforms can read them | n/a (writes to disk, no upload) |
2353
2378
  | `baker images tags` | List available image tag names (defaults + company custom tags) | n/a |
2379
+ | `baker images tags create\|update\|delete <name>` | Manage the company's custom tags — one pool shared by images, videos and testimonials (also under `baker videos tags` / `baker testimonials tags`) | n/a |
2354
2380
 
2355
2381
  **Every image record carries `width` and `height`, without `--full`.** They are there to be passed straight to the component that places the image: a remote image rendered with no declared size makes the site build download the file purely to measure it, which is the only reason building a site needs the network at all — and a dropped connection there fails the entire quality-check run for a reason nothing on the page caused.
2356
2382
 
@@ -3087,6 +3113,10 @@ Baker's YouTube source sync runs this same command on a disposable machine, with
3087
3113
 
3088
3114
  Delete a video by ID.
3089
3115
 
3116
+ ### `baker videos retry <id>`
3117
+
3118
+ Process a video whose status is `error` again. When the upload itself never finished it answers `status: "error"` with a `message` saying the file has to be uploaded again.
3119
+
3090
3120
  ### `baker videos describe <id>`
3091
3121
 
3092
3122
  The same correction for a clip: fix the stored `name`, `description` or `tags` when the analysis read the video wrong. Only the flags you pass change, `--tags` replaces the whole set, and the search index rebuilds in the background.
@@ -3102,8 +3132,13 @@ List the available video tag names — built-in defaults plus the company's cust
3102
3132
 
3103
3133
  ```bash
3104
3134
  baker videos tags
3135
+ baker videos tags create "summer sale" --description "Assets for the summer sale campaign"
3136
+ baker videos tags update summer-sale --description "Assets for the 2026 summer sale"
3137
+ baker videos tags delete summer-sale
3105
3138
  ```
3106
3139
 
3140
+ `tags create|update|delete` manage the company's custom tags, one pool shared by images, videos and testimonials. Built-in tags cannot be changed. Like every library change from a chat, they apply immediately and are listed on the chat as already applied.
3141
+
3107
3142
  ### `baker testimonials search <query>`
3108
3143
 
3109
3144
  Semantic search testimonials. For landing pages, query the product/offer and USP before filtering by rating so selected quotes match what the landing sells.
@@ -3127,8 +3162,11 @@ The review pages testimonials are imported from — Google Maps, Trustpilot, Yel
3127
3162
  | `baker testimonials sources list` | Every source: id, site, status, reviews imported, auto-sync. |
3128
3163
  | `baker testimonials sources sync <id>` | Import new reviews now. |
3129
3164
  | `baker testimonials sources schedule <id> --every <interval>` | Set the auto-sync cadence. |
3165
+ | `baker testimonials sources reset <id>` | Unstick a source whose import never finished, so it can import again. Keeps its reviews. |
3130
3166
  | `baker testimonials sources remove <id>` | Remove the source and every testimonial it imported. |
3131
3167
 
3168
+ `baker testimonials delete <id> [--dry-run]` removes one testimonial (and the images it brought in) from the library. It applies immediately.
3169
+
3132
3170
  ```bash
3133
3171
  baker testimonials sources add https://www.trustpilot.com/review/acme.com
3134
3172
  baker testimonials sources add "Acme Bakery Madrid"
@@ -3265,6 +3303,7 @@ Connecting and removing apply immediately and show on the chat as an already-app
3265
3303
  | `baker media-sources list` | Every source: key, platform, label, auto-sync, and per library `{ status, stored, pending?, failed?, error? }`. |
3266
3304
  | `baker media-sources sync <key>` | Import new posts now. |
3267
3305
  | `baker media-sources schedule <key> --every <interval>` | Set the auto-sync cadence. |
3306
+ | `baker media-sources reset <key>` | Unstick a source whose import never finished, so it can sync again. Keeps what it imported. |
3268
3307
  | `baker media-sources remove <key>` | Disconnect; imported media stays in the library. |
3269
3308
 
3270
3309
  ```bash
@@ -3289,6 +3328,8 @@ Search the **ad-dna** corpus of scored "winning" competitor ads for reference cr
3289
3328
 
3290
3329
  > Replaces the old `baker ads google library` tree, which has been removed. Competitor-by-keyword discovery still lives at `baker research advertisers`.
3291
3330
 
3331
+ `baker winning-ads refresh <advertiserId>` re-scrapes a followed brand so its newest ads land in the library. It applies immediately and runs at most once every 6 hours per brand; inside that window it answers `RATE_LIMITED` with an `error.fix` naming when the brand can be refreshed again. While a follow or the last refresh is still collecting the brand's ads, it starts nothing and says so.
3332
+
3292
3333
  ### `baker winning-ads search <query>`
3293
3334
 
3294
3335
  Semantic search (dense recall + BM25 + rerank) → `POST /api/ad-library/winners/search`. The CLI projects each result to a **lean, decision-focused** shape so the agent's context stays small — default fields: `advertiser`, `advertiser_id`, `platform`, `format`, `relevance`, `winner_score`, `summary` (what the ad is about), `media_url`, and `visual` (what the viewer sees) + `container` (a static's layout pattern) + `mechanism` (why it works) when known; plus top-level `pool_size`, `match_confidence` (`high|medium|low`), and `below_floor_count` (matches dropped under the relevance floor). The proof signals ride along (`winner_category`, `days_active`, `active`), and so does who the ad was made for when the library knows it: `audience_temperature` (`0_cold|1_warm_engaged|2_hot_visited|3_customer`), `funnel_stage`, `advertiser_size`, and `presumes_brand_knowledge` (whether the copy only works on viewers who already know the brand, with `brand_knowledge_reason` when `true`; absent while the ad is not judged yet); `--full` adds DNA detail (`angle`, `target_persona`, `hook_archetype`, `awareness_stage`, `industry`) + `reach` and `media_kind`. By default the search draws from the brands the company follows first (`--scope followed-first`) and tops up from the shared library; every result says `source: followed|library`. `--output json` (default) returns the lean objects; `--output md` prints a table.
@@ -3547,13 +3588,14 @@ baker scheduled-agents templates --delete weekly-posthog-check
3547
3588
 
3548
3589
  Read the client's marketing/analytics tags (Meta pixel, ChatGPT Ads pixel, GA4, Google Ads, GTM, Clarity, Hotjar, PostHog, …) — production tags overlaid with the changes staged in this chat.
3549
3590
 
3550
- **The CLI is read-only.** Every tag change (create, edit, delete) goes through the `request_tag_input` tool (`baker_ui` MCP server): the agent proposes one or more changes — each becomes a tab in one blocking approval form — pre-filling the non-secret fields it knows; the user reviews, edits, fills secret fields, and approves or skips each tab. Approved changes stage on the chat and apply when the chat is published; discarding the chat drops them.
3591
+ **The CLI never creates or edits a tag.** Every tag change (create, edit, delete) goes through the `request_tag_input` tool (`baker_ui` MCP server): the agent proposes one or more changes — each becomes a tab in one blocking approval form — pre-filling the non-secret fields it knows; the user reviews, edits, fills secret fields, and approves or skips each tab. Approved changes stage on the chat and apply when the chat is published; discarding the chat drops them.
3551
3592
 
3552
3593
  `BAKER_CHAT_ID` must be set.
3553
3594
 
3554
3595
  ```bash
3555
3596
  baker tags list # effective view: production + staged, full readable config + secret status
3556
3597
  baker tags draft # review the staged changes awaiting publish
3598
+ baker tags unstage tag_temp_abc123 # take back one change this chat staged (or --all)
3557
3599
  ```
3558
3600
 
3559
3601
  Notes:
@@ -3563,7 +3605,7 @@ Notes:
3563
3605
  - **Secrets never travel through this CLI or the chat.** Secret fields (`accessToken`, `apiSecret`, `authorizationToken`, `apiKey`, `conversionToken`, `oauthProviderId`) are entered only in the dashboard's secure tag form and flow straight into the staged draft; tool responses only ever name which secret fields are set/pending.
3564
3606
  - A `chatgptAds` tag takes a Pixel ID. Its optional `apiKey` is the Conversions API key and enables the server copy of page and Form events; the key stays out of the CLI and published page.
3565
3607
  - Staged creates get a server-generated `tag_temp_*` ref (returned in the tool result and printed by `list`). Use it (or a real tag id) as flow side-effect `tagIds` — the published tag keeps resolving under the temp ref.
3566
- - Proposing a delete on a `tag_temp_*` ref drops the staged create instead.
3608
+ - **`unstage` is the one write.** It takes back a change this chat staged — the same as discarding the row in the change review — by the ref `draft` prints, or `--all`. It carries no config and no secret, never touches a live tag, and refuses a ref nothing is staged under. Taking back a staged create drops the secrets entered for it with it.
3567
3609
  - Single-instance types (`code`, `posthog`, `datafast`) reject a second instance against the chat's effective view.
3568
3610
  - Conflicts at publish (tag deleted in the dashboard, config invalid) skip the op with a recorded reason — they never block the publish.
3569
3611
 
@@ -3681,10 +3723,17 @@ baker actions complete <action-id-or-tempId> --note "What was done" # stages
3681
3723
  # --note is REQUIRED (≥20 chars): what changed, where, and the outcome. It is the durable, client-facing
3682
3724
  # record surfaced by `baker actions log`. A missing/too-short note is rejected with a VALIDATION_ERROR.
3683
3725
  baker actions discard <action-id> --reason "obsolete"
3726
+ baker actions reopen <action-id> # stages — a completed Task goes back to the backlog on publish
3727
+
3728
+ # Assigning — staged, applies on publish. --to is a userId or email from `members`, or `none`
3729
+ baker actions members # teammates a Task can be handed to (freelancers hidden unless you are a superadmin)
3730
+ baker actions assign <id-or-tempId> --to maria@empresa.com
3731
+ baker actions assign <id> --to none # unassign
3684
3732
 
3685
3733
  # Tags — taxonomy is built-in defaults + company custom tags; --tags is STRICT (unknown slugs are rejected)
3686
3734
  baker actions tags list # available tags (defaults + company custom); errors → stderr (inline-safe)
3687
3735
  baker actions tags create --slug pmax --description "Performance Max work" # mint a custom tag
3736
+ baker actions tags update --slug pmax --description "Performance Max campaigns" # what it means; applies at once
3688
3737
  baker actions tags delete --slug pmax # remove a custom tag (default tags can't be deleted)
3689
3738
 
3690
3739
  baker actions link --blocker <id-or-tempId> --blocked <id-or-tempId>
@@ -3696,7 +3745,7 @@ baker actions draft --output md # one row per staged op (json defaul
3696
3745
  baker actions draft --output md --fields kind,name,ref,tags # pick the columns
3697
3746
  baker actions draft --output md --full # add each op's payload (description, note, reason, blocker)
3698
3747
  baker actions draft remove temp_hero # drop a staged create (cascades its complete/link ops)
3699
- baker actions draft remove <id> --op complete # drop a staged op on a real action (--op update|complete|discard)
3748
+ baker actions draft remove <id> --op complete # drop a staged op on a real action (--op update|complete|discard|assign|reopen)
3700
3749
  baker actions draft clear # drop everything staged in this chat
3701
3750
  ```
3702
3751
 
@@ -3734,13 +3783,16 @@ Permissions enforced server-side:
3734
3783
  - Only `claim`/`release` mutate live state.
3735
3784
  - `claim` returns action details (`id`, `name`, `description`) plus `recommendedSkills` — a fast model reads the action's name/description/tags against the local `.claude/skills/` catalog and returns the skills (`{ name, reason }`) most worth loading for the work, echoed as `/skill — reason` lines in `hints`. It is best-effort: if the catalog is absent or the model call fails, the claim still succeeds and falls back to a generic review hint. Every claim also carries a routing hint: actions often span several surfaces, so load every skill that owns part of the work and read the tool doc (`__tooling__/docs/tools/baker/<family>.md`) for each baker CLI family the work needs.
3736
3785
  - `complete` and `unlink` require the action to be claimed by the current chat — otherwise the API returns `FORBIDDEN` with a hint to claim first. Completing is the record that the work is done, so it stays claim-gated.
3786
+ - `assign` and `reopen` do not require a claim either, and are blocked the same way. `assign --to` is resolved only among the teammates the key's person can see (`members`), so a hidden freelancer cannot be named by id or email; restaging replaces the earlier assignment. At publish an assignee who lost access to the company is skipped as a conflict, never a failed publish.
3787
+ - `reopen` refuses a Task that is not completed, at stage time and again at publish.
3788
+ - `tags update` changes only what a custom tag means; the slug stays, because every Task carrying it stores it.
3737
3789
  - `update` and `discard` do NOT require a claim — a chat may edit or retire an action it never claimed. They are blocked only when another chat currently holds the claim (`CONFLICT` with that chat's title).
3738
3790
  - Claiming an action already claimed by another chat returns `CONFLICT` with the other chat's title — pick a different action.
3739
3791
  - All staged ops are reverted automatically when the chat is discarded.
3740
3792
 
3741
3793
  ---
3742
3794
 
3743
- ### `baker mcp connected | catalog | list | add | remove`
3795
+ ### `baker mcp connected | catalog | list | add | remove | verify | disable`
3744
3796
 
3745
3797
  See everything a chat can reach — managed integrations, custom servers, and connected platforms — and manage **custom MCP servers** by pointing the agent at any remote HTTPS MCP endpoint. Registered tools appear as `mcp__<name>__*` on the next chat message.
3746
3798
 
@@ -3752,6 +3804,8 @@ baker mcp add --name weather --url https://mcp.example.com/mcp
3752
3804
  baker mcp add --name acme --url https://acme.dev/mcp --header "Authorization: Bearer sk-…"
3753
3805
  baker mcp add --name mine --url https://my.dev/mcp --scope user
3754
3806
  baker mcp remove --name weather
3807
+ baker mcp verify --name weather # check it now (the dashboard's "Check now")
3808
+ baker mcp disable --name weather # stop its tools loading; only a person turns it back on (org-wide servers: a person only)
3755
3809
  ```
3756
3810
 
3757
3811
  - `connected` returns three lists. `managed` and `custom` are MCP tools the agent calls directly; `platforms` are the accounts the company signed in to (HubSpot, Google Ads, GA4, Search Console, Tag Manager, LinkedIn Ads), each with its login and the resources it may read. A platform has **no** `mcp__*` tools — it is read through its own command family — so it is listed here to keep the agent from concluding a working connection is missing.
@@ -3819,6 +3873,22 @@ baker credentials delete stripe-key
3819
3873
 
3820
3874
  ---
3821
3875
 
3876
+ ### `baker setup-links create | list`
3877
+
3878
+ A setup link lets whoever holds the company's accounts connect them without a Baker login. `create` makes one at once and returns its `url` (valid 30 days); the link is also listed on the chat as already made. Revoke links in the dashboard (Settings → Setup links).
3879
+
3880
+ ```bash
3881
+ baker setup-links create --connect google-ads,meta --tags meta # sign in to accounts, add tracking tags
3882
+ baker setup-links create --keys chatgpt-ads --domains shop.acme.com # paste a key, set a domain's DNS
3883
+ baker setup-links create --apps slack --mcp crm=https://mcp.example.com/sse
3884
+ baker setup-links list # active links: asks, progress, url, expiresAt
3885
+ ```
3886
+
3887
+ - Every flag is repeatable or comma-separated; at least one is required. Unknown tag, connection or key-account names are refused with the valid list. A `--domains` hostname must already be one of the company's domains.
3888
+ - `list` returns what each link asks for in the same words `create` takes. A read-only key sees no `url`.
3889
+
3890
+ ---
3891
+
3822
3892
  ### `baker hubspot forms list | view | submissions` · `baker hubspot workflows list | view` · `baker hubspot pipelines list` · `baker hubspot contacts summary | lookup | properties | fields` · `baker hubspot deals properties | fields` · `baker hubspot meetings list | view`
3823
3893
 
3824
3894
  Read-only view of the company's **connected HubSpot account** — the forms and meeting links (calendars) that live there, the leads those forms received, and the workflows, deal pipelines, and contact records a lead runs through afterwards. Fetched from HubSpot live on every call; nothing is cached and nothing is ever written back.
@@ -6508,6 +6578,7 @@ baker landing inspiration page <source id> # a whole page as a section sequ
6508
6578
  baker landing inspiration sequences "b2b saas pricing page" --scope all # what follows what, across many pages
6509
6579
  baker landing inspiration add https://linear.app --note "client likes this density"
6510
6580
  baker landing inspiration favorites # what this company has saved
6581
+ baker landing inspiration retry-failed # study again every saved page that failed
6511
6582
  baker landing inspiration scrape <url> --out .baker/<dir> # capture any page now, synchronously
6512
6583
  ```
6513
6584
 
@@ -6547,6 +6618,21 @@ baker landing variant oferta --fork Hero.astro,Proof.astro --because "…" --cha
6547
6618
  - **Errors carry the retry.** `NOT_FOUND` returns `availableSlugs` (wrong page) or `availableComponents` (wrong `--fork`); `INVALID_SLUG` fires when the slug is not a page, or is already a variant of one. Omitting `--fork` succeeds with a hint saying the page currently renders exactly the control, so a test between them cannot conclude.
6548
6619
  - **Run `baker experiment plan` first.** Most pages never get the traffic to settle most questions.
6549
6620
 
6621
+ ### `baker landing export`
6622
+
6623
+ A download of the company's **published** landings as a ZIP of plain HTML — the same pack Landings → Export makes. It reads what is live, so it starts at once; landings changed in the chat and not yet published are not in it.
6624
+
6625
+ ```bash
6626
+ baker landing export start # → { exportId }, returns at once
6627
+ baker landing export start --profile '{"htmlOutput":"fragment"}' # download format for this export only (JSON or @file)
6628
+ baker landing export status <id> # progress; downloadUrl once ready
6629
+ baker landing export list # the last 10 downloads
6630
+ ```
6631
+
6632
+ - **No password flag.** A protected ZIP is made from the dashboard — secrets never pass through the agent.
6633
+ - **Listed on the chat as already applied**, with a download button once ready.
6634
+ - `--profile` fields sit on top of the company's saved download format; a field that cannot be built is refused by name (`BAD_REQUEST`).
6635
+
6550
6636
  ### `baker landing critique`
6551
6637
 
6552
6638
  Deterministic design-quality critic for landing pages — an offline, no-LLM detector for the well-known "AI slop" tells (gradient text, overused fonts like Inter, side-tab colored borders, cream/parchment grounds, purple-on-heading palettes, buzzword copy, broken images, and more). It scores a landing's `.astro` source and returns findings tiered **block / warn / advisory**.