mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-14 19:24:54 +00:00
7 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
090b213ad8
|
feat(web-shell): add native workspace folder picker (#7849)
* feat(web-shell): add native workspace folder picker * fix(serve): harden native directory picker and add coverage (#7849) Add a 5-minute timeout to each native picker subprocess and to the webui action so a dismissed dialog cannot leave an orphaned GUI process, and distinguish a headless Linux "cannot open display" failure from a deliberate zenity cancellation. Cover pickNativeDirectory's platform branches, the route's 501/500 error paths, and the dialog's picker failure path with focused tests. * fix(serve): log directory picker failures to daemon stderr (#7849) * fix(serve): abort directory picker on client disconnect and stagger timeouts (#7849) * test(webui): add unit tests for pickWorkspaceDirectory action (#7849) * fix(serve): set UTF-8 console encoding for PowerShell picker and treat timeout kills as cancels (#7849) * fix(serve): abort directory picker on response close, not request close (#7849) --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com> Co-authored-by: Qwen Code CI <qwen-code-ci@users.noreply.github.com> |
||
|
|
6f5d6dfd65
|
feat(web-shell): add workspace selector button with add/switch dropdown in composer toolbar (#7390)
* feat(web-shell): add managed workspace selector Let Web Shell create and select daemon-managed workspaces without changing ownership of existing sessions. - Add capability-gated existing and scratch workspace registration - Validate scratch roots, trust provenance, capacity, and shutdown races - Serialize workspace mutations, session switching, and refresh results - Add SDK/WebUI wiring and focused cross-package regression coverage # Conflicts: # packages/web-shell/client/App.tsx # packages/web-shell/client/components/sidebar/WebShellSidebar.tsx # Conflicts: # packages/cli/src/serve/capabilities.ts # packages/cli/src/serve/routes/workspace-management.ts # packages/cli/src/serve/server.test.ts # packages/sdk-typescript/src/daemon/DaemonClient.ts # packages/web-shell/client/App.tsx # packages/web-shell/client/components/dialogs/AddWorkspaceDialog.tsx # packages/web-shell/client/components/sidebar/WebShellSidebar.tsx * fix(web-shell): revalidate workspace before session creation Prevent a stale workspace selection from bypassing the latest trusted capability snapshot during lazy session creation. - Validate the selected workspace before passing it to the daemon - Fall back to the primary workspace when trust has been revoked - Add a regression test for the pre-effect race window - Remove stale branch state and clarify add-workspace ownership * fix(web-shell): improve workspace removal feedback Keep workspace removal controls legible and make blocked force removals visibly inactive. - Size the action menu independently from its narrow icon trigger - Add a disabled affordance and suppress destructive hover styling - Cover the removal menu width override with a regression test * fix(web-shell): centralize existing workspace registration Route sidebar and composer entry points through the App-owned dialog so capability gating and workspace reconciliation remain consistent. - Forward display names only when the daemon advertises support - Hide and suppress persistence when registration is runtime-only - Mark directory registrations with existing-workspace provenance - Cover both entry points and capability combinations with tests * fix(web-shell): address review feedback on workspace dialogs and capability docs (#7390) - Document dynamic_workspace_registration and scratch_workspace_registration in the conditional serve-features table so the capabilities-docs-contract test passes. - Gate DialogShell backdrop-click and Escape dismissal on the dismissible prop so non-dismissible dialogs ignore both gestures. - Surface an inline error when an added folder registers but the capability refresh fails, mirroring the scratch recovery path. - Add coverage for the active-session workspace switch and the add-folder refresh-failure paths. * fix(web-shell): address review feedback on workspace dialogs and capability docs (#7390) --------- Co-authored-by: heyang.why <heyang.why@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> |
||
|
|
9e822d6004
|
feat: support workspace display names (#7179)
* feat(sdk): support workspace display names * docs: add Web Shell screenshot * feat(web-shell): add workspace display names * fix(serve): harden workspace display name updates * refactor(serve): simplify workspace display names * fix(serve): validate trimmed workspace display names * feat(serve): add workspace update API * docs(serve): clarify workspace display name null handling * docs(sdk): list addWorkspace in daemon client methods |
||
|
|
620effef09
|
feat(web-shell): add directory autocomplete to the Add Workspace dialog (#7125)
Typing the full absolute path of a project by hand into the Add Workspace dialog was slow and error-prone, and the only feedback was a generic error after submitting. The existing GET /list route could not back an autocomplete here because it resolves paths through a registered workspace's filesystem boundary, and the path being picked is not a workspace yet. Add a deliberately narrow read-only daemon route, GET /workspace-path-suggestions?prefix=<absolute>, that returns only the names of subdirectories matching the prefix (case-insensitive on the final segment, dot-directories only once the filter starts with a dot, symlinked directories included, capped at 50 entries). It shares the trust surface of POST /workspaces, which already lets an authenticated client stat and register any absolute directory. The dialog's path field becomes a combobox fed by that route through DaemonClient.workspacePathSuggestions() and a new suggestWorkspacePaths workspace action: suggestions render in a listbox under the input (debounced 150ms, stale responses dropped), ArrowUp/Down move the highlight, Enter/Tab or click accepts a directory and descends into it, and Escape closes just the list — intercepted on window capture so Radix does not close the whole dialog. Fixes #7102 Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
79ae054bb8
|
feat(web-shell): modernize multi-workspace sidebar (#6804)
* feat(web-shell): modernize multi-workspace sidebar * fix(web-shell): address sidebar review feedback * fix(web-shell): address remaining review feedback --------- Co-authored-by: ytahdn <ytahdn@gmail.com> |
||
|
|
732d85df39
|
fix(web-shell): correct Add Workspace dialog theming and multi-workspace session rows (#6705)
* fix(web-shell): theme and lay out the Add Workspace dialog correctly The dialog's stylesheet referenced CSS variables that are defined nowhere (--text-secondary, --input-bg, --border-color, --accent-color, --hover-bg), so they fell back to hardcoded dark values — in light mode the input rendered dark-on-light with a purple focus ring, inconsistent with every other dialog. It also reused a two-column form-row grid meant for label/value pairs, which cramped the path input into a narrow column. Rebuild the dialog on the shared dialog primitives (themed .dialog-form input, dialog-inline-button, dialog-primary-button) so it tracks the active theme in both light and dark and gives the path a full-width input. Add a proactive absolute-path hint, an accessible inline error (role="alert", aria-describedby, aria-invalid) that clears as you type, and a localized "Adding…" state. Keep the hint and error as siblings of the input rather than nested in the label, so their text stays out of the input's accessible name. * fix(web-shell): render full session rows for every workspace in the sidebar Registering a second workspace switched the sidebar to the multi-workspace view, which rendered each workspace's sessions with a bespoke minimal row: a smaller font (12px vs 14px) and no per-session actions. The rich single-workspace row (hover actions, current-session highlight, inline rename, running/unread state) was hidden entirely, so even the primary workspace's list degraded. Render sessions through the sidebar's shared renderSessionRow so every workspace matches the single-workspace list. Gate the mutation actions to the primary (daemon-bound) workspace: the daemon can't resolve another workspace's session for pin/archive/export/delete (they 404 or silently no-op), so non-primary rows are read-only — they keep click-to-load and the font/highlight but drop the action buttons. Session mutations now also bump the per-workspace poll token so those lists refresh promptly. * refactor(web-shell): move Add Workspace footer padding into a CSS class The footer sits inside .dialog-form (which already pads its sides) and reuses the shared dialog-footer-actions primitive, doubling the horizontal padding; the override lived as an inline style, hiding the deviation from the stylesheet. Move it to a local .footer class applied alongside the shared class. A doubled selector keeps it winning over the primitive regardless of stylesheet order. * test(web-shell): cover workspace read-only gating and Add Workspace dialog Add tests for the behaviors introduced by the sidebar and dialog fixes: - non-primary workspace rows render the session but expose no action buttons (the daemon, bound to the primary workspace, can't service their mutations), while the primary workspace keeps its full actions; - a session mutation re-polls the per-workspace list instead of waiting for the 10s interval; - the Add Workspace dialog's absolute-path validation, accessible error wiring (role="alert", aria-describedby/aria-invalid), error-clear-on-edit, trimmed submit, and onAdd-failure handling. * refactor(web-shell): centralize the workspace reload-token bump in a helper Per review: the setWorkspaceSessionsReloadToken bump was repeated verbatim across the session-mutation handlers. Extract a stable bumpWorkspaceReload() helper and route every site through it, including assignSessionGroup and assignSessionColor — the two organization mutations that were missing the bump — so assigning a group or color now also re-polls the per-workspace session lists instead of waiting for the 10s interval. * test(web-shell): cover Windows paths and non-Error rejections in Add Workspace dialog Per review: add the two untested handleSubmit branches — a Windows-style absolute path accepted by the drive-letter regex, and a non-Error onAdd rejection falling back to the generic error message. * fix(web-shell): gate inline rename on readOnly and refresh on group-create assign Per review: the readOnly option hid the hover action buttons but not the inline rename — onDoubleClick and the isEditing branch still fired on read-only rows, so a session shown in multiple workspaces could render an editable rename input on its non-primary (read-only) copy. Gate both on !readOnly. Also add the missing bumpWorkspaceReload() to saveGroupEditor's create-with-target-session path so that organization mutation refreshes the per-workspace lists like the others. * test(web-shell): cover readOnly rename gating and dialog submitting state Per review: assert the read-only (non-primary) row does not open the inline rename form when the shared session is renamed from the primary row, and that the Add Workspace dialog shows the localized "Adding…" label with disabled controls while onAdd is pending. |
||
|
|
2523a36b52
|
feat(web-shell): workspace management sidebar with dynamic registration (daemon multi-workspace phase 4) (#6625)
* feat(web-shell): add workspace picker for new sessions (issue #6378 phase 4) Multi-workspace daemons now show a new-session workspace picker in the sidebar (default primary, untrusted disabled); the chosen workspace cwd is sent on POST /session so the session spawns in that workspace. daemon-react-sdk createSession gains an optional per-call workspaceCwd override covering both the detached and active-session paths; omitting it preserves the previous primary behavior. * feat(web-shell): workspace management with dynamic registration Replace the new-session workspace picker with a full workspace management sidebar. Registered workspaces render as a parallel, collapsible list (folder icon per workspace), each with its own sessions nested underneath, and a "+" entry registers an existing directory as a new workspace at runtime with no daemon restart. Backend: WorkspaceRegistry becomes mutable (add()/onChange()); a new POST /workspaces route validates the directory (exists, not a duplicate, not nested) and registers it; run-qwen-serve exposes a runtime factory that builds a complete workspace runtime (bridge, fs factory, channel factory, workspace service) on demand. The SDK DaemonClient and daemon-react-sdk gain addWorkspace(). * fix(web-shell): show newly registered workspace without a reload Registering a workspace via the sidebar "+" left the list unchanged until a full page reload. handleAddWorkspace called workspace.getCapabilities(), which returns a cached promise and only feeds setCapabilities from the mount effect, so the refresh was a no-op. Add DaemonWorkspaceProvider.refreshCapabilities(): it bypasses the promise cache, issues a fresh /capabilities fetch, and pushes the result into state so consumers re-render. handleAddWorkspace now awaits it (best-effort, so a refresh failure never masks a successful registration). * fix(web-shell): address review feedback for workspace management - registry: list() returns a frozen snapshot so callers can't mutate the internal runtimes array (restores the push()-throws invariant) - POST /workspaces: reject relative paths on the raw input, canonicalize via realpath so symlink aliases can't bypass the duplicate/nesting checks, and serialize concurrent registrations to close a TOCTOU race that leaked bridge/channel infrastructure - sidebar: restore a compact single-workspace project header (name, search toggle, collapse) so single-workspace users keep those affordances and searchOpen/projectExpanded are no longer dead - daemon session: include the target workspace in the create-session failure message - tests: rework WebShellSidebar tests for the WorkspaceSection UI (add the useWorkspace mock, query workspace buttons, cover primary->undefined), use the canonical DaemonWorkspaceCapability type, and add a createSession workspaceCwd forwarding test * fix(cli): harden dynamic workspace registration per review - POST /workspaces: bound cwd by MAX_WORKSPACE_PATH_LENGTH before any filesystem work, and return a generic 500 (log the full error to stderr) so responses can't leak internal filesystem paths - createDynamicWorkspaceRuntime: log a stderr warning when a workspace's settings can't be read, matching the startup secondary-workspace path * qwen: address PR review feedback (#6625) Dynamic workspace reloadDaemonEnv now mirrors the startup secondary path: after reloadEnvironment() it rebuilds the runtime env via buildRuntimeEnvironment(), calls wsEnv.replace(), and updates the env metadata (envFileReadFailed / envFileReadFailures / overlayKeys / envFilePaths). Without this, .env changes on a dynamically registered workspace never propagated to that workspace's spawned child processes. * qwen: address PR review feedback (#6625) Harden POST /workspaces and the workspace registry per review: - canonicalize with realpathSync.native (matches startup) so the same physical dir on a case-insensitive FS can't register twice - nesting guard now also checks in-flight registrations, closing a concurrent parent/child registration race - error responses no longer echo resolved/other-workspace paths - registry add() isolates onChange listener throws so a bad listener can't abort a caller after the workspace is already committed * qwen: address PR review feedback (#6625) - POST /workspaces: cap total registered workspaces (startup + dynamic) to guard against unbounded registration exhausting resources - createDynamicWorkspaceRuntime: register shutdown-cleanup arrays only after the runtime is fully built, so a throw during workspace-service construction can't orphan the bridge/channel - web-shell App: reset selectedWorkspaceCwd after session creation so the workspace picker is one-shot (next new chat defaults to primary) * qwen: address human review suggestions (batch 1) - WorkspaceSection: add console.warn on session-poll failure (was silent) - WorkspaceSection: add aria-expanded for screen readers - AddWorkspaceDialog: associate label/input (htmlFor/id), i18n the absolute-path error, accept Windows drive-letter paths - i18n: remove unused workspaceUntrustedHint key, add addWorkspaceAbsError * qwen: address human review suggestions (batch 2) - Remove dead CSS (.workspacePickerSelect, .workspaceItem* classes from the old select-based picker, replaced by WorkspaceSection) - Add title tooltip to single-workspace project name (shows full path) - WorkspaceSection: sync expanded state on workspace.primary change * qwen: address human review suggestions (batch 3) - DaemonWorkspaceProvider: refreshCapabilities now clears error on success and sets error+status on failure (was incomplete vs mount) - Remove unused onChange/WorkspaceRegistryEvent from workspace registry per simplicity-first (no consumer exists; defers API surface until a real subscriber like SSE push is needed) * qwen: add workspace-management route test coverage Tests cover: 501 (no factory), 400 (missing/empty/relative/long/ nonexistent cwd), 409 (duplicate canonical path), 201 (success), and verifying error messages are generic (no path leak). * qwen: fix CI build failure — add explicit types in route test The CLI's tsconfig includes test files in tsc --build, so all noImplicitAny violations in tests cause build failures. Add explicit type annotations to mock parameters. * qwen: add type/title to single-workspace add-button --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |