Compare commits

..

7 Commits

Author SHA1 Message Date
yiliang114
8106e094e8 refactor(vscode-ide-companion): Fixes #1524, simplify permission response handling
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-01-22 21:09:13 +08:00
yiliang114
2818bb604d Merge branch 'main' of https://github.com/QwenLM/qwen-code into fix/edit-faild-and-vscode-diff 2026-01-22 16:36:22 +08:00
tanzhenxin
2aa681f610 Merge pull request #1578 from QwenLM/fix/pkg-dependence
fix prompts denpendence
2026-01-22 16:04:59 +08:00
tanzhenxin
a7e55ccf43 Merge pull request #1576 from QwenLM/fix/pkg-dependence
fix github pkg dependence
2026-01-22 15:30:29 +08:00
tanzhenxin
64eea4889d Merge pull request #1574 from QwenLM/fix/pkg-dependence
fix dependences of core pkg
2026-01-22 14:26:02 +08:00
yiliang114
571d2bd762 Merge branch 'main' of https://github.com/QwenLM/qwen-code into fix/edit-faild-and-vscode-diff 2026-01-22 00:25:29 +08:00
yiliang114
317d0af50e wip: edit fail and diff 2026-01-21 01:16:30 +08:00
6 changed files with 39 additions and 93 deletions

View File

@@ -0,0 +1,14 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
export interface PermissionResponsePayload {
optionId: string;
}
export interface PermissionResponseMessage {
type: string;
data: PermissionResponsePayload;
}

View File

@@ -431,6 +431,7 @@ export const App: React.FC = () => {
type: 'permissionResponse',
data: { optionId },
});
setPermissionRequest(null);
},
[vscode],

View File

@@ -6,6 +6,7 @@
import type { QwenAgentManager } from '../services/qwenAgentManager.js';
import type { ConversationStore } from '../services/conversationStore.js';
import type { PermissionResponseMessage } from '../types/webviewMessageTypes.js';
import { MessageRouter } from './handlers/MessageRouter.js';
/**
@@ -55,7 +56,7 @@ export class MessageHandler {
* Set permission handler
*/
setPermissionHandler(
handler: (message: { type: string; data: { optionId: string } }) => void,
handler: (message: PermissionResponseMessage) => void,
): void {
this.router.setPermissionHandler(handler);
}

View File

