Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions packages/cloud/src/AuthService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getClerkBaseUrl, getRooCodeApiUrl } from "./Config"
import { RefreshTimer } from "./RefreshTimer"

export interface AuthServiceEvents {
"inactive-session": [data: { previousState: AuthState }]
"active-session": [data: { previousState: AuthState }]
"logged-out": [data: { previousState: AuthState }]
"user-info": [data: { userInfo: CloudUserInfo }]
Expand Down Expand Up @@ -92,11 +93,15 @@ export class AuthService extends EventEmitter<AuthServiceEvents> {

private transitionToInactiveSession(credentials: AuthCredentials): void {
this.credentials = credentials

const previousState = this.state
this.state = "inactive-session"

this.sessionToken = null
this.userInfo = null

this.emit("inactive-session", { previousState })

this.timer.start()

console.log("[auth] Transitioned to inactive-session state")
Expand Down Expand Up @@ -281,14 +286,19 @@ export class AuthService extends EventEmitter<AuthServiceEvents> {
return
}

const previousState = this.state
this.sessionToken = await this.clerkCreateSessionToken()
this.state = "active-session"
try {
const previousState = this.state
this.sessionToken = await this.clerkCreateSessionToken()
this.state = "active-session"

if (previousState !== "active-session") {
console.log("[auth] Transitioned to active-session state")
this.emit("active-session", { previousState })
this.fetchUserInfo()
if (previousState !== "active-session") {
console.log("[auth] Transitioned to active-session state")
this.emit("active-session", { previousState })
this.fetchUserInfo()
}
} catch (error) {
console.error("[auth] Failed to refresh session", error)
throw error
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/cloud/src/CloudService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class CloudService {
try {
this.authService = await AuthService.createInstance(this.context)

this.authService.on("inactive-session", this.authListener)
this.authService.on("active-session", this.authListener)
this.authService.on("logged-out", this.authListener)
this.authService.on("user-info", this.authListener)
Expand Down
13 changes: 13 additions & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1300,6 +1300,7 @@ export class ClineProvider
terminalCompressProgressBar,
historyPreviewCollapsed,
cloudUserInfo,
cloudIsAuthenticated,
organizationAllowList,
maxConcurrentFileReads,
condensingApiConfigId,
Expand Down Expand Up @@ -1398,6 +1399,7 @@ export class ClineProvider
hasSystemPromptOverride,
historyPreviewCollapsed: historyPreviewCollapsed ?? false,
cloudUserInfo,
cloudIsAuthenticated: cloudIsAuthenticated ?? false,
organizationAllowList,
condensingApiConfigId,
customCondensingPrompt,
Expand Down Expand Up @@ -1453,6 +1455,16 @@ export class ClineProvider
)
}

let cloudIsAuthenticated: boolean = false

try {
cloudIsAuthenticated = CloudService.instance.isAuthenticated()
} catch (error) {
console.error(
`[getState] failed to get cloud authentication state: ${error instanceof Error ? error.message : String(error)}`,
)
}

// Return the same structure as before
return {
apiConfiguration: providerSettings,
Expand Down Expand Up @@ -1528,6 +1540,7 @@ export class ClineProvider
: 1,
historyPreviewCollapsed: stateValues.historyPreviewCollapsed ?? false,
cloudUserInfo,
cloudIsAuthenticated,
organizationAllowList,
// Explicitly add condensing settings
condensingApiConfigId: stateValues.condensingApiConfigId,
Expand Down
1 change: 1 addition & 0 deletions src/core/webview/__tests__/ClineProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ describe("ClineProvider", () => {
organizationAllowList: ORGANIZATION_ALLOW_ALL,
autoCondenseContext: true,
autoCondenseContextPercent: 100,
cloudIsAuthenticated: false,
}

const message: ExtensionMessage = {
Expand Down
1 change: 1 addition & 0 deletions src/shared/ExtensionMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ export type ExtensionState = Pick<
historyPreviewCollapsed?: boolean

cloudUserInfo: CloudUserInfo | null
cloudIsAuthenticated: boolean
organizationAllowList: OrganizationAllowList

autoCondenseContext: boolean
Expand Down
9 changes: 8 additions & 1 deletion webview-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const App = () => {
telemetryKey,
machineId,
cloudUserInfo,
cloudIsAuthenticated,
} = useExtensionState()

const [showAnnouncement, setShowAnnouncement] = useState(false)
Expand Down Expand Up @@ -127,7 +128,13 @@ const App = () => {
{tab === "settings" && (
<SettingsView ref={settingsRef} onDone={() => setTab("chat")} targetSection={currentSection} />
)}
{tab === "account" && <AccountView userInfo={cloudUserInfo} onDone={() => switchTab("chat")} />}
{tab === "account" && (
<AccountView
userInfo={cloudUserInfo}
isAuthenticated={cloudIsAuthenticated}
onDone={() => switchTab("chat")}
/>
)}
<ChatView
ref={chatViewRef}
isHidden={tab !== "chat"}
Expand Down
43 changes: 23 additions & 20 deletions webview-ui/src/components/account/AccountView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import { vscode } from "@src/utils/vscode"

type AccountViewProps = {
userInfo: CloudUserInfo | null
isAuthenticated: boolean
onDone: () => void
}

export const AccountView = ({ userInfo, onDone }: AccountViewProps) => {
export const AccountView = ({ userInfo, isAuthenticated, onDone }: AccountViewProps) => {
const { t } = useAppTranslation()

const rooLogoUri = (window as any).IMAGES_BASE_URI + "/roo-logo.svg"
Expand All @@ -23,27 +24,29 @@ export const AccountView = ({ userInfo, onDone }: AccountViewProps) => {
{t("settings:common.done")}
</VSCodeButton>
</div>
{userInfo ? (
{isAuthenticated ? (
<>
<div className="flex flex-col items-center mb-6">
<div className="w-16 h-16 mb-3 rounded-full overflow-hidden">
{userInfo?.picture ? (
<img
src={userInfo.picture}
alt={t("account:profilePicture")}
className="w-full h-full object-cover"
/>
) : (
<div className="w-full h-full flex items-center justify-center bg-vscode-button-background text-vscode-button-foreground text-xl">
{userInfo?.name?.charAt(0) || userInfo?.email?.charAt(0) || "?"}
</div>
)}
{userInfo && (
<div className="flex flex-col items-center mb-6">
<div className="w-16 h-16 mb-3 rounded-full overflow-hidden">
{userInfo?.picture ? (
<img
src={userInfo.picture}
alt={t("account:profilePicture")}
className="w-full h-full object-cover"
/>
) : (
<div className="w-full h-full flex items-center justify-center bg-vscode-button-background text-vscode-button-foreground text-xl">
{userInfo?.name?.charAt(0) || userInfo?.email?.charAt(0) || "?"}
</div>
)}
</div>
<h2 className="text-lg font-medium text-vscode-foreground mb-1">
{userInfo?.name || t("account:unknownUser")}
</h2>
<p className="text-sm text-vscode-descriptionForeground">{userInfo?.email || ""}</p>
</div>
<h2 className="text-lg font-medium text-vscode-foreground mb-1">
{userInfo?.name || t("account:unknownUser")}
</h2>
<p className="text-sm text-vscode-descriptionForeground">{userInfo?.email || ""}</p>
</div>
)}
<div className="flex flex-col gap-2 mt-4">
<VSCodeButton
appearance="secondary"
Expand Down
3 changes: 3 additions & 0 deletions webview-ui/src/context/ExtensionStateContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface ExtensionStateContextType extends ExtensionState {
filePaths: string[]
openedTabs: Array<{ label: string; isActive: boolean; path?: string }>
organizationAllowList: OrganizationAllowList
cloudIsAuthenticated: boolean
maxConcurrentFileReads?: number
condensingApiConfigId?: string
setCondensingApiConfigId: (value: string) => void
Expand Down Expand Up @@ -199,6 +200,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
terminalCompressProgressBar: true, // Default to compress progress bar output
historyPreviewCollapsed: false, // Initialize the new state (default to expanded)
cloudUserInfo: null,
cloudIsAuthenticated: false,
organizationAllowList: ORGANIZATION_ALLOW_ALL,
autoCondenseContext: true,
autoCondenseContextPercent: 100,
Expand Down Expand Up @@ -317,6 +319,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
writeDelayMs: state.writeDelayMs,
screenshotQuality: state.screenshotQuality,
routerModels: extensionRouterModels,
cloudIsAuthenticated: state.cloudIsAuthenticated ?? false,
setExperimentEnabled: (id, enabled) =>
setState((prevState) => ({ ...prevState, experiments: { ...prevState.experiments, [id]: enabled } })),
setApiConfiguration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ describe("mergeExtensionState", () => {
organizationAllowList: { allowAll: true, providers: {} },
autoCondenseContext: true,
autoCondenseContextPercent: 100,
cloudIsAuthenticated: false,
}

const prevState: ExtensionState = {
Expand Down