Skip to content

Commit 26dca01

Browse files
Simplify permission response handling and fix edit failure and VSCode diff issues (#1581)
* wip: edit fail and diff * refactor(vscode-ide-companion): Fixes #1524, simplify permission response handling Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
1 parent 72480f7 commit 26dca01

File tree

6 files changed

+39
-93
lines changed

6 files changed

+39
-93
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Qwen Team
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
export interface PermissionResponsePayload {
8+
optionId: string;
9+
}
10+
11+
export interface PermissionResponseMessage {
12+
type: string;
13+
data: PermissionResponsePayload;
14+
}

packages/vscode-ide-companion/src/webview/App.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ export const App: React.FC = () => {
431431
type: 'permissionResponse',
432432
data: { optionId },
433433
});
434+
434435
setPermissionRequest(null);
435436
},
436437
[vscode],

packages/vscode-ide-companion/src/webview/MessageHandler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import type { QwenAgentManager } from '../services/qwenAgentManager.js';
88
import type { ConversationStore } from '../services/conversationStore.js';
9+
import type { PermissionResponseMessage } from '../types/webviewMessageTypes.js';
910
import { MessageRouter } from './handlers/MessageRouter.js';
1011

1112
/**
@@ -55,7 +56,7 @@ export class MessageHandler {
5556
* Set permission handler
5657
*/
5758
setPermissionHandler(
58-
handler: (message: { type: string; data: { optionId: string } }) => void,
59+
handler: (message: PermissionResponseMessage) => void,
5960
): void {
6061
this.router.setPermissionHandler(handler);
6162
}

