mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Revert some whitespace changes
This commit is contained in:
@@ -205,10 +205,10 @@ export class Cline {
|
|||||||
const taskMessage = this.clineMessages[0] // first message is always the task say
|
const taskMessage = this.clineMessages[0] // first message is always the task say
|
||||||
const lastRelevantMessage =
|
const lastRelevantMessage =
|
||||||
this.clineMessages[
|
this.clineMessages[
|
||||||
findLastIndex(
|
findLastIndex(
|
||||||
this.clineMessages,
|
this.clineMessages,
|
||||||
(m) => !(m.ask === "resume_task" || m.ask === "resume_completed_task"),
|
(m) => !(m.ask === "resume_task" || m.ask === "resume_completed_task"),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
await this.providerRef.deref()?.updateTaskHistory({
|
await this.providerRef.deref()?.updateTaskHistory({
|
||||||
id: this.taskId,
|
id: this.taskId,
|
||||||
@@ -390,7 +390,8 @@ export class Cline {
|
|||||||
async sayAndCreateMissingParamError(toolName: ToolUseName, paramName: string, relPath?: string) {
|
async sayAndCreateMissingParamError(toolName: ToolUseName, paramName: string, relPath?: string) {
|
||||||
await this.say(
|
await this.say(
|
||||||
"error",
|
"error",
|
||||||
`Cline tried to use ${toolName}${relPath ? ` for '${relPath.toPosix()}'` : ""
|
`Cline tried to use ${toolName}${
|
||||||
|
relPath ? ` for '${relPath.toPosix()}'` : ""
|
||||||
} without value for required parameter '${paramName}'. Retrying...`,
|
} without value for required parameter '${paramName}'. Retrying...`,
|
||||||
)
|
)
|
||||||
return formatResponse.toolError(formatResponse.missingToolParameterError(paramName))
|
return formatResponse.toolError(formatResponse.missingToolParameterError(paramName))
|
||||||
@@ -448,7 +449,7 @@ export class Cline {
|
|||||||
// need to make sure that the api conversation history can be resumed by the api, even if it goes out of sync with cline messages
|
// need to make sure that the api conversation history can be resumed by the api, even if it goes out of sync with cline messages
|
||||||
|
|
||||||
let existingApiConversationHistory: Anthropic.Messages.MessageParam[] =
|
let existingApiConversationHistory: Anthropic.Messages.MessageParam[] =
|
||||||
await this.getSavedApiConversationHistory()
|
await this.getSavedApiConversationHistory()
|
||||||
|
|
||||||
// Now present the cline messages to the user and ask if they want to resume
|
// Now present the cline messages to the user and ask if they want to resume
|
||||||
|
|
||||||
@@ -559,8 +560,8 @@ export class Cline {
|
|||||||
: [{ type: "text", text: lastMessage.content }]
|
: [{ type: "text", text: lastMessage.content }]
|
||||||
if (previousAssistantMessage && previousAssistantMessage.role === "assistant") {
|
if (previousAssistantMessage && previousAssistantMessage.role === "assistant") {
|
||||||
const assistantContent = Array.isArray(previousAssistantMessage.content)
|
const assistantContent = Array.isArray(previousAssistantMessage.content)
|
||||||
? previousAssistantMessage.content
|
? previousAssistantMessage.content
|
||||||
: [{ type: "text", text: previousAssistantMessage.content }]
|
: [{ type: "text", text: previousAssistantMessage.content }]
|
||||||
|
|
||||||
const toolUseBlocks = assistantContent.filter(
|
const toolUseBlocks = assistantContent.filter(
|
||||||
(block) => block.type === "tool_use",
|
(block) => block.type === "tool_use",
|
||||||
@@ -625,9 +626,10 @@ export class Cline {
|
|||||||
newUserContent.push({
|
newUserContent.push({
|
||||||
type: "text",
|
type: "text",
|
||||||
text:
|
text:
|
||||||
`[TASK RESUMPTION] This task was interrupted ${agoText}. It may or may not be complete, so please reassess the task context. Be aware that the project state may have changed since then. The current working directory is now '${cwd.toPosix()}'. If the task has not been completed, retry the last step before interruption and proceed with completing the task.\n\nNote: If you previously attempted a tool use that the user did not provide a result for, you should assume the tool use was not successful and assess whether you should retry. If the last tool was a browser_action, the browser has been closed and you must launch a new browser if needed.${wasRecent
|
`[TASK RESUMPTION] This task was interrupted ${agoText}. It may or may not be complete, so please reassess the task context. Be aware that the project state may have changed since then. The current working directory is now '${cwd.toPosix()}'. If the task has not been completed, retry the last step before interruption and proceed with completing the task.\n\nNote: If you previously attempted a tool use that the user did not provide a result for, you should assume the tool use was not successful and assess whether you should retry. If the last tool was a browser_action, the browser has been closed and you must launch a new browser if needed.${
|
||||||
? "\n\nIMPORTANT: If the last tool use was a write_to_file that was interrupted, the file was reverted back to its original state before the interrupted edit, and you do NOT need to re-read the file as you already have its up-to-date contents."
|
wasRecent
|
||||||
: ""
|
? "\n\nIMPORTANT: If the last tool use was a write_to_file that was interrupted, the file was reverted back to its original state before the interrupted edit, and you do NOT need to re-read the file as you already have its up-to-date contents."
|
||||||
|
: ""
|
||||||
}` +
|
}` +
|
||||||
(responseText
|
(responseText
|
||||||
? `\n\nNew instructions for task continuation:\n<user_message>\n${responseText}\n</user_message>`
|
? `\n\nNew instructions for task continuation:\n<user_message>\n${responseText}\n</user_message>`
|
||||||
@@ -741,7 +743,8 @@ export class Cline {
|
|||||||
return [
|
return [
|
||||||
true,
|
true,
|
||||||
formatResponse.toolResult(
|
formatResponse.toolResult(
|
||||||
`Command is still running in the user's terminal.${result.length > 0 ? `\nHere's the output so far:\n${result}` : ""
|
`Command is still running in the user's terminal.${
|
||||||
|
result.length > 0 ? `\nHere's the output so far:\n${result}` : ""
|
||||||
}\n\nThe user provided the following feedback:\n<feedback>\n${userFeedback.text}\n</feedback>`,
|
}\n\nThe user provided the following feedback:\n<feedback>\n${userFeedback.text}\n</feedback>`,
|
||||||
userFeedback.images,
|
userFeedback.images,
|
||||||
),
|
),
|
||||||
@@ -753,7 +756,8 @@ export class Cline {
|
|||||||
} else {
|
} else {
|
||||||
return [
|
return [
|
||||||
false,
|
false,
|
||||||
`Command is still running in the user's terminal.${result.length > 0 ? `\nHere's the output so far:\n${result}` : ""
|
`Command is still running in the user's terminal.${
|
||||||
|
result.length > 0 ? `\nHere's the output so far:\n${result}` : ""
|
||||||
}\n\nYou will be updated on the terminal status and new output in the future.`,
|
}\n\nYou will be updated on the terminal status and new output in the future.`,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -931,8 +935,9 @@ export class Cline {
|
|||||||
case "apply_diff":
|
case "apply_diff":
|
||||||
return `[${block.name} for '${block.params.path}']`
|
return `[${block.name} for '${block.params.path}']`
|
||||||
case "search_files":
|
case "search_files":
|
||||||
return `[${block.name} for '${block.params.regex}'${block.params.file_pattern ? ` in '${block.params.file_pattern}'` : ""
|
return `[${block.name} for '${block.params.regex}'${
|
||||||
}]`
|
block.params.file_pattern ? ` in '${block.params.file_pattern}'` : ""
|
||||||
|
}]`
|
||||||
case "list_files":
|
case "list_files":
|
||||||
return `[${block.name} for '${block.params.path}']`
|
return `[${block.name} for '${block.params.path}']`
|
||||||
case "list_code_definition_names":
|
case "list_code_definition_names":
|
||||||
@@ -1118,7 +1123,7 @@ export class Cline {
|
|||||||
if (block.partial) {
|
if (block.partial) {
|
||||||
// update gui message
|
// update gui message
|
||||||
const partialMessage = JSON.stringify(sharedMessageProps)
|
const partialMessage = JSON.stringify(sharedMessageProps)
|
||||||
await this.ask("tool", partialMessage, block.partial).catch(() => { })
|
await this.ask("tool", partialMessage, block.partial).catch(() => {})
|
||||||
// update editor
|
// update editor
|
||||||
if (!this.diffViewProvider.isEditing) {
|
if (!this.diffViewProvider.isEditing) {
|
||||||
// open the editor and prepare to stream content in
|
// open the editor and prepare to stream content in
|
||||||
@@ -1154,7 +1159,7 @@ export class Cline {
|
|||||||
if (!this.diffViewProvider.isEditing) {
|
if (!this.diffViewProvider.isEditing) {
|
||||||
// show gui message before showing edit animation
|
// show gui message before showing edit animation
|
||||||
const partialMessage = JSON.stringify(sharedMessageProps)
|
const partialMessage = JSON.stringify(sharedMessageProps)
|
||||||
await this.ask("tool", partialMessage, true).catch(() => { }) // sending true for partial even though it's not a partial, this shows the edit row before the content is streamed into the editor
|
await this.ask("tool", partialMessage, true).catch(() => {}) // sending true for partial even though it's not a partial, this shows the edit row before the content is streamed into the editor
|
||||||
await this.diffViewProvider.open(relPath)
|
await this.diffViewProvider.open(relPath)
|
||||||
}
|
}
|
||||||
await this.diffViewProvider.update(everyLineHasLineNumbers(newContent) ? stripLineNumbers(newContent) : newContent, true)
|
await this.diffViewProvider.update(everyLineHasLineNumbers(newContent) ? stripLineNumbers(newContent) : newContent, true)
|
||||||
@@ -1192,10 +1197,10 @@ export class Cline {
|
|||||||
content: fileExists ? undefined : newContent,
|
content: fileExists ? undefined : newContent,
|
||||||
diff: fileExists
|
diff: fileExists
|
||||||
? formatResponse.createPrettyPatch(
|
? formatResponse.createPrettyPatch(
|
||||||
relPath,
|
relPath,
|
||||||
this.diffViewProvider.originalContent,
|
this.diffViewProvider.originalContent,
|
||||||
newContent,
|
newContent,
|
||||||
)
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
} satisfies ClineSayTool)
|
} satisfies ClineSayTool)
|
||||||
const didApprove = await askApproval("tool", completeMessage)
|
const didApprove = await askApproval("tool", completeMessage)
|
||||||
@@ -1217,13 +1222,13 @@ export class Cline {
|
|||||||
)
|
)
|
||||||
pushToolResult(
|
pushToolResult(
|
||||||
`The user made the following updates to your content:\n\n${userEdits}\n\n` +
|
`The user made the following updates to your content:\n\n${userEdits}\n\n` +
|
||||||
`The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file, including line numbers:\n\n` +
|
`The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file, including line numbers:\n\n` +
|
||||||
`<final_file_content path="${relPath.toPosix()}">\n${addLineNumbers(finalContent || '')}\n</final_file_content>\n\n` +
|
`<final_file_content path="${relPath.toPosix()}">\n${addLineNumbers(finalContent || '')}\n</final_file_content>\n\n` +
|
||||||
`Please note:\n` +
|
`Please note:\n` +
|
||||||
`1. You do not need to re-write the file with these changes, as they have already been applied.\n` +
|
`1. You do not need to re-write the file with these changes, as they have already been applied.\n` +
|
||||||
`2. Proceed with the task using this updated file content as the new baseline.\n` +
|
`2. Proceed with the task using this updated file content as the new baseline.\n` +
|
||||||
`3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` +
|
`3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` +
|
||||||
`${newProblemsMessage}`,
|
`${newProblemsMessage}`,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
pushToolResult(
|
pushToolResult(
|
||||||
@@ -1252,7 +1257,7 @@ export class Cline {
|
|||||||
if (block.partial) {
|
if (block.partial) {
|
||||||
// update gui message
|
// update gui message
|
||||||
const partialMessage = JSON.stringify(sharedMessageProps)
|
const partialMessage = JSON.stringify(sharedMessageProps)
|
||||||
await this.ask("tool", partialMessage, block.partial).catch(() => { })
|
await this.ask("tool", partialMessage, block.partial).catch(() => {})
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
if (!relPath) {
|
if (!relPath) {
|
||||||
@@ -1281,9 +1286,9 @@ export class Cline {
|
|||||||
|
|
||||||
// Apply the diff to the original content
|
// Apply the diff to the original content
|
||||||
const diffResult = this.diffStrategy?.applyDiff(
|
const diffResult = this.diffStrategy?.applyDiff(
|
||||||
originalContent,
|
originalContent,
|
||||||
diffContent,
|
diffContent,
|
||||||
parseInt(block.params.start_line ?? ''),
|
parseInt(block.params.start_line ?? ''),
|
||||||
parseInt(block.params.end_line ?? '')
|
parseInt(block.params.end_line ?? '')
|
||||||
) ?? {
|
) ?? {
|
||||||
success: false,
|
success: false,
|
||||||
@@ -1335,13 +1340,13 @@ export class Cline {
|
|||||||
)
|
)
|
||||||
pushToolResult(
|
pushToolResult(
|
||||||
`The user made the following updates to your content:\n\n${userEdits}\n\n` +
|
`The user made the following updates to your content:\n\n${userEdits}\n\n` +
|
||||||
`The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file, including line numbers:\n\n` +
|
`The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file, including line numbers:\n\n` +
|
||||||
`<final_file_content path="${relPath.toPosix()}">\n${addLineNumbers(finalContent || '')}\n</final_file_content>\n\n` +
|
`<final_file_content path="${relPath.toPosix()}">\n${addLineNumbers(finalContent || '')}\n</final_file_content>\n\n` +
|
||||||
`Please note:\n` +
|
`Please note:\n` +
|
||||||
`1. You do not need to re-write the file with these changes, as they have already been applied.\n` +
|
`1. You do not need to re-write the file with these changes, as they have already been applied.\n` +
|
||||||
`2. Proceed with the task using this updated file content as the new baseline.\n` +
|
`2. Proceed with the task using this updated file content as the new baseline.\n` +
|
||||||
`3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` +
|
`3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` +
|
||||||
`${newProblemsMessage}`,
|
`${newProblemsMessage}`,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
pushToolResult(`Changes successfully applied to ${relPath.toPosix()}:\n\n${newProblemsMessage}`)
|
pushToolResult(`Changes successfully applied to ${relPath.toPosix()}:\n\n${newProblemsMessage}`)
|
||||||
@@ -1367,7 +1372,7 @@ export class Cline {
|
|||||||
...sharedMessageProps,
|
...sharedMessageProps,
|
||||||
content: undefined,
|
content: undefined,
|
||||||
} satisfies ClineSayTool)
|
} satisfies ClineSayTool)
|
||||||
await this.ask("tool", partialMessage, block.partial).catch(() => { })
|
await this.ask("tool", partialMessage, block.partial).catch(() => {})
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
if (!relPath) {
|
if (!relPath) {
|
||||||
@@ -1409,7 +1414,7 @@ export class Cline {
|
|||||||
...sharedMessageProps,
|
...sharedMessageProps,
|
||||||
content: "",
|
content: "",
|
||||||
} satisfies ClineSayTool)
|
} satisfies ClineSayTool)
|
||||||
await this.ask("tool", partialMessage, block.partial).catch(() => { })
|
await this.ask("tool", partialMessage, block.partial).catch(() => {})
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
if (!relDirPath) {
|
if (!relDirPath) {
|
||||||
@@ -1449,7 +1454,7 @@ export class Cline {
|
|||||||
...sharedMessageProps,
|
...sharedMessageProps,
|
||||||
content: "",
|
content: "",
|
||||||
} satisfies ClineSayTool)
|
} satisfies ClineSayTool)
|
||||||
await this.ask("tool", partialMessage, block.partial).catch(() => { })
|
await this.ask("tool", partialMessage, block.partial).catch(() => {})
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
if (!relDirPath) {
|
if (!relDirPath) {
|
||||||
@@ -1494,7 +1499,7 @@ export class Cline {
|
|||||||
...sharedMessageProps,
|
...sharedMessageProps,
|
||||||
content: "",
|
content: "",
|
||||||
} satisfies ClineSayTool)
|
} satisfies ClineSayTool)
|
||||||
await this.ask("tool", partialMessage, block.partial).catch(() => { })
|
await this.ask("tool", partialMessage, block.partial).catch(() => {})
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
if (!relDirPath) {
|
if (!relDirPath) {
|
||||||
@@ -1549,7 +1554,7 @@ export class Cline {
|
|||||||
"browser_action_launch",
|
"browser_action_launch",
|
||||||
removeClosingTag("url", url),
|
removeClosingTag("url", url),
|
||||||
block.partial
|
block.partial
|
||||||
).catch(() => { })
|
).catch(() => {})
|
||||||
} else {
|
} else {
|
||||||
await this.say(
|
await this.say(
|
||||||
"browser_action",
|
"browser_action",
|
||||||
@@ -1649,7 +1654,8 @@ export class Cline {
|
|||||||
await this.say("browser_action_result", JSON.stringify(browserActionResult))
|
await this.say("browser_action_result", JSON.stringify(browserActionResult))
|
||||||
pushToolResult(
|
pushToolResult(
|
||||||
formatResponse.toolResult(
|
formatResponse.toolResult(
|
||||||
`The browser action has been executed. The console logs and screenshot have been captured for your analysis.\n\nConsole logs:\n${browserActionResult.logs || "(No new logs)"
|
`The browser action has been executed. The console logs and screenshot have been captured for your analysis.\n\nConsole logs:\n${
|
||||||
|
browserActionResult.logs || "(No new logs)"
|
||||||
}\n\n(REMEMBER: if you need to proceed to using non-\`browser_action\` tools or launch a new browser, you MUST first close this browser. For example, if after analyzing the logs and screenshot you need to edit a file, you must first close the browser before you can use the write_to_file tool.)`,
|
}\n\n(REMEMBER: if you need to proceed to using non-\`browser_action\` tools or launch a new browser, you MUST first close this browser. For example, if after analyzing the logs and screenshot you need to edit a file, you must first close the browser before you can use the write_to_file tool.)`,
|
||||||
browserActionResult.screenshot ? [browserActionResult.screenshot] : [],
|
browserActionResult.screenshot ? [browserActionResult.screenshot] : [],
|
||||||
),
|
),
|
||||||
@@ -1676,7 +1682,7 @@ export class Cline {
|
|||||||
try {
|
try {
|
||||||
if (block.partial) {
|
if (block.partial) {
|
||||||
await this.ask("command", removeClosingTag("command", command), block.partial).catch(
|
await this.ask("command", removeClosingTag("command", command), block.partial).catch(
|
||||||
() => { }
|
() => {}
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
@@ -1717,7 +1723,7 @@ export class Cline {
|
|||||||
toolName: removeClosingTag("tool_name", tool_name),
|
toolName: removeClosingTag("tool_name", tool_name),
|
||||||
arguments: removeClosingTag("arguments", mcp_arguments),
|
arguments: removeClosingTag("arguments", mcp_arguments),
|
||||||
} satisfies ClineAskUseMcpServer)
|
} satisfies ClineAskUseMcpServer)
|
||||||
await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => { })
|
await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => {})
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
if (!server_name) {
|
if (!server_name) {
|
||||||
@@ -1778,19 +1784,19 @@ export class Cline {
|
|||||||
// TODO: add progress indicator and ability to parse images and non-text responses
|
// TODO: add progress indicator and ability to parse images and non-text responses
|
||||||
const toolResultPretty =
|
const toolResultPretty =
|
||||||
(toolResult?.isError ? "Error:\n" : "") +
|
(toolResult?.isError ? "Error:\n" : "") +
|
||||||
toolResult?.content
|
toolResult?.content
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
if (item.type === "text") {
|
if (item.type === "text") {
|
||||||
return item.text
|
return item.text
|
||||||
}
|
}
|
||||||
if (item.type === "resource") {
|
if (item.type === "resource") {
|
||||||
const { blob, ...rest } = item.resource
|
const { blob, ...rest } = item.resource
|
||||||
return JSON.stringify(rest, null, 2)
|
return JSON.stringify(rest, null, 2)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join("\n\n") || "(No response)"
|
.join("\n\n") || "(No response)"
|
||||||
await this.say("mcp_server_response", toolResultPretty)
|
await this.say("mcp_server_response", toolResultPretty)
|
||||||
pushToolResult(formatResponse.toolResult(toolResultPretty))
|
pushToolResult(formatResponse.toolResult(toolResultPretty))
|
||||||
break
|
break
|
||||||
@@ -1810,7 +1816,7 @@ export class Cline {
|
|||||||
serverName: removeClosingTag("server_name", server_name),
|
serverName: removeClosingTag("server_name", server_name),
|
||||||
uri: removeClosingTag("uri", uri),
|
uri: removeClosingTag("uri", uri),
|
||||||
} satisfies ClineAskUseMcpServer)
|
} satisfies ClineAskUseMcpServer)
|
||||||
await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => { })
|
await this.ask("use_mcp_server", partialMessage, block.partial).catch(() => {})
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
if (!server_name) {
|
if (!server_name) {
|
||||||
@@ -1866,7 +1872,7 @@ export class Cline {
|
|||||||
try {
|
try {
|
||||||
if (block.partial) {
|
if (block.partial) {
|
||||||
await this.ask("followup", removeClosingTag("question", question), block.partial).catch(
|
await this.ask("followup", removeClosingTag("question", question), block.partial).catch(
|
||||||
() => { },
|
() => {},
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
@@ -1925,7 +1931,7 @@ export class Cline {
|
|||||||
"command",
|
"command",
|
||||||
removeClosingTag("command", command),
|
removeClosingTag("command", command),
|
||||||
block.partial,
|
block.partial,
|
||||||
).catch(() => { })
|
).catch(() => {})
|
||||||
} else {
|
} else {
|
||||||
// last message is completion_result
|
// last message is completion_result
|
||||||
// we have command string, which means we have the result as well, so finish it (doesnt have to exist yet)
|
// we have command string, which means we have the result as well, so finish it (doesnt have to exist yet)
|
||||||
@@ -1939,7 +1945,7 @@ export class Cline {
|
|||||||
"command",
|
"command",
|
||||||
removeClosingTag("command", command),
|
removeClosingTag("command", command),
|
||||||
block.partial,
|
block.partial,
|
||||||
).catch(() => { })
|
).catch(() => {})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no command, still outputting partial result
|
// no command, still outputting partial result
|
||||||
@@ -2165,9 +2171,10 @@ export class Cline {
|
|||||||
type: "text",
|
type: "text",
|
||||||
text:
|
text:
|
||||||
assistantMessage +
|
assistantMessage +
|
||||||
`\n\n[${cancelReason === "streaming_failed"
|
`\n\n[${
|
||||||
? "Response interrupted by API Error"
|
cancelReason === "streaming_failed"
|
||||||
: "Response interrupted by user"
|
? "Response interrupted by API Error"
|
||||||
|
: "Response interrupted by user"
|
||||||
}]`,
|
}]`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -2421,7 +2428,7 @@ export class Cline {
|
|||||||
await pWaitFor(() => busyTerminals.every((t) => !this.terminalManager.isProcessHot(t.id)), {
|
await pWaitFor(() => busyTerminals.every((t) => !this.terminalManager.isProcessHot(t.id)), {
|
||||||
interval: 100,
|
interval: 100,
|
||||||
timeout: 15_000,
|
timeout: 15_000,
|
||||||
}).catch(() => { })
|
}).catch(() => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
// we want to get diagnostics AFTER terminal cools down for a few reasons: terminal could be scaffolding a project, dev servers (compilers like webpack) will first re-compile and then send diagnostics, etc
|
// we want to get diagnostics AFTER terminal cools down for a few reasons: terminal could be scaffolding a project, dev servers (compilers like webpack) will first re-compile and then send diagnostics, etc
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
diffEnabled,
|
diffEnabled,
|
||||||
fuzzyMatchThreshold
|
fuzzyMatchThreshold
|
||||||
} = await this.getState()
|
} = await this.getState()
|
||||||
|
|
||||||
this.cline = new Cline(
|
this.cline = new Cline(
|
||||||
this,
|
this,
|
||||||
apiConfiguration,
|
apiConfiguration,
|
||||||
@@ -255,7 +255,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
diffEnabled,
|
diffEnabled,
|
||||||
fuzzyMatchThreshold
|
fuzzyMatchThreshold
|
||||||
} = await this.getState()
|
} = await this.getState()
|
||||||
|
|
||||||
this.cline = new Cline(
|
this.cline = new Cline(
|
||||||
this,
|
this,
|
||||||
apiConfiguration,
|
apiConfiguration,
|
||||||
@@ -321,15 +321,15 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
|
|
||||||
// Use a nonce to only allow a specific script to be run.
|
// Use a nonce to only allow a specific script to be run.
|
||||||
/*
|
/*
|
||||||
content security policy of your webview to only allow scripts that have a specific nonce
|
content security policy of your webview to only allow scripts that have a specific nonce
|
||||||
create a content security policy meta tag so that only loading scripts with a nonce is allowed
|
create a content security policy meta tag so that only loading scripts with a nonce is allowed
|
||||||
As your extension grows you will likely want to add custom styles, fonts, and/or images to your webview. If you do, you will need to update the content security policy meta tag to explicity allow for these resources. E.g.
|
As your extension grows you will likely want to add custom styles, fonts, and/or images to your webview. If you do, you will need to update the content security policy meta tag to explicity allow for these resources. E.g.
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; font-src ${webview.cspSource}; img-src ${webview.cspSource} https:; script-src 'nonce-${nonce}';">
|
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; font-src ${webview.cspSource}; img-src ${webview.cspSource} https:; script-src 'nonce-${nonce}';">
|
||||||
- 'unsafe-inline' is required for styles due to vscode-webview-toolkit's dynamic style injection
|
- 'unsafe-inline' is required for styles due to vscode-webview-toolkit's dynamic style injection
|
||||||
- since we pass base64 images to the webview, we need to specify img-src ${webview.cspSource} data:;
|
- since we pass base64 images to the webview, we need to specify img-src ${webview.cspSource} data:;
|
||||||
|
|
||||||
in meta tag we add nonce attribute: A cryptographic nonce (only used once) to allow scripts. The server must generate a unique nonce value each time it transmits a policy. It is critical to provide a nonce that cannot be guessed as bypassing a resource's policy is otherwise trivial.
|
in meta tag we add nonce attribute: A cryptographic nonce (only used once) to allow scripts. The server must generate a unique nonce value each time it transmits a policy. It is critical to provide a nonce that cannot be guessed as bypassing a resource's policy is otherwise trivial.
|
||||||
*/
|
*/
|
||||||
const nonce = getNonce()
|
const nonce = getNonce()
|
||||||
|
|
||||||
// Tip: Install the es6-string-html VS Code extension to enable code highlighting below
|
// Tip: Install the es6-string-html VS Code extension to enable code highlighting below
|
||||||
@@ -557,7 +557,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
this.postMessageToWebview({ type: "lmStudioModels", lmStudioModels })
|
this.postMessageToWebview({ type: "lmStudioModels", lmStudioModels })
|
||||||
break
|
break
|
||||||
case "refreshGlamaModels":
|
case "refreshGlamaModels":
|
||||||
await this.refreshGlamaModels()
|
await this.refreshGlamaModels()
|
||||||
break
|
break
|
||||||
case "refreshOpenRouterModels":
|
case "refreshOpenRouterModels":
|
||||||
await this.refreshOpenRouterModels()
|
await this.refreshOpenRouterModels()
|
||||||
@@ -566,7 +566,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
if (message?.values?.baseUrl && message?.values?.apiKey) {
|
if (message?.values?.baseUrl && message?.values?.apiKey) {
|
||||||
const openAiModels = await this.getOpenAiModels(message?.values?.baseUrl, message?.values?.apiKey)
|
const openAiModels = await this.getOpenAiModels(message?.values?.baseUrl, message?.values?.apiKey)
|
||||||
this.postMessageToWebview({ type: "openAiModels", openAiModels })
|
this.postMessageToWebview({ type: "openAiModels", openAiModels })
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "openImage":
|
case "openImage":
|
||||||
openImage(message.text!)
|
openImage(message.text!)
|
||||||
@@ -1257,7 +1257,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
alwaysApproveResubmit,
|
alwaysApproveResubmit,
|
||||||
requestDelaySeconds,
|
requestDelaySeconds,
|
||||||
} = await this.getState()
|
} = await this.getState()
|
||||||
|
|
||||||
const allowedCommands = vscode.workspace
|
const allowedCommands = vscode.workspace
|
||||||
.getConfiguration('roo-cline')
|
.getConfiguration('roo-cline')
|
||||||
.get<string[]>('allowedCommands') || []
|
.get<string[]>('allowedCommands') || []
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ jest.mock('../../../integrations/misc/extract-text', () => ({
|
|||||||
|
|
||||||
// Spy on console.error and console.log to suppress expected messages
|
// Spy on console.error and console.log to suppress expected messages
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
jest.spyOn(console, 'error').mockImplementation(() => { })
|
jest.spyOn(console, 'error').mockImplementation(() => {})
|
||||||
jest.spyOn(console, 'log').mockImplementation(() => { })
|
jest.spyOn(console, 'log').mockImplementation(() => {})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
@@ -230,7 +230,7 @@ describe('ClineProvider', () => {
|
|||||||
|
|
||||||
test('resolveWebviewView sets up webview correctly', () => {
|
test('resolveWebviewView sets up webview correctly', () => {
|
||||||
provider.resolveWebviewView(mockWebviewView)
|
provider.resolveWebviewView(mockWebviewView)
|
||||||
|
|
||||||
expect(mockWebviewView.webview.options).toEqual({
|
expect(mockWebviewView.webview.options).toEqual({
|
||||||
enableScripts: true,
|
enableScripts: true,
|
||||||
localResourceRoots: [mockContext.extensionUri]
|
localResourceRoots: [mockContext.extensionUri]
|
||||||
@@ -240,7 +240,7 @@ describe('ClineProvider', () => {
|
|||||||
|
|
||||||
test('postMessageToWebview sends message to webview', async () => {
|
test('postMessageToWebview sends message to webview', async () => {
|
||||||
provider.resolveWebviewView(mockWebviewView)
|
provider.resolveWebviewView(mockWebviewView)
|
||||||
|
|
||||||
const mockState: ExtensionState = {
|
const mockState: ExtensionState = {
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
preferredLanguage: 'English',
|
preferredLanguage: 'English',
|
||||||
@@ -263,16 +263,15 @@ describe('ClineProvider', () => {
|
|||||||
browserViewportSize: "900x600",
|
browserViewportSize: "900x600",
|
||||||
fuzzyMatchThreshold: 1.0,
|
fuzzyMatchThreshold: 1.0,
|
||||||
mcpEnabled: true,
|
mcpEnabled: true,
|
||||||
alwaysApproveResubmit: false,
|
requestDelaySeconds: 5
|
||||||
requestDelaySeconds: 5,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const message: ExtensionMessage = {
|
const message: ExtensionMessage = {
|
||||||
type: 'state',
|
type: 'state',
|
||||||
state: mockState
|
state: mockState
|
||||||
}
|
}
|
||||||
await provider.postMessageToWebview(message)
|
await provider.postMessageToWebview(message)
|
||||||
|
|
||||||
expect(mockPostMessage).toHaveBeenCalledWith(message)
|
expect(mockPostMessage).toHaveBeenCalledWith(message)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -303,7 +302,7 @@ describe('ClineProvider', () => {
|
|||||||
|
|
||||||
test('getState returns correct initial state', async () => {
|
test('getState returns correct initial state', async () => {
|
||||||
const state = await provider.getState()
|
const state = await provider.getState()
|
||||||
|
|
||||||
expect(state).toHaveProperty('apiConfiguration')
|
expect(state).toHaveProperty('apiConfiguration')
|
||||||
expect(state.apiConfiguration).toHaveProperty('apiProvider')
|
expect(state.apiConfiguration).toHaveProperty('apiProvider')
|
||||||
expect(state).toHaveProperty('customInstructions')
|
expect(state).toHaveProperty('customInstructions')
|
||||||
@@ -320,7 +319,7 @@ describe('ClineProvider', () => {
|
|||||||
test('preferredLanguage defaults to VSCode language when not set', async () => {
|
test('preferredLanguage defaults to VSCode language when not set', async () => {
|
||||||
// Mock VSCode language as Spanish
|
// Mock VSCode language as Spanish
|
||||||
(vscode.env as any).language = 'es-ES';
|
(vscode.env as any).language = 'es-ES';
|
||||||
|
|
||||||
const state = await provider.getState();
|
const state = await provider.getState();
|
||||||
expect(state.preferredLanguage).toBe('Spanish');
|
expect(state.preferredLanguage).toBe('Spanish');
|
||||||
})
|
})
|
||||||
@@ -328,7 +327,7 @@ describe('ClineProvider', () => {
|
|||||||
test('preferredLanguage defaults to English for unsupported VSCode language', async () => {
|
test('preferredLanguage defaults to English for unsupported VSCode language', async () => {
|
||||||
// Mock VSCode language as an unsupported language
|
// Mock VSCode language as an unsupported language
|
||||||
(vscode.env as any).language = 'unsupported-LANG';
|
(vscode.env as any).language = 'unsupported-LANG';
|
||||||
|
|
||||||
const state = await provider.getState();
|
const state = await provider.getState();
|
||||||
expect(state.preferredLanguage).toBe('English');
|
expect(state.preferredLanguage).toBe('English');
|
||||||
})
|
})
|
||||||
@@ -336,9 +335,9 @@ describe('ClineProvider', () => {
|
|||||||
test('diffEnabled defaults to true when not set', async () => {
|
test('diffEnabled defaults to true when not set', async () => {
|
||||||
// Mock globalState.get to return undefined for diffEnabled
|
// Mock globalState.get to return undefined for diffEnabled
|
||||||
(mockContext.globalState.get as jest.Mock).mockReturnValue(undefined)
|
(mockContext.globalState.get as jest.Mock).mockReturnValue(undefined)
|
||||||
|
|
||||||
const state = await provider.getState()
|
const state = await provider.getState()
|
||||||
|
|
||||||
expect(state.diffEnabled).toBe(true)
|
expect(state.diffEnabled).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -350,7 +349,7 @@ describe('ClineProvider', () => {
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
const state = await provider.getState()
|
const state = await provider.getState()
|
||||||
expect(state.writeDelayMs).toBe(1000)
|
expect(state.writeDelayMs).toBe(1000)
|
||||||
})
|
})
|
||||||
@@ -358,9 +357,9 @@ describe('ClineProvider', () => {
|
|||||||
test('handles writeDelayMs message', async () => {
|
test('handles writeDelayMs message', async () => {
|
||||||
provider.resolveWebviewView(mockWebviewView)
|
provider.resolveWebviewView(mockWebviewView)
|
||||||
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
|
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
|
||||||
|
|
||||||
await messageHandler({ type: 'writeDelayMs', value: 2000 })
|
await messageHandler({ type: 'writeDelayMs', value: 2000 })
|
||||||
|
|
||||||
expect(mockContext.globalState.update).toHaveBeenCalledWith('writeDelayMs', 2000)
|
expect(mockContext.globalState.update).toHaveBeenCalledWith('writeDelayMs', 2000)
|
||||||
expect(mockPostMessage).toHaveBeenCalled()
|
expect(mockPostMessage).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,28 +8,28 @@ import { GitCommit } from "../utils/git"
|
|||||||
// webview will hold state
|
// webview will hold state
|
||||||
export interface ExtensionMessage {
|
export interface ExtensionMessage {
|
||||||
type:
|
type:
|
||||||
| "action"
|
| "action"
|
||||||
| "state"
|
| "state"
|
||||||
| "selectedImages"
|
| "selectedImages"
|
||||||
| "ollamaModels"
|
| "ollamaModels"
|
||||||
| "lmStudioModels"
|
| "lmStudioModels"
|
||||||
| "theme"
|
| "theme"
|
||||||
| "workspaceUpdated"
|
| "workspaceUpdated"
|
||||||
| "invoke"
|
| "invoke"
|
||||||
| "partialMessage"
|
| "partialMessage"
|
||||||
| "glamaModels"
|
| "glamaModels"
|
||||||
| "openRouterModels"
|
| "openRouterModels"
|
||||||
| "openAiModels"
|
| "openAiModels"
|
||||||
| "mcpServers"
|
| "mcpServers"
|
||||||
| "enhancedPrompt"
|
| "enhancedPrompt"
|
||||||
| "commitSearchResults"
|
| "commitSearchResults"
|
||||||
text?: string
|
text?: string
|
||||||
action?:
|
action?:
|
||||||
| "chatButtonClicked"
|
| "chatButtonClicked"
|
||||||
| "mcpButtonClicked"
|
| "mcpButtonClicked"
|
||||||
| "settingsButtonClicked"
|
| "settingsButtonClicked"
|
||||||
| "historyButtonClicked"
|
| "historyButtonClicked"
|
||||||
| "didBecomeVisible"
|
| "didBecomeVisible"
|
||||||
invoke?: "sendMessage" | "primaryButtonClick" | "secondaryButtonClick"
|
invoke?: "sendMessage" | "primaryButtonClick" | "secondaryButtonClick"
|
||||||
state?: ExtensionState
|
state?: ExtensionState
|
||||||
images?: string[]
|
images?: string[]
|
||||||
@@ -117,14 +117,14 @@ export type ClineSay =
|
|||||||
|
|
||||||
export interface ClineSayTool {
|
export interface ClineSayTool {
|
||||||
tool:
|
tool:
|
||||||
| "editedExistingFile"
|
| "editedExistingFile"
|
||||||
| "appliedDiff"
|
| "appliedDiff"
|
||||||
| "newFileCreated"
|
| "newFileCreated"
|
||||||
| "readFile"
|
| "readFile"
|
||||||
| "listFilesTopLevel"
|
| "listFilesTopLevel"
|
||||||
| "listFilesRecursive"
|
| "listFilesRecursive"
|
||||||
| "listCodeDefinitionNames"
|
| "listCodeDefinitionNames"
|
||||||
| "searchFiles"
|
| "searchFiles"
|
||||||
path?: string
|
path?: string
|
||||||
diff?: string
|
diff?: string
|
||||||
content?: string
|
content?: string
|
||||||
|
|||||||
@@ -1,59 +1,59 @@
|
|||||||
import { ApiConfiguration } from "./api"
|
import { ApiConfiguration, ApiProvider } from "./api"
|
||||||
|
|
||||||
export type AudioType = "notification" | "celebration" | "progress_loop"
|
export type AudioType = "notification" | "celebration" | "progress_loop"
|
||||||
|
|
||||||
export interface WebviewMessage {
|
export interface WebviewMessage {
|
||||||
type:
|
type:
|
||||||
| "apiConfiguration"
|
| "apiConfiguration"
|
||||||
| "customInstructions"
|
| "customInstructions"
|
||||||
| "allowedCommands"
|
| "allowedCommands"
|
||||||
| "alwaysAllowReadOnly"
|
| "alwaysAllowReadOnly"
|
||||||
| "alwaysAllowWrite"
|
| "alwaysAllowWrite"
|
||||||
| "alwaysAllowExecute"
|
| "alwaysAllowExecute"
|
||||||
| "webviewDidLaunch"
|
| "webviewDidLaunch"
|
||||||
| "newTask"
|
| "newTask"
|
||||||
| "askResponse"
|
| "askResponse"
|
||||||
| "clearTask"
|
| "clearTask"
|
||||||
| "didShowAnnouncement"
|
| "didShowAnnouncement"
|
||||||
| "selectImages"
|
| "selectImages"
|
||||||
| "exportCurrentTask"
|
| "exportCurrentTask"
|
||||||
| "showTaskWithId"
|
| "showTaskWithId"
|
||||||
| "deleteTaskWithId"
|
| "deleteTaskWithId"
|
||||||
| "exportTaskWithId"
|
| "exportTaskWithId"
|
||||||
| "resetState"
|
| "resetState"
|
||||||
| "requestOllamaModels"
|
| "requestOllamaModels"
|
||||||
| "requestLmStudioModels"
|
| "requestLmStudioModels"
|
||||||
| "openImage"
|
| "openImage"
|
||||||
| "openFile"
|
| "openFile"
|
||||||
| "openMention"
|
| "openMention"
|
||||||
| "cancelTask"
|
| "cancelTask"
|
||||||
| "refreshGlamaModels"
|
| "refreshGlamaModels"
|
||||||
| "refreshOpenRouterModels"
|
| "refreshOpenRouterModels"
|
||||||
| "refreshOpenAiModels"
|
| "refreshOpenAiModels"
|
||||||
| "alwaysAllowBrowser"
|
| "alwaysAllowBrowser"
|
||||||
| "alwaysAllowMcp"
|
| "alwaysAllowMcp"
|
||||||
| "playSound"
|
| "playSound"
|
||||||
| "soundEnabled"
|
| "soundEnabled"
|
||||||
| "soundVolume"
|
| "soundVolume"
|
||||||
| "diffEnabled"
|
| "diffEnabled"
|
||||||
| "browserViewportSize"
|
| "browserViewportSize"
|
||||||
| "screenshotQuality"
|
| "screenshotQuality"
|
||||||
| "openMcpSettings"
|
| "openMcpSettings"
|
||||||
| "restartMcpServer"
|
| "restartMcpServer"
|
||||||
| "toggleToolAlwaysAllow"
|
| "toggleToolAlwaysAllow"
|
||||||
| "toggleMcpServer"
|
| "toggleMcpServer"
|
||||||
| "fuzzyMatchThreshold"
|
| "fuzzyMatchThreshold"
|
||||||
| "preferredLanguage"
|
| "preferredLanguage"
|
||||||
| "writeDelayMs"
|
| "writeDelayMs"
|
||||||
| "enhancePrompt"
|
| "enhancePrompt"
|
||||||
| "enhancedPrompt"
|
| "enhancedPrompt"
|
||||||
| "draggedImages"
|
| "draggedImages"
|
||||||
| "deleteMessage"
|
| "deleteMessage"
|
||||||
| "terminalOutputLineLimit"
|
| "terminalOutputLineLimit"
|
||||||
| "mcpEnabled"
|
| "mcpEnabled"
|
||||||
| "searchCommits"
|
| "searchCommits"
|
||||||
| "alwaysApproveResubmit"
|
| "alwaysApproveResubmit"
|
||||||
| "requestDelaySeconds"
|
| "requestDelaySeconds"
|
||||||
text?: string
|
text?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
askResponse?: ClineAskResponse
|
askResponse?: ClineAskResponse
|
||||||
|
|||||||
@@ -96,18 +96,18 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||||||
const config = message.state?.apiConfiguration
|
const config = message.state?.apiConfiguration
|
||||||
const hasKey = config
|
const hasKey = config
|
||||||
? [
|
? [
|
||||||
config.apiKey,
|
config.apiKey,
|
||||||
config.glamaApiKey,
|
config.glamaApiKey,
|
||||||
config.openRouterApiKey,
|
config.openRouterApiKey,
|
||||||
config.awsRegion,
|
config.awsRegion,
|
||||||
config.vertexProjectId,
|
config.vertexProjectId,
|
||||||
config.openAiApiKey,
|
config.openAiApiKey,
|
||||||
config.ollamaModelId,
|
config.ollamaModelId,
|
||||||
config.lmStudioModelId,
|
config.lmStudioModelId,
|
||||||
config.geminiApiKey,
|
config.geminiApiKey,
|
||||||
config.openAiNativeApiKey,
|
config.openAiNativeApiKey,
|
||||||
config.deepSeekApiKey,
|
config.deepSeekApiKey,
|
||||||
].some((key) => key !== undefined)
|
].some((key) => key !== undefined)
|
||||||
: false
|
: false
|
||||||
setShowWelcome(!hasKey)
|
setShowWelcome(!hasKey)
|
||||||
setDidHydrateState(true)
|
setDidHydrateState(true)
|
||||||
|
|||||||
Reference in New Issue
Block a user