Skip to content

Commit 8b84ded

Browse files
committed
Merge branch 'main' into jq/save-browser-session
2 parents d6fb7a8 + 7eada8b commit 8b84ded

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2771
-1192
lines changed

.clinerules

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
- Logs can be found in `logs\app.log`
1717
- Logfile is overwritten on each run to keep it to a manageable volume.
1818

19+
4. Styling Guidelines:
20+
- Use Tailwind CSS classes instead of inline style objects for new markup
21+
- VSCode CSS variables must be added to webview-ui/src/index.css before using them in Tailwind classes
22+
- Example: `<div className="text-md text-vscode-descriptionForeground mb-2" />` instead of style objects
23+
1924

2025
# Adding a New Setting
2126

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Roo Code Changelog
22

3+
## [3.3.20]
4+
5+
- Support project-specific custom modes in a .roomodes file
6+
- Add more Mistral models (thanks @d-oit and @bramburn!)
7+
- By popular request, make it so Ask mode can't write to Markdown files and is purely for chatting with
8+
- Add a setting to control the number of open editor tabs to tell the model about (665 is probably too many!)
9+
- Fix race condition bug with entering API key on the welcome screen
10+
11+
## [3.3.19]
12+
13+
- Fix a bug where aborting in the middle of file writes would not revert the write
14+
- Honor the VS Code theme for dialog backgrounds
15+
- Make it possible to clear out the default custom instructions for built-in modes
16+
- Add a help button that links to our new documentation site (which we would love help from the community to improve!)
17+
- Switch checkpoints logic to use a shadow git repository to work around issues with hot reloads and polluting existing repositories (thanks Cline for the inspiration!)
18+
319
## [3.3.18]
420

521
- Add a per-API-configuration model temperature setting (thanks @joemanley201!)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
<a href="https://marketplace.visualstudio.com/items?itemName=RooVeterinaryInc.roo-cline" target="_blank"><img src="https://img.shields.io/badge/Download%20on%20VS%20Marketplace-blue?style=for-the-badge&logo=visualstudiocode&logoColor=white" alt="Download on VS Marketplace"></a>
1616
<a href="https://github.com/RooVetGit/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop" target="_blank"><img src="https://img.shields.io/badge/Feature%20Requests-yellow?style=for-the-badge" alt="Feature Requests"></a>
1717
<a href="https://marketplace.visualstudio.com/items?itemName=RooVeterinaryInc.roo-cline&ssr=false#review-details" target="_blank"><img src="https://img.shields.io/badge/Rate%20%26%20Review-green?style=for-the-badge" alt="Rate & Review"></a>
18+
<a href="https://docs.roocode.com" target="_blank"><img src="https://img.shields.io/badge/Documentation-6B46C1?style=for-the-badge&logo=readthedocs&logoColor=white" alt="Documentation"></a>
19+
1820
</div>
1921

2022
**Roo Code** is an AI-powered **autonomous coding agent** that lives in your editor. It can:

package-lock.json