packages/vscode-ide-companion/src/webview/WebViewProvider.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as vscode from 'vscode';
88
import { QwenAgentManager } from '../services/qwenAgentManager.js';
99
import { ConversationStore } from '../services/conversationStore.js';
1010
import type { AcpPermissionRequest } from '../types/acpTypes.js';
11+
import type { PermissionResponseMessage } from '../types/webviewMessageTypes.js';
1112
import { PanelManager } from '../webview/PanelManager.js';
1213
import { MessageHandler } from '../webview/MessageHandler.js';
1314
import { WebViewContent } from '../webview/WebViewContent.js';
@@ -251,10 +252,7 @@ export class WebViewProvider {
251252
}
252253
}
253254
};
254-
const handler = (message: {
255-
type: string;
256-
data: { optionId: string };
257-
}) => {
255+
const handler = (message: PermissionResponseMessage) => {
258256
if (message.type !== 'permissionResponse') {
259257
return;
260258
}
@@ -270,6 +268,16 @@ export class WebViewProvider {
270268
optionId.toLowerCase().includes('reject');
271269

272270
if (isCancel) {
271+
// Close any open qwen-diff editors first
272+
try {
273+
void vscode.commands.executeCommand('qwen.diff.closeAll');
274+
} catch (err) {
275+
console.warn(
276+
'[WebViewProvider] Failed to close diffs after reject:',
277+
err,
278+
);
279+
}
280+
273281
// Fire and forget – do not block the ACP resolve
274282
(async () => {
275283
try {
@@ -296,7 +304,6 @@ export class WebViewProvider {
296304
const title =
297305
(request.toolCall as { title?: string } | undefined)
298306
?.title || '';
299-
// Normalize kind for UI – fall back to 'execute'
300307
let kind = ((
301308
request.toolCall as { kind?: string } | undefined
302309
)?.kind || 'execute') as string;
@@ -319,7 +326,6 @@ export class WebViewProvider {
319326
title,
320327
kind,
321328
status: 'failed',
322-
// Best-effort pass-through (used by UI hints)
323329
rawInput: (request.toolCall as { rawInput?: unknown })
324330
?.rawInput,
325331
locations: (

packages/vscode-ide-companion/src/webview/components/PermissionDrawer/PermissionDrawer.tsx

Lines changed: 6 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
2424
onClose,
2525
}) => {
2626
const [focusedIndex, setFocusedIndex] = useState(0);
27-
const [customMessage, setCustomMessage] = useState('');
2827
const containerRef = useRef<HTMLDivElement>(null);
29-
// Correct the ref type for custom input to HTMLInputElement to avoid subsequent forced casting
30-
const customInputRef = useRef<HTMLInputElement>(null);
3128

3229
console.log('PermissionDrawer rendered with isOpen:', isOpen, toolCall);
3330
// Prefer file name from locations, fall back to content[].path if present
@@ -94,10 +91,7 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
9491

9592
// Number keys 1-9 for quick select
9693
const numMatch = e.key.match(/^[1-9]$/);
97-
if (
98-
numMatch &&
99-
!customInputRef.current?.contains(document.activeElement)
100-
) {
94+
if (numMatch) {
10195
const index = parseInt(e.key, 10) - 1;
10296
if (index < options.length) {
10397
e.preventDefault();
@@ -109,7 +103,10 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
109103
// Arrow keys for navigation
110104
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
111105
e.preventDefault();
112-
const totalItems = options.length + 1; // +1 for custom input
106+
if (options.length === 0) {
107+
return;
108+
}
109+
const totalItems = options.length;
113110
if (e.key === 'ArrowDown') {
114111
setFocusedIndex((prev) => (prev + 1) % totalItems);
115112
} else {
@@ -118,10 +115,7 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
118115
}
119116

120117
// Enter to select
121-
if (
122-
e.key === 'Enter' &&
123-
!customInputRef.current?.contains(document.activeElement)
124-
) {
118+
if (e.key === 'Enter') {
125119
e.preventDefault();
126120
if (focusedIndex < options.length) {
127121
onResponse(options[focusedIndex].optionId);
@@ -234,79 +228,10 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
234228
</button>
235229
);
236230
})}
237-
238-
{/* Custom message input (extracted component) */}
239-
{(() => {
240-
const isFocused = focusedIndex === options.length;
241-
const rejectOptionId = options.find((o) =>
242-
o.kind.includes('reject'),
243-
)?.optionId;
244-
return (
245-
<CustomMessageInputRow
246-
isFocused={isFocused}
247-
customMessage={customMessage}
248-
setCustomMessage={setCustomMessage}
249-
onFocusRow={() => setFocusedIndex(options.length)}
250-
onSubmitReject={() => {
251-
if (rejectOptionId) {
252-
onResponse(rejectOptionId);
253-
}
254-
}}
255-
inputRef={customInputRef}
256-
/>
257-
);
258-
})()}
259231
</div>
260232
</div>
261233

262234
{/* Moved slide-up keyframes to Tailwind theme (tailwind.config.js) */}
263235
</div>
264236
);
265237
};
266-
267-
/**
268-
* CustomMessageInputRow: Reusable custom input row component (without hooks)
269-
*/
270-
interface CustomMessageInputRowProps {
271-
isFocused: boolean;
272-
customMessage: string;
273-
setCustomMessage: (val: string) => void;
274-
onFocusRow: () => void; // Set focus when mouse enters or input box is focused
275-
onSubmitReject: () => void; // Triggered when Enter is pressed (selecting reject option)
276-
inputRef: React.RefObject<HTMLInputElement | null>;
277-
}
278-
279-
const CustomMessageInputRow: React.FC<CustomMessageInputRowProps> = ({
280-
isFocused,
281-
customMessage,
282-
setCustomMessage,
283-
onFocusRow,
284-
onSubmitReject,
285-
inputRef,
286-
}) => (
287-
<div
288-
className={`flex items-center gap-2 px-2 py-1.5 text-left w-full box-border rounded-[4px] border-0 shadow-[inset_0_0_0_1px_var(--app-transparent-inner-border)] cursor-text text-[var(--app-primary-foreground)] ${
289-
isFocused ? 'text-[var(--app-list-active-foreground)]' : ''
290-
}`}
291-
onMouseEnter={onFocusRow}
292-
onClick={() => inputRef.current?.focus()}
293-
>
294-
<input
295-
ref={inputRef as React.LegacyRef<HTMLInputElement> | undefined}
296-
type="text"
297-
placeholder="Tell Qwen what to do instead"
298-
spellCheck={false}
299-
className="flex-1 bg-transparent border-0 outline-none text-sm placeholder:opacity-70"
300-
style={{ color: 'var(--app-input-foreground)' }}
301-
value={customMessage}
302-
onChange={(e) => setCustomMessage(e.target.value)}
303-
onFocus={onFocusRow}
304-
onKeyDown={(e) => {
305-
if (e.key === 'Enter' && !e.shiftKey && customMessage.trim()) {
306-
e.preventDefault();
307-
onSubmitReject();
308-
}
309-
}}
310-
/>
311-
</div>
312-
);

packages/vscode-ide-companion/src/webview/handlers/MessageRouter.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import type { IMessageHandler } from './BaseMessageHandler.js';
88
import type { QwenAgentManager } from '../../services/qwenAgentManager.js';
99
import type { ConversationStore } from '../../services/conversationStore.js';
10+
import type { PermissionResponseMessage } from '../../types/webviewMessageTypes.js';
1011
import { SessionMessageHandler } from './SessionMessageHandler.js';
1112
import { FileMessageHandler } from './FileMessageHandler.js';
1213
import { EditorMessageHandler } from './EditorMessageHandler.js';
@@ -22,7 +23,7 @@ export class MessageRouter {
2223
private authHandler: AuthMessageHandler;
2324
private currentConversationId: string | null = null;
2425
private permissionHandler:
25-
| ((message: { type: string; data: { optionId: string } }) => void)
26+
| ((message: PermissionResponseMessage) => void)
2627
| null = null;
2728

2829
constructor(
@@ -80,9 +81,7 @@ export class MessageRouter {
8081
// Handle permission response specially
8182
if (message.type === 'permissionResponse') {
8283
if (this.permissionHandler) {
83-
this.permissionHandler(
84-
message as { type: string; data: { optionId: string } },
85-
);
84+
this.permissionHandler(message as PermissionResponseMessage);
8685
}
8786
return;
8887
}
@@ -131,7 +130,7 @@ export class MessageRouter {
131130
* Set permission handler
132131
*/
133132
setPermissionHandler(
134-
handler: (message: { type: string; data: { optionId: string } }) => void,
133+
handler: (message: PermissionResponseMessage) => void,
135134
): void {
136135
this.permissionHandler = handler;
137136
}

0 commit comments

Comments
 (0)