Skip to content

Commit a9d8a1d

Browse files
authored
Merge branch 'main' into mistral
2 parents 8a5563b + c815ea7 commit a9d8a1d

Some content is hidden

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

47 files changed

+2517
-1184
lines changed

.changeset/clever-news-arrive.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
Disable writing in ask mode

.changeset/orange-geese-provide.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Roo Code Changelog
22

3+
## [3.3.19]
4+
5+
- Fix a bug where aborting in the middle of file writes would not revert the write
6+
- Honor the VS Code theme for dialog backgrounds
7+
- Make it possible to clear out the default custom instructions for built-in modes
8+
- Add a help button that links to our new documentation site (which we would love help from the community to improve!)
9+
- 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!)
10+
311
## [3.3.18]
412

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

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: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Roo Code (prev. Roo Cline)",
44
"description": "A VS Code plugin that enhances coding with AI-powered automation, multi-model support, and experimental features.",
55
"publisher": "RooVeterinaryInc",
6-
"version": "3.3.18",
6+
"version": "3.3.19",
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

src/core/Cline.ts

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import delay from "delay"
66
import fs from "fs/promises"
77
import os from "os"
88
import pWaitFor from "p-wait-for"
9+
import getFolderSize from "get-folder-size"
910
import * as path from "path"
1011
import { serializeError } from "serialize-error"
1112
import * as vscode from "vscode"
1213
import { ApiHandler, SingleCompletionHandler, buildApiHandler } from "../api"
1314
import { ApiStream } from "../api/transform/stream"
1415
import { DIFF_VIEW_URI_SCHEME, DiffViewProvider } from "../integrations/editor/DiffViewProvider"
15-
import { CheckpointService } from "../services/checkpoints/CheckpointService"
16+
import { CheckpointService, CheckpointServiceFactory } from "../services/checkpoints"
1617
import { findToolName, formatContentBlockToMarkdown } from "../integrations/misc/export-markdown"
1718
import {
1819
extractTextFromFile,
@@ -239,7 +240,8 @@ export class Cline {
239240

240241
private async saveClineMessages() {
241242
try {
242-
const filePath = path.join(await this.ensureTaskDirectoryExists(), GlobalFileNames.uiMessages)
243+
const taskDir = await this.ensureTaskDirectoryExists()
244+
const filePath = path.join(taskDir, GlobalFileNames.uiMessages)
243245
await fs.writeFile(filePath, JSON.stringify(this.clineMessages))
244246
// combined as they are in ChatView
245247
const apiMetrics = getApiMetrics(combineApiRequests(combineCommandSequences(this.clineMessages.slice(1))))
@@ -251,6 +253,17 @@ export class Cline {
251253
(m) => !(m.ask === "resume_task" || m.ask === "resume_completed_task"),
252254
)
253255
]
256+
257+
let taskDirSize = 0
258+
259+
try {
260+
taskDirSize = await getFolderSize.loose(taskDir)
261+
} catch (err) {
262+
console.error(
263+
`[saveClineMessages] failed to get task directory size (${taskDir}): ${err instanceof Error ? err.message : String(err)}`,
264+
)
265+
}
266+
254267
await this.providerRef.deref()?.updateTaskHistory({
255268
id: this.taskId,
256269
ts: lastRelevantMessage.ts,
@@ -260,6 +273,7 @@ export class Cline {
260273
cacheWrites: apiMetrics.totalCacheWrites,
261274
cacheReads: apiMetrics.totalCacheReads,
262275
totalCost: apiMetrics.totalCost,
276+
size: taskDirSize,
263277
})
264278
} catch (error) {
265279
console.error("Failed to save cline messages:", error)
@@ -2692,7 +2706,7 @@ export class Cline {
26922706
}
26932707

26942708
if (isCheckpointPossible) {
2695-
await this.checkpointSave()
2709+
await this.checkpointSave({ isFirst: false })
26962710
}
26972711

26982712
/*
@@ -2762,7 +2776,7 @@ export class Cline {
27622776
const isFirstRequest = this.clineMessages.filter((m) => m.say === "api_req_started").length === 0
27632777

27642778
if (isFirstRequest) {
2765-
await this.checkpointSave()
2779+
await this.checkpointSave({ isFirst: true })
27662780
}
27672781

27682782
// getting verbose details is an expensive operation, it uses globby to top-down build file structure of project which for large projects can take a few seconds
@@ -3098,11 +3112,14 @@ export class Cline {
30983112
}
30993113

31003114
details += "\n\n# VSCode Open Tabs"
3115+
const { maxOpenTabsContext } = (await this.providerRef.deref()?.getState()) ?? {}
3116+
const maxTabs = maxOpenTabsContext ?? 20
31013117
const openTabs = vscode.window.tabGroups.all
31023118
.flatMap((group) => group.tabs)
31033119
.map((tab) => (tab.input as vscode.TabInputText)?.uri?.fsPath)
31043120
.filter(Boolean)
31053121
.map((absolutePath) => path.relative(cwd, absolutePath).toPosix())
3122+
.slice(0, maxTabs)
31063123
.join("\n")
31073124
if (openTabs) {
31083125
details += `\n${openTabs}`
@@ -3255,11 +3272,32 @@ export class Cline {
32553272
// Checkpoints
32563273

32573274
private async getCheckpointService() {
3275+
if (!this.checkpointsEnabled) {
3276+
throw new Error("Checkpoints are disabled")
3277+
}
3278+
32583279
if (!this.checkpointService) {
3259-
this.checkpointService = await CheckpointService.create({
3260-
taskId: this.taskId,
3261-
baseDir: vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) ?? "",
3262-
log: (message) => this.providerRef.deref()?.log(message),
3280+
const workspaceDir = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0)
3281+
const shadowDir = this.providerRef.deref()?.context.globalStorageUri.fsPath
3282+
3283+
if (!workspaceDir) {
3284+
this.providerRef.deref()?.log("[getCheckpointService] workspace folder not found")
3285+
throw new Error("Workspace directory not found")
3286+
}
3287+
3288+
if (!shadowDir) {
3289+
this.providerRef.deref()?.log("[getCheckpointService] shadowDir not found")
3290+
throw new Error("Global storage directory not found")
3291+
}
3292+
3293+
this.checkpointService = await CheckpointServiceFactory.create({
3294+
strategy: "shadow",
3295+
options: {
3296+
taskId: this.taskId,
3297+
workspaceDir,
3298+
shadowDir,
3299+
log: (message) => this.providerRef.deref()?.log(message),
3300+
},
32633301
})
32643302
}
32653303

@@ -3318,29 +3356,25 @@ export class Cline {
33183356
}
33193357
}
33203358

3321-
public async checkpointSave() {
3359+
public async checkpointSave({ isFirst }: { isFirst: boolean }) {
33223360
if (!this.checkpointsEnabled) {
33233361
return
33243362
}
33253363

33263364
try {
3327-
const isFirst = !this.checkpointService
33283365
const service = await this.getCheckpointService()
3329-
const commit = await service.saveCheckpoint(`Task: ${this.taskId}, Time: ${Date.now()}`)
3366+
const strategy = service.strategy
3367+
const version = service.version
33303368

3331-
if (commit?.commit) {
3332-
await this.providerRef
3333-
.deref()
3334-
?.postMessageToWebview({ type: "currentCheckpointUpdated", text: service.currentCheckpoint })
3369+
const commit = await service.saveCheckpoint(`Task: ${this.taskId}, Time: ${Date.now()}`)
3370+
const fromHash = service.baseHash
3371+
const toHash = isFirst ? commit?.commit || fromHash : commit?.commit
33353372

3336-
// Checkpoint metadata required by the UI.
3337-
const checkpoint = {
3338-
isFirst,
3339-
from: service.baseCommitHash,
3340-
to: commit.commit,
3341-
}
3373+
if (toHash) {
3374+
await this.providerRef.deref()?.postMessageToWebview({ type: "currentCheckpointUpdated", text: toHash })
33423375

3343-
await this.say("checkpoint_saved", commit.commit, undefined, undefined, checkpoint)
3376+
const checkpoint = { isFirst, from: fromHash, to: toHash, strategy, version }
3377+
await this.say("checkpoint_saved", toHash, undefined, undefined, checkpoint)
33443378
}
33453379
} catch (err) {
33463380
this.providerRef.deref()?.log("[checkpointSave] disabling checkpoints for this task")
@@ -3371,9 +3405,7 @@ export class Cline {
33713405
const service = await this.getCheckpointService()
33723406
await service.restoreCheckpoint(commitHash)
33733407

3374-
await this.providerRef
3375-
.deref()
3376-
?.postMessageToWebview({ type: "currentCheckpointUpdated", text: service.currentCheckpoint })
3408+
await this.providerRef.deref()?.postMessageToWebview({ type: "currentCheckpointUpdated", text: commitHash })
33773409

33783410
if (mode === "restore") {
33793411
await this.overwriteApiConversationHistory(

0 commit comments

Comments
 (0)