@koda-sl/baker-cli 0.408.0 → 0.409.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 +14 -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-KMCVSEGU.js → chunk-QWRXQ2UC.js} +3 -3
- package/dist/{chunk-WQE4SRLY.js → chunk-S5BY45H7.js} +3 -3
- package/dist/{chunk-X37GPJ54.js → chunk-VKWHVMMD.js} +3 -3
- package/dist/{chunk-3ZN2DUBU.js → chunk-ZIOW64BL.js} +4 -4
- package/dist/cli.js +415 -348
- 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-5X5LUMVV.js.map → chunk-ISJOVAJP.js.map} +0 -0
- /package/dist/{chunk-KMCVSEGU.js.map → chunk-QWRXQ2UC.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
|
@@ -3237,11 +3237,11 @@ Search the **ad-dna** corpus of scored "winning" competitor ads for reference cr
|
|
|
3237
3237
|
|
|
3238
3238
|
### `baker winning-ads search <query>`
|
|
3239
3239
|
|
|
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`) +
|
|
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). 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
3241
|
|
|
3242
3242
|
> `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
3243
|
|
|
3244
|
-
> Results are already de-junked and winner-first: the corpus auto-drops measured failures (duds, thrash) and ranks `final = relevance^0.
|
|
3244
|
+
> 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
3245
|
|
|
3246
3246
|
```bash
|
|
3247
3247
|
# Only LinkedIn video ads:
|
|
@@ -3260,6 +3260,8 @@ baker winning-ads search --format-pattern comparison_table --platform meta --out
|
|
|
3260
3260
|
|---|---|
|
|
3261
3261
|
| `query` (positional) | Free-text natural-language query |
|
|
3262
3262
|
| `--ref-ad-id <id>` | Find ads similar to this ad (instead of free text) |
|
|
3263
|
+
| `--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) |
|
|
3264
|
+
| `--sort winner\|longest_running\|newest` | Order of a no-query browse (default `winner`); ignored when a query is given |
|
|
3263
3265
|
| `--limit <n>` | Max results 1–100 (**default 10** — shortlist size) |
|
|
3264
3266
|
| `--max-per-advertiser <n>` | Cap results per advertiser 0–50 (default 3; `0` = no cap) |
|
|
3265
3267
|
| `--min-relevance <0-1>` | Relevance floor; trims weak matches |
|
|
@@ -3287,7 +3289,7 @@ Read the **winner-weighted rollup** of the ad-dna corpus → `GET /api/ad-librar
|
|
|
3287
3289
|
mechanism / static-format patterns that actually win, ranked by `winner_score` among the ads of the segment you
|
|
3288
3290
|
pass (`--platform`, `--awareness`, `--industry`; an unset one means any), keyed on the closed seeds/enums the
|
|
3289
3291
|
extractor emits (no clustering). Ground a creative in a **proven** pattern for the exact segment instead of
|
|
3290
|
-
guessing. The rollup is recomputed daily.
|
|
3292
|
+
guessing. The rollup is recomputed daily.
|
|
3291
3293
|
|
|
3292
3294
|
```bash
|
|
3293
3295
|
# Top winning hook seeds for problem-aware SaaS on Meta:
|
|
@@ -3390,24 +3392,6 @@ Stop following a brand by advertiser id → `POST /api/ad-library/unfollow`. Ret
|
|
|
3390
3392
|
baker winning-ads unfollow adv_123
|
|
3391
3393
|
```
|
|
3392
3394
|
|
|
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
3395
|
### Scheduled agents (`baker scheduled-agents`)
|
|
3412
3396
|
|
|
3413
3397
|
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 +5721,7 @@ The two scaffold passes are billed (the full `video_deconstruct` is the heavy on
|
|
|
5737
5721
|
|
|
5738
5722
|
**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
5723
|
|
|
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.
|
|
5724
|
+
`<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
5725
|
|
|
5742
5726
|
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
5727
|
|
|
@@ -5759,7 +5743,11 @@ The canvas is validated before it is written. stdout returns `{ ok, canvas_path,
|
|
|
5759
5743
|
|
|
5760
5744
|
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
5745
|
|
|
5746
|
+
**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.
|
|
5747
|
+
|
|
5762
5748
|
```bash
|
|
5749
|
+
baker canvas scaffold-static-ad --source-ad-id adg_123 --source-platform meta --slug spring-offer --platform meta
|
|
5750
|
+
# → the library's picture and read; writes src/creatives/spring-offer/{spring-offer.canvas.json, prompt.json, _definition.md}
|
|
5763
5751
|
baker canvas scaffold-static-ad ./reference-ad.png --context "competitor ad for <brand>, <category>, <market>"
|
|
5764
5752
|
# → writes ./static-ad.canvas.json + ./prompt.json
|
|
5765
5753
|
# edit prompt.json into your ad + replace each [TODO] ingest path with a real file, then:
|
|
@@ -5769,7 +5757,10 @@ baker canvas run ./static-ad.canvas.json
|
|
|
5769
5757
|
|
|
5770
5758
|
| Flag | Default | Effect |
|
|
5771
5759
|
|---|---|---|
|
|
5772
|
-
| `--
|
|
5760
|
+
| `--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. |
|
|
5761
|
+
| `--source-platform <platform>` | `meta` | Platform the library ad is on: `meta`\|`linkedin`\|`tiktok`. Another value exits 2 (`invalid_source_platform`). |
|
|
5762
|
+
| `--source-advertiser-id <id>` | the library's | The reference's library advertiser id, recorded as `sourceAdvertiserId`. |
|
|
5763
|
+
| `--context <text>` | — | Known provenance (advertiser, category, market) to ground the describe. Appended to the library's read when `--source-ad-id` is given. |
|
|
5773
5764
|
| `--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
5765
|
| `--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
5766
|
| `--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
|