Skip to content

feat(posthog): delegate SDK install to @posthog/wizard#129

Merged
CarmenDou merged 2 commits into
mainfrom
feat/posthog-wizard-refactor
May 15, 2026
Merged

feat(posthog): delegate SDK install to @posthog/wizard#129
CarmenDou merged 2 commits into
mainfrom
feat/posthog-wizard-refactor

Conversation

@CarmenDou
Copy link
Copy Markdown
Contributor

@CarmenDou CarmenDou commented May 15, 2026

Summary by CodeRabbit

  • New Features

    • PostHog setup now uses a two-phase flow: establishing a dashboard connection followed by the official PostHog wizard for SDK integration.
  • Chores

    • Simplified PostHog setup command interface and removed built-in framework/package detection and template management in favor of delegating to the PostHog wizard.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Walkthrough

The PostHog setup command is refactored to remove framework detection, package installation, and embedded template file generation. The new flow ensures a dashboard connection exists, then delegates SDK integration to the official PostHog wizard launched via npx @posthog/wizard@latest.

Changes

PostHog Setup Command Refactor

Layer / File(s) Summary
CLI command contract and result shape
src/commands/posthog/setup.ts
CLI options for framework selection and package installation are removed. The SetupResult interface now returns dashboardConnection and wizardExitCode instead of framework, install status, and file-writing details.
Two-phase setup flow implementation
src/commands/posthog/setup.ts
runSetup validates the linked project and token, ensures a PostHog dashboard connection via startPosthogCliFlow and fetchPosthogConnection, then spawns the official wizard with spawnSync and error handling for launch failures and non-zero exit codes.
Dashboard connection messaging and spinner updates
src/commands/posthog/setup.ts
Spinner text and connection flow messages are updated to consistently say "InsForge dashboard connection" instead of prior project-level wording.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • InsForge/CLI#95: Both PRs refactor the same PostHog CLI setup flow by changing src/commands/posthog/setup.ts and the shared PostHog API helpers in src/lib/api/posthog.ts (including the startPosthogCliFlow/pollPosthogConnection usage and credential-fetching logic).

Suggested reviewers

  • jwfing

Poem

🐰 The wizard arrives with a flourish and spell,
Framework detection? We bid thee farewell!
Dashboard connected, the setup flows free,
npx handles SDK integration with glee!
One PhilosophyRabbit celebrates the new way,
Simpler, cleaner, a refactoring day! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: delegating PostHog SDK installation to the @posthog/wizard tool instead of handling it directly.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/posthog-wizard-refactor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 15, 2026

Greptile Summary

