@koda-sl/baker-cli 0.122.0-dev.ab8c14ab5 → 0.122.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -397,6 +397,262 @@ baker ads google keywords metrics --customer-id 1234567890 --keywords "running s
397
397
 
398
398
  ---
399
399
 
400
+ ### Google Ads Library (`baker ads google library`)
401
+
402
+ Manage and search the Google Ads Transparency Center. Track competitor advertisers, browse their ad creatives, and discover who's bidding on keywords.
403
+
404
+ **Typical workflow:** `search-advertiser` → `track` → `search-ads`
405
+
406
+ ---
407
+
408
+ ### `baker ads google library search-advertiser "query"`
409
+
410
+ Search for an advertiser on the Google Ads Transparency Center.
411
+
412
+ > **Recommended:** use the domain running the ads (e.g. `example.com`) for more accurate results.
413
+
414
+ ```bash
415
+ baker ads google library search-advertiser "example.com"
416
+ baker ads google library search-advertiser "Nike"
417
+ ```
418
+
419
+ **Response:**
420
+
421
+ ```json
422
+ {
423
+ "ok": true,
424
+ "data": {
425
+ "results": [
426
+ { "advertiserId": "AR12345678901234567", "name": "Nike, Inc.", "region": "US", "format": "TEXT_IMAGE_VIDEO" }
427
+ ]
428
+ }
429
+ }
430
+ ```
431
+
432
+ **Flags:**
433
+
434
+ | Flag | Description |
435
+ |------------|--------------------------------|
436
+ | `--output` | Format: `json` \| `csv` \| `md` |
437
+
438
+ ---
439
+
440
+ ### `baker ads google library track <id> <name>`
441
+
442
+ Track a new Google advertiser and wait for the initial ad sync to complete. Polls every 5 seconds with a 10-minute timeout. Progress is written to stderr.
443
+
444
+ ```bash
445
+ baker ads google library track AR12345678901234567 "Nike, Inc."
446
+ baker ads google library track AR12345678901234567 "Nike, Inc." --json
447
+ ```
448
+
449
+ **Response (with `--json`):**
450
+
451
+ ```json
452
+ {
453
+ "ok": true,
454
+ "data": {
455
+ "advertiserId": "ar_abc123",
456
+ "accountId": "acc_def456",
457
+ "totalAdCount": 342,
458
+ "activeAdCount": 89
459
+ }
460
+ }
461
+ ```
462
+
463
+ **Flags:**
464
+
465
+ | Flag | Description |
466
+ |----------|----------------------|
467
+ | `--json` | Output in JSON format |
468
+
469
+ ---
470
+
471
+ ### `baker ads google library list-advertisers`
472
+
473
+ List all tracked Google advertisers and their accounts.
474
+
475
+ ```bash
476
+ baker ads google library list-advertisers
477
+ baker ads google library list-advertisers --output md
478
+ ```
479
+
480
+ **Flags:**
481
+
482
+ | Flag | Description |
483
+ |------------|--------------------------------|
484
+ | `--output` | Format: `json` \| `csv` \| `md` |
485
+
486
+ ---
487
+
488
+ ### `baker ads google library sync-status <accountId>`
489
+
490
+ Check the sync status and ad counts of a tracked account.
491
+
492
+ ```bash
493
+ baker ads google library sync-status acc_def456
494
+ ```
495
+
496
+ **Response:**
497
+
498
+ ```json
499
+ {
500
+ "ok": true,
501
+ "data": {
502
+ "syncStatus": null,
503
+ "totalAdCount": 342,
504
+ "activeAdCount": 89
505
+ }
506
+ }
507
+ ```
508
+
509
+ `syncStatus` is `null` when idle, `"syncing"` during a sync, or `"error"` if the last sync failed.
510
+
511
+ ---
512
+
513
+ ### `baker ads google library search-ads <accountId>`
514
+
515
+ Search and filter ads for a tracked account. Supports pagination.
516
+
517
+ ```bash
518
+ baker ads google library search-ads acc_def456
519
+ baker ads google library search-ads acc_def456 --search "summer sale" --isActive --mediaType image
520
+ baker ads google library search-ads acc_def456 --sort newest --limit 50
521
+ baker ads google library search-ads acc_def456 --cursor "eyJwYWdl..."
522
+ ```
523
+
524
+ **Response:**
525
+
526
+ ```json
527
+ {
528
+ "ok": true,
529
+ "data": {
530
+ "page": [
531
+ {
532
+ "_id": "abc123",
533
+ "platform": "google",
534
+ "externalId": "CR_1234567890",
535
+ "isActive": true,
536
+ "mediaType": "image",
537
+ "headline": "Summer Sale — 50% Off Everything",
538
+ "description": "Shop our biggest sale of the year. Free shipping on all orders.",
539
+ "destinationUrl": "https://example.com/summer-sale",
540
+ "bodyText": "Summer Sale — 50% Off Everything",
541
+ "pageName": "Example Store",
542
+ "impressionsMin": 100000,
543
+ "impressionsMax": 200000,
544
+ "startDate": "2025-06-01",
545
+ "endDate": "2025-06-30",
546
+ "firstSeenAt": 1717200000000,
547
+ "lastSeenAt": 1719792000000,
548
+ "publisherPlatforms": ["GOOGLE_ADS"],
549
+ "regionCodes": ["US", "GB"],
550
+ "variations": [
551
+ {
552
+ "headline": "Summer Sale — 50% Off",
553
+ "description": "Shop our biggest sale of the year.",
554
+ "destinationUrl": "https://example.com/summer-sale",
555
+ "imageUrl": "https://...",
556
+ "visibleUrl": "example.com"
557
+ }
558
+ ],
559
+ "regions": [
560
+ { "code": "US", "name": "United States" }
561
+ ],
562
+ "analysisStatus": "completed",
563
+ "aiAnalysis": {
564
+ "aiSummary": "Promotional display ad for a seasonal sale with urgency-driven CTA",
565
+ "hookAngle": "Discount/Price",
566
+ "offerType": "Percentage Discount",
567
+ "ctaStrategy": "Shop Now",
568
+ "funnelStage": "Bottom",
569
+ "targetAudience": "Price-sensitive shoppers",
570
+ "adFormat": "responsive_display",
571
+ "tags": ["sale", "discount", "ecommerce"],
572
+ "trustSignals": ["Free shipping"],
573
+ "keyMessages": ["50% off", "Free shipping"],
574
+ "competitiveAngle": "Price leadership",
575
+ "dominantColors": ["#FF5733", "#FFFFFF"],
576
+ "analyzedAt": 1719792000000
577
+ }
578
+ }
579
+ ],
580
+ "continueCursor": "eyJwYWdl...",
581
+ "isDone": false
582
+ }
583
+ }
584
+ ```
585
+
586
+ **Key response fields:**
587
+
588
+ | Field | Description |
589
+ |-------|-------------|
590
+ | `headline`, `description` | Top-level ad copy (first variation) |
591
+ | `variations[]` | All ad variations with copy, images, videos, and URLs |
592
+ | `regions[]` | Geographic targeting regions |
593
+ | `impressionsMin/Max` | Estimated impression range (Google Ads Transparency data) |
594
+ | `publisherPlatforms` | Where the ad ran (GOOGLE_ADS, YOUTUBE, etc.) |
595
+ | `analysisStatus` | AI analysis state: `pending`, `processing`, `completed`, `failed` |
596
+ | `aiAnalysis` | AI-generated creative analysis (only present when `analysisStatus` is `completed`) |
597
+ | `aiAnalysis.aiSummary` | One-line AI summary of the ad |
598
+ | `aiAnalysis.hookAngle` | Creative hook (Discount, Fear, Social Proof, etc.) |
599
+ | `aiAnalysis.funnelStage` | Funnel position: Top, Middle, Bottom |
600
+ | `aiAnalysis.tags` | AI-generated tags for filtering |
601
+
602
+ **Flags:**
603
+
604
+ | Flag | Description |
605
+ |---------------|------------------------------------------------|
606
+ | `--search` | Search term for ad text |
607
+ | `--isActive` | Filter by active ads only |
608
+ | `--mediaType` | Filter by media type: `image`, `video`, `text` |
609
+ | `--sort` | Sort: `newest` or `oldest` |
610
+ | `--limit` | Max results per page (default 20, max 100) |
611
+ | `--cursor` | Pagination cursor from previous response |
612
+ | `--output` | Format: `json` \| `csv` \| `md` |
613
+
614
+ ---
615
+
616
+ ### `baker ads google library sync <accountId>`
617
+
618
+ Trigger an immediate re-sync for a tracked account. Polls every 5 seconds until complete (10-minute timeout). Progress is written to stderr.
619
+
620
+ ```bash
621
+ baker ads google library sync acc_def456
622
+ ```
623
+
624
+ **Response:**
625
+
626
+ ```json
627
+ {
628
+ "ok": true,
629
+ "data": {
630
+ "totalAdCount": 350,
631
+ "activeAdCount": 92
632
+ }
633
+ }
634
+ ```
635
+
636
+ ---
637
+
638
+ ### `baker ads google library search-competitors "keyword"`
639
+
640
+ Search for competitors running Google ads for a keyword. Uses DataForSEO (same data as `baker research advertisers`).
641
+
642
+ ```bash
643
+ baker ads google library search-competitors "running shoes"
644
+ baker ads google library search-competitors "crm software" --location uk
645
+ ```
646
+
647
+ **Flags:**
648
+
649
+ | Flag | Description |
650
+ |--------------|----------------------------|
651
+ | `--location` | Location name or code |
652
+ | `--json` | Output in JSON format |
653
+
654
+ ---
655
+
400
656
  ### Staged writes (`baker ads google budgets|campaigns|...`)
