@koda-sl/baker-cli 0.153.0 → 0.155.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 +55 -1
- package/dist/{chunk-OO5BDH3J.js → chunk-7Z6C5OVO.js} +99 -17
- package/dist/chunk-7Z6C5OVO.js.map +1 -0
- package/dist/cli.js +2372 -1311
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-OO5BDH3J.js.map +0 -1
package/README.md
CHANGED
|
@@ -2495,9 +2495,16 @@ baker actions claim <action-id> # live — returns action details + r
|
|
|
2495
2495
|
baker actions release <action-id>
|
|
2496
2496
|
|
|
2497
2497
|
baker actions create --name "Build hero" --priority high --tags landing,creative --description "..."
|
|
2498
|
-
# → returns { ok, data: { tempId }, hints: [...] } — check hints for tags/priority/dependencies/description reminders
|
|
2498
|
+
# → returns { ok, data: { tempId, draftCreateCount }, hints: [...] } — check hints for tags/priority/dependencies/description reminders
|
|
2499
2499
|
# If the name/description reads as recurring or future-dated (e.g. "weekly", "every Monday", "schedule"),
|
|
2500
2500
|
# create emits a hint to use `baker scheduled-actions create` instead of a Work Action.
|
|
2501
|
+
# If it instead names work a surface executes in-chat (a GTM container change, a site tag, an ad-platform
|
|
2502
|
+
# write, a page or form edit, or a value only the user has), create emits a do-it-now hint naming that
|
|
2503
|
+
# surface — doing the work is the default, an action is the exception. One advisory hint per call: the
|
|
2504
|
+
# scheduled redirect wins when both match.
|
|
2505
|
+
# `draftCreateCount` is how many creates this chat has staged (counted after this op, so it drops again
|
|
2506
|
+
# after `draft remove`). At 3 or more, create emits a fan-out hint: re-read the draft and merge actions
|
|
2507
|
+
# that touch the same system into one.
|
|
2501
2508
|
# If no --tags are passed, create emits a MISSING --tags hint — the action is invisible to the backlog's tag filter.
|
|
2502
2509
|
# If no --priority is passed, create emits a MISSING --priority hint — the action ranks as normal/medium in the do-first order.
|
|
2503
2510
|
baker actions update <action-id> --name "Better name" --tags google-ads,strategy # --tags REPLACES the set; '' clears
|
|
@@ -2623,6 +2630,52 @@ baker history list --category ads --full # ad writes with raw metadata
|
|
|
2623
2630
|
|
|
2624
2631
|
---
|
|
2625
2632
|
|
|
2633
|
+
### `baker hubspot forms list | view` · `baker hubspot meetings list | view`
|
|
2634
|
+
|
|
2635
|
+
Read-only view of the company's **connected HubSpot account** — the forms and meeting links (calendars) that live there, plus the settings inside HubSpot that decide how each behaves once placed in a Form. Fetched from HubSpot live on every call; nothing is cached.
|
|
2636
|
+
|
|
2637
|
+
The reason this exists: a form's **post-submit action** (inline thank-you vs redirect to a URL), its embed version, its consent mode, and a calendar's booking fields are *not* persisted onto the flow node when a form is picked. They cannot be read from `_data.json` or `baker flows show` — only from here.
|
|
2638
|
+
|
|
2639
|
+
```bash
|
|
2640
|
+
baker hubspot forms list # every form: embed type + post-submit action
|
|
2641
|
+
baker hubspot forms list --redirecting-only # which forms redirect away on submit
|
|
2642
|
+
baker hubspot forms list --embed-type legacy # only legacy-embed forms
|
|
2643
|
+
baker hubspot forms view <formId> # fields, consent mode, full configuration
|
|
2644
|
+
baker hubspot forms view <formId> --full # + the raw HubSpot payload
|
|
2645
|
+
baker hubspot forms view <formId> --as-node # the form.external blob for a flow node
|
|
2646
|
+
baker hubspot meetings list # every calendar + whether booking redirects
|
|
2647
|
+
baker hubspot meetings view <slug> # booking-form fields for one calendar
|
|
2648
|
+
baker hubspot meetings view <slug> --as-node # the form.external blob for a flow node
|
|
2649
|
+
```
|
|
2650
|
+
|
|
2651
|
+
**`forms list` flags:** `--search <text>` (name substring), `--redirecting-only`, `--embed-type legacy|v4|unknown`. Rows carry only what it takes to choose; `portalId` is returned once on `data`, not per row.
|
|
2652
|
+
**`forms view`:** positional `<formId>`; `--full` adds the untouched HubSpot payload; `--as-node` returns the resource blob instead of the readable view.
|
|
2653
|
+
**`meetings list` flags:** `--search <text>`, `--redirecting-only`.
|
|
2654
|
+
**`meetings view`:** positional `<slug>` — the only reliable source for a calendar's booking fields (HubSpot omits `customParams` from the list endpoint, so `fieldCount: null` there means unknown, not zero); `--as-node` as above.
|
|
2655
|
+
|
|
2656
|
+
**`--as-node`** returns exactly the object a flow node's `form.external` expects, so an agent can wire a HubSpot step by editing the flow's `_data.json` instead of interrupting the user with the `request_flow_input` approval form. It includes two fields the dashboard picker omits and the renderer needs: `configuration.postSubmitAction` (drives post-submit redirect suppression) and `region` (selects the v4 embed host — without it a v4 form on a eu1/ap1 portal loads the wrong script host).
|
|
2657
|
+
|
|
2658
|
+
**Response:**
|
|
2659
|
+
|
|
2660
|
+
```json
|
|
2661
|
+
{
|
|
2662
|
+
"ok": true,
|
|
2663
|
+
"data": {
|
|
2664
|
+
"portalId": 1234567,
|
|
2665
|
+
"forms": [
|
|
2666
|
+
{ "id": "…", "name": "Demo request", "embedType": "v4", "fieldCount": 4, "postSubmitAction": { "type": "redirect_url", "value": "https://example.com/thanks" } }
|
|
2667
|
+
]
|
|
2668
|
+
},
|
|
2669
|
+
"meta": { "count": 1 }
|
|
2670
|
+
}
|
|
2671
|
+
```
|
|
2672
|
+
|
|
2673
|
+
No write surface against HubSpot itself — a form's fields, redirect, or consent text are changed inside HubSpot. Wiring one into a Form step is done with `--as-node` (above), not `request_flow_input`; the approval form is only needed when no account is connected or the right form is ambiguous. When no HubSpot account is connected, every command exits 1 with `NO_HUBSPOT_CONNECTION` and a `fix` telling the agent to route the user to **Brain → Integrations → Tools**.
|
|
2674
|
+
|
|
2675
|
+
`meetings list` reports `redirectKnown: false` when HubSpot omitted the calendar's booking settings; `redirectUrl: null` alongside it means *unknown*, not "no redirect". `--redirecting-only` deliberately keeps those rows rather than answering "none" from missing data.
|
|
2676
|
+
|
|
2677
|
+
---
|
|
2678
|
+
|
|
2626
2679
|
### `baker chats list | view | transcript | diff`
|
|
2627
2680
|
|
|
2628
2681
|
Read-only inspection of **other Sessions (chats) on the same account** — so an agent can reuse prior work ("like we did in that other chat, but for X"). Same-account only; never crosses a company boundary and has no write surface.
|
|
@@ -3415,6 +3468,7 @@ Generate video. Async with polling. Two curated models.
|
|
|
3415
3468
|
| `first_frame` | image | no | Starting keyframe (image-to-video) |
|
|
3416
3469
|
| `last_frame` | image | no | Ending keyframe |
|
|
3417
3470
|
| `reference` | image | no | Alternative to `first_frame` when only one image is given |
|
|
3471
|
+
| `references` | image[] | no | Reference-to-video: several images used as visual guidance (this person, this product) instead of an exact opening frame. **Mutually exclusive with `first_frame`** — when both are wired the frame wins and these are ignored, so pick one mode. |
|
|
3418
3472
|
|
|
3419
3473
|
Accepted ref-image MIMEs vary by model — see per-model sections below.
|
|
3420
3474
|
|
|
@@ -1119,6 +1119,7 @@ var OPENROUTER_IMAGE_SIZE = ["1K", "2K", "4K"];
|
|
|
1119
1119
|
var OPENROUTER_IMAGE_SIZE_EXTENDED = ["0.5K", ...OPENROUTER_IMAGE_SIZE];
|
|
1120
1120
|
var OPENROUTER_IMAGE_QUALITY = ["auto", "low", "medium", "high"];
|
|
1121
1121
|
var SEEDANCE_DURATIONS = [4, 5, 6, 8, 10, 12, 15];
|
|
1122
|
+
var KLING_DURATIONS = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
1122
1123
|
var ELEVENLABS_OUTPUT_FORMATS = [
|
|
1123
1124
|
"mp3_22050_32",
|
|
1124
1125
|
"mp3_44100_32",
|
|
@@ -1376,9 +1377,13 @@ var MODEL_REGISTRY = {
|
|
|
1376
1377
|
video_generate: {
|
|
1377
1378
|
"bytedance/seedance-2.0": {
|
|
1378
1379
|
// Routed via Replicate's official `bytedance/seedance-2.0` model. NOTE:
|
|
1379
|
-
// ByteDance's upstream
|
|
1380
|
-
//
|
|
1381
|
-
//
|
|
1380
|
+
// ByteDance's upstream likeness filter blocks photoreal human faces on ANY
|
|
1381
|
+
// reseller, and it does NOT care whether the person is real: it classifies
|
|
1382
|
+
// pixels, so an AI-generated face that looks photographic is refused
|
|
1383
|
+
// exactly like a photograph (E005 / content_policy_blocked). Confirmed in
|
|
1384
|
+
// production against faces we generated ourselves. The only escape is Veo
|
|
1385
|
+
// — NOT a synthetic presenter, which an earlier version of this note
|
|
1386
|
+
// wrongly recommended and which sends you round the same loop.
|
|
1382
1387
|
label: "ByteDance Seedance 2.0",
|
|
1383
1388
|
inputs: [],
|
|
1384
1389
|
optional_inputs: [{ kind: "image", mimes: REPLICATE_IMAGE_MIMES }],
|
|
@@ -1412,7 +1417,7 @@ var MODEL_REGISTRY = {
|
|
|
1412
1417
|
prompt: { kind: "string" },
|
|
1413
1418
|
negative_prompt: { kind: "string" },
|
|
1414
1419
|
aspect_ratio: { kind: "string", enum: ["16:9", "9:16"] },
|
|
1415
|
-
resolution: { kind: "string", enum: ["720p", "1080p"] },
|
|
1420
|
+
resolution: { kind: "string", enum: ["720p", "1080p", "4K"] },
|
|
1416
1421
|
duration: { kind: "number", enum: [4, 6, 8] },
|
|
1417
1422
|
seed: { kind: "number" },
|
|
1418
1423
|
generate_audio: { kind: "boolean" },
|
|
@@ -1424,9 +1429,14 @@ var MODEL_REGISTRY = {
|
|
|
1424
1429
|
"kwaivgi/kling-v3.0-pro": {
|
|
1425
1430
|
// Motion-transfer / dynamic multi-shot beats. Reachable through the default
|
|
1426
1431
|
// OpenRouter gateway (generic video body — no google-vertex block), so it
|
|
1427
|
-
// needs no direct-provider exception.
|
|
1428
|
-
//
|
|
1429
|
-
//
|
|
1432
|
+
// needs no direct-provider exception. `cfg_scale` trades prompt adherence
|
|
1433
|
+
// vs motion freedom; higher = closer to prompt.
|
|
1434
|
+
//
|
|
1435
|
+
// Params below are the ones OpenRouter actually advertises for this model
|
|
1436
|
+
// (GET /api/v1/videos/models). Three were wrong before and each was a free
|
|
1437
|
+
// 400 or a silently unsupported knob: it renders 720p ONLY (1080p was
|
|
1438
|
+
// offered and rejected), it takes ANY duration from 3-15s (we allowed just
|
|
1439
|
+
// 5 and 10), and it does not support `seed` at all.
|
|
1430
1440
|
label: "Kling 3.0",
|
|
1431
1441
|
inputs: [],
|
|
1432
1442
|
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES }],
|
|
@@ -1436,10 +1446,9 @@ var MODEL_REGISTRY = {
|
|
|
1436
1446
|
// over-length prompt fails validate (free) not the billed call.
|
|
1437
1447
|
prompt: { kind: "string", maxLength: 2500 },
|
|
1438
1448
|
negative_prompt: { kind: "string" },
|
|
1439
|
-
aspect_ratio: { kind: "string", enum: ["
|
|
1440
|
-
resolution: { kind: "string", enum: ["720p"
|
|
1441
|
-
duration: { kind: "number", enum:
|
|
1442
|
-
seed: { kind: "number" },
|
|
1449
|
+
aspect_ratio: { kind: "string", enum: ["16:9", "9:16", "1:1"] },
|
|
1450
|
+
resolution: { kind: "string", enum: ["720p"] },
|
|
1451
|
+
duration: { kind: "number", enum: KLING_DURATIONS },
|
|
1443
1452
|
generate_audio: { kind: "boolean" },
|
|
1444
1453
|
cfg_scale: { kind: "number", min: 0, max: 1 }
|
|
1445
1454
|
}
|
|
@@ -1455,7 +1464,7 @@ var MODEL_REGISTRY = {
|
|
|
1455
1464
|
prompt: { kind: "string" },
|
|
1456
1465
|
negative_prompt: { kind: "string" },
|
|
1457
1466
|
aspect_ratio: { kind: "string", enum: ["16:9", "9:16"] },
|
|
1458
|
-
resolution: { kind: "string", enum: ["720p", "1080p"] },
|
|
1467
|
+
resolution: { kind: "string", enum: ["720p", "1080p", "4K"] },
|
|
1459
1468
|
duration: { kind: "number", enum: [4, 6, 8] },
|
|
1460
1469
|
seed: { kind: "number" },
|
|
1461
1470
|
generate_audio: { kind: "boolean" },
|
|
@@ -1777,6 +1786,58 @@ function validateValue(key, value, schema, model) {
|
|
|
1777
1786
|
}
|
|
1778
1787
|
}
|
|
1779
1788
|
|
|
1789
|
+
// ../canvas-contract/src/videoCost.ts
|
|
1790
|
+
var CREDITS_PER_USD = 100;
|
|
1791
|
+
var SEEDANCE_USD_PER_SECOND = {
|
|
1792
|
+
"480p": 0.18,
|
|
1793
|
+
"720p": 0.5,
|
|
1794
|
+
"1080p": 0.62,
|
|
1795
|
+
"4k": 0.62
|
|
1796
|
+
};
|
|
1797
|
+
var DEFAULT_VIDEO_RESOLUTION = "720p";
|
|
1798
|
+
var DEFAULT_VIDEO_DURATION_S = 5;
|
|
1799
|
+
function isSeedanceModel(model) {
|
|
1800
|
+
return model.startsWith("bytedance/seedance");
|
|
1801
|
+
}
|
|
1802
|
+
var FALLBACK_USD_PER_SECOND = 0.5;
|
|
1803
|
+
function seedanceUsdPerSecond(resolution) {
|
|
1804
|
+
return SEEDANCE_USD_PER_SECOND[resolution ?? DEFAULT_VIDEO_RESOLUTION] ?? FALLBACK_USD_PER_SECOND;
|
|
1805
|
+
}
|
|
1806
|
+
var USD_PER_SECOND = {
|
|
1807
|
+
// Kling publishes one flat rate across every resolution and mode.
|
|
1808
|
+
"kwaivgi/kling-v3.0-pro": { silent: 0.112, audio: 0.168 },
|
|
1809
|
+
// Veo prices 4K far above the base tier — and 4K is a selectable resolution,
|
|
1810
|
+
// so folding it into the base rate under-quotes the dearest clip we can make.
|
|
1811
|
+
"google/veo-3.1": {
|
|
1812
|
+
silent: 0.2,
|
|
1813
|
+
audio: 0.4,
|
|
1814
|
+
byResolution: { "4K": { silent: 0.4, audio: 0.6 } }
|
|
1815
|
+
},
|
|
1816
|
+
"google/veo-3.1-fast": {
|
|
1817
|
+
silent: 0.1,
|
|
1818
|
+
audio: 0.12,
|
|
1819
|
+
byResolution: {
|
|
1820
|
+
"720p": { silent: 0.08, audio: 0.1 },
|
|
1821
|
+
"4K": { silent: 0.25, audio: 0.3 }
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
};
|
|
1825
|
+
function estimateVideoCostUsd({ model, duration, resolution, generateAudio }) {
|
|
1826
|
+
const seconds = duration ?? DEFAULT_VIDEO_DURATION_S;
|
|
1827
|
+
if (isSeedanceModel(model)) return seedanceUsdPerSecond(resolution) * seconds;
|
|
1828
|
+
const published = USD_PER_SECOND[model];
|
|
1829
|
+
if (published) {
|
|
1830
|
+
const rate = (resolution ? published.byResolution?.[resolution] : void 0) ?? published;
|
|
1831
|
+
return (generateAudio ? rate.audio : rate.silent) * seconds;
|
|
1832
|
+
}
|
|
1833
|
+
const dearestKnownRate = Math.max(...Object.values(SEEDANCE_USD_PER_SECOND));
|
|
1834
|
+
return dearestKnownRate * seconds;
|
|
1835
|
+
}
|
|
1836
|
+
function estimateVideoCredits(input) {
|
|
1837
|
+
const credits = estimateVideoCostUsd(input) * CREDITS_PER_USD;
|
|
1838
|
+
return Math.ceil(Number(credits.toFixed(6)));
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1780
1841
|
// src/engine/lib/concurrency.ts
|
|
1781
1842
|
var DEFAULT_CONCURRENCY = 8;
|
|
1782
1843
|
function resolveConcurrency(...candidates) {
|
|
@@ -2573,7 +2634,7 @@ function looksLikeHttpUrl(value) {
|
|
|
2573
2634
|
var VEO_PERSON_GENERATION = "allow_adult";
|
|
2574
2635
|
var VEO_NEGATIVE_PROMPT = "subtitles, captions, on-screen text, watermark, logo, warped face, distorted hands, extra fingers, low quality";
|
|
2575
2636
|
var VEO_DURATIONS = [4, 6, 8];
|
|
2576
|
-
var
|
|
2637
|
+
var KLING_DURATIONS2 = [5, 10];
|
|
2577
2638
|
var KLING_NEGATIVE_PROMPT = "warped face, distorted hands, extra fingers, morphing, flicker, on-screen text, watermark, low quality";
|
|
2578
2639
|
var KLING_CFG_SCALE = 0.7;
|
|
2579
2640
|
var SPEAKS_PROSE = (line) => `The person speaks to camera; lip-sync follows the dialogue verbatim, with delivery and emotion carried in the wording itself (no bracketed cues). Dialogue: "${line}"`;
|
|
@@ -2619,7 +2680,7 @@ var KLING_PROFILE = {
|
|
|
2619
2680
|
// Kling takes a negative_prompt PARAM instead (paramDefaults).
|
|
2620
2681
|
keyframeInstruction: "Preserve the composition and colors of the first frame; animate the motion described.",
|
|
2621
2682
|
wordBudget: 200,
|
|
2622
|
-
durationSet:
|
|
2683
|
+
durationSet: KLING_DURATIONS2,
|
|
2623
2684
|
paramDefaults: { negative_prompt: KLING_NEGATIVE_PROMPT, cfg_scale: KLING_CFG_SCALE }
|
|
2624
2685
|
};
|
|
2625
2686
|
function clipProfileFor(modelId) {
|
|
@@ -7453,12 +7514,33 @@ var videoGenerateNode = delegated({
|
|
|
7453
7514
|
inputs: z28.object({
|
|
7454
7515
|
first_frame: ImageRef.optional(),
|
|
7455
7516
|
last_frame: ImageRef.optional(),
|
|
7456
|
-
reference: ImageRef.optional()
|
|
7517
|
+
reference: ImageRef.optional(),
|
|
7518
|
+
/**
|
|
7519
|
+
* Reference-to-video: several images the model uses as visual guidance
|
|
7520
|
+
* (this person, this product) instead of an exact opening frame. Mutually
|
|
7521
|
+
* exclusive with `first_frame` — OpenRouter treats a request carrying both
|
|
7522
|
+
* as image-to-video and ignores these, so wire one or the other.
|
|
7523
|
+
*/
|
|
7524
|
+
references: z28.array(ImageRef).optional()
|
|
7457
7525
|
}).loose(),
|
|
7458
7526
|
params: VideoGenerateParams,
|
|
7459
7527
|
outputs: z28.object({ video: VideoRef }).strict(),
|
|
7460
7528
|
outputKinds: { video: "video" },
|
|
7461
|
-
|
|
7529
|
+
// Priced from the shared contract, so `validate`'s quote and the charge the
|
|
7530
|
+
// backend applies come from ONE table. A flat number here under-quoted a
|
|
7531
|
+
// 1080p 8s clip by ~10x, and the agent reads this out to the user as "this
|
|
7532
|
+
// will cost N" before spending it.
|
|
7533
|
+
cost: ({ params }) => ({
|
|
7534
|
+
credits: estimateVideoCredits({
|
|
7535
|
+
model: params.model,
|
|
7536
|
+
duration: params.duration,
|
|
7537
|
+
resolution: params.resolution,
|
|
7538
|
+
// Audio bills at a separate, higher rate on every model that offers it
|
|
7539
|
+
// (Veo 3.1 doubles), so omitting it quotes half the real cost.
|
|
7540
|
+
generateAudio: params.generate_audio
|
|
7541
|
+
}),
|
|
7542
|
+
seconds_estimate: 120
|
|
7543
|
+
})
|
|
7462
7544
|
});
|
|
7463
7545
|
|
|
7464
7546
|
// src/engine/nodes/remote/videoBackgroundRemove.ts
|
|
@@ -7941,4 +8023,4 @@ export {
|
|
|
7941
8023
|
defaultRegistry,
|
|
7942
8024
|
createEngineFromEnv
|
|
7943
8025
|
};
|
|
7944
|
-
//# sourceMappingURL=chunk-
|
|
8026
|
+
//# sourceMappingURL=chunk-7Z6C5OVO.js.map
|