@@ -8,6 +8,7 @@ import * as vscode from 'vscode';
import { QwenAgentManager } from '../services/qwenAgentManager.js';
import { ConversationStore } from '../services/conversationStore.js';
import type { AcpPermissionRequest } from '../types/acpTypes.js';
import type { PermissionResponseMessage } from '../types/webviewMessageTypes.js';
import { PanelManager } from '../webview/PanelManager.js';
import { MessageHandler } from '../webview/MessageHandler.js';
import { WebViewContent } from '../webview/WebViewContent.js';
@@ -251,10 +252,7 @@ export class WebViewProvider {
}
}
};
const handler = (message: {
type: string;
data: { optionId: string };
}) => {
const handler = (message: PermissionResponseMessage) => {
if (message.type !== 'permissionResponse') {
return;
}
@@ -270,6 +268,16 @@ export class WebViewProvider {
optionId.toLowerCase().includes('reject');
if (isCancel) {
// Close any open qwen-diff editors first
try {
void vscode.commands.executeCommand('qwen.diff.closeAll');
} catch (err) {
console.warn(
'[WebViewProvider] Failed to close diffs after reject:',
err,
);
}
// Fire and forget do not block the ACP resolve
(async () => {
try {
@@ -296,7 +304,6 @@ export class WebViewProvider {
const title =
(request.toolCall as { title?: string } | undefined)
?.title || '';
// Normalize kind for UI fall back to 'execute'
let kind = ((
request.toolCall as { kind?: string } | undefined
)?.kind || 'execute') as string;
@@ -319,7 +326,6 @@ export class WebViewProvider {
title,
kind,
status: 'failed',
// Best-effort pass-through (used by UI hints)
rawInput: (request.toolCall as { rawInput?: unknown })
?.rawInput,
locations: (

View File

@@ -24,10 +24,7 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
onClose,
}) => {
const [focusedIndex, setFocusedIndex] = useState(0);
const [customMessage, setCustomMessage] = useState('');
const containerRef = useRef<HTMLDivElement>(null);
// Correct the ref type for custom input to HTMLInputElement to avoid subsequent forced casting
const customInputRef = useRef<HTMLInputElement>(null);
console.log('PermissionDrawer rendered with isOpen:', isOpen, toolCall);
// Prefer file name from locations, fall back to content[].path if present
@@ -94,10 +91,7 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
// Number keys 1-9 for quick select
const numMatch = e.key.match(/^[1-9]$/);
if (
numMatch &&
!customInputRef.current?.contains(document.activeElement)
) {
if (numMatch) {
const index = parseInt(e.key, 10) - 1;
if (index < options.length) {
e.preventDefault();
@@ -109,7 +103,10 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
// Arrow keys for navigation
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault();
const totalItems = options.length + 1; // +1 for custom input
if (options.length === 0) {
return;
}
const totalItems = options.length;
if (e.key === 'ArrowDown') {
setFocusedIndex((prev) => (prev + 1) % totalItems);
} else {
@@ -118,10 +115,7 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
}
// Enter to select
if (
e.key === 'Enter' &&
!customInputRef.current?.contains(document.activeElement)
) {
if (e.key === 'Enter') {
e.preventDefault();
if (focusedIndex < options.length) {
onResponse(options[focusedIndex].optionId);
@@ -234,28 +228,6 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
</button>
);
})}
{/* Custom message input (extracted component) */}
{(() => {
const isFocused = focusedIndex === options.length;
const rejectOptionId = options.find((o) =>
o.kind.includes('reject'),
)?.optionId;
return (
<CustomMessageInputRow
isFocused={isFocused}
customMessage={customMessage}
setCustomMessage={setCustomMessage}
onFocusRow={() => setFocusedIndex(options.length)}
onSubmitReject={() => {
if (rejectOptionId) {
onResponse(rejectOptionId);
}
}}
inputRef={customInputRef}
/>
);
})()}
</div>
</div>
@@ -263,50 +235,3 @@ export const PermissionDrawer: React.FC<PermissionDrawerProps> = ({
</div>
);
};
/**
* CustomMessageInputRow: Reusable custom input row component (without hooks)
*/
interface CustomMessageInputRowProps {
isFocused: boolean;
customMessage: string;
setCustomMessage: (val: string) => void;
onFocusRow: () => void; // Set focus when mouse enters or input box is focused
onSubmitReject: () => void; // Triggered when Enter is pressed (selecting reject option)
inputRef: React.RefObject<HTMLInputElement | null>;
}
const CustomMessageInputRow: React.FC<CustomMessageInputRowProps> = ({
isFocused,
customMessage,
setCustomMessage,
onFocusRow,
onSubmitReject,
inputRef,
}) => (
<div
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)] ${
isFocused ? 'text-[var(--app-list-active-foreground)]' : ''
}`}
onMouseEnter={onFocusRow}
onClick={() => inputRef.current?.focus()}
>
<input
ref={inputRef as React.LegacyRef<HTMLInputElement> | undefined}
type="text"
placeholder="Tell Qwen what to do instead"
spellCheck={false}
className="flex-1 bg-transparent border-0 outline-none text-sm placeholder:opacity-70"
style={{ color: 'var(--app-input-foreground)' }}
value={customMessage}
onChange={(e) => setCustomMessage(e.target.value)}
onFocus={onFocusRow}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey && customMessage.trim()) {
e.preventDefault();
onSubmitReject();
}
}}
/>
</div>
);

View File

@@ -7,6 +7,7 @@
import type { IMessageHandler } from './BaseMessageHandler.js';
import type { QwenAgentManager } from '../../services/qwenAgentManager.js';
import type { ConversationStore } from '../../services/conversationStore.js';
import type { PermissionResponseMessage } from '../../types/webviewMessageTypes.js';
import { SessionMessageHandler } from './SessionMessageHandler.js';
import { FileMessageHandler } from './FileMessageHandler.js';
import { EditorMessageHandler } from './EditorMessageHandler.js';
@@ -22,7 +23,7 @@ export class MessageRouter {
private authHandler: AuthMessageHandler;
private currentConversationId: string | null = null;
private permissionHandler:
| ((message: { type: string; data: { optionId: string } }) => void)
| ((message: PermissionResponseMessage) => void)
| null = null;
constructor(
@@ -80,9 +81,7 @@ export class MessageRouter {
// Handle permission response specially
if (message.type === 'permissionResponse') {
if (this.permissionHandler) {
this.permissionHandler(
message as { type: string; data: { optionId: string } },
);
this.permissionHandler(message as PermissionResponseMessage);
}
return;
}
@@ -131,7 +130,7 @@ export class MessageRouter {
* Set permission handler
*/
setPermissionHandler(
handler: (message: { type: string; data: { optionId: string } }) => void,
handler: (message: PermissionResponseMessage) => void,
): void {
this.permissionHandler = handler;
}