@koda-sl/baker-cli 0.408.0 → 0.410.0-dev.53b577900
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 +31 -23
- package/dist/{chunk-N72QYDJY.js → chunk-ISCXDKWB.js} +25 -8
- package/dist/{chunk-N72QYDJY.js.map → chunk-ISCXDKWB.js.map} +1 -1
- package/dist/{chunk-5X5LUMVV.js → chunk-ISJOVAJP.js} +2 -2
- package/dist/{chunk-WQE4SRLY.js → chunk-S5BY45H7.js} +3 -3
- package/dist/{chunk-KMCVSEGU.js → chunk-TI5KBK4V.js} +6 -6
- package/dist/chunk-TI5KBK4V.js.map +1 -0
- package/dist/{chunk-X37GPJ54.js → chunk-VKWHVMMD.js} +3 -3
- package/dist/{chunk-3ZN2DUBU.js → chunk-ZIOW64BL.js} +4 -4
- package/dist/cli.js +1290 -904
- package/dist/cli.js.map +1 -1
- package/dist/{client-BPKOHQWA.js → client-AY6TPFQ4.js} +4 -4
- package/dist/engine/index.js +3 -3
- package/dist/{env-B7V77K6K.js → env-CWEGTJF3.js} +2 -2
- package/dist/{output-5M2QPMKZ.js → output-EPF3HHJ4.js} +5 -5
- package/dist/{shared-OEQKSDWO.js → shared-53G34I3U.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-KMCVSEGU.js.map +0 -1
- /package/dist/{chunk-5X5LUMVV.js.map → chunk-ISJOVAJP.js.map} +0 -0
- /package/dist/{chunk-WQE4SRLY.js.map → chunk-S5BY45H7.js.map} +0 -0
- /package/dist/{chunk-X37GPJ54.js.map → chunk-VKWHVMMD.js.map} +0 -0
- /package/dist/{chunk-3ZN2DUBU.js.map → chunk-ZIOW64BL.js.map} +0 -0
- /package/dist/{client-BPKOHQWA.js.map → client-AY6TPFQ4.js.map} +0 -0
- /package/dist/{env-B7V77K6K.js.map → env-CWEGTJF3.js.map} +0 -0
- /package/dist/{output-5M2QPMKZ.js.map → output-EPF3HHJ4.js.map} +0 -0
- /package/dist/{shared-OEQKSDWO.js.map → shared-53G34I3U.js.map} +0 -0
package/README.md
CHANGED
|
@@ -3080,6 +3080,23 @@ baker testimonials search "competitor support" --source trustpilot --sentiment n
|
|
|
3080
3080
|
baker testimonials search "[product/offer] for [persona] that delivers [USP/outcome]" --rating-min 4 --language en --output md --full --limit 12
|
|
3081
3081
|
```
|
|
3082
3082
|
|
|
3083
|
+
### `baker testimonials sources`
|
|
3084
|
+
|
|
3085
|
+
The review pages testimonials are imported from — Google Maps, Trustpilot, Yelp, Tripadvisor, G2, Capterra, Amazon, App Store, Google Play. Adding or removing one applies immediately and shows on the chat as an already-applied change.
|
|
3086
|
+
|
|
3087
|
+
| Command | What it does |
|
|
3088
|
+
| --- | --- |
|
|
3089
|
+
| `baker testimonials sources add <link \| business name> [--platform <site>] [--every never\|daily\|weekly\|monthly]` | Recognise the page from its link (a business name finds a Google Maps listing) and import its reviews in the background. Idempotent. |
|
|
3090
|
+
| `baker testimonials sources list` | Every source: id, site, status, reviews imported, auto-sync. |
|
|
3091
|
+
| `baker testimonials sources sync <id>` | Import new reviews now. |
|
|
3092
|
+
| `baker testimonials sources schedule <id> --every <interval>` | Set the auto-sync cadence. |
|
|
3093
|
+
| `baker testimonials sources remove <id>` | Remove the source and every testimonial it imported. |
|
|
3094
|
+
|
|
3095
|
+
```bash
|
|
3096
|
+
baker testimonials sources add https://www.trustpilot.com/review/acme.com
|
|
3097
|
+
baker testimonials sources add "Acme Bakery Madrid"
|
|
3098
|
+
```
|
|
3099
|
+
|
|
3083
3100
|
### `baker testimonials get <id>`
|
|
3084
3101
|
|
|
3085
3102
|
Get a single testimonial by ID.
|
|
@@ -3237,11 +3254,11 @@ Search the **ad-dna** corpus of scored "winning" competitor ads for reference cr
|
|
|
3237
3254
|
|
|
3238
3255
|
### `baker winning-ads search <query>`
|
|
3239
3256
|
|
|
3240
|
-
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). `--full` adds DNA detail (`angle`, `target_persona`, `hook_archetype`, `awareness_stage`, `industry`) +
|
|
3257
|
+
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`); `--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.
|
|
3241
3258
|
|
|
3242
3259
|
> `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.
|
|
3243
3260
|
|
|
3244
|
-
> Results are already de-junked and winner-first: the corpus auto-drops measured failures (duds, thrash) and ranks `final = relevance^0.
|
|
3261
|
+
> Results are already de-junked and winner-first: the corpus auto-drops measured failures (duds, thrash) and ranks `final = relevance^0.5 × winner_score^0.5`, so a direct match beats a stronger-but-tangential ad. So `--winner-category winner` is usually unnecessary — it's a stricter filter that also removes `untested` (unproven-but-maybe-fresh) ads. Rely on the default + `--min-relevance`; only add `--winner-category` to force-exclude unproven creatives. (With a query, restricting to a single `--advertiser-id` turns the failure-exclusion and the per-advertiser cap off: you then see that brand's duds too. A search with no query is a browse, which always drops failures and `untested` ads. A company that follows one brand keeps both with `--scope followed`/`followed-first`.)
|
|
3245
3262
|
|
|
3246
3263
|
```bash
|
|
3247
3264
|
# Only LinkedIn video ads:
|
|
@@ -3260,6 +3277,8 @@ baker winning-ads search --format-pattern comparison_table --platform meta --out
|
|
|
3260
3277
|
|---|---|
|
|
3261
3278
|
| `query` (positional) | Free-text natural-language query |
|
|
3262
3279
|
| `--ref-ad-id <id>` | Find ads similar to this ad (instead of free text) |
|
|
3280
|
+
| `--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) |
|
|
3281
|
+
| `--sort winner\|longest_running\|newest` | Order of a no-query browse (default `winner`); ignored when a query is given |
|
|
3263
3282
|
| `--limit <n>` | Max results 1–100 (**default 10** — shortlist size) |
|
|
3264
3283
|
| `--max-per-advertiser <n>` | Cap results per advertiser 0–50 (default 3; `0` = no cap) |
|
|
3265
3284
|
| `--min-relevance <0-1>` | Relevance floor; trims weak matches |
|
|
@@ -3287,7 +3306,7 @@ Read the **winner-weighted rollup** of the ad-dna corpus → `GET /api/ad-librar
|
|
|
3287
3306
|
mechanism / static-format patterns that actually win, ranked by `winner_score` among the ads of the segment you
|
|
3288
3307
|
pass (`--platform`, `--awareness`, `--industry`; an unset one means any), keyed on the closed seeds/enums the
|
|
3289
3308
|
extractor emits (no clustering). Ground a creative in a **proven** pattern for the exact segment instead of
|
|
3290
|
-
guessing. The rollup is recomputed daily.
|
|
3309
|
+
guessing. The rollup is recomputed daily.
|
|
3291
3310
|
|
|
3292
3311
|
```bash
|
|
3293
3312
|
# Top winning hook seeds for problem-aware SaaS on Meta:
|
|
@@ -3390,24 +3409,6 @@ Stop following a brand by advertiser id → `POST /api/ad-library/unfollow`. Ret
|
|
|
3390
3409
|
baker winning-ads unfollow adv_123
|
|
3391
3410
|
```
|
|
3392
3411
|
|
|
3393
|
-
### `baker winning-ads brief`
|
|
3394
|
-
|
|
3395
|
-
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`.
|
|
3396
|
-
|
|
3397
|
-
```bash
|
|
3398
|
-
baker winning-ads brief --dna '{"angle":"cost savings","awareness_stage":"solution_aware"}' --notes "B2B, LinkedIn video" --k 8
|
|
3399
|
-
```
|
|
3400
|
-
|
|
3401
|
-
### `baker winning-ads patterns --winners <adIds> --duds <adIds>`
|
|
3402
|
-
|
|
3403
|
-
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.
|
|
3404
|
-
|
|
3405
|
-
```bash
|
|
3406
|
-
baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --top-n 10 --output md
|
|
3407
|
-
```
|
|
3408
|
-
|
|
3409
|
-
---
|
|
3410
|
-
|
|
3411
3412
|
### Scheduled agents (`baker scheduled-agents`)
|
|
3412
3413
|
|
|
3413
3414
|
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.
|
|
@@ -5737,7 +5738,7 @@ The two scaffold passes are billed (the full `video_deconstruct` is the heavy on
|
|
|
5737
5738
|
|
|
5738
5739
|
**New-creative limit:** a chat makes at most 10 new creatives. The eleventh `scaffold-static-ad`, `scaffold-ad` or `scaffold-video` with a new `--slug` exits 2 with `CREATIVE_LIMIT` before any billed pass. Re-scaffolding a creative already made in the chat, or one whose `_definition.md` existed before, does not count.
|
|
5739
5740
|
|
|
5740
|
-
`<image>` is a **local path or an `http(s)` URL** (e.g. a presigned S3 link from ad-dna). With `--slug` the source is localized to durable, content-addressed storage before anything bills, so the emitted canvas stays runnable in any sandbox; without a slug a URL is passed straight into the `original` ingest node (a presigned one expires). For the URL case, `--out` defaults to the current directory — pass `--out` to scaffold two URL sources into distinct files, or the second run overwrites the first.
|
|
5741
|
+
`<image>` is a **local path or an `http(s)` URL** (e.g. a presigned S3 link from ad-dna), and it is **optional when `--source-ad-id` is given**: the library's picture is used. With `--slug` the source is localized to durable, content-addressed storage before anything bills, so the emitted canvas stays runnable in any sandbox; without a slug a URL is passed straight into the `original` ingest node (a presigned one expires). For the URL case, `--out` defaults to the current directory — pass `--out` to scaffold two URL sources into distinct files, or the second run overwrites the first.
|
|
5741
5742
|
|
|
5742
5743
|
Turn a source/inspiration image into a **runnable, self-validated static-ad canvas** — the static counterpart of `scaffold-video`. It runs **billed Gemini passes** up front:
|
|
5743
5744
|
|
|
@@ -5759,7 +5760,11 @@ The canvas is validated before it is written. stdout returns `{ ok, canvas_path,
|
|
|
5759
5760
|
|
|
5760
5761
|
The render prompt is **model-aware**: for **gpt-image** the exclusions (no invented badges/watermark) are hoisted to the very *end* of the prompt where the model reads them as pure exclusions rather than composition. Run `baker canvas critique` on the scaffolded canvas for an advisory read before you spend.
|
|
5761
5762
|
|
|
5763
|
+
**A reference from the winners library goes in by id.** `--source-ad-id <ad_id> --source-platform meta|linkedin|tiktok [--source-advertiser-id <id>]` (the ids beside the ad in `baker winning-ads search`) fetches the library's structured read of that ad, the same one `baker winning-ads content <ad_id> --full` returns, and writes it into `prompt.json` as a `reference` block: `{ ad_id, platform, advertiser, advertiser_id, format_pattern, layout: { composition, focal_subject, aspect_ratio, background, palette_mood, colors, production, aesthetic, cta_in_image, markers }, message: { mechanism, awareness, sophistication, angle, hook_archetype, pain_points, desires, value_props, objections_handled, proof, risk_reversal }, offer: { offer_type, pricing_model, entry_price, no_credit_card, guarantee, guarantee_days, urgency, bonus }, text_blocks: [{ text, role, position }], copy: { primary_text, headline, cta } }` (filled fields only). The describe pass still reads the pixels but is told that read as grounding, so the two cannot disagree on the container or the mechanism; when it names no `winning_mechanisms`, the library's container + mechanism seeds the list. The source ids (`sourceAdId`, `sourcePlatform`, `sourceAdvertiserId`, and `sourceAdvertiser` from the library when `--advertiser` is absent) are written to `_definition.md` and synced to the creative at scaffold time. A library read that fails warns, records the ids anyway and scaffolds from the picture alone (`hints`: `REFERENCE NOT READ`); with no picture either, the command exits 2 (`source_unavailable`). `baker canvas sync-definition` re-reads the three ids from `_definition.md` on every sync.
|
|
5764
|
+
|
|
5762
5765
|
```bash
|
|
5766
|
+
baker canvas scaffold-static-ad --source-ad-id adg_123 --source-platform meta --slug spring-offer --platform meta
|
|
5767
|
+
# → the library's picture and read; writes src/creatives/spring-offer/{spring-offer.canvas.json, prompt.json, _definition.md}
|
|
5763
5768
|
baker canvas scaffold-static-ad ./reference-ad.png --context "competitor ad for <brand>, <category>, <market>"
|
|
5764
5769
|
# → writes ./static-ad.canvas.json + ./prompt.json
|
|
5765
5770
|
# edit prompt.json into your ad + replace each [TODO] ingest path with a real file, then:
|
|
@@ -5769,7 +5774,10 @@ baker canvas run ./static-ad.canvas.json
|
|
|
5769
5774
|
|
|
5770
5775
|
| Flag | Default | Effect |
|
|
5771
5776
|
|---|---|---|
|
|
5772
|
-
| `--
|
|
5777
|
+
| `--source-ad-id <ad_id>` | — | The winners-library ad this creative adapts. Fetches its structured read into `prompt.json` `reference`, grounds the describe pass with it, and records the source on the creative. Makes `<image>` optional. |
|
|
5778
|
+
| `--source-platform <platform>` | `meta` | Platform the library ad is on: `meta`\|`linkedin`\|`tiktok`. Another value exits 2 (`invalid_source_platform`). |
|
|
5779
|
+
| `--source-advertiser-id <id>` | the library's | The reference's library advertiser id, recorded as `sourceAdvertiserId`. |
|
|
5780
|
+
| `--context <text>` | — | Known provenance (advertiser, category, market) to ground the describe. Appended to the library's read when `--source-ad-id` is given. |
|
|
5773
5781
|
| `--out <path>` | `<image-dir>/static-ad.canvas.json` (cwd when `<image>` is a URL) | Where to write the canvas (`prompt.json` is written alongside). |
|
|
5774
5782
|
| `--slug <slug>` | — | Creative slug (lowercase kebab): writes the canvas to `src/creatives/<slug>/<slug>.canvas.json` — the repo convention that attaches every run to the creative's dashboard generation history. `--out` wins over `--slug`. With a slug, the reference image is localized to durable storage and normalized to a model-safe format (SVG/AVIF/HEIC/… → PNG), so the canvas ingests a stable URL instead of an expiring one. |
|
|
5775
5783
|
| `--describe-model <id>` | registry default (`~google/gemini-pro-latest`) | Override the `image_describe` model. |
|
|
@@ -951,7 +951,26 @@ function bakerUses(value) {
|
|
|
951
951
|
const uses = asRecord(value);
|
|
952
952
|
const companies = typeof uses.companies === "number" ? uses.companies : 0;
|
|
953
953
|
if (companies === 0) return {};
|
|
954
|
-
|
|
954
|
+
const count = (n) => typeof n === "number" && n > 0 ? n : void 0;
|
|
955
|
+
const approved = count(uses.approved);
|
|
956
|
+
const rejected = count(uses.rejected);
|
|
957
|
+
return {
|
|
958
|
+
baker_uses: companies,
|
|
959
|
+
...uses.ours === true ? { already_adapted: true } : {},
|
|
960
|
+
...approved !== void 0 ? { approved } : {},
|
|
961
|
+
...rejected !== void 0 ? { rejected } : {}
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
function dnaMove(dna) {
|
|
965
|
+
const text = (value) => typeof value === "string" && value ? value : void 0;
|
|
966
|
+
const visual = text(dna.visual);
|
|
967
|
+
const container = text(dna.container);
|
|
968
|
+
const mechanism = text(dna.mechanism);
|
|
969
|
+
return {
|
|
970
|
+
...visual ? { visual } : {},
|
|
971
|
+
...container ? { container } : {},
|
|
972
|
+
...mechanism ? { mechanism } : {}
|
|
973
|
+
};
|
|
955
974
|
}
|
|
956
975
|
function compactWinningAd(record) {
|
|
957
976
|
const dna = asRecord(record.dna);
|
|
@@ -961,13 +980,14 @@ function compactWinningAd(record) {
|
|
|
961
980
|
format: String(record.format ?? ""),
|
|
962
981
|
relevance: round2(record.relevance),
|
|
963
982
|
winner_score: round2(record.winner_score),
|
|
983
|
+
winner_category: typeof record.winner_category === "string" ? record.winner_category : null,
|
|
984
|
+
days_active: typeof record.days_active === "number" ? record.days_active : null,
|
|
985
|
+
active: typeof record.active === "boolean" ? record.active : null,
|
|
964
986
|
summary: String(dna.creative_concept ?? ""),
|
|
965
987
|
advertiser_id: String(record.advertiser_id ?? ""),
|
|
966
988
|
ad_id: String(record.ad_id ?? ""),
|
|
967
989
|
media_url: String(record.media_url ?? ""),
|
|
968
|
-
...
|
|
969
|
-
...typeof dna.container === "string" && dna.container ? { container: dna.container } : {},
|
|
970
|
-
...typeof dna.mechanism === "string" && dna.mechanism ? { mechanism: dna.mechanism } : {},
|
|
990
|
+
...dnaMove(dna),
|
|
971
991
|
...bakerUses(record.baker_uses),
|
|
972
992
|
...record.source === "followed" || record.source === "library" ? { source: record.source } : {}
|
|
973
993
|
};
|
|
@@ -977,11 +997,8 @@ function fullWinningAd(record) {
|
|
|
977
997
|
const dna = asRecord(record.dna);
|
|
978
998
|
return {
|
|
979
999
|
...compact,
|
|
980
|
-
winner_category: String(record.winner_category ?? ""),
|
|
981
1000
|
media_kind: record.media_kind ?? null,
|
|
982
|
-
days_active: record.days_active ?? null,
|
|
983
1001
|
reach: record.reach ?? null,
|
|
984
|
-
active: typeof record.active === "boolean" ? record.active : null,
|
|
985
1002
|
angle: dna.angle ?? null,
|
|
986
1003
|
awareness_stage: dna.awareness_stage ?? null,
|
|
987
1004
|
target_persona: dna.target_persona ?? null,
|
|
@@ -1339,4 +1356,4 @@ export {
|
|
|
1339
1356
|
captureVimeoCookie,
|
|
1340
1357
|
childEnvWith
|
|
1341
1358
|
};
|
|
1342
|
-
//# sourceMappingURL=chunk-
|
|
1359
|
+
//# sourceMappingURL=chunk-ISCXDKWB.js.map
|