Lines changed: 28 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"name": "roo-cline",
33
"displayName": "Roo Code (prev. Roo Cline)",
4-
"description": "A VS Code plugin that enhances coding with AI-powered automation, multi-model support, and experimental features.",
4+
"description": "An AI-powered autonomous coding agent that lives in your editor.",
55
"publisher": "RooVeterinaryInc",
6-
"version": "3.3.18",
6+
"version": "3.3.20",
77
"icon": "assets/icons/rocket.png",
88
"galleryBanner": {
99
"color": "#617A91",
@@ -99,6 +99,11 @@
9999
"title": "Settings",
100100
"icon": "$(settings-gear)"
101101
},
102+
{
103+
"command": "roo-cline.helpButtonClicked",
104+
"title": "Documentation",
105+
"icon": "$(question)"
106+
},
102107
{
103108
"command": "roo-cline.openInNewTab",
104109
"title": "Open In New Tab",
@@ -225,6 +230,11 @@
225230
"command": "roo-cline.settingsButtonClicked",
226231
"group": "navigation@6",
227232
"when": "view == roo-cline.SidebarProvider"
233+
},
234+
{
235+
"command": "roo-cline.helpButtonClicked",
236+
"group": "navigation@7",
237+
"when": "view == roo-cline.SidebarProvider"
228238
}
229239
]
230240
},
@@ -272,7 +282,9 @@
272282
"compile:integration": "tsc -p tsconfig.integration.json",
273283
"install:all": "npm install && cd webview-ui && npm install",
274284
"lint": "eslint src --ext ts && npm run lint --prefix webview-ui",
285+
"lint-local": "eslint -c .eslintrc.local.json src --ext ts && npm run lint --prefix webview-ui",
275286
"lint-fix": "eslint src --ext ts --fix && npm run lint-fix --prefix webview-ui",
287+
"lint-fix-local": "eslint -c .eslintrc.local.json src --ext ts --fix && npm run lint-fix --prefix webview-ui",
276288
"package": "npm run build:webview && npm run check-types && npm run lint && node esbuild.js --production",
277289
"pretest": "npm run compile && npm run compile:integration",
278290
"dev": "cd webview-ui && npm run dev",
@@ -314,6 +326,7 @@
314326
"diff-match-patch": "^1.0.5",
315327
"fast-deep-equal": "^3.1.3",
316328
"fastest-levenshtein": "^1.0.16",
329+
"get-folder-size": "^5.0.0",
317330
"globby": "^14.0.2",
318331
"isbinaryfile": "^5.0.2",
319332
"mammoth": "^1.8.0",
@@ -322,6 +335,7 @@
322335
"os-name": "^6.0.0",
323336
"p-wait-for": "^5.0.2",
324337
"pdf-parse": "^1.1.1",
338+
"pretty-bytes": "^6.1.1",
325339
"puppeteer-chromium-resolver": "^23.0.0",
326340
"puppeteer-core": "^23.4.0",
327341
"serialize-error": "^11.0.3",
@@ -352,17 +366,17 @@
352366
"@vscode/test-cli": "^0.0.9",
353367
"@vscode/test-electron": "^2.4.0",
354368
"esbuild": "^0.24.0",
355-
"mkdirp": "^3.0.1",
356-
"rimraf": "^6.0.1",
357369
"eslint": "^8.57.0",
358370
"glob": "^11.0.1",
359371
"husky": "^9.1.7",
360372
"jest": "^29.7.0",
361373
"jest-simple-dot-reporter": "^1.0.5",
362374
"lint-staged": "^15.2.11",
375+
"mkdirp": "^3.0.1",
363376
"mocha": "^11.1.0",
364377
"npm-run-all": "^4.1.5",
365378
"prettier": "^3.4.2",
379+
"rimraf": "^6.0.1",
366380
"ts-jest": "^29.2.5",
367381
"typescript": "^5.4.5"
368382
},

src/__mocks__/get-folder-size.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module.exports = async function getFolderSize() {
2+
return {
3+
size: 1000,
4+
errors: [],
5+
}
6+
}
7+
8+
module.exports.loose = async function getFolderSizeLoose() {
9+
return {
10+
size: 1000,
11+
errors: [],
12+
}
13+
}

