mirror of
https://github.com/cline/cline.git
synced 2026-09-06 12:28:08 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c294b86524 | |||
| 8d133d9031 | |||
| 1adf19a873 |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Fix list_files tool to return files if the targeted directory is a hidden directory
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
add ability to constrain size of terminal output
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Exclude clinerules from checkpoints
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
chore(bedrock): remove @anthropic-ai/bedrock-sdk
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Update developer reset to allow for resetting workspace settings.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Added file context warnings to reduce diff edit errors when resuming a task after it has been restored
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Clear the chat input when the user changes mode within a task
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Added a configurable default terminal profile setting
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Fixed race condition where clineAsk was undefined, leading to task restoration and other downstream issues
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
update the copy button functionality
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Fix where clineMessages were not saving checkpoint commitHash on some messages
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Integrate Claude Code
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": patch
|
||||
---
|
||||
|
||||
Better debounce on checkmark control menu
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Add SAP AI Core as a provider for Cline
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"claude-dev": minor
|
||||
---
|
||||
|
||||
Adding MCP Rich Display settings in cline's settings page, to enable users to change it in a persistent manner
|
||||
@@ -1,5 +1,22 @@
|
||||
# Changelog
|
||||
|
||||
## [3.17.14]
|
||||
|
||||
- Add Claude Code as a new API provider, allowing integration with Anthropic's Claude Code CLI tool and Claude Max Plan (Thanks @BarreiroT!)
|
||||
- Add SAP AI Core as a new API provider with support for Claude and GPT models (Thanks @schardosin!)
|
||||
- Add configurable default terminal profile setting, allowing users to specify which terminal Cline should use (Thanks @valinha!)
|
||||
- Add terminal output size constraint setting to limit how much terminal output is processed
|
||||
- Add MCP Rich Display settings to the settings page for persistent configuration (Thanks @Vl4diC0de!)
|
||||
- Improve copy button functionality with refactored reusable components (Thanks @shouhanzen!)
|
||||
- Improve AWS Bedrock provider by removing deprecated dependency and using standard AWS SDK (Thanks @watany-dev!)
|
||||
- Fix list_files tool to properly return files when targeting hidden directories
|
||||
- Fix search and replace edge case that could cause file deletion, making the algorithm more lenient for models using different diff formats
|
||||
- Fix task restoration issues that could occur when resuming interrupted tasks
|
||||
- Fix checkpoint saving to properly track all file changes
|
||||
- Improve file context warnings to reduce diff edit errors when resuming restored tasks
|
||||
- Clear chat input when switching between Plan/Act modes within a task
|
||||
- Exclude .clinerules files from checkpoint tracking
|
||||
|
||||
## [3.17.13]
|
||||
|
||||
- Add Thinking UX for Gemini models, providing visual feedback during model reasoning
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "claude-dev",
|
||||
"version": "3.17.13",
|
||||
"version": "3.17.14",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "claude-dev",
|
||||
"version": "3.17.13",
|
||||
"version": "3.17.14",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.37.0",
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"name": "claude-dev",
|
||||
"displayName": "Cline",
|
||||
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
|
||||
"version": "3.17.13",
|
||||
"version": "3.17.14",
|
||||
"icon": "assets/icons/icon.png",
|
||||
"engines": {
|
||||
"vscode": "^1.84.0"
|
||||
|
||||
@@ -21,10 +21,7 @@ const NICE_JS_OUT_DIR = path.join(ROOT_DIR, "src/generated/nice-grpc")
|
||||
const DESCRIPTOR_OUT_DIR = path.join(ROOT_DIR, "dist-standalone/proto")
|
||||
|
||||
const isWindows = process.platform === "win32"
|
||||
const TS_PROTO_PLUGIN = isWindows
|
||||
? path.join(ROOT_DIR, "node_modules", ".bin", "protoc-gen-ts_proto.cmd") // Use the .bin directory path for Windows
|
||||
: require.resolve("ts-proto/protoc-gen-ts_proto")
|
||||
|
||||
const TS_PROTO_PLUGIN = require.resolve("ts-proto/protoc-gen-ts_proto") + (isWindows ? ".cmd" : "")
|
||||
const TS_PROTO_OPTIONS = [
|
||||
"env=node",
|
||||
"esModuleInterop=true",
|
||||
|
||||
@@ -19,14 +19,34 @@ new content
|
||||
isFinal: true,
|
||||
},
|
||||
{
|
||||
name: "full file replacement",
|
||||
original: "old content",
|
||||
diff: `------- SEARCH
|
||||
name: "malformed search - mixed symbols",
|
||||
original: "line1\nline2\nline3",
|
||||
diff: `<<-- SEARCH
|
||||
line2
|
||||
=======
|
||||
new content
|
||||
replaced
|
||||
+++++++ REPLACE`,
|
||||
expected: "new content\n",
|
||||
isFinal: true,
|
||||
shouldThrow: true,
|
||||
},
|
||||
{
|
||||
name: "malformed search - insufficient dashes",
|
||||
original: "line1\nline2\nline3",
|
||||
diff: `-- SEARCH
|
||||
line2
|
||||
=======
|
||||
replaced
|
||||
+++++++ REPLACE`,
|
||||
shouldThrow: true,
|
||||
},
|
||||
{
|
||||
name: "malformed search - missing space",
|
||||
original: "line1\nline2\nline3",
|
||||
diff: `-------SEARCH
|
||||
line2
|
||||
=======
|
||||
replaced
|
||||
+++++++ REPLACE`,
|
||||
shouldThrow: true,
|
||||
},
|
||||
{
|
||||
name: "exact match replacement",
|
||||
@@ -139,17 +159,33 @@ replaced
|
||||
]
|
||||
//.filter(({name}) => name === "multiple ordered replacements")
|
||||
//.filter(({name}) => name === "delete then replace")
|
||||
testCases.forEach(({ name, original, diff, expected, isFinal }) => {
|
||||
testCases.forEach(({ name, original, diff, expected, isFinal, shouldThrow }) => {
|
||||
it(`should handle ${name} case correctly`, async () => {
|
||||
const result1 = await cnfc(diff, original, isFinal)
|
||||
const result2 = await cnfc2(diff, original, isFinal)
|
||||
const equal = result1 === result2
|
||||
const equal2 = result1 === expected
|
||||
// Verify both implementations produce same result
|
||||
expect(result1).to.equal(result2)
|
||||
if (shouldThrow) {
|
||||
try {
|
||||
await cnfc(diff, original, isFinal ?? true)
|
||||
expect.fail("Expected an error to be thrown")
|
||||
} catch (err) {
|
||||
expect(err).to.be.an("error")
|
||||
}
|
||||
|
||||
// Verify result matches expected
|
||||
expect(result1).to.equal(expected)
|
||||
try {
|
||||
await cnfc2(diff, original, isFinal ?? true)
|
||||
expect.fail("Expected an error to be thrown")
|
||||
} catch (err) {
|
||||
expect(err).to.be.an("error")
|
||||
}
|
||||
} else {
|
||||
const result1 = await cnfc(diff, original, isFinal ?? true)
|
||||
const result2 = await cnfc2(diff, original, isFinal ?? true)
|
||||
const equal = result1 === result2
|
||||
const equal2 = result1 === expected
|
||||
// Verify both implementations produce same result
|
||||
expect(result1).to.equal(result2)
|
||||
|
||||
// Verify result matches expected
|
||||
expect(result1).to.equal(expected)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -4,15 +4,19 @@ const REPLACE_BLOCK_END = "+++++++ REPLACE"
|
||||
|
||||
const SEARCH_BLOCK_CHAR = "-"
|
||||
const REPLACE_BLOCK_CHAR = "+"
|
||||
const LEGACY_SEARCH_BLOCK_CHAR = "<"
|
||||
const LEGACY_REPLACE_BLOCK_CHAR = ">"
|
||||
|
||||
// Replace the exact string constants with flexible regex patterns
|
||||
const SEARCH_BLOCK_START_REGEX = /^[-]{3,} SEARCH$/
|
||||
const SEARCH_BLOCK_END_REGEX = /^[=]{3,}$/
|
||||
const REPLACE_BLOCK_END_REGEX = /^[+]{3,} REPLACE$/
|
||||
const LEGACY_SEARCH_BLOCK_START_REGEX = /^[<]{3,} SEARCH$/
|
||||
const LEGACY_REPLACE_BLOCK_END_REGEX = /^[>]{3,} REPLACE$/
|
||||
|
||||
// Helper functions to check if a line matches the flexible patterns
|
||||
function isSearchBlockStart(line: string): boolean {
|
||||
return SEARCH_BLOCK_START_REGEX.test(line)
|
||||
return SEARCH_BLOCK_START_REGEX.test(line) || LEGACY_SEARCH_BLOCK_START_REGEX.test(line)
|
||||
}
|
||||
|
||||
function isSearchBlockEnd(line: string): boolean {
|
||||
@@ -20,7 +24,7 @@ function isSearchBlockEnd(line: string): boolean {
|
||||
}
|
||||
|
||||
function isReplaceBlockEnd(line: string): boolean {
|
||||
return REPLACE_BLOCK_END_REGEX.test(line)
|
||||
return REPLACE_BLOCK_END_REGEX.test(line) || LEGACY_REPLACE_BLOCK_END_REGEX.test(line)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +273,11 @@ async function constructNewFileContentV1(diffContent: string, originalContent: s
|
||||
const lastLine = lines[lines.length - 1]
|
||||
if (
|
||||
lines.length > 0 &&
|
||||
(lastLine.startsWith(SEARCH_BLOCK_CHAR) || lastLine.startsWith("=") || lastLine.startsWith(REPLACE_BLOCK_CHAR)) &&
|
||||
(lastLine.startsWith(SEARCH_BLOCK_CHAR) ||
|
||||
lastLine.startsWith(LEGACY_SEARCH_BLOCK_CHAR) ||
|
||||
lastLine.startsWith("=") ||
|
||||
lastLine.startsWith(REPLACE_BLOCK_CHAR) ||
|
||||
lastLine.startsWith(LEGACY_REPLACE_BLOCK_CHAR)) &&
|
||||
!isSearchBlockStart(lastLine) &&
|
||||
!isSearchBlockEnd(lastLine) &&
|
||||
!isReplaceBlockEnd(lastLine)
|
||||
@@ -303,9 +311,12 @@ async function constructNewFileContentV1(diffContent: string, originalContent: s
|
||||
searchMatchIndex = 0
|
||||
searchEndIndex = 0
|
||||
} else {
|
||||
// Complete file replacement scenario: treat the entire file as matched
|
||||
searchMatchIndex = 0
|
||||
searchEndIndex = originalContent.length
|
||||
// ERROR: Empty search block with non-empty file indicates malformed SEARCH marker
|
||||
throw new Error(
|
||||
"Empty SEARCH block detected with non-empty file. This usually indicates a malformed SEARCH marker.\n" +
|
||||
"Please ensure your SEARCH marker follows the correct format:\n" +
|
||||
"- Use '------- SEARCH' (7+ dashes + space + SEARCH)\n",
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Add check for inefficient full-file search
|
||||
@@ -570,7 +581,7 @@ class NewFileContentConstructor {
|
||||
pendingNonStandardLineLimit: number,
|
||||
): number {
|
||||
let removeLineCount = 0
|
||||
if (line === SEARCH_BLOCK_START) {
|
||||
if (isSearchBlockStart(line)) {
|
||||
removeLineCount = this.trimPendingNonStandardTrailingEmptyLines(pendingNonStandardLineLimit)
|
||||
if (removeLineCount > 0) {
|
||||
pendingNonStandardLineLimit = pendingNonStandardLineLimit - removeLineCount
|
||||
@@ -580,7 +591,7 @@ class NewFileContentConstructor {
|
||||
canWritependingNonStandardLines && (this.pendingNonStandardLines.length = 0)
|
||||
}
|
||||
this.activateSearchState()
|
||||
} else if (line === SEARCH_BLOCK_END) {
|
||||
} else if (isSearchBlockEnd(line)) {
|
||||
// 校验非标内容
|
||||
if (!this.isSearchingActive()) {
|
||||
this.tryFixSearchBlock(pendingNonStandardLineLimit)
|
||||
@@ -588,7 +599,7 @@ class NewFileContentConstructor {
|
||||
}
|
||||
this.activateReplaceState()
|
||||
this.beforeReplace()
|
||||
} else if (line === REPLACE_BLOCK_END) {
|
||||
} else if (isReplaceBlockEnd(line)) {
|
||||
if (!this.isReplacingActive()) {
|
||||
this.tryFixReplaceBlock(pendingNonStandardLineLimit)
|
||||
canWritependingNonStandardLines && (this.pendingNonStandardLines.length = 0)
|
||||
@@ -695,7 +706,7 @@ class NewFileContentConstructor {
|
||||
if (!lineLimit) {
|
||||
throw new Error("Invalid SEARCH/REPLACE block structure - no lines available to process")
|
||||
}
|
||||
let searchTagRegexp = /^[-]{3,} SEARCH$/
|
||||
let searchTagRegexp = /^([-]{3,}|[<]{3,}) SEARCH$/
|
||||
const searchTagIndex = this.findLastMatchingLineIndex(searchTagRegexp, lineLimit)
|
||||
if (searchTagIndex !== -1) {
|
||||
let fixLines = this.pendingNonStandardLines.slice(searchTagIndex, lineLimit)
|
||||
@@ -746,7 +757,7 @@ class NewFileContentConstructor {
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
let replaceEndTagRegexp = /^[+]{3,} REPLACE$/
|
||||
let replaceEndTagRegexp = /^([+]{3,}|[>]{3,}) REPLACE$/
|
||||
const replaceEndTagIndex = this.findLastMatchingLineIndex(replaceEndTagRegexp, lineLimit)
|
||||
const likeReplaceEndTag = replaceEndTagIndex === lineLimit - 1
|
||||
if (likeReplaceEndTag) {
|
||||
@@ -795,7 +806,11 @@ export async function constructNewFileContentV2(diffContent: string, originalCon
|
||||
const lastLine = lines[lines.length - 1]
|
||||
if (
|
||||
lines.length > 0 &&
|
||||
(lastLine.startsWith(SEARCH_BLOCK_CHAR) || lastLine.startsWith("=") || lastLine.startsWith(REPLACE_BLOCK_CHAR)) &&
|
||||
(lastLine.startsWith(SEARCH_BLOCK_CHAR) ||
|
||||
lastLine.startsWith(LEGACY_SEARCH_BLOCK_CHAR) ||
|
||||
lastLine.startsWith("=") ||
|
||||
lastLine.startsWith(REPLACE_BLOCK_CHAR) ||
|
||||
lastLine.startsWith(LEGACY_REPLACE_BLOCK_CHAR)) &&
|
||||
lastLine !== SEARCH_BLOCK_START &&
|
||||
lastLine !== SEARCH_BLOCK_END &&
|
||||
lastLine !== REPLACE_BLOCK_END
|
||||
|
||||
@@ -94,27 +94,27 @@ const AutoApproveMenuItem = ({
|
||||
<HeroTooltip content={action.description} delay={500}>
|
||||
<CheckboxContainer isFavorited={favorited} onClick={onChange}>
|
||||
<div className="left-content">
|
||||
{onToggleFavorite && !condensed && (
|
||||
<HeroTooltip
|
||||
delay={500}
|
||||
content={favorited ? "Remove from quick-access menu" : "Add to quick-access menu"}>
|
||||
<span
|
||||
className={`p-0.5 codicon codicon-${favorited ? "star-full" : "star-empty"} star`}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={async (e) => {
|
||||
e.stopPropagation()
|
||||
if (action.id === "enableAll") return
|
||||
await onToggleFavorite?.(action.id)
|
||||
}}
|
||||
/>
|
||||
</HeroTooltip>
|
||||
)}
|
||||
<VSCodeCheckbox checked={checked} />
|
||||
{showIcon && <span className={`codicon ${action.icon} icon`}></span>}
|
||||
<span className="label">{condensed ? action.shortName : action.label}</span>
|
||||
</div>
|
||||
{onToggleFavorite && !condensed && (
|
||||
<HeroTooltip
|
||||
delay={500}
|
||||
content={favorited ? "Remove from quick-access menu" : "Add to quick-access menu"}>
|
||||
<span
|
||||
className={`p-0.5 codicon codicon-${favorited ? "star-full" : "star-empty"} star`}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={async (e) => {
|
||||
e.stopPropagation()
|
||||
if (action.id === "enableAll") return
|
||||
await onToggleFavorite?.(action.id)
|
||||
}}
|
||||
/>
|
||||
</HeroTooltip>
|
||||
)}
|
||||
</CheckboxContainer>
|
||||
</HeroTooltip>
|
||||
</ActionButtonContainer>
|
||||
|
||||
Reference in New Issue
Block a user