feat(cli): choose-a-plan wording for direct-offer orgs without a trial
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.tsandcli/src/build/request.ts.
Strings changed (direct-offer orgs only)
| Where | Before | After |
|---|---|---|
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 error | Plan upgrade required / Plan upgrade required for upload | Plan required / Plan required for upload |
build request and build start, 429 need_plan_upgrade | Cannot 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.orgCreatedAt | Your 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 oftest:plan-validation, 16 tests with mocked HTTP:isZeroLengthTrialedge cases.isDirectOfferApp: request shape,orgCreatedAtnull or missing, billing unavailable, 403, missing app id.checkPlanValidUploadandcheckPlanValidfor 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.throwIfBuildPlanLimitErrorfor 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:mcpandtest:bundleall 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)

After (this PR)

๐ค 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.