From 6b90ffddae2e487f242befa21e4d6c30eee161e8 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Mon, 4 May 2026 12:22:39 -0700 Subject: [PATCH 1/8] Misc --- apps/code/src/renderer/api/fetcher.ts | 8 ++++++-- .../settings/components/sections/PlanUsageSettings.tsx | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/code/src/renderer/api/fetcher.ts b/apps/code/src/renderer/api/fetcher.ts index cccefd7eb..e78b713ca 100644 --- a/apps/code/src/renderer/api/fetcher.ts +++ b/apps/code/src/renderer/api/fetcher.ts @@ -64,7 +64,9 @@ export const buildApiFetcher: (config: { await config.refreshAccessToken(), ); } catch { - const errorResponse = await response.json(); + const errorResponse = await response + .json() + .catch(() => ({ error: response.statusText })); throw new Error( `Failed request: [${response.status}] ${JSON.stringify(errorResponse)}`, ); @@ -72,7 +74,9 @@ export const buildApiFetcher: (config: { } if (!response.ok) { - const errorResponse = await response.json(); + const errorResponse = await response + .json() + .catch(() => ({ error: response.statusText })); throw new Error( `Failed request: [${response.status}] ${JSON.stringify(errorResponse)}`, ); diff --git a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx index f86802341..a8d30b2db 100644 --- a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx @@ -238,10 +238,10 @@ export function PlanUsageSettings() { className="rounded-(--radius-3) border border-(--accent-7) bg-(--accent-2)" > - Alpha plan + Extended Alpha Plan - You're on the free alpha Pro plan with full Pro features. You can - upgrade to the paid Pro plan anytime for higher usage limits. + You're on the free Pro plan with full Pro features until June 4, + 2026. From d270539da5f923cc644e07ddd80c440375aa0699 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Mon, 4 May 2026 12:44:58 -0700 Subject: [PATCH 2/8] Show update indicator on pre-auth screens --- .../renderer/components/FullScreenLayout.tsx | 32 ++++++------ .../sidebar/components/UpdateBanner.tsx | 49 ++++++++++++++++++- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/apps/code/src/renderer/components/FullScreenLayout.tsx b/apps/code/src/renderer/components/FullScreenLayout.tsx index 3fcfef1aa..45037b565 100644 --- a/apps/code/src/renderer/components/FullScreenLayout.tsx +++ b/apps/code/src/renderer/components/FullScreenLayout.tsx @@ -1,3 +1,4 @@ +import { UpdateBanner } from "@features/sidebar/components/UpdateBanner"; import { Lifebuoy } from "@phosphor-icons/react"; import { Button, Flex, Theme } from "@radix-ui/themes"; import phWordmark from "@renderer/assets/images/wordmark.svg"; @@ -63,20 +64,23 @@ export function FullScreenLayout({ className="absolute right-[32px] bottom-[20px] left-[32px] z-[2]" > {footerLeft ?? ( - + + + + )} {footerRight ??
} diff --git a/apps/code/src/renderer/features/sidebar/components/UpdateBanner.tsx b/apps/code/src/renderer/features/sidebar/components/UpdateBanner.tsx index ab42cc598..ac3cd68db 100644 --- a/apps/code/src/renderer/features/sidebar/components/UpdateBanner.tsx +++ b/apps/code/src/renderer/features/sidebar/components/UpdateBanner.tsx @@ -3,7 +3,11 @@ import { Box } from "@radix-ui/themes"; import { useUpdateStore } from "@stores/updateStore"; import { AnimatePresence, motion } from "framer-motion"; -export function UpdateBanner() { +interface UpdateBannerProps { + variant?: "sidebar" | "compact"; +} + +export function UpdateBanner({ variant = "sidebar" }: UpdateBannerProps) { const status = useUpdateStore((s) => s.status); const version = useUpdateStore((s) => s.version); const isEnabled = useUpdateStore((s) => s.isEnabled); @@ -13,6 +17,49 @@ export function UpdateBanner() { isEnabled && (status === "downloading" || status === "ready" || status === "installing"); + if (variant === "compact") { + return ( + + {isVisible && ( + + {status === "downloading" && ( +
+ + Downloading update... +
+ )} + + {status === "ready" && ( + + )} + + {status === "installing" && ( +
+ + Restarting... +
+ )} +
+ )} +
+ ); + } + return ( {isVisible && ( From 7deff003cc1646b01d3b8e4668872c07073ffc6f Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Mon, 4 May 2026 14:27:36 -0700 Subject: [PATCH 3/8] Re-fetch seat after org switch, fix error fallback --- apps/code/src/renderer/api/fetcher.ts | 10 ++++++++-- .../onboarding/components/ProjectSelectStep.tsx | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/code/src/renderer/api/fetcher.ts b/apps/code/src/renderer/api/fetcher.ts index e78b713ca..74a45e26d 100644 --- a/apps/code/src/renderer/api/fetcher.ts +++ b/apps/code/src/renderer/api/fetcher.ts @@ -64,9 +64,12 @@ export const buildApiFetcher: (config: { await config.refreshAccessToken(), ); } catch { + const cloned = response.clone(); const errorResponse = await response .json() - .catch(() => ({ error: response.statusText })); + .catch(() => + cloned.text().then((t) => ({ error: t || `${response.status}` })), + ); throw new Error( `Failed request: [${response.status}] ${JSON.stringify(errorResponse)}`, ); @@ -74,9 +77,12 @@ export const buildApiFetcher: (config: { } if (!response.ok) { + const cloned = response.clone(); const errorResponse = await response .json() - .catch(() => ({ error: response.statusText })); + .catch(() => + cloned.text().then((t) => ({ error: t || `${response.status}` })), + ); throw new Error( `Failed request: [${response.status}] ${JSON.stringify(errorResponse)}`, ); diff --git a/apps/code/src/renderer/features/onboarding/components/ProjectSelectStep.tsx b/apps/code/src/renderer/features/onboarding/components/ProjectSelectStep.tsx index 7686f6584..49fca4636 100644 --- a/apps/code/src/renderer/features/onboarding/components/ProjectSelectStep.tsx +++ b/apps/code/src/renderer/features/onboarding/components/ProjectSelectStep.tsx @@ -7,6 +7,8 @@ import { useAuthStateValue, useCurrentUser, } from "@features/auth/hooks/authQueries"; +import { useSeatStore } from "@features/billing/stores/seatStore"; +import { Command } from "@features/command/components/Command"; import { type ProjectInfo, useProjects, @@ -107,6 +109,7 @@ export function ProjectSelectStep({ onNext, onBack }: ProjectSelectStepProps) { await queryClient.invalidateQueries({ queryKey: authKeys.currentUsers(), }); + void useSeatStore.getState().fetchSeat({ autoProvision: true }); }, onMutate: () => { setIsSwitchingOrg(true); From 0a16ea70e5a188c552fd8786afcb1a10f161a3b0 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Mon, 4 May 2026 14:38:36 -0700 Subject: [PATCH 4/8] Show current org plan on Plan & Usage page --- apps/code/src/renderer/api/fetcher.test.ts | 18 +++++-- apps/code/src/renderer/api/posthogClient.ts | 8 +++- .../features/billing/stores/seatStore.test.ts | 1 + .../features/billing/stores/seatStore.ts | 14 ++++++ .../components/sections/PlanUsageSettings.tsx | 47 ++++++++++++++----- apps/code/src/renderer/hooks/useSeat.ts | 17 +++++-- 6 files changed, 83 insertions(+), 22 deletions(-) diff --git a/apps/code/src/renderer/api/fetcher.test.ts b/apps/code/src/renderer/api/fetcher.test.ts index e3890a7ae..62a510620 100644 --- a/apps/code/src/renderer/api/fetcher.test.ts +++ b/apps/code/src/renderer/api/fetcher.test.ts @@ -13,11 +13,19 @@ describe("buildApiFetcher", () => { status: 200, json: () => Promise.resolve(data), }); - const err = (status: number) => ({ - ok: false, - status, - json: () => Promise.resolve({ error: status }), - }); + const err = (status: number) => { + const response = { + ok: false, + status, + statusText: `Error ${status}`, + json: () => Promise.resolve({ error: status }), + clone: () => ({ + ...response, + text: () => Promise.resolve(`Error ${status}`), + }), + }; + return response; + }; beforeEach(() => { vi.resetAllMocks(); diff --git a/apps/code/src/renderer/api/posthogClient.ts b/apps/code/src/renderer/api/posthogClient.ts index 8f64e5037..1c1e10fb1 100644 --- a/apps/code/src/renderer/api/posthogClient.ts +++ b/apps/code/src/renderer/api/posthogClient.ts @@ -2460,11 +2460,15 @@ export class PostHogAPIClient { return data.results ?? data ?? []; } - async getMySeat(): Promise { + async getMySeat( + options: { best?: boolean } = { best: true }, + ): Promise { try { const url = new URL(`${this.api.baseUrl}/api/seats/me/`); url.searchParams.set("product_key", SEAT_PRODUCT_KEY); - url.searchParams.set("best", "true"); + if (options.best) { + url.searchParams.set("best", "true"); + } const response = await this.api.fetcher.fetch({ method: "get", url, diff --git a/apps/code/src/renderer/features/billing/stores/seatStore.test.ts b/apps/code/src/renderer/features/billing/stores/seatStore.test.ts index b2e4cffb3..72e344b73 100644 --- a/apps/code/src/renderer/features/billing/stores/seatStore.test.ts +++ b/apps/code/src/renderer/features/billing/stores/seatStore.test.ts @@ -85,6 +85,7 @@ describe("seatStore", () => { vi.clearAllMocks(); useSeatStore.setState({ seat: null, + orgSeat: null, isLoading: false, error: null, redirectUrl: null, diff --git a/apps/code/src/renderer/features/billing/stores/seatStore.ts b/apps/code/src/renderer/features/billing/stores/seatStore.ts index 531ab5c01..2e88cc283 100644 --- a/apps/code/src/renderer/features/billing/stores/seatStore.ts +++ b/apps/code/src/renderer/features/billing/stores/seatStore.ts @@ -14,6 +14,7 @@ const log = logger.scope("seat-store"); interface SeatStoreState { seat: SeatData | null; + orgSeat: SeatData | null; isLoading: boolean; error: string | null; redirectUrl: string | null; @@ -22,6 +23,7 @@ interface SeatStoreState { interface SeatStoreActions { fetchSeat: (options?: { autoProvision?: boolean }) => Promise; + fetchOrgSeat: () => Promise; provisionFreeSeat: () => Promise; upgradeToPro: () => Promise; cancelSeat: () => Promise; @@ -77,6 +79,7 @@ function invalidatePlanCache(): void { const initialState: SeatStoreState = { seat: null, + orgSeat: null, isLoading: false, error: null, redirectUrl: null, @@ -116,6 +119,17 @@ export const useSeatStore = create()((set, get) => ({ } }, + fetchOrgSeat: async () => { + try { + const client = await getClient(); + const orgSeat = await client.getMySeat({ best: false }); + set({ orgSeat }); + } catch (error) { + log.warn("fetchOrgSeat failed", error); + set({ orgSeat: null }); + } + }, + provisionFreeSeat: async () => { log.info("Provisioning free seat"); set({ isLoading: true, error: null, redirectUrl: null }); diff --git a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx index a8d30b2db..eed7f6478 100644 --- a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx @@ -8,6 +8,7 @@ import { ArrowSquareOut, Check, CreditCard, + Info, WarningCircle, } from "@phosphor-icons/react"; import { @@ -56,16 +57,24 @@ function formatResetTime(seconds: number): string { export function PlanUsageSettings() { const { seat, - isPro, + orgSeat, + isOrgPro, isCanceling, activeUntil, isLoading, error, redirectUrl, billingOrgId, + hasBetterPlanElsewhere, } = useSeat(); - const { fetchSeat, upgradeToPro, cancelSeat, reactivateSeat, clearError } = - useSeatStore(); + const { + fetchSeat, + fetchOrgSeat, + upgradeToPro, + cancelSeat, + reactivateSeat, + clearError, + } = useSeatStore(); const cloudRegion = useAuthStateValue((state) => state.cloudRegion); const billingUrl = getPostHogUrl("/organization/billing", cloudRegion); const redirectFullUrl = redirectUrl @@ -73,7 +82,7 @@ export function PlanUsageSettings() { : null; const [showUpgradeDialog, setShowUpgradeDialog] = useState(false); - const isAlpha = seat?.plan_key === PLAN_PRO_ALPHA; + const isAlpha = orgSeat?.plan_key === PLAN_PRO_ALPHA; const { usage, isLoading: usageLoading, @@ -84,8 +93,9 @@ export function PlanUsageSettings() { useEffect(() => { void fetchSeat(); + void fetchOrgSeat(); void refetchUsage(); - }, [fetchSeat, refetchUsage]); + }, [fetchSeat, fetchOrgSeat, refetchUsage]); const formattedActiveUntil = activeUntil ? activeUntil.toLocaleDateString(undefined, { @@ -142,8 +152,21 @@ export function PlanUsageSettings() { )} + {hasBetterPlanElsewhere && seat?.organization_name && ( + + + + + + You have a Pro plan on{" "} + {seat.organization_name}. Usage on this + page reflects your current organization. + + + )} + - {seat ? ( + {orgSeat ? ( <> - {isPro && ( + {isOrgPro && ( Billing s.seat); + const orgSeat = useSeatStore((s) => s.orgSeat); const isLoading = useSeatStore((s) => s.isLoading); const error = useSeatStore((s) => s.error); const redirectUrl = useSeatStore((s) => s.redirectUrl); const billingOrgId = useSeatStore((s) => s.billingOrgId); const isPro = isProPlan(seat?.plan_key); + const isOrgPro = isProPlan(orgSeat?.plan_key); const hasAccess = seat ? seatHasAccess(seat.status) : false; - const isCanceling = seat?.status === "canceling"; + const isCanceling = orgSeat?.status === "canceling"; const planLabel = isPro ? "Pro" : "Free"; - const activeUntil = seat?.active_until - ? new Date(seat.active_until * 1000) + const activeUntil = orgSeat?.active_until + ? new Date(orgSeat.active_until * 1000) : null; + const hasBetterPlanElsewhere = + seat !== null && + orgSeat !== null && + isProPlan(seat.plan_key) && + !isProPlan(orgSeat.plan_key); + return { seat, + orgSeat, isLoading, error, redirectUrl, billingOrgId, isPro, + isOrgPro, hasAccess, isCanceling, planLabel, activeUntil, + hasBetterPlanElsewhere, }; } From 49bfcd607689668353362aaff9249db27f843489 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Mon, 4 May 2026 15:11:17 -0700 Subject: [PATCH 5/8] Consolidate seat fetching into single fetchSeat call --- .../features/auth/hooks/useAuthSession.ts | 6 +-- .../features/billing/stores/seatStore.ts | 51 +++++++++++-------- .../components/sections/PlanUsageSettings.tsx | 15 ++---- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/apps/code/src/renderer/features/auth/hooks/useAuthSession.ts b/apps/code/src/renderer/features/auth/hooks/useAuthSession.ts index 03d489290..a8ed01f4c 100644 --- a/apps/code/src/renderer/features/auth/hooks/useAuthSession.ts +++ b/apps/code/src/renderer/features/auth/hooks/useAuthSession.ts @@ -14,6 +14,7 @@ import { trpcClient } from "@renderer/trpc/client"; import { BILLING_FLAG } from "@shared/constants"; import { identifyUser, resetUser } from "@utils/analytics"; import { logger } from "@utils/logger"; +import { queryClient } from "@utils/queryClient"; import { useEffect } from "react"; const log = logger.scope("auth-session"); @@ -93,9 +94,8 @@ function useSeatSync( return; } - void useSeatStore.getState().fetchSeat({ - autoProvision: true, - }); + void useSeatStore.getState().fetchSeat({ autoProvision: true }); + void queryClient.invalidateQueries({ queryKey: [["llmGateway"]] }); }, [authIdentity, billingEnabled]); } diff --git a/apps/code/src/renderer/features/billing/stores/seatStore.ts b/apps/code/src/renderer/features/billing/stores/seatStore.ts index 2e88cc283..f5064416b 100644 --- a/apps/code/src/renderer/features/billing/stores/seatStore.ts +++ b/apps/code/src/renderer/features/billing/stores/seatStore.ts @@ -23,7 +23,6 @@ interface SeatStoreState { interface SeatStoreActions { fetchSeat: (options?: { autoProvision?: boolean }) => Promise; - fetchOrgSeat: () => Promise; provisionFreeSeat: () => Promise; upgradeToPro: () => Promise; cancelSeat: () => Promise; @@ -42,6 +41,25 @@ async function getClient() { return client; } +async function fetchAndProvision( + client: Awaited>, + options: { best: boolean; autoProvision: boolean }, +): Promise { + let seat = await client.getMySeat({ best: options.best }); + if (!seat && options.autoProvision) { + log.info("No seat found, auto-provisioning free plan", { + best: options.best, + }); + try { + seat = await client.createSeat(PLAN_FREE); + } catch { + log.info("Auto-provision failed, re-fetching seat"); + seat = await client.getMySeat({ best: options.best }); + } + } + return seat; +} + function handleSeatError( error: unknown, set: (state: Partial) => void, @@ -93,18 +111,14 @@ export const useSeatStore = create()((set, get) => ({ set({ isLoading: true, error: null, redirectUrl: null }); try { const client = await getClient(); - let seat = await client.getMySeat(); - if (!seat && options?.autoProvision) { - log.info("No seat found, auto-provisioning free plan"); - try { - seat = await client.createSeat(PLAN_FREE); - } catch { - log.info("Auto-provision failed, re-fetching seat"); - seat = await client.getMySeat(); - } - } + const autoProvision = options?.autoProvision ?? false; + const [seat, orgSeat] = await Promise.all([ + fetchAndProvision(client, { best: true, autoProvision }), + fetchAndProvision(client, { best: false, autoProvision }), + ]); set({ seat, + orgSeat, isLoading: false, billingOrgId: seat?.organization_id ?? null, }); @@ -119,17 +133,6 @@ export const useSeatStore = create()((set, get) => ({ } }, - fetchOrgSeat: async () => { - try { - const client = await getClient(); - const orgSeat = await client.getMySeat({ best: false }); - set({ orgSeat }); - } catch (error) { - log.warn("fetchOrgSeat failed", error); - set({ orgSeat: null }); - } - }, - provisionFreeSeat: async () => { log.info("Provisioning free seat"); set({ isLoading: true, error: null, redirectUrl: null }); @@ -179,6 +182,7 @@ export const useSeatStore = create()((set, get) => ({ const seat = await client.upgradeSeat(PLAN_PRO); set({ seat, + orgSeat: seat, isLoading: false, billingOrgId: seat.organization_id ?? null, }); @@ -188,6 +192,7 @@ export const useSeatStore = create()((set, get) => ({ const seat = await client.createSeat(PLAN_PRO); set({ seat, + orgSeat: seat, isLoading: false, billingOrgId: seat.organization_id ?? null, }); @@ -205,6 +210,7 @@ export const useSeatStore = create()((set, get) => ({ const seat = await client.getMySeat(); set({ seat, + orgSeat: seat, isLoading: false, billingOrgId: seat?.organization_id ?? null, }); @@ -221,6 +227,7 @@ export const useSeatStore = create()((set, get) => ({ const seat = await client.reactivateSeat(); set({ seat, + orgSeat: seat, isLoading: false, billingOrgId: seat.organization_id ?? null, }); diff --git a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx index eed7f6478..5ef94430a 100644 --- a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx @@ -67,14 +67,8 @@ export function PlanUsageSettings() { billingOrgId, hasBetterPlanElsewhere, } = useSeat(); - const { - fetchSeat, - fetchOrgSeat, - upgradeToPro, - cancelSeat, - reactivateSeat, - clearError, - } = useSeatStore(); + const { fetchSeat, upgradeToPro, cancelSeat, reactivateSeat, clearError } = + useSeatStore(); const cloudRegion = useAuthStateValue((state) => state.cloudRegion); const billingUrl = getPostHogUrl("/organization/billing", cloudRegion); const redirectFullUrl = redirectUrl @@ -92,10 +86,9 @@ export function PlanUsageSettings() { }); useEffect(() => { - void fetchSeat(); - void fetchOrgSeat(); + void fetchSeat({ autoProvision: true }); void refetchUsage(); - }, [fetchSeat, fetchOrgSeat, refetchUsage]); + }, [fetchSeat, refetchUsage]); const formattedActiveUntil = activeUntil ? activeUntil.toLocaleDateString(undefined, { From ac6c5c2732b5fac10ed87ff6f6f6722cb5e2e564 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Mon, 4 May 2026 15:24:28 -0700 Subject: [PATCH 6/8] Add VITE_POSTHOG_ACCESS_TOKEN_OVERRIDE env var --- apps/code/src/main/services/auth/service.ts | 20 ++++++++++++++++++++ apps/code/vite.main.config.mts | 3 +++ 2 files changed, 23 insertions(+) diff --git a/apps/code/src/main/services/auth/service.ts b/apps/code/src/main/services/auth/service.ts index f391226de..fcd8c4d75 100644 --- a/apps/code/src/main/services/auth/service.ts +++ b/apps/code/src/main/services/auth/service.ts @@ -113,6 +113,16 @@ export class AuthService extends TypedEventEmitter { return this.getState(); } async getValidAccessToken(): Promise { + const override = process.env.VITE_POSTHOG_ACCESS_TOKEN_OVERRIDE; + if (override) { + await this.initialize(); + const region = this.session?.cloudRegion ?? "us"; + return { + accessToken: override, + apiHost: getCloudUrlFromRegion(region), + }; + } + await this.initialize(); const session = await this.ensureValidSession(); @@ -122,6 +132,16 @@ export class AuthService extends TypedEventEmitter { }; } async refreshAccessToken(): Promise { + const override = process.env.VITE_POSTHOG_ACCESS_TOKEN_OVERRIDE; + if (override) { + await this.initialize(); + const region = this.session?.cloudRegion ?? "us"; + return { + accessToken: override, + apiHost: getCloudUrlFromRegion(region), + }; + } + await this.initialize(); const session = await this.ensureValidSession(true); diff --git a/apps/code/vite.main.config.mts b/apps/code/vite.main.config.mts index 402b6c341..596433f67 100644 --- a/apps/code/vite.main.config.mts +++ b/apps/code/vite.main.config.mts @@ -550,6 +550,9 @@ export default defineConfig(({ mode }) => { "process.env.VITE_POSTHOG_API_HOST": JSON.stringify( env.VITE_POSTHOG_API_HOST || "", ), + "process.env.VITE_POSTHOG_ACCESS_TOKEN_OVERRIDE": JSON.stringify( + env.VITE_POSTHOG_ACCESS_TOKEN_OVERRIDE || "", + ), "process.env.SKILLS_ZIP_URL": JSON.stringify(SKILLS_ZIP_URL), "process.env.CONTEXT_MILL_ZIP_URL": JSON.stringify(CONTEXT_MILL_ZIP_URL), ...createForceDevModeDefine(), From eda1680f584c9da281e4d365a1ae739517d73922 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Mon, 4 May 2026 15:26:59 -0700 Subject: [PATCH 7/8] remove unused Command import from rebase --- .../features/onboarding/components/ProjectSelectStep.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/code/src/renderer/features/onboarding/components/ProjectSelectStep.tsx b/apps/code/src/renderer/features/onboarding/components/ProjectSelectStep.tsx index 49fca4636..60844ef22 100644 --- a/apps/code/src/renderer/features/onboarding/components/ProjectSelectStep.tsx +++ b/apps/code/src/renderer/features/onboarding/components/ProjectSelectStep.tsx @@ -8,7 +8,6 @@ import { useCurrentUser, } from "@features/auth/hooks/authQueries"; import { useSeatStore } from "@features/billing/stores/seatStore"; -import { Command } from "@features/command/components/Command"; import { type ProjectInfo, useProjects, From 9669e4fdae5688d4782530312beb6ec4c43dd6bc Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Mon, 4 May 2026 15:31:48 -0700 Subject: [PATCH 8/8] Add billing link to payment error callout --- .../components/sections/PlanUsageSettings.tsx | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx index 5ef94430a..182a1b662 100644 --- a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx @@ -111,7 +111,27 @@ export function PlanUsageSettings() { - {error} + + + {error} + + Update your payment method in PostHog to continue. + + + + )}