@drip-apex/apex-cli 0.19.0 → 0.20.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/AGENTS.md CHANGED
@@ -89,7 +89,8 @@ the first writes: `apex experiments create`, `apex goals create`,
89
89
  - Edit experiment files, variation code, metrics, and targeting only through supported paths.
90
90
  - Do not bypass the variation artifact persistence path with direct API writes.
91
91
  - Keep generated evidence outside `qa.json`; attach it through QA commands.
92
- - Author commerce drafts in `commerce/price.json`, `commerce/shipping.json`, `commerce/offer.json`, or `commerce/post-purchase.json`; never edit their `serverOwned` sections.
92
+ - Author commerce drafts in `commerce/price.json`, `commerce/shipping.json`, `commerce/offer.json`, `commerce/discount-codes.json`, or `commerce/post-purchase.json`; never edit their `serverOwned` sections.
93
+ - Checkout messages use `{ "action": "checkoutBlock", "checkoutBlock": { "heading": "Free returns for 30 days" } }`: one per A/B arm, flat mutations only (`variations/<slug>/mutations.json` or workspace `src/mutations.json`), never URL blocks or a test with post-purchase. Money copy is refused. Run each message arm's QA checkout from its `apex preview <id> <variation-id>` link or the dashboard, then launch in the dashboard.
93
94
 
94
95
  ## Project code
95
96
 
package/README.md CHANGED
@@ -1,4 +1,46 @@
1
- # Apex CLI
1
+ # Apex CLI: run A/B tests on your online shop from the terminal or an AI coding agent
2
+
3
+ Apex by DRIP is an A/B testing platform for online shops that predicts which tests will win before they go live, built on one of the largest A/B test databases in e-commerce.
4
+
5
+ This package is the `apex` command line. Developers and AI coding agents (Claude Code, Codex, Cursor) use it to build and run Apex A/B tests as code: list tests and read results, pull a test into local files, edit the variation, review a plan and apply it, open preview links for QA, check tracking, and push goals, targeting and feature flags from a config file. Launching a test to live traffic happens in the Apex app.
6
+
7
+ - Website: https://www.drip-apex.com
8
+ - Docs: https://docs.drip-apex.com
9
+ - CLI install and sign-in: https://docs.drip-apex.com/docs/cli/install-auth
10
+ - Command reference: https://docs.drip-apex.com/docs/cli/commands-output
11
+
12
+ Want Apex inside ChatGPT, Claude or Cursor without a terminal? Connect the hosted MCP server at `https://app.drip-apex.com/api/mcp` (OAuth). Setup: https://docs.drip-apex.com/docs/mcp/install-configure and the [`@drip-apex/mcp-server`](https://www.npmjs.com/package/@drip-apex/mcp-server) package.
13
+
14
+ ## Quick start
15
+
16
+ ```bash
17
+ npm install -g @drip-apex/apex-cli
18
+ apex login
19
+ apex experiments list
20
+ ```
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ npm install -g @drip-apex/apex-cli
26
+ ```
27
+
28
+ Install the CLI once, then call `apex` directly. `apex --help` and `apex schema --json` answer without network access. Do not run `npx @drip-apex/apex-cli@latest` for every command: npx asks the npm registry for the package before the CLI starts, so it prints nothing and hangs when the registry is slow or blocked, which is common in agent sandboxes. Update with `npm install -g @drip-apex/apex-cli@latest`.
29
+
30
+ ## Authenticate
31
+
32
+ ```bash
33
+ apex login
34
+ apex whoami
35
+ ```
36
+
37
+ `apex login` opens the default browser OAuth flow at Apex `/cli/login`. For
38
+ headless environments, use an existing API key:
39
+
40
+ ```bash
41
+ apex login --api-key apx_your_key_here
42
+ APEX_API_KEY=apx_your_key_here apex experiments list --json
43
+ ```
2
44
 
3
45
  ## Choosing a workflow
4
46
 
@@ -50,32 +92,6 @@ change the stored login. Use `apex login --api-key apx_uk_...` for a headless
50
92
  account login or `apex login --api-key apx_...` to store a shop key. The old
51
93
  `apex login --user` spelling is a deprecated alias for `apex login`.
52
94
 
53
- Command-line tools for Apex experiments, draft workspaces, GitOps pushes, QA
54
- evidence, tracking checks, and agent handoffs.
55
-
56
- ## Install
57
-
58
- ```bash
59
- npm install -g @drip-apex/apex-cli
60
- ```
61
-
62
- Install the CLI once, then call `apex` directly. `apex --help` and `apex schema --json` answer without network access. Do not run `npx @drip-apex/apex-cli@latest` for every command: npx asks the npm registry for the package before the CLI starts, so it prints nothing and hangs when the registry is slow or blocked, which is common in agent sandboxes. Update with `npm install -g @drip-apex/apex-cli@latest`.
63
-
64
- ## Authenticate
65
-
66
- ```bash
67
- apex login
68
- apex whoami
69
- ```
70
-
71
- `apex login` opens the default browser OAuth flow at Apex `/cli/login`. For
72
- headless environments, use an existing API key:
73
-
74
- ```bash
75
- apex login --api-key apx_your_key_here
76
- APEX_API_KEY=apx_your_key_here apex experiments list --json
77
- ```
78
-
79
95
  ## Common usage
80
96
 
81
97
  ```bash
