Skip to content

feat: add anonymous CLI telemetry via PostHog#123

Merged
felipefreitag merged 20 commits intomainfrom
feat-telemetry
Mar 20, 2026
Merged

feat: add anonymous CLI telemetry via PostHog#123
felipefreitag merged 20 commits intomainfrom
feat-telemetry

Conversation

@felipefreitag
Copy link
Contributor

Fire-and-forget usage tracking (command name, OS, arch, CLI version). No PII collected.
Opt out with DO_NOT_TRACK=1 or RESEND_TELEMETRY_DISABLED=1.
Anonymous ID stored at ~/.config/resend/telemetry-id.

if (full.startsWith('brew')) {
return 'homebrew';
}
return 'install-script';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want an event for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a property on the event, not a separate event. The goal is to understand the distribution channel split (npm vs homebrew vs install script). It's a nice-to-have.

@felipefreitag felipefreitag marked this pull request as ready for review March 19, 2026 14:01
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 issues found across 4 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/cli.ts">

<violation number="1" location="src/cli.ts:164">
P2: Exclude the internal `telemetry flush` subprocess from the post-command update check. Right now every tracked command triggers a second `checkForUpdates()` run in the telemetry child.</violation>
</file>

<file name="tests/lib/telemetry.test.ts">

<violation number="1" location="tests/lib/telemetry.test.ts:158">
P2: Don't hardcode `macOS` here; this test will fail on Linux and Windows runners.</violation>

<violation number="2" location="tests/lib/telemetry.test.ts:159">
P2: This assertion codifies the missing `arch` field instead of testing the telemetry contract.</violation>
</file>

<file name="src/lib/telemetry.ts">

<violation number="1" location="src/lib/telemetry.ts:76">
P2: Don't print the telemetry notice during JSON/non-interactive runs; the first invocation currently writes to stderr in machine mode.</violation>

<violation number="2" location="src/lib/telemetry.ts:102">
P2: This argv construction breaks telemetry flushing for native binary installs because `process.argv[1]` is the user's command there, not a script path.</violation>

<violation number="3" location="src/lib/telemetry.ts:124">
P1: Validate the flush path before deleting it; this hidden command currently unlinks any readable file path the caller supplies.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 7 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/build.mjs">

<violation number="1" location="scripts/build.mjs:10">
P2: The custom `.env` loader keeps surrounding quotes, so quoted `POSTHOG_PUBLIC_KEY` values are embedded incorrectly and telemetry requests use an invalid API key.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/test-telemetry-windows.yml">

<violation number="1" location=".github/workflows/test-telemetry-windows.yml:3">
P2: This workflow is effectively branch-locked to `feat-telemetry`, so telemetry CI checks won't run for normal PRs/mainline after this branch lifecycle ends.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/test-telemetry-windows.yml">

<violation number="1" location=".github/workflows/test-telemetry-windows.yml:37">
P2: The test only fails when telemetry files remain, but it never asserts that a telemetry temp file was created. If telemetry doesn’t write a file at all, `remaining` stays 0 and the step still passes, masking regressions. Add a creation check before the consumption check.</violation>
</file>

<file name="src/lib/telemetry.ts">

<violation number="1" location="src/lib/telemetry.ts:65">
P2: The notice marker is written even when `interactive` is false, so a first non-interactive run suppresses the notice permanently. If the intent is to only skip output in non-interactive mode, the marker should only be written when the notice is actually shown.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/test-telemetry-windows.yml">

<violation number="1" location=".github/workflows/test-telemetry-windows.yml:54">
P1: `fi` is invalid in this PowerShell script and will break the workflow step. Close the `if` block with `}` instead.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Fire-and-forget usage tracking (command name, OS, arch, CLI version).
No PII collected. Opt out with DO_NOT_TRACK=1 or RESEND_TELEMETRY_DISABLED=1.
Anonymous ID stored at ~/.config/resend/telemetry-id.
Single boolean: isInteractive() && !opts.json
Covers TTY, CI, piped, and --json/--quiet cases.
Spawn `resend telemetry flush <payload>` as a detached child process
instead of calling fetch() inline, which either blocks exit or never
completes. The child process POSTs to PostHog independently, adding
no latency to the parent CLI command.
- Pass payload via temp file instead of CLI arg to avoid ps visibility
- Validate JSON in flushPayload before sending
- Use Commander public API for hidden command instead of _hidden
- Skip tracking when no command was matched (bare `resend` invocation)
- Replace os/arch with friendly os name (macOS, Windows, Linux)
- Change detectInstallMethodName fallback to 'other'
Replace hardcoded API key with process.env.POSTHOG_PUBLIC_KEY, injected
at bundle time through a build script using esbuild's define option.
The key is sourced from .env (local) or env vars (CI). Telemetry
silently no-ops when the key is absent.

A verify-bundle script in prepack ensures the key is present before
publishing. A preflight job in the release workflow catches missing
secrets early.
Record which flags users pass (names only, never values) to understand
feature usage and interactive-vs-explicit preference. Uses Commander's
getOptionValueSource to capture only CLI-provided flags, split into
command-specific `flags` and program-level `global_flags` arrays.
pkg-compiled binaries fail to spawn themselves without clearing
PKG_EXECPATH. Also adds .env-based build-time key injection,
flag tracking, and removes debug logging.
- Skip telemetry child from update check and re-tracking
- Suppress first-run notice in non-interactive/JSON mode
- Validate flush path is in tmpdir with expected naming pattern
- Remove stale arch assertion from tests
- Skip telemetry child from update check and re-tracking
- Suppress first-run notice in non-interactive/JSON mode
- Validate flush path is in tmpdir with expected naming pattern
- Add full spawn test for Windows CI
@felipefreitag felipefreitag merged commit 1aa0f16 into main Mar 20, 2026
6 checks passed
@felipefreitag felipefreitag deleted the feat-telemetry branch March 20, 2026 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants