feat(trial): auto-prompt for Seer trial + sentry trial list/start commands#399
feat(trial): auto-prompt for Seer trial + sentry trial list/start commands#399
Conversation
When `issue explain` or `issue plan` fails with a 402 (no budget) or
403 (not enabled) error in an interactive terminal, the CLI now checks
if the org has an available Seer product trial. If one exists, it
prompts the user to start a free trial and retries the command on
success.
The flow mirrors the existing `executeWithAutoAuth` pattern: a new
`executeWithSeerTrialPrompt` middleware wraps `runCommand` and catches
`SeerError`. Errors that aren't trial-eligible (`ai_disabled`, missing
org slug, non-TTY) pass through unchanged.
Key behaviors:
- Checks `GET /customers/{org}/` for unstarted seerUsers trial
(falls back to seerAutofix for legacy orgs)
- Starts trial via `PUT /customers/{org}/product-trial/`
- API failures during trial check degrade gracefully (show original error)
- consola prompt cancel handled with strict equality check
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨Init
Issue List
Other
Bug Fixes 🐛Init
Other
Internal Changes 🔧Init
Other
Other
🤖 This preview updates automatically when you update the PR. |
Codecov Results 📊✅ 104 passed | Total: 104 | Pass Rate: 100% | Execution Time: 0ms 📊 Comparison with Base Branch
✨ No test changes detected All tests are passing successfully. ✅ Patch coverage is 100.00%. Project has 916 uncovered lines. Files with missing lines (2)
Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
+ Coverage 95.49% 95.59% +0.1%
==========================================
Files 142 147 +5
Lines 20352 20755 +403
Branches 0 0 —
==========================================
+ Hits 19435 19839 +404
- Misses 917 916 -1
- Partials 0 0 —Generated by Codecov Action |
- Add standalone trial commands: sentry trial list, sentry trial start - Rename getSeerTrialStatus → getProductTrials (returns ProductTrial[]) - Rename startSeerTrial → startProductTrial (generic category param) - Add src/lib/trials.ts with trial name mapping and status helpers - Add swap detection for trial start args (org/name order) - Update SeerError messages to hint at trial commands - Refactor seer-trial.ts to use shared trial infrastructure - Fix getTrialDisplayName bug: add getDisplayNameForTrialName for CLI names - Add comprehensive tests (80 tests across 5 files)
The xn-- prefix is interpreted as IDN encoding by URL parsers, causing invalid URLs when used as subdomain slugs (e.g., xn--a.sentry.io). This was a pre-existing flaky test failure.
- Use getControlSiloUrl() for /customers/ endpoints (control silo, not region-scoped) - Replace stderr.write() with consola logger in seer-trial.ts - Move instanceof SeerError check into isTrialEligible() (accepts unknown) - Fix timezone bug: use setUTCHours in getTrialStatus() - Soften unconditional trial hint wording in SeerError.format() - Update seer-trial tests for new API (logger mocks, 2-arg signature)
- Add support@sentry.io mention when trial start fails - Simplify no-op conditional type to plain ReturnType<>
|
Addressed all review feedback in b17c30b and df55458. Summary of changes:
All 87 trial-related tests pass, typecheck and lint clean. |
Change test assertion to check for 'support@sentry' substring instead of 'support@sentry.io' to avoid triggering CodeQL's 'Incomplete URL substring sanitization' rule (code-scanning/43).
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Replace nested executeWithAutoAuth/executeWithSeerTrialPrompt wrappers with a composable ErrorMiddleware type and an array of middlewares. - ErrorMiddleware type: (next, args) => Promise<void> - buildExecutor() composes middlewares innermost-first - Easy to add new middlewares by appending to errorMiddlewares array Also: - Use Object.hasOwn() instead of `in` for TRIAL_NAMES lookup - Fix getDaysRemaining to use same end-of-day UTC as getTrialStatus
Summary
When Seer commands (
issue explain,issue plan) fail with a budget or enablement error in an interactive terminal, the CLI now checks for an available Seer product trial, prompts the user, and retries the command on success. Additionally, newsentry trial listandsentry trial startcommands give users proactive control over product trials.Auto-prompt flow
Mirrors the existing
executeWithAutoAuthmiddleware pattern:SeerError(no_budgetornot_enabled)isTrialEligible()checks: eligible reason + org slug available + interactive TTYGET /api/0/customers/{org}/(control silo)seerUsers, falls back toseerAutofix)PUT /api/0/customers/{org}/product-trial/Non-eligible errors (
ai_disabled, missing org slug, non-TTY, API failures) pass through unchanged.Trial commands
sentry trial list [org]Lists all product trials for an org with status indicators:
Supports
--jsonand--fieldsfor machine consumption.sentry trial start <name> [org]Starts a named product trial. Supported names:
seer,replays,performance,spans,profiling,logs.Features smart argument swap detection —
sentry trial start my-org seerworks the same assentry trial start seer my-org.Key design decisions
isTrialEligible()acceptsunknown— does theinstanceof SeerErrorcheck internally so callers don't need to narrow first/customers/is a billing endpoint, usesgetControlSiloUrl()not region URLslog.info()/log.warn()/log.success()per project conventions (no rawstderr.write)ai_disabledexcluded — admin's explicit choice to disable AI; trial wouldn't override itgetTrialStatus()usessetUTCHours()for consistent date comparisonSeerError.format()says "You may be eligible" +sentry trial list(not a direct "start" since trial may not exist)New files
src/lib/seer-trial.tsisTrialEligible()+promptAndStartTrial()src/lib/trials.tsfindAvailableTrial()src/commands/trial/index.tssrc/commands/trial/list.tssentry trial listcommandsrc/commands/trial/start.tssentry trial startcommandsrc/lib/arg-parsing.tsdetectSwappedTrialArgs()Modified files
src/lib/api-client.tsgetProductTrials()+startProductTrial()using control silosrc/lib/errors.tsSeerError.format()src/bin.tsexecuteWithSeerTrialPrompt()middlewaresrc/app.tstrialsaliassrc/types/sentry.tsProductTrialSchema,CustomerTrialInfoSchemaTests
seer-trial.test.ts)api-client.seer-trial.test.ts)trials.test.ts)seer-trial.property.test.ts)trial listcommand (trial/list.test.ts)trial startcommand (trial/start.test.ts)detectSwappedTrialArgs(arg-parsing.test.ts)