Просмотр исходного кода

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
sam hoang 10 месяцев назад
Родитель
Сommit
0ceb370008

+ 47 - 0
package.json

@@ -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",

+ 1 - 0
src/activate/index.ts

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

+ 56 - 0
src/activate/registerTerminalActions.ts

@@ -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)
+}

+ 36 - 0
src/core/webview/ClineProvider.ts

@@ -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

+ 2 - 1
src/extension.ts

@@ -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)
 }

+ 0 - 0
src/integrations/terminal/TerminalActions.ts


+ 53 - 0
src/integrations/terminal/TerminalManager.ts

@@ -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
+		}
+	}
 }

+ 37 - 0
src/shared/support-prompt.ts

@@ -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