diff --git a/design/qwen-code-electron-desktop-implementation-plan.md b/design/qwen-code-electron-desktop-implementation-plan.md index 3bedf995b..2b4035604 100644 --- a/design/qwen-code-electron-desktop-implementation-plan.md +++ b/design/qwen-code-electron-desktop-implementation-plan.md @@ -20,766 +20,6 @@ execution order, verification, decisions, and remaining work. - Every completed slice must leave targeted verification and a conventional commit. -## Current Status - -Slices 1-18 established the desktop package, Electron main/preload/renderer -startup, authenticated health/runtime/settings/session APIs, ACP process -wrapper, WebSocket chat loop, permission bridge, settings/model/mode controls, -packaging configuration, package smoke verification, project/Git status, -renderer asset/CDP startup support, the componentized workspace shell, the -CDP-driven Electron E2E harness, hunk-aware diff review controls, terminal -stdin/copy/send-to-AI controls, UI-driven commit coverage, final package launch -smoke verification, and the Ralph/home.jpg-aligned fixed-viewport workbench -layout. - -Iteration 13 corrected the renderer layout drift called out in -`.qwen/scripts/electron-desktop-ralph-prompt.md` by reshaping the visible -workspace around the `docs/design/qwen-code-electron-desktop/home.jpg` -reference: narrow project/thread sidebar, compact top status bar, dominant -conversation canvas, independently scrolling review panel, and docked terminal -drawer. PTY resize, terminal tabs/history, persisted review comments, worktree -tasks, and richer artifacts remain deferred beyond MVP. - ## Task Breakdown -### Slice 1: Desktop Workspace Skeleton and Health Service - -- Status: complete -- Goal: runnable desktop package with Electron main/preload, React renderer, - and authenticated `/health`. -- Verification: desktop tests, lint, typecheck, build, root typecheck/build. - -### Slice 2: Desktop Server Runtime Surface - -- Status: complete -- Goal: authenticated `/api/runtime` with CLI/platform/auth summary. -- Verification: desktop tests, lint, typecheck, build, root typecheck/build. - -### Slice 3: ACP Process Client Wrapper - -- Status: complete -- Goal: desktop-local ACP child-process client for - `qwen --acp --channel=Desktop`. -- Verification: desktop tests, lint, typecheck, build, root typecheck/build. - -### Slice 4: Session REST API - -- Status: complete -- Goal: ACP-backed session create/list/load/delete/rename endpoints. -- Verification: desktop tests, lint, typecheck, build, root typecheck/build. - -### Slice 5: WebSocket Chat Loop - -- Status: complete -- Goal: authenticated per-session WebSocket prompt/cancel/update stream. -- Verification: desktop tests, lint, typecheck, build. - -### Slice 6: Permission Bridge - -- Status: complete -- Goal: route ACP permission and ask-user-question callbacks to renderer and - resolve responses with timeout cancellation. -- Verification: desktop tests, lint, typecheck, build, root typecheck/build. - -### Slice 7: Settings, Auth, Model, and Mode UI - -- Status: complete -- Goal: expose Qwen settings/auth/model/mode controls without returning secrets. -- Verification: desktop tests, lint, typecheck, build, root typecheck/build. - -### Slice 8: Packaging and Smoke Test - -- Status: complete -- Goal: package a desktop app that can launch with bundled CLI resources. -- Verification: desktop tests, lint, typecheck, build, bundle, - `package:dir`, package smoke, package launch smoke, root typecheck/build. - -### Slice 9: Project Registry and Git Status - -- Status: complete in iteration 7 -- Goal: make opened projects first-class desktop server data and surface Git - branch/status in the workbench. -- Files: - - `packages/desktop/src/server/services/projectService.ts` - - `packages/desktop/src/server/index.ts` - - `packages/desktop/src/server/index.test.ts` - - `packages/desktop/src/server/types.ts` - - `packages/desktop/src/renderer/api/client.ts` - - `packages/desktop/src/renderer/App.tsx` - - `packages/desktop/src/renderer/styles.css` -- Acceptance criteria: - - `GET /api/projects` returns recent projects from a Qwen global desktop - store. - - `POST /api/projects/open` validates a directory, persists it as recent, - and returns name/path/branch/status. - - `GET /api/projects/:id/git/status` refreshes Git status for a registered - project. - - Renderer Open Project flow registers the selected directory through the - server, lists recent projects, scopes thread creation/listing to the active - project, and shows branch/status in the top bar and review panel. -- Verification: - - `npm run test --workspace=packages/desktop` - - `npm run typecheck --workspace=packages/desktop` - - `npm run lint --workspace=packages/desktop` - - `npm run build --workspace=packages/desktop` -- E2E coverage: - - Record in - `.qwen/e2e-tests/electron-desktop/project-git-status.md`. - - Later Playwright Electron coverage must use a temporary Git workspace, - choose it through the preload dialog hook/fake native bridge, assert recent - project visibility, branch/status chips, and no black screen. - -### Slice 10: Renderer Asset Loading and CDP Port - -- Status: complete in iteration 7 -- Goal: make the built renderer load reliably from Electron main and expose a - local-only Chrome DevTools Protocol endpoint when explicitly requested for - tests/debugging. -- Files: - - `packages/desktop/src/main/main.ts` - - `packages/desktop/src/main/lifecycle/remoteDebugging.ts` - - `packages/desktop/src/main/lifecycle/remoteDebugging.test.ts` - - `packages/desktop/src/main/windows/MainWindow.ts` - - `packages/desktop/vite.config.ts` -- Acceptance criteria: - - `QWEN_DESKTOP_CDP_PORT=` appends Electron remote debugging switches - for `127.0.0.1` and the requested numeric port only. - - Invalid ports do not enable remote debugging. - - Built renderer assets use relative URLs so `file://.../dist/renderer` can - load CSS/JS. - - MainWindow resolves preload and renderer paths correctly from - `dist/main/windows`. -- Verification: - - `npm run test --workspace=packages/desktop` - - `npm run typecheck --workspace=packages/desktop` - - `npm run lint --workspace=packages/desktop` - - `npm run build --workspace=packages/desktop` - - `QWEN_DESKTOP_CDP_PORT=9339 npm run start --workspace=packages/desktop` - exposed `http://127.0.0.1:9339/json/version` and `/json/list`; process was - terminated after endpoint verification. -- E2E coverage: - - Record in - `.qwen/e2e-tests/electron-desktop/cdp-renderer-observability.md`. - - Later Playwright/DevTools MCP coverage must connect to the page websocket, - assert DOM text and console/network health, and save a screenshot. - -### Slice 11: Workspace Review Shell - -- Status: complete in iteration 8 -- Goal: split the renderer into explicit TopBar, ProjectSidebar, ThreadList, - ChatThread, ReviewPanel, and TerminalDrawer components while preserving the - current server-backed project/session/chat/settings behavior. -- Files: - - `packages/desktop/src/renderer/App.tsx` - - `packages/desktop/src/renderer/components/layout/WorkspacePage.tsx` - - `packages/desktop/src/renderer/components/layout/TopBar.tsx` - - `packages/desktop/src/renderer/components/layout/ProjectSidebar.tsx` - - `packages/desktop/src/renderer/components/layout/ThreadList.tsx` - - `packages/desktop/src/renderer/components/layout/ChatThread.tsx` - - `packages/desktop/src/renderer/components/layout/ReviewPanel.tsx` - - `packages/desktop/src/renderer/components/layout/TerminalDrawer.tsx` - - `packages/desktop/src/renderer/components/layout/StatusPill.tsx` - - `packages/desktop/src/renderer/components/layout/formatters.ts` - - `packages/desktop/src/renderer/components/layout/types.ts` - - `packages/desktop/src/renderer/components/layout/WorkspacePage.test.tsx` - - `packages/desktop/vitest.config.ts` -- Acceptance criteria: - - First workspace viewport visibly contains top bar, project/thread sidebar, - central thread, right review tabs, and bottom terminal drawer structure. - - No renderer Node access or IPC broadening. - - Existing desktop tests and typecheck still pass. -- Completed: - - Kept `App.tsx` as the server/state coordinator and moved visible shell - regions into explicit renderer layout components. - - Added stable `data-testid` landmarks for future Electron E2E and DevTools - MCP assertions. - - Added a jsdom renderer smoke test that renders fake project/session/diff - data and asserts the workbench landmarks. -- Verification: - - `npm run test --workspace=packages/desktop` passed: 9 files, 53 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. - - `npm run build` passed. Existing VS Code companion lint warnings remain - warnings only and unrelated to desktop. - - `npm run typecheck` passed. -- E2E coverage: - - Recorded in - `.qwen/e2e-tests/electron-desktop/workspace-review-shell.md`. - - Current coverage is a jsdom renderer landmark smoke test; Slice 14 must - launch Electron and assert the same landmarks through CDP with screenshot, - console, and network diagnostics. - -### Slice 12: Diff Review and Commit - -- Status: partial complete in iteration 7 -- Goal: add Git diff/status review APIs and UI actions for accept/revert and - commit. -- Files: - - `packages/desktop/src/server/services/gitReviewService.ts` - - `packages/desktop/src/server/index.ts` - - `packages/desktop/src/server/index.test.ts` - - `packages/desktop/src/server/services/projectService.ts` - - `packages/desktop/src/renderer/api/client.ts` - - `packages/desktop/src/renderer/App.tsx` - - `packages/desktop/src/renderer/styles.css` -- Acceptance criteria: - - Right Changes tab shows changed files and unified diff. - - Stage/unstage/revert/commit routes are token protected and scoped to a - registered project. - - Commit errors are visible in the UI. -- Completed: - - Token-protected diff, stage, revert, and commit routes scoped to registered - projects. - - Basic right Review panel changed-file list, textual diff preview, Stage - All, Revert All, commit message input, and Commit action. - - Server tests for diff, stage, commit, revert, invalid project path, and Git - status metadata. -- Remaining: - - Hunk-level accept/revert, inline comments, Open in Editor, richer file tree, - and renderer E2E coverage. -- E2E coverage: - - Record in `.qwen/e2e-tests/electron-desktop/diff-review-commit.md`. - - Later Electron E2E must use a temporary Git workspace with a fake file - change, accept/stage, commit, and error diagnostics. - -### Slice 13: Scoped Terminal - -- Status: partial complete in iteration 7 -- Goal: add a current-project/current-thread terminal drawer with spawn, output, - clear, kill, and send-output-to-AI plumbing. -- Files: - - `packages/desktop/src/server/services/terminalService.ts` - - `packages/desktop/src/server/index.ts` - - `packages/desktop/src/server/index.test.ts` - - `packages/desktop/src/renderer/api/client.ts` - - `packages/desktop/src/renderer/App.tsx` - - `packages/desktop/src/renderer/styles.css` -- Acceptance criteria: - - Terminal cwd is constrained to the active project. - - Terminal output is visible and copyable; kill and clear work. - - Agent command permission remains separate from user terminal execution. -- Completed: - - Token-protected terminal run/get/kill routes resolve cwd from the - registered project id. - - Bottom drawer runs project-scoped commands, polls output while running, - supports Kill and Clear, and does not use renderer Node APIs. - - Server tests cover command output and killing a running command. -- Remaining: - - Interactive PTY resize/write, output selection/copy polish, send output to - AI, terminal tabs/history, and Electron renderer E2E. -- E2E coverage: - - Record in `.qwen/e2e-tests/electron-desktop/terminal-drawer.md`. - - Later Electron E2E must run a harmless command in a temporary workspace and - assert output appears in the drawer. - -### Slice 14: Desktop E2E Harness - -- Status: complete in iteration 9 -- Goal: add repeatable Electron E2E harness with fake ACP, temporary HOME and - workspace, screenshot/console/network diagnostics, and CDP renderer access. -- Files: - - `packages/desktop/package.json` - - `packages/desktop/scripts/e2e-cdp-smoke.mjs` - - `packages/desktop/src/main/acp/createE2eAcpClient.ts` - - `packages/desktop/src/main/main.ts` - - `packages/desktop/src/main/native/dialogs.ts` -- Acceptance criteria: - - `QWEN_DESKTOP_CDP_PORT` is used by the harness to inspect the renderer on - `127.0.0.1`. - - E2E asserts first screen is not black, service is connected, project open - works, thread creation works, permission response works, settings save - works, and package smoke still passes. - - Failures write screenshots, console errors, failed requests, and main logs - under `.qwen/e2e-tests/electron-desktop/`. -- Completed: - - Added `npm run e2e:cdp --workspace=packages/desktop`. - - Harness launches Electron with `QWEN_DESKTOP_CDP_PORT`, a temporary HOME, - temporary runtime/userData directories, a temporary Git workspace, and a - fake ACP client enabled only through E2E environment variables. - - CDP checks stable workbench landmarks, opens the test project through the - preload dialog path, creates a fake local thread, sends a prompt, responds - to a command approval request, saves model settings, runs a scoped terminal - command, and captures initial/final screenshots. - - Failure diagnostics include screenshots, DOM text, renderer console errors, - failed network requests, Electron stdout/stderr, and Git status/diff. -- Verification: - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. - - `npm run e2e:cdp --workspace=packages/desktop` passed. Success artifacts - were written under ignored - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T02-54-48-799Z/`. - - `npm run typecheck` passed. - - `npm run build` passed. - - Bundle/package smoke passed: - `npm run bundle && npm run package:dir --workspace=packages/desktop && npm run smoke:package --workspace=packages/desktop`. - - After tightening the E2E fake ACP gate, package dir, package smoke, and - packaged launch smoke passed again. -- E2E coverage: - - Recorded in - `.qwen/e2e-tests/electron-desktop/cdp-renderer-observability.md`. - -### Slice 15: Hunk-Level Diff Review Controls - -- Status: complete in iteration 10 -- Goal: complete the next review-depth increment with hunk metadata, hunk - accept/revert mutations, visible file/hunk review actions, inline review - comments, and Open in Editor wiring. -- Files: - - `packages/desktop/src/server/services/gitReviewService.ts` - - `packages/desktop/src/server/index.ts` - - `packages/desktop/src/server/index.test.ts` - - `packages/desktop/src/renderer/api/client.ts` - - `packages/desktop/src/renderer/App.tsx` - - `packages/desktop/src/renderer/components/layout/WorkspacePage.tsx` - - `packages/desktop/src/renderer/components/layout/ReviewPanel.tsx` - - `packages/desktop/src/renderer/components/layout/WorkspacePage.test.tsx` - - `packages/desktop/src/renderer/styles.css` - - `packages/desktop/scripts/e2e-cdp-smoke.mjs` - - `.qwen/e2e-tests/electron-desktop/diff-review-commit.md` - - `.qwen/e2e-tests/electron-desktop/cdp-renderer-observability.md` -- Acceptance criteria: - - `GET /api/projects/:id/git/diff` includes per-file hunks with stable ids, - source state, range metadata, and visible hunk lines. - - `POST /api/projects/:id/git/stage` accepts `{ scope: 'hunk', filePath, -hunkId }` and stages only that current hunk. - - `POST /api/projects/:id/git/revert` accepts the same hunk target and - reverts only that current hunk when the patch still applies. - - Review panel exposes Accept/Revert All, file-level Accept/Revert, hunk-level - Accept/Revert, Open file, and inline file comments. - - Electron CDP smoke drives the visible hunk accept and comment path without - console errors or failed network requests. -- Completed: - - Added server-side hunk parsing from current Git diffs and recomputed hunk - patches on mutation so the renderer does not submit patch contents. - - Added hunk-target parsing and token-protected hunk stage/revert routes - scoped to registered projects. - - Added renderer API target types and response guards for hunk metadata. - - Reworked the review panel to show file actions, hunk cards, accepted/pending - state, local inline comments, and Open in Editor via the existing preload - `openPath` whitelist. - - Extended the CDP smoke to accept a hunk and add a review comment after - opening the temporary Git workspace. -- Verification: - - `npm run test --workspace=packages/desktop` passed: 9 files, 54 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. - - `npm run e2e:cdp --workspace=packages/desktop` passed. Success artifacts - were written under ignored - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T03-08-06-087Z/`. - - `npm run typecheck` passed across workspaces. - - `npm run build` passed across workspaces. Existing VS Code companion lint - warnings were reported by its build script, with no errors. -- E2E coverage: - - Updated - `.qwen/e2e-tests/electron-desktop/diff-review-commit.md` and - `.qwen/e2e-tests/electron-desktop/cdp-renderer-observability.md`. - -### Slice 16: Terminal Output to AI and Stdin Write - -- Status: complete in iteration 12 -- Goal: close the P0 terminal gap by allowing running terminal processes to - receive stdin, making output easy to copy, and sending scoped terminal output - back into the active AI thread through the existing session socket. -- Files: - - `packages/desktop/src/server/services/terminalService.ts` - - `packages/desktop/src/server/index.ts` - - `packages/desktop/src/server/index.test.ts` - - `packages/desktop/src/shared/desktopApi.ts` - - `packages/desktop/src/shared/ipcChannels.ts` - - `packages/desktop/src/main/ipc/registerIpc.ts` - - `packages/desktop/src/preload/index.ts` - - `packages/desktop/src/renderer/api/client.ts` - - `packages/desktop/src/renderer/api/websocket.ts` - - `packages/desktop/src/renderer/App.tsx` - - `packages/desktop/src/renderer/components/layout/WorkspacePage.tsx` - - `packages/desktop/src/renderer/components/layout/TerminalDrawer.tsx` - - `packages/desktop/src/renderer/components/layout/WorkspacePage.test.tsx` - - `packages/desktop/src/renderer/styles.css` - - `packages/desktop/scripts/e2e-cdp-smoke.mjs` - - `.qwen/e2e-tests/electron-desktop/terminal-drawer.md` -- Acceptance criteria: - - `POST /api/terminals/:id/write` writes text to stdin for a running - project-scoped terminal and fails closed for completed terminals. - - Terminal drawer exposes copy output, clear, kill, stdin input, and - send-output-to-AI controls without renderer Node APIs. - - Copy output uses a preload-whitelisted Electron clipboard IPC because - `file://` Electron renderers cannot rely on browser clipboard permission. - - Send-output-to-AI requires an active session and posts a bounded terminal - transcript through the existing authenticated WebSocket prompt path. - - Electron CDP smoke verifies command output, stdin write output, copy status, - and send-output-to-AI fake ACP response without console errors or failed - network requests. -- E2E coverage: - - Updated `.qwen/e2e-tests/electron-desktop/terminal-drawer.md` with the new - stdin/write, copy, and send-output-to-AI scenario and diagnostics. -- UI direction: - - Called `frontend-design` before modifying the terminal drawer. The adopted - direction is a dense developer-tool terminal control strip inside the - existing dark workbench: compact action buttons, explicit stdin row, - visible success/error feedback, and no decorative card nesting or marketing - layout. - - User-visible changes are scoped to `TerminalDrawer`, `WorkspacePage`, - `App`, and terminal drawer CSS. The CDP harness verifies the top bar, - sidebar, chat thread, review panel, terminal drawer, copy status, stdin - output, and send-to-AI response in a real Electron renderer. -- Completed: - - Added token-protected `POST /api/terminals/:id/write` to write stdin to a - running server-owned terminal process and reject stale writes. - - Added renderer terminal controls for copy output, stdin input, and sending - a bounded terminal transcript to the active AI thread. - - Added a preload-whitelisted `writeClipboardText` IPC backed by Electron - clipboard for reliable desktop copy output without enabling renderer Node - access. - - Kept send-output-to-AI on the existing authenticated WebSocket - `user_message` prompt path instead of adding a second prompt transport. - - Extended the Electron CDP smoke to verify copy status, stdin output, and - fake ACP response after sending terminal output to AI. -- Verification: - - `npm run test --workspace=packages/desktop` passed: 9 files, 55 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. - - Initial `npm run e2e:cdp --workspace=packages/desktop` failed at copy - output because the renderer fallback clipboard path was unavailable in the - Electron `file://` page. Diagnostics were written to ignored - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T04-42-48-004Z/`. - - After adding the preload clipboard IPC, the CDP smoke passed. Success - artifacts were written under ignored - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T04-45-53-738Z/`. - - `npm run typecheck` passed across workspaces. - - `npm run build` passed across workspaces. Existing VS Code companion lint - warnings were reported by its build script, with no errors. - -### Slice 17: Final Commit E2E and Package Smoke - -- Status: complete in iteration 12 -- Goal: close the final MVP readiness gap by exercising the user-visible Git - commit path from the real Electron renderer and re-running packaged launch - smoke. -- Files: - - `packages/desktop/scripts/e2e-cdp-smoke.mjs` - - `design/qwen-code-electron-desktop-implementation-plan.md` - - `.qwen/e2e-tests/electron-desktop/diff-review-commit.md` - - `.qwen/e2e-tests/electron-desktop/cdp-renderer-observability.md` -- Acceptance criteria: - - CDP smoke opens a temporary Git project through the preload directory - selection path. - - Review panel stages a hunk, stages all remaining changes, enters a commit - message, clicks Commit, and waits for the UI to report a clean review - state. - - The harness verifies the latest Git commit subject and clean working tree - outside the renderer after the UI commit action. - - The same run still covers session creation, permission approval, settings - save, terminal copy/stdin/send-to-AI, screenshots, console errors, failed - network requests, and Electron logs. - - Bundle/package dir/package launch smoke pass. -- E2E coverage: - - Updated `packages/desktop/scripts/e2e-cdp-smoke.mjs` to cover the commit - UI path and stabilize the Open Project click by retrying until the - temporary project is visible. - - Updated `.qwen/e2e-tests/electron-desktop/diff-review-commit.md` and - `.qwen/e2e-tests/electron-desktop/cdp-renderer-observability.md` with the - executable harness path, command, result, and artifact directory. -- Completed: - - Added UI-driven commit coverage to the existing CDP smoke. - - Added post-commit Git assertions for latest subject and clean status. - - Re-ran final packaging and launch smoke against the packaged `.app`. -- Verification: - - `npm run e2e:cdp --workspace=packages/desktop` initially failed when the - harness clicked Commit before the async stage-all update had stabilized. - Diagnostics were written to ignored - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T04-50-16-704Z/`. - - `npm run e2e:cdp --workspace=packages/desktop` then had one transient - Open Project click miss with no console or network errors. Diagnostics were - written to ignored - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T04-51-49-185Z/`. - - After waiting for the staged/untracked counts before Commit and retrying - Open Project until the project appears, the CDP smoke passed. Success - artifacts were written to ignored - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T04-52-52-305Z/`. - - `npm run bundle` passed. - - `npm run package:dir --workspace=packages/desktop` passed. Electron-builder - reported existing non-fatal metadata/dependency/signing/notarization - warnings only. - - `npm run smoke:package --workspace=packages/desktop -- --launch` passed. - -### Slice 18: Ralph-Aligned Workbench Layout - -- Status: complete in iteration 13 -- Goal: fix renderer UI drift by aligning the desktop workspace with - `.qwen/scripts/electron-desktop-ralph-prompt.md` and the - `docs/design/qwen-code-electron-desktop/home.jpg` workbench reference. -- frontend-design: - - Used before changing renderer UI. - - Visual direction: dense local coding workbench, not a dashboard form. - Keep a fixed dark desktop viewport, a narrow project/thread navigation - rail, a compact top status/control bar, a dominant conversation canvas, - an independently scrolling right review column, and a docked terminal - drawer. Use blue, green, and amber status accents instead of a single - one-note palette. -- Files: - - `packages/desktop/src/renderer/styles.css` - - `packages/desktop/src/renderer/components/layout/TopBar.tsx` - - `packages/desktop/src/renderer/components/layout/ProjectSidebar.tsx` - - `packages/desktop/src/renderer/components/layout/ChatThread.tsx` - - `packages/desktop/src/renderer/components/layout/ReviewPanel.tsx` - - `packages/desktop/src/renderer/components/layout/WorkspacePage.tsx` - - `packages/desktop/scripts/e2e-cdp-smoke.mjs` - - `.qwen/e2e-tests/electron-desktop/ralph-layout-alignment.md` -- Acceptance criteria: - - The app document fits a single Electron viewport; page content does not - stretch into a long form. - - Sidebar, topbar, conversation panel, right review panel, message composer, - and terminal drawer are visible and aligned in the first viewport. - - The conversation canvas is wider than the right review panel and remains - the dominant work area. - - Project/thread rows stay compact when only one item exists. - - Composer and terminal drawer are docked within the workspace instead of - creating document-level vertical overflow. - - Chat timeline auto-scrolls to the newest AI/user activity. -- E2E coverage: - - Updated `packages/desktop/scripts/e2e-cdp-smoke.mjs` with layout metrics - assertions for viewport height, sidebar width, topbar height, review panel - width, terminal drawer height, chat/review alignment, terminal docking, - composer containment, and compact project/thread row heights. - - The same executable harness still drives Open Project, hunk accept, - review note, stage all, UI commit, new thread, command approval, settings - save, terminal copy/stdin/send-to-AI, screenshots, console errors, failed - network requests, and Electron logs. -- Verification: - - `cd packages/desktop && SHELL=/bin/bash vitest run` passed: 9 files, 55 - tests. The explicit shell setting avoids a pre-existing stdin race in the - terminal command-runner test under zsh. - - `tsc --noEmit --project packages/desktop/tsconfig.main.json` passed. - - `tsc --noEmit --project packages/desktop/tsconfig.renderer.json` passed. - - `eslint src --ext .ts,.tsx` passed from `packages/desktop`. - - Desktop build passed via `tsc`, preload `esbuild`, and `vite build`. - - `node packages/desktop/scripts/e2e-cdp-smoke.mjs` passed with success - artifacts at ignored - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T05-09-38-476Z/`. - -## Decision Log - -- 2026-04-25: Use a main-process hosted `DesktopServer` for MVP, matching the - architecture recommendation while keeping HTTP/WS boundaries explicit. -- 2026-04-25: Use Electron 41.3.0, whose embedded Node satisfies the repository - runtime requirement. -- 2026-04-25: Use Node built-in HTTP for the current server surface instead of - adding Express/Fastify. -- 2026-04-25: Keep ACP update normalization inside `packages/desktop` until the - desktop protocol stabilizes. -- 2026-04-25: Package the root `dist/` bundle as `resources/qwen-cli` and - launch it with `ELECTRON_RUN_AS_NODE=1` in packaged apps. -- 2026-04-25: Store desktop recent projects in the Qwen global directory as - `desktop-projects.json`, separate from `settings.json`, because it is app UI - state rather than model/auth configuration. -- 2026-04-25: Use `git status --porcelain=v1 --branch` for Slice 9 instead of - introducing a desktop `simple-git` dependency. This keeps the server surface - small and returns conservative status metadata for both clean and dirty repos. -- 2026-04-25: Keep the CDP switch opt-in through `QWEN_DESKTOP_CDP_PORT` and - always pair it with `remote-debugging-address=127.0.0.1`; production remains - closed unless the environment variable is set. -- 2026-04-25: Implement desktop Git review with `git` via `execFile` and - explicit relative path validation. This avoids broad shell execution and - keeps review operations scoped to projects registered through the desktop - project service. -- 2026-04-25: Start the scoped terminal as a project-bound command runner - rather than an interactive PTY. This gives the renderer verifiable output and - kill behavior now while leaving PTY write/resize and send-output-to-AI as the - next terminal refinement. -- 2026-04-25: Keep `App.tsx` as the renderer state/effects coordinator and - extract the visible workspace regions into layout components. This preserves - server-backed behavior while making the workbench structure testable through - stable DOM landmarks. -- 2026-04-25: Add a fake ACP client only behind - `QWEN_DESKTOP_E2E_FAKE_ACP=1` so the Electron E2E harness can cover session, - prompt, and permission UI without credentials or network calls. Production - startup still creates the real `AcpProcessClient`. -- 2026-04-25: Implement hunk-level review by exposing stable hunk ids and - server-derived patch application, not renderer-submitted patches. This keeps - hunk accept/revert scoped to the current registered project state and avoids - trusting client-provided diff text. -- 2026-04-25: Implement terminal send-output-to-AI by formatting a bounded - transcript in the renderer and submitting it through the existing session - WebSocket user-message path. This reuses ACP prompt concurrency, permissions, - and chat history instead of introducing a second terminal-specific prompt - route. -- 2026-04-25: Use a narrow preload IPC for terminal transcript copy because the - real Electron renderer is loaded from `file://` and browser clipboard - permissions are not reliable there. The renderer still has no Node - integration and the IPC accepts only a non-empty string. -- 2026-04-25: Treat UI-driven commit as part of the CDP smoke, not only a - server test. The harness now waits for stage-all status to settle before - committing and verifies Git state after the renderer action. -- 2026-04-25: Treat Ralph/home.jpg alignment as a renderer quality gate, not - just a CSS refresh. The CDP smoke now records layout metrics and fails if the - workbench turns back into a document-length form, if sidebar rows stretch, or - if the main canvas/review/terminal regions drift out of their desktop - proportions. - -## Verification Log - -- 2026-04-25 Slices 1-8: - - Prior iterations passed desktop tests, lint, typecheck, build, root - typecheck/build, bundle, package dir, package smoke, and package launch - smoke. Electron-builder warnings were non-fatal metadata/signing warnings. -- 2026-04-25 Slice 9: - - `npm run test --workspace=packages/desktop` passed: 7 files, 45 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. -- 2026-04-25 Slice 10: - - `npm run test --workspace=packages/desktop` passed: 8 files, 48 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. - - `curl --fail --silent http://127.0.0.1:9339/json/version` passed while the - app was launched with `QWEN_DESKTOP_CDP_PORT=9339`. - - `curl --fail --silent http://127.0.0.1:9339/json/list` passed and returned - a `Qwen Code` page at - `file:///Users/dragon/Documents/qwen-code/packages/desktop/dist/renderer/index.html`. -- 2026-04-25 Slice 12 basic diff review: - - `npm run test --workspace=packages/desktop` passed: 8 files, 50 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. -- 2026-04-25 Slice 13 basic scoped terminal: - - `npm run test --workspace=packages/desktop` passed: 8 files, 52 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. -- 2026-04-25 Iteration 7 final verification: - - `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. -- 2026-04-25 Slice 11 workspace shell: - - `npm run test --workspace=packages/desktop` passed: 9 files, 53 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. - - `npm run build` passed across the configured build order. Existing VS Code - companion lint warnings were reported by its build script, with no errors. - - `npm run typecheck` passed across workspaces. -- 2026-04-25 Slice 14 desktop E2E harness: - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. - - `npm run e2e:cdp --workspace=packages/desktop` passed and reported no - renderer console errors or failed network requests. - - `npm run typecheck` passed across workspaces. - - `npm run build` passed across workspaces. Existing VS Code companion lint - warnings were reported by its build script, with no errors. - - After pre-commit formatting, focused desktop test/typecheck/lint passed - again on the committed tree. - - `npm run typecheck` passed across workspaces. - - `npm run build` passed across workspaces. Existing VS Code companion lint - warnings were reported by its build script, with no errors. - - Bundle/package smoke passed: - `npm run bundle && npm run package:dir --workspace=packages/desktop && npm run smoke:package --workspace=packages/desktop`. - Electron builder reported non-fatal metadata/dependency warnings - consistent with prior package runs. - - After tightening the E2E fake ACP gate, package dir, package smoke, and - packaged launch smoke passed again. -- 2026-04-25 Slice 15 hunk-level diff review: - - `npm run test --workspace=packages/desktop` passed: 9 files, 54 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. - - `npm run e2e:cdp --workspace=packages/desktop` passed and reported no - renderer console errors or failed network requests. -- 2026-04-25 Slice 16 terminal output-to-AI and stdin write: - - `npm run test --workspace=packages/desktop` passed: 9 files, 55 tests. - - `npm run typecheck --workspace=packages/desktop` passed. - - `npm run lint --workspace=packages/desktop` passed. - - `npm run build --workspace=packages/desktop` passed. - - Initial `npm run e2e:cdp --workspace=packages/desktop` failed at the copy - status assertion, with no console errors or failed network requests; the - DOM showed `Clipboard is unavailable.` - - After adding the preload clipboard IPC, the CDP smoke passed and reported - no renderer console errors or failed network requests. - - `npm run typecheck` passed across workspaces. - - `npm run build` passed across workspaces. Existing VS Code companion lint - warnings were reported by its build script, with no errors. -- 2026-04-25 Slice 17 final commit E2E and package smoke: - - `npm run e2e:cdp --workspace=packages/desktop` passed with artifacts at - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T04-52-52-305Z/`. - - `npm run bundle` passed. - - `npm run package:dir --workspace=packages/desktop` passed. - - `npm run smoke:package --workspace=packages/desktop -- --launch` passed. -- 2026-04-25 Slice 18 Ralph-aligned workbench layout: - - `cd packages/desktop && SHELL=/bin/bash vitest run` passed: 9 files, 55 - tests. - - `tsc --noEmit --project packages/desktop/tsconfig.main.json` passed. - - `tsc --noEmit --project packages/desktop/tsconfig.renderer.json` passed. - - `cd packages/desktop && eslint src --ext .ts,.tsx` passed. - - Desktop build passed via package-equivalent `tsc`, preload `esbuild`, and - `vite build`. - - `node packages/desktop/scripts/e2e-cdp-smoke.mjs` passed with screenshots, - layout metrics, console/network diagnostics, and Electron logs at - `.qwen/e2e-tests/electron-desktop/artifacts/2026-04-25T05-09-38-476Z/`. - -## Self Review Notes - -- Slice 9 keeps project registration behind the existing bearer-token and - origin gates. -- Project open validates that the path exists and is a directory before - persisting it. -- Git status failures are non-fatal and render as non-repository metadata, - avoiding a broken workspace for projects without Git. -- Renderer still obtains the token only from preload and does not gain Node - integration. -- Slice 10 keeps remote debugging off by default, rejects non-numeric/out of - range ports, and binds only to loopback when enabled. -- The CDP smoke verified endpoint discovery but did not yet drive DOM, - console, network, or screenshot assertions through MCP; that remains in the - E2E harness slice. -- Slice 12 review operations resolve the project path from the registered - project id server-side; renderer cannot submit arbitrary cwd values. -- File-scoped Git operations reject absolute paths and parent-directory - traversal. The current UI exposes all-scope operations only; file/hunk UI is - still pending. -- Revert All uses `git restore` and `git clean -fd`, so it is intentionally - available only as an explicit user review action and remains scoped to the - active registered project. -- Slice 13 terminal commands resolve cwd from the active registered project id - on the server. The renderer never sends an arbitrary cwd. -- The current terminal is a command runner, not a full PTY. It does not bypass - agent tool permission because agent shell execution still flows through ACP - and core permissions. -- Slice 11 did not broaden preload or IPC. The renderer shell split is a pure - component refactor with stable DOM landmarks for the future Electron/CDP - harness. -- Slice 14 E2E hooks are gated by explicit environment variables: - `QWEN_DESKTOP_E2E`, `QWEN_DESKTOP_E2E_FAKE_ACP`, - `QWEN_DESKTOP_E2E_USER_DATA_DIR`, and - `QWEN_DESKTOP_TEST_SELECT_DIRECTORY`. Normal desktop startup still uses the - native directory picker and real ACP process. -- Slice 15 hunk review recomputes hunk patches from server-side Git state for - each mutation. A stale hunk id fails closed with `git_hunk_not_found` or - `git_error` instead of applying renderer-provided patch contents. -- Review comments are currently local renderer notes for the active review - session. Persisting them into ACP/session artifacts or Git commit metadata is - deferred. -- Slice 16 terminal stdin writes only target server-owned running terminal - records. Completed/killed terminals and closed stdin streams fail closed with - `terminal_not_running`. -- Terminal output-to-AI does not bypass ACP permissions: it sends a normal user - prompt to the active session and therefore inherits the same prompt - concurrency, permission bridge, and fake/real ACP behavior as composer sends. -- The current terminal remains a command runner with stdin pipes. Full PTY - resize/write semantics and terminal tabs/history are deferred beyond the P0 - workflow verified by CDP smoke. -- Slice 17 verifies commit via the renderer action and independent Git checks. - It still uses fake ACP for AI traffic, so live-provider model behavior remains - covered by the existing CLI/core paths rather than desktop E2E credentials. -- Slice 18 is a renderer-only quality correction and does not broaden preload, - IPC, server APIs, ACP permissions, or terminal/Git mutation scope. CDP now - asserts actual layout proportions in addition to visual screenshots. - -## Remaining Work - -- MVP P0 is complete for this plan. Deferred non-P0 work: PTY resize, terminal - tabs/history, persisted review comments, richer artifact previews, worktree - task mode, automation inbox, browser preview, and live-provider desktop E2E - credentials. +### Slice 1: Composer-First Thread Creation Alignment