@koda-sl/baker-cli 0.121.0-dev.3a1b48e85 → 0.121.0-dev.3b02f951b

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
@@ -1142,7 +1142,7 @@ Notes:
1142
1142
  - All write commands take `--file <json>` payloads; explicit flags override file keys. `baker schema ads.linkedin.campaigns.create` for exact args.
1143
1143
  - Money flags (`--bid`, `--daily-budget`, `--total-budget`) require `--currency`.
1144
1144
  - Creative media comes from the Baker library (`--image-id`/`--video-id` from `baker images`/`baker videos` — uploaded to LinkedIn at publish) or as LinkedIn URNs (`--image-urn`/`--video-urn`). Formats: `image|video|text|spotlight|follower|document|carousel|conversation|tla|jobs`; complex formats take `--file` with the full content object; conversation ads take `--file` with the message flow (`{message: {subject, body, senderName?, buttons[]}}` — buttons `NESTED` (with `nestedMessage`) or `LANDING_PAGE` (with `landingPageUrl`), ≤25 messages, bodies ≤500 chars, labels ≤25). Limits: headline ≤70, text-ad 25/75, intro soft-truncates at 600 chars. TLA sponsors an existing post via `--post-urn`.
1145
- - Lead forms are file-first (`lead-forms create --file form.json`). Required: name, headline (≤60), privacyPolicyUrl, questions[] (≤12; playbook: ≤4 for completion). Each question is a predefined profile field (`{ name, predefinedField: "EMAIL" }` — Contact/Work/Company/Education/Demographic library) or a custom question (`{ name, questionType: "SINGLE_LINE_TEXT" | "MULTIPLE_CHOICE", options?: [...] }`; ≤3 custom, MULTIPLE_CHOICE needs 2–30 options). Also supported: `locale {country,language}`, `formImageId`/`formImageUrn` (banner), `consents[]` (≤5 disclosure checkboxes `{text, required}`), `hiddenFields[]` (≤20 `{name, value}` tracking fields), `legalDisclaimer`, `thankYou {message, cta, landingUrl | appointmentUrl}` (Calendly/Chili Piper booking link). The staged preview emits non-blocking best-practice warnings when a form has no qualifying question, no confirmation message/action, or no consent checkbox.
1145
+ - Lead forms are file-first (`lead-forms create --file form.json`). Required: name, headline (≤60), privacyPolicyUrl, questions[] (≤12; playbook: ≤4 for completion). Each question is a predefined profile field (`{ name, predefinedField: "EMAIL" }` — Contact/Work/Company/Education/Demographic library) or a custom question (`{ name, questionType: "SINGLE_LINE_TEXT" | "MULTIPLE_CHOICE", options?: [...] }`; ≤3 custom, MULTIPLE_CHOICE needs 2–30 options). Also supported: `locale {country,language}`, `formImageId`/`formImageUrn` (banner), `privacyPolicyText`, `consents[]` (≤5 disclosure checkboxes `{text, required}`), `hiddenFields[]` (≤20 `{name, value}` tracking fields), `legalDisclaimer`, `thankYou {message, cta, landingUrl | appointmentUrl}` (Calendly/Chili Piper booking link). The staged preview emits non-blocking best-practice warnings when a form has no qualifying question, no confirmation message/action, or no consent checkbox.
1146
1146
 
1147
1147
  #### `audit` — playbook diagnostic
1148
1148
 
@@ -2502,31 +2502,6 @@ Rules:
2502
2502
 
2503
2503
  ---
2504
2504
 