@@ -204,6 +220,8 @@ including every subcommand, argument, option, and alias.
204
220
  - `apex workspace` — check out, preview, and publish draft workspace files.
205
221
  - `apex goals` — manage conversion and revenue goals. Create/update accept `--page-id <id>` (UUID only, no lookup) or `--page <id-or-key>` (keys need `pages:read` for lookup); use one option.
206
222
  - `apex flags` — manage feature flags.
223
+ - `apex forms` — track storefront forms and read form and checkout analytics: list, add, remove,
224
+ summary, fields, field, errors, sessions, label, merge, unmerge and detect. Needs the shop's form analytics switch.
207
225
  - `apex surveys` — list, get, create, update, start, pause, complete, duplicate, and delete surveys.
208
226
  Use `apex surveys list --status live` to filter, and `apex surveys create @survey.json`
209
227
  or `apex surveys update <id> <body>` with inline JSON, `@file`, or a file path.
@@ -279,6 +297,18 @@ command inventory:
279
297
  | `apex admin shops settings get --shop <uuid-or-domain> --key <key>` | Read one setting; unknown keys list the available registry keys. |
280
298
  | `apex admin shops settings set --shop <uuid-or-domain> --key <key> --value <value>` | Resolve and pin the shop, then make an audited write. Booleans accept on/off/true/false; numbers must be finite; null clears nullable settings. Sensitive writes require `--confirm`; optional `--reason` and `--expected-version` preserve audit context and concurrency. |
281
299
 
300
+ ## Consent setup warnings
301
+
302
+ `apex consent get`, `set`, and `off` include setup warnings in JSON output and print
303
+ them on stderr in human output. Custom consent without a getter waits for the site
304
+ to call `Drip.setConsent(true)`. A configured consent provider with consent mode off
305
+ does not gate tracking or storage.
306
+
307
+ `apex shops doctor` runs `unbound_hosts`, `dev_pollution`, `cmp_mismatch`,
308
+ `consent_gate`, `stale_served_config`, `goal_reachability`, `consent_rate`, and
309
+ `purchase_capture`, in that order. `consent_gate` warns about consent setup, passes
310
+ when the API returns no warnings, and skips older servers without warning support.
311
+
282
312
  ## Landing pages built outside Apex
283
313
 
