@koda-sl/baker-cli 0.374.0 → 0.375.0-dev.7b550440d
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 +63 -36
- package/dist/{chunk-ZI7TPBXB.js → chunk-2QXMPTHG.js} +3 -3
- package/dist/{chunk-HJEMOSPH.js → chunk-7YNOGIWQ.js} +2 -439
- package/dist/chunk-7YNOGIWQ.js.map +1 -0
- package/dist/{chunk-VZEDAFAR.js → chunk-IZOAYU2G.js} +2 -2
- package/dist/{chunk-4ACU7GBN.js → chunk-PGYWZEAW.js} +4 -4
- package/dist/{chunk-FGHMWBUD.js → chunk-RK44ZR7L.js} +114 -196
- package/dist/chunk-RK44ZR7L.js.map +1 -0
- package/dist/{chunk-MF7YA62W.js → chunk-UMIALY2G.js} +3 -3
- package/dist/cli.js +5677 -3567
- package/dist/cli.js.map +1 -1
- package/dist/{client-GR6YL3YX.js → client-OTWPBCHC.js} +4 -4
- package/dist/engine/index.js +3 -3
- package/dist/{env-4P5HOGNA.js → env-P7YVNPZ6.js} +2 -2
- package/dist/{output-KMEPFOFT.js → output-WCDFLOHZ.js} +5 -5
- package/dist/{shared-26NWGQ5G.js → shared-JZJ6PVJ7.js} +6 -6
- package/package.json +1 -2
- package/dist/chunk-FGHMWBUD.js.map +0 -1
- package/dist/chunk-HJEMOSPH.js.map +0 -1
- /package/dist/{chunk-ZI7TPBXB.js.map → chunk-2QXMPTHG.js.map} +0 -0
- /package/dist/{chunk-VZEDAFAR.js.map → chunk-IZOAYU2G.js.map} +0 -0
- /package/dist/{chunk-4ACU7GBN.js.map → chunk-PGYWZEAW.js.map} +0 -0
- /package/dist/{chunk-MF7YA62W.js.map → chunk-UMIALY2G.js.map} +0 -0
- /package/dist/{client-GR6YL3YX.js.map → client-OTWPBCHC.js.map} +0 -0
- /package/dist/{env-4P5HOGNA.js.map → env-P7YVNPZ6.js.map} +0 -0
- /package/dist/{output-KMEPFOFT.js.map → output-WCDFLOHZ.js.map} +0 -0
- /package/dist/{shared-26NWGQ5G.js.map → shared-JZJ6PVJ7.js.map} +0 -0
package/README.md
CHANGED
|
@@ -110,22 +110,6 @@ question — and nothing in the output said so. Both spellings of an option work
|
|
|
110
110
|
that lists every option: `baker schema <command>` (`check_schema`) when the command
|
|
111
111
|
registers a schema, `baker <command> --help` (`check_help`) when it does not.
|
|
112
112
|
|
|
113
|
-
### Narrowing a result: `--fields`
|
|
114
|
-
|
|
115
|
-
`--fields a,b,c` works on every command that prints the JSON envelope. It keeps only
|
|
116
|
-
those keys of each record in `data` — the rows when `data` is a list or wraps one
|
|
117
|
-
(`baker chats list --fields id,title`), `data` itself when it is a single record
|
|
118
|
-
(`baker experiment plan ... --fields traffic,warning`). Naming a key of the wrapper beside
|
|
119
|
-
keys of its rows narrows both. `meta`, `hints` and warnings are
|
|
120
|
-
kept, and a name no record carries is reported in `hints` alongside the keys that do
|
|
121
|
-
exist. Commands that declare `--fields` themselves keep their own meaning
|
|
122
|
-
(`ads meta insights` chooses which metrics to request; `ads linkedin creatives` takes dotted
|
|
123
|
-
paths; `actions draft` picks the columns of `--output md|files` and leaves its JSON
|
|
124
|
-
whole). A command whose default output is text needs `--output json` for there to be an
|
|
125
|
-
envelope to narrow; without it a note on stderr says the flag changed nothing. A success
|
|
126
|
-
that prints its result beside `ok` rather than under `data` (`canvas validate`,
|
|
127
|
-
`canvas critique`) comes back whole, with a hint saying `--fields` was not applied.
|
|
128
|
-
|
|
129
113
|
### Fresh reads: `--no-cache`
|
|
130
114
|
|
|
131
115
|
Every command that caches takes `--no-cache`, and it skips **both** cache layers — the
|
|
@@ -721,7 +705,7 @@ Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remo
|
|
|
721
705
|
|
|
722
706
|
**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.
|
|
723
707
|
|
|
724
|
-
**Reading an earlier chat's changes** — `draft list` and `draft show` take `--chat <chat-id>` to read another chat in the same company instead of the current one. Every staged-draft family accepts it: `ads google|meta|linkedin draft list|show`, `tag-manager draft list|show`, `actions draft`, `tags draft`, and `scheduled-agents list|get
|
|
708
|
+
**Reading an earlier chat's changes** — `draft list` and `draft show` take `--chat <chat-id>` to read another chat in the same company instead of the current one. Every staged-draft family accepts it: `ads google|meta|linkedin draft list|show`, `tag-manager draft list|show`, `actions draft`, `tags draft`, and `scheduled-agents list|get`. A published draft is kept in full, so this returns what that chat actually wrote — every headline, bid and target — plus each op's outcome and error. Use it when asked to redo or reapply earlier work rather than reconstructing copy from a summary. Read-only: staging, `amend`, `remove` and `clear` stay bound to `BAKER_CHAT_ID`, so one chat can never edit another's draft. To re-run only the changes a publish failed to land, use the chat's **Retry** control in the dashboard — it re-sends exactly those and leaves the ones that applied untouched.
|
|
725
709
|
|
|
726
710
|
**Already-satisfied writes aren't staged** — an update or pause/resume whose every field already holds the requested value on the live account is dropped instead of staged: the envelope returns `"staged": false, "noop": true` with a `reason` ("this ad is already Paused on Google Ads"), plus a hint. This is a success, not an error — there is nothing to publish. Only a positively-read live snapshot can trigger it; a failed or empty read always stages. Batch responses list the dropped ops under `skipped`, and `count` reflects what actually entered the draft.
|
|
727
711
|
|
|
@@ -959,8 +943,7 @@ baker ads meta creatives create --account-id act_123 --page 555 --instagram-us
|
|
|
959
943
|
baker ads meta ads create --account-id act_123 --name "Ad 1" --adset meta_temp_as --creative meta_temp_cr
|
|
960
944
|
|
|
961
945
|
# review + edit before publish
|
|
962
|
-
baker ads meta draft
|
|
963
|
-
baker ads meta draft --json # raw JSON envelope for scripting
|
|
946
|
+
baker ads meta draft
|
|
964
947
|
baker ads meta draft show meta_temp_cr # full staged payload — the receipt before publish
|
|
965
948
|
baker ads meta draft remove meta_temp_cr # removing a create cascades to dependents
|
|
966
949
|
baker ads meta draft clear
|
|
@@ -1306,9 +1289,6 @@ baker analytics map --platform google --set kw=keyword # name a parameter, se
|
|
|
1306
1289
|
baker analytics map --platform google --remove kw # take that answer back
|
|
1307
1290
|
baker analytics conversions # what counts, what each produced, and which Forms count nothing
|
|
1308
1291
|
baker analytics conversions --candidates --output md # everything these pages do, and which of it is counted, as tables
|
|
1309
|
-
baker analytics conversions --candidates # the same as compact JSON: one line per page event, Form keys folded onto `flows`
|
|
1310
|
-
baker analytics conversions --candidates --flow contact # only that Form's event keys, one line each
|
|
1311
|
-
baker analytics conversions --candidates --full --output json # every field of every candidate, Form keys unfolded
|
|
1312
1292
|
baker analytics conversions --flow contact # one Form's endings as event keys, traffic or not
|
|
1313
1293
|
baker analytics conversions --event page:request_demo --name "Demo requested"
|
|
1314
1294
|
baker analytics conversions --event page:a --event submit:b --name "Lead" # both, as one number
|
|
@@ -1360,7 +1340,7 @@ Shared flags: `--days <n>` (default 30) or `--start-date` / `--end-date` (`YYYY-
|
|
|
1360
1340
|
|
|
1361
1341
|
**Paging the list reports.** `people`, `submissions` and `delivery` are lists of individual things rather than breakdowns — `delivery` and `submissions` are the ones the CLI exposes, `people` backs the People section of the dashboard's landing Analytics screen over the same wire — and only they take `--page <n>` (1-based) and `--page-size <n>` (up to 200, default 50). The response carries `pageInfo` with `hasMore` — when it is true there **are** more rows, so a total must never be reported from one page. Pass neither flag and a list comes back at the size it always did. A value that is not a whole positive number (`--page /pricing`) is refused before any request, naming `--landing` as the flag that narrows a report to one page of the site.
|
|
1362
1342
|
|
|
1363
|
-
**A conversion is a company-level named event, not a property of a Form.** `baker analytics conversions` is the only place "what counts" is decided, and an empty `definitions` list means every conversion number in every other report is zero — not because nobody converted, but because nothing is named as an outcome and Baker never guesses which event is the point of a page. `--candidates` lists every event these pages actually produced — each Form step and trigger, every `data-baker-*` event, every outbound destination — with volume and whether it is already counted; that list is where an event key comes from, so never invent one.
|
|
1343
|
+
**A conversion is a company-level named event, not a property of a Form.** `baker analytics conversions` is the only place "what counts" is decided, and an empty `definitions` list means every conversion number in every other report is zero — not because nobody converted, but because nothing is named as an outcome and Baker never guesses which event is the point of a page. `--candidates` lists every event these pages actually produced — each Form step and trigger, every `data-baker-*` event, every outbound destination — with volume and whether it is already counted; that list is where an event key comes from, so never invent one. `--event <key> --name "Booked a call"` starts counting it **immediately and retroactively**: the whole stored history is rescored, so naming the right event today also fixes last month. Nothing here is staged and publishing is not involved. Two events given the same `--name` become one row and one number, which is how a call booked on three different Forms reads as one outcome. `--count-mode every_time` is for the outcomes people genuinely repeat (a guide downloaded twice is two downloads); the default counts once per visit.
|
|
1364
1344
|
|
|
1365
1345
|
**The name is the grouping, so the CLI defends it.** Repeat `--event` to count several events under one `--name` in a single call; `--rename "<old>" --to "<new>"` renames every event under an outcome, and renaming *onto* a name that already exists **merges** them into one row and one number — the fix for a company whose Forms each invented their own word for the same thing. `--remove-name` drops an outcome entirely, `--remove` a single event key. A name that differs from one already counted only by case, accent, punctuation or a plural is **refused**: Baker groups by exact name, so "Booked a Call" beside "Booked a call" is a number split in half with both halves plausible. Every answer leads with the names already in use, and a company that has named nothing gets a standard set to start from — after which the rule is reuse, in that company's own language.
|
|
1366
1346
|
|
|
@@ -3312,10 +3292,8 @@ baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --top-n 10 --out
|
|
|
3312
3292
|
A Scheduled agent is a **trigger** and a **prompt**. When the trigger fires, a Session opens with that prompt and does the job — there is no Task in between. `create`, `update`, and `delete` stage draft ops on `BAKER_CHAT_ID` and apply when the chat is published. `unstage` takes back what this chat staged on one item before Publish (`--index <n>` for one change only, by its index in `list` → `draft.ops`). `list` and `get` include draft state when `BAKER_CHAT_ID` is set; `get` on a published item also returns `runsAs` — who each run acts as and which tools it loads. `run` fires a published item immediately and does not require a chat id. Publishing every run unreviewed is switched on by the user on the item, never through the CLI: `--auto-publish` is refused with an `ask_user` fix.
|
|
3313
3293
|
|
|
3314
3294
|
```bash
|
|
3315
|
-
baker scheduled-agents triggers # every trigger
|
|
3316
|
-
baker scheduled-agents
|
|
3317
|
-
baker scheduled-agents triggers --group tasks # one group in full; --full for the whole catalog
|
|
3318
|
-
baker scheduled-agents list # id, name, trigger, status; briefs left out (--full for everything)
|
|
3295
|
+
baker scheduled-agents triggers # every trigger there is
|
|
3296
|
+
baker scheduled-agents list
|
|
3319
3297
|
baker scheduled-agents get <id-or-temp_agent_id>
|
|
3320
3298
|
|
|
3321
3299
|
baker scheduled-agents create --name "Weekly report" --description "Prepare report" --prompt "Review last week's spend." --cron "0 9 * * MON" --timezone Europe/Madrid
|
|
@@ -3478,8 +3456,7 @@ baker actions list # default: bucketed (claimable, myCla
|
|
|
3478
3456
|
# then most recent. The `blocked` bucket is ordered closest-to-ready first.
|
|
3479
3457
|
baker actions list --bucketed=false --status pending
|
|
3480
3458
|
baker actions list --bucketed=false --sort priority # flat list, do-first order (default); use --sort recent for newest-first
|
|
3481
|
-
baker actions list --output md # id-first Markdown;
|
|
3482
|
-
baker actions list --full # whole descriptions and full records (large on a real backlog)
|
|
3459
|
+
baker actions list --output md # id-first Markdown; works for both the bucketed and flat shapes
|
|
3483
3460
|
baker actions list --search "conversion goal" --output md # find Tasks by words in name/description/tags (flat, best match first)
|
|
3484
3461
|
# With BAKER_CHAT_ID, the bucketed list folds in THIS chat's draft: staged creates appear in
|
|
3485
3462
|
# `draftCreates`; published actions being completed/discarded/updated carry a `draftStatus` marker.
|
|
@@ -3706,6 +3683,63 @@ No write surface against HubSpot itself — a form's fields, redirect, or consen
|
|
|
3706
3683
|
|
|
3707
3684
|
---
|
|
3708
3685
|
|
|
3686
|
+
### `baker shopify store | products | product | collections | stock | sales | buyers | buyer | countries | best-sellers | cohorts | segments | promotions | stock-holds`
|
|
3687
|
+
|
|
3688
|
+
Read-only view of the company's **connected Shopify store**, from **Baker's own copy** of its catalog and the store's own orders — never a live call to Shopify. Baker keeps the copy current from the store (a change usually shows within about a minute) and checks the whole catalog daily; product photos are already in the image library.
|
|
3689
|
+
|
|
3690
|
+
```bash
|
|
3691
|
+
baker shopify store # name, currency, home country, counts, prices by country, the Products page link
|
|
3692
|
+
baker shopify products --search "snowboard" # what the store sells: price, sale price, stock, where it can be bought
|
|
3693
|
+
baker shopify products --stock out_of_stock # --stock in_stock|partly_out|out_of_stock, --collection <handle|id>
|
|
3694
|
+
baker shopify products --limit 10 --cursor <c> # page with meta.next_cursor (25 by default, up to 100)
|
|
3695
|
+
baker shopify product <id|handle|link> # one product: options with buyUrl, prices by country, stock, photos, videos
|
|
3696
|
+
baker shopify product <handle> --content # its whole details: description, custom fields, subscriptions, translations
|
|
3697
|
+
baker shopify product <handle> --field "Size chart" # one custom field, whole
|
|
3698
|
+
baker shopify product <handle> --quantity 2 # buy links that put 2 of the option in the cart
|
|
3699
|
+
baker shopify product <id> --out-of-stock # only the options that are out of stock (page with --variants-cursor)
|
|
3700
|
+
baker shopify collections --search "summer" # collections, with the handle --collection takes (--full: descriptions, images)
|
|
3701
|
+
baker shopify stock --limit 20 # every product with every option out, and every product with some out
|
|
3702
|
+
baker shopify sales --days 7 --by campaign # what sold and which campaigns brought it (--by day|product|campaign|landing)
|
|
3703
|
+
baker shopify sales --all --by weekday # when buyers order, in the store's time (--by hour|month|month_of_year)
|
|
3704
|
+
baker shopify buyers --days 90 --by channel # who buys: new and returning, repeat rate, segments, value per acquisition
|
|
3705
|
+
baker shopify buyer 1042 # one numbered customer: profile, every order, what they bought
|
|
3706
|
+
baker shopify countries --country DE # where buyers are: by country, a country's regions (--region for cities)
|
|
3707
|
+
baker shopify best-sellers --view repeat # what sells (--view products|variants|trend|together|repeat|momentum)
|
|
3708
|
+
baker shopify segments # best, loyal, at risk, new, one-time, with this store's own rules
|
|
3709
|
+
baker shopify cohorts --months 12 # buyers by first-order month: who came back, spend per buyer
|
|
3710
|
+
baker shopify promotions <id|handle|link> # what advertises a product: ads (via page, buy link, landing), landings, Shopping
|
|
3711
|
+
baker shopify stock-holds --product <id> # ads Baker paused because the product ran out, each with a resume verdict
|
|
3712
|
+
```
|
|
3713
|
+
|
|
3714
|
+
**`meta.store`** is on every answer: `connection` (`connected` · `needs_reconnect` · `disconnected`), `catalog` (`starting` · `importing` · `ready` · `failed`, with `importProgress` while importing), `unreadable` (products Baker couldn't read; `unreadableCapped` past 100), `checksFailing` (Baker couldn't check the store for changes lately), `storefront` (`online_store`, or `own` for a store that sells through its own site) and `lastActivity` (when Baker last heard from the store — not a promise the copy is current). `hints[]` turn each of these into what to tell the user.
|
|
3715
|
+
**`store`:** `--full` adds the admin link and every country. `capped: true` means a count stopped at its ceiling — `outOfStock` and `partlyOut` at 100, `collections` at 500 — so that count reads "that many or more"; a hint says which.
|
|
3716
|
+
**`products`:** `--search <words>`, `--collection <handle|id>`, `--stock`, `--limit <1-100>`, `--cursor`; `--full` adds vendor, type, option count, photo link, visibility and status. Every price, here and in `product` (`price`, `compareAt`, each option's price, `pricesByCountry`), is one string with its currency beside each amount: `"USD 785.95"`, `"USD 9.95 – USD 49.95"`. A row's `availability` is absent when the product is on the store, `link_only` when it is buyable only through its link, `not_for_sale` (with `status`) when it can't be bought on the online store.
|
|
3717
|
+
**`product`:** positional `<ref>` — the numeric id, the handle, a store product link (`…/products/<handle>`, even an all-digit handle), a Baker Products link, a Shopify admin product link (`admin.shopify.com/store/<shop>/products/<n>`), or `gid://shopify/Product/<n>`. Returns options (50 per page, `--variants-cursor` for more; 250 with `--full`), `outOptions` (up to 50, `outOptionsMore` for the rest), `pricesByCountry` when the store sells at more than one price, `photos[]` (`imageId` + a Baker-hosted `url`, never a Shopify link), `url` (the product's page in Baker) and `storeUrl` (the product's page on the store — never a buy button's link). `--full` adds the whole description, SEO, category, the admin link and each option's SKU, barcode, feed id and prices by country. `NOT_FOUND` carries a hint to search instead.
|
|
3718
|
+
|
|
3719
|
+
**Details and buy links (`product`):** every option carries `buyUrl` — the link for a page's buy button, following the store's own setting (`buyDestination`: `checkout`, `store_cart` or `product_page`) — with `buyUrlKind`, `unavailable` when it can't be bought, and `notes` for what a link can't do (`password_protected`, `subscription_only`, `subscription_optional`, `own_storefront`, `details_pending`). `--quantity <1-99>` sets how many it adds. `videos[]` lists the product's videos in the library (`videoId`, `playbackId`); `contentSummary` names what else Baker keeps. `--content` adds `content`: the formatted description, every custom field by its name (long values previewed, `truncated: true`), the rating, subscriptions, bundle, YouTube/Vimeo and 3D links, translations, and `unreadable` for content the store owner hasn't let Baker read yet. `--field <name|namespace.key>` returns one field whole. `--full` adds `--content`, all three links per option and each option's weight, unit price, shipping and tax. `store` adds `buyDestination`, `passwordProtected`, `languages`, `policies` (`--full`: their text, and the store's brand).
|
|
3720
|
+
**`collections`:** `--search <words>`; each row has `handle`, Shopify's product count and, on a store with an online store, `onStore`.
|
|
3721
|
+
**`stock`:** `--collection`, `--limit <1-200>` (default 50 per list), `--full` (SKUs and Baker links). Options that keep selling at zero or don't track stock are not out of stock.
|
|
3722
|
+
**`sales`:** `--days <1-395>` (default 30), `--by day|product|campaign|landing` (default `day`), `--limit <1-100>`, `--full` (each row's source, medium, campaign, click platform, landing or product id). `data.totals` (`orders`, `sales`, `added`, `refunded`, `net`) in `data.currency`; `data.rows[]` with a `label` and, by campaign or landing, a `credit` (`campaign` · `order` · `landing` · `unattributed` · `before_baker` · `other`), adding up to the totals. A sale counts when it is paid, at what was received; by day and product each fact counts when it happened, by campaign and landing each order paid in the period carries what was added and refunded on it since. `meta.salesReporting` (`meta`, `google`: `baker` · `shopify_channel` · `undecided`) says who reports the sales to the ad platforms; `meta.history` is `importing` while past orders still come in.
|
|
3723
|
+
|
|
3724
|
+
**`sales --by weekday|hour|month|month_of_year`:** orders placed in the period by when they were placed, in the store's timezone (`data.window.timezone`), from the store's whole order history — `--days` up to 3650 or `--all` (only these breakdowns take them).
|
|
3725
|
+
|
|
3726
|
+
**Buyers, countries and best sellers** (`buyers`, `buyer`, `countries`, `best-sellers`, `cohorts`, `segments`) read the store's whole order history as Baker keeps it. Every answer carries `meta.window` (local `from`/`to`, `days` or `"all"`, the store's `timezone`), `meta.history` (`state`: `importing` · `done` · `failed` · `none`; `reach`: `all` or `60_days`; the first day held) and `meta.basis` (`all_orders`, or `last_60_days` when the store lets Baker read only its last 60 days — then a buyer whose earlier orders are older counts as new). The period is orders **placed** in it, with what was refunded on them since. A buyer is a numbered customer (`Customer #1042`) with a country, region and city — never a name or an email; guest orders count in money, never as buyers. Shared flags: `--days <1-3650>` (default 365) or `--all`, `--country <ISO2>`, `--full`.
|
|
3727
|
+
|
|
3728
|
+
- **`buyers`:** `data.summary` (buyers, new and returning, guest orders, orders, net, average order, new/returning orders and net, repeat rate, median days to a second order), `data.segments`, `data.thresholds`, `data.buyers[]` (`--sort net|orders|recent|first`, `--limit`, `--offset`, `--segment best|loyal|at_risk|new|one_time`, `--channel <key>`), and with `--by campaign|channel` `data.acquisition.rows[]` (buyers whose first order is in the period, first-order net, lifetime net per buyer, average orders, repeat rate). Baker keeps no ad spend.
|
|
3729
|
+
- **`buyer <number>`:** `1042`, `#1042` or `Customer #1042`. A buyer erased by their store or merged into another answers `NOT_FOUND` "This buyer is no longer in Baker."
|
|
3730
|
+
- **`countries`:** `data.total`, `data.rows[]` (orders, buyers, new buyers, net, average order, share, growth against the period before, the currency paid in), `data.unknown` (no readable address) and `data.other` (past `--limit`), adding up to the total; `--country` for its regions, `--region` for a region's cities, `--product <id|handle>` for one product's orders and money.
|
|
3731
|
+
- **`best-sellers`:** `--view products` (default; units ordered beside refunded units, orders, buyers, revenue, refunds, refund rate, growth; `--sort units|revenue|orders`) · `variants` (with `--product`) · `trend` · `together` · `repeat` · `momentum`.
|
|
3732
|
+
- **`cohorts`:** `--months <3-36>` (default 12); retention at months 1, 2, 3, 6, 12 and net per buyer by month 12 (`--full`: every month).
|
|
3733
|
+
- **`segments`:** each segment's buyers, share, net, average orders, days since the last order, top countries and first products, and its rule in this store's numbers.
|
|
3734
|
+
|
|
3735
|
+
**`promotions`:** positional `<ref>` like `product`. Reads the product, scans this workspace's `src/pages/*` (import graph, ≤ 300 pages, files ≤ 256 KB) for its buy link, `/products/<handle>` or an option id, then `POST /api/shopify/promotions` with the linked landings. `data.ads[]` (`platform`, `level` ad|asset_group, `name`, `campaign`, `status` active|paused, `via` product_page|buy_link|landing), `data.landings[]` (`published`, `via` links_to_product|visitors_went_on), `data.shopping[]`, `data.catalog_ads`, `data.checked` (`not_checked` names a platform it could not read), `data.remembered` (the read was kept for this Session — only then is a pause staged from it undone when the product is back). `--full` adds ids, accounts, campaign / ad group / ad set ids, the Google `resource` and the URL.
|
|
3736
|
+
|
|
3737
|
+
**`stock-holds`:** `--product <ref>`, `--all` (resolved holds too). `data.holds[]` — one per paused entity and product, with `verdict` (`resumable` · `still_out_of_stock` · `changed_since` · `already_active` · `still_promotes_out_of_stock` · `cannot_confirm`) read live from the ad platform; `data.pending_sessions[]` — out-of-stock work still waiting for review that would pause this product's ads.
|
|
3738
|
+
|
|
3739
|
+
**Refusals:** `NO_SHOPIFY_CONNECTION` — no store is connected; `error.fix.action` is `request_connection` (`{ platform: "shopify" }`). `SHOPIFY_NOT_AVAILABLE` — Shopify can't be connected on this Baker yet; `error.fix.action` is `continue_without`. Both exit 1.
|
|
3740
|
+
|
|
3741
|
+
---
|
|
3742
|
+
|
|
3709
3743
|
### `baker chats list | view | transcript | diff`
|
|
3710
3744
|
|
|
3711
3745
|
Read-only inspection of **other Sessions (chats) on the same account** — so an agent can reuse prior work ("like we did in that other chat, but for X"). Same-account only; never crosses a company boundary and has no write surface.
|
|
@@ -3933,19 +3967,12 @@ baker canvas validate my-canvas.json
|
|
|
3933
3967
|
# or the same ad rendered once per aspect ratio instead of one hero + a terminal
|
|
3934
3968
|
# image_aspect_adapt (IMAGE_PARALLEL_FORMAT_RENDERS — separate renders drift in type,
|
|
3935
3969
|
# crop, and color, so the sizes stop matching).
|
|
3936
|
-
# A generator prompt is measured with its {{slots}} filled from text nodes and local
|
|
3937
|
-
# prompt.json/text ingests: past the model's character cap it is refused as
|
|
3938
|
-
# PROMPT_OVER_MODEL_LIMIT, naming the node and the overshoot, before anything bills.
|
|
3939
|
-
# `scaffold-static-ad` runs the same check on the prompt.json it writes and, when it is over,
|
|
3940
|
-
# still writes the canvas and returns the overshoot in `hints[]` — trim prompt.json, then validate.
|
|
3941
3970
|
|
|
3942
3971
|
# 2. Run (executes nodes, writes files to ./canvas/<run_id>/)
|
|
3943
3972
|
baker canvas run my-canvas.json
|
|
3944
3973
|
# Advisory warnings print as `[warn] <CODE>: …` before anything bills.
|
|
3945
3974
|
# Only nodes reachable from the declared output execute (orphaned nodes are skipped,
|
|
3946
3975
|
# not billed). Add --keep-runs N to prune old r_* run dirs, keeping the N newest.
|
|
3947
|
-
# A failed run reports `error.code: "input_invalid"` when the backend refused a node's
|
|
3948
|
-
# own input (it fails the same way until the input changes), `"runtime"` otherwise.
|
|
3949
3976
|
|
|
3950
3977
|
# 2b. Independent nodes ALREADY fan out in parallel — every node in the same
|
|
3951
3978
|
# topological layer (e.g. all the per-clip video_generate nodes) runs concurrently
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ApiError,
|
|
3
3
|
apiGet
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UMIALY2G.js";
|
|
5
5
|
import {
|
|
6
6
|
getEnv
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7YNOGIWQ.js";
|
|
8
8
|
|
|
9
9
|
// src/error-handler.ts
|
|
10
10
|
var REQUEST_CONNECTION_PLATFORM = {
|
|
@@ -297,4 +297,4 @@ export {
|
|
|
297
297
|
writeAdsOutput,
|
|
298
298
|
resolveCustomerId
|
|
299
299
|
};
|
|
300
|
-
//# sourceMappingURL=chunk-
|
|
300
|
+
//# sourceMappingURL=chunk-2QXMPTHG.js.map
|
|
@@ -282,434 +282,6 @@ function isBakerApiKey(value) {
|
|
|
282
282
|
return KEY_PREFIXES.some((prefix) => value.startsWith(prefix));
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
// src/schemas.ts
|
|
286
|
-
var registry = /* @__PURE__ */ new Map();
|
|
287
|
-
function registerSchema(schema) {
|
|
288
|
-
registry.set(schema.command, schema);
|
|
289
|
-
}
|
|
290
|
-
function listSchemas() {
|
|
291
|
-
return [...registry.keys()];
|
|
292
|
-
}
|
|
293
|
-
function spellingKey(name) {
|
|
294
|
-
return name.toLowerCase().replaceAll("-", "");
|
|
295
|
-
}
|
|
296
|
-
function resolveSchemaName(words, names) {
|
|
297
|
-
const joined = words.join(".");
|
|
298
|
-
if (names.includes(joined)) {
|
|
299
|
-
return joined;
|
|
300
|
-
}
|
|
301
|
-
const matches = names.filter((name) => spellingKey(name) === spellingKey(joined));
|
|
302
|
-
return matches.length === 1 ? matches[0] : void 0;
|
|
303
|
-
}
|
|
304
|
-
function findSchema(words) {
|
|
305
|
-
const name = resolveSchemaName(words, listSchemas());
|
|
306
|
-
return name === void 0 ? void 0 : registry.get(name);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// src/unknown-flags.ts
|
|
310
|
-
var ALWAYS_ACCEPTED = /* @__PURE__ */ new Set(["help", "h", "version"]);
|
|
311
|
-
function subCommandsOf(command) {
|
|
312
|
-
const sub = command.subCommands;
|
|
313
|
-
return sub && typeof sub === "object" ? sub : null;
|
|
314
|
-
}
|
|
315
|
-
function argsOf(command) {
|
|
316
|
-
const args = command.args;
|
|
317
|
-
return args && typeof args === "object" ? args : null;
|
|
318
|
-
}
|
|
319
|
-
function resolveCommand(root, argv) {
|
|
320
|
-
let command = root;
|
|
321
|
-
for (const token of argv) {
|
|
322
|
-
if (token === "--" || token.startsWith("-")) {
|
|
323
|
-
break;
|
|
324
|
-
}
|
|
325
|
-
const subCommands = subCommandsOf(command);
|
|
326
|
-
if (!subCommands) {
|
|
327
|
-
break;
|
|
328
|
-
}
|
|
329
|
-
const next = subCommands[token];
|
|
330
|
-
if (next === void 0) {
|
|
331
|
-
break;
|
|
332
|
-
}
|
|
333
|
-
if (typeof next !== "object") {
|
|
334
|
-
return { command, resolved: false };
|
|
335
|
-
}
|
|
336
|
-
command = next;
|
|
337
|
-
}
|
|
338
|
-
return { command, resolved: true };
|
|
339
|
-
}
|
|
340
|
-
function typeOf(def) {
|
|
341
|
-
return def && typeof def === "object" ? def.type : void 0;
|
|
342
|
-
}
|
|
343
|
-
function acceptedNames(command) {
|
|
344
|
-
const args = argsOf(command);
|
|
345
|
-
if (!args) {
|
|
346
|
-
return null;
|
|
347
|
-
}
|
|
348
|
-
const names = new Set(ALWAYS_ACCEPTED);
|
|
349
|
-
for (const [name, def] of Object.entries(args)) {
|
|
350
|
-
if (typeOf(def) === "positional") {
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
for (const spelling of [name, kebab(name), camel(name)]) {
|
|
354
|
-
names.add(spelling);
|
|
355
|
-
if (typeOf(def) === "boolean") {
|
|
356
|
-
names.add(`no-${spelling}`);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
return names;
|
|
361
|
-
}
|
|
362
|
-
function kebab(name) {
|
|
363
|
-
return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
364
|
-
}
|
|
365
|
-
function camel(name) {
|
|
366
|
-
return name.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
367
|
-
}
|
|
368
|
-
function findUnknownFlags(root, argv) {
|
|
369
|
-
const { command, resolved } = resolveCommand(root, argv);
|
|
370
|
-
if (!resolved) {
|
|
371
|
-
return [];
|
|
372
|
-
}
|
|
373
|
-
const accepted = acceptedNames(command);
|
|
374
|
-
if (!accepted) {
|
|
375
|
-
return [];
|
|
376
|
-
}
|
|
377
|
-
const unknown = [];
|
|
378
|
-
for (const token of argv) {
|
|
379
|
-
if (token === "--") {
|
|
380
|
-
break;
|
|
381
|
-
}
|
|
382
|
-
if (!token.startsWith("--")) {
|
|
383
|
-
continue;
|
|
384
|
-
}
|
|
385
|
-
const name = token.slice(2).split("=")[0] ?? "";
|
|
386
|
-
if (name.length > 0 && !accepted.has(name) && !unknown.includes(token)) {
|
|
387
|
-
unknown.push(token);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
return unknown;
|
|
391
|
-
}
|
|
392
|
-
var SYNONYMS = {
|
|
393
|
-
from: ["start-date", "start", "since"],
|
|
394
|
-
since: ["start-date", "start"],
|
|
395
|
-
start: ["start-date", "since"],
|
|
396
|
-
to: ["end-date", "end", "until"],
|
|
397
|
-
until: ["end-date", "end"],
|
|
398
|
-
end: ["end-date", "until"],
|
|
399
|
-
path: ["landing"],
|
|
400
|
-
url: ["landing"]
|
|
401
|
-
};
|
|
402
|
-
function closestFlag(unknown, command) {
|
|
403
|
-
const accepted = acceptedNames(command);
|
|
404
|
-
if (!accepted) {
|
|
405
|
-
return null;
|
|
406
|
-
}
|
|
407
|
-
const name = unknown.replace(/^--/, "").split("=")[0] ?? "";
|
|
408
|
-
const synonym = SYNONYMS[name]?.find((candidate) => accepted.has(candidate));
|
|
409
|
-
if (synonym) {
|
|
410
|
-
return `--${synonym}`;
|
|
411
|
-
}
|
|
412
|
-
const scored = [...accepted].filter((candidate) => !ALWAYS_ACCEPTED.has(candidate)).map((candidate) => ({
|
|
413
|
-
candidate,
|
|
414
|
-
prefix: sharedPrefix(name, candidate),
|
|
415
|
-
distance: editDistance(name, candidate)
|
|
416
|
-
})).filter(({ prefix, distance }) => prefix >= 4 || distance <= typoBudget(name)).sort((a, b) => b.prefix - a.prefix || a.distance - b.distance);
|
|
417
|
-
return scored[0] ? `--${scored[0].candidate}` : null;
|
|
418
|
-
}
|
|
419
|
-
function typoBudget(name) {
|
|
420
|
-
return Math.max(1, Math.floor(name.length / 3));
|
|
421
|
-
}
|
|
422
|
-
function sharedPrefix(a, b) {
|
|
423
|
-
let i = 0;
|
|
424
|
-
while (i < a.length && i < b.length && a[i] === b[i]) {
|
|
425
|
-
i++;
|
|
426
|
-
}
|
|
427
|
-
return i;
|
|
428
|
-
}
|
|
429
|
-
function editDistance(a, b) {
|
|
430
|
-
let previous = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
431
|
-
for (let i = 1; i <= a.length; i++) {
|
|
432
|
-
const current = [i];
|
|
433
|
-
for (let j = 1; j <= b.length; j++) {
|
|
434
|
-
const substitution = (previous[j - 1] ?? 0) + (a[i - 1] === b[j - 1] ? 0 : 1);
|
|
435
|
-
current.push(Math.min((previous[j] ?? 0) + 1, (current[j - 1] ?? 0) + 1, substitution));
|
|
436
|
-
}
|
|
437
|
-
previous = current;
|
|
438
|
-
}
|
|
439
|
-
return previous[b.length] ?? 0;
|
|
440
|
-
}
|
|
441
|
-
function commandFor(root, argv) {
|
|
442
|
-
const { command, resolved } = resolveCommand(root, argv);
|
|
443
|
-
return resolved ? command : null;
|
|
444
|
-
}
|
|
445
|
-
function suggestFlag(unknown, command) {
|
|
446
|
-
const flag = closestFlag(unknown, command);
|
|
447
|
-
if (!flag) {
|
|
448
|
-
return null;
|
|
449
|
-
}
|
|
450
|
-
const args = argsOf(command) ?? {};
|
|
451
|
-
const name = flag.slice(2);
|
|
452
|
-
const def = args[name] ?? args[camel(name)];
|
|
453
|
-
const described = def && typeof def === "object" ? def.description : void 0;
|
|
454
|
-
const description = typeof described === "string" ? described.split(/(?<!\b(?:e\.g|i\.e|vs))\.\s/)[0]?.trim().replace(/\.$/, "") : "";
|
|
455
|
-
return description ? { flag, description } : { flag };
|
|
456
|
-
}
|
|
457
|
-
function suggestionText(suggestion) {
|
|
458
|
-
if (!suggestion) {
|
|
459
|
-
return "";
|
|
460
|
-
}
|
|
461
|
-
return suggestion.description ? `Did you mean ${suggestion.flag}? It is described as: ${suggestion.description}. ` : `Did you mean ${suggestion.flag}? `;
|
|
462
|
-
}
|
|
463
|
-
var OUTPUT_EXPLANATION = "This command has no --output option: `--output json` is accepted by every command that prints the JSON envelope, and md or files only where `baker schema` lists `output`. Drop the option and read the default output. ";
|
|
464
|
-
function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
|
|
465
|
-
const list = unknown.join(", ");
|
|
466
|
-
return {
|
|
467
|
-
ok: false,
|
|
468
|
-
error: {
|
|
469
|
-
code: "UNKNOWN_ARGUMENT",
|
|
470
|
-
message: `${list} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
|
|
471
|
-
fix: {
|
|
472
|
-
action: hasSchema ? "check_schema" : "check_help",
|
|
473
|
-
explanation: (unknown.some((flag) => flag === "--output" || flag.startsWith("--output=")) ? OUTPUT_EXPLANATION : "") + suggestionText(suggestion) + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
|
|
474
|
-
},
|
|
475
|
-
retryable: false
|
|
476
|
-
}
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
function commandPathOf(root, argv) {
|
|
480
|
-
const path = [];
|
|
481
|
-
let command = root;
|
|
482
|
-
for (const token of argv) {
|
|
483
|
-
if (token === "--" || token.startsWith("-")) {
|
|
484
|
-
break;
|
|
485
|
-
}
|
|
486
|
-
const subCommands = subCommandsOf(command);
|
|
487
|
-
const next = subCommands?.[token];
|
|
488
|
-
if (next === void 0 || typeof next !== "object") {
|
|
489
|
-
break;
|
|
490
|
-
}
|
|
491
|
-
path.push(token);
|
|
492
|
-
command = next;
|
|
493
|
-
}
|
|
494
|
-
return path.join(" ");
|
|
495
|
-
}
|
|
496
|
-
function refuseUnknownFlags(root, argv) {
|
|
497
|
-
const unknown = findUnknownFlags(root, argv);
|
|
498
|
-
if (unknown.length === 0) {
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
501
|
-
const command = commandFor(root, argv);
|
|
502
|
-
const first = unknown[0];
|
|
503
|
-
const suggestion = command && first ? suggestFlag(first, command) : null;
|
|
504
|
-
const path = commandPathOf(root, argv);
|
|
505
|
-
process.stdout.write(
|
|
506
|
-
`${JSON.stringify(unknownFlagEnvelope(unknown, path, suggestion, findSchema(path.split(" ")) !== void 0), null, 2)}
|
|
507
|
-
`
|
|
508
|
-
);
|
|
509
|
-
process.exit(1);
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// src/output-flag.ts
|
|
513
|
-
var FLAG = "--output";
|
|
514
|
-
var ENVELOPE = "json";
|
|
515
|
-
var PRINTS_NO_ENVELOPE = /* @__PURE__ */ new Set([
|
|
516
|
-
"analytics sending-events",
|
|
517
|
-
"canvas run",
|
|
518
|
-
"canvas rerun",
|
|
519
|
-
"canvas sync-definition"
|
|
520
|
-
]);
|
|
521
|
-
function declaredArg(command, name) {
|
|
522
|
-
const args = command.args;
|
|
523
|
-
if (!args || typeof args !== "object" || !(name in args)) {
|
|
524
|
-
return null;
|
|
525
|
-
}
|
|
526
|
-
const def = args[name];
|
|
527
|
-
return def && typeof def === "object" ? def : {};
|
|
528
|
-
}
|
|
529
|
-
function envelopeRequests(argv) {
|
|
530
|
-
const end = argv.indexOf("--");
|
|
531
|
-
const limit = end === -1 ? argv.length : end;
|
|
532
|
-
const found = [];
|
|
533
|
-
for (let index = 0; index < limit; index++) {
|
|
534
|
-
const token = argv[index];
|
|
535
|
-
if (token === `${FLAG}=${ENVELOPE}`) {
|
|
536
|
-
found.push({ index, length: 1 });
|
|
537
|
-
} else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 < limit) {
|
|
538
|
-
found.push({ index, length: 2 });
|
|
539
|
-
index++;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
return found;
|
|
543
|
-
}
|
|
544
|
-
function outputFlagForCommand(root, argv) {
|
|
545
|
-
const requests = envelopeRequests(argv);
|
|
546
|
-
if (requests.length === 0) {
|
|
547
|
-
return argv;
|
|
548
|
-
}
|
|
549
|
-
const command = commandFor(root, argv);
|
|
550
|
-
if (!command || declaredArg(command, "output") || PRINTS_NO_ENVELOPE.has(commandPathOf(root, argv))) {
|
|
551
|
-
return argv;
|
|
552
|
-
}
|
|
553
|
-
const jsonSwitch = declaredArg(command, "json")?.type === "boolean";
|
|
554
|
-
const dropped = new Set(requests.flatMap(({ index, length }) => length === 2 ? [index, index + 1] : [index]));
|
|
555
|
-
const first = requests[0]?.index;
|
|
556
|
-
return argv.flatMap((token, index) => {
|
|
557
|
-
if (!dropped.has(index)) {
|
|
558
|
-
return [token];
|
|
559
|
-
}
|
|
560
|
-
return jsonSwitch && index === first ? ["--json"] : [];
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// src/field-mask.ts
|
|
565
|
-
var FLAG2 = "--fields";
|
|
566
|
-
function parseFields(value) {
|
|
567
|
-
return value.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
|
|
568
|
-
}
|
|
569
|
-
function takeFieldsFlag(root, argv) {
|
|
570
|
-
const end = argv.indexOf("--");
|
|
571
|
-
const limit = end === -1 ? argv.length : end;
|
|
572
|
-
const taken = /* @__PURE__ */ new Set();
|
|
573
|
-
const fields = [];
|
|
574
|
-
for (let index = 0; index < limit; index++) {
|
|
575
|
-
const token = argv[index] ?? "";
|
|
576
|
-
if (token.startsWith(`${FLAG2}=`)) {
|
|
577
|
-
taken.add(index);
|
|
578
|
-
fields.push(...parseFields(token.slice(FLAG2.length + 1)));
|
|
579
|
-
} else if (token === FLAG2) {
|
|
580
|
-
const value = argv[index + 1];
|
|
581
|
-
if (value === void 0 || index + 1 >= limit || value.startsWith("-")) {
|
|
582
|
-
return { argv, fields: null };
|
|
583
|
-
}
|
|
584
|
-
taken.add(index).add(index + 1);
|
|
585
|
-
fields.push(...parseFields(value));
|
|
586
|
-
index++;
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
if (taken.size === 0 || fields.length === 0) {
|
|
590
|
-
return { argv, fields: null };
|
|
591
|
-
}
|
|
592
|
-
const command = commandFor(root, argv);
|
|
593
|
-
if (!command || declaredArg(command, "fields") || PRINTS_NO_ENVELOPE.has(commandPathOf(root, argv))) {
|
|
594
|
-
return { argv, fields: null };
|
|
595
|
-
}
|
|
596
|
-
return { argv: argv.filter((_, index) => !taken.has(index)), fields };
|
|
597
|
-
}
|
|
598
|
-
function isRecord(value) {
|
|
599
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
600
|
-
}
|
|
601
|
-
function pick(record, fields) {
|
|
602
|
-
return Object.fromEntries(fields.filter((field) => field in record).map((field) => [field, record[field]]));
|
|
603
|
-
}
|
|
604
|
-
function soleList(data) {
|
|
605
|
-
const lists = Object.entries(data).filter(
|
|
606
|
-
(entry) => Array.isArray(entry[1]) && entry[1].length > 0 && entry[1].every((item) => isRecord(item))
|
|
607
|
-
);
|
|
608
|
-
return lists.length === 1 ? lists[0] ?? null : null;
|
|
609
|
-
}
|
|
610
|
-
function wrappedList(data, fields) {
|
|
611
|
-
const rowFields = fields.filter((field) => !(field in data));
|
|
612
|
-
const list = soleList(data);
|
|
613
|
-
if (list === null || !list[1].some((row) => rowFields.some((field) => field in row))) {
|
|
614
|
-
return null;
|
|
615
|
-
}
|
|
616
|
-
return list[0];
|
|
617
|
-
}
|
|
618
|
-
function recordsOf(data, fields) {
|
|
619
|
-
if (Array.isArray(data)) {
|
|
620
|
-
return data;
|
|
621
|
-
}
|
|
622
|
-
if (!isRecord(data)) {
|
|
623
|
-
return [];
|
|
624
|
-
}
|
|
625
|
-
const list = wrappedList(data, fields);
|
|
626
|
-
return list === null ? [data] : data[list];
|
|
627
|
-
}
|
|
628
|
-
function maskData(data, fields) {
|
|
629
|
-
const maskWith = (keep) => (item) => isRecord(item) ? pick(item, keep) : item;
|
|
630
|
-
if (Array.isArray(data)) {
|
|
631
|
-
return data.map(maskWith(fields));
|
|
632
|
-
}
|
|
633
|
-
if (!isRecord(data)) {
|
|
634
|
-
return data;
|
|
635
|
-
}
|
|
636
|
-
const list = wrappedList(data, fields);
|
|
637
|
-
if (list === null) {
|
|
638
|
-
return pick(data, fields);
|
|
639
|
-
}
|
|
640
|
-
const wrapperFields = fields.filter((field) => field in data);
|
|
641
|
-
const rows = recordsOf(data, fields).map(maskWith(fields.filter((field) => !(field in data))));
|
|
642
|
-
return { ...wrapperFields.length > 0 ? pick(data, wrapperFields) : data, [list]: rows };
|
|
643
|
-
}
|
|
644
|
-
function unmatchedHint(data, fields) {
|
|
645
|
-
const records = recordsOf(data, fields).filter(isRecord);
|
|
646
|
-
if (records.length === 0) {
|
|
647
|
-
return null;
|
|
648
|
-
}
|
|
649
|
-
const keys = isRecord(data) ? [data, ...soleList(data)?.[1] ?? []] : records;
|
|
650
|
-
const carried = new Set(keys.flatMap((record) => Object.keys(record)));
|
|
651
|
-
const unmatched = fields.filter((field) => !carried.has(field));
|
|
652
|
-
if (unmatched.length === 0) {
|
|
653
|
-
return null;
|
|
654
|
-
}
|
|
655
|
-
return `--fields matched nothing for: ${unmatched.join(", ")}. The keys data carries are: ${[...carried].join(", ")}.`;
|
|
656
|
-
}
|
|
657
|
-
function reprint(text, envelope) {
|
|
658
|
-
const indent = text.trimStart().startsWith("{\n") ? 2 : void 0;
|
|
659
|
-
return `${JSON.stringify(envelope, null, indent)}${text.endsWith("\n") ? "\n" : ""}`;
|
|
660
|
-
}
|
|
661
|
-
function withHint(envelope, hint) {
|
|
662
|
-
return { ...envelope, hints: [...Array.isArray(envelope.hints) ? envelope.hints : [], hint] };
|
|
663
|
-
}
|
|
664
|
-
var NO_DATA_HINT = "--fields was not applied: this result carries no data to narrow, so it is printed whole. Drop --fields on this command.";
|
|
665
|
-
function maskPrintedEnvelope(text, fields) {
|
|
666
|
-
let parsed;
|
|
667
|
-
try {
|
|
668
|
-
parsed = JSON.parse(text);
|
|
669
|
-
} catch {
|
|
670
|
-
return null;
|
|
671
|
-
}
|
|
672
|
-
if (!isRecord(parsed) || typeof parsed.ok !== "boolean") {
|
|
673
|
-
return null;
|
|
674
|
-
}
|
|
675
|
-
if (parsed.ok !== true || "dryRun" in parsed) {
|
|
676
|
-
return text;
|
|
677
|
-
}
|
|
678
|
-
return reprint(text, maskEnvelope(parsed, fields));
|
|
679
|
-
}
|
|
680
|
-
function maskEnvelope(envelope, fields) {
|
|
681
|
-
if (!("data" in envelope)) {
|
|
682
|
-
return withHint(envelope, NO_DATA_HINT);
|
|
683
|
-
}
|
|
684
|
-
const masked = { ...envelope, data: maskData(envelope.data, fields) };
|
|
685
|
-
const miss = unmatchedHint(envelope.data, fields);
|
|
686
|
-
return miss ? withHint(masked, miss) : masked;
|
|
687
|
-
}
|
|
688
|
-
function maskWrites(stream, fields) {
|
|
689
|
-
let applied = false;
|
|
690
|
-
const write2 = stream.write.bind(stream);
|
|
691
|
-
stream.write = (chunk, ...rest) => {
|
|
692
|
-
const masked = typeof chunk === "string" ? maskPrintedEnvelope(chunk, fields) : null;
|
|
693
|
-
if (masked === null) {
|
|
694
|
-
return write2(chunk, ...rest);
|
|
695
|
-
}
|
|
696
|
-
applied = true;
|
|
697
|
-
return write2(masked, ...rest);
|
|
698
|
-
};
|
|
699
|
-
return { sawEnvelope: () => applied };
|
|
700
|
-
}
|
|
701
|
-
function installFieldMask(fields, commandPath) {
|
|
702
|
-
const mask = maskWrites(process.stdout, fields);
|
|
703
|
-
process.on("exit", () => {
|
|
704
|
-
if (!mask.sawEnvelope()) {
|
|
705
|
-
process.stderr.write(
|
|
706
|
-
`--fields was not applied: \`baker ${commandPath}\` printed no JSON envelope to narrow. Add --output json to get the envelope, or drop --fields.
|
|
707
|
-
`
|
|
708
|
-
);
|
|
709
|
-
}
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
|
|
713
285
|
// src/output.ts
|
|
714
286
|
var ASPECT_RATIO_MAP = {
|
|
715
287
|
"1:1": 1,
|
|
@@ -1099,8 +671,7 @@ function writeOutput(envelope, format, fields, full, normalizer) {
|
|
|
1099
671
|
return;
|
|
1100
672
|
}
|
|
1101
673
|
if (format === "json") {
|
|
1102
|
-
|
|
1103
|
-
`);
|
|
674
|
+
writeJson(envelope);
|
|
1104
675
|
return;
|
|
1105
676
|
}
|
|
1106
677
|
if (format !== "files" && format !== "md") {
|
|
@@ -1258,14 +829,6 @@ export {
|
|
|
1258
829
|
plannedRoutes,
|
|
1259
830
|
API_KEY_FORMAT_MESSAGE,
|
|
1260
831
|
isBakerApiKey,
|
|
1261
|
-
registerSchema,
|
|
1262
|
-
listSchemas,
|
|
1263
|
-
findSchema,
|
|
1264
|
-
commandPathOf,
|
|
1265
|
-
refuseUnknownFlags,
|
|
1266
|
-
outputFlagForCommand,
|
|
1267
|
-
takeFieldsFlag,
|
|
1268
|
-
installFieldMask,
|
|
1269
832
|
compactImage,
|
|
1270
833
|
compactVideo,
|
|
1271
834
|
videoNormalizer,
|
|
@@ -1289,4 +852,4 @@ export {
|
|
|
1289
852
|
captureVimeoCookie,
|
|
1290
853
|
childEnvWith
|
|
1291
854
|
};
|
|
1292
|
-
//# sourceMappingURL=chunk-
|
|
855
|
+
//# sourceMappingURL=chunk-7YNOGIWQ.js.map
|