@feastalytics/cli 0.1.4 → 0.1.5

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/feast/SKILL.md CHANGED
@@ -91,7 +91,7 @@ For the domain-specific meaning of fields — how automations chain, what a funn
91
91
 
92
92
  Many tasks are multi-step and have a required ordering the app normally enforces. The most important rule: **automations live inside flows — always find a flow (`listAutomationFlows`) or create one (`createAutomationFlow`) before adding automations; never create an orphan automation.** The same "resolve the parent/ids first, then act" shape recurs across campaigns, funnels, and offers.
93
93
 
94
- For the ordered steps and domain rules of each common workflow, read `references/workflows.md`. It covers what's **fully doable** — creating/cloning a campaign, authoring automations end-to-end (create/edit/delete/simulate, with the trigger, condition, send-time, and chaining rules that make a flow professional), editing funnel screens (the draft → preview → promote loop), creating offers, and exploring users — and what's **not yet exposed** — members-program reward creation, brand identity, and replying to guests by SMS. Don't fabricate a call for a workflow whose tools aren't listed by `feast tools`; tell the user that part isn't available yet.
94
+ For the ordered steps and domain rules of each common workflow, read `references/workflows.md`. It covers what's **fully doable** — creating/cloning a campaign, authoring automations end-to-end (draft-first: stage edits on a draft, dry-run them with `simulateAutomations`, hand the user the preview link, then promote), editing funnel screens (the draft → preview → promote loop, including staging brand-new screens), reading and saving the wallet pass configuration (full-document save — read, modify, save the whole thing), listing/creating members-program rewards, creating offers, and exploring users — and what's **not yet exposed** — reward update/delete, pass image generation, brand identity, and replying to guests by SMS. Don't fabricate a call for a workflow whose tools aren't listed by `feast tools`; tell the user that part isn't available yet.
95
95
 
96
96
  ## Link to what you touched
97
97
 
@@ -33,6 +33,19 @@ Settings tabs: `account`, `general`, `members`, `integrations`, `notifications`,
33
33
 
34
34
  Funnels are always edited inside a panel, never on a page of their own — a campaign's `funnel-v2` panel, or the members program's `funnel` panel.
35
35
 
36
+ ### Automation previews
37
+
38
+ These two hang off the **root**, not off `/<organizationId>/app` — the organization id is the first path segment:
39
+
40
+ ```
41
+ https://feastalytics.com/automation-preview/<organizationId>/<flowId>
42
+ https://feastalytics.com/automation-preview/<organizationId>/<flowId>?draftId=<draftId>
43
+ ```
44
+
45
+ Without `draftId` it dry-runs the live flow as a text-message thread. With one, the same page diffs the draft's staged changes against live — added messages tinted, removed struck through, edited showing the old copy above the new — which is the link to hand someone before you promote.
46
+
47
+ A `flowId` contains `:` and `;` and **must be percent-encoded** in the path. Easier: `createAutomationDraft` and `stageAutomationEdits` both return `previewUrls`, already built and encoded, one per flow the draft touches. Use those rather than assembling your own.
48
+
36
49
  ## Public pages
37
50
 
38
51
  The guest-facing site lives on the organization's own subdomain, `https://<subdomain>.feastalytics.com`:
