@koda-sl/baker-cli 0.244.0 → 0.246.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 +49 -24
- package/dist/cli.js +626 -573
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -278,7 +278,31 @@ baker ads google query --list-presets
|
|
|
278
278
|
}
|
|
279
279
|
```
|
|
280
280
|
|
|
281
|
-
Read it before interpreting any null.
|
|
281
|
+
Read it before interpreting any null. Field coverage is folded page by page on the `--out` path too, so the file summary reports it; `.resource_name` is never reported (the server strips it from every row).
|
|
282
|
+
|
|
283
|
+
**A page is not the data set.** Without `--all`, a query returns one page capped by `--limit` (default 200, or the `LIMIT` in the statement, whichever is smaller). With `--all` every page is followed, but the statement's `LIMIT` still caps the read — and preflight adds one at `--limit` to any query that arrives without it, so `--all` on its own still stops at 200 rows. When the rows fill whichever cap is in force, or the API returns a cursor the run did not follow, the response carries a `TRUNCATED_RESULTS` warning:
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"ok": true,
|
|
288
|
+
"warnings": [{ "code": "TRUNCATED_RESULTS", "message": "INCOMPLETE READ — ..." }],
|
|
289
|
+
"pagination": { "hasMore": true, "cursor": "eyJwYWdl..." },
|
|
290
|
+
"data": [...],
|
|
291
|
+
"notice": "Read the \"warnings\" above before using these rows: TRUNCATED_RESULTS."
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Never total or count from a response carrying it — re-run with `--all --limit 10000 --out data.csv` (the API accepts page sizes up to 10,000) and check the re-run came back without the warning. Warnings reach every output format, so no `--output` choice can hide one:
|
|
296
|
+
|
|
297
|
+
| `--output` | Where warnings land |
|
|
298
|
+
|------------|---------------------|
|
|
299
|
+
| `json` | `warnings` and `pagination` **before** `data`, one-line `notice` last |
|
|
300
|
+
| `csv` | `# baker <CODE>: …` comment lines under the header and after the last row |
|
|
301
|
+
| `md` | `> **<CODE>** — …` blockquote above and below the table |
|
|
302
|
+
| `jsonl` | a `{"_baker_warning":{…}}` line first and last |
|
|
303
|
+
| `--out` | the file summary carries `complete: true|false`, every warning, and the `notice` |
|
|
304
|
+
|
|
305
|
+
The same lines also go to stderr. A read with nothing to report prints none of it.
|
|
282
306
|
|
|
283
307
|
**Response (with pagination):**
|
|
284
308
|
|
|
@@ -311,7 +335,7 @@ Read it before interpreting any null. It does not fire on the `--out` path (rows
|
|
|
311
335
|
| `--include-paused` | Include paused entities in preset results. Off by default: presets return only actually-serving entities (enabled campaign **and** ad group **and** ad). Google Ads has no single serving flag, so the whole chain must be `ENABLED` for an entity to serve. |
|
|
312
336
|
| `--limit` | Max rows per page (default 200) |
|
|
313
337
|
| `--cursor` | Pagination cursor from previous response |
|
|
314
|
-
| `--all` | Auto-paginate all results
|
|
338
|
+
| `--all` | Auto-paginate all results. Exhausts the pages, not the statement's `LIMIT` — pair it with a `--limit` above the expected row count, and a read that still fills its cap is flagged `TRUNCATED_RESULTS` either way |
|
|
315
339
|
| `--out` | Write data to file (format from extension: .csv, .jsonl, .json) |
|
|
316
340
|
| `--append` | Append to existing file (skip CSV headers) |
|
|
317
341
|
| `--output` | Output format: `json` \| `csv` \| `jsonl` \| `md` |
|
|
@@ -337,7 +361,7 @@ Read it before interpreting any null. It does not fire on the `--out` path (rows
|
|
|
337
361
|
|
|
338
362
|
Every preset except the negatives lists and `account-summary` filters to **actually-serving entities** by default — the full status chain (`campaign.status = 'ENABLED' AND ad_group.status = 'ENABLED' AND ad_group_ad.status = 'ENABLED'`, as applicable) — and selects the status columns so you can see them. Pass `--include-paused` to widen to `!= 'REMOVED'` (keeps paused, still drops removed). Raw GAQL (no `--preset`) has no such default: a query over a serving-hierarchy resource without a status filter emits a `SERVING_SCOPE` warning reminding you to add the chain, because Google Ads has no single serving flag.
|
|
339
363
|
|
|
340
|
-
**"Eligible (Limited)" keywords:** an enabled keyword that barely shows is invisible in the performance presets — near-zero impressions look the same whether it is outbid, low quality, or rarely searched. `--preset keyword-serving` reads the signals behind Google Ads' status column: `ad_group_criterion.primary_status` and `primary_status_reasons` (the status enum has no `LIMITED` value — "(Limited)" lives in the reasons while the status stays `ELIGIBLE`), `position_estimates.first_page_cpc_micros` (the number in "Below first page bid (€3.63)"), the max CPC actually in force and where it comes from, quality score split into ad relevance / landing page / expected CTR, approval status, and `system_serving_status`. Any read whose rows carry those fields — preset or raw GAQL — comes back with a `KEYWORD_SERVING_LIMITED` warning naming the affected keywords (each by its ad group, since one keyword's copies share a criterion id) and the bid each would need. Below-first-page-bid and low-quality want opposite fixes (raise the bid vs. improve relevance), so the warning reports them separately. On `--out` the verdict is folded across pages as they stream to disk and returned on the file summary;
|
|
364
|
+
**"Eligible (Limited)" keywords:** an enabled keyword that barely shows is invisible in the performance presets — near-zero impressions look the same whether it is outbid, low quality, or rarely searched. `--preset keyword-serving` reads the signals behind Google Ads' status column: `ad_group_criterion.primary_status` and `primary_status_reasons` (the status enum has no `LIMITED` value — "(Limited)" lives in the reasons while the status stays `ELIGIBLE`), `position_estimates.first_page_cpc_micros` (the number in "Below first page bid (€3.63)"), the max CPC actually in force and where it comes from, quality score split into ad relevance / landing page / expected CTR, approval status, and `system_serving_status`. Any read whose rows carry those fields — preset or raw GAQL — comes back with a `KEYWORD_SERVING_LIMITED` warning naming the affected keywords (each by its ad group, since one keyword's copies share a criterion id) and the bid each would need. Below-first-page-bid and low-quality want opposite fixes (raise the bid vs. improve relevance), so the warning reports them separately. On `--out` the verdict is folded across pages as they stream to disk and returned on the file summary; like every other warning it also travels in `--output csv|jsonl|md`.
|
|
341
365
|
|
|
342
366
|
The warning defers to Google: when the query selects `primary_status_reasons`, a keyword Google did not flag is not reported, even if its bid sits under the first-page estimate — the estimate is advisory and the bid may not be the criterion's to set under a portfolio strategy. Only an estimates-only read (no reasons selected) falls back to inferring the limit from the bid gap.
|
|
343
367
|
|
|
@@ -432,13 +456,14 @@ baker ads google keywords discover --customer-id 1234567890 --url "https://compe
|
|
|
432
456
|
"data": {
|
|
433
457
|
"keywords": [
|
|
434
458
|
{
|
|
459
|
+
"source": "keyword_planner_estimate",
|
|
435
460
|
"keyword": "student services",
|
|
436
|
-
"
|
|
437
|
-
"
|
|
438
|
-
"
|
|
439
|
-
"
|
|
440
|
-
"
|
|
441
|
-
"
|
|
461
|
+
"planner_avg_monthly_searches": "1000",
|
|
462
|
+
"planner_competition": "LOW",
|
|
463
|
+
"planner_competition_index": "4",
|
|
464
|
+
"planner_low_top_of_page_bid_micros": 0,
|
|
465
|
+
"planner_high_top_of_page_bid_micros": 0,
|
|
466
|
+
"planner_monthly_search_volumes": [
|
|
442
467
|
{ "year": "2025", "month": "APRIL", "monthly_searches": "590" }
|
|
443
468
|
]
|
|
444
469
|
}
|
|
@@ -447,12 +472,13 @@ baker ads google keywords discover --customer-id 1234567890 --url "https://compe
|
|
|
447
472
|
"next_page_token": "..."
|
|
448
473
|
},
|
|
449
474
|
"fields": {
|
|
475
|
+
"source": "Always \"keyword_planner_estimate\" — these rows are Keyword Planner ESTIMATES of total market search volume, NOT this account's data",
|
|
450
476
|
"keyword": "Suggested keyword text",
|
|
451
|
-
"
|
|
452
|
-
"
|
|
453
|
-
"
|
|
454
|
-
"
|
|
455
|
-
"
|
|
477
|
+
"planner_avg_monthly_searches": "ESTIMATE: average monthly searches across the whole market",
|
|
478
|
+
"planner_competition": "ESTIMATE: competition level — LOW, MEDIUM, HIGH, UNKNOWN",
|
|
479
|
+
"planner_competition_index": "ESTIMATE: competition index 0-100 (higher = more competitive)",
|
|
480
|
+
"planner_low_top_of_page_bid_micros": "ESTIMATE: low-range CPC bid in micros (÷ 1,000,000 for currency)",
|
|
481
|
+
"planner_high_top_of_page_bid_micros": "ESTIMATE: high-range CPC bid in micros (÷ 1,000,000 for currency)"
|
|
456
482
|
}
|
|
457
483
|
}
|
|
458
484
|
```
|
|
@@ -491,13 +517,14 @@ baker ads google keywords metrics --customer-id 1234567890 --keywords "running s
|
|
|
491
517
|
"data": {
|
|
492
518
|
"historical_metrics": [
|
|
493
519
|
{
|
|
520
|
+
"source": "keyword_planner_estimate",
|
|
494
521
|
"keyword": "running shoes",
|
|
495
|
-
"
|
|
496
|
-
"
|
|
497
|
-
"
|
|
498
|
-
"
|
|
499
|
-
"
|
|
500
|
-
"
|
|
522
|
+
"planner_avg_monthly_searches": "1000",
|
|
523
|
+
"planner_competition": "LOW",
|
|
524
|
+
"planner_competition_index": "4",
|
|
525
|
+
"planner_low_top_of_page_bid_micros": 0,
|
|
526
|
+
"planner_high_top_of_page_bid_micros": 0,
|
|
527
|
+
"planner_monthly_search_volumes": [
|
|
501
528
|
{ "year": "2025", "month": "APRIL", "monthly_searches": "590" }
|
|
502
529
|
]
|
|
503
530
|
}
|
|
@@ -5623,7 +5650,7 @@ baker landing inspiration scrape <url> --out .baker/<dir> # capture any page n
|
|
|
5623
5650
|
- **`add` studies in the background; `scrape` returns with the page on disk.** `add` grows the shared library and takes minutes, so it can never answer "build our page like this one" within the same turn. `scrape` runs the identical capture locally and blocks until it finishes, writing section screenshots, standalone markup, a whole-page reproduction and `report.html`. `--no-motion` is the single biggest lever on runtime; `--no-mobile`, `--no-code` and `--no-report` skip further passes.
|
|
5624
5651
|
- **Filming is the expensive pass, and it runs three sections at a time.** Every moving section is filmed in its own fresh page load — the only way to catch an entrance animation before it fires — so a page with ten moving sections pays for ten full loads. Measured on one heavy page, filming was 74% of the capture. The takes are independent, so they overlap; a page that cannot be captured inside the library's budget now says so instead of timing out silently.
|
|
5625
5652
|
- **A page we can't open says why.** A dead certificate, an address that doesn't resolve, a site that won't answer or one that is simply too slow each produce their own plain-language reason rather than a browser error.
|
|
5626
|
-
- **Inspiration, never a clipboard.**
|
|
5653
|
+
- **Inspiration, never a clipboard.** A reference's structure and mechanism are the lesson; write the client's own words.
|
|
5627
5654
|
- **A capture has to land in `.baker/`, and `scrape` refuses anywhere else in a workspace.** `--out` is free-form and the directory is the agent's choice, but a capture is tens of MB of lossless PNG whose individual files clear every size gate — written to a tracked directory it becomes a permanent part of the client's repo, force-cloned into every later session. `.baker/` is gitignored precisely so a capture costs nothing. The refusal is scoped to the workspace: outside a git work tree — a local run against `/tmp` — any path is allowed, because there is no history to bloat.
|
|
5628
5655
|
|
|
5629
5656
|
### `baker landing critique`
|
|
@@ -5645,9 +5672,7 @@ baker landing critique spring-offer summer-offer claude # score three landings
|
|
|
5645
5672
|
|
|
5646
5673
|
- **Agent washing is a copy tell.** A page that claims autonomy ("fully autonomous", "while you sleep", "no human intervention") and never says anywhere what the buyer approves, overrides, or audits scores an `agent-washing` warn. One signal about oversight of the agent's actions — approval, review, override, undo/rollback, audit log, escalation — anywhere on the page clears it; the rule is page-scope precisely because the hero can defer the trust story to a section below it. Generic privacy boilerplate ("GDPR", "encrypted", "your data") deliberately does **not** clear it, since it appears in most footers and says nothing about who is in charge of the agent.
|
|
5647
5674
|
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
Output is the standard envelope `{ ok, data, hints }` with `data = { advisory, slug, overall, counts, dimensions, findings }`. `dimensions` scores eight design families (typography, color, borders_depth, motion, spacing, copy, integrity, originality) 0–1 (higher is better); `counts` is the block/warn/advisory tally.
|
|
5675
|
+
Output is the standard envelope `{ ok, data, hints }` with `data = { advisory, slug, overall, counts, dimensions, findings }`. `dimensions` scores seven design families (typography, color, borders_depth, motion, spacing, copy, integrity) 0–1 (higher is better); `counts` is the block/warn/advisory tally.
|
|
5651
5676
|
|
|
5652
5677
|
## Brand Fonts (`baker brand fonts`)
|
|
5653
5678
|
|