2505
- ### Marketing Tags (`baker tags`)
2506
-
2507
- Manage the client's marketing/analytics tags (Meta pixel, GA4, Google Ads, GTM, Clarity, Hotjar, PostHog, …) as per-chat **staged** changes. Nothing touches production tags until the chat is published; discarding the chat drops the draft.
2508
-
2509
- `BAKER_CHAT_ID` must be set.
2510
-
2511
- ```bash
2512
- baker tags list # effective view: production + staged, with secret status
2513
- baker tags add clarity --set projectId=abcde12345 # client-only tag, no secrets needed
2514
- baker tags add meta --set pixelId=123 --request-secret accessToken
2515
- baker tags update <ref> --set pixelId=999 --clear testEventCode
2516
- baker tags remove <ref> # stage deletion (tag_temp_* ref drops the staged create)
2517
- baker tags draft # review staged ops
2518
- baker tags draft remove <ref> # drop one staged op
2519
- baker tags draft clear # drop everything staged
2520
- ```
2521
-
2522
- Notes:
2523
-
2524
- - **Secrets never travel through this CLI.** Secret fields (`accessToken`, `apiSecret`, `authorizationToken`, `apiKey`, `conversionToken`, `oauthProviderId`) are rejected in `--set`. Stage with `--request-secret <field>`; the user provides values via the secure tag form in the chat (`request_tag_input`), which writes them straight into the staged draft. Responses only ever name which secret fields are set/pending.
2525
- - Staged creates get a server-generated `tag_temp_*` ref. Use it (or a real tag id) as flow side-effect `tagIds` — the published tag keeps resolving under the temp ref.
2526
- - `update`/`remove` with a `tag_temp_*` ref amend/drop the staged create in place.
2527
- - Single-instance types (`code`, `posthog`, `datafast`) reject a second instance against the chat's effective view.
2528
- - Conflicts at publish (tag deleted in the dashboard, config invalid) skip the op with a recorded reason — they never block the publish.
2529
-
2530
2505
  ### Action Items (`baker actions`)
2531
2506
 
2532
2507
  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.
@@ -2686,6 +2661,17 @@ baker canvas run my-canvas.json
2686
2661
  # single node — that old serial workaround is obsolete.
2687
2662
  baker canvas run my-canvas.json --parallel 8
2688
2663
 
2664
+ # 2c. Runs persist across sandboxes/sessions by default: node results sync to a
2665
+ # company-scoped remote cache (small JSON pointers; bytes stay in R2), so a FRESH
2666
+ # sandbox re-runs an already-computed canvas at zero credits — assets rehydrate
2667
+ # from R2, sha-verified. Every run also posts a durable history record (per-node
2668
+ # outputs, credits, cached/fresh) that powers the dashboard's Creatives
2669
+ # generations timeline. Opt out with --remote-cache off (env
2670
+ # BAKER_CANVAS_REMOTE_CACHE=off) and --no-record. With --remote-cache off,
2671
+ # assets are not uploaded, so a recorded run keeps its stats but has no
2672
+ # browsable outputs — pass --no-record too if you want nothing persisted.
2673
+ baker canvas run my-canvas.json --remote-cache off --no-record
2674
+
2689
2675
  # 3. Inspect a finished run (per-node timing, file list, optional video thumbs)
2690
2676
  baker canvas inspect <run_id>
2691
2677
 
