11import { CheckCircleIcon } from "@heroicons/react/24/solid" ;
22import { LoaderFunctionArgs } from "@remix-run/server-runtime" ;
3- import { title } from "process" ;
43import { typedjson , useTypedLoaderData } from "remix-typedjson" ;
54import { z } from "zod" ;
6- import { ErrorIcon } from "~/assets/icons/ErrorIcon" ;
75import { AppContainer , MainCenteredContainer } from "~/components/layout/AppLayout" ;
8- import { LinkButton } from "~/components/primitives/Buttons" ;
96import { Callout } from "~/components/primitives/Callout" ;
107import { Header1 } from "~/components/primitives/Headers" ;
118import { Icon } from "~/components/primitives/Icon" ;
129import { Paragraph } from "~/components/primitives/Paragraph" ;
1310import { logger } from "~/services/logger.server" ;
1411import { createPersonalAccessTokenFromAuthorizationCode } from "~/services/personalAccessToken.server" ;
1512import { requireUserId } from "~/services/session.server" ;
16- import { rootPath } from "~/utils/pathBuilder" ;
1713
1814const ParamsSchema = z . object ( {
1915 authorizationCode : z . string ( ) ,
2016} ) ;
2117
18+ const SearchParamsSchema = z . object ( {
19+ source : z . string ( ) . optional ( ) ,
20+ clientName : z . string ( ) . optional ( ) ,
21+ } ) ;
22+
2223export const loader = async ( { request, params } : LoaderFunctionArgs ) => {
2324 const userId = await requireUserId ( request ) ;
2425
@@ -32,13 +33,23 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
3233 } ) ;
3334 }
3435
36+ const url = new URL ( request . url ) ;
37+ const searchObject = Object . fromEntries ( url . searchParams . entries ( ) ) ;
38+
39+ const searchParams = SearchParamsSchema . safeParse ( searchObject ) ;
40+
41+ const source = ( searchParams . success ? searchParams . data . source : undefined ) ?? "cli" ;
42+ const clientName = ( searchParams . success ? searchParams . data . clientName : undefined ) ?? "unknown" ;
43+
3544 try {
3645 const personalAccessToken = await createPersonalAccessTokenFromAuthorizationCode (
3746 parsedParams . data . authorizationCode ,
3847 userId
3948 ) ;
4049 return typedjson ( {
4150 success : true as const ,
51+ source,
52+ clientName,
4253 } ) ;
4354 } catch ( error ) {
4455 if ( error instanceof Response ) {
@@ -49,6 +60,8 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
4960 return typedjson ( {
5061 success : false as const ,
5162 error : error . message ,
63+ source,
64+ clientName,
5265 } ) ;
5366 }
5467
@@ -73,7 +86,7 @@ export default function Page() {
7386 < Icon icon = { CheckCircleIcon } className = "h-6 w-6 text-emerald-500" /> Successfully
7487 authenticated
7588 </ Header1 >
76- < Paragraph > Return to your terminal to continue. </ Paragraph >
89+ < Paragraph > { getInstructionsForSource ( result . source , result . clientName ) } </ Paragraph >
7790 </ div >
7891 ) : (
7992 < div >
@@ -91,3 +104,21 @@ export default function Page() {
91104 </ AppContainer >
92105 ) ;
93106}
107+
108+ const prettyClientNames : Record < string , string > = {
109+ "claude-code" : "Claude Code" ,
110+ "cursor-vscode" : "Cursor" ,
111+ "Visual Studio Code" : "VSCode" ,
112+ "windsurf-client" : "Windsurf" ,
113+ "claude-ai" : "Claude Desktop" ,
114+ } ;
115+
116+ function getInstructionsForSource ( source : string , clientName : string ) {
117+ if ( source === "mcp" ) {
118+ if ( clientName ) {
119+ return `Return to your ${ prettyClientNames [ clientName ] ?? clientName } to continue.` ;
120+ }
121+ }
122+
123+ return `Return to your terminal to continue.` ;
124+ }
0 commit comments