284
314
  A landing page is built in a checkout folder by any tool (Claude Code, Codex,
@@ -323,7 +353,7 @@ folder belongs to `apex experiments pull/plan/apply`, `landing-page.json` means
323
353
  an `apex landing-pages` checkout, while `session.json`
324
354
  means it is an `apex workspace checkout/status/publish` workspace. Keep the two
325
355
  formats in different folders; when the wrong command is run, Apex points to the
326
- matching status command.
356
+ matching status command. In a workspace folder, a checkout message goes in `src/mutations.json`.
327
357
 
328
358
  ## Page targeting: URL rules and Pages
329
359
 
@@ -360,6 +390,39 @@ In a pulled `targeting.json`, `url` is the expanded rule set and `authorUrl` is
360
390
  the authored subset, always present. Edit `url` and `pages`; treat `authorUrl`
361
391
  and `pageRules` as output.
362
392
 
393
+ ## Checkout messages
394
+
395
+ A checkout message adds text to the Apex block in Shopify checkout, as a typed change on an A/B test arm. Add `[{ "action": "checkoutBlock", "checkoutBlock": { "heading": "Free returns for 30 days", "body": "Not the right fit? Send it back for free.", "tone": "info" } }]` to the arm's flat mutations.
396
+
397
+ The required `heading` is trimmed and must contain visible text in 1–120 characters. Optional `eyebrow`, `body` and `disclosure` allow up to 60, 500 and 300 characters. `tone` defaults to `info`; it also accepts `success`, `warning` or `critical`. `placement` accepts only `checkout`, the default. Unknown keys are refused at both levels. Omit deprecated `enabled`; `false` hides the message.
398
+
399
+ Use at most one message per arm (`duplicate_checkout_block`), in `variations/<slug>/mutations.json` for a pulled experiment or `src/mutations.json` for a workspace folder, never `url-blocks.json`. Messages cannot share a test with `commerce/post-purchase.json`, and personalizations refuse them. Omit `surface` and `checkoutBlock` from `targeting.json`; those retired keys return `409 checkout_mode_retired`.
400
+
401
+ Copy cannot state a money amount: a number next to a currency symbol, ISO code or currency word, or a percent next to a discount word such as off, save, sale or Rabatt. Apply returns `422 checkout_copy_states_money` (CLI exit 3). A plain percent only warns at launch.
402
+
403
+ Pause a running test before changing its message, run its QA checkout again, then resume. On paused or running tests, adding the first message to a test with no storefront change or removing the last message is refused (`checkout_exposure_owner_frozen`).
404
+
405
+ Messages may share an arm with DOM mutations, CSS, JS and commerce levers other than post-purchase. Combined tests count visitors on the storefront and show their storefront change only while Apex can confirm the message is live at checkout. Tests whose arms change only messages count visitors at checkout and show messages only to buyers who allow analytics, marketing and sale-of-data processing; QA testers must grant that consent too. Apex recommends a revenue primary goal for these tests. Control may carry a message, but it does not count as treatment work.
406
+
407
+ From nothing to a saved draft:
408
+
409
+ 1. Run `apex login`, then `apex use <org>/<shop>`. Alternatively set `APEX_API_KEY` with `DRIP_ORG`/`DRIP_SHOP` or pass `--org`/`--shop`. With only `APEX_API_KEY`, `apex use` cannot persist context; a shop-scoped key needs no selection.
410
+ 2. Run `apex experiments create --name "Checkout message" --page-url <url> --yes --json` and read `.data.experiment.id`. A fresh draft has `control` and `variation-b` arms.
411
+ 3. Run `apex experiments pull <id> --out <folder> --json`.
412
+ 4. Put the entry above in `<folder>/variations/variation-b/mutations.json`; leave `variations/control/mutations.json` as `[]`.
413
+ 5. Run `apex experiments plan <folder> --json`. Blocking issues return exit 3; plan lists the rules above except apply-only refusals.
414
+ 6. Run `apex experiments apply <folder> --json`. If the test already holds QA approval, add `--accept-qa-invalidation`; without it, exit 4 requests confirmation.
415
+ 7. Apply stores the entry with `"placement": "checkout"` added; run `apex experiments apply <folder> --sync` so the folder matches the stored bytes. `apex experiments status <folder> --json` shows the QA checklist and file state, not launch blockers; the Apex dashboard shows those. The CLI validates file names; the server validates contents. `apex schema --json` prints the contract offline.
416
+
417
+ Before launch:
418
+
419
+ - Use Shopify Plus (development stores with "development" or "plus" in their plan name also pass), with the Apex app connected.
420
+ - Ask your Apex contact at Drip for the Checkout extension tests add-on and to switch on checkout tests for the store. The Apex team sets both.
421
+ - Add the Apex Checkout Experiment block in the Shopify checkout editor, normally at the information step. Apex cannot see placement directly; an unplaced block appears as a missing QA checkout. If the store offers Shop Pay, turn on "Include block in Shop Pay" for the block.
422
+ - Use production or the store's active environment and keep the store's checkout messages within Shopify's size budget.
423
+ - Open each message arm's QA link in a real checkout: `apex preview <id> <variation-id> --json --no-open` prints a signed link (treat it as a secret), or use "Preview links" in the experiment's Check panel. Add a product, go to checkout, allow analytics, marketing and sale-of-data processing if the store asks, and wait for the message. The receipt must match the current message text and test epoch. A customer approval link does not count.
424
+ - Mark QA done and launch in the dashboard. API and CLI launch are unavailable. Apex confirms delivery after launch and pauses the test if it cannot confirm the message within 30 minutes.
425
+
363
426
  ## Push config format
364
427
 
365
428
  Run `apex push -c <config>` to load a JavaScript or TypeScript config. The
@@ -452,12 +515,13 @@ experiments reject these metadata changes.
452
515
 
453
516
  Experiment references accept an ID, slug, or test key (for example `BIO-085`). Test keys resolve within the selected shop; use `--shop <shop-id>` to change it. Bare lowercase references remain slugs.
454
517
 
455
- Price, shipping, offer, and post-purchase drafts use typed `commerce/<kind>.json` files. Each file defines the lever once and maps every variation to values or `sameAsControl`; its `serverOwned` section is informational and read-only.
518
+ Price, shipping, offer, discount-code, and post-purchase drafts use typed `commerce/price.json`, `commerce/shipping.json`, `commerce/offer.json`, `commerce/discount-codes.json`, and `commerce/post-purchase.json` files. Each file defines the lever once and maps every variation to values or `sameAsControl`; its `serverOwned` section is informational and read-only. A checkout message cannot share a test with `commerce/post-purchase.json`.
456
519
 
457
520
  Filesystem apply preserves authored local bytes by default. Use
458
521
  `apex experiments apply <folder> --sync` to refresh them from stored server bytes.
459
- The receipt's `files` contains SHA-256 digests for every pull path; `synced` reports
522
+ The receipt's `files` includes per-file `normalizations` and `submitted_sha256` (null for unsubmitted files), alongside SHA-256 digests for every stored pull path; `synced` reports
460
523
  whether a full refresh succeeded. Server-owned QA and launch files are healed.
524
+ JSON bodies and checkout JSON files accept a leading UTF-8 BOM, including PowerShell-written files.
461
525
  Create/get return `dashboard_url`; apply returns `dashboardUrl`. These links
462
526
  switch the signed-in dashboard user's active shop before opening the experiment.
463
527
 
@@ -644,6 +708,37 @@ store ID (or null), invitation results and partial delivery status.
644
708
 
645
709
  Upload CSV or JSON exports with `apex results import --file results.csv --dry-run`. Apex suggests column and outcome-value mappings from the file; use repeated `--map 'Column=field'` and `--outcome-value 'Source value=won|lost|inconclusive'` overrides, then pass `--yes` for non-interactive confirmation. Files are inspected and previewed before any rows are written. `--source <name>` applies to the confirmed rows; the preview shows the uploaded file name.
646
710
 
711
+ ### Read past test results
712
+
713
+ `apex results list [--source import|native|all] [--limit <n>] [--all] [--json]` lists past results for the selected shop (default source `all`, page size 50, maximum 200). Use `--all` to follow every page. The table shows legacy ID (or UUID), title, outcome, metric, lift, sample size, dates, and source. Empty lists print `No test results.`
714
+
715
+ `apex results get <legacy-id-or-id> [--json]` opens a result by legacy ID, test key, or UUID, including its full learning, confidence, dates, page, and device. Missing results exit with code 1 through the existing API failure path. Both commands use shop or user keys with `experiments:read` and verify each row belongs to the selected shop. Imports show their source name and original date range, falling back to import time; native results show source `apex` and creation time.
716
+
717
+ `apex results delete <legacy-id-or-id> [--yes] [--json]` permanently removes one imported result with `experiments:write`. It first reads the result and, outside `--json`, prints its title, outcome, dates, source, and legacy ID; with `--json --yes` it removes without printing a preview, so check the ID first (for example with `apex results get`). Native results are refused locally (exit 3). Confirm the prompt or pass `--yes`; non-TTY callers without `--yes` receive exit 4 with the exact rerun hint. Removed results cannot be restored in Apex; the full record remains in the audit log. JSON output wraps the API `{ data }` response and verifies the echoed shop.
718
+
719
+ JSON uses the standard CLI envelope: its `data` contains `{ data, pagination }` for lists (merged rows and final pagination with `--all`) or `{ data: result }` for a single result. Invalid `--source` or `--limit` exits 3 before an HTTP request.
720
+
647
721
  ### Tracking health
648
722
 
649
723
  `apex tracking health [--json]` reads one tracking-health report for the current shop: every check with pass, warn, fail or unknown, a plain summary and the deciding numbers, plus each running test's first-hour verdict and traffic split overall and per device (`--json` carries visitors per arm per day). Exit code 0 is pass, 1 is warn or fail, 3 is unknown.
724
+
725
+ ### Forms
726
+
727
+ `apex forms list` lists tracked forms and their collection status. Add a storefront form with
728
+ `apex forms add newsletter --url https://shop.example/newsletter --selector '#newsletter' --complete-on-call`.
729
+ Choose exactly one of `--complete-on-goal <goal>`, `--complete-on-page <path>`, or `--complete-on-call`.
730
+ `apex forms remove <key>` soft-removes it. Checkout is tracked automatically on Shopify.
731
+
732
+ Read analytics with `apex forms summary <key>`, `apex forms fields <key>`,
733
+ `apex forms field <key> <identity>`, `apex forms errors <key>`, or `apex forms sessions <key>`.
734
+ Reads accept `--range`, `--split`, `--device`, `--country`, `--include-qa`, and `--include-removed`.
735
+ Sessions also accept `--outcome all|completed|abandoned|in_progress`, `--field`, `--with-replay`, `--limit`, and `--cursor`.
736
+ Fields, errors, and sessions accept `--format csv|json|table`. Every command accepts `--json`.
737
+ Unavailable values print `–` (empty in CSV); `*` marks a denominator below 50.
738
+
739
+ `apex forms label <key> <identity> <text>` attaches a label; `apex forms label <key> <identity> --clear` clears it.
740
+ `apex forms merge <key> <old> <new>` combines an old identity with its replacement;
741
+ `apex forms unmerge <key> <identity>` undoes it. `apex forms detect <url>` scans a shop page without returning values.
742
+ `apex tracking manifest [manifest]` includes the shop's form definitions in a schemaVersion 1 manifest.
743
+
744
+ Flag goals: `apex flags create --key banner --name "Banner" --goal <uuid> --goal <uuid> --primary-goal <uuid>`. The same options work on `flags update <id>`; `--goal` replaces the attached set. `flags get <id>` prints goals and marks the primary goal. JSON input can clear the set with `{"goal_ids":[]}`.