@koda-sl/baker-cli 0.228.0-dev.ddddd841e → 0.231.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
@@ -1151,54 +1151,6 @@ Each finding: `{id, area, check, status, severity, evidence, fix: {explanation,
1151
1151
 
1152
1152
  ---
1153
1153
 
1154
- ### First-party web analytics (`baker analytics`)
1155
-
1156
- Baker's own measurement of the pages it publishes. No connection to set up and nothing to configure — data exists from the moment a page is published — and it is the only source that reports drop-off **per Form step**.
1157
-
1158
- Preset-first; `overview` answers most questions in one call.
1159
-
1160
- ```bash
1161
- baker analytics overview # traffic, top pages, sources, and every Form's worst step
1162
- baker analytics overview --days 7
1163
- baker analytics traffic --days 90 --full # full breakdowns plus the per-day trend
1164
- baker analytics funnel --flow contact # which step loses people
1165
- baker analytics page --path /pricing # one page in detail
1166
- baker analytics triggers --flow contact # what visitors did in the Form, wired up or not
1167
- baker analytics releases # traffic and conversions per published build
1168
- baker analytics landings # every page side by side, with a sparkline each
1169
- baker analytics landings --tag q4 # only the pages filed under one campaign tag
1170
- baker analytics tags # the same numbers rolled up per campaign
1171
- baker analytics events # the events the pages define for themselves
1172
- baker analytics events --event video_progress --property milestone
1173
- baker analytics events --steps hero_view,pricing_view,demo_click # an ordered page funnel
1174
- baker analytics devices --grain viewport # which widths the page has to survive
1175
- baker analytics geo --grain postal_code --country ES
1176
- baker analytics bots # which crawlers fetch the site
1177
- baker analytics presets # what each report answers
1178
- ```
1179
-
1180
- Shared flags: `--days <n>` (default 30) or `--start-date` / `--end-date` (`YYYY-MM-DD`, end inclusive); `--full`; `--compare` to also return the preceding window of the same length; `--timezone <IANA>` and `--granularity hour|day|week|month` to shape a series. Every call reads live — there is no cache layer, so there is nothing to bypass.
1181
-
1182
- Pass `--timezone` whenever the client is not in UTC. Day boundaries are drawn in UTC by default, which moves two hours of every Spanish evening onto the following day — not a rounding error on a day-of-week comparison, but the wrong day.
1183
-
1184
- Reading the output:
1185
-
1186
- - `visitors` and `sessions` are counted from explicit `visitor_new` / `session_start` events, so a session begins when the page says it did rather than when a query guesses.
1187
- - `pageViews` prefers the server-side count, which ad blockers cannot suppress, so it usually exceeds what GA4 reports for the same period.
1188
- - Rates are `null`, never `0`, when there is no denominator — `null` means "no data", `0` means "genuinely none".
1189
- - `warnings[]` and `hints[]` carry caveats (small sample, sampled data) that belong in the answer, not in the footnotes.
1190
- - `triggers[]` reports what visitors *did* inside a Form — a link click that redirects them off the site, a scheduling widget, an embedded checkout posting back — none of which produces a funnel step. `sideEffectsFired` says how many of those fires actually did something; a trigger with many fires and none is real behaviour with nothing wired to it.
1191
- - `releases[]` gives one row per published build, so a change to a page can be compared before and after instead of against a date. Only events carrying a build are counted, so its `pageViews` sits below the site total for the same period.
1192
-
1193
- - `landings[]` is one row per page with its real name and campaign tags, joined from a dimension Baker mirrors on every publish. An empty `name` means the mirror has not caught up — say "not synced yet" rather than showing the id as a title.
1194
- - `trend[]` returns **every** bucket in the window, including ones with no traffic. A quiet day is a real zero rather than a missing row, so a chart cannot draw a straight line through it and imply traffic that did not happen.
1195
- - `customEvents[]` covers only events a page defined for itself through `data-baker-*` attributes or `window.baker.track()`. Each row lists the property keys it carries, which is what tells you what you can break it down by.
1196
- - `customFunnel[]` is **ordered**: a session counts at step N only if it produced step N after step N-1. Reordering `--steps` answers a different question.
1197
-
1198
- Data is retained for 400 days; a window reaching further back comes back with a `BEYOND_RETENTION` warning, and the older part is missing rather than zero.
1199
-
1200
- ---
1201
-
1202
1154
  ### Google Analytics 4 (`baker ga4`)
1203
1155
 
1204
1156
  GA4 commands for multi-channel audits **and** for configuring what the property measures. Playbook-aligned report presets, property health audits, free-form Data API queries, and staged Admin API writes.
@@ -2976,18 +2928,42 @@ Notes:
2976
2928
 
2977
2929
  ### Forms / Flows (`baker flows`)
2978
2930
 
2979
- 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.
2931
+ Read and shape this workspace's Forms (flows). Operates on the local `_data.json` files only; no secret values are ever decrypted or printed.
2980
2932
 
2981
- **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.
2933
+ **A Form has two halves, split by a trust boundary.** Its *structure* — steps, conditions, side effects, field mappings is yours, and the write subcommands below edit exactly that. Its *confidential* half connection secrets, OAuth accounts, third-party field definitions (HubSpot, Calendly, HighLevel, SavvyCal) — is configured through the `request_flow_input` tool (`baker_ui` MCP server): the agent authors the surrounding structure and references it by `nodeId`/`sideEffectId`, and the user enters secrets, connects accounts, and picks resources 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. Nothing any of these commands does touches a live system.
2982
2934
 
2983
2935
  ```bash
