Repository navigation
feat(cli): track which registry items add installs - #3099
Conversation
`cli_command` records that `add` ran and nothing about what it installed, and the registry is served from raw.githubusercontent.com, which gives no per-item counter either — so there is no way to tell which block or component people actually pull, and no way to know what is worth building more of. Emit one `registry_item_added` event per item written into a project, from `runAdd` after the install succeeds. That is the single choke point: the bulk `add <tag>` path re-enters it per item, and a failed or compatibility-refused install throws before it, so a refused install is never counted as a download. `requested` separates the item the user named from the transitive `registryDependencies` pulled in behind it; without it a popular dependency outranks everything that depends on it. Item names are public registry identifiers, never user content or project data, and the event goes through `trackEvent` — an install that opted out via `hyperframes telemetry disable`, `HYPERFRAMES_NO_TELEMETRY` or `DO_NOT_TRACK` sends nothing.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
Closing the gap the test plan admitted: the event is now proven end to end through the built CLI, not just at the emit seam. Running from source could never show this — Single item — {"item":"code-snippet-visual-studio-dark","item_type":"hyperframes:block","requested":true}Bulk tag — This is the case I most wanted to see, since the tag path re-enters Opt-out — same command with Unknown item — the run that kicked this off was One honest gap this surfaced: no registry item currently declares |
The unit tests assert the emit seam and nothing past it. `shouldTrack()` short-circuits whenever `isDevMode()` is true, and that is true for any `.ts` entry, so under vitest a real event and no event are indistinguishable and the transport is never exercised at all. Drive the built CLI instead and assert on the HTTP body it actually produces: one event per installed item, the dependency reported with `requested: false`, an opted-out install sending no request at all (not merely one without this event), and a refused install counting nothing. Two fixtures, because neither case is reachable through the real registry. The registry origin is a first-class project setting, so a local one supplies the `registryDependencies` edge that no shipped catalog item declares today; and `globalThis.fetch` is wrapped to capture the batch rather than send it. The faked 200 is load-bearing: only a failed flush leaves events queued, and only a non-empty queue spawns the detached `flushSync` child that would bypass the hook and reach production analytics. Verified the check can fail — forcing `requested: true` for every item turns it red on exactly the dependency assertion.
|
Pushed
It closes the gap I flagged earlier. The The opt-out assertions are on zero batches, not zero matching events: an opted-out install must make no request at all, not a request that happens to omit this one event. Nothing reaches PostHog. And the check can actually fail. Forcing Reverted and green again. |
What
Emits one
registry_item_addedevent per registry itemhyperframes addwrites into a project, so the catalog can be ranked by what people actually install.Why
cli_commandrecords thataddran and nothing about what it installed:And the registry is served from
raw.githubusercontent.com, so there is no server-side counter either. The result is that "which block or component is most installed" is unanswerable today — which also means there is no signal for what is worth building more of, or what is dead weight in a 50+ item catalog.How
The event is emitted from
runAdd, immediately afterinstallAllreturns. That is the single choke point for an item reaching a project:add <tag>path re-entersrunAddonce per item rather than installing separately, so tag installs are covered without a second call site.requesteddistinguishes the item the user named from the transitiveregistryDependenciespulled in behind it. Collapsing the two would rank a popular dependency above everything that depends on it, which inverts exactly the question the event exists to answer.Properties are
item,item_type,requested.Privacy
Item names are public registry identifiers — never project names, paths, or file content. The event goes through
trackEvent, which returns early unlessshouldTrack(), so an install that opted out viahyperframes telemetry disable,HYPERFRAMES_NO_TELEMETRY, orDO_NOT_TRACKsends nothing. No new opt-out surface, and none needed. Thetelemetrydocs section is updated to name what is now collected.Test plan
Two assertions in
add.test.ts, both against the emitted payload rather than the transport (shouldTrack()is already false under test, so a real call and no call are indistinguishable):dep-block, which depends onbase-component, emits both, withrequestedtrue only for the item that was asked for.packages/clisuite green (315 tests across add + telemetry).Verified end to end through the built CLI, with
globalThis.fetchwrapped to capture the PostHog batch instead of sending it. Running from source proves nothing here:isDevMode()is true for a.tsentry, soshouldTrack()short-circuits and a real call looks exactly like no call. Faking a 200 in the hook keeps it off production analytics, since only a failed flush leaves events queued for the detachedflushSyncchild that would bypass it.add code-snippet-visual-studio-darkemitted{"item":"code-snippet-visual-studio-dark","item_type":"hyperframes:block","requested":true}.add captionsinstalled 16/16 and emitted exactly 16 events, one per item,item_typecorrect across 15 components and 1 block. This is the case worth seeing, since the tag path re-entersrunAddper item instead of having its own call site.HYPERFRAMES_NO_TELEMETRY=1andDO_NOT_TRACK=1: zero batches captured, not merely zeroregistry_item_added— no HTTP request at all.Not covered: no registry item declares
registryDependenciestoday (grep -rl registryDependencies registry/is empty), sorequested: falsecannot be exercised against the real registry and rests on the fixture-based unit test. Worth watching that the first item to take a dependency produces the expected split.Also here:
runinadd.tscarries a barefallow-ignore-next-line complexity. It is 28 cyclomatic, predates this change, and is untouched by it — Fallow scores it as new only because the file changed. Splitting its tag-fallback branch into a helper would fix it honestly, and is worth a follow-up, but not inside a telemetry change.