src/activate/registerCommands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
3838
"roo-cline.historyButtonClicked": () => {
3939
provider.postMessageToWebview({ type: "action", action: "historyButtonClicked" })
4040
},
41+
"roo-cline.helpButtonClicked": () => {
42+
vscode.env.openExternal(vscode.Uri.parse("https://docs.roocode.com"))
43+
},
4144
}
4245
}
4346

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { MistralHandler } from "../mistral"
2+
import { ApiHandlerOptions, mistralDefaultModelId } from "../../../shared/api"
3+
import { Anthropic } from "@anthropic-ai/sdk"
4+
import { ApiStreamTextChunk } from "../../transform/stream"
5+
6+
// Mock Mistral client
7+
const mockCreate = jest.fn()
8+
jest.mock("@mistralai/mistralai", () => {
9+
return {
10+
Mistral: jest.fn().mockImplementation(() => ({
11+
chat: {
12+
stream: mockCreate.mockImplementation(async (options) => {
13+
const stream = {
14+
[Symbol.asyncIterator]: async function* () {
15+
yield {
16+
data: {
17+
choices: [
18+
{
19+
delta: { content: "Test response" },
20+
index: 0,
21+
},
22+
],
23+
},
24+
}
25+
},
26+
}
27+
return stream
28+
}),
29+
},
30+
})),
31+
}
32+
})
33+
34+
describe("MistralHandler", () => {
35+
let handler: MistralHandler
36+
let mockOptions: ApiHandlerOptions
37+
38+
beforeEach(() => {
39+
mockOptions = {
40+
apiModelId: "codestral-latest", // Update to match the actual model ID
41+
mistralApiKey: "test-api-key",
42+
includeMaxTokens: true,
43+
modelTemperature: 0,
44+
}
45+
handler = new MistralHandler(mockOptions)
46+
mockCreate.mockClear()
47+
})
48+
49+
describe("constructor", () => {
50+
it("should initialize with provided options", () => {
51+
expect(handler).toBeInstanceOf(MistralHandler)
52+
expect(handler.getModel().id).toBe(mockOptions.apiModelId)
53+
})
54+
55+
it("should throw error if API key is missing", () => {
56+
expect(() => {
57+
new MistralHandler({
58+
...mockOptions,
59+
mistralApiKey: undefined,
60+
})
61+
}).toThrow("Mistral API key is required")
62+
})
63+
64+
it("should use custom base URL if provided", () => {
65+
const customBaseUrl = "https://custom.mistral.ai/v1"
66+
const handlerWithCustomUrl = new MistralHandler({
67+
...mockOptions,
68+
mistralCodestralUrl: customBaseUrl,
69+
})
70+
expect(handlerWithCustomUrl).toBeInstanceOf(MistralHandler)
71+
})
72+
})
73+
74+
describe("getModel", () => {
75+
it("should return correct model info", () => {
76+
const model = handler.getModel()
77+
expect(model.id).toBe(mockOptions.apiModelId)
78+
expect(model.info).toBeDefined()
79+
expect(model.info.supportsPromptCache).toBe(false)
80+
})
81+
})
82+
83+
describe("createMessage", () => {
84+
const systemPrompt = "You are a helpful assistant."
85+
const messages: Anthropic.Messages.MessageParam[] = [
86+
{
87+
role: "user",
88+
content: [{ type: "text", text: "Hello!" }],
89+
},
90+
]
91+
92+
it("should create message successfully", async () => {
93+
const iterator = handler.createMessage(systemPrompt, messages)
94+
const result = await iterator.next()
95+
96+
expect(mockCreate).toHaveBeenCalledWith({
97+
model: mockOptions.apiModelId,
98+
messages: expect.any(Array),
99+
maxTokens: expect.any(Number),
100+
temperature: 0,
101+
})
102+
103+
expect(result.value).toBeDefined()
104+
expect(result.done).toBe(false)
105+
})
106+
107+
it("should handle streaming response correctly", async () => {
108+
const iterator = handler.createMessage(systemPrompt, messages)
109+
const results: ApiStreamTextChunk[] = []
110+
111+
for await (const chunk of iterator) {
112+
if ("text" in chunk) {
113+
results.push(chunk as ApiStreamTextChunk)
114+
}
115+
}
116+
117+
expect(results.length).toBeGreaterThan(0)
118+
expect(results[0].text).toBe("Test response")
119+
})
120+
121+
it("should handle errors gracefully", async () => {
122+
mockCreate.mockRejectedValueOnce(new Error("API Error"))
123+
await expect(handler.createMessage(systemPrompt, messages).next()).rejects.toThrow("API Error")
124+
})
125+
})
126+
})

0 commit comments

Comments
 (0)