mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-30 04:30:48 +00:00
feat(desktop): add project git status
This commit is contained in:
parent
b5d089488a
commit
9fadbd5919
9 changed files with 1157 additions and 407 deletions
|
|
@ -3,447 +3,223 @@
|
|||
This plan tracks the incremental MVP implementation for the Electron desktop
|
||||
client described in
|
||||
`docs/design/qwen-code-electron-desktop/qwen-code-electron-desktop-architecture.md`.
|
||||
The architecture document is the source of truth; this file records execution
|
||||
order, verification, decisions, and remaining work.
|
||||
The architecture document remains the source of truth; this file records
|
||||
execution order, verification, decisions, and remaining work.
|
||||
|
||||
## Ground Rules
|
||||
|
||||
- Use Electron only; do not introduce Tauri.
|
||||
- Keep the desktop shell thin: Electron main owns windows, native IPC, and the
|
||||
local server lifecycle.
|
||||
- Reuse Qwen Code ACP, core services, and shared web UI as later slices reach
|
||||
those layers.
|
||||
- Renderer must run with `nodeIntegration: false`, context isolation enabled,
|
||||
and a preload whitelist.
|
||||
- Keep Electron main thin: windows, native IPC, local server lifecycle, and ACP
|
||||
process lifecycle.
|
||||
- Reuse Qwen Code ACP, core configuration/auth/session/permission behavior, and
|
||||
shared web UI surfaces where practical.
|
||||
- Renderer must use `nodeIntegration: false`, context isolation, and a preload
|
||||
whitelist.
|
||||
- The local server must bind only `127.0.0.1`, use a random token, and reject
|
||||
unauthorized requests.
|
||||
- Every completed slice must leave passing targeted checks and a conventional
|
||||
- Every completed slice must leave targeted verification and a conventional
|
||||
commit.
|
||||
|
||||
## Current Status
|
||||
|
||||
Slices 1-8 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, and package smoke verification.
|
||||
|
||||
Important correction from iteration 7: the previous plan text called the MVP
|
||||
complete after packaging smoke, but the architecture P0 also requires project
|
||||
registry, recent projects, Git status, diff review, terminal, commit flow,
|
||||
desktop E2E, and Chrome DevTools renderer observability. Those items remain in
|
||||
scope before a DONE marker can be created.
|
||||
|
||||
## Task Breakdown
|
||||
|
||||
### Slice 1: Desktop Workspace Skeleton and Health Service
|
||||
|
||||
- Status: complete
|
||||
- Goal: add the first runnable desktop package with Electron main/preload,
|
||||
React renderer, and a local authenticated `/health` endpoint.
|
||||
- Files:
|
||||
- `packages/desktop/package.json`
|
||||
- `packages/desktop/tsconfig*.json`
|
||||
- `packages/desktop/vite.config.ts`
|
||||
- `packages/desktop/src/main/**`
|
||||
- `packages/desktop/src/preload/**`
|
||||
- `packages/desktop/src/server/**`
|
||||
- `packages/desktop/src/renderer/**`
|
||||
- `scripts/build.js`
|
||||
- `package-lock.json`
|
||||
- Acceptance criteria:
|
||||
- `packages/desktop` is recognized as an npm workspace.
|
||||
- Main starts `DesktopServer` before creating the window.
|
||||
- Preload exposes only typed `qwenDesktop` methods.
|
||||
- Renderer fetches server info through preload and calls `/health` with a
|
||||
bearer token.
|
||||
- `/health` returns success only for valid token and allowed origin.
|
||||
- Desktop build is included after reusable packages in the root build order.
|
||||
- Verification:
|
||||
- `npm install --workspace=packages/desktop`
|
||||
- `npm run test --workspace=packages/desktop`
|
||||
- `npm run typecheck --workspace=packages/desktop`
|
||||
- `npm run build --workspace=packages/desktop`
|
||||
- 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: add `/api/runtime` and typed error responses that expose CLI path,
|
||||
platform, desktop version, and auth/account placeholders without spawning ACP.
|
||||
- Files:
|
||||
- `packages/desktop/src/server/http/router.ts`
|
||||
- `packages/desktop/src/server/services/runtimeService.ts`
|
||||
- `packages/desktop/src/renderer/api/client.ts`
|
||||
- `packages/desktop/src/renderer/App.tsx`
|
||||
- Acceptance criteria:
|
||||
- Runtime route is token protected.
|
||||
- Renderer shows runtime summary without exposing secrets.
|
||||
- Tests cover success, unauthorized, and unknown route errors.
|
||||
- Verification:
|
||||
- `npm run test --workspace=packages/desktop`
|
||||
- `npm run typecheck --workspace=packages/desktop`
|
||||
- `npm run build --workspace=packages/desktop`
|
||||
- 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: implement a desktop-local ACP child-process client around
|
||||
- Goal: desktop-local ACP child-process client for
|
||||
`qwen --acp --channel=Desktop`.
|
||||
- Files:
|
||||
- `packages/desktop/src/server/acp/AcpProcessClient.ts`
|
||||
- `packages/desktop/src/server/acp/AcpEventRouter.ts`
|
||||
- `packages/desktop/src/server/services/sessionService.ts`
|
||||
- Acceptance criteria:
|
||||
- Development mode can spawn the repository CLI ACP entrypoint.
|
||||
- Production path is isolated behind a resolver for packaged `dist/cli.js`.
|
||||
- Tests mock ACP transport and cover initialize, list, new, load, and close.
|
||||
- Verification:
|
||||
- `npm run test --workspace=packages/desktop`
|
||||
- `npm run typecheck --workspace=packages/desktop`
|
||||
- targeted ACP smoke command when credentials are not required
|
||||
- Verification: desktop tests, lint, typecheck, build, root typecheck/build.
|
||||
|
||||
### Slice 4: Session REST API
|
||||
|
||||
- Status: complete
|
||||
- Goal: add session create/list/load/delete/rename endpoints backed by ACP.
|
||||
- Files:
|
||||
- `packages/desktop/src/server/http/router.ts`
|
||||
- `packages/desktop/src/server/services/sessionService.ts`
|
||||
- `packages/desktop/src/renderer/stores/sessionStore.ts`
|
||||
- Acceptance criteria:
|
||||
- Session routes enforce token and origin rules.
|
||||
- Renderer can create a session for a selected cwd and list existing sessions.
|
||||
- Failed ACP operations return typed retryable/non-retryable errors.
|
||||
- Verification:
|
||||
- `npm run test --workspace=packages/desktop`
|
||||
- `npm run typecheck --workspace=packages/desktop`
|
||||
- manual DesktopServer smoke with fake ACP client
|
||||
- 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: add per-session WS connections and send user prompts through ACP.
|
||||
- Files:
|
||||
- `packages/desktop/src/server/ws/SessionSocketHub.ts`
|
||||
- `packages/desktop/src/server/acp/AcpEventRouter.ts`
|
||||
- `packages/desktop/src/renderer/api/websocket.ts`
|
||||
- `packages/desktop/src/renderer/stores/chatStore.ts`
|
||||
- Acceptance criteria:
|
||||
- WS handshake validates session id and token.
|
||||
- One active prompt per session is enforced.
|
||||
- Renderer receives normalized assistant/tool/usage events.
|
||||
- Progress:
|
||||
- 2026-04-25: authenticated `/ws/:sessionId` handshake, `ping`/`pong`,
|
||||
`user_message` to ACP `prompt`, `stop_generation` to ACP `cancel`, and
|
||||
one-active-prompt guard are implemented on the server.
|
||||
- 2026-04-25: added `AcpEventRouter` normalization for ACP message, tool,
|
||||
plan, mode, commands, and usage updates; routed session updates into the
|
||||
per-session socket hub; added a renderer WebSocket client, chat reducer,
|
||||
and basic workbench wiring for session selection, streaming messages,
|
||||
tool updates, plan updates, usage, stop, and send.
|
||||
- Verification:
|
||||
- `npm run test --workspace=packages/desktop`
|
||||
- fake ACP integration test for prompt and stream completion
|
||||
- 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.
|
||||
- Files:
|
||||
- `packages/desktop/src/server/acp/permissionBridge.ts`
|
||||
- `packages/desktop/src/server/ws/SessionSocketHub.ts`
|
||||
- `packages/desktop/src/renderer/stores/chatStore.ts`
|
||||
- Acceptance criteria:
|
||||
- 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
|
||||
- Verification: desktop tests, lint, typecheck, build, root typecheck/build.
|
||||
|
||||
### Slice 7: Settings, Auth, Model, and Mode UI
|
||||
|
||||
- Status: complete
|
||||
- Goal: expose settings/auth/model/mode controls while reusing Qwen Code
|
||||
configuration semantics.
|
||||
- Files:
|
||||
- `packages/desktop/src/server/services/settingsService.ts`
|
||||
- `packages/desktop/src/server/services/runtimeService.ts`
|
||||
- `packages/desktop/src/renderer/stores/settingsStore.ts`
|
||||
- `packages/desktop/src/renderer/stores/modelStore.ts`
|
||||
- Acceptance criteria:
|
||||
- Settings writes target the existing Qwen settings locations.
|
||||
- Auth actions go through ACP or shared settings writer logic.
|
||||
- Approval mode values remain `plan/default/auto-edit/yolo`.
|
||||
- Progress:
|
||||
- 2026-04-25: added a desktop settings service for reading/writing
|
||||
`~/.qwen/settings.json` using Qwen core `Storage`, `AuthType`, and Coding
|
||||
Plan constants; API-key and Coding Plan writes preserve the existing
|
||||
Qwen settings shape and never return API key values in REST payloads.
|
||||
- 2026-04-25: added authenticated REST routes for user settings,
|
||||
ACP-backed authentication, session model state, and session mode state;
|
||||
cached model/mode state is captured from ACP `newSession`/`loadSession`
|
||||
responses and updates call `unstable_setSessionModel` / `setSessionMode`.
|
||||
- 2026-04-25: added renderer settings/model stores and basic controls for
|
||||
provider setup, OAuth authentication, active model, and approval mode.
|
||||
WebSocket protocol now also accepts `set_model` and
|
||||
`set_permission_mode` messages.
|
||||
- Verification:
|
||||
- `npm run test --workspace=packages/desktop`
|
||||
- temp HOME/QWEN_RUNTIME_DIR settings tests
|
||||
- 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 the bundled CLI ACP child.
|
||||
- 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/electron-builder.*`
|
||||
- `scripts/build.js`
|
||||
- `scripts/copy_bundle_assets.js`
|
||||
- `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:
|
||||
- Packaged app starts renderer and DesktopServer.
|
||||
- Production ACP launch uses `ELECTRON_RUN_AS_NODE=1`.
|
||||
- Required CLI bundle and native/vendor resources are present.
|
||||
- Progress:
|
||||
- 2026-04-25: added a tested desktop ACP launch resolver. Development uses
|
||||
the built workspace CLI entrypoint, explicit `QWEN_DESKTOP_CLI_PATH`
|
||||
remains supported, and packaged apps resolve
|
||||
`process.resourcesPath/qwen-cli/cli.js` with
|
||||
`ELECTRON_RUN_AS_NODE=1`.
|
||||
- 2026-04-25: Electron main now creates a real `AcpProcessClient`, passes it
|
||||
into `DesktopServer`, exposes the resolved CLI path through runtime info,
|
||||
and disconnects ACP on app quit.
|
||||
- 2026-04-25: added electron-builder configuration and package scripts.
|
||||
Packaging copies the root CLI bundle resources from `dist/` to
|
||||
`resources/qwen-cli` while excluding the desktop package output to avoid
|
||||
recursive resource copies.
|
||||
- 2026-04-25: added a packaged-app smoke script that verifies `app.asar`,
|
||||
bundled `qwen-cli/cli.js`, and optionally launches the packaged app long
|
||||
enough to confirm startup before terminating it.
|
||||
- `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 build`
|
||||
- `npm run typecheck`
|
||||
- desktop packaging smoke command
|
||||
- `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: Workspace Review Shell
|
||||
|
||||
- Status: pending
|
||||
- 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.
|
||||
- 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.
|
||||
- E2E coverage:
|
||||
- Launch renderer with fake server/preload data and assert layout landmarks.
|
||||
|
||||
### Slice 11: Diff Review and Commit
|
||||
|
||||
- Status: pending
|
||||
- Goal: add Git diff/status review APIs and UI actions for accept/revert and
|
||||
commit.
|
||||
- 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.
|
||||
- E2E coverage:
|
||||
- Temporary Git workspace with a fake file change, accept/stage, commit, and
|
||||
error diagnostics.
|
||||
|
||||
### Slice 12: Scoped Terminal
|
||||
|
||||
- Status: pending
|
||||
- Goal: add a current-project/current-thread terminal drawer with spawn, output,
|
||||
clear, kill, and send-output-to-AI plumbing.
|
||||
- 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.
|
||||
- E2E coverage:
|
||||
- Run a harmless command in a temporary workspace and assert output appears.
|
||||
|
||||
### Slice 13: Desktop E2E and CDP Observability
|
||||
|
||||
- Status: pending
|
||||
- Goal: add repeatable Electron E2E harness with fake ACP, temporary HOME and
|
||||
workspace, screenshot/console/network diagnostics, and CDP renderer access.
|
||||
- Acceptance criteria:
|
||||
- `QWEN_DESKTOP_CDP_PORT` enables renderer inspection 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/`.
|
||||
|
||||
## Decision Log
|
||||
|
||||
- 2026-04-25: Use a main-process hosted `DesktopServer` for MVP, matching the
|
||||
architecture recommendation and keeping the HTTP/WS boundary ready for a
|
||||
future `utilityProcess` move.
|
||||
- 2026-04-25: Use the latest stable Electron line available during this slice.
|
||||
Electron releases list Electron 41.3.0 with Node.js 24.15.0, satisfying the
|
||||
repository runtime requirement of Node >=20.
|
||||
- 2026-04-25: Implement the first server routes with Node built-ins instead of
|
||||
adding Express/Fastify. The current surface is small and this avoids
|
||||
committing to an HTTP framework before the ACP routing shape is known.
|
||||
- 2026-04-25: Allow CORS preflight without bearer auth, but only for allowed
|
||||
app origins. Actual REST requests remain bearer-token protected.
|
||||
- 2026-04-25: Keep ACP update normalization inside `packages/desktop` for now
|
||||
instead of importing the VS Code session update handler. The desktop protocol
|
||||
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.
|
||||
- 2026-04-25: Reimplemented the VS Code settings-writer semantics inside the
|
||||
desktop server instead of importing from `packages/vscode-ide-companion`.
|
||||
The desktop package now depends directly on `@qwen-code/qwen-code-core` for
|
||||
`Storage`, auth constants, and Coding Plan templates while keeping extension
|
||||
code out of the desktop runtime boundary.
|
||||
- 2026-04-25: Package the root `dist/` bundle as an Electron `extraResources`
|
||||
directory named `qwen-cli` rather than relying on `app.asar` paths for the
|
||||
CLI sidecar. This keeps `cli.js`, sandbox profiles, vendor binaries, and
|
||||
bundled skills together and lets the main process launch the CLI via
|
||||
`ELECTRON_RUN_AS_NODE=1`.
|
||||
- 2026-04-25: Keep the electron-builder smoke script non-launching by default
|
||||
so it works in headless environments; use `--launch` for local packaged
|
||||
startup verification.
|
||||
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.
|
||||
|
||||
## Verification Log
|
||||
|
||||
- 2026-04-25 Slice 1:
|
||||
- `npm install --ignore-scripts --workspace=@qwen-code/desktop` passed.
|
||||
- `npx prettier --check design/qwen-code-electron-desktop-implementation-plan.md scripts/build.js packages/desktop` passed.
|
||||
- `npm run lint --workspace=packages/desktop` passed.
|
||||
- `npm run test --workspace=packages/desktop` passed: 1 file, 4 tests.
|
||||
- 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 build --workspace=packages/desktop` passed.
|
||||
- `npm exec --workspace=packages/desktop -- electron --version` passed:
|
||||
`v41.3.0`.
|
||||
- `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 2:
|
||||
- `npx prettier --check design/qwen-code-electron-desktop-implementation-plan.md scripts/build.js packages/desktop` passed.
|
||||
- `npm run test --workspace=packages/desktop` passed: 1 file, 6 tests.
|
||||
- `npm run lint --workspace=packages/desktop` passed.
|
||||
- `npm run typecheck --workspace=packages/desktop` passed.
|
||||
- `npm run build --workspace=packages/desktop` passed.
|
||||
- `npm exec --workspace=packages/desktop -- electron --version` passed:
|
||||
`v41.3.0`.
|
||||
- `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 3:
|
||||
- `npm install --ignore-scripts --workspace=@qwen-code/desktop` passed.
|
||||
- `npx prettier --check design/qwen-code-electron-desktop-implementation-plan.md scripts/build.js packages/desktop` passed.
|
||||
- `npm run test --workspace=packages/desktop` passed: 2 files, 12 tests.
|
||||
- `npm run lint --workspace=packages/desktop` passed.
|
||||
- `npm run typecheck --workspace=packages/desktop` passed.
|
||||
- `npm run build --workspace=packages/desktop` passed.
|
||||
- `npm exec --workspace=packages/desktop -- electron --version` passed:
|
||||
`v41.3.0`.
|
||||
- `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 4:
|
||||
- `npx prettier --check design/qwen-code-electron-desktop-implementation-plan.md scripts/build.js packages/desktop` passed.
|
||||
- `npm run test --workspace=packages/desktop` passed: 2 files, 17 tests.
|
||||
- `npm run lint --workspace=packages/desktop` passed.
|
||||
- `npm run typecheck --workspace=packages/desktop` passed.
|
||||
- `npm run build --workspace=packages/desktop` passed.
|
||||
- `npm exec --workspace=packages/desktop -- electron --version` passed:
|
||||
`v41.3.0`.
|
||||
- `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 5a:
|
||||
- `npm install --ignore-scripts --workspace=@qwen-code/desktop` passed.
|
||||
- `npx prettier --check design/qwen-code-electron-desktop-implementation-plan.md scripts/build.js packages/desktop` passed.
|
||||
- `npm run test --workspace=packages/desktop` passed: 2 files, 21 tests.
|
||||
- `npm run lint --workspace=packages/desktop` passed.
|
||||
- `npm run typecheck --workspace=packages/desktop` passed.
|
||||
- `npm run build --workspace=packages/desktop` passed.
|
||||
- `npm exec --workspace=packages/desktop -- electron --version` passed:
|
||||
`v41.3.0`.
|
||||
- `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 5b:
|
||||
- `npm run test --workspace=packages/desktop` passed: 3 files, 26 tests.
|
||||
- `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.
|
||||
- 2026-04-25 Slice 7:
|
||||
- `npm install --ignore-scripts --workspace=@qwen-code/desktop` passed.
|
||||
- `npx prettier --check design/qwen-code-electron-desktop-implementation-plan.md packages/desktop` passed.
|
||||
- `npm run test --workspace=packages/desktop` passed: 6 files, 40 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.
|
||||
- 2026-04-25 Slice 8:
|
||||
- `npm install --save-dev --ignore-scripts --workspace=@qwen-code/desktop electron-builder` passed.
|
||||
- `npm run test --workspace=packages/desktop` passed: 7 files, 43 tests.
|
||||
- `npm run lint --workspace=packages/desktop` passed.
|
||||
- `npm run typecheck --workspace=packages/desktop` passed.
|
||||
- `npm run build --workspace=packages/desktop` passed.
|
||||
- `npm run bundle` passed and copied sandbox profiles, vendor resources,
|
||||
bundled skills, and docs into root `dist/`.
|
||||
- `npm run package:dir --workspace=packages/desktop` passed after fixing the
|
||||
initial recursive `dist/desktop` resource copy by excluding `desktop/**`.
|
||||
electron-builder reported non-fatal warnings for missing package author,
|
||||
default Electron icon, ad-hoc macOS signing, skipped notarization, and
|
||||
existing npm dependency tree issues.
|
||||
- `npm run smoke:package --workspace=packages/desktop` passed.
|
||||
- `npm run smoke:package --workspace=packages/desktop -- --launch` passed;
|
||||
the packaged macOS app stayed alive through startup and was terminated by
|
||||
the smoke script.
|
||||
- `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
|
||||
|
||||
- 2026-04-25 Slice 1:
|
||||
- Security boundary checked: renderer uses `nodeIntegration: false`,
|
||||
context isolation, a bundled preload whitelist, and no arbitrary IPC.
|
||||
- Local server checked: binds `127.0.0.1`, generates a random token by
|
||||
default, requires bearer auth for real routes, and rejects non-local
|
||||
origins.
|
||||
- CORS preflight intentionally remains unauthenticated but origin-gated so
|
||||
packaged `file://` and dev `127.0.0.1` renderers can send authorization
|
||||
headers.
|
||||
- Fixed self-review issues before completion: guarded app startup behind the
|
||||
Electron single-instance lock, tightened bearer parsing, and removed unused
|
||||
direct WebSocket dependencies until the WS slice.
|
||||
- 2026-04-25 Slice 2:
|
||||
- Runtime route remains behind the same token and origin checks as `/health`.
|
||||
- Runtime payload does not expose secrets; auth/account are explicit
|
||||
placeholders until ACP is connected.
|
||||
- Renderer displays runtime summary from REST only and still obtains the
|
||||
server token only through preload.
|
||||
- 2026-04-25 Slice 3:
|
||||
- `AcpProcessClient` follows the existing Qwen ACP boundary:
|
||||
`ClientSideConnection`, `ndJsonStream`, and `qwen --acp`.
|
||||
- The wrapper defaults permission requests to cancellation until the
|
||||
permission bridge slice supplies a UI-backed resolver.
|
||||
- Startup failures race initialize against child exit; later process exits
|
||||
clear connection state without leaving a rejected startup promise.
|
||||
- 2026-04-25 Slice 4:
|
||||
- Session REST routes share the same origin and bearer-token gate as health
|
||||
and runtime routes.
|
||||
- The route layer is ACP-backed through an injected client so tests cover the
|
||||
Qwen ACP method contracts without requiring credentials or a live model.
|
||||
- Electron main intentionally does not auto-start real ACP yet; CLI path
|
||||
resolution and packaged `ELECTRON_RUN_AS_NODE=1` behavior remain for the
|
||||
packaging/runtime integration slices.
|
||||
- 2026-04-25 Slice 5a:
|
||||
- WebSocket upgrade uses the same local-origin policy and random token as the
|
||||
REST API.
|
||||
- The hub defaults to an `acp_unavailable` error when no ACP client is
|
||||
injected, rather than silently dropping user messages.
|
||||
- Session update broadcasting is intentionally a follow-up; this keeps the
|
||||
prompt/cancel transport independently testable before event normalization.
|
||||
- 2026-04-25 Slice 5b:
|
||||
- ACP session updates now broadcast only to sockets for the matching session;
|
||||
tests cover a second session socket receiving only its own `pong`.
|
||||
- Renderer chat state consumes the shared desktop WebSocket protocol without
|
||||
Node access and keeps the server token in memory from preload-provided
|
||||
server info.
|
||||
- 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.
|
||||
- 2026-04-25 Slice 7:
|
||||
- Settings REST responses intentionally expose only `hasApiKey` booleans and
|
||||
provider metadata; tests assert API key values are written to the existing
|
||||
Qwen settings shape but not returned to the renderer.
|
||||
- Model and mode changes remain ACP-backed. REST updates also refresh the
|
||||
server cache used by the UI, while WebSocket `set_model` and
|
||||
`set_permission_mode` are available for future lower-latency controls.
|
||||
- Runtime auth status now reports `authenticated` only when ACP account info
|
||||
contains an auth/model/baseUrl signal, avoiding a misleading state for
|
||||
empty account payloads.
|
||||
- 2026-04-25 Slice 8:
|
||||
- Packaged CLI launch is lazy: desktop startup creates the ACP client but the
|
||||
child process still starts on the first session/auth operation. This keeps
|
||||
app launch independent of user credentials while preserving the ACP
|
||||
boundary for real work.
|
||||
- The renderer security posture remains unchanged after packaging:
|
||||
`nodeIntegration: false`, context isolation enabled, preload whitelist only,
|
||||
and CSP restricted to self plus local `127.0.0.1` HTTP/WS.
|
||||
- The package smoke validates resource presence and startup, but does not run
|
||||
an authenticated model turn. A live credentialed packaged chat test remains
|
||||
outside MVP verification.
|
||||
- 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.
|
||||
|
||||
## Remaining Work
|
||||
|
||||
- Commit Slice 8.
|
||||
- MVP scope from the architecture plan is complete and verified. Future work:
|
||||
signed/notarized distributables, app icon/metadata polish, and a credentialed
|
||||
packaged chat smoke test.
|
||||
- Commit Slice 9.
|
||||
- Implement real workspace review shell, diff review, commit flow, scoped
|
||||
terminal, Electron E2E, CDP observability verification, and final package
|
||||
smoke before creating the DONE marker.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue