Skip to content

Commit bfb97a3

Browse files
Revert "Merge branch 'main' into watsonx-ai-integration"
This reverts commit 798f3cc.
1 parent 798f3cc commit bfb97a3

File tree

12 files changed

+570
-9
lines changed

12 files changed

+570
-9
lines changed

CHANGELOG.md

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,39 @@
11
# Roo Code Changelog
22

3-
## 3.28.5
3+
## [3.28.7] - 2025-09-23
44

5-
### Patch Changes
5+
![3.28.7 Release - Hidden Thinking](/releases/3.28.7-release.png)
66

7-
- - Add an announcement for Supernova (thanks @mrubens!)
7+
- UX: Collapse thinking blocks by default with UI settings to always show them (thanks @brunobergher!)
8+
- Fix: Resolve checkpoint restore popover positioning issue (#8219 by @NaccOll, PR by @app/roomote)
9+
- Add cloud account switcher functionality (thanks @mrubens!)
10+
- Add support for zai-org/GLM-4.5-turbo model in Chutes provider (#8155 by @mugnimaestra, PR by @app/roomote)
11+
12+
## [3.28.6] - 2025-09-23
13+
14+
![3.28.6 Release - Kangaroo studying ancient codex](/releases/3.28.6-release.png)
15+
16+
- Feat: Add GPT-5-Codex model (thanks @daniel-lxs!)
17+
- Feat: Add keyboard shortcut for toggling auto-approve (Cmd/Ctrl+Alt+A) (thanks @brunobergher!)
18+
- Fix: Improve reasoning block formatting for better readability (thanks @daniel-lxs!)
19+
- Fix: Respect Ollama Modelfile num_ctx configuration (#7797 by @hannesrudolph, PR by @app/roomote)
20+
- Fix: Prevent checkpoint text from wrapping in non-English languages (#8206 by @NaccOll, PR by @app/roomote)
21+
- Remove language selection and word wrap toggle from CodeBlock (thanks @mrubens!)
22+
- Feat: Add package.nls.json checking to find-missing-translations script (thanks @app/roomote!)
23+
- Fix: Bare metal evals fixes (thanks @cte!)
24+
- Fix: Follow-up questions should trigger the "interactive" state (thanks @cte!)
25+
26+
## [3.28.5] - 2025-09-20
27+
28+
![3.28.5 Release - Kangaroo staying hydrated](/releases/3.28.5-release.png)
29+
30+
- Fix: Resolve duplicate rehydrate during reasoning; centralize rehydrate and preserve cancel metadata (#8153 by @hannesrudolph, PR by @hannesrudolph)
31+
- Add an announcement for Supernova (thanks @mrubens!)
32+
- Wrap code blocks by default for improved readability (thanks @mrubens!)
33+
- Fix: Support dash prefix in parseMarkdownChecklist for todo lists (#8054 by @NaccOll, PR by app/roomote)
34+
- Fix: Apply tiered pricing for Gemini models via Vertex AI (#8017 by @ikumi3, PR by app/roomote)
35+
- Update SambaNova models to latest versions (thanks @snova-jorgep!)
36+
- Update privacy policy to allow occasional emails (thanks @jdilla1277!)
837

938
## [3.28.4] - 2025-09-19
1039

apps/web-evals/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"dev": "scripts/check-services.sh && next dev -p 3446",
99
"format": "prettier --write src",
1010
"build": "next build",
11-
"start": "next start",
11+
"start": "next start -p 3446",
1212
"clean": "rimraf tsconfig.tsbuildinfo .next .turbo"
1313
},
1414
"dependencies": {
428 KB
Loading

apps/web-roo-code/src/lib/seo.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://roocode.com"
33
export const SEO = {
44
url: SITE_URL,
55
name: "Roo Code",
6-
title: "Roo Code – Your AI-Powered Dev Team in VS Code",
6+
title: "Roo Code – Your AI-Powered Dev Team in VS Code and Beyond",
77
description:
88
"Roo Code puts an entire AI dev team right in your editor, outpacing closed tools with deep project-wide context, multi-step agentic coding, and unmatched developer-centric flexibility.",
99
locale: "en_US",
1010
ogImage: {
11-
url: "/android-chrome-512x512.png",
12-
width: 512,
13-
height: 512,
14-
alt: "Roo Code Logo",
11+
url: "/opengraph.png",
12+
width: 1200,
13+
height: 600,
14+
alt: "Roo Code",
1515
},
1616
keywords: [
1717
"Roo Code",

releases/3.28.5-release.png

1.16 MB
Loading

releases/3.28.6-release.png

2 MB
Loading

releases/3.28.7-release.png

970 KB
Loading
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// npx vitest run src/components/chat/checkpoints/__tests__/CheckpointSaved.spec.tsx
2+
3+
vi.mock("@/components/ui", () => {
4+
// Minimal UI primitives to ensure deterministic behavior in tests
5+
return {
6+
Button: ({ children, ...rest }: any) => <button {...rest}>{children}</button>,
7+
StandardTooltip: ({ children }: any) => <>{children}</>,
8+
Popover: ({ children, onOpenChange, open }: any) => {
9+
lastOnOpenChange = onOpenChange
10+
return (
11+
<div data-testid="popover-root" data-open={open}>
12+
{children}
13+
</div>
14+
)
15+
},
16+
PopoverTrigger: ({ children }: any) => <div data-testid="popover-trigger">{children}</div>,
17+
PopoverContent: ({ children }: any) => <div data-testid="popover-content">{children}</div>,
18+
}
19+
})
20+
21+
import { render, waitFor, screen } from "@/utils/test-utils"
22+
import React from "react"
23+
import userEvent from "@testing-library/user-event"
24+
import { CheckpointSaved } from "../CheckpointSaved"
25+
26+
// Capture onOpenChange from Popover to control open/close in tests
27+
let lastOnOpenChange: ((open: boolean) => void) | undefined
28+
29+
const waitForOpenHandler = async () => {
30+
await waitFor(() => {
31+
// ensure Popover mock captured the onOpenChange handler before using it
32+
expect(lastOnOpenChange).toBeTruthy()
33+
})
34+
}
35+
36+
describe("CheckpointSaved popover visibility", () => {
37+
// Timers are controlled per-test to avoid interfering with i18n init
38+
const baseProps = {
39+
ts: 123,
40+
commitHash: "abc123",
41+
currentHash: "zzz999",
42+
checkpoint: { from: "prev123", to: "abc123" } as Record<string, unknown>,
43+
}
44+
45+
it("shows menu while popover is open and hides when closed", async () => {
46+
const { getByTestId } = render(<CheckpointSaved {...baseProps} />)
47+
48+
const getMenu = () => getByTestId("checkpoint-menu-container") as HTMLElement
49+
50+
// Initially hidden (relies on group-hover)
51+
expect(getMenu()).toBeTruthy()
52+
expect(getMenu().className).toContain("hidden")
53+
54+
// Open via captured handler
55+
await waitForOpenHandler()
56+
lastOnOpenChange?.(true)
57+
58+
await waitFor(() => {
59+
expect(getMenu().className).toContain("block")
60+
expect(getMenu().className).not.toContain("hidden")
61+
})
62+
63+
// Close via captured handler — menu remains visible briefly, then hides
64+
lastOnOpenChange?.(false)
65+
66+
await waitFor(() => {
67+
expect(getMenu().className).toContain("block")
68+
})
69+
70+
await waitFor(() => {
71+
expect(getMenu().className).toContain("hidden")
72+
})
73+
})
74+
75+
it("resets confirm state when popover closes", async () => {
76+
const { getByTestId } = render(<CheckpointSaved {...baseProps} />)
77+
78+
// Open the popover
79+
await waitForOpenHandler()
80+
lastOnOpenChange?.(true)
81+
82+
// Enter confirm state
83+
const restoreFilesAndTaskBtn = await waitFor(() => getByTestId("restore-files-and-task-btn"))
84+
await userEvent.click(restoreFilesAndTaskBtn)
85+
86+
// Confirm warning should be visible
87+
expect(getByTestId("checkpoint-confirm-warning")).toBeTruthy()
88+
89+
// Close popover -> confirm state should reset
90+
lastOnOpenChange?.(false)
91+
92+
// Reopen
93+
lastOnOpenChange?.(true)
94+
95+
// Confirm warning should be gone after reopening
96+
await waitFor(() => {
97+
expect(screen.queryByTestId("checkpoint-confirm-warning")).toBeNull()
98+
})
99+
})
100+
101+
it("closes popover after preview and after confirm restore", async () => {
102+
const { getByTestId } = render(<CheckpointSaved {...baseProps} />)
103+
104+
const popoverRoot = () => getByTestId("popover-root")
105+
const menuContainer = () => getByTestId("checkpoint-menu-container")
106+
107+
// Open
108+
await waitForOpenHandler()
109+
lastOnOpenChange?.(true)
110+
await waitFor(() => {
111+
expect(popoverRoot().getAttribute("data-open")).toBe("true")
112+
expect(menuContainer().className).toContain("block")
113+
})
114+
115+
// Click preview -> popover closes; menu remains briefly visible, then hides
116+
await userEvent.click(getByTestId("restore-files-btn"))
117+
await waitFor(() => {
118+
expect(popoverRoot().getAttribute("data-open")).toBe("false")
119+
expect(menuContainer().className).toContain("block")
120+
})
121+
await waitFor(() => {
122+
expect(menuContainer().className).toContain("hidden")
123+
})
124+
125+
// Reopen
126+
lastOnOpenChange?.(true)
127+
await waitFor(() => {
128+
expect(popoverRoot().getAttribute("data-open")).toBe("true")
129+
})
130+
131+
// Enter confirm and confirm restore -> popover closes; menu then hides
132+
await userEvent.click(getByTestId("restore-files-and-task-btn"))
133+
await userEvent.click(getByTestId("confirm-restore-btn"))
134+
await waitFor(() => {
135+
expect(popoverRoot().getAttribute("data-open")).toBe("false")
136+
})
137+
await waitFor(() => {
138+
expect(menuContainer().className).toContain("hidden")
139+
})
140+
})
141+
})
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { useState, useEffect } from "react"
2+
import { Building2 } from "lucide-react"
3+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectSeparator } from "@/components/ui/select"
4+
import { useAppTranslation } from "@src/i18n/TranslationContext"
5+
import { vscode } from "@src/utils/vscode"
6+
import { useExtensionState } from "@src/context/ExtensionStateContext"
7+
import { cn } from "@src/lib/utils"
8+
9+
export const CloudAccountSwitcher = () => {
10+
const { t } = useAppTranslation()
11+
const { cloudUserInfo, cloudOrganizations = [] } = useExtensionState()
12+
const [selectedOrgId, setSelectedOrgId] = useState<string | null>(cloudUserInfo?.organizationId || null)
13+
const [isLoading, setIsLoading] = useState(false)
14+
15+
// Update selected org when userInfo changes
16+
useEffect(() => {
17+
setSelectedOrgId(cloudUserInfo?.organizationId || null)
18+
}, [cloudUserInfo?.organizationId])
19+
20+
// Don't show the switcher if user has no organizations
21+
if (!cloudOrganizations || cloudOrganizations.length === 0 || !cloudUserInfo) {
22+
return null
23+
}
24+
25+
const handleOrganizationChange = async (value: string) => {
26+
const newOrgId = value === "personal" ? null : value
27+
28+
// Don't do anything if selecting the same organization
29+
if (newOrgId === selectedOrgId) {
30+
return
31+
}
32+
33+
setIsLoading(true)
34+
35+
// Send message to switch organization
36+
vscode.postMessage({
37+
type: "switchOrganization",
38+
organizationId: newOrgId,
39+
})
40+
41+
// Update local state optimistically
42+
setSelectedOrgId(newOrgId)
43+
44+
// Reset loading state after a delay
45+
setTimeout(() => {
46+
setIsLoading(false)
47+
}, 1000)
48+
}
49+
50+
const currentValue = selectedOrgId || "personal"
51+
const currentOrg = cloudOrganizations.find((org) => org.organization.id === selectedOrgId)
52+
53+
// Render the account icon based on current context
54+
const renderAccountIcon = () => {
55+
if (selectedOrgId && currentOrg?.organization.image_url) {
56+
// Organization with logo
57+
return (
58+
<img
59+
src={currentOrg.organization.image_url}
60+
alt={currentOrg.organization.name}
61+
className="w-5 h-5 rounded object-cover"
62+
/>
63+
)
64+
} else if (selectedOrgId) {
65+
// Organization without logo
66+
return <Building2 className="w-4.5 h-4.5" />
67+
} else if (cloudUserInfo.picture) {
68+
// Personal account with avatar
69+
return (
70+
<img
71+
src={cloudUserInfo.picture}
72+
alt={cloudUserInfo.name || cloudUserInfo.email}
73+
className="w-5 h-5 rounded-full object-cover"
74+
/>
75+
)
76+
} else {
77+
// Personal account without avatar - show initials
78+
const initial = cloudUserInfo.name?.charAt(0) || cloudUserInfo.email?.charAt(0) || "?"
79+
return (
80+
<div className="w-5 h-5 rounded-full flex items-center justify-center bg-vscode-button-background text-vscode-button-foreground text-xs">
81+
{initial}
82+
</div>
83+
)
84+
}
85+
}
86+
87+
return (
88+
<div className="inline-block ml-1">
89+
<Select value={currentValue} onValueChange={handleOrganizationChange} disabled={isLoading}>
90+
<SelectTrigger
91+
className={cn(
92+
"h-4.5 w-4.5 p-0 gap-0",
93+
"bg-transparent opacity-90 hover:opacity-50",
94+
"flex items-center justify-center",
95+
"rounded-lg overflow-clip",
96+
"border border-vscode-dropdown-border",
97+
"[&>svg]:hidden", // Hide the default chevron/caret
98+
isLoading && "opacity-50",
99+
)}
100+
aria-label={selectedOrgId ? currentOrg?.organization.name : t("cloud:personalAccount")}>
101+
{renderAccountIcon()}
102+
</SelectTrigger>
103+
104+
<SelectContent>
105+
{/* Personal Account Option */}
106+
<SelectItem value="personal">
107+
<div className="flex items-center gap-2">
108+
{cloudUserInfo.picture ? (
109+
<img
110+
src={cloudUserInfo.picture}
111+
alt={cloudUserInfo.name || cloudUserInfo.email}
112+
className="w-4.5 h-4.5 rounded-full object-cover overflow-clip"
113+
/>
114+
) : (
115+
<div className="w-4.5 h-4.5 rounded-full flex items-center justify-center bg-vscode-button-background text-vscode-button-foreground text-xs">
116+
{cloudUserInfo.name?.charAt(0) || cloudUserInfo.email?.charAt(0) || "?"}
117+
</div>
118+
)}
119+
<span>{t("cloud:personalAccount")}</span>
120+
</div>
121+
</SelectItem>
122+
123+
{cloudOrganizations.length > 0 && <SelectSeparator />}
124+
125+
{/* Organization Options */}
126+
{cloudOrganizations.map((org) => (
127+
<SelectItem key={org.organization.id} value={org.organization.id}>
128+
<div className="flex items-center gap-2">
129+
{org.organization.image_url ? (
130+
<img
131+
src={org.organization.image_url}
132+
alt=""
133+
className="w-4.5 h-4.5 rounded-full object-cover overflow-clip"
134+
/>
135+
) : (
136+
<Building2 className="w-4.5 h-4.5" />
137+
)}
138+
<span className="truncate">{org.organization.name}</span>
139+
</div>
140+
</SelectItem>
141+
))}
142+
</SelectContent>
143+
</Select>
144+
</div>
145+
)
146+
}

0 commit comments

Comments
 (0)