401
657
 
402
658
  Write commands **never touch the Google Ads API at stage time**. Each command stages a create/update/pause/resume/remove op against the current chat's draft (`BAKER_CHAT_ID`); the dashboard shows it as a pending "Google Ads" change, and the whole draft applies as one atomic `GoogleAdsService.Mutate` when the chat is published. Feature-flagged per company (`companies.googleAdsWriteEnabled`) — off by default = a fully simulated publish with zero real API calls.
@@ -2161,17 +2417,13 @@ baker testimonials tags
2161
2417
 
2162
2418
  ### Winning Ads (`baker winning-ads`)
2163
2419
 
2164
- Search the **ad-dna** corpus of scored "winning" competitor ads for reference creatives to reproduce (e.g. with `baker canvas`), and manage the brands your library tracks (`follow` / `following` / `unfollow`). Each result carries a presigned media URL (~1h TTL), the ad's DNA summary, and scores. The CLI authenticates with the normal `BAKER_API_KEY`; the Baker backend proxies the request to the ad-dna service with a server-held token — no extra credential in the sandbox.
2165
-
2166
- > The corpus has **Meta + LinkedIn** connectors, so `--platform` inputs are limited to `meta,linkedin`. (Older result rows may still carry a legacy platform string.)
2420
+ Search the **ad-dna** corpus of scored "winning" competitor ads for reference creatives to reproduce (e.g. with `baker canvas`). Each result carries a presigned media URL (~1h TTL), the ad's DNA summary, and scores. The CLI authenticates with the normal `BAKER_API_KEY`; the Baker backend proxies the request to the ad-dna service with a server-held token — no extra credential in the sandbox.
2167
2421
 
