mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Merge branch 'main' into jq/sound-setting-improvements
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# Roo Cline Changelog
|
# Roo Cline Changelog
|
||||||
|
|
||||||
|
## [2.2.11]
|
||||||
|
|
||||||
|
- Added settings checkbox for verbose diff debugging
|
||||||
|
|
||||||
## [2.2.6 - 2.2.10]
|
## [2.2.6 - 2.2.10]
|
||||||
|
|
||||||
- More fixes to search/replace diffs
|
- More fixes to search/replace diffs
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "roo-cline",
|
"name": "roo-cline",
|
||||||
"version": "2.2.10",
|
"version": "2.2.11",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "roo-cline",
|
"name": "roo-cline",
|
||||||
"version": "2.2.10",
|
"version": "2.2.11",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/bedrock-sdk": "^0.10.2",
|
"@anthropic-ai/bedrock-sdk": "^0.10.2",
|
||||||
"@anthropic-ai/sdk": "^0.26.0",
|
"@anthropic-ai/sdk": "^0.26.0",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"displayName": "Roo Cline",
|
"displayName": "Roo Cline",
|
||||||
"description": "A fork of Cline, an autonomous coding agent, with some added experimental configuration and automation features.",
|
"description": "A fork of Cline, an autonomous coding agent, with some added experimental configuration and automation features.",
|
||||||
"publisher": "RooVeterinaryInc",
|
"publisher": "RooVeterinaryInc",
|
||||||
"version": "2.2.10",
|
"version": "2.2.11",
|
||||||
"icon": "assets/icons/rocket.png",
|
"icon": "assets/icons/rocket.png",
|
||||||
"galleryBanner": {
|
"galleryBanner": {
|
||||||
"color": "#617A91",
|
"color": "#617A91",
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ export class Cline {
|
|||||||
apiConfiguration: ApiConfiguration,
|
apiConfiguration: ApiConfiguration,
|
||||||
customInstructions?: string,
|
customInstructions?: string,
|
||||||
diffEnabled?: boolean,
|
diffEnabled?: boolean,
|
||||||
|
debugDiffEnabled?: boolean,
|
||||||
task?: string,
|
task?: string,
|
||||||
images?: string[],
|
images?: string[],
|
||||||
historyItem?: HistoryItem,
|
historyItem?: HistoryItem,
|
||||||
@@ -109,7 +110,7 @@ export class Cline {
|
|||||||
this.diffViewProvider = new DiffViewProvider(cwd)
|
this.diffViewProvider = new DiffViewProvider(cwd)
|
||||||
this.customInstructions = customInstructions
|
this.customInstructions = customInstructions
|
||||||
if (diffEnabled && this.api.getModel().id) {
|
if (diffEnabled && this.api.getModel().id) {
|
||||||
this.diffStrategy = getDiffStrategy(this.api.getModel().id)
|
this.diffStrategy = getDiffStrategy(this.api.getModel().id, debugDiffEnabled)
|
||||||
}
|
}
|
||||||
if (historyItem) {
|
if (historyItem) {
|
||||||
this.taskId = historyItem.id
|
this.taskId = historyItem.id
|
||||||
@@ -1237,7 +1238,12 @@ export class Cline {
|
|||||||
const originalContent = await fs.readFile(absolutePath, "utf-8")
|
const originalContent = await fs.readFile(absolutePath, "utf-8")
|
||||||
|
|
||||||
// Apply the diff to the original content
|
// Apply the diff to the original content
|
||||||
const diffResult = this.diffStrategy?.applyDiff(originalContent, diffContent) ?? {
|
const diffResult = this.diffStrategy?.applyDiff(
|
||||||
|
originalContent,
|
||||||
|
diffContent,
|
||||||
|
parseInt(block.params.start_line ?? ''),
|
||||||
|
parseInt(block.params.end_line ?? '')
|
||||||
|
) ?? {
|
||||||
success: false,
|
success: false,
|
||||||
error: "No diff strategy available"
|
error: "No diff strategy available"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -278,7 +278,8 @@ describe('Cline', () => {
|
|||||||
mockProvider,
|
mockProvider,
|
||||||
mockApiConfig,
|
mockApiConfig,
|
||||||
'custom instructions',
|
'custom instructions',
|
||||||
false,
|
false, // diffEnabled
|
||||||
|
false, // debugDiffEnabled
|
||||||
'test task'
|
'test task'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ export const toolParamNames = [
|
|||||||
"question",
|
"question",
|
||||||
"result",
|
"result",
|
||||||
"diff",
|
"diff",
|
||||||
|
"start_line",
|
||||||
|
"end_line",
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export type ToolParamName = (typeof toolParamNames)[number]
|
export type ToolParamName = (typeof toolParamNames)[number]
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import { SearchReplaceDiffStrategy } from './strategies/search-replace'
|
|||||||
* @param model The name of the model being used (e.g., 'gpt-4', 'claude-3-opus')
|
* @param model The name of the model being used (e.g., 'gpt-4', 'claude-3-opus')
|
||||||
* @returns The appropriate diff strategy for the model
|
* @returns The appropriate diff strategy for the model
|
||||||
*/
|
*/
|
||||||
export function getDiffStrategy(model: string): DiffStrategy {
|
export function getDiffStrategy(model: string, debugEnabled?: boolean): DiffStrategy {
|
||||||
// For now, return SearchReplaceDiffStrategy for all models (with a fuzzy threshold of 0.9)
|
// For now, return SearchReplaceDiffStrategy for all models (with a fuzzy threshold of 0.9)
|
||||||
// This architecture allows for future optimizations based on model capabilities
|
// This architecture allows for future optimizations based on model capabilities
|
||||||
return new SearchReplaceDiffStrategy(0.9)
|
return new SearchReplaceDiffStrategy(0.9, debugEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { DiffStrategy }
|
export type { DiffStrategy }
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { DiffStrategy, DiffResult } from "../types"
|
import { DiffStrategy, DiffResult } from "../types"
|
||||||
|
import { addLineNumbers } from "../../../integrations/misc/extract-text"
|
||||||
|
|
||||||
|
const BUFFER_LINES = 5; // Number of extra context lines to show before and after matches
|
||||||
|
|
||||||
function levenshteinDistance(a: string, b: string): number {
|
function levenshteinDistance(a: string, b: string): number {
|
||||||
const matrix: number[][] = [];
|
const matrix: number[][] = [];
|
||||||
@@ -48,10 +51,12 @@ function getSimilarity(original: string, search: string): number {
|
|||||||
|
|
||||||
export class SearchReplaceDiffStrategy implements DiffStrategy {
|
export class SearchReplaceDiffStrategy implements DiffStrategy {
|
||||||
private fuzzyThreshold: number;
|
private fuzzyThreshold: number;
|
||||||
|
public debugEnabled: boolean;
|
||||||
|
|
||||||
constructor(fuzzyThreshold?: number) {
|
constructor(fuzzyThreshold?: number, debugEnabled?: boolean) {
|
||||||
// Default to exact matching (1.0) unless fuzzy threshold specified
|
// Default to exact matching (1.0) unless fuzzy threshold specified
|
||||||
this.fuzzyThreshold = fuzzyThreshold ?? 1.0;
|
this.fuzzyThreshold = fuzzyThreshold ?? 1.0;
|
||||||
|
this.debugEnabled = debugEnabled ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getToolDescription(cwd: string): string {
|
getToolDescription(cwd: string): string {
|
||||||
@@ -119,15 +124,11 @@ Your search/replace content here
|
|||||||
// Extract the search and replace blocks
|
// Extract the search and replace blocks
|
||||||
const match = diffContent.match(/<<<<<<< SEARCH\n([\s\S]*?)\n=======\n([\s\S]*?)\n>>>>>>> REPLACE/);
|
const match = diffContent.match(/<<<<<<< SEARCH\n([\s\S]*?)\n=======\n([\s\S]*?)\n>>>>>>> REPLACE/);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
// Log detailed format information
|
const debugInfo = this.debugEnabled ? `\n\nDebug Info:\n- Expected Format: <<<<<<< SEARCH\\n[search content]\\n=======\\n[replace content]\\n>>>>>>> REPLACE\n- Tip: Make sure to include both SEARCH and REPLACE sections with correct markers` : '';
|
||||||
console.log('Invalid Diff Format Debug:', {
|
|
||||||
expectedFormat: "<<<<<<< SEARCH\\n[search content]\\n=======\\n[replace content]\\n>>>>>>> REPLACE",
|
|
||||||
tip: "Make sure to include both SEARCH and REPLACE sections with correct markers"
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: "Invalid diff format - missing required SEARCH/REPLACE sections"
|
error: `Invalid diff format - missing required SEARCH/REPLACE sections${debugInfo}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,21 +162,17 @@ Your search/replace content here
|
|||||||
let bestMatchScore = 0;
|
let bestMatchScore = 0;
|
||||||
let bestMatchContent = "";
|
let bestMatchContent = "";
|
||||||
|
|
||||||
if (startLine !== undefined && endLine !== undefined) {
|
if (startLine && endLine) {
|
||||||
// Convert to 0-based index
|
// Convert to 0-based index
|
||||||
const exactStartIndex = startLine - 1;
|
const exactStartIndex = startLine - 1;
|
||||||
const exactEndIndex = endLine - 1;
|
const exactEndIndex = endLine - 1;
|
||||||
|
|
||||||
if (exactStartIndex < 0 || exactEndIndex >= originalLines.length) {
|
if (exactStartIndex < 0 || exactEndIndex >= originalLines.length || exactStartIndex > exactEndIndex) {
|
||||||
// Log detailed debug information
|
const debugInfo = this.debugEnabled ? `\n\nDebug Info:\n- Requested Range: lines ${startLine}-${endLine}\n- File Bounds: lines 1-${originalLines.length}` : '';
|
||||||
console.log('Invalid Line Range Debug:', {
|
|
||||||
requestedRange: { start: startLine, end: endLine },
|
|
||||||
fileBounds: { start: 1, end: originalLines.length }
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `Line range ${startLine}-${endLine} is invalid (file has ${originalLines.length} lines)`,
|
error: `Line range ${startLine}-${endLine} is invalid (file has ${originalLines.length} lines)${debugInfo}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,13 +193,13 @@ Your search/replace content here
|
|||||||
let searchStartIndex = 0;
|
let searchStartIndex = 0;
|
||||||
let searchEndIndex = originalLines.length;
|
let searchEndIndex = originalLines.length;
|
||||||
|
|
||||||
if (startLine !== undefined || endLine !== undefined) {
|
if (startLine || endLine) {
|
||||||
// Convert to 0-based index and add buffer
|
// Convert to 0-based index and add buffer
|
||||||
if (startLine !== undefined) {
|
if (startLine) {
|
||||||
searchStartIndex = Math.max(0, startLine - 6);
|
searchStartIndex = Math.max(0, startLine - (BUFFER_LINES + 1));
|
||||||
}
|
}
|
||||||
if (endLine !== undefined) {
|
if (endLine) {
|
||||||
searchEndIndex = Math.min(originalLines.length, endLine + 5);
|
searchEndIndex = Math.min(originalLines.length, endLine + BUFFER_LINES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,17 +221,27 @@ Your search/replace content here
|
|||||||
// Require similarity to meet threshold
|
// Require similarity to meet threshold
|
||||||
if (matchIndex === -1 || bestMatchScore < this.fuzzyThreshold) {
|
if (matchIndex === -1 || bestMatchScore < this.fuzzyThreshold) {
|
||||||
const searchChunk = searchLines.join('\n');
|
const searchChunk = searchLines.join('\n');
|
||||||
// Log detailed debug information to console
|
const originalContentSection = startLine !== undefined && endLine !== undefined
|
||||||
console.log('Search/Replace Debug Info:', {
|
? `\n\nOriginal Content:\n${addLineNumbers(
|
||||||
similarity: bestMatchScore,
|
originalLines.slice(
|
||||||
threshold: this.fuzzyThreshold,
|
Math.max(0, startLine - 1 - BUFFER_LINES),
|
||||||
searchContent: searchChunk,
|
Math.min(originalLines.length, endLine + BUFFER_LINES)
|
||||||
bestMatch: bestMatchContent || undefined
|
).join('\n'),
|
||||||
});
|
Math.max(1, startLine - BUFFER_LINES)
|
||||||
|
)}`
|
||||||
|
: `\n\nOriginal Content:\n${addLineNumbers(originalLines.join('\n'))}`;
|
||||||
|
|
||||||
|
const bestMatchSection = bestMatchContent
|
||||||
|
? `\n\nBest Match Found:\n${addLineNumbers(bestMatchContent, matchIndex + 1)}`
|
||||||
|
: `\n\nBest Match Found:\n(no match)`;
|
||||||
|
|
||||||
|
const debugInfo = this.debugEnabled ? `\n\nDebug Info:\n- Similarity Score: ${Math.floor(bestMatchScore * 100)}%\n- Required Threshold: ${Math.floor(this.fuzzyThreshold * 100)}%\n- Search Range: ${startLine && endLine ? `lines ${startLine}-${endLine}` : 'start to end'}\n\nSearch Content:\n${searchChunk}${bestMatchSection}${originalContentSection}` : '';
|
||||||
|
|
||||||
|
const lineRange = startLine || endLine ?
|
||||||
|
` at ${startLine ? `start: ${startLine}` : 'start'} to ${endLine ? `end: ${endLine}` : 'end'}` : '';
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `No sufficiently similar match found${startLine !== undefined ? ` near lines ${startLine}-${endLine}` : ''} (${Math.round(bestMatchScore * 100)}% similar, needs ${Math.round(this.fuzzyThreshold * 100)}%)`
|
error: `No sufficiently similar match found${lineRange} (${Math.floor(bestMatchScore * 100)}% similar, needs ${Math.floor(this.fuzzyThreshold * 100)}%)${debugInfo}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ export type DiffResult =
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
export interface DiffStrategy {
|
export interface DiffStrategy {
|
||||||
|
/**
|
||||||
|
* Whether to enable detailed debug logging
|
||||||
|
*/
|
||||||
|
debugEnabled?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the tool description for this diff strategy
|
* Get the tool description for this diff strategy
|
||||||
* @param cwd The current working directory
|
* @param cwd The current working directory
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ type GlobalStateKey =
|
|||||||
| "soundEnabled"
|
| "soundEnabled"
|
||||||
| "soundVolume"
|
| "soundVolume"
|
||||||
| "diffEnabled"
|
| "diffEnabled"
|
||||||
|
| "debugDiffEnabled"
|
||||||
| "alwaysAllowMcp"
|
| "alwaysAllowMcp"
|
||||||
|
|
||||||
export const GlobalFileNames = {
|
export const GlobalFileNames = {
|
||||||
@@ -213,28 +214,11 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
|
|
||||||
async initClineWithTask(task?: string, images?: string[]) {
|
async initClineWithTask(task?: string, images?: string[]) {
|
||||||
await this.clearTask()
|
await this.clearTask()
|
||||||
const {
|
const {
|
||||||
apiConfiguration,
|
apiConfiguration,
|
||||||
customInstructions,
|
customInstructions,
|
||||||
diffEnabled,
|
|
||||||
} = await this.getState()
|
|
||||||
|
|
||||||
this.cline = new Cline(
|
|
||||||
this,
|
|
||||||
apiConfiguration,
|
|
||||||
customInstructions,
|
|
||||||
diffEnabled,
|
|
||||||
task,
|
|
||||||
images
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async initClineWithHistoryItem(historyItem: HistoryItem) {
|
|
||||||
await this.clearTask()
|
|
||||||
const {
|
|
||||||
apiConfiguration,
|
|
||||||
customInstructions,
|
|
||||||
diffEnabled,
|
diffEnabled,
|
||||||
|
debugDiffEnabled,
|
||||||
} = await this.getState()
|
} = await this.getState()
|
||||||
|
|
||||||
this.cline = new Cline(
|
this.cline = new Cline(
|
||||||
@@ -242,6 +226,27 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
apiConfiguration,
|
apiConfiguration,
|
||||||
customInstructions,
|
customInstructions,
|
||||||
diffEnabled,
|
diffEnabled,
|
||||||
|
debugDiffEnabled,
|
||||||
|
task,
|
||||||
|
images
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async initClineWithHistoryItem(historyItem: HistoryItem) {
|
||||||
|
await this.clearTask()
|
||||||
|
const {
|
||||||
|
apiConfiguration,
|
||||||
|
customInstructions,
|
||||||
|
diffEnabled,
|
||||||
|
debugDiffEnabled,
|
||||||
|
} = await this.getState()
|
||||||
|
|
||||||
|
this.cline = new Cline(
|
||||||
|
this,
|
||||||
|
apiConfiguration,
|
||||||
|
customInstructions,
|
||||||
|
diffEnabled,
|
||||||
|
debugDiffEnabled,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
historyItem,
|
historyItem,
|
||||||
@@ -609,6 +614,11 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
await this.updateGlobalState("diffEnabled", diffEnabled)
|
await this.updateGlobalState("diffEnabled", diffEnabled)
|
||||||
await this.postStateToWebview()
|
await this.postStateToWebview()
|
||||||
break
|
break
|
||||||
|
case "debugDiffEnabled":
|
||||||
|
const debugDiffEnabled = message.bool ?? false
|
||||||
|
await this.updateGlobalState("debugDiffEnabled", debugDiffEnabled)
|
||||||
|
await this.postStateToWebview()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
@@ -935,6 +945,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
alwaysAllowMcp,
|
alwaysAllowMcp,
|
||||||
soundEnabled,
|
soundEnabled,
|
||||||
diffEnabled,
|
diffEnabled,
|
||||||
|
debugDiffEnabled,
|
||||||
taskHistory,
|
taskHistory,
|
||||||
soundVolume,
|
soundVolume,
|
||||||
} = await this.getState()
|
} = await this.getState()
|
||||||
@@ -959,6 +970,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
.sort((a, b) => b.ts - a.ts),
|
.sort((a, b) => b.ts - a.ts),
|
||||||
soundEnabled: soundEnabled ?? false,
|
soundEnabled: soundEnabled ?? false,
|
||||||
diffEnabled: diffEnabled ?? false,
|
diffEnabled: diffEnabled ?? false,
|
||||||
|
debugDiffEnabled: debugDiffEnabled ?? false,
|
||||||
shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
|
shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
|
||||||
allowedCommands,
|
allowedCommands,
|
||||||
soundVolume: soundVolume ?? 0.5,
|
soundVolume: soundVolume ?? 0.5,
|
||||||
@@ -1054,6 +1066,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
allowedCommands,
|
allowedCommands,
|
||||||
soundEnabled,
|
soundEnabled,
|
||||||
diffEnabled,
|
diffEnabled,
|
||||||
|
debugDiffEnabled,
|
||||||
soundVolume,
|
soundVolume,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
|
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
|
||||||
@@ -1092,6 +1105,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
this.getGlobalState("allowedCommands") as Promise<string[] | undefined>,
|
this.getGlobalState("allowedCommands") as Promise<string[] | undefined>,
|
||||||
this.getGlobalState("soundEnabled") as Promise<boolean | undefined>,
|
this.getGlobalState("soundEnabled") as Promise<boolean | undefined>,
|
||||||
this.getGlobalState("diffEnabled") as Promise<boolean | undefined>,
|
this.getGlobalState("diffEnabled") as Promise<boolean | undefined>,
|
||||||
|
this.getGlobalState("debugDiffEnabled") as Promise<boolean | undefined>,
|
||||||
this.getGlobalState("soundVolume") as Promise<number | undefined>,
|
this.getGlobalState("soundVolume") as Promise<number | undefined>,
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -1146,8 +1160,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
alwaysAllowMcp: alwaysAllowMcp ?? false,
|
alwaysAllowMcp: alwaysAllowMcp ?? false,
|
||||||
taskHistory,
|
taskHistory,
|
||||||
allowedCommands,
|
allowedCommands,
|
||||||
soundEnabled,
|
soundEnabled: soundEnabled ?? false,
|
||||||
diffEnabled,
|
diffEnabled: diffEnabled ?? false,
|
||||||
|
debugDiffEnabled: debugDiffEnabled ?? false,
|
||||||
soundVolume,
|
soundVolume,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/integrations/misc/__tests__/extract-text.test.ts
Normal file
32
src/integrations/misc/__tests__/extract-text.test.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { addLineNumbers } from '../extract-text';
|
||||||
|
|
||||||
|
describe('addLineNumbers', () => {
|
||||||
|
it('should add line numbers starting from 1 by default', () => {
|
||||||
|
const input = 'line 1\nline 2\nline 3';
|
||||||
|
const expected = '1 | line 1\n2 | line 2\n3 | line 3';
|
||||||
|
expect(addLineNumbers(input)).toBe(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add line numbers starting from specified line number', () => {
|
||||||
|
const input = 'line 1\nline 2\nline 3';
|
||||||
|
const expected = '10 | line 1\n11 | line 2\n12 | line 3';
|
||||||
|
expect(addLineNumbers(input, 10)).toBe(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle empty content', () => {
|
||||||
|
expect(addLineNumbers('')).toBe('1 | ');
|
||||||
|
expect(addLineNumbers('', 5)).toBe('5 | ');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle single line content', () => {
|
||||||
|
expect(addLineNumbers('single line')).toBe('1 | single line');
|
||||||
|
expect(addLineNumbers('single line', 42)).toBe('42 | single line');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pad line numbers based on the highest line number', () => {
|
||||||
|
const input = 'line 1\nline 2';
|
||||||
|
// When starting from 99, highest line will be 100, so needs 3 spaces padding
|
||||||
|
const expected = ' 99 | line 1\n100 | line 2';
|
||||||
|
expect(addLineNumbers(input, 99)).toBe(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -53,15 +53,12 @@ async function extractTextFromIPYNB(filePath: string): Promise<string> {
|
|||||||
|
|
||||||
return addLineNumbers(extractedText)
|
return addLineNumbers(extractedText)
|
||||||
}
|
}
|
||||||
|
export function addLineNumbers(content: string, startLine: number = 1): string {
|
||||||
export function addLineNumbers(content: string): string {
|
|
||||||
const lines = content.split('\n')
|
const lines = content.split('\n')
|
||||||
const maxLineNumberWidth = String(lines.length).length
|
const maxLineNumberWidth = String(startLine + lines.length - 1).length
|
||||||
return lines
|
return lines
|
||||||
.map((line, index) => {
|
.map((line, index) => {
|
||||||
const lineNumber = String(index + 1).padStart(maxLineNumberWidth, ' ')
|
const lineNumber = String(startLine + index).padStart(maxLineNumberWidth, ' ')
|
||||||
return `${lineNumber} | ${line}`
|
return `${lineNumber} | ${line}`
|
||||||
}).join('\n')
|
}).join('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -53,6 +53,7 @@ export interface ExtensionState {
|
|||||||
soundEnabled?: boolean
|
soundEnabled?: boolean
|
||||||
soundVolume?: number
|
soundVolume?: number
|
||||||
diffEnabled?: boolean
|
diffEnabled?: boolean
|
||||||
|
debugDiffEnabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClineMessage {
|
export interface ClineMessage {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export interface WebviewMessage {
|
|||||||
| "soundEnabled"
|
| "soundEnabled"
|
||||||
| "soundVolume"
|
| "soundVolume"
|
||||||
| "diffEnabled"
|
| "diffEnabled"
|
||||||
|
| "debugDiffEnabled"
|
||||||
| "openMcpSettings"
|
| "openMcpSettings"
|
||||||
| "restartMcpServer"
|
| "restartMcpServer"
|
||||||
| "toggleToolAlwaysAllow"
|
| "toggleToolAlwaysAllow"
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
|
|||||||
setSoundVolume,
|
setSoundVolume,
|
||||||
diffEnabled,
|
diffEnabled,
|
||||||
setDiffEnabled,
|
setDiffEnabled,
|
||||||
|
debugDiffEnabled,
|
||||||
|
setDebugDiffEnabled,
|
||||||
openRouterModels,
|
openRouterModels,
|
||||||
setAllowedCommands,
|
setAllowedCommands,
|
||||||
allowedCommands,
|
allowedCommands,
|
||||||
@@ -48,7 +50,10 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
|
|||||||
setApiErrorMessage(apiValidationResult)
|
setApiErrorMessage(apiValidationResult)
|
||||||
setModelIdErrorMessage(modelIdValidationResult)
|
setModelIdErrorMessage(modelIdValidationResult)
|
||||||
if (!apiValidationResult && !modelIdValidationResult) {
|
if (!apiValidationResult && !modelIdValidationResult) {
|
||||||
vscode.postMessage({ type: "apiConfiguration", apiConfiguration })
|
vscode.postMessage({
|
||||||
|
type: "apiConfiguration",
|
||||||
|
apiConfiguration
|
||||||
|
})
|
||||||
vscode.postMessage({ type: "customInstructions", text: customInstructions })
|
vscode.postMessage({ type: "customInstructions", text: customInstructions })
|
||||||
vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
|
vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
|
||||||
vscode.postMessage({ type: "alwaysAllowWrite", bool: alwaysAllowWrite })
|
vscode.postMessage({ type: "alwaysAllowWrite", bool: alwaysAllowWrite })
|
||||||
@@ -59,6 +64,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
|
|||||||
vscode.postMessage({ type: "soundEnabled", bool: soundEnabled })
|
vscode.postMessage({ type: "soundEnabled", bool: soundEnabled })
|
||||||
vscode.postMessage({ type: "soundVolume", value: soundVolume })
|
vscode.postMessage({ type: "soundVolume", value: soundVolume })
|
||||||
vscode.postMessage({ type: "diffEnabled", bool: diffEnabled })
|
vscode.postMessage({ type: "diffEnabled", bool: diffEnabled })
|
||||||
|
vscode.postMessage({ type: "debugDiffEnabled", bool: debugDiffEnabled })
|
||||||
onDone()
|
onDone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +164,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
|
|||||||
marginTop: "5px",
|
marginTop: "5px",
|
||||||
color: "var(--vscode-descriptionForeground)",
|
color: "var(--vscode-descriptionForeground)",
|
||||||
}}>
|
}}>
|
||||||
When enabled, Cline will be able to edit files more quickly and will automatically reject truncated full-file writes.
|
When enabled, Cline will be able to edit files more quickly and will automatically reject truncated full-file writes. Works best with the latest Claude 3.5 Sonnet model.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -352,6 +358,20 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginBottom: 5 }}>
|
||||||
|
<VSCodeCheckbox checked={debugDiffEnabled} onChange={(e: any) => setDebugDiffEnabled(e.target.checked)}>
|
||||||
|
<span style={{ fontWeight: "500" }}>Debug diff operations</span>
|
||||||
|
</VSCodeCheckbox>
|
||||||
|
<p
|
||||||
|
style={{
|
||||||
|
fontSize: "12px",
|
||||||
|
marginTop: "5px",
|
||||||
|
color: "var(--vscode-descriptionForeground)",
|
||||||
|
}}>
|
||||||
|
When enabled, Cline will show detailed debug information when applying diffs fails.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{IS_DEV && (
|
{IS_DEV && (
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export interface ExtensionStateContextType extends ExtensionState {
|
|||||||
setSoundEnabled: (value: boolean) => void
|
setSoundEnabled: (value: boolean) => void
|
||||||
setSoundVolume: (value: number) => void
|
setSoundVolume: (value: number) => void
|
||||||
setDiffEnabled: (value: boolean) => void
|
setDiffEnabled: (value: boolean) => void
|
||||||
|
setDebugDiffEnabled: (value: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
|
const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
|
||||||
@@ -45,6 +46,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||||||
soundEnabled: false,
|
soundEnabled: false,
|
||||||
soundVolume: 0.5,
|
soundVolume: 0.5,
|
||||||
diffEnabled: false,
|
diffEnabled: false,
|
||||||
|
debugDiffEnabled: false,
|
||||||
})
|
})
|
||||||
const [didHydrateState, setDidHydrateState] = useState(false)
|
const [didHydrateState, setDidHydrateState] = useState(false)
|
||||||
const [showWelcome, setShowWelcome] = useState(false)
|
const [showWelcome, setShowWelcome] = useState(false)
|
||||||
@@ -132,7 +134,10 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||||||
mcpServers,
|
mcpServers,
|
||||||
filePaths,
|
filePaths,
|
||||||
soundVolume: state.soundVolume,
|
soundVolume: state.soundVolume,
|
||||||
setApiConfiguration: (value) => setState((prevState) => ({ ...prevState, apiConfiguration: value })),
|
setApiConfiguration: (value) => setState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
apiConfiguration: value
|
||||||
|
})),
|
||||||
setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })),
|
setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })),
|
||||||
setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
|
setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
|
||||||
setAlwaysAllowWrite: (value) => setState((prevState) => ({ ...prevState, alwaysAllowWrite: value })),
|
setAlwaysAllowWrite: (value) => setState((prevState) => ({ ...prevState, alwaysAllowWrite: value })),
|
||||||
@@ -144,6 +149,10 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||||||
setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })),
|
setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })),
|
||||||
setSoundVolume: (value) => setState((prevState) => ({ ...prevState, soundVolume: value })),
|
setSoundVolume: (value) => setState((prevState) => ({ ...prevState, soundVolume: value })),
|
||||||
setDiffEnabled: (value) => setState((prevState) => ({ ...prevState, diffEnabled: value })),
|
setDiffEnabled: (value) => setState((prevState) => ({ ...prevState, diffEnabled: value })),
|
||||||
|
setDebugDiffEnabled: (value) => setState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
debugDiffEnabled: value
|
||||||
|
})),
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>
|
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>
|
||||||
|
|||||||
Reference in New Issue
Block a user