Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 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
19 changes: 16 additions & 3 deletions apps/web-roo-code/src/app/privacy/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function Privacy() {
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl">
Roo Code Cloud Privacy Policy
</h1>
<p className="text-muted-foreground">Last Updated: August 20, 2025</p>
<p className="text-muted-foreground">Last Updated: September 19, 2025</p>

<p className="lead">
This Privacy Policy explains how Roo Code, Inc. (&quot;Roo Code,&quot; &quot;we,&quot;
Expand Down Expand Up @@ -86,8 +86,8 @@ export default function Privacy() {
Your source code does not transit Roo Code servers unless you explicitly choose Roo Code
as a model provider (proxy mode).
</strong>{" "}
When Roo Code Cloud is your model provider, your code briefly transits Roo Code servers only to
forward it to the upstream model, is not stored, and is deleted immediately after
When Roo Code Cloud is your model provider, your code briefly transits Roo Code servers only
to forward it to the upstream model, is not stored, and is deleted immediately after
forwarding. Otherwise, your code is sent <strong>directly</strong>β€”via client‑to‑provider
TLSβ€”to the model you select. Roo Code never stores, inspects, or trains on your code.
</li>
Expand Down Expand Up @@ -184,6 +184,13 @@ export default function Privacy() {
<li>
<strong>Send product updates and roadmap communications</strong> (opt‑out available)
</li>
<li>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The privacy policy now includes a section on marketing communications. Has this been reviewed by legal to ensure compliance with applicable data protection regulations (GDPR, CCPA, etc.)?

<strong>Send onboarding, educational, and promotional communications</strong>. We may use
your account information (such as your name and email address) to send you onboarding
messages, product tutorials, feature announcements, newsletters, and other marketing
communications. You can opt out of non‑transactional emails at any time (see β€œYour Choices”
below).
</li>
</ul>

<h2 className="mt-12 text-2xl font-bold">3. Where Your Data Goes (And Doesn&apos;t)</h2>
Expand Down Expand Up @@ -277,6 +284,12 @@ export default function Privacy() {
<strong>Delete your Cloud account</strong> at any time from{" "}
<strong>Security Settings</strong> inside Roo Code Cloud.
</li>
<li>
<strong>Marketing communications:</strong> You can unsubscribe from marketing and
promotional emails by clicking the unsubscribe link in those emails. Transactional or
service‑related emails (such as password resets, billing notices, or security alerts) will
continue even if you opt out.
</li>
</ul>

<h2 className="mt-12 text-2xl font-bold">6. Security Practices</h2>
Expand Down
5 changes: 5 additions & 0 deletions src/core/webview/webviewMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3035,5 +3035,10 @@ export const webviewMessageHandler = async (
})
break
}
case "openSettings": {
// Execute the settings command to open the settings panel
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional? The new "openSettings" message type executes a settings command. Could we add a comment explaining what settings panel this opens and why it's needed for the CODE SUPERNOVA feature?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree with this, not really sure why this new message is needed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking a look now.

await vscode.commands.executeCommand(getCommand("settingsButtonClicked"))
break
}
}
}
1 change: 1 addition & 0 deletions src/shared/WebviewMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ export interface WebviewMessage {
| "editQueuedMessage"
| "dismissUpsell"
| "getDismissedUpsells"
| "openSettings"
text?: string
editedMessageContent?: string
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud"
Expand Down
36 changes: 21 additions & 15 deletions webview-ui/src/components/chat/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ import { CheckpointWarning } from "./CheckpointWarning"
import { QueuedMessages } from "./QueuedMessages"
import DismissibleUpsell from "../common/DismissibleUpsell"
import { useCloudUpsell } from "@src/hooks/useCloudUpsell"
import { Cloud } from "lucide-react"

export interface ChatViewProps {
isHidden: boolean
Expand Down Expand Up @@ -131,7 +130,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
messagesRef.current = messages
}, [messages])

const { tasks } = useTaskSearch()
const { tasks, recentTasks } = useTaskSearch()
const hasTaskHistory = recentTasks.length > 0

// Initialize expanded state based on the persisted setting (default to expanded if undefined)
const [isExpanded, setIsExpanded] = useState(
Expand Down Expand Up @@ -212,7 +212,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro

const {
isOpen: isUpsellOpen,
openUpsell,
openUpsell: _openUpsell,
closeUpsell,
handleConnect,
} = useCloudUpsell({
Expand Down Expand Up @@ -1819,10 +1819,10 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
) : (
<div className="flex-1 min-h-0 overflow-y-auto flex flex-col gap-4 relative">
{/* Moved Task Bar Header Here */}
{tasks.length !== 0 && (
{hasTaskHistory && (
<div className="flex text-vscode-descriptionForeground w-full mx-auto px-5 pt-3">
<div className="flex items-center gap-1 cursor-pointer" onClick={toggleExpanded}>
{tasks.length < 10 && (
{recentTasks.length < 10 && (
<span className={`font-medium text-xs `}>{t("history:recentTasks")}</span>
)}
<span
Expand All @@ -1847,23 +1847,29 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
) : (
<>
<DismissibleUpsell
upsellId="taskList"
icon={<Cloud className="size-4 mt-0.5 shrink-0" />}
onClick={() => openUpsell()}
upsellId="taskListSupernova"
dismissOnClick={false}
className="bg-vscode-editor-background p-4 !text-base">
<Trans
i18nKey="cloud:upsell.taskList"
components={{
learnMoreLink: <VSCodeLink href="#" />,
}}
/>
<div className="w-full text-center leading-relaxed">
<Trans
i18nKey="cloud:upsell.taskList"
components={{
lineBreak: <br />,
providersLink: (
<VSCodeLink
href="#"
onClick={() => vscode.postMessage({ type: "openSettings" })}
/>
),
}}
/>
</div>
</DismissibleUpsell>
</>
)}
</div>
{/* Show the task history preview if expanded and tasks exist */}
{taskHistory.length > 0 && isExpanded && <HistoryPreview />}
{hasTaskHistory && isExpanded && <HistoryPreview />}
</div>
</div>
)}
Expand Down
21 changes: 18 additions & 3 deletions webview-ui/src/components/cloud/CloudView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, onDone }: Cl
vscode.postMessage({ type: "openExternal", url: cloudUrl })
}

const handleStartFreeTrial = () => {
vscode.postMessage({ type: "openExternal", url: "https://app.roocode.com/billing" })
}

const handleOpenCloudUrl = () => {
if (cloudApiUrl) {
vscode.postMessage({ type: "openExternal", url: cloudApiUrl })
Expand Down Expand Up @@ -272,9 +276,20 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, onDone }: Cl
<div className={cn(authInProgress && "opacity-50")}>{renderCloudBenefitsContent(t)}</div>

{!authInProgress && (
<VSCodeButton appearance="primary" onClick={handleConnectClick} className="w-full">
{t("cloud:connect")}
</VSCodeButton>
<>
<VSCodeButton
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This button logic is duplicated in ApiOptions.tsx (lines 666-679). Could we extract this into a shared component to avoid duplication and ensure consistency?

appearance="primary"
onClick={handleStartFreeTrial}
className="w-full">
{t("cloud:startFreeTrial")}
</VSCodeButton>
<VSCodeButton
appearance="secondary"
onClick={handleConnectClick}
className="w-full">
{t("cloud:connect")}
</VSCodeButton>
</>
)}

{/* Manual entry section */}
Expand Down
10 changes: 7 additions & 3 deletions webview-ui/src/components/history/HistoryPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@ import { useTaskSearch } from "./useTaskSearch"
import TaskItem from "./TaskItem"

const HistoryPreview = () => {
const { tasks } = useTaskSearch()
const { tasks, recentTasks } = useTaskSearch()
const { t } = useAppTranslation()

const handleViewAllHistory = () => {
vscode.postMessage({ type: "switchTab", tab: "history" })
}

const previewSource = tasks.length > 0 ? tasks : recentTasks
const previewTasks = previewSource.slice(0, 3)
const hasAnyTasks = recentTasks.length > 0

return (
<div className="flex flex-col gap-3">
{tasks.length !== 0 && (
{hasAnyTasks && (
<>
{tasks.slice(0, 3).map((item) => (
{previewTasks.map((item) => (
<TaskItem key={item.id} item={item} variant="compact" />
))}
<button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ describe("HistoryPreview", () => {
it("renders nothing when no tasks are available", () => {
mockUseTaskSearch.mockReturnValue({
tasks: [],
recentTasks: [],
searchQuery: "",
setSearchQuery: vi.fn(),
sortOption: "newest",
Expand All @@ -107,6 +108,7 @@ describe("HistoryPreview", () => {
it("renders up to 3 tasks when tasks are available", () => {
mockUseTaskSearch.mockReturnValue({
tasks: mockTasks,
recentTasks: mockTasks,
searchQuery: "",
setSearchQuery: vi.fn(),
sortOption: "newest",
Expand All @@ -132,6 +134,7 @@ describe("HistoryPreview", () => {
const threeTasks = mockTasks.slice(0, 3)
mockUseTaskSearch.mockReturnValue({
tasks: threeTasks,
recentTasks: threeTasks,
searchQuery: "",
setSearchQuery: vi.fn(),
sortOption: "newest",
Expand All @@ -156,6 +159,7 @@ describe("HistoryPreview", () => {
const oneTask = mockTasks.slice(0, 1)
mockUseTaskSearch.mockReturnValue({
tasks: oneTask,
recentTasks: oneTask,
searchQuery: "",
setSearchQuery: vi.fn(),
sortOption: "newest",
Expand All @@ -175,6 +179,7 @@ describe("HistoryPreview", () => {
it("passes correct props to TaskItem components", () => {
mockUseTaskSearch.mockReturnValue({
tasks: mockTasks.slice(0, 3),
recentTasks: mockTasks.slice(0, 3),
searchQuery: "",
setSearchQuery: vi.fn(),
sortOption: "newest",
Expand Down Expand Up @@ -228,4 +233,25 @@ describe("HistoryPreview", () => {

expect(container.firstChild).toHaveClass("flex", "flex-col", "gap-3")
})

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good addition of the fallback test case! Consider adding more edge cases:

  • What happens when both tasks and recentTasks are empty?
  • What happens when tasks has fewer than 3 items?
  • Test the interaction between filtered and recent tasks

it("falls back to recent tasks when filtered tasks are empty", () => {
mockUseTaskSearch.mockReturnValue({
tasks: [],
recentTasks: mockTasks,
searchQuery: "",
setSearchQuery: vi.fn(),
sortOption: "newest",
setSortOption: vi.fn(),
lastNonRelevantSort: null,
setLastNonRelevantSort: vi.fn(),
showAllWorkspaces: false,
setShowAllWorkspaces: vi.fn(),
})

render(<HistoryPreview />)

expect(screen.getByTestId("task-item-task-1")).toBeInTheDocument()
expect(screen.getByTestId("task-item-task-2")).toBeInTheDocument()
expect(screen.getByTestId("task-item-task-3")).toBeInTheDocument()
})
})
6 changes: 6 additions & 0 deletions webview-ui/src/components/history/useTaskSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export const useTaskSearch = () => {
return tasks
}, [taskHistory, showAllWorkspaces, cwd])

const recentTasks = useMemo(
() => [...presentableTasks].sort((a, b) => (b.ts || 0) - (a.ts || 0)),
[presentableTasks],
)

const fzf = useMemo(() => {
return new Fzf(presentableTasks, {
selector: (item) => item.task,
Expand Down Expand Up @@ -80,6 +85,7 @@ export const useTaskSearch = () => {

return {
tasks,
recentTasks,
searchQuery,
setSearchQuery,
sortOption,
Expand Down
8 changes: 8 additions & 0 deletions webview-ui/src/components/settings/ApiOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,14 @@ const ApiOptions = ({
<div className="flex flex-col gap-2">
<VSCodeButton
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates the button logic from CloudView.tsx. Consider extracting into a shared component to maintain DRY principles and ensure consistent behavior across the app.

appearance="primary"
onClick={() =>
vscode.postMessage({ type: "openExternal", url: "https://app.roocode.com/billing" })
}
className="w-fit">
{t("settings:providers.roo.startFreeTrialButton")}
</VSCodeButton>
<VSCodeButton
appearance="secondary"
onClick={() => vscode.postMessage({ type: "rooCloudSignIn" })}
className="w-fit">
{t("settings:providers.roo.connectButton")}
Expand Down
6 changes: 3 additions & 3 deletions webview-ui/src/i18n/locales/ca/cloud.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/ca/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions webview-ui/src/i18n/locales/de/cloud.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/de/settings.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions webview-ui/src/i18n/locales/en/cloud.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
"logOut": "Log out",
"testApiAuthentication": "Test API Authentication",
"signIn": "Connect to Roo Code Cloud",
"connect": "Get started",
"connect": "Connect to Roo Code Cloud",
"startFreeTrial": "Start a Free Trial of Roo Code Pro",
"cloudBenefitsTitle": "Try Roo Code Cloud",
"cloudBenefitWalkaway": "Follow and control tasks from anywhere (including your phone)",
"cloudBenefitWalkaway": "Follow and control tasks from anywhere, including your phone (Pro only)",
"cloudBenefitSharing": "Share tasks with others",
"cloudBenefitHistory": "Access your task history from anywhere",
"cloudBenefitMetrics": "Get a holistic view of your token consumption",
Expand All @@ -26,6 +27,6 @@
"upsell": {
"autoApprovePowerUser": "Giving Roo some independence? Control it from anywhere with Roo Code Cloud. <learnMoreLink>Learn more</learnMoreLink>.",
"longRunningTask": "This might take a while. Continue from anywhere with Cloud.",
"taskList": "Roo Code Cloud is here: follow and control your tasks from anywhere. <learnMoreLink>Learn more</learnMoreLink>."
"taskList": "πŸ’« CODE SUPERNOVA 🌌<lineBreak/>Astronomical context β€’ Long-running tasks β€’ Mobile management via Roo Code Pro<lineBreak/>Try both free today by selecting <providersLink>provider Roo Code Cloud</providersLink>"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a typo in the test procedure section of the PR description: "app.roocode.com/bililng" should be "app.roocode.com/billing" (missing 'l'). While this isn't in the code itself, it could cause confusion during testing.

}
}
3 changes: 2 additions & 1 deletion webview-ui/src/i18n/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,8 @@
},
"roo": {
"authenticatedMessage": "Securely authenticated through your Roo Code Cloud account.",
"connectButton": "Connect to Roo Code Cloud"
"connectButton": "Connect to Roo Code Cloud",
"startFreeTrialButton": "Start Free Pro Trial"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Start Free Pro Trial" button text should be properly internationalized. Currently it's hardcoded in English across all locale files. Consider using a translation key like "startFreeTrialButton" with appropriate translations for each locale.

},
"openRouter": {
"providerRouting": {
Expand Down
Loading
Loading