@koda-sl/baker-cli 0.422.0 → 0.424.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.
Files changed (26) hide show
  1. package/README.md +98 -10
  2. package/dist/{chunk-5JVAP5DC.js → chunk-FQOKJYKN.js} +4 -1
  3. package/dist/{chunk-S36N4SOX.js → chunk-GCTR4MDE.js} +2 -2
  4. package/dist/{chunk-2S6QIXLX.js → chunk-IR4ZOEZV.js} +2999 -2607
  5. package/dist/chunk-IR4ZOEZV.js.map +1 -0
  6. package/dist/{chunk-XNFV6BQU.js → chunk-PHLFNYGQ.js} +4 -4
  7. package/dist/{chunk-G5L5FX2B.js → chunk-Q6F5UNOU.js} +3 -3
  8. package/dist/{chunk-3X2EMLBQ.js → chunk-RFZYRG2Q.js} +3 -3
  9. package/dist/cli.js +4059 -2589
  10. package/dist/cli.js.map +1 -1
  11. package/dist/{client-PIKJZFRA.js → client-GS7T7ETG.js} +4 -4
  12. package/dist/engine/index.js +3 -3
  13. package/dist/{env-6UAIAY4M.js → env-SL22S6CM.js} +2 -2
  14. package/dist/{output-CFDBWWYJ.js → output-OFDKEPPJ.js} +5 -5
  15. package/dist/{shared-3O5RKQYZ.js → shared-XR54KFMH.js} +6 -6
  16. package/package.json +1 -1
  17. package/dist/chunk-2S6QIXLX.js.map +0 -1
  18. /package/dist/{chunk-5JVAP5DC.js.map → chunk-FQOKJYKN.js.map} +0 -0
  19. /package/dist/{chunk-S36N4SOX.js.map → chunk-GCTR4MDE.js.map} +0 -0
  20. /package/dist/{chunk-XNFV6BQU.js.map → chunk-PHLFNYGQ.js.map} +0 -0
  21. /package/dist/{chunk-G5L5FX2B.js.map → chunk-Q6F5UNOU.js.map} +0 -0
  22. /package/dist/{chunk-3X2EMLBQ.js.map → chunk-RFZYRG2Q.js.map} +0 -0
  23. /package/dist/{client-PIKJZFRA.js.map → client-GS7T7ETG.js.map} +0 -0
  24. /package/dist/{env-6UAIAY4M.js.map → env-SL22S6CM.js.map} +0 -0
  25. /package/dist/{output-CFDBWWYJ.js.map → output-OFDKEPPJ.js.map} +0 -0
  26. /package/dist/{shared-3O5RKQYZ.js.map → shared-XR54KFMH.js.map} +0 -0
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.
@@ -3319,7 +3360,7 @@ baker winning-ads search "delivery driver recruitment" --audience-temperature 0_
3319
3360
  | `--scope followed-first\|followed\|all` | Which brands to draw from (default `followed-first`: the company's followed brands, topped up from the shared library; the whole library when it follows nobody) |
3320
3361
  | `--sort winner\|longest_running\|newest` | Order of a no-query browse (default `winner`); ignored when a query is given |
3321
3362
  | `--limit <n>` | Max results 1–100 (**default 10** — shortlist size) |
3322
- | `--max-per-advertiser <n>` | Cap results per advertiser 0–50 (default 3; `0` = no cap) |
3363
+ | `--max-per-advertiser <n>` | Unset (default): brands spread, each brand's best 3 first and the rest after the other brands, none dropped. `1`–`50`: drop a brand's ads past N (`1` = one reference per brand). `0`: rank order. Brands the query names ("HubSpot video ads") are never capped |
3323
3364
  | `--min-relevance <0-1>` | Relevance floor; trims weak matches |
3324
3365
  | `--platform <list>` | `meta,linkedin,tiktok` — pass a single value to search **only** that platform |
3325
3366
  | `--format <list>` | `video,static,carousel` |
@@ -3331,15 +3372,17 @@ baker winning-ads search "delivery driver recruitment" --audience-temperature 0_
3331
3372
  | `--exclude-brand-reliant` | Drop ads whose copy only works if the viewer already knows the brand (ads not judged yet are kept) |
3332
3373
  | `--advertiser-id <list>` | **Restrict to** these advertiser ids (browse one brand's winners) |
3333
3374
  | `--exclude-advertiser <list>` | **Drop** these advertiser ids, usually your own brand |
3334
- | `--country <list>` / `--language <list>` | Filter by country / language codes |
3375
+ | `--country <list>` | ISO country codes: ads known to run there, plus ads with no country data (every Meta ad) in that country's main language |
3376
+ | `--language <list>` | ISO 639-1 codes (`es,en`) for the language of the ad's copy and voiceover |
3335
3377
  | `--first-seen-after` / `--first-seen-before` | ISO date (`2026-01-01`, read as the start of that day in UTC) or datetime bounds (recency) |
3336
3378
  | `--hook-archetype <list>` | Narrow to ads on a proven hook **seed** (from `winning-ads hooks`) |
3337
3379
  | `--format-pattern <list>` | Narrow to statics in these containers (from `winning-ads formats`, e.g. `comparison_table`) |
3338
3380
  | `--diverse` | One varied page (different brands, containers, hooks) instead of rank order; ignores paging |
3339
3381
  | `--output json\|md\|files` | Output format (default json) |
3382
+ | `--fields <list>` | Only these row fields (e.g. `advertiser,container,mechanism`); a `--full`-only field turns `--full` on, an unknown one is refused with `error.fix.validValues` |
3340
3383
  | `--full` | Include DNA detail + longevity |
3341
3384
 
3342
- A value outside a closed list (`--platform`, `--format`, `--winner-category`, `--awareness`, `--audience-temperature`, `--funnel-stage`, `--advertiser-size`, `--format-pattern`), a non-numeric `--limit`/`--max-per-advertiser`/`--min-relevance`, or a bound that is not a date is refused before the search runs; a refused list value comes with `error.fix.validValues`. References this company already adapted (`already_adapted`) never take a fresh reference's place: `--limit N` returns up to N fresh ones first. The search waits up to 120 s (`followed-first` can run two library searches).
3385
+ A value outside a closed list (`--platform`, `--format`, `--winner-category`, `--awareness`, `--audience-temperature`, `--funnel-stage`, `--advertiser-size`, `--format-pattern`), a non-numeric `--limit`/`--max-per-advertiser`/`--min-relevance`, or a bound that is not a date is refused before the search runs; a refused list value comes with `error.fix.validValues`. References this company already adapted (`already_adapted`) never take a fresh reference's place: `--limit N` returns up to N fresh ones first. The search waits up to 120 s (`followed-first` can run two library searches). A library that does not answer in time is `UNAVAILABLE`, with an `error.fix` to retry once narrower. An empty answer carries a hint naming the one filter to loosen.
3343
3386
 
3344
3387
  Reading the scores: **`relevance`** (0–1) = match of the creative to your query; **`winner_score`** = how proven the ad is in-market. Pick references that are both relevant *and* proven.
3345
3388
 
@@ -3413,7 +3456,7 @@ Winners across **every** brand you follow, in one library → `GET /api/ad-libra
3413
3456
  Response `data`: `winners`, `following_count` (how many brands you follow), `advertiser_ids` (the ids actually queried = follows ∩ requested), and — when relevant — `hints` (e.g. you follow nobody yet, or a requested id isn't in your follows and was skipped). In `--output md`/`files` the table is the payload and the hints are written to **stderr** so they still surface without corrupting the output.
3414
3457
 
3415
3458
  ```bash
3416
- baker winning-ads feed --per-advertiser 5 --output md
3459
+ baker winning-ads feed --output md
3417
3460
  baker winning-ads feed --advertiser adv_123,adv_456 --platform meta --output md
3418
3461
  ```
3419
3462
 
@@ -3421,7 +3464,7 @@ baker winning-ads feed --advertiser adv_123,adv_456 --platform meta --output md
3421
3464
  |---|---|
3422
3465
  | `--advertiser <ids>` | Trim to a comma-separated subset of your followed advertiser ids (ids you don't follow are skipped and reported) |
3423
3466
  | `--platform meta\|linkedin` | Filter to a single platform |
3424
- | `--per-advertiser <n>` | Max winners kept per advertiser 0–50 (`0` = no cap, default 5) |
3467
+ | `--per-advertiser <n>` | Unset (default): brands spread, each brand's best 3 first and the rest after, none dropped. `1`–`50`: keep at most N per brand. `0`: rank order |
3425
3468
  | `--limit <n>` | Total winners across all follows 1–200 (default 40) |
3426
3469
  | `--winner-category <list>` | Restrict to specific winner categories |
3427
3470
  | `--format <list>` | Restrict to specific formats (e.g. `static,video`) |
@@ -3547,13 +3590,14 @@ baker scheduled-agents templates --delete weekly-posthog-check
3547
3590
 
3548
3591
  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
3592
 
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.
3593
+ **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
3594
 
3552
3595
  `BAKER_CHAT_ID` must be set.
3553
3596
 
3554
3597
  ```bash
3555
3598
  baker tags list # effective view: production + staged, full readable config + secret status
3556
3599
  baker tags draft # review the staged changes awaiting publish
3600
+ baker tags unstage tag_temp_abc123 # take back one change this chat staged (or --all)
3557
3601
  ```
3558
3602
 
3559
3603
  Notes:
@@ -3563,7 +3607,7 @@ Notes:
3563
3607
  - **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
3608
  - 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
3609
  - 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.
3610
+ - **`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
3611
  - Single-instance types (`code`, `posthog`, `datafast`) reject a second instance against the chat's effective view.
3568
3612
  - Conflicts at publish (tag deleted in the dashboard, config invalid) skip the op with a recorded reason — they never block the publish.
3569
3613
 
@@ -3681,10 +3725,17 @@ baker actions complete <action-id-or-tempId> --note "What was done" # stages
3681
3725
  # --note is REQUIRED (≥20 chars): what changed, where, and the outcome. It is the durable, client-facing
3682
3726
  # record surfaced by `baker actions log`. A missing/too-short note is rejected with a VALIDATION_ERROR.
3683
3727
  baker actions discard <action-id> --reason "obsolete"
3728
+ baker actions reopen <action-id> # stages — a completed Task goes back to the backlog on publish
3729
+
3730
+ # Assigning — staged, applies on publish. --to is a userId or email from `members`, or `none`
3731
+ baker actions members # teammates a Task can be handed to (freelancers hidden unless you are a superadmin)
3732
+ baker actions assign <id-or-tempId> --to maria@empresa.com
3733
+ baker actions assign <id> --to none # unassign
3684
3734
 
3685
3735
  # Tags — taxonomy is built-in defaults + company custom tags; --tags is STRICT (unknown slugs are rejected)
3686
3736
  baker actions tags list # available tags (defaults + company custom); errors → stderr (inline-safe)
3687
3737
  baker actions tags create --slug pmax --description "Performance Max work" # mint a custom tag
3738
+ baker actions tags update --slug pmax --description "Performance Max campaigns" # what it means; applies at once
3688
3739
  baker actions tags delete --slug pmax # remove a custom tag (default tags can't be deleted)
3689
3740
 
3690
3741
  baker actions link --blocker <id-or-tempId> --blocked <id-or-tempId>
@@ -3696,7 +3747,7 @@ baker actions draft --output md # one row per staged op (json defaul
3696
3747
  baker actions draft --output md --fields kind,name,ref,tags # pick the columns
3697
3748
  baker actions draft --output md --full # add each op's payload (description, note, reason, blocker)
3698
3749
  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)
3750
+ baker actions draft remove <id> --op complete # drop a staged op on a real action (--op update|complete|discard|assign|reopen)
3700
3751
  baker actions draft clear # drop everything staged in this chat
3701
3752
  ```
3702
3753
 
@@ -3734,13 +3785,16 @@ Permissions enforced server-side:
3734
3785
  - Only `claim`/`release` mutate live state.
3735
3786
  - `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
3787
  - `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.
3788
+ - `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.
3789
+ - `reopen` refuses a Task that is not completed, at stage time and again at publish.
3790
+ - `tags update` changes only what a custom tag means; the slug stays, because every Task carrying it stores it.
3737
3791
  - `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
3792
  - Claiming an action already claimed by another chat returns `CONFLICT` with the other chat's title — pick a different action.
3739
3793
  - All staged ops are reverted automatically when the chat is discarded.
3740
3794
 
3741
3795
  ---
3742
3796
 
3743
- ### `baker mcp connected | catalog | list | add | remove`
3797
+ ### `baker mcp connected | catalog | list | add | remove | verify | disable`
3744
3798
 
3745
3799
  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
3800
 
@@ -3752,6 +3806,8 @@ baker mcp add --name weather --url https://mcp.example.com/mcp
3752
3806
  baker mcp add --name acme --url https://acme.dev/mcp --header "Authorization: Bearer sk-…"
3753
3807
  baker mcp add --name mine --url https://my.dev/mcp --scope user
3754
3808
  baker mcp remove --name weather
3809
+ baker mcp verify --name weather # check it now (the dashboard's "Check now")
3810
+ baker mcp disable --name weather # stop its tools loading; only a person turns it back on (org-wide servers: a person only)
3755
3811
  ```
3756
3812
 
3757
3813
  - `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 +3875,22 @@ baker credentials delete stripe-key
3819
3875
 
3820
3876
  ---
3821
3877
 
3878
+ ### `baker setup-links create | list`
3879
+
3880
+ 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).
3881
+
3882
+ ```bash
3883
+ baker setup-links create --connect google-ads,meta --tags meta # sign in to accounts, add tracking tags
3884
+ baker setup-links create --keys chatgpt-ads --domains shop.acme.com # paste a key, set a domain's DNS
3885
+ baker setup-links create --apps slack --mcp crm=https://mcp.example.com/sse
3886
+ baker setup-links list # active links: asks, progress, url, expiresAt
3887
+ ```
3888
+
3889
+ - 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.
3890
+ - `list` returns what each link asks for in the same words `create` takes. A read-only key sees no `url`.
3891
+
3892
+ ---
3893
+
3822
3894
  ### `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
3895
 
3824
3896
  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 +6580,7 @@ baker landing inspiration page <source id> # a whole page as a section sequ
6508
6580
  baker landing inspiration sequences "b2b saas pricing page" --scope all # what follows what, across many pages
6509
6581
  baker landing inspiration add https://linear.app --note "client likes this density"
6510
6582
  baker landing inspiration favorites # what this company has saved
6583
+ baker landing inspiration retry-failed # study again every saved page that failed
6511
6584
  baker landing inspiration scrape <url> --out .baker/<dir> # capture any page now, synchronously
6512
6585
  ```
6513
6586
 
@@ -6547,6 +6620,21 @@ baker landing variant oferta --fork Hero.astro,Proof.astro --because "…" --cha
6547
6620
  - **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
6621
  - **Run `baker experiment plan` first.** Most pages never get the traffic to settle most questions.
6549
6622
 
6623
+ ### `baker landing export`
6624
+
6625
+ 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.
6626
+
6627
+ ```bash
6628
+ baker landing export start # → { exportId }, returns at once
6629
+ baker landing export start --profile '{"htmlOutput":"fragment"}' # download format for this export only (JSON or @file)
6630
+ baker landing export status <id> # progress; downloadUrl once ready
6631
+ baker landing export list # the last 10 downloads
6632
+ ```
6633
+
6634
+ - **No password flag.** A protected ZIP is made from the dashboard — secrets never pass through the agent.
6635
+ - **Listed on the chat as already applied**, with a download button once ready.
6636
+ - `--profile` fields sit on top of the company's saved download format; a field that cannot be built is refused by name (`BAD_REQUEST`).
6637
+
6550
6638
  ### `baker landing critique`
6551
6639
 
6552
6640
  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**.
@@ -1391,8 +1391,11 @@ export {
1391
1391
  compactVideo,
1392
1392
  videoNormalizer,
1393
1393
  testimonialNormalizer,
1394
+ compactWinningAd,
1395
+ fullWinningAd,
1394
1396
  winningAdNormalizer,
1395
1397
  adContentNormalizer,
1398
+ applyFieldMask,
1396
1399
  writeJson,
1397
1400
  writeOutput,
1398
1401
  getEnv,
@@ -1412,4 +1415,4 @@ export {
1412
1415
  captureVimeoCookie,
1413
1416
  childEnvWith
1414
1417
  };
1415
- //# sourceMappingURL=chunk-5JVAP5DC.js.map
1418
+ //# sourceMappingURL=chunk-FQOKJYKN.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  debugLogSetting
3
- } from "./chunk-5JVAP5DC.js";
3
+ } from "./chunk-FQOKJYKN.js";
4
4
 
5
5
  // src/debugLog.ts
6
6
  import { appendFileSync, mkdirSync, renameSync, statSync } from "fs";
@@ -212,4 +212,4 @@ export {
212
212
  readBodyForLog,
213
213
  installStreamTaps
214
214
  };
215
- //# sourceMappingURL=chunk-S36N4SOX.js.map
215
+ //# sourceMappingURL=chunk-GCTR4MDE.js.map