2168
2422
  > Backend env: the Convex deployment must have `AD_DNA_API_TOKEN` set (`npx convex env set AD_DNA_API_TOKEN …`). `AD_DNA_API_URL` is optional and defaults to `https://ads.withbaker.com`.
2169
2423
 
2170
- > Replaces the old `baker ads google library` tree, which has been removed. Competitor-by-keyword discovery still lives at `baker research advertisers`.
2171
-
2172
2424
  ### `baker winning-ads search <query>`
2173
2425
 
2174
- 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`; plus top-level `pool_size`, `match_confidence` (`high|medium|low`), and `below_floor_count` (matches dropped under the relevance floor). `--full` adds DNA detail (`angle`, `target_persona`, `hook_archetype`, `awareness_stage`, `industry`) + longevity (`days_active`, `reach`, `active`, `winner_category`, `media_kind`). `--output json` (default) returns the lean objects; `--output md` prints a table.
2426
+ Semantic search (dense recall + BM25 + rerank). 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`; plus top-level `pool_size` and `match_confidence`. `--full` adds DNA detail (`angle`, `target_persona`, `hook_archetype`, `awareness_stage`, `industry`) + longevity (`days_active`, `reach`, `active`, `winner_category`, `media_kind`). `--output json` (default) returns the lean objects; `--output md` prints a table.
2175
2427
 
2176
2428
  > `media_url` is the creative itself: for `static` it's the image, for `video` it's the video file. ad-dna stores **no separate poster** for videos, so a video result has only the video URL.
2177
2429
 
@@ -2193,7 +2445,7 @@ baker winning-ads search --ref-ad-id a_12345 --first-seen-after 2026-01-01T00:00
2193
2445
  | `--limit <n>` | Max results 1–100 (**default 10** — shortlist size) |
2194
2446
  | `--max-per-advertiser <n>` | Cap results per advertiser 1–50 (default 3) |
