diff --git a/design/qwen-code-electron-desktop-implementation-plan.md b/design/qwen-code-electron-desktop-implementation-plan.md index 350dd7786..d4b92239a 100644 --- a/design/qwen-code-electron-desktop-implementation-plan.md +++ b/design/qwen-code-electron-desktop-implementation-plan.md @@ -133,7 +133,7 @@ order, verification, decisions, and remaining work. ### Slice 6: Permission Bridge -- Status: pending +- Status: complete - Goal: route ACP permission and ask-user-question callbacks to renderer and resolve responses with timeout cancellation. - Files: @@ -144,6 +144,12 @@ order, verification, decisions, and remaining work. - Permission requests are visible to the active session. - Closing a WS connection cancels pending requests. - Timeout defaults to deny/cancel. +- Progress: + - 2026-04-25: added `PermissionBridge` for ACP `requestPermission`, including + `ask_user_question` detection from tool raw input, typed WS request/response + messages, timeout cancellation, and session-disconnect cancellation. + - 2026-04-25: renderer chat state now tracks pending permission/question + prompts and sends selected options back over the active session socket. - Verification: - `npm run test --workspace=packages/desktop` - renderer store tests for allow, deny, and timeout state @@ -201,6 +207,10 @@ order, verification, decisions, and remaining work. needs WebSocket message shapes, while the VS Code handler is callback/UI oriented; shared extraction can happen after permission and settings slices stabilize the common surface. +- 2026-04-25: Treat `ask_user_question` as a specialized ACP permission request + in desktop, matching the VS Code companion behavior. The bridge returns + `cancelled` for cancel/reject option ids and passes answer payloads through + for submit responses. ## Verification Log @@ -267,6 +277,15 @@ order, verification, decisions, and remaining work. - `npm run lint --workspace=packages/desktop` passed. - `npm run typecheck --workspace=packages/desktop` passed. - `npm run build --workspace=packages/desktop` passed. +- 2026-04-25 Slice 6: + - `npx prettier --check design/qwen-code-electron-desktop-implementation-plan.md packages/desktop` passed. + - `npm run test --workspace=packages/desktop` passed: 4 files, 31 tests. + - `npm run lint --workspace=packages/desktop` passed. + - `npm run typecheck --workspace=packages/desktop` passed. + - `npm run build --workspace=packages/desktop` passed. + - `npm run typecheck` passed across workspaces. + - `npm run build` passed across the configured build order. Existing VS Code + companion lint warnings were reported by its build script, with no errors. ## Self Review Notes @@ -319,12 +338,20 @@ order, verification, decisions, and remaining work. - Main still does not auto-start a real ACP child process; the chat loop is verified with an injected fake ACP client and remains ready for the runtime integration slice. +- 2026-04-25 Slice 6: + - Permission responses are accepted only for pending request ids; stale or + unknown responses produce a typed socket error instead of resolving any ACP + callback. + - Pending permission and ask-user-question callbacks are cancelled when a + session loses its last socket or the bridge closes, preventing ACP hangs. + - The renderer prompt UI is intentionally minimal for this slice; richer + answer collection can reuse `@qwen-code/webui` dialogs once the shared + desktop state surface is stable. ## Remaining Work -- Commit Slice 5b. -- Start Slice 6 permission bridge: route ACP permission and ask-user-question - callbacks through the existing per-session WebSocket channel with timeout - cancellation. -- Continue through permission, settings/auth/model/mode, real ACP runtime - startup, and packaging slices until the architecture MVP is fully verified. +- Commit Slice 6. +- Start Slice 7 settings/auth/model/mode UI and supporting services while + preserving existing Qwen settings/auth semantics. +- Continue through settings/auth/model/mode, real ACP runtime startup, and + packaging slices until the architecture MVP is fully verified. diff --git a/packages/desktop/src/renderer/App.tsx b/packages/desktop/src/renderer/App.tsx index 683f3e6c5..e6d69bd25 100644 --- a/packages/desktop/src/renderer/App.tsx +++ b/packages/desktop/src/renderer/App.tsx @@ -183,6 +183,22 @@ export function App() { socketRef.current?.stopGeneration(); }, []); + const respondToPermission = useCallback( + (requestId: string, optionId: string) => { + socketRef.current?.respondToPermission(requestId, optionId); + dispatchChat({ type: 'clear_permission_request', requestId }); + }, + [], + ); + + const respondToAskUserQuestion = useCallback( + (requestId: string, optionId: string) => { + socketRef.current?.respondToAskUserQuestion(requestId, optionId, {}); + dispatchChat({ type: 'clear_ask_user_question', requestId }); + }, + [], + ); + const statusLabel = useMemo(() => { if (loadState.state === 'ready') { return 'Connected'; @@ -253,6 +269,11 @@ export function App() { +