Repository navigation
Conversation
Move the YYYY-MM-DD day and the inclusive day-range rule to sdk/core/dates.ts, the --date-from/--date-to flags to cli/input/period.ts and the dimension=value[,value] parser to cli/input/filter.ts, so a second product (the Developer API analytics) can take them without importing sdk/attribution. Attribution behavior is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new topic with eight commands: catalog, values, and one data command per operation (chart, conversion, funnel, retention, ltv, cohort). Each data command prints a human view, the API answer unchanged (--json), or a CSV made from it (--csv): one row per segment, the total first, a null value as an empty cell. The human view keeps the total first, prints null as — and an empty window as "No data for this period." Bad input exits 2 before any request and names the flag: the app id, the dates, the chart and conversion ids, a compared period with both ends (chart and conversion only), --renewal-days only with --period-type days, --csv with --json. A server refusal exits 4 with its error code; no token exits 3. The sdk resource lives in sdk/adapty/analytics, one file per operation; the views in cli/views/analytics. Docs: docs/agent/analytics.md, the skill and its command reference, README, CLAUDE.md and docs/architecture.md; the agent docs check now covers the analytics topic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… local revenue-basis rule - --filter of the analytics commands sends values exactly as written; an empty value is a value, so --filter country= keeps the "No Data" group as the dashboard does. Attribution keeps its parser (trimmed, empty refused). - The human view and the CSV read their fields from the answer, so every field the API gives is shown: nested objects as dotted names, list items by index; the CSV has a column per point field (<point>.<field>). This carries the new funnel step fields, the cohort money on three bases and predict sections, and the typed resolved query. - --revenue-basis with a chart that is not about money exits 2 before any request. - A success that is not the API envelope exits 4 with malformed_response. - Tests: one table over the six commands, human and CSV; the fetch step helpers move to test/helpers; unused re-exports leave the doors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…input - An answer without segments still shows every number of the period: the human view prints "No data for this period." and under it the summary (data fields, time zone, other meta fields such as recommended_period, null as —). The CSV gets one summary row per period (column row = summary) after the segment rows, so it keeps its header and invents no group row. - cli/input keeps only what attribution and analytics share: the date parser, a day-range flag factory that takes the time-zone text, and the split of dimension=value[,value]. The attribution period flags and filter parser move to base/attribution/flags.ts, the exact analytics filter parser to base/adapty/flags.ts. Attribution behavior is unchanged. - One naming rule: AnalyticsCatalog; the analytics flag helpers drop the analytics prefix. Test helpers are function declarations; the no-token test asserts the literal message instead of repeating a date case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The CSV has one row per group and the total first. A compared period is in
compare.* columns of the same row (a group of one period only has empty
cells in the other); the numbers of the whole answer (data.value,
data.compare.value, meta.query.timezone, meta.recommended_period, ...)
are in columns of every row under their JSON paths. No groups: stdout has
the header line only, stderr "No data for this period." and the summary.
- The --csv help says how to tell the total (is_total, empty key) from a
"No Data" group (key "").
- The human view and the CSV show the step number x of funnel steps and
retention periods ("-2 Install").
- One helper turns groupBy and granularity into segmentation and
period_unit for all six operations; conversion counts and the funnel value
follow the API types (null where the backend has no number).
- The sdk rule message names no CLI flag; exports used only in their file
are private; imports sorted; the exit-2 test asserts whole messages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…umns, local renewal-days rule
- Carry the backend change: each catalog grouping names its filter (the
filter key that takes its group keys, or null); the catalog human view
shows it, and the docs say how to drill down (--filter <filter>=<key>).
LTV cohort_size can be null.
- The CSV names each point column by x alone, the same for every segment; a
step's title is a cell of its own (<x>.title). The human view prints the
step number once ("2 Period", "-2 Install").
- --renewal-days must be whole days in ascending order, each once: refused
with exit 2 before any request. An sdk message names another field as
{fieldName} and the CLI writes the flag ("needs --period-type days").
- The CSV notice on stderr comes whenever the asked period has no segments,
with the summary of each period.
- The six data commands print through one AnalyticsCommand.renderAnswer;
the report --filter parser is back in its command.
- Tests: sdk table tests for the rules and the request; a conversion with a
compared period; an asked period without groups beside a compared one;
list messages asserted by the flag and a sample.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The drill-down docs and the segment key comment follow the backend: use
the grouping's filter from the catalog of that operation or chart (null:
no drill-down; period goes to renewal_period); the "No Data" key is the
zero UUID for id groupings, no_offer for offer type and category,
Uncategorized for duration, "" for other text groupings; no filter
selects it for store_product_id, flow_screen_id and period; a comma inside
a --filter value is written \,.
- Finished before the scope change: an sdk issue lists the fields its
message names ({fieldName}) and only those are rewritten to flags; the
compare messages name the other flag; the views read every field of
meta.query from one source; the six data commands render with a view
function and write the CSV notice to stderr (no base class); compare and
grouping flags are mapped once; sdk table tests per source module;
README says a 403 exits 3; the architecture doc lists every analytics file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…chart and conversion names The human view of the six data commands is a short table: one row per group, the total first, money at 2 decimals, null as a dash. --json and --csv do not change. The CLI no longer keeps local lists of chart and conversion ids: which names exist is the backend's knowledge (docs/architecture.md); the API refuses a bad name (exit 4).
- The catalog no longer names a filter for a grouping: the type has no `filter`, and the human view lists the grouping keys only. - A group `key` is the raw value that the backend gives, not a filter value: docs, skill reference, README, model and flag texts say so; the drill-down section and the "No Data" filter values are gone. `--filter` is unchanged (values exactly as written, an empty one too, `\,` for a comma). - The total is found by `is_total` alone. A group with a null, "" or "None" key is a group of its own in the table and the CSV (one row, paired with its compared segment by the exact key). - Tests: a table and CSV test with null, "" and "None" keys listed before the total; the funnel "No Data" group has the raw key null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A funnel group key is its title and can repeat. The CSV matched groups by raw key and kept only the last one. A key that is unique in both periods is still matched by itself; a repeated key is matched by position. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat:
adapty analytics, the analytics of an app from the Developer API. Spec: adaptyteam/headless-workbench#26.Summary
A new topic
adapty analyticsreads the analytics of one app as the dashboard shows them, with the same developer token as the rest of the CLI: one login reads every app the token can access. All commands are read-only and take--app.analytics catalog--appanalytics values--app,--dimensionanalytics chart--app,--chart,--date-from,--date-to--compare-from/--compare-to,--group-by,--filter(repeatable),--granularity,--revenue-basis(money charts),--timezone,--csvanalytics conversion--app,--conversion,--date-from,--date-to--compare-from/--compare-to,--group-by,--filter,--granularity,--timezone,--csvanalytics funnel--app,--date-from,--date-to--group-by,--filter,--timezone,--csvanalytics retention--app,--date-from,--date-to--group-by,--filter,--use-trial,--timezone,--csvanalytics ltv--app,--date-from,--date-to--group-by,--filter,--revenue-basis,--period-type,--renewal-days,--timezone,--csvanalytics cohort--app,--date-from,--date-to--filter,--granularity,--revenue-basis,--period-type,--renewal-days,--timezone,--csvNames and flags follow the
attributioncommands. Onlychartandconversiontake a compared period.Outputs. Every data command answers in one shape:
data.value(the number of the period),data.segmentswith the total first (keynull), then one segment per group, andmeta.query(the query that ran, with defaults and the time zone).nullprints as—; a compared period has its own table; an empty window printsNo data for this period.and the summary;--json: the API answer unchanged;--csv: a table the CLI makes from that answer: one row per group, total first; a compared period incompare.*columns on the same row;--csvwith--jsonis refused.The CSV reads its fields from the answer, so a field the API adds later shows without a CLI change. Where the table leaves fields out, one line under it says that
--jsonand--csvgive every field.The CLI keeps no list of chart or conversion names: which names exist is the server's knowledge (
docs/architecture.md).analytics cataloglists them, and the API refuses an unknown name.Group keys. A group
keyis the raw value that the API gives for the group. It is not promised to be a--filtervalue (a funnel groupkeyis its title and can repeat; every group stays in the output, matched by position). Take filter values fromanalytics values. The total is found only byis_total, never by a nullkey. Details:docs/agent/analytics.md.Exit codes.
--renewal-dayswithout--period-type days(whole days, ascending, once),--filterwithout=,--csvwith--json. The message names the flag.adapty auth login."; also a 403 (no access to the app)--revenue-basison a chart that is not about money; 429 withretry_after_secondsin--json; a success that is not the API envelope:malformed_response)Also: the date rule, the day-range flag factory and the
dimension=valuesplitting are now shared insrc/cli/input/andsrc/sdk/core/; each product keeps its own--filterparser (attribution behavior unchanged, its tests pass); docs (docs/agent/analytics.md, the skill,cli-commands.md, README, architecture),check-agent-docsfor the new topic; version 0.10.0.Evidence
adapty analyticsdoes not exist.test/commands/analytics.test.tsandtest/sdk/adapty/analytics/*.test.ts:pnpm build,pnpm check:agent-docsandpnpm test(with lint) pass: 805 tests.Verification
The commands were run against the backend change on a test stand: the catalog, an empty window (
No data for this period.),--json/--csv/ human output for each data command, the local refusals and the exit codes. Results: see the evidence bundle in the spec issue adaptyteam/headless-workbench#26.The last two commits (no drill-down, a group
keyis the raw backend value; every group kept when a key repeats in one period) were run on the stand: the checks for the catalog, empty windows, the three outputs, local refusals and exit codes pass, and a wrong chart or conversion name exits 4 with the API code.Merge Danger
Door: two-way in code, one-way after a release
New commands only; attribution behavior is unchanged. Once 0.10.0 is published, the command names, flags, CSV columns and exit codes are a public interface that agents and scripts use.
Blast Radius: small
New topic. The shared input code touches the
attribution reportflags (same behavior, tests updated).Owners: CODEOWNERS gives the new
analyticspaths to the default owners @mlnchk @gshteynardt.package.jsonandskills/adapty-cli/references/cli-commands.mdhave no owner.Order: release after the Developer API analytics routes are live; until then the commands get 404.
Open points for the reviewer
--timezoneis not checked locally: the API refuses it (exit 4).