Skip to content

Commit 161480b

Browse files
committed
feat: Add commands and shortcut keys to send clipboard content to human relay
1 parent fb1550c commit 161480b

File tree

5 files changed

+65
-17
lines changed

5 files changed

+65
-17
lines changed

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@
153153
"command": "roo-cline.terminalExplainCommandInCurrentTask",
154154
"title": "Roo Code: Explain This Command (Current Task)",
155155
"category": "Terminal"
156+
},
157+
{
158+
"command": "roo-cline.sendClipboardToHumanRelay",
159+
"title": "Roo Code: Send Clipboard Content to Human Relay",
160+
"category": "Roo Code"
161+
}
162+
],
163+
"keybindings": [
164+
{
165+
"command": "roo-cline.sendClipboardToHumanRelay",
166+
"key": "ctrl+alt+v",
167+
"mac": "cmd+alt+v"
156168
}
157169
],
158170
"menus": {

src/activate/humanRelay.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import * as vscode from "vscode"
2+
import { getPanel } from "./registerCommands"
3+
14
// Callback mapping of human relay response.
25
const humanRelayCallbacks = new Map<string, (response: string | undefined) => void>()
36

@@ -24,3 +27,36 @@ export const handleHumanRelayResponse = (response: { requestId: string; text?: s
2427
humanRelayCallbacks.delete(response.requestId)
2528
}
2629
}
30+
31+
/**
32+
* Validate if content contains any tags in <xxx> format
33+
*/
34+
export function containsValidTags(content: string): boolean {
35+
const tagPattern = /<[^>]+>/
36+
return tagPattern.test(content)
37+
}
38+
39+
export const sendClipboardToHumanRelay = async () => {
40+
const panel = getPanel()
41+
if (!panel) {
42+
return
43+
}
44+
45+
try {
46+
const clipboardText = await vscode.env.clipboard.readText()
47+
if (!clipboardText) {
48+
return
49+
}
50+
51+
const requestId = "SendAIResponse"
52+
53+
panel?.webview.postMessage({ type: "closeHumanRelayDialog" })
54+
55+
vscode.commands.executeCommand("roo-cline.handleHumanRelayResponse", {
56+
requestId,
57+
text: clipboardText,
58+
})
59+
} catch (error) {
60+
console.error("Failed to process clipboard content:", error)
61+
}
62+
}

src/activate/registerCommands.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import delay from "delay"
33

44
import { ClineProvider } from "../core/webview/ClineProvider"
55

6-
import { registerHumanRelayCallback, unregisterHumanRelayCallback, handleHumanRelayResponse } from "./humanRelay"
6+
import {
7+
registerHumanRelayCallback,
8+
unregisterHumanRelayCallback,
9+
handleHumanRelayResponse,
10+
sendClipboardToHumanRelay,
11+
} from "./humanRelay"
712

813
// Store panel references in both modes
914
let sidebarPanel: vscode.WebviewView | undefined = undefined
@@ -85,6 +90,7 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
8590
"roo-cline.registerHumanRelayCallback": registerHumanRelayCallback,
8691
"roo-cline.unregisterHumanRelayCallback": unregisterHumanRelayCallback,
8792
"roo-cline.handleHumanRelayResponse": handleHumanRelayResponse,
93+
"roo-cline.sendClipboardToHumanRelay": sendClipboardToHumanRelay,
8894
}
8995
}
9096

src/api/providers/human-relay.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { ApiHandlerOptions, ModelInfo } from "../../shared/api"
33
import { ApiHandler, SingleCompletionHandler } from "../index"
44
import { ApiStream } from "../transform/stream"
55
import * as vscode from "vscode"
6-
import { ExtensionMessage } from "../../shared/ExtensionMessage"
76
import { getPanel } from "../../activate/registerCommands"
7+
import { containsValidTags } from "../../activate/humanRelay"
88

99
/**
1010
* Human Relay API processor
@@ -103,11 +103,10 @@ function getMessageContent(message: Anthropic.Messages.MessageParam): string {
103103
}
104104

105105
// Global variables
106-
let lastAIResponse: string | null = null
107106
let normalizedPrompt: string | null = null
107+
let currentPrompt: string | null = null
108108
let normalizedLastResponse: string | null = null
109109
let globalClipboardInterval: NodeJS.Timeout | null = null
110-
let lastMonitorOptions: ApiHandlerOptions | undefined
111110

112111
/**
113112
* Normalize text by removing extra spaces
@@ -136,15 +135,13 @@ function stopClipboardMonitoring() {
136135
}
137136
}
138137

139-
// Store clipboard content when monitoring starts
140-
let clipboardContentAtMonitorStart: string | null = null
141-
142138
/**
143139
* Start clipboard monitoring
144140
*/
145141
async function startClipboardMonitoring(requestId: string, options?: ApiHandlerOptions) {
146142
// Stop any existing monitoring
147143
stopClipboardMonitoring()
144+
vscode.env.clipboard.writeText(currentPrompt ?? "")
148145

149146
// Start new monitoring
150147
const monitorInterval = Math.min(Math.max(100, options?.humanRelayMonitorInterval ?? 500), 2000)
@@ -178,7 +175,6 @@ async function startClipboardMonitoring(requestId: string, options?: ApiHandlerO
178175

179176
// Process valid new response
180177
if (normalizedClipboard !== normalizedPrompt) {
181-
lastAIResponse = currentClipboardContent
182178
normalizedLastResponse = normalizedClipboard
183179

184180
// Clear timer
@@ -201,11 +197,12 @@ async function startClipboardMonitoring(requestId: string, options?: ApiHandlerO
201197
* Display human relay dialog and wait for user response
202198
*/
203199
async function showHumanRelayDialog(promptText: string, options?: ApiHandlerOptions): Promise<string | undefined> {
200+
currentPrompt = promptText
204201
normalizedPrompt = normalizeText(promptText)
205202

206203
return new Promise<string | undefined>((resolve) => {
207204
// Create unique request ID
208-
const requestId = Date.now().toString()
205+
const requestId = "SendAIResponse"
209206

210207
// Register global callback function
211208
vscode.commands.executeCommand(
@@ -243,11 +240,3 @@ async function showHumanRelayDialog(promptText: string, options?: ApiHandlerOpti
243240
}
244241
})
245242
}
246-
247-
/**
248-
* Validate if content contains any tags in <xxx> format
249-
*/
250-
function containsValidTags(content: string): boolean {
251-
const tagPattern = /<[^>]+>/
252-
return tagPattern.test(content)
253-
}

webview-ui/src/components/human-relay/HumanRelayDialog.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ export const HumanRelayDialog: React.FC<HumanRelayDialogProps> = ({
159159
</Button>
160160
</div>
161161

162+
<div className="text-sm text-vscode-descriptionForeground mt-2">
163+
You can use the shortcut Ctrl/Cmd+Alt+V (default) to send the clipboard content. You can also
164+
search for `Send Clipboard` in the shortcut settings to modify the hotkey.
165+
</div>
166+
162167
<div>
163168
<div className="mb-2 font-medium">Please enter the AI's response:</div>
164169
<Textarea

0 commit comments

Comments
 (0)