mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-13 10:45:27 +00:00
14 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
727c2d580c
|
fix(web-shell): prevent sidebar footer overflow (#6522) | ||
|
|
045bbee6ce
|
fix(web-shell): hide sidebar settings text when width is insufficient (#6494)
Prevent the 'Settings' label from wrapping to a new line when the sidebar is narrow. Instead, the text is clipped via overflow:hidden and only the gear icon remains visible. |
||
|
|
f7296d0333
|
feat(web-shell): add Qwen logo beside the sidebar new-chat button (#6437)
Place the Qwen brand mark to the left of the sidebar's New chat button. The artwork is the same SVG used for the browser-tab favicon (and the QwenLM GitHub avatar), inlined rather than hot-linked because the Web Shell CSP is `img-src 'self' data: blob:`, which blocks remote images. When the sidebar is collapsed there is no room beside the compact button, so the mark is hidden and only the New chat button remains. |
||
|
|
f41e95ac18
|
feat(web-shell): add Session Overview panel and in-window split view (#6400)
* feat(web-shell): add Session Overview panel and in-window split view
Add a large-screen "Session Overview" mission-control panel and an
in-window split view so users can monitor and drive multiple daemon
sessions at once.
- SessionOverviewPanel: ranked live cards (needs-approval -> running ->
idle) merging the workspace session list with the detail=full status
report. Multi-select opens the selected sessions as a split view in
the current tab ("Open in split") or in a new browser tab ("Open in
new tab", via a ?split=a,b URL).
- SplitView + ChatPane: one DaemonWorkspaceProvider hosting N
DaemonSessionProvider panes, each a self-contained interactive chat
(transcript, composer, streaming, tool/ask approvals). Browser focus
scopes the keyboard per pane, so panes never contend over approvals.
- Sidebar entry points gated to large screens; the split view's Back
returns to the Session Overview.
* refactor(web-shell): address review feedback on the session overview / split view
- SessionOverviewPanel: prune the selection Set when a session leaves the list
(so a reappearing session isn't silently reselected) and make select-all use
the intersection rather than prev.size.
- Extract isAskUserPermission into a shared util so App.tsx and ChatPane.tsx no
longer keep verbatim copies that can drift.
- SplitView: dismiss the "add session" picker on Escape or a click outside it.
- Tests: MAX_PANES cap, popup-blocked path, checkbox-selects-without-navigating,
stale-selection pruning, and a direct test for the extracted util.
* fix(web-shell): address /review findings on the split view
- ToolApproval: add a `keyboardActive` prop; split panes pass false so global
Enter/Escape/digit shortcuts can't confirm the wrong session's approval, and
the outer session's approval overlay is no longer rendered behind the split
(where it would keep its global shortcuts while hidden).
- ChatPane: defer the composer commit until sendPrompt resolves, so a rejected
prompt (transcript loading / disconnected / turn active) preserves the draft
instead of silently dropping it.
- SplitView: include a per-mount nonce in each pane's clientId so two tabs
opening the same split don't share a client id — which suppressOwnUserEcho
would treat as a self-echo and drop from the transcript.
- SessionOverviewPanel: cap the split selection to MAX_SPLIT_PANES before
building the ?split= URL or opening the in-window split, with a hint when more
are selected; also dismiss the split picker on Escape / click-outside.
- Tests covering each.
* fix(web-shell): address second /review round on the split view
- SplitView: wrap each pane in its own ErrorBoundary, so a render crash in one
pane (malformed block, unexpected tool shape) shows an inline fallback with a
close action instead of white-screening the whole split.
- splitUrl / overview: carry the daemon token into the new-tab split URL's
fragment. The current tab has already stripped the token from its URL, so a
token-auth (`serve --open`) deployment would otherwise open the split tab
unauthenticated. The token rides the hash (never sent to the server / logs).
- Tests: per-pane error isolation, token-in-fragment (and none without a token),
and the overview polling effects (interval fires, document.hidden skips, and
the in-flight guard prevents overlapping polls).
* fix(web-shell): hide the outer chat under the split and share app-level contexts
- App: hide (display:none) + aria-hide the outer chat subtree whenever
mainView !== 'chat', not only when a panel is open. Previously the outer
chat/composer/toolbar stayed reachable by keyboard/AT behind the full-page
split (it was only covered visually). State is preserved (node stays mounted).
- App: wrap SplitView in the app-level WebShellCustomizationProvider and
CompactModeContext so split panes render markdown / tool-headers / thinking
the same way the single-session chat does. Todo contexts stay chat-only —
they belong to the outer session, not the panes.
* refactor(web-shell): address review suggestions — coverage, dedup, split UX
- ToolApproval: add a dedicated test on the real component that the global
keyboard shortcut is armed by default and NOT armed when keyboardActive=false
(the cross-pane approval safety mechanism).
- SplitView: auto-exit to the Session Overview when the last pane is closed
(guarded so an initial empty seed doesn't bounce straight back out).
- ChatPane: add tests for the cancel action, the empty/whitespace submit guard,
and error routing to the onError prop.
- Extract the shared session-list page size + organization feature flag into
constants/sessions.ts, used by the overview, split view, and sidebar, so the
values can't drift between the three.
* fix(web-shell): surface outer approval + failed refresh in overview/split
- Split view: when the outer (main) session is waiting on an approval
that's hidden behind the split, show a non-blocking notice banner with
a "Go to it" button that returns to the chat where the approval lives.
- Auto-close the split (like the overview panel) when the viewport shrinks
below the large-screen breakpoint, so users aren't stranded.
- Session Overview: surface a failed refresh inline (keeping the last-good
cards) instead of silently swallowing it once cards are on screen.
- Tests: status-report poll cadence, picker dismiss (Escape / outside /
inside click), inline refresh-failure banner.
* fix(web-shell): sever window.opener on split tab; tighten hidden-chat test
- openSelectedInNewTab now clears win.opener (the split tab carries a
daemon token in its URL fragment) to prevent reverse tabnabbing, matching
the existing bug-report window.open path.
- Strengthen the split-view App test so a missing outer-chat subtree fails
instead of passing vacuously through an optional chain.
* fix(web-shell): split-view focus/stability/robustness follow-ups
- Refocus the composer after a shrink-driven split close so keyboard users
aren't dropped onto <body> (skips when an approval or panel takes over).
- Stabilize SplitView onExit via useCallback so its last-pane-close effect
doesn't re-fire on every App re-render.
- ChatPane: surface a per-pane connection-loss banner instead of silently
showing stale messages when a pane's daemon connection drops.
- ChatPane: anchor the streaming timer to the active turn's start (last user
message timestamp) so a pane opened mid-turn shows real elapsed time.
- Tests: split auto-close on shrink, outer-approval split notice + return-to-
chat, connection banner, and streaming-timer anchoring.
|
||
|
|
9a63c03224
|
feat(web-shell): add a Scheduled Tasks management page (#6348)
* feat(web-shell): add scheduled tasks management page Add a "Scheduled tasks" page to the Web Shell for managing durable cron tasks against the current workspace. - Sidebar entry opens a full-pane page (replaces the chat area, not a modal) listing tasks with enable/disable toggle, delete, run-now, and human-readable schedules. - "New scheduled task" opens a modal with a schedule builder (daily / weekdays / weekly / hourly / every-N-minutes / custom cron) and a live preview. - "Create via chat" returns to the chat and primes the composer so the agent creates the task through its cron_create tool. - Daemon CRUD routes (GET/POST/PATCH/DELETE /scheduled-tasks) read/write the existing per-project scheduled_tasks.json; task firing stays with the session-side scheduler. - Extend DurableCronTask with optional name/enabled (backward compatible); the scheduler skips tasks with enabled:false. - Add /scheduled-tasks to the vite dev-server proxy allowlist so the page works under npm run dev:daemon. * chore(web-shell): address review feedback on scheduled tasks - cron_list: surface name/enabled so the agent can tell a disabled durable task from an active one (a disabled task no longer looks identical to an active one). - core: export only the tasks-file functions the daemon route actually uses (drop unused addCronTask / getCronFilePath / CRON_TASKS_DISPLAY_PATH from the public barrel). - CronScheduler: warn when a durable reload fails and the prior view is kept, since a just-disabled or -deleted task can keep firing until the next successful reload. - Extract the schedule helpers (buildCron / describeCron / parseHhmm / describeLastRun) into a pure module and add unit tests for them. - Add route tests for PATCH cron/prompt/recurring, empty-patch rejection, and POST field-length / boolean-type validation. * chore(web-shell): address second review round on scheduled tasks - Log CRUD errors server-side (writeStderrLine) in each route catch block, matching the other daemon routes. - Share one id generator (generateCronTaskId in cronTasksFile) between the scheduler and the daemon route instead of duplicating it. - describeCron: recognize cron day-of-week 7 as an alternate notation for Sunday. - Reset the builder time to :00 when switching to the hourly frequency (its time picker is hidden, so it no longer silently carries the daily minute). - Tests: cron_list name/disabled output; route Feb-30 impossible-cron and corrupt-file 500 read-failure; describeCron dow=7. * chore(web-shell): address third review round on scheduled tasks - Run now: report sendPrompt rejections via the toast/error path instead of dropping the promise. - Block chat interaction while the full-pane Scheduled Tasks view is open, so the covered composer can't receive keystrokes/Escape. - Guard reload() with a request-sequence id so a slow load can't overwrite a newer list after a mutation. - Re-enabling a task that had genuinely fired resumes from now instead of catching up work paused while it was disabled. - Restrict "every N minutes" to divisors of 60 (a non-divisor */N fires more often than the label claims). - Show a Repeats / Runs once label on each card so tool-created one-shots aren't mistaken for repeating schedules. - Return generic 500 client messages (no internal file path); the detail is logged server-side. - Tests: SDK scheduled-task methods (method/URL/id-encoding/headers/errors); route re-enable behavior both ways. * chore(web-shell): address fourth review round (minor suggestions) - Route error logs interpolate the actual task id instead of the literal ":id". - cron_list returnDisplay includes the task name (matching llmContent) so terminal /cron list shows UI-assigned names. - Truncate the delete-confirm label so an unnamed task's long prompt doesn't blow up the confirm() dialog. - Cap the create-form prompt textarea at MAX_PROMPT_LENGTH and drop the dead typeof-window guard. - Test generateCronTaskId (format + near-uniqueness). * chore(web-shell): address fifth review round on scheduled tasks - Re-enable now resumes any recurring task from now (stamp on every false→true), not only ones that had already fired — a task disabled before its first run no longer catch-up-fires the slot it was paused through. - describeCron applies the same divisor-of-60 check as buildCron, so a hand-edited/persisted */45 falls back to the raw expression instead of a misleading "every 45 minutes". - Strengthen the corrupt-file route test to assert the generic client message and no leaked file path. - Tests: recurring-disabled-before-first-run and one-shot re-enable; describeCron non-divisor fallback. * test(cli): cover legacy scheduled-task normalization on GET Seed a pre-fields task (no name/enabled) directly to disk and assert the GET response normalizes it to name:null / enabled:true, guarding backward compatibility with existing scheduled_tasks.json files. * fix(core): cap durable cron loads against a durable-only budget The daemon route accepts up to MAX_JOBS durable tasks on disk, but the scheduler previously capped durable loads against its combined job map (session-only + durable). A session holding session-only cron jobs could push the map to MAX_JOBS and make loadFileTasks silently skip durable tasks the route had already accepted — a create that returned 201 would then never fire. Cap durable installs against a durable-only count instead, and share one MAX_JOBS constant between the scheduler and the daemon route, so a successful create is always loadable. Adds a scheduler test that 40 session-only jobs no longer crowd out 20 durable loads. |
||
|
|
edc0555ed1
|
feat(web-shell): named session groups and color tags in the sidebar (#6350)
* feat(web-shell): named session groups and color tags in the sidebar Extend web-shell session organization with named groups (create / rename / delete, assign a session to a group) alongside quick color tags, and surface pin / archive state. The grouping data is plumbed end-to-end through the daemon. - core: session-organization-service carries group id / name / color and pin / archive metadata on organized-list entries - sdk / acp-bridge: session-list entries gain groupId / groupName / groupColor / archivedAt; add SessionGroupColor and list-session-groups result types - cli/serve: dispatch + session routes expose listing and assigning groups - web-shell: sidebar group management UI (create / rename / delete groups, color picker, pin, archive) and reuse the shared "Group" label for the group action, dropping the redundant "Move to group" string * fix(cli): exclude color-tagged sessions from the ungrouped filter Color / named group / recent are mutually exclusive buckets in the web-shell sidebar — a color-tagged session shows in its color section, not "recent". But the organized session-list `group=ungrouped` filter only checked `groupId == null`, so a color-tagged session with no named group leaked into ungrouped results for REST/ACP consumers, disagreeing with the UI taxonomy. Align the server filter: ungrouped means no named group and no color tag. Adds an ACP session/list test asserting a color-tagged session is excluded from group=ungrouped (fails on the old filter, passes on the new one). * fix(web-shell): clear color tag when creating a group for a session saveGroupEditor's create-with-target path assigned the new group but left any existing color tag in place, unlike the sibling assignSessionGroup / assignSessionColor paths that keep color and named group mutually exclusive. Because color takes precedence in the sidebar's section bucketing, the session stayed in its color section and the group assignment had no visible effect. Send `color: null` alongside `groupId` on that path, and extend the create-group dialog test to assert the assignment clears the color. * fix(cli): exclude color-tagged sessions from the named-group filter Follow-up to the ungrouped filter fix: the per-group filter (group=<id>) also ignored color precedence. Core and the REST/ACP update paths can persist both groupId and color, and the sidebar renders such a session in its color bucket, so group=<id> API consumers saw a session the web-shell shows elsewhere. Require `color == null` there too, matching the sidebar taxonomy (color > group > recent). Adds an ACP session/list test for a session with both groupId and color set. |
||
|
|
7605c8bd15
|
feat(web-shell): add onSessionChange and onSubmitBefore callbacks (#6333)
* feat(web-shell): add onSessionChange and onSubmitBefore callbacks Add session-level event callbacks and a pre-submit interception hook to WebShellProps, enabling external consumers to observe session lifecycle events and gate prompt submissions. New APIs: - onSessionChange: fires on rename (SSE-driven), submit (direct and queued), and turn_complete (streamingState transition with error context including block ID). - onSubmitBefore: async hook called before prompt submission; reject cancels the prompt with full retry-state rollback (lastSubmittedPrompt, lastSubmittedImages, retriedTurnErrorId, showRetryHint). Sidebar integration: - sessionListReloadToken triggers sidebar reload on session events with pollInFlightRef + document.hidden guards. - Delayed 2s reload after submit to account for daemon registration lag. Safety: - isPreparingPrompt loading state during onSubmitBefore prevents duplicate submissions. - streamingSessionIdRef prevents spurious turn_complete on session switch. - All slash commands (including internal /language, /model) go through onSubmitBefore; queued prompts intentionally bypass it. * fix(web-shell): add null initial value to delayedReloadTimerRef React 19's useRef requires an explicit initial value argument. Match the existing escapeTimerRef pattern: | null + null. * fix(web-shell): move clearFollowup after onSubmitBefore gate and add tests - Move clearFollowup() to after onSubmitBefore succeeds so that followup context is preserved when the before hook rejects - Add null guard for clearTimeout on delayedReloadTimerRef - Add 5 unit tests for sidebar sessionListReloadToken effect covering: token change, undefined, unchanged, document.hidden, and poll-in-flight gate conditions Addresses PR #6333 review feedback. * feat(web-shell): call onSubmitBefore for queued prompts Previously enqueuePrompt bypassed onSubmitBefore entirely. Now the before hook is also invoked for queued prompts — if it rejects, the prompt is cancelled and not added to the queue. The composer still clears synchronously (fire-and-forget) since the Composer's onSubmit contract is synchronous (boolean | void). Also updates the onSubmitBefore JSDoc to reflect this behavior. Addresses PR #6333 review feedback on security gap. * test(web-shell): cover session callback behavior * fix(web-shell): preserve rejected queued prompts * fix(web-shell): preserve rejected direct prompts --------- Co-authored-by: ytahdn <ytahdn@gmail.com> |
||
|
|
7a528d078a
|
feat(daemon): Add session organization (#6305)
* feat(daemon): add session organization Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(daemon): address session organization review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(daemon): cover session organization review cases Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6305) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6305) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6305) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6305) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6305) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6305) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(web-shell): Address session organization review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): Harden session organization review edge cases Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): Address session organization review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
59e771cef6
|
feat(daemon): Add session export endpoint (#6297)
* feat(daemon): add session export endpoint Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address PR review feedback (#6297) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: fix PR integration capability baseline (#6297) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * codex: address export tool call id review (#6297) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
c37cb23ccc
|
feat(web-shell): manage sessions from the sidebar (archive, unarchive, delete) (#6293)
Add an Archive quick action and a "..." overflow menu (Rename / Archive / Delete) to each session row in the web-shell sidebar, plus a collapsible "Archived" section that lazily lists archived sessions with Restore / Delete. Thread the daemon's existing archiveState filter and archive/unarchive endpoints through the webui workspace facade and the useDaemonSessions hook; rename stays limited to the current live session. |
||
|
|
9b2fb30cb0
|
feat(web-shell): add a daemon status page backed by GET /daemon/status (#6272)
* feat(web-shell): add a daemon status page backed by GET /daemon/status Surface the consolidated daemon status API (#5174) in the Web Shell as a dashboard dialog opened from a sidebar footer button. - @qwen-code/sdk: DaemonClient.daemonStatus(detail) plus DaemonStatusReport* wire types for the /daemon/status envelope (summary and full detail). - @qwen-code/webui: loadDaemonStatus workspace action and a useDaemonStatusReport hook (exported as useDaemonStatus from daemon-react-sdk). - web-shell: DaemonStatusDialog rendering one dashboard — overall status badge, issues list, daemon/runtime/transport/security/limits/capabilities cards, plus per-session, workspace-diagnostics, and auth sections. The daemon's summary/full cost split is hidden from the operator rather than exposed as a toggle: the cheap summary rides a 5s auto-refresh while the expensive full report (which may spawn the ACP child and aggregate workspace diagnostics) is fetched only on open and on manual refresh, so parking the dialog open never rehits that path. Capabilities are sorted, counted, and height-capped; the long workspace path stays on one line, front-truncated so the tail remains visible. New pulse-icon sidebar entry; EN/zh-CN strings. - vite dev proxy: forward /daemon to the daemon; without it the SPA fallback answered /daemon/status with index.html and the dialog failed JSON parsing under npm run dev:daemon. * fix(web-shell): address review on the daemon status dashboard - Drive the status badge and issues list off the full report when it is available, not the summary. The daemon only rolls workspace/preflight/MCP problems into status+issues for detail=full, so the summary can read "ok" with no issues while a loaded full report is degraded — the dashboard now reflects the full rollup (live counters still come from the summary). - Guard the 5s poll with an in-flight ref so a slow/degraded daemon cannot accumulate overlapping status calls (useDaemonResource discards stale completions but does not abort; the client timeout is 30s). - Fix the public DaemonStatusReport wire type: runtime.channelWorker.channels is string[] (ChannelWorkerSnapshot), not an array of objects; mirror the remaining optional snapshot fields. * fix(web-shell): translate workspace section status badges WorkspaceSectionRow rendered the raw wire status (`ok`/`warning`/`error`/ `unavailable`) while every other badge in the dialog goes through `t()`, so under a Chinese UI these badges showed lowercase English. Route the badge through `t('daemon.level.<status>')` and add the missing `daemon.level.unavailable` key to both dictionaries. * fix(web-shell): scope toolbar error to summary; broaden dashboard test coverage - The toolbar "failed to load" banner now keys on the summary fetch only. A failed full fetch is already surfaced in the diagnostics section, so it no longer makes an otherwise-healthy summary (fresh cards + timestamp) read as broken. - Use the ASCII "..." ellipsis in the diagnostics-loading string to match the rest of the i18n dictionary. - Add tests: summary-healthy/full-failed degraded state, the ACP-disabled transport branch, uptime/memory/duration formatting across unit boundaries (day, GB, sub-second, fractional-second), and sidebar Daemon Status button click (expanded + collapsed) — the feature's only entry point. * fix(web-shell): pause polling on hidden tab; scope dev proxy; fix test mock - Skip the 5s status poll while document.hidden, matching the sidebar poll — a backgrounded tab no longer hits the daemon every 5s. - Narrow the vite dev proxy to the exact /daemon/status route instead of a bare /daemon prefix, mirroring the scoped /voice/stream entry; verified the dashboard still proxies (summary + detail=full) in dev. - Add a message field to the DaemonStatusReport issue mock in the webui provider test so it matches the required DaemonStatusReportIssue shape. * feat(web-shell): surface runtime/channel-worker diagnostics; a11y + polish Address the daemon-status review round: - Render the runtime startup/failure state (runtime.loading / runtime.error) in the Runtime card so the plausible-looking zero counters during startup are not mistaken for a healthy idle daemon. - Surface channel-worker diagnostics (state, exit code/signal, error, restart count) when the worker is enabled — these fields were fetched and typed but never shown, leaving a bare "down" with no context. - Include full.error.message in the diagnostics-failure line (matching the summary error path) so a failed detail fetch is actionable. - Show "N/A" instead of a literal "null" chip for null workspace summary values (the wire type allows null). - Add role="status" + aria-label to the health badge for screen readers. - Rename the public hook alias useDaemonStatus -> useStatusReport, matching the Daemon-prefix-stripping convention of the other re-exports. - Add tests: runtime startup/failure, channel-worker diagnostics, and the empty/disabled placeholders (sessions, rate limit, capabilities, ACP), toolbar-banner-with-data, and pure-loading branches. * fix(web-shell): contain daemon status crashes; workspace empty-state - Wrap the dashboard in a local ErrorBoundary so a malformed/partial daemon response (e.g. an older daemon omitting an additive field like channelWorker) — most likely exactly when the daemon is sick and the dashboard is most needed — shows a contained fallback instead of throwing to the root boundary and white-screening the whole web shell. - Add an empty-state to the Workspace Diagnostics card (parity with the Sessions card) for when full.workspace is empty. - Tests: error-boundary containment on a malformed report, and the workspace empty-state. * fix(web-shell): fix error-boundary recovery; contain detail crashes Address the review round (one Critical): - ErrorBoundary recovery was broken: the comment claimed resetKeys cleared the fallback, but none was passed. Switch to a function-form fallback that surfaces the actual render error (distinct from a network failure) and fix the comment — recovery happens on re-open, since the parent only mounts the dialog while open. - Wrap FullDetail in its own ErrorBoundary so a malformed detail=full payload is contained to the detail region instead of taking down the healthy summary cards with it; add a catch-all branch so a fetch that resolves without a `full` section shows a failed state instead of hanging on "Loading...". - Toolbar failure banner now shows only when the summary errored AND still has data on screen (`summary.error && summary.report`), so it no longer misrepresents a dashboard that is rendering from the full fallback. - SDK type: drop `& Record<string, unknown>` on DaemonStatusReport.daemon and add the typed optional `startup` field, matching the DaemonCapabilities convention the interface JSDoc claims. - Add a real useDaemonStatusReport hook test asserting the `report` alias maps from `data` — the dialog test mocks the whole hook, so nothing else guarded it. * feat(web-shell): surface runtime.activity in the daemon status dashboard PR #6270 added a runtime.activity sub-object to GET /daemon/status (activePrompts, lastActivityAt, idleSinceMs). Type it as an additive optional on the SDK DaemonStatusReport and render it in the Runtime card: active-prompt count and an idle duration ("no activity yet" when the daemon has seen none). Gated on the field's presence so older daemons that omit it still render. Verified end-to-end against a real qwen serve --web that emits the field. * fix(web-shell): daemon status polish — i18n count, negative clamp, coverage Address the review round (all minor): - Move the capabilities count into the i18n string (daemon.capabilities.titleCount with a {count} placeholder) so locales can reorder it. - Clamp negative durations in formatDurationMs (clock-skew defense). - Re-export the hook options type as StatusReportOptions for consumers wrapping useStatusReport. - Tests: use the real rate-limit tier keys (prompt/mutation/read) in the fixture, and cover the session-id display fallback, the channel-worker signal branch, and a healthy workspace section's chip/status rendering. * feat(web-shell): name the failing checks behind a workspace section status A "warning"/"error" workspace-diagnostics section only showed a rollup badge plus count chips, so e.g. a warning preflight was opaque — the operator couldn't tell it was the auth check without curling the API. Extract the individual warning/error cells from the section's raw data (across cells / servers / skills / tools / providers / hooks / extensions) and render each with its label and message (e.g. "auth: No auth method configured."). OK and other non-problem cells stay hidden. Verified end-to-end: a real daemon with no credentials now shows the auth warning inline under preflight. |
||
|
|
da22360c25
|
feat(web-shell): show the qwen-code version in the sidebar footer (#6222)
* feat(web-shell): show the qwen-code version in the sidebar footer The Web Shell had no visible version. Show the running qwen-code version (from the daemon capabilities) in the sidebar footer, inline with the Settings button so it stays visible without taking its own row. Render the version consistently wherever it appears: - Prefix "v" only for a real semver release; a non-semver fallback such as "unknown" is shown as-is, so we never render a bogus "vunknown". Applied to the Web Shell badge and the TUI header. - Dev builds (scripts/dev.js) now report the real package version instead of the "dev" sentinel, matching scripts/start.js, so the UI shows the actual version (e.g. v0.19.4). DEV=true / NODE_ENV=development remain the signals that mark a dev build. * test: add readFileSync to node:fs mock in dev.test.js scripts/dev.js now reads package.json via readFileSync at module load to report the real CLI_VERSION, but the node:fs mock in dev.test.js did not export readFileSync, causing vitest to throw "No readFileSync export is defined on the node:fs mock" and failing the suite. |
||
|
|
7b9e31885b
|
feat(web-shell): add mobile sidebar drawer with session list (#6003)
* feat(web-shell): add mobile sidebar drawer with session list Replace the display:none behavior at viewport <=760px with an overlay drawer pattern. A hamburger menu button appears on mobile, tapping it slides the existing WebShellSidebar in as a fixed overlay with a semi-transparent backdrop. Selecting or creating a session auto-closes the drawer. Desktop layout (>=761px) is unaffected. Closes #6000 * fix(web-shell): address review feedback for mobile sidebar drawer - Use display:contents for desktop wrapper transparency (Critical: sidebar was hidden) - Fix z-index stacking so sidebar renders above backdrop in drawer - Force sidebar expand when mobile drawer is open (collapsed state) - Hide resizeHandle on mobile to prevent touch scroll conflicts - Reset drawer state on viewport resize via matchMedia listener - Add role=dialog, aria-modal, Escape key dismissal, body scroll lock - Add aria-expanded to hamburger button - Close drawer when opening Settings or resuming sessions * fix(web-shell): address second round of review feedback - Remove dead :global(.sidebar) selector (CSS Modules hash class names) - Fix Escape key capture-phase handler to not intercept sidebar inputs - Conditionally apply role=dialog/aria-modal only when drawer is open - Stop toggling collapsed prop on drawer open/close to preserve sidebar state - Add closeMobileDrawer() for bare /resume command path - Fix hamburger button vertical centering in empty chat state on mobile * fix(web-shell): fix stacking context and escape handler in mobile drawer * fix(web-shell): prevent iOS Safari background scroll when drawer is open * chore: remove accidentally committed .qwen-session and gitignore it The .qwen-session file is a developer-local session UUID generated by qwen serve. It was accidentally committed to the repo and should never be tracked. * fix(web-shell): address review feedback for mobile drawer - Don't preventDefault touchmove inside the drawer so the session list can scroll natively; only block scrolling on the page behind it. - Defer Escape to a pending tool/permission approval (reject) instead of closing the drawer when a prompt is visible. - Reuse isEditableTarget from utils/dom and only bail out for editable targets outside the drawer, so the drawer search input still closes on the first Escape. - Close the drawer before awaiting loadSession so it doesn't linger over the old transcript, matching the other session-switch paths. - Keep the drawer panel visible until the backdrop finishes fading out to avoid a one-frame flicker on close. Co-Authored-By: Qwen-Coder <noreply@qwen.ai> * fix(web-shell): mobile drawer ignores collapsed rail + block backdrop scroll - collapsed: a user who collapsed the desktop sidebar got a mobile drawer that still rendered as the icon rail (no session list — the whole point of the drawer). Force the expanded layout while the drawer is open. - touchmove: the allowlist matched the outer [data-mobile-drawer] wrapper, which also contains the full-screen backdrop, so a touchmove starting on the dim backdrop skipped preventDefault and let iOS Safari scroll the page behind. Exclude the backdrop so only the panel keeps native scroll. Co-Authored-By: Qwen-Coder <noreply@qwen.ai> * fix(web-shell): harden mobile drawer collapse, error path, and width cap - Hide the sidebar collapse button while the mobile drawer is open so its no-op toggle can no longer silently persist desktop collapsed state. - Close the drawer before awaiting createSession() so a failed create no longer leaves the drawer stuck open with page scroll locked. - Drop redundant width/min-width/position from .sidebar.mobileOpen and cap it with max-width:100vw so a wide persisted width can't overflow phones. Co-Authored-By: Qwen-Coder <noreply@qwen.ai> --------- Co-authored-by: pomelo-nwu <czynwu@gmail.com> Co-authored-by: Qwen-Coder <noreply@qwen.ai> |
||
|
|
22389247d5
|
feat(web-shell): add optional session sidebar with navigation (#5931)
Co-authored-by: ytahdn <ytahdn@gmail.com> |