@@ -39,18 +39,26 @@ The one-shot text→campaign endpoints (`createWithOffer` / `parseCampaignDescri
39
39
  - A **flow** groups automations by a shared trigger, and belongs to *either* a campaign *or* the members program — never both.
40
40
  - **The rule that matters most: every automation needs a `flowId`. `batchEditAutomations` throws on a create op without one.** So you must resolve the flow *before* creating. Never invent a flowId.
41
41
 
42
- ### The CLI loop (simpler than the app — no navigate/stage/save split)
42
+ ### The CLI loop: draft → stage → share → save
43
43
 
44
- Unlike the in-app agent (which scaffolds an automation, then edits it, then explicitly saves), the CLI sends a **complete** automation in one operation and it persists immediately.
44
+ Automations have a staging tier, and it is the default path. Changes accumulate on a **draft** — an off-prod overlay — until someone explicitly promotes them. A draft carries a link that renders the change as a text-message thread with the edits highlighted, which is what you hand a human to look at before anything reaches a real guest.
45
45
 
46
46
  1. `listAutomationFlows` — find an existing flow. Pass `{ "campaignId": "<id>" }` for a campaign's flows, or `{ "scope": "membersProgram" }` for members-program flows. Reuse a matching flow when one fits.
47
47
  2. If none fits, `createAutomationFlow` to make one. If the campaign/members-program has **no flows at all**, strongly prefer `applyAutomationTemplate` (then customize) over building from scratch. Only apply a template when there are no existing flows.
48
48
  3. `listAutomations` with `{ "flowId": "<id>" }` to see the automations already in that flow before editing (omit the input to list every automation in the org).
49
- 4. `batchEditAutomations` with a list of `operations`:
50
- - `{ "type": "create", "automation": { ...full automation..., "flowId": "<id>" } }` — generate a fresh UUID for the automation's id, set the `flowId`, and include triggers, conditions, actions, send time, and a descriptive title all at once. The server validates it and (create ops) requires the flowId.
49
+ 4. `createAutomationDraft` with a short `title` describing the change in the user's terms ("Shorten the day-3 nudge") — that title is what the reviewer sees. Keep the returned `draftId`; **there is no way to list drafts, so if you lose it the draft is unreachable.**
50
+ 5. `stageAutomationEdits` with `{ "draftId": "<id>", "operations": [...] }`. The ops are exactly the ones `batchEditAutomations` takes:
51
+ - `{ "type": "create", "automation": { ...full automation..., "flowId": "<id>" } }` — generate a fresh UUID for the automation's id, set the `flowId`, and include triggers, conditions, actions, send time, and a descriptive title all at once. Create ops require the flowId.
51
52
  - `{ "type": "update", "automationId": "<id>", "automation": { ...changed fields... } }`
52
- - `{ "type": "delete", "automationId": "<id>" }` — blocked if the automation already has sends.
53
- 5. `simulateAutomations` — dry-run the flow against a synthetic event timeline with **no real sends**, to confirm the right automations fire before or after you save. It can also preview un-saved `edits` before you commit them.
53
+ - `{ "type": "delete", "automationId": "<id>" }` — blocked at save time if the automation already has sends.
54
+ Call it repeatedly to build a change up; ops append in order.
55
+ 6. `simulateAutomations` with `{ "flowId": "<id>", "edits": <the draft's operations> }` — dry-run against a synthetic event timeline with **no real sends** and confirm the right automations fire. If the simulation surprises you, stage a correction rather than promoting and patching live.
56
+ 7. **Give the user the `previewUrls` from the draft** and let them look before you promote. Each entry is one flow's before/after view. Don't promote unprompted work on the user's behalf — staging exists so a human sees the change first.
57
+ 8. `saveAutomationEdits` with `{ "draftId": "<id>" }` — this is the write to production. It refuses if any automation the draft touches was changed by someone else since you staged, naming which; re-stage against the current state rather than retrying.
58
+
59
+ `discardAutomationDraft` throws a draft away without promoting. `getAutomationDraft` re-reads one by id. Drafts expire after 14 days.
60
+
61
+ **`batchEditAutomations` still exists and writes straight to production in one call.** Reach for it only when the user explicitly wants an immediate live change and has said so — not as a shortcut past the review step.
54
62
 
55
63
  `updateAutomationFlow` renames/retitles a flow; `deleteAutomationFlow` removes a flow and its automations (blocked at ≥20 sends — turn it off instead).
56
64
 
@@ -142,8 +150,19 @@ Every offer picks one **framework**:
142
150
  The retention counterpart to campaigns — flows with no `campaignId`.
143
151
 
144
152
  - **Automations are authorable** (see the automations workflow): use `listAutomationFlows` with `{ "scope": "membersProgram" }`, then the same create/edit loop. Remember the members-program 30-day `awardReward` default.
145
- - **Creating members-program rewards themselves is NOT exposed.** Reward creation in the app writes a catalog item + reward link through generic object-query mutations with no dedicated tool, and orchestrates catalog-item-create-or-reuse plus awarding-automation scaffolding client-side. There's no tagged `createReward`. If asked, tell the user this needs the app (or a new endpoint).
146
- - **Pass builder** (wallet pass design) is not exposed to the CLI.
153
+ - **Rewards are now readable and creatable.** `listMembersProgramRewards` returns every reward with its catalog `name`, `staffInstructions`, and `pointsCost` (fields are `null` when unset). `createMembersProgramReward` takes `{ "name", "staffInstructions"?, "pointsCost"? }` and does the catalog-item dance for you: an existing catalog item with that exact name is reused (updating its `staffInstructions` if you passed any), otherwise one is created, then the reward row is linked to it.
154
+ - **The `pointsCost` fork matters.** A reward with `pointsCost` set is redeemed *by the member with points* and is never auto-awarded. Omit `pointsCost` for automation-awarded rewards — and then actually pair the reward with an `awardReward` automation (see the automations workflow), or it will never reach anyone. `listMembersProgramRewards` deliberately has no `hasAutomation` flag: cross-reference `listAutomations` for `awardReward` actions carrying the reward's `itemId` to find orphans.
155
+ - Reward **update/delete are not exposed** yet — those still need the app.
156
+
157
+ ---
158
+
159
+ ## Wallet pass configuration
160
+
161
+ The pass (the wallet membership card) is now CLI-readable and -writable as a whole document.
162
+
163
+ - **`readPassConfiguration`** `{}` — returns the latest live configuration: `sections`, `features`, `locations`, `metadata`, and its `version`.
164
+ - **`savePassConfiguration`** — **a full-document save, not a patch.** Anything you omit is dropped from the new version. The only safe workflow is read → modify the returned document → save the complete result. Saving appends a new version (history is preserved server-side), and a visible change triggers a re-push of the pass to every member's wallet — so this confirms before running and deserves the same care as a live send.
165
+ - Pass **image generation** (punch-card strips etc.) is not exposed — image workflows still need the app.
147
166
 
148
167
  ---
149
168
 
@@ -160,7 +179,7 @@ The retention counterpart to campaigns — flows with no `campaignId`.
160
179
 
161
180
  **Applying a funnel template** expands a whole screen tree server-side in one call: `chooseFunnelTemplate` (needs the campaign's funnel unset — a fresh campaign — and resolves the referrer from the campaign). `deleteFunnel` tears one down.
162
181
 
163
- **Editing individual funnel screens is now CLI-drivable** through a **draft → preview → promote** loop. You never apply edits locally: you stage them on an off-prod draft, preview the result at a stable URL, then save. Tools: `listFunnelScreens`, `createFunnelDraft`, `stageFunnelEdit`, `getFunnelDraft`, `listFunnelDrafts`, `discardFunnelDraft`, `saveFunnelEdits`.
182
+ **Editing individual funnel screens is now CLI-drivable** through a **draft → preview → promote** loop. You never apply edits locally: you stage them on an off-prod draft, preview the result at a stable URL, then save. Tools: `listFunnelScreens`, `createFunnelDraft`, `stageFunnelEdit`, `stageFunnelScreen`, `getFunnelDraft`, `listFunnelDrafts`, `discardFunnelDraft`, `saveFunnelEdits`.
164
183
 
165
184
  ### The loop
166
185
 
@@ -170,6 +189,7 @@ The retention counterpart to campaigns — flows with no `campaignId`.
170
189
  - `{ "type": "update", "id": "<renderableId>", "renderable": { ...clone of what you read, with your changes... } }` — keep the same `id`.
171
190
  - `{ "type": "create", "renderable": { "id": "<new-uuid>", ... }, "targetId": "<sibling id>", "position": "before" | "after" | "inside" }` — generate a fresh UUID.
172
191
  - `{ "type": "delete", "id": "<renderableId>" }` and `{ "type": "move", "id": "...", "targetId": "...", "position": "..." }`.
192
+ **Need a brand-new screen?** `stageFunnelScreen` `{ "draftId": "...", "title": "...", "description"? }` stages an empty screen on the draft and returns its **permanent `screenId`** — the id is assigned at staging time, not at save, so you can immediately `stageFunnelEdit` content into it and reference it from navigation/buttons on other screens; nothing gets re-keyed at promote. On a campaign draft the screen is campaign-scoped unless you pass `"campaignScoped": false`. The screen only exists on the draft (and in draft-scoped `listFunnelScreens`/previews) until `saveFunnelEdits` promotes it, which reports it in `createdScreenIds`.
173
193
  4. **Preview** (no CLI call): open `https://{referrer}.feastalytics.com/preview/{draftId}/{campaignId}` (drop `/{campaignId}` for a members-program draft). It renders the whole funnel as a flow diagram with the draft's edits applied. Screenshot it, then iterate — re-run `listFunnelScreens` **with the `draftId`** to read the funnel *with* the staged edits, stage more, re-preview — until it's right.
174
194
  5. **`saveFunnelEdits`** `{ "draftId": "..." }` — **promotes to prod** (mutation, confirms first): applies the draft's edits to the live funnel and marks the draft `promoted`. To abandon instead, `discardFunnelDraft`.
175
195
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feastalytics/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Command-line client for the Feastalytics platform — list, create, and update campaigns, automations, offers, and members-program rewards from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {