feat(cli): choose-a-plan wording for direct-offer orgs without a trial

Closed
RI
2d ago
+346-17

Summary

Follow-up to #3782 (direct offer, no free trial). That PR creates direct-offer orgs with stripe_info.trial_at equal to the creation time and updates the console copy. The CLI still told these users "You need to upgrade your plan" when the plan check blocked them. This PR switches them to the console's wording and leaves every other user's output unchanged.

Detection. This uses the same rule as the console's isZeroLengthTrial: an org counts as direct offer when its trial ends within 24h of its creation. The CLI now checks plans through private/cli/preflight, which does not return trial dates. So the lookup runs only after a command has been blocked. It makes one call to the existing private/onboarding_progress with includeBilling: true and reads billing.orgCreatedAt (added in #3782) and billing.trialEndsAt. The call uses N: 4 without initial, so none of the periodic onboarding checks run.

Any error, the 5s timeout, billing.status: 'unavailable', an older server without the field, or orgCreatedAt: null keeps today's copy. Paying orgs and orgs in an active trial never make the extra call.

New code:

  • cli/src/shared/direct-offer.ts: the pure rule and copy.
  • cli/src/api/direct-offer.ts: isDirectOfferApp, the network lookup.
  • Wired into cli/src/api/preflight.ts and cli/src/build/request.ts.

Strings changed (direct-offer orgs only)

WhereBeforeAfter
bundle upload and bundle unlink (preflight plan_upgrade_required; init shows the upload failure)You need to upgrade your plan to continue to use capgo. / Upgrade here: <plans url>Choose a plan to start using Capgo. 14-day money-back guarantee. Cancel anytime. / Choose a plan here: <plans url>
Thrown errorPlan upgrade required / Plan upgrade required for uploadPlan required / Plan required for upload
build request and build start, 429 need_plan_upgradeCannot request native build, upgrade plan to continue to build: <url>Choose a plan to start using Capgo. 14-day money-back guarantee. Cancel anytime. Choose a plan here: <url>
Setup-complete footer (setup-notices.ts), from billing.orgCreatedAtYour trial has ended. / Choose a Capgo plan to continue using Capgo.Choose a plan to start using Capgo. 14-day money-back guarantee. Cancel anytime. (no trial line)

The Plans URL and the browser-open behavior are unchanged. Active-trial, expired-trial and paying orgs see exactly what they see today.

Depends on #3782 for orgCreatedAt. Until #3782 is deployed, direct-offer orgs see today's copy; nothing breaks.

Test plan

  • New cli/test/test-direct-offer-plan.mjs, run as part of test:plan-validation, 16 tests with mocked HTTP:
    • isZeroLengthTrial edge cases.
    • isDirectOfferApp: request shape, orgCreatedAt null or missing, billing unavailable, 403, missing app id.
    • checkPlanValidUpload and checkPlanValid for direct-offer, expired-trial, active-trial and paying orgs. Direct-offer output never matches /trial|upgrade/i. Active-trial and paying orgs make only the preflight call.
    • throwIfBuildPlanLimitError for direct-offer, expired-trial and concurrency-limit errors; the concurrency error makes no lookup.
  • cli/test/test-setup-notices.mjs: three new cases: direct offer, orgCreatedAt: null, and a 15-day trial.
  • bun run typecheck, bun run lint, bun run build, test:setup-notices (40/40), test:plan-validation (7 + 16), test:mcp and test:bundle all pass.

Screenshots

bundle upload blocked for a direct-offer org. The output comes from checkPlanValidUpload running against a stubbed preflight and onboarding-progress response.

Before (origin/main)

before

After (this PR)

after

๐Ÿค– Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added tailored plan guidance for organizations without a free trial.
    • Updated plan-limit and preflight messages to distinguish direct-offer billing from standard trial or upgrade scenarios.
    • Preserved existing trial messaging for organizations with active or expired trials.
  • Bug Fixes

    • Improved handling of missing, invalid, unavailable, or timed-out billing information by falling back to standard behavior.
  • Tests

    • Added coverage for direct-offer detection, plan messaging, build limits, uploads, usage checks, and trial scenarios.