2984
- baker flows list # every Form + how many confidential fields still need setup
2985
- baker flows show contact # one Form's confidential fields and their status
2986
- baker flows show contact --full # include the full flow tree (secret values redacted)
2936
+ baker flows list # every Form + how many confidential fields still need setup
2937
+ baker flows show contact # one Form's confidential fields and their status
2938
+ baker flows show contact --full # include the full flow tree (secret values redacted)
2939
+
2940
+ baker flows schema # both vocabularies + the customForm field types
2941
+ baker flows schema node customForm # one type: skeleton, who fills what, the reference file
2942
+ baker flows schema side-effect googleSpreadsheet
2943
+
2944
+ baker flows add-node contact --type text --name "Thanks"
2945
+ baker flows add-side-effect contact --node <nodeId> --type googleSpreadsheet # triggerId comes from the step
2946
+ baker flows map contact --from map.json --write # a whole mapping at once — past ~3 fields, use this
2947
+ baker flows map contact --map A=nombre --write # one or two fields
2948
+ baker flows map contact --hubspot-form <guid> --from map.json --write # HubSpot: field types read off the form
2949
+ baker flows map contact --from map.json --replace --write # the slot becomes exactly this; use it to REMOVE a mapping
2950
+ baker flows normalize contact --write # repairs a nulled optional; runs pre-commit anyway
2987
2951
  ```
2988
2952
 
2989
2953
  Notes:
2990
2954
 
2955
+ - **`schema` takes the kind as an argument because `hubspot` is both** — a node type (embeds a form on the page) and a side-effect type (fires a behavioural event). They are different things with one name.
2956
+ - **Configure the destination before you map.** `columnMapping`/`fieldMapping` describe a *specific* destination — sheet columns, a portal's field names — that only `request_flow_input` can see, and that call returns it. A mapping written first is valid JSON that ships and drops every submission; `verify` blocks the half-wired result.
2957
+ - **`map` reads the record shape off the side effect's type.** One property name, four record shapes: a Sheet is addressed by column letter, HubSpot by property name, Pipedrive and GoHighLevel by field key, Crmble by field id. That is why there is no `--key`, and why `--entity` and `--custom`/`--standard` are required rather than defaulted.
2958
+ - **A mapping is usually eight to fifteen fields, so `--from` is the main door.** It takes `{ "map": { "<destField>": "<value>" } }` from a file or stdin; `--map` flags are for one or two. Both produce identical output.
2959
+ - **Most CRM fields are not fed by a form field.** The value grammar is a bare form field (`nombre`), `field:Step.name` when two steps share a name, `tracking:utm_source`, `global:Name`, `code:exposed_value`, a `"literal"`, or any of those joined with `+`. Tracking names are validated against the engine's own `TRACKING_FIELD_IDS`, read out of the workspace rather than copied — attribution columns are the most common CRM mapping there is, and they were unexpressible before.
2960
+ - **A CRM mapping's field type is derived from the destination, never defaulted.** Every CRM record types `fieldType` as required, and it is the account's answer, not the agent's — HubSpot builds its submission key as `<objectTypeId>.<fieldType>.<fieldName>`, so a wrong type on a date property skips the `YYYY-MM-DD` coercion and the value is dropped. `--hubspot-form <formGuid>` (or `"hubspotForm"` in the mapping file) reads every property's type and object type off the form, so nothing has to state one. Where a destination cannot be read, put the type on the LEFT — `c0ffee:varchar=email` — which leaves `:` on the right for the value kinds. A mapping with no type from either route is refused, never written without one.
2961
+ - **`email` maps like anything else**, into `body.fields`, while `body.format` is `"json"`. A `"body"`-format email is one written message with no keys to address, and `map` refuses it rather than reshaping the body.
2962
+ - **Mapping twice adds; it does not start over.** Every slot merges with what is already in it, addressed by destination name — re-mapping a name overwrites it in place, a new name is appended, and a name the call did not mention is left alone. That is the default because a mapping is built in stages (configure the destination, read the real names back, map, come back for the rest), and replacing on every call turned "add the ninth field" into "delete the other eight". `--replace` (or `"replace": true` in the mapping file) writes the slot exactly as passed, and is the only way to remove a mapping. The response says how many were kept either way.
2963
+ - **`triggerId` is set from the step, not from the side-effect type.** A side effect runs only when its trigger is the id its own step raises: a `customForm` step raises `customForm.onFormSubmitted`, a Calendly step `calendlyEvent.eventScheduled`, a HubSpot widget `hubspotForm.onFormSubmitted`, a `text` step one of two depending on `allowNextNode`, and an `iframe` step one per declared event. A mismatch is the quietest failure in the engine — the file is valid, verify is green, and the side effect never runs — so `add-side-effect` derives it and refuses an id the step cannot raise. `--trigger` is for the non-completion moments (a HubSpot form's `onFormReady`, a Calendly page view). **A SavvyCal step raises no trigger at all**, so a side effect there is refused outright; put it on the following step, which the booking still advances to. `baker flows schema node <type>` lists a step's ids, and `baker flows show <slug>` names any side effect already wired to a moment its step never raises.
2964
+ - **A step's name becomes a constant, so `add-node` judges it as one.** The Form's generated code carries `export const <NAME> = "<node id>"` per step, keyed by upper-casing the name and splitting camelCase — so `contactInfo` and `Contact Info` are the same constant, and `1. Your details` or `Thanks!` are not valid ones at all. Both are refused when the step is created, where the message can name the step; left to the generator they surface as a duplicate-constant error or a syntax error in a file nobody wrote.
2965
+ - **`normalize` exists so authoring a Form does not require remembering an exception.** `oauthProviderId` is an optional `string`, so a `null` there fails typecheck one build later — it is repaired and staged instead of rejected.
2966
+
2991
2967
  - **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.
2992
2968
  - 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`.
