mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-24 16:16:13 +00:00
* feat(web-shell): Bind GitHub PRs to sessions with sidebar badge and search
When a PR is created from the Web Shell Git dialog, bind its number and
URL to the current session. The daemon accepts the binding through the
session metadata routes (validated at the route, bridge, SDK, and sidecar
layers, with the URL restricted to http(s) since it is rendered as a link
target), keeps it in live memory, and persists it as a per-session sidecar
file so the binding survives daemon restarts and follows the session
through archive/unarchive/delete.
The sidebar renders a #N badge next to the session title (opening the PR
via the desktop-aware external-link opener, shows the PR in the details
tooltip, and the session search now also matches PR number, branch name,
and worktree slug — so with many concurrent sessions, the one that
produced a given PR is one search away.
EOF
)
* feat(web-shell): Support multiple PR bindings per session
A session can produce several PRs (stacked or follow-up work), and
keeping only the latest binding would defeat the sidebar's
search-by-PR-number flow for every earlier one. The binding is now a
bounded list (10, oldest dropped) ordered by binding time: re-binding
the same number refreshes it and moves it to latest, the badge shows
the newest number with a +N overflow, the tooltip lists every bound
PR, and search matches any of them. The write API stays single-binding
per call; reads, SSE events, and responses carry the full list, with
the sidecar as the complete history merged over the live entry's
daemon-lifetime bindings.
* feat(web-shell): Show PR badges in the session overview and picker dialogs
The mission-control overview panel and the shared session picker row
(resume / delete / release dialogs) now show the same PR badge as the
sidebar — latest number with a +N overflow, opening the PR via the
desktop-aware opener — and the resume dialog's search matches bound PR
numbers, branch names, and worktree slugs through the shared
sessionMatchesGitQuery helper.
* fix(web-shell): Match the overview PR badge color to the sidebar accent
The overview card badge used the panel's neutral --primary tint while
the sidebar and picker badges use the accent violet; one element should
read the same on every surface.
* fix(web-shell): Address review findings on PR bindings
Read/display correctness (verified by ytahdn and the R1 review):
- mergeLiveSessionSummary merged {..existing, ..live} wholesale, so a
live entry's this-daemon-lifetime prs overwrote the sidecar-enriched
full history after a restart; prs is now merged by PR number (live
url wins, history kept), and the dead merge branch in
enrichPrSidecars is gone.
- The pr-only session_metadata_updated event carried no displayName,
which SDK folds treat as "cleared" — the title blanked on every PR
bind. The producer now echoes the current name.
- GitDialog synced sessionIdRef from the prop on every render, so the
fresh session id the dialog resolves for its own side queries was
clobbered before the binding read it; the sync now runs only when
the prop changes.
Robustness:
- upsertSessionPr's read-modify-write is serialized per sidecar path,
closing the concurrent-bind drop race under runSharedMany.
- The REST routes persist the sidecar before mutating the bridge, so a
failure on either side leaves the binding durable.
- The ACP dispatch only upserts when the call actually binds a PR (a
displayName-only rename no longer rewrites createdAt/order).
- pr.url is capped at 2048 chars across all four validation layers.
Structure & a11y:
- The three badge copies (sidebar / overview / picker) are now one
SessionPrBadge component: shared CSS, count-aware aria-label,
non-http(s) entries filtered defensively, and tabIndex=-1 inside
listbox options.
- The SDK's duplicated PR validator is a single session-pr module used
by both DaemonClient and events.
- Delete/Release dialogs' search matches bound PR numbers like Resume.
Tests: list-level live+sidecar prs merge, sidecar-vs-bridge echo
authority, route tests made order-independent, bridge
atomicity/cap/catalog-revision/displayName-echo cases, concurrent
upsert serialization, SDK fold keeps the name, GitDialog bind-failure
degradation, url-cap rejections at every layer.
* fix(core): harden session pr sidecar persistence and moves (#9543)
* fix(serve): align session pr echoes with the persisted sidecar (#9543)
Address round-4 review findings:
- R4-1 (Critical): bridge entries are re-created without prs on daemon
restart / close / archive-restore, so ACP and REST metadata updates
replied and broadcast only this daemon lifetime's bindings, silently
dropping persisted history. Hydrate the entry from the sidecar before
the mutation (new optional bridge seedSessionPrs) and make the ACP
handler reply with the authoritative persisted list like the REST
routes, fixing both the response and the session_metadata_updated
event on all three surfaces.
- R4-2 (Critical): the non-live metadata fallback persisted the rename
before the PR sidecar while bumping the catalog revision only after
both writes succeeded; a failed sidecar write stranded a durable,
unannounced rename behind a total-failure response. Persist the
sidecar first so a failed write leaves nothing durable behind.
- R4-3: map InvalidSessionMetadataError in toRpcError to the REST
invalid_metadata contract instead of an opaque -32603 Internal error.
- R1-5: add the stderr audit record for pr binding mutations, mirroring
the displayName branch (accepted in the round-2/3 thread).
- R2-4 (source part): make enrichPrSidecars' archiveState required so a
future archived-listing call site cannot silently enrich from the
active chats dir.
- R2-16: filter non-openable URL schemes in the session details tooltip
exactly like SessionPrBadge.
* chore(desktop): regenerate bun.lock to match workspace versions
Main's desktop lockfile drifted: @craft-agent/electron and
@craft-agent/shared are 0.0.5 in the workspaces but 0.0.1 in the
lockfile, and the @qwen-code/live-host workspace entry is missing.
bun install --frozen-lockfile (the Live Host CI gate) fails on any
PR touching packages/sdk-typescript/src/daemon/types.ts because of
this. Regenerated with bun 1.3.x.
* fix(web-shell): address R2 review findings on PR bindings
- SessionPrBadge: narrow onKeyDown to Enter only so the badge no longer
blocks roving-listbox navigation keys in picker dialogs (R2-15).
- SDK updateSessionMetadata: per-entry prs shape gate so a hostile or
buggy daemon response cannot surface javascript: urls or malformed
numbers downstream; valid entries survive (R1-17).
- Tests: bridge mirror atomicity (valid pr + invalid displayName),
GitDialog stale-id retry binding, list-level merge dedupe by number,
organized + archived listing paths keep PR sidecars, DaemonClient pr
request/parse + gate, Delete/Release dialog PR-number search (R2-6,
R2-13, R2-14, R1-15, R1-17, R2-20).
* fix(serve): address R5 review findings on PR bindings
Best-effort hydration (R5-1/R5-2/R5-3): the sidecar hydration read at
all three metadata-mutation sites (ACP dispatch, primary and workspace
REST routes) now absorbs non-ENOENT I/O errors as "no sidecar" instead
of failing the whole call — a squatted sidecar path no longer turns a
pr-less rename into a 500/-32603. This also makes the R4-2 fallback
ordering test reach the branch it names.
Validation hardening (R5-4): pr.url rejects control characters at all
four layers (bridge via hasControlCharacter, route, SDK guard, sidecar
reader) — the url is interpolated into the stderr audit line, so a
newline-bearing url could forge audit records.
Traversal parity (R5-5, R4-5): the ACP session/update_metadata handler
now gates on isValidSessionId before any sidecar I/O, and the primary
REST route's gate moved ahead of runtime resolution so traversal ids
get 400 invalid_session_id identically on single- and multi-workspace
daemons (previously 404 on multi-entry registries).
Tooltip (R5-6): PR rows key on index+number — a hand-edited sidecar
with duplicate numbers no longer risks cross-row reconciliation.
Tests: FakeBridge callLog pins seed-before-mutate order (R5-9);
cross-workspace pr sidecar lands in the owning workspace's chats dir
(R4-4); multi-workspace traversal test; metadata-filtered listing
keeps prs (R1-15); Resume dialog PR-number search (R2-20); dialog
fixtures annotated DaemonSessionSummary[] (R5-7/R5-8); control-char
rejection cases at bridge and sidecar layers.
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
|
||
|---|---|---|
| .. | ||
| assets | ||
| design | ||
| developers | ||
| e2e-tests | ||
| images | ||
| plans | ||
| superpowers | ||
| users | ||
| verification/abort-controller-refactor | ||
| _meta.ts | ||
| index.md | ||