@@ -2930,7 +2916,7 @@ Pick a `source` discriminator and declare the kind you expect. See [Ingestion](#
2930
2916
 
2931
2917
  **Outputs:** `asset` → `<params.expect>` / content-determined (URL strategy table) or extension-inferred (path).
2932
2918
 
2933
- **Path-source notes:** the canvas is **not portable** to another machine without the file. Cache key folds the file's `mtime:size`, so editing the file invalidates the cache automatically. Supported extensions: `png`, `jpg`/`jpeg`, `webp`, `gif`, `avif`, `svg`, `mp4`, `webm`, `mov`, `m4v`, `mp3`, `wav`, `m4a`, `ogg`, `flac`, `json`, `txt`, `md`, `markdown`, `html`/`htm`, `csv`, `ttf`, `otf`, `woff`, `woff2`. Unknown extensions fall back to magic-byte sniffing for common image formats (and an SVG content sniff), else `kind_mismatch`. **SVG (`expect: "image"`) is rasterized to a transparent PNG on ingest** — brand logos are usually SVG, and image-generation models can't read SVG markup, so it's upscaled (longest edge near 2048px) with transparency preserved and the resulting asset carries `metadata.rasterized_from: "svg"`. **Video (`expect: "video"`) duration is probed from the file's ISO-BMFF (`mp4`/`mov`/`m4v`) header** and stamped as the canonical `duration_ms` (and `metadata.duration_ms`); other containers (e.g. `webm`) leave it unset. Downstream `video_deconstruct` uses this declared duration to size its ingest-poll timeout and preflight — without it those fall back to worst-case budgets and a single deconstruct step can hit the action time limit.
2919
+ **Path-source notes:** the canvas is **not portable** to another machine without the file. Cache key folds the file's `mtime:size`, so editing the file invalidates the cache automatically. Supported extensions: `png`, `jpg`/`jpeg`, `webp`, `gif`, `avif`, `svg`, `mp4`, `webm`, `mov`, `m4v`, `mp3`, `wav`, `m4a`, `ogg`, `flac`, `json`, `txt`, `md`, `markdown`, `html`/`htm`, `csv`, `ttf`, `otf`, `woff`, `woff2`. Unknown extensions fall back to magic-byte sniffing for common image formats (and an SVG content sniff), else `kind_mismatch`. **Any `expect: "image"` in a format image-generation models can't read (SVG, AVIF, HEIC, TIFF, BMP) is normalized to PNG on ingest** — model-safe rasters (`jpeg`/`png`/`gif`/`webp`) pass through untouched, everything else is transcoded so a reference can never 400 a generation. This applies to **both `source: "path"` and `source: "url"`** (URL images are fetched and normalized locally, since the backend can't run the rasterizer). SVG gets density-aware upscaling (longest edge near 2048px, transparency preserved). The normalized asset carries `metadata.rasterized_from` set to the source format (e.g. `"svg"`, `"avif"`). **Video (`expect: "video"`) duration is probed from the file's ISO-BMFF (`mp4`/`mov`/`m4v`) header** and stamped as the canonical `duration_ms` (and `metadata.duration_ms`); other containers (e.g. `webm`) leave it unset. Downstream `video_deconstruct` uses this declared duration to size its ingest-poll timeout and preflight — without it those fall back to worst-case budgets and a single deconstruct step can hit the action time limit.
2934
2920
 
2935
2921
  **Cost:** 0 engine credits for direct fetch + yt-dlp + local file. Handinger charges per scrape.
2936
2922
 
@@ -3997,6 +3983,7 @@ baker canvas run ./reference-ad.video.canvas.json
3997
3983
  | Flag | Default | Effect |
3998
3984
  |---|---|---|
3999
3985
  | `--out <path>` | `<video-dir>/<name>.video.canvas.json` | Where to write the canvas (composition is copied alongside). |
3986
+ | `--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`. |
4000
3987
  | `--frames <mode>` | `generate` | `generate` emits ONE recast keyframe per scene (the original frame is dropped so the dropped `el_*` assets drive identity); `reuse` wires the real extracted first+last frames straight into the clips (faithful, cheaper, no recast). |
4001
3988
  | `--ambient` | off | Give silent **b-roll** scenes native diegetic ambient (Seedance `generate_audio`), mixed deep under the music bed. Talking scenes already carry voice; check levels don't muddy the mix before keeping it. |
4002
3989
  | `--max-scenes <n>` | all source scenes | **Cost lever that reduces fidelity** — caps the deconstruct, MERGING away every scene beyond the cap (fewer cuts, lost beats). Prints a warning when set; omit it to reproduce every scene. |
@@ -4038,6 +4025,7 @@ baker canvas run ./static-ad.canvas.json
4038
4025
  |---|---|---|
4039
4026
  | `--context <text>` | — | Known provenance (advertiser, category, market) to ground the describe. |
4040
4027
  | `--out <path>` | `<image-dir>/static-ad.canvas.json` (cwd when `<image>` is a URL) | Where to write the canvas (`prompt.json` is written alongside). |
4028
+ | `--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`. |
4041
4029
  | `--describe-model <id>` | registry default (`~google/gemini-pro-latest`) | Override the `image_describe` model. |
4042
4030
  | `--select-model <id>` | registry default (`~google/gemini-flash-latest`) | Override the element-selection `text_generate` model. |
4043
4031
  | `--layout-model <id>` | registry default (`~google/gemini-flash-latest`) | Override the global-layout `text_generate` model. |
@@ -4509,6 +4497,26 @@ import {
4509
4497
  } from "@koda-sl/baker-cli/engine";
4510
4498
  ```
4511
4499
 
4500
+ ## Creatives
4501
+
4502
+ Publish an approved canvas render as a first-class Baker creative. The image uploads to the Baker image library (tagged `creative`), a creative record is created/updated, and the command prints the creative reference JSON the dashboard renders in chat.
4503
+
4504
+ ```bash
4505
+ baker creatives publish ./canvas/<run_id>/<final>.png --title "Spring Offer 4x5" \
4506
+ --slug spring-offer-4x5 --run-id r_01JXYZ... \
4507
+ --source-reference-url "https://www.facebook.com/ads/library/?id=..."
4508
+ ```
4509
+
4510
+ | Flag | Effect |
4511
+ |---|---|
4512
+ | `--title <text>` | Required. Human title for the creative. |
4513
+ | `--slug <slug>` | Creative slug (`src/creatives/<slug>/`) — attaches the image to that creative's row, marks it `published`. |
4514
+ | `--run-id <r_…>` | Pins the approved generation from the creative's run history as the published one. |
4515
+ | `--source-reference-url <url>` | Original reference ad URL, recorded on the creative. |
4516
+ | `--context <text>` | Optional describe context for the uploaded image asset. |
4517
+
4518
+ Without `--slug` the command behaves as before (one creative record per published image). With `--slug` it upserts the repo-convention row — the same one the dashboard's Creatives tab and the `src/creatives/{slug}/` folder describe — so publish, repo sync, and run history all land on a single record regardless of order.
4519
+
4512
4520
  ## Help & Discovery
4513
4521
 
4514
4522
  Every command supports `--help` for usage info:
@@ -4545,7 +4553,6 @@ This CLI is designed for AI agent consumption. Key patterns:
4545
4553
  - **0.105.0**: `baker images ...`, `baker videos ...`, and `baker testimonials ...` commands now type their `/api/{images,videos,testimonials}/...` request/response payloads from the shared `@baker/api` contract package instead of hand-written local interfaces. No command, flag, or output-shape changes.
4546
4554
  - **0.106.0**: `baker ads linkedin` gains staged write commands — `campaign-groups`/`campaigns`/`creatives` create|update|pause|resume|(archive|)duplicate, `audiences create|upload`, `conversions create|update`, `lead-forms create|update`, plus `draft [remove|clear]` for review/undo. Ops validate at stage time, apply on chat publish, and run simulated (`urn:li:simulated:*`) unless LinkedIn writes are enabled for the company.
4547
4555
  - **0.116.0**: `lead-forms create` models the full Campaign Manager form — `locale`, form banner image (`formImageId`/`formImageUrn`), predefined profile-field questions (validated enum) vs custom questions (`SINGLE_LINE_TEXT`/`MULTIPLE_CHOICE` with `options`, ≤3 custom), `privacyPolicyText`, disclosure `consents[]` (≤5), tracking `hiddenFields[]` (≤20), and `thankYou` confirmation CTA + landing/appointment link. Staged preview surfaces best-practice warnings (no qualifying question, no confirmation, no consent). No breaking flag changes.
4548
- - **0.121.0**: `lead-forms create` drops the `privacyPolicyText` field — LinkedIn's versioned lead-form API has no privacy-policy-text slot, so it was silently discarded on publish. Use `legalDisclaimer` (shown under the form) or `consents[]` (disclosure checkboxes) instead. (Companion backend fix: staged lead-form questions were serialized in a shape LinkedIn dropped — they now publish correctly, and the staged preview lists each question.)
4549
4556
  - **0.119.0**: `draft amend`/`draft show` land on both `baker ads google` and `baker ads linkedin` — a generic JSON-merge-patch to update any staged op in place plus a full-payload receipt, replacing remove+recreate as the correction path. Google gains `assets update` and `asset-groups create|update` (Performance Max asset groups are now their own entity — `ads create --format performanceMaxAssetGroup` never worked and is gone); `ads create --format video` moves from a bare YouTube id to `--video-assets` refs (**breaking flag change** — stage the video as an asset first); `--format demandGen` gains `--image-assets`/`--square-image-assets`/`--logo-image-assets` and flag-building for headlines/descriptions. LinkedIn's `draft list` now renders a readable Campaign group ▸ Campaign ▸ Creative tree by default (`--json` for raw), `creatives update` gains `--campaign` (re-parent while staged), and `campaigns update` passes create-only fields (`--group`/`--type`/`--locale`/`--associated-entity`) through when amending a `li_temp_*` staged create instead of always stripping them.
4550
4557
 
4551
4558
  ## Publishing