feat: add terminal integration commands

- Add terminal context menu commands for:
  - Adding terminal content to context
  - Fixing failed commands
  - Explaining commands
- Implement terminal content selection and retrieval
- Add support prompts for terminal actions
- Register terminal action handlers
This commit is contained in:
sam hoang 2025-02-06 10:27:12 +07:00
parent fa80f4e160
commit 0ceb370008
8 changed files with 232 additions and 1 deletions

View file

@ -123,6 +123,31 @@
"command": "roo-cline.addToContext",
"title": "Roo Code: Add To Context",
"category": "Roo Code"
},
{
"command": "roo-cline.terminalAddToContext",
"title": "Roo Code: Add Terminal Content to Context",
"category": "Terminal"
},
{
"command": "roo-cline.terminalFixCommand",
"title": "Roo Code: Fix This Command",
"category": "Terminal"
},
{
"command": "roo-cline.terminalExplainCommand",
"title": "Roo Code: Explain This Command",
"category": "Terminal"
},
{
"command": "roo-cline.terminalFixCommandInCurrentTask",
"title": "Roo Code: Fix This Command (Current Task)",
"category": "Terminal"
},
{
"command": "roo-cline.terminalExplainCommandInCurrentTask",
"title": "Roo Code: Explain This Command (Current Task)",
"category": "Terminal"
}
],
"menus": {
@ -148,6 +173,28 @@
"group": "Roo Code@4"
}
],
"terminal/context": [
{
"command": "roo-cline.terminalAddToContext",
"group": "Roo Code@1"
},
{
"command": "roo-cline.terminalFixCommand",
"group": "Roo Code@2"
},
{
"command": "roo-cline.terminalExplainCommand",
"group": "Roo Code@3"
},
{
"command": "roo-cline.terminalFixCommandInCurrentTask",
"group": "Roo Code@5"
},
{
"command": "roo-cline.terminalExplainCommandInCurrentTask",
"group": "Roo Code@6"
}
],
"view/title": [
{
"command": "roo-cline.plusButtonClicked",

View file

@ -1,3 +1,4 @@
export { handleUri } from "./handleUri"
export { registerCommands } from "./registerCommands"
export { registerCodeActions } from "./registerCodeActions"
export { registerTerminalActions } from "./registerTerminalActions"

View file

@ -0,0 +1,56 @@
import * as vscode from "vscode"
import { ClineProvider } from "../core/webview/ClineProvider"
import { TerminalManager } from "../integrations/terminal/TerminalManager"
const TERMINAL_COMMAND_IDS = {
ADD_TO_CONTEXT: "roo-cline.terminalAddToContext",
FIX: "roo-cline.terminalFixCommand",
FIX_IN_CURRENT_TASK: "roo-cline.terminalFixCommandInCurrentTask",
EXPLAIN: "roo-cline.terminalExplainCommand",
EXPLAIN_IN_CURRENT_TASK: "roo-cline.terminalExplainCommandInCurrentTask",
} as const
export const registerTerminalActions = (context: vscode.ExtensionContext) => {
const terminalManager = new TerminalManager()
registerTerminalAction(context, terminalManager, TERMINAL_COMMAND_IDS.ADD_TO_CONTEXT, "TERMINAL_ADD_TO_CONTEXT")
registerTerminalActionPair(context, terminalManager, TERMINAL_COMMAND_IDS.FIX, "TERMINAL_FIX")
registerTerminalActionPair(context, terminalManager, TERMINAL_COMMAND_IDS.EXPLAIN, "TERMINAL_EXPLAIN")
}
const registerTerminalAction = (
context: vscode.ExtensionContext,
terminalManager: TerminalManager,
command: string,
promptType: "TERMINAL_ADD_TO_CONTEXT" | "TERMINAL_FIX" | "TERMINAL_EXPLAIN",
) => {
context.subscriptions.push(
vscode.commands.registerCommand(command, async (args: any) => {
let content = args.selection
if (!content || content === "") {
content = await terminalManager.getTerminalContents(promptType === "TERMINAL_ADD_TO_CONTEXT" ? -1 : 1)
}
if (!content) {
vscode.window.showWarningMessage("No terminal content selected")
return
}
await ClineProvider.handleTerminalAction(command, promptType, content)
}),
)
}
const registerTerminalActionPair = (
context: vscode.ExtensionContext,
terminalManager: TerminalManager,
baseCommand: string,
promptType: "TERMINAL_ADD_TO_CONTEXT" | "TERMINAL_FIX" | "TERMINAL_EXPLAIN",
) => {
// Register new task version
registerTerminalAction(context, terminalManager, baseCommand, promptType)
// Register current task version
registerTerminalAction(context, terminalManager, `${baseCommand}InCurrentTask`, promptType)
}

View file

@ -132,6 +132,42 @@ export class ClineProvider implements vscode.WebviewViewProvider {
public static readonly tabPanelId = "roo-cline.TabPanelProvider"
private static activeInstances: Set<ClineProvider> = new Set()
private disposables: vscode.Disposable[] = []
public static async handleTerminalAction(
command: string,
promptType: "TERMINAL_ADD_TO_CONTEXT" | "TERMINAL_FIX" | "TERMINAL_EXPLAIN",
terminalContent: string,
): Promise<void> {
const visibleProvider = await ClineProvider.getInstance()
if (!visibleProvider) {
return
}
const { customSupportPrompts } = await visibleProvider.getState()
const prompt = supportPrompt.create(promptType, { terminalContent }, customSupportPrompts)
if (command.endsWith("AddToContext")) {
await visibleProvider.postMessageToWebview({
type: "invoke",
invoke: "setChatBoxMessage",
text: prompt,
})
return
}
if (visibleProvider.cline && command.endsWith("InCurrentTask")) {
await visibleProvider.postMessageToWebview({
type: "invoke",
invoke: "sendMessage",
text: prompt,
})
return
}
await visibleProvider.initClineWithTask(prompt)
}
private view?: vscode.WebviewView | vscode.WebviewPanel
private isViewLaunched = false
private cline?: Cline

View file

@ -5,7 +5,7 @@ import { createClineAPI } from "./exports"
import "./utils/path" // Necessary to have access to String.prototype.toPosix.
import { CodeActionProvider } from "./core/CodeActionProvider"
import { DIFF_VIEW_URI_SCHEME } from "./integrations/editor/DiffViewProvider"
import { handleUri, registerCommands, registerCodeActions } from "./activate"
import { handleUri, registerCommands, registerCodeActions, registerTerminalActions } from "./activate"
/**
* Built using https://github.com/microsoft/vscode-webview-ui-toolkit
@ -78,6 +78,7 @@ export function activate(context: vscode.ExtensionContext) {
)
registerCodeActions(context)
registerTerminalActions(context)
return createClineAPI(outputChannel, sidebarProvider)
}

View file

@ -224,4 +224,57 @@ export class TerminalManager {
this.disposables.forEach((disposable) => disposable.dispose())
this.disposables = []
}
/**
* Gets the terminal contents based on the number of commands to include
* @param commands Number of previous commands to include (-1 for all)
* @returns The selected terminal contents
*/
public async getTerminalContents(commands = -1): Promise<string> {
// Save current clipboard content
const tempCopyBuffer = await vscode.env.clipboard.readText()
try {
// Select terminal content
if (commands < 0) {
await vscode.commands.executeCommand("workbench.action.terminal.selectAll")
} else {
for (let i = 0; i < commands; i++) {
await vscode.commands.executeCommand("workbench.action.terminal.selectToPreviousCommand")
}
}
// Copy selection and clear it
await vscode.commands.executeCommand("workbench.action.terminal.copySelection")
await vscode.commands.executeCommand("workbench.action.terminal.clearSelection")
// Get copied content
let terminalContents = (await vscode.env.clipboard.readText()).trim()
// Restore original clipboard content
await vscode.env.clipboard.writeText(tempCopyBuffer)
if (tempCopyBuffer === terminalContents) {
// No terminal content was copied
return ""
}
// Process multi-line content
const lines = terminalContents.split("\n")
const lastLine = lines.pop()?.trim()
if (lastLine) {
let i = lines.length - 1
while (i >= 0 && !lines[i].trim().startsWith(lastLine)) {
i--
}
terminalContents = lines.slice(Math.max(i, 0)).join("\n")
}
return terminalContents
} catch (error) {
// Ensure clipboard is restored even if an error occurs
await vscode.env.clipboard.writeText(tempCopyBuffer)
throw error
}
}
}

View file

@ -101,6 +101,43 @@ Provide the improved code along with explanations for each enhancement.`,
\${selectedText}
\`\`\``,
},
TERMINAL_ADD_TO_CONTEXT: {
label: "Add Terminal Content to Context",
description:
"Add terminal output to your current task or conversation. Useful for providing command outputs or logs. Available in the terminal context menu (right-click on selected terminal content).",
template: `Terminal output:
\`\`\`
\${terminalContent}
\`\`\``,
},
TERMINAL_FIX: {
label: "Fix Terminal Command",
description:
"Get help fixing terminal commands that failed or need improvement. Available in the terminal context menu (right-click on selected terminal content).",
template: `Fix this terminal command:
\`\`\`
\${terminalContent}
\`\`\`
Please:
1. Identify any issues in the command
2. Provide the corrected command
3. Explain what was fixed and why`,
},
TERMINAL_EXPLAIN: {
label: "Explain Terminal Command",
description:
"Get detailed explanations of terminal commands and their outputs. Available in the terminal context menu (right-click on selected terminal content).",
template: `Explain this terminal command:
\`\`\`
\${terminalContent}
\`\`\`
Please provide:
1. What the command does
2. Explanation of each part/flag
3. Expected output and behavior`,
},
} as const
type SupportPromptType = keyof typeof supportPromptConfigs