feat(dsh-plugin): better-sidebar 集成、会话关停与归档清理、悬浮窗修复 - #130
Open
BB-fat wants to merge 11 commits into
Open
Conversation
…gable The expanded observation overlay's bottom-left (sw) and bottom-right (se) resize handles sat at z-index 2, below the full-width bottom actions bar (z-index 3) inside the card's stacking context, so every pointer event in the bottom corners landed on the toolbar and resize never started. The top corners worked only because the header is unpositioned. Raise the corner hit targets to z-index 4 so all four corners receive pointerdown again.
…-sidebar tab When the dsh-better-sidebar plugin is installed, its client publishes a betterSidebar cordis service; the observation tracking view now moves from the floating card into a single-instance sidebar tab registered through that service (detected via ctx.inject, so profiles without the sidebar plugin keep the floating overlay untouched): - observation-sidebar.tsx: tab descriptor (globe icon, live session-count badge, single instance) + ObservationSidebarTab rendering the shared OverlayBody without card chrome; auto-opens the tab when the first browser session appears but never re-focuses an already-open tab; the Document PiP pop-out upgrade stays available from inside the tab. - sidebar-mode.ts: carrier flag the floating overlay subscribes to — while sidebar mode is active the card/capsule hides (an open PiP window keeps its portal), and it resumes the moment the sidebar service unloads. - observation-view.ts: the view model (snapshot/focus/pin/ticker) and the PiP plumbing extracted from ObservationOverlay so both carriers share them; focusOf/statusOf move here and are re-exported. - observation-store.ts: refcounted acquire/release so overlapping carriers (overlay, tab, integration fiber) never kill each other's SSE feed. - OverlayBody is exported; the header only shows the move cursor when the carrier actually drags (data-draggable).
The sidebar already ships a built-in "browser" tab, so retitle the observation tab to "Browser Skill" and swap the remixicon globe for the BSK product mark (apps/extension/assets/logo.png downscaled to 32px and inlined as a data URL — 2.4 kB, no route or asset serving needed).
…n the status row Two live-reported issues with the sidebar carrier: - Auto-open appeared not to work: the type-only openTab minted the tab but never expanded a collapsed panel, so nothing surfaced for the user. The open now carries an inert content seed (path), which the sidebar treats as a content open — it expands the hosting panel and lands the tracking view in sight. - The status header's bottom border sat ~7px above the shell header's hairline (tab strip 34px + compact 28px card header vs the builtin tabs' 36px first rows), breaking the window-wide line at the panel boundary. In the sidebar the header now follows the builtin first-row metrics (36px, matching paddings); the floating card keeps its compact header.
…ons behind a collapsed panel When the observation tab already exists but the panel is collapsed, a new browser session now issues the same content open: the sidebar dedupe- focuses the existing tab AND expands the panel (documented openTab semantics), so the tracking view resurfaces exactly like the floating card did. While the panel is open, an existing tab is still never re-focused.
…rder Pixel analysis of the user's window showed the line still stepped ~6px at the panel boundary — the shell conversation header's height varies per window (35-38px), so no fixed row height can land a border on it — and the BSK warm border tint (oklch hue 60) visibly clashes with the sidebar's neutral hairlines. Borderless in the sidebar, the status row reads as plain chrome and the stage's own background separates it; the floating card keeps its bordered compact header.
…with a two-click confirm Every carrier of the observation view (floating card, better-sidebar tab, PiP) now offers a stop button next to interrupt, driven by a lightweight armed-state confirm: the first click flips the button to a solid-red check (3s expiry, auto-disarm when the focus vanishes), the second executes — a stray single click can never close an Agent Window. - host: ObservationService.stopSession kills in-flight tool children so a hung command never delays the stop, funnels the stop through the session's keyed queue like the tool path, treats a daemon-forgotten session (dead strip entries) as an idempotent success, and removes the registry + observation entries; POST /bsk-observation/stop requires an explicit sessionId (destructive calls never default to "current"). - client: store.stopSession posts the stop; the session's removal arrives through the existing SSE remove event, so all carriers update at once.
…n it is archived Archiving a DSH conversation hides it from every surface, but any Agent Windows it opened kept running with no way back to them. The plugin now records which conversation started each bsk session — the calling agent's session id plus every ancestor along the seed lineage (a subagent's browsers belong to the root conversation too) — and watches the workspace registry's domain/changed broadcast for newly archived ids, stopping those sessions through the same kill/queue/teardown path as the overlay's stop button. Re-archiving after an unarchive cleans up again; headless compositions (no workspace domain) degrade to a no-op.
…sation's own bsk sessions The sidebar tab used to show every bsk session in the profile. Each observation entry now carries the owning DSH conversations (the starting agent's session plus its seed-lineage ancestors, stamped at addSession), and the sidebar surface filters by them: - the tab body (focus view + strip) shows only sessions started by the sidebar's own conversation or its descendants; the floating card and PiP keep the global view; untracked (orphan) sessions stay global-only - the tab badge counts only sessions visible to its conversation - auto-open fires only when a session visible to the ACTIVE conversation appears, and re-evaluates on sidebar state changes (subscribeState) — which also covers the store's async init after page load and conversation switches
…ests - drop the tab-icon data-URL assertion (cosmetic constant, no logic) - drop the sidebar PiP round-trip (already covered through the shared usePip path by the overlay's PiP test) - fold the feed-lifetime check into the registration lifecycle test - fold disarm-silence, empty-identity, and empty-ownership guards into their parent behavior tests No coverage lost: 156 tests (was 162, −6 cases).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
优化 dsh 插件的观察视图(observation overlay),共 9 个 commit:better-sidebar 集成、会话生命周期管理(关停/归档清理)、悬浮窗 bug 修复。
改动
better-sidebar 集成
dsh-better-sidebar插件后(cordis 服务探测,未安装时行为完全不变),追踪视图从悬浮卡片迁入侧边栏单例 tab(browserskill:observation),保留 Document PiP 弹出会话生命周期
POST /bsk-observation/stop(强制显式 sessionId,daemon 已遗忘的死会话幂等成功,先杀在途命令避免挂起拖住关停)header.parentSession血缘祖先),监听 workspace registry 的domain/changed差分触发;取消归档后再归档会重新清理悬浮窗修复
验证