Skip to content

Commit 522d716

Browse files
committed
Merge branch 'main' of https://github.com/RooVetGit/Roo-Cline into chores/remove-ai-releases
2 parents 5aa2634 + 5b682fe commit 522d716

File tree

19 files changed

+825
-156
lines changed

19 files changed

+825
-156
lines changed

.changeset/eighty-nails-peel.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+
Add volume slider in settings and change sound effects to only trigger when user intervention is required, an error occurs, or a task is completed.

.changeset/shaggy-moons-dance.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+
Fix lint errors and change npm run lint to also run on webview-ui

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Roo Cline Changelog
22

3+
## [2.2.12]
4+
5+
- Better support for pure deletion and insertion diffs
6+
37
## [2.2.11]
48

59
- Added settings checkbox for verbose diff debugging

package-lock.json

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

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Roo Cline",
44
"description": "A fork of Cline, an autonomous coding agent, with some added experimental configuration and automation features.",
55
"publisher": "RooVeterinaryInc",
6-
"version": "2.2.11",
6+
"version": "2.2.12",
77
"icon": "assets/icons/rocket.png",
88
"galleryBanner": {
99
"color": "#617A91",
@@ -153,7 +153,7 @@
153153
"compile": "npm run check-types && npm run lint && node esbuild.js",
154154
"compile-tests": "tsc -p . --outDir out",
155155
"install:all": "npm install && cd webview-ui && npm install",
156-
"lint": "eslint src --ext ts",
156+
"lint": "eslint src --ext ts && npm run lint --prefix webview-ui",
157157
"package": "npm run build:webview && npm run check-types && npm run lint && node esbuild.js --production",
158158
"pretest": "npm run compile-tests && npm run compile && npm run lint",
159159
"start:webview": "cd webview-ui && npm run start",
@@ -217,10 +217,10 @@
217217
"os-name": "^6.0.0",
218218
"p-wait-for": "^5.0.2",
219219
"pdf-parse": "^1.1.1",
220-
"play-sound": "^1.1.6",
221220
"puppeteer-chromium-resolver": "^23.0.0",
222221
"puppeteer-core": "^23.4.0",
223222
"serialize-error": "^11.0.3",
223+
"sound-play": "^1.1.0",
224224
"strip-ansi": "^7.1.0",
225225
"tree-sitter-wasms": "^0.1.11",
226226
"turndown": "^7.2.0",

src/core/diff/strategies/__tests__/search-replace.test.ts

Lines changed: 228 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,26 @@ this.init();
591591
expect(result.content).toBe('function test() {\n return false;\n}\n')
592592
}
593593
})
594+
595+
it('should strip line numbers with leading spaces', () => {
596+
const originalContent = 'function test() {\n return true;\n}\n'
597+
const diffContent = `test.ts
598+
<<<<<<< SEARCH
599+
1 | function test() {
600+
2 | return true;
601+
3 | }
602+
=======
603+
1 | function test() {
604+
2 | return false;
605+
3 | }
606+
>>>>>>> REPLACE`
607+
608+
const result = strategy.applyDiff(originalContent, diffContent)
609+
expect(result.success).toBe(true)
610+
if (result.success) {
611+
expect(result.content).toBe('function test() {\n return false;\n}\n')
612+
}
613+
})
594614

595615
it('should not strip when not all lines have numbers in either section', () => {
596616
const originalContent = 'function test() {\n return true;\n}\n'
@@ -711,6 +731,212 @@ this.init();
711731
})
712732
});
713733