This PR replaces all custom PostHog SDK installation logic (framework detection, package manager utilities, code templates) with a two-step delegation flow: (1) ensure the InsForge dashboard has a PostHog connection via cli-start / OAuth polling, then (2) spawn npx @posthog/wizard@latest to handle SDK installation and app-code wiring.

  • SetupResult shape is updated — framework, installedSdk, filesWritten, and envWritten are replaced by dashboardConnection and wizardExitCode/wizardSkipped/wizardCommand.
  • JSON mode now skips the interactive wizard entirely and surfaces the command for the caller to run under a real TTY.
  • Deleted: src/lib/framework-detect.ts, src/lib/package-manager.ts, src/templates/posthog/**, src/types/text-imports.d.ts, and the corresponding tests.

Confidence Score: 5/5

Safe to merge — the production code is well-structured and the previously raised interactive-stdio and version-drift concerns have been addressed.

The refactor correctly delegates all SDK installation to the official wizard. The two-step flow is cleanly separated, SIGINT cancellation is handled gracefully, and JSON mode avoids blocking on the interactive wizard. The one test-quality issue in the --json mode case is cosmetic and does not affect production behaviour.

src/commands/posthog/setup.test.ts — the --json mode test contains a dead first runSetup call that silently fails; otherwise no files require special attention.

Important Files Changed

Filename Overview
src/commands/posthog/setup.ts Core refactor: replaces framework/install/template logic with spawnSync of @posthog/wizard; JSON mode correctly skips the wizard and returns wizardCommand; SIGINT/exit-130 handled as graceful cancellation.
src/commands/posthog/setup.test.ts New tests cover the happy path, error, SIGINT, ENOENT, and JSON-mode flows; the --json mode test contains a redundant first runSetup call that silently fails due to a missing spawnSyncMock setup.
src/lib/api/posthog.ts Removes fetchPosthogCliCredentials and PosthogCliCredentials; remaining API surface is unchanged.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant CLI as insforge posthog setup
    participant API as InsForge API
    participant W as @posthog/wizard (npx)

    U->>CLI: insforge posthog setup
    CLI->>API: startPosthogCliFlow(projectId)
    alt already connected
        API-->>CLI: "{ type: connected }"
        CLI->>API: fetchPosthogConnection(projectId)
        API-->>CLI: "{ kind: connected, connection }"
        CLI-->>U: PostHog already connected
    else not yet connected
        API-->>CLI: "{ type: authorize, authorizeUrl }"
        CLI-->>U: Print / open authorizeUrl
        loop Poll every 2s (max 15 min)
            CLI->>API: pollPosthogConnection
            API-->>CLI: connected?
        end
        CLI-->>U: Connection received
    end
    alt --json mode
        CLI-->>U: "JSON { wizardSkipped: true, wizardCommand }"
    else interactive mode
        CLI->>W: "spawnSync npx -y @posthog/wizard@latest"
        W-->>U: Interactive TUI
        W-->>CLI: exit code
        alt exit 0
            CLI-->>U: Done.
        else exit 130 / SIGINT
            CLI-->>U: Setup cancelled.
        else other non-zero
            CLI-->>U: CLIError
        end
    end
Loading

Reviews (2): Last reviewed commit: "fix(posthog): address review (json-mode ..." | Re-trigger Greptile

Comment thread src/commands/posthog/setup.ts Outdated
Comment thread src/commands/posthog/setup.ts Outdated
Copy link
Copy Markdown
Member

@jwfing jwfing left a comment

Choose a reason for hiding this comment

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

Summary

Good scope reduction overall — delegating SDK wiring to @posthog/wizard removes a lot of fragile framework-specific code, and the two-step flow is clearly explained. However, two blocking issues need to be addressed before this merges.

Requirements context

No matching spec/plan found under docs/specs/ (the three existing specs are for the diagnose command and db-migrations). Assessment is based on the PR description and body alone.


Findings

Critical

Software Engineering — No tests for new behavior

src/commands/posthog/setup.ts is the core of this PR (70 lines added, replacing 429), yet no test file is added or updated for it. The deleted framework-detect.test.ts is correctly removed alongside its subject, but the new two-step flow has zero coverage:

  • ensureDashboardConnection — two code paths (already-connected fast path with sanity-fetch vs. OAuth + poll), each testable by mocking startPosthogCliFlow / fetchPosthogConnection / pollPosthogConnection.
  • Wizard error handling — the wizardResult.error branch and the exitCode !== 0 branch.
  • --json flag interactions.

The insforge-development skill (this project's own TDD convention) is explicit: "Every new behavior has at least one test. Every bug fix has a regression test." No tests = does not meet the merge bar.

Functionality — JSON mode is non-functional (setup.ts:100-111)

const wizardResult = spawnSync('npx', ['-y', '@posthog/wizard@latest'], {
  stdio: opts.json ? 'pipe' : 'inherit',   // <-- problem
  env: process.env,
});

@posthog/wizard is an interactive tool: it prompts for PostHog project selection and OAuth. With stdio: 'pipe', the wizard's stdin is a closed/empty pipe — any read blocks indefinitely or gets EOF immediately, causing the wizard to exit non-zero. That triggers the exitCode !== 0 branch and a CLIError, so outputJson({ success: true, ...result }) never runs. insforge posthog setup --json will always fail.

The options to fix this are:

  1. Run the wizard unconditionally with stdio: 'inherit' (dropping --json support for this command, which is documented as a behavioral change anyway), or
  2. Document that --json only covers the dashboard-connection step and skip the wizard in JSON mode (returning early after ensureDashboardConnection), or
  3. Use async spawn and stream wizard output to process.stdout/stderr while still capturing the exit code.

Suggestion

Performance — spawnSync blocks the event loop for the full wizard duration (setup.ts:100)

spawnSync is synchronous and holds the V8 event loop until the wizard exits — which involves OAuth round-trips and package installation, potentially 5+ minutes. Signal handlers registered on the parent process (SIGTERM, SIGINT) won't fire during this time in the expected way.

The repo's established pattern for long-running subprocesses is async spawn wrapped in a Promise (see src/lib/flyctl.ts:112). Using async spawn with stdio: 'inherit' achieves the same TTY-passthrough behavior without blocking.

Functionality — Exit code 130 treated as a hard error (setup.ts:108-110)

if (exitCode !== 0) {
  throw new CLIError(`PostHog wizard exited with code ${exitCode}.`);
}

If the user presses Ctrl+C inside the wizard, it exits with code 130 (SIGINT). The current code surfaces this as "PostHog wizard exited with code 130" — a confusing error for an intentional cancellation. Consider special-casing 130 (and signal === 'SIGINT' on the spawnSync result) to print a friendlier "Setup cancelled." message and exit cleanly.


Information

Design — runConnectFlow return value is silently discarded (setup.ts:148)

await runConnectFlow(projectId, token, startResult.authorizeUrl, opts);
return 'newly-connected';

runConnectFlow returns Promise<PosthogConnectionResponse> but the result is unused. This is harmless — the connection object is no longer needed — but the return type is now misleading. Consider changing runConnectFlow to return Promise<void> to signal intent clearly.

Security — @posthog/wizard@latest is unpinned

The command always downloads and executes the current @posthog/wizard@latest at runtime. This is a deliberate design choice (wizard manages its own upgrades) and acceptable for delegating to a first-party tool, but worth acknowledging: if PostHog's npm account were compromised, any published @latest would run in the user's environment with their full filesystem access. Pinning to a minor range (e.g. @posthog/wizard@^0) rather than @latest would limit blast radius from a hypothetical supply-chain incident.


Verdict

request_changes — two Critical findings (missing tests for new behavior; JSON mode always fails). Suggestion items can be addressed in a follow-up if preferred, but the Critical items must be resolved before merge.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/commands/posthog/setup.ts (1)

93-97: ⚡ Quick win

Warn users to select the same PostHog project in the wizard.

The comment above runSetup() already notes that the dashboard OAuth and wizard OAuth can land on different PostHog projects, but the user-facing copy never says that. If the wizard is completed against a different project, setup still reports success while the app sends data somewhere the InsForge dashboard is not watching.

Suggested copy
   if (!opts.json) {
     outputInfo('Running the official PostHog setup wizard to wire PostHog into your app...');
+    outputInfo(
+      pc.yellow('In the wizard, choose the same PostHog project you connected to the InsForge dashboard.'),
+    );
     outputInfo(
       pc.dim('(it will open a browser for OAuth and let you pick a PostHog project)'),
     );
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/posthog/setup.ts` around lines 93 - 97, The user-facing wizard
messaging does not warn that the OAuth browser flow must target the same PostHog
project as the dashboard, so update the pre-wizard output in setup.ts (the
outputInfo calls before runSetup()) to include a clear warning that users must
select the same PostHog project in the OAuth wizard as their InsForge dashboard;
change the copy emitted before invoking runSetup() to explicitly tell users to
pick the same project (and optionally how to verify it) so successful setup
won’t point telemetry to a different PostHog project.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/commands/posthog/setup.ts`:
- Around line 100-103: The current spawnSync call that invokes '@posthog/wizard'
in the posthog setup (the wizardResult / spawnSync invocation in setup.ts) uses
stdio: opts.json ? 'pipe' : 'inherit', which breaks the wizard's interactive
OAuth flow when opts.json is true; update the invocation so that when opts.json
is true you either add the '--ci' flag to the arguments (i.e., spawn
'@posthog/wizard' with ['-y','@posthog/wizard@latest','--ci'] for
non-interactive mode) or detect opts.json and fail fast with a clear error
message indicating JSON mode is incompatible with the interactive wizard (so
callers can switch to CI mode or not use --json); ensure you reference opts.json
and the spawnSync call/wizardResult when making the change.
- Around line 100-103: The spawnSync call that runs 'npx' (the wizardResult =
spawnSync('npx', ...) in src/commands/posthog/setup.ts) is not Windows-safe;
update the spawnSync options to run via a shell (e.g., add shell: true to the
options object) so Windows can resolve npx.cmd (alternatively invoke cmd.exe /c
or use exec), and keep existing stdio/env handling (preserve opts.json logic) so
the child runs correctly on all platforms.

---

Nitpick comments:
In `@src/commands/posthog/setup.ts`:
- Around line 93-97: The user-facing wizard messaging does not warn that the
OAuth browser flow must target the same PostHog project as the dashboard, so
update the pre-wizard output in setup.ts (the outputInfo calls before
runSetup()) to include a clear warning that users must select the same PostHog
project in the OAuth wizard as their InsForge dashboard; change the copy emitted
before invoking runSetup() to explicitly tell users to pick the same project
(and optionally how to verify it) so successful setup won’t point telemetry to a
different PostHog project.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3c7aacbc-2b88-4e46-9098-81cb01b9edd5

📥 Commits

Reviewing files that changed from the base of the PR and between 2981811 and 62d8486.

📒 Files selected for processing (13)
  • src/commands/posthog/setup.ts
  • src/lib/api/posthog.ts
  • src/lib/framework-detect.test.ts
  • src/lib/framework-detect.ts
  • src/lib/package-manager.ts
  • src/templates/posthog/astro/posthog-init.ts.txt
  • src/templates/posthog/index.ts
  • src/templates/posthog/next-app/layout-snippet.tsx.txt
  • src/templates/posthog/next-app/posthog-provider.tsx.txt
  • src/templates/posthog/next-pages/_app.tsx.txt
  • src/templates/posthog/sveltekit/hooks.client.ts.txt
  • src/templates/posthog/vite-react/main-snippet.tsx.txt
  • src/types/text-imports.d.ts
💤 Files with no reviewable changes (12)
  • src/templates/posthog/next-app/layout-snippet.tsx.txt
  • src/templates/posthog/next-app/posthog-provider.tsx.txt
  • src/lib/framework-detect.ts
  • src/templates/posthog/vite-react/main-snippet.tsx.txt
  • src/templates/posthog/sveltekit/hooks.client.ts.txt
  • src/templates/posthog/index.ts
  • src/templates/posthog/next-pages/_app.tsx.txt
  • src/templates/posthog/astro/posthog-init.ts.txt
  • src/lib/framework-detect.test.ts
  • src/types/text-imports.d.ts
  • src/lib/api/posthog.ts
  • src/lib/package-manager.ts

Comment thread src/commands/posthog/setup.ts Outdated
Copy link
Copy Markdown

@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 13 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/commands/posthog/setup.ts">

<violation number="1" location="src/commands/posthog/setup.ts:100">
P1: Use a Windows-safe command when launching the wizard (`npx.cmd` on win32, or `cmd /c`) to avoid `ENOENT` failures on Windows.</violation>

<violation number="2" location="src/commands/posthog/setup.ts:101">
P2: Using `stdio: 'pipe'` in JSON mode breaks the wizard’s interactive flow; `@posthog/wizard` expects terminal interaction in normal mode.</violation>
</file>

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

Comment thread src/commands/posthog/setup.ts Outdated
Comment thread src/commands/posthog/setup.ts Outdated
Copy link
Copy Markdown
Member

@jwfing jwfing left a comment

Choose a reason for hiding this comment

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

Summary

Clean, well-scoped refactor that correctly delegates SDK wiring to @posthog/wizard while keeping the InsForge dashboard connection step; the code is leaner and the tests cover the main flows.

Requirements context

No /docs/superpowers/ directory exists in this repo — assessing against the PR description and code intent alone.

Findings

Critical

(none)

Suggestion

[Software Engineering — Test quality] JSON mode test has an unintentional first-run failure
src/commands/posthog/setup.test.ts:234-263

The 'skips wizard, emits JSON with wizardCommand' test calls await runSetup(['--skip-browser']) before the JSON-mode run, but never configures spawnSyncMock. After beforeEach's mockReset(), spawnSyncMock() returns undefined, so wizardResult.error throws a TypeError, handleError calls process.exit(1), and the first run silently fails. spawnSyncMock.mockClear() then hides the evidence before the real assertion. The final assertions still validate the correct behaviour, but the first call is dead weight and may confuse future maintainers.

Fix: either add spawnSyncMock.mockReturnValue(spawnOk()) before the first call, or simply drop the first runSetup call entirely — the API mocks set at lines 236–242 remain configured for the second (JSON-mode) invocation without it.


[Functionality — Error message accuracy] forbidden from the sanity-check fetchPosthogConnection reports "not-connected"
src/commands/posthog/setup.ts:167-173

When startPosthogCliFlow returns { type: 'connected' } but the subsequent fetchPosthogConnection sanity-check returns { kind: 'forbidden' }, the code throws:

'cli-start reported connected, but /connection returned not-connected. Try again, or check the dashboard.'

A permissions error is not the same as not-connected — the user will be confused about why retrying would help. Worth handling kind === 'forbidden' distinctly with a message pointing at project access, consistent with how pollPosthogConnection handles it (exit code 5, explicit forbidden message at posthog.ts:181).


[Functionality — Result accuracy] SIGINT-via-signal reports wizardExitCode: 1 instead of 130
src/commands/posthog/setup.ts:128-138

const exitCode = wizardResult.status ?? 1;
if (wizardResult.signal === 'SIGINT' || exitCode === 130) { ... }

When the wizard is killed by SIGINT (Node sets status: null, signal: 'SIGINT'), exitCode resolves to 1 via the ?? 1 fallback. The resulting SetupResult then carries wizardExitCode: 1, even though the conventional exit code for SIGINT is 130. Consumers that inspect wizardExitCode to distinguish cancellation from a real wizard failure will misread this. Consider const exitCode = wizardResult.signal === 'SIGINT' ? 130 : (wizardResult.status ?? 1).

Information

env: process.env in spawnSync is redundant
src/commands/posthog/setup.ts:120-123

spawnSync inherits process.env by default when env is omitted; passing it explicitly has no effect. Safe to drop.

Verdict

approved (informational — no Critical findings; human approval via the approve flow is still required)

Three Suggestion-level items worth addressing before merge, but none are blocking. The JSON mode test issue is the most important to fix — it should either configure spawnSyncMock or remove the redundant first runSetup call so the test reads cleanly.

Copy link
Copy Markdown
Member

@jwfing jwfing left a comment

Choose a reason for hiding this comment

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

LGTM, approved.

@CarmenDou CarmenDou merged commit 82dac53 into main May 15, 2026
4 checks passed
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.

2 participants