2993
2969
  - `request_flow_input` changes stage on the chat's branch and apply when the chat is published; discarding the chat drops them.
@@ -16,9 +16,9 @@ import {
16
16
  shouldEscalate
17
17
  } from "./chunk-DZUVUGEP.js";
18
18
 
19
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js
19
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js
20
20
  var require_safe_stable_stringify = __commonJS({
21
- "../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js"(exports, module) {
21
+ "../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports, module) {
22
22
  "use strict";
23
23
  var { hasOwnProperty } = Object.prototype;
24
24
  var stringify = configure2();
@@ -1092,7 +1092,7 @@ function resolveAdaptFormats(params) {
1092
1092
  return params.formats ?? [];
1093
1093
  }
1094
1094
 
1095
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/esm/wrapper.js
1095
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/esm/wrapper.js
1096
1096
  var import__ = __toESM(require_safe_stable_stringify(), 1);
1097
1097
  var configure = import__.default.configure;
1098
1098
  var wrapper_default = import__.default;
@@ -9074,4 +9074,4 @@ export {
9074
9074
  defaultRegistry,
9075
9075
  createEngineFromEnv
9076
9076
  };
9077
- //# sourceMappingURL=chunk-CMPAHYLB.js.map
9077
+ //# sourceMappingURL=chunk-EKLAHWSF.js.map