2195
2447
  | `--min-relevance <0-1>` | Relevance floor; trims weak matches |
2196
- | `--platform <list>` | `meta,linkedin` — pass a single value to search **only** that platform |
2448
+ | `--platform <list>` | One or many of `meta,tiktok,linkedin,google_search,google_display,youtube,reddit,x,pinterest,snapchat` — pass a single value to search **only** that platform |
2197
2449
  | `--format <list>` | `video,static,carousel` |
2198
2450
  | `--winner-category <list>` | `winner,scaled_winner,evergreen,rising,untested,dud,…` (default: all) |
2199
2451
  | `--awareness <list>` | `unaware,problem_aware,solution_aware,product_aware,most_aware` |
@@ -2208,66 +2460,13 @@ Reading the scores: **`relevance`** (0–1) = match of the creative to your quer
2208
2460
 
2209
2461
  ### `baker winning-ads advertisers <brand>`
2210
2462
 
2211
- List corpus brands by name or domain → `GET /api/ad-library/advertisers`. Use it to find **your own** advertiser (to `--exclude-advertiser`) or a **competitor** (to `--advertiser-id` / `winners`). Lean default fields: `advertiser_id`, `label`, `platform_count`, `family_count`, `active_ad_count`, `total_ad_count`; `--full` adds `scraped_name`, `image_url`, `platforms`, `total_reach`, `last_synced_at`. Supports `--platform meta|linkedin`, `--limit`, `--offset`.
2463
+ Resolve a brand name → `advertiser_id`(s) in the corpus. Use it to find **your own** advertiser (to `--exclude-advertiser`) or a **competitor** (to `--advertiser-id`). Returns `advertiser_id`, `label`, `active_ads`, `total_ads`.
2212
2464
 
2213
2465
  ```bash
2214
2466
  baker winning-ads advertisers "Acme" --output md # find our own advertiser id
2215
2467
  baker winning-ads advertisers "Deel" --platform meta --output md
2216
2468
  ```
2217
2469
 
2218
- ### `baker winning-ads follow "<domain | profile URL | brand>" --platform meta|linkedin`
2219
-
2220
- Add a brand's ads to your library → `POST /api/ad-library/follow`. `--platform` is **required**. The result `status` is one of:
2221
-
2222
- - `following` — the brand is already in the corpus; you're now subscribed (no wait).
2223
- - `added` — a new brand was queued for ingestion; its ads appear as discovery completes (a `hints[]` note flags this).
2224
- - `ambiguous` — the input mapped to multiple brands; pick one from `candidates` and re-run with a more specific domain/URL.
2225
-
2226
- ```bash
2227
- baker winning-ads follow "deel.com" --platform meta
2228
- baker winning-ads follow "https://www.linkedin.com/company/acme" --platform linkedin --label "Acme (competitor)"
2229
- ```
2230
-
2231
- ### `baker winning-ads following`
2232
-
2233
- List the brands you follow → `GET /api/ad-library/following`. Each row shows `status` (`ready` vs `adding…`) plus cached counts (`active_ad_count`, `total_ad_count`, `family_count`) and discovery progress (`adding_discovered`, `adding_enqueued`). `--full` adds `image_url` + `platforms`.
2234
-
2235
- ```bash
2236
- baker winning-ads following --output md
2237
- ```
2238
-
2239
- ### `baker winning-ads winners <advertiser>`
2240
-
2241
- Top winning ads for one advertiser id → `GET /api/ad-library/advertiser-winners`. Same lean winner cards as `search` (add `--full` for DNA + longevity). Supports `--top N` and `--platform meta|linkedin`.
2242
-
2243
- ```bash
2244
- baker winning-ads winners adv_123 --top 15 --output md
2245
- ```
2246
-
2247
- ### `baker winning-ads unfollow <advertiser>`
2248
-
2249
- Stop following a brand by advertiser id → `POST /api/ad-library/unfollow`. Returns `{ removed }`.
2250
-
2251
- ```bash
2252
- baker winning-ads unfollow adv_123
2253
- ```
2254
-
2255
- ### `baker winning-ads brief`
2256
-
2257
- Generate a creative brief grounded in strategically-similar winners → `POST /api/ad-library/brief`. Optionally describe the target creative with `--dna` (a JSON object), steer with `--notes`, and cap references with `--k`. Returns `brief_markdown` + `reference_ad_ids`.
2258
-
2259
- ```bash
2260
- baker winning-ads brief --dna '{"angle":"cost savings","awareness_stage":"solution_aware"}' --notes "B2B, LinkedIn video" --k 8
2261
- ```
2262
-
2263
- ### `baker winning-ads patterns --winners <adIds> --duds <adIds>`
2264
-
2265
- Mine what separates two cohorts of ads → `POST /api/ad-library/patterns`. Pass a comma-list of winning ad ids (`--winners`, cohort A) and weaker/dud ad ids (`--duds`, cohort B), plus optional `--top-n`. Returns each discriminating DNA field with the cohort it `favors` (`winners`/`duds`), a `score`, and the top values on each side.
2266
-
2267
- ```bash
2268
- baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --top-n 10 --output md
2269
- ```
2270
-
2271
2470
  ---