734+
describe('insertion/deletion', () => {
735+
let strategy: SearchReplaceDiffStrategy
736+
737+
beforeEach(() => {
738+
strategy = new SearchReplaceDiffStrategy()
739+
})
740+
741+
describe('deletion', () => {
742+
it('should delete code when replace block is empty', () => {
743+
const originalContent = `function test() {
744+
console.log("hello");
745+
// Comment to remove
746+
console.log("world");
747+
}`
748+
const diffContent = `test.ts
749+
<<<<<<< SEARCH
750+
// Comment to remove
751+
=======
752+
>>>>>>> REPLACE`
753+
754+
const result = strategy.applyDiff(originalContent, diffContent)
755+
expect(result.success).toBe(true)
756+
if (result.success) {
757+
expect(result.content).toBe(`function test() {
758+
console.log("hello");
759+
console.log("world");
760+
}`)
761+
}
762+
})
763+
764+
it('should delete multiple lines when replace block is empty', () => {
765+
const originalContent = `class Example {
766+
constructor() {
767+
// Initialize
768+
this.value = 0;
769+
// Set defaults
770+
this.name = "";
771+
// End init
772+
}
773+
}`
774+
const diffContent = `test.ts
775+
<<<<<<< SEARCH
776+
// Initialize
777+
this.value = 0;
778+
// Set defaults
779+
this.name = "";
780+
// End init
781+
=======
782+
>>>>>>> REPLACE`
783+
784+
const result = strategy.applyDiff(originalContent, diffContent)
785+
expect(result.success).toBe(true)
786+
if (result.success) {
787+
expect(result.content).toBe(`class Example {
788+
constructor() {
789+
}
790+
}`)
791+
}
792+
})
793+
794+
it('should preserve indentation when deleting nested code', () => {
795+
const originalContent = `function outer() {
796+
if (true) {
797+
// Remove this
798+
console.log("test");
799+
// And this
800+
}
801+
return true;
802+
}`
803+
const diffContent = `test.ts
804+
<<<<<<< SEARCH
805+
// Remove this
806+
console.log("test");
807+
// And this
808+
=======
809+
>>>>>>> REPLACE`
810+
811+
const result = strategy.applyDiff(originalContent, diffContent)
812+
expect(result.success).toBe(true)
813+
if (result.success) {
814+
expect(result.content).toBe(`function outer() {
815+
if (true) {
816+
}
817+
return true;
818+
}`)
819+
}
820+
})
821+
})
822+
823+
describe('insertion', () => {
824+
it('should insert code at specified line when search block is empty', () => {
825+
const originalContent = `function test() {
826+
const x = 1;
827+
return x;
828+
}`
829+
const diffContent = `test.ts
830+
<<<<<<< SEARCH
831+
=======
832+
console.log("Adding log");
833+
>>>>>>> REPLACE`
834+
835+
const result = strategy.applyDiff(originalContent, diffContent, 2, 2)
836+
expect(result.success).toBe(true)
837+
if (result.success) {
838+
expect(result.content).toBe(`function test() {
839+
console.log("Adding log");
840+
const x = 1;
841+
return x;
842+
}`)
843+
}
844+
})
845+
846+
it('should preserve indentation when inserting at nested location', () => {
847+
const originalContent = `function test() {
848+
if (true) {
849+
const x = 1;
850+
}
851+
}`
852+
const diffContent = `test.ts
853+
<<<<<<< SEARCH
854+
=======
855+
console.log("Before");
856+
console.log("After");
857+
>>>>>>> REPLACE`
858+
859+
const result = strategy.applyDiff(originalContent, diffContent, 3, 3)
860+
expect(result.success).toBe(true)
861+
if (result.success) {
862+
expect(result.content).toBe(`function test() {
863+
if (true) {
864+
console.log("Before");
865+
console.log("After");
866+
const x = 1;
867+
}
868+
}`)
869+
}
870+
})
871+
872+
it('should handle insertion at start of file', () => {
873+
const originalContent = `function test() {
874+
return true;
875+
}`
876+
const diffContent = `test.ts
877+
<<<<<<< SEARCH
878+
=======
879+
// Copyright 2024
880+
// License: MIT
881+
882+
>>>>>>> REPLACE`
883+
884+
const result = strategy.applyDiff(originalContent, diffContent, 1, 1)
885+
expect(result.success).toBe(true)
886+
if (result.success) {
887+
expect(result.content).toBe(`// Copyright 2024
888+
// License: MIT
889+
890+
function test() {
891+
return true;
892+
}`)
893+
}
894+
})
895+
896+
it('should handle insertion at end of file', () => {
897+
const originalContent = `function test() {
898+
return true;
899+
}`
900+
const diffContent = `test.ts
901+
<<<<<<< SEARCH
902+
=======
903+
904+
// End of file
905+
>>>>>>> REPLACE`
906+
907+
const result = strategy.applyDiff(originalContent, diffContent, 4, 4)
908+
expect(result.success).toBe(true)
909+
if (result.success) {
910+
expect(result.content).toBe(`function test() {
911+
return true;
912+
}
913+
914+
// End of file`)
915+
}
916+
})
917+
918+
it('should insert at the start of the file if no start_line is provided for insertion', () => {
919+
const originalContent = `function test() {
920+
return true;
921+
}`
922+
const diffContent = `test.ts
923+
<<<<<<< SEARCH
924+
=======
925+
console.log("test");
926+
>>>>>>> REPLACE`
927+
928+
const result = strategy.applyDiff(originalContent, diffContent)
929+
expect(result.success).toBe(true)
930+
if (result.success) {
931+
expect(result.content).toBe(`console.log("test");
932+
function test() {
933+
return true;
934+
}`)
935+
}
936+
})
937+
})
938+
})
939+
714940
describe('fuzzy matching', () => {
715941
let strategy: SearchReplaceDiffStrategy
716942

@@ -1241,8 +1467,8 @@ function two() {
12411467

12421468
it('should document start_line and end_line parameters', () => {
12431469
const description = strategy.getToolDescription('/test')
1244-
expect(description).toContain('start_line: (required) The line number where the search block starts.')
1245-
expect(description).toContain('end_line: (required) The line number where the search block ends.')
1470+
expect(description).toContain('start_line: (required) The line number where the search block starts (inclusive).')
1471+
expect(description).toContain('end_line: (required) The line number where the search block ends (inclusive).')
12461472
})
12471473
})
12481474
})

0 commit comments

Comments
 (0)