2272
2471
 
2273
2472
  ### Scheduled Actions (`baker scheduled-actions`)
@@ -2325,24 +2524,6 @@ Notes:
2325
2524
  - Single-instance types (`code`, `posthog`, `datafast`) reject a second instance against the chat's effective view.
2326
2525
  - Conflicts at publish (tag deleted in the dashboard, config invalid) skip the op with a recorded reason — they never block the publish.
2327
2526
 
2328
- ### Forms / Flows (`baker flows`)
2329
-
2330
- Read this workspace's Forms (flows) and the configuration status of each one's **confidential fields** — side-effect connection secrets, OAuth connections, and third-party field definitions (HubSpot, Calendly, HighLevel, SavvyCal). Reads the local `_data.json` files; no secret values are ever decrypted or printed.
2331
-
2332
- **The CLI is read-only.** Author a Form's structure (nodes, conditions, side effects, field mappings) by editing its `_data.json` with the flow-builder skill. Configure the confidential fields it reports as `[missing]` / `[needs connection]` / `not selected` through the `request_flow_input` tool (`baker_ui` MCP server): the agent authors the surrounding structure, references it by `nodeId`/`sideEffectId`, and the user enters secrets, connects/picks OAuth accounts, and picks third-party forms in the dashboard. Those values are written (encrypted, where a secret) into the Form on the chat's branch and go live when the chat is published.
2333
-
2334
- ```bash
2335
- baker flows list # every Form + how many confidential fields still need setup
2336
- baker flows show contact # one Form's confidential fields and their status
2337
- baker flows show contact --full # include the full flow tree (secret values redacted)
2338
- ```
2339
-
2340
- Notes:
2341
-
2342
- - **Secrets never travel through this CLI or the chat.** `show` reports only whether each field is configured (`[set]`/`[missing]`, `[connected]`/`[needs connection]`, selected/not selected) — never a value. Configured secrets appear only as `[configured]` ciphertext markers.
2343
- - Confidential side-effect types: `httpWebhook`, `zapier`, `crmble` (typed credentials); `pipedrive`, `googleSpreadsheet`, `hubspotForm`, `goHighlevelContact` (OAuth connection + resource); `email`. Widget node types needing a resource pick: `calendly`, `savvycal`, `hubspot`, `hubspotMeeting`, `highlevel`, `highlevelForm`.
2344
- - `request_flow_input` changes stage on the chat's branch and apply when the chat is published; discarding the chat drops them.
2345
-
2346
2527
  ### Action Items (`baker actions`)
2347
2528
 
2348
2529
  Manage action items for the current chat. Most write operations stage on the chat's draft and apply atomically when the chat is published. Claim/release run live so other chats can see who's working on what.
@@ -3,9 +3,9 @@ import {
3
3
  __toESM
4
4
  } from "./chunk-5WRI5ZAA.js";
5
5
 
6
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js
6
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js
7
7
  var require_safe_stable_stringify = __commonJS({
8
- "../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js"(exports, module) {
8
+ "../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports, module) {
9
9
  "use strict";
10
10
  var { hasOwnProperty } = Object.prototype;
11
11
  var stringify = configure2();
@@ -901,7 +901,7 @@ function describeCause(c) {
901
901
  }
902
902
  }
903
903
 
904
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/esm/wrapper.js
904
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/esm/wrapper.js
905
905
  var import__ = __toESM(require_safe_stable_stringify(), 1);
906
906
  var configure = import__.default.configure;
907
907
  var wrapper_default = import__.default;
@@ -6542,4 +6542,4 @@ export {
6542
6542
  defaultRegistry,
6543
6543
  createEngineFromEnv
6544
6544
  };
6545
- //# sourceMappingURL=chunk-MWFJ5NOP.js.map
6545
+ //# sourceMappingURL=chunk-IWPAXJC3.js.map