zhchxiao123/dsh-devflow-plugins--packages-devflow-ui ↗★ 0
@zhchxiao123/dsh-devflow-ui
Devflow 看板浏览器端插件:提供只读的卡片阶段展示界面,支持侧边栏页面或悬浮控制面板。
AI 分析
核心用途是为用户提供直观的可视化任务看板。适合需要实时查看 AI 任务流转状态和开发进度的 DSH Web 用户。
安装
此插件尚未提供可验证的 bundle,或兼容性检查未通过。请先阅读仓库说明。 阅读完整 README ↗
说明文档
阅读完整 README ↗@zhchxiao123/dsh-devflow-ui
English | 中文
Devflow board plugin, browser half. The board has two surfaces and shows exactly one: where the dsh-better-sidebar foundation is composed it registers a sidebar page (dsh-devflow:board, single-instance, ordered after the foundation's own pages) and the header control is not registered at all; everywhere else it is the floating control described below. One place in the plugin decides, from the foundation's presence, and swaps the mounted surface when the foundation arrives or leaves — so the two can never both appear. The foundation is neither imported nor depended on: only the slice of its service this plugin calls is restated locally, and everything crosses through the service name, which keeps the client bundle purity gate satisfied and leaves compositions without the foundation byte-identical to before. A page the foundation refuses (a duplicate id) warns and leaves the rest of the plugin running.
The sidebar page is a full-height column: a header carrying the title (or the back control while a detail is open), then the workspace total and its distribution (in progress / blocked / done, three buckets that partition the total) and a row of stage chips that narrow the list to one location — a requirement whose own stage misses stays as the context of a matching slice, and its k/n keeps counting the whole breakdown. Below that the grouped card list fills the remaining height and scrolls. Opening a card replaces the list with its detail sheet, whose four blocks — requirement, breakdown, artifacts, timeline — are foldable sections that all arrive open, so the timeline finally has room. Where the foundation can persist and republish page settings, a side-by-side switch appears on the page's settings card: with it on, the list stays beside an open detail instead of giving way to it.
The sidebar page shows its own scope's workspace, not whichever session the app has in front: bindings are per session, and each page fetches its own. It fetches when it becomes the visible tab of an expanded panel; change frames refetch the scopes visible pages watch plus the selected session's — the one the tab badge and the + menu report on — so a background tab of another session costs nothing while the badge in front of the user stays live. The selected session's board is also refreshed on every open of the change stream and on every real selection change. The tab badge reports the in-progress card count from the last fetch (never a request of its own), counted exactly as the page's stats head counts it, and is only supplied where the foundation announces the badge capability. A workspace known to hold no cards offers the page as unavailable rather than hiding it; a workspace nothing has fetched yet stays openable, since opening it is what fetches.
The floating surface is a control anchored at the conversation area's top-right corner through a body portal (registered on the session header's utility slot for lifecycle, rendered outside it so no header stacking context can trap it). Collapsed it is one pill with the active-card count (or an idle label when everything is done); expanded it adds the read-only panel — a titled header with a collapse button, one row per card (state dot, id, title, localized stage plus the blocked origin, a seven-segment stage progress bar whose reached run is toned by state, and the revision), and a totals footer. The list is one level deep: a decomposed requirement leads its child cards, which sit indented under it, and its own row adds the k/n breakdown progress plus a marker when a child is blocked. A per-row toggle folds the children away and back; a child whose parent is absent from the listing (archived ahead of it) reads as a top-level row, so no card can vanish. Clicking a row swaps the list for that card's read-only detail: title and identity, an enlarged pipeline naming every stage, the requirement Markdown (rendered through the shared MarkdownText primitive, its acceptance checklist non-interactive), the breakdown relations (a child's parent backlink, a parent's child list, each drilling to that card's detail), the registered artifacts — one line per registration with its kind (a neutral placeholder for a registration predating kinds), registering stage, and revision, every superseded version still listed and the newest of a re-registered kind carrying a "latest" marker — the card file path, and the transition timeline — every journal entry newest-first with its actor, rework reason, approval signature, recorded gate verdicts (one line per check naming its actor and summary, a cached verdict's [cached] prefix verbatim), and takeover record, headed by the current lease holder with heartbeat freshness and the client-derived summary (card age, rework count; durations quietly disappear when a hand-written timestamp does not parse). A timeline agent whose session the client list knows renders as a backlink that switches to that session; a vanished session stays plain text. The detail fetches per open through the aggregated detail read (card + entries + holder in one round trip), refreshes with the board on every change frame, closes on a session switch (its card belongs to the old workspace) or a failed fetch, and the back control returns to the list without collapsing the panel. The board arrives over the plugin's own read-face route, served by dsh-devflow-web on the same origin as the app and scoped to the currently selected session: every fetch POSTs that session's id (never a path) and the host resolves its workspace to the devflow root, so switching sessions switches boards. One module — the binding layer — knows the channel; the views, the pages, and the surface chooser take values. Liveness is the plugin's own too: a downlink socket to the host's /devflow/ws endpoint carries one frame per card creation or stage move, saying only that something moved. A dropped socket reopens after a delay that doubles from two seconds toward a thirty-second ceiling and resets on the next open, so one blip costs the floor while a host that stays down is not hammered. The board fetches at activation, on every open of that socket — the first and every reopen, because a board that was down has no way to know what it missed — on every real selection change, and on every frame, so a chat-created card appears without a refresh — into a plugin-owned observable snapshot bound through the hooks compartment, so the pill and the open panel always show one fetch's cards. A workspace without devflow (or a failed fetch) renders no control at all.
The plugin issues no mutations: card moves belong to the model-facing devflow tools and the intervention command plane, and human approvals ride the existing approval composer because the gates plugin routes them over ctx.approval.
Model Experience
None, as this package renders fetched board state for a human and touches no prompt, message, schema, stream, or tool result. The model's own view of the same cards stays with dsh-tool-devflow.
KV Cache effect
None; the package never assembles or sends provider requests.
Known Limitations and Deferred Work
- Rows are read-only by design — the PRD's three-plane split keeps semantic moves in the chat plane and interventions in
/devflow; the panel's only future affordance is answering pending approvals, which today surfaces through the approval composer instead. - Whole-board refetch per change frame — the board refetches completely on every frame; incremental frames wait for a board large enough to need them.
- The breakdown marker sees only
blockedchildren — the listing carries current stages, not history, so a child that was reworked back todevelopingis indistinguishable from one that arrived there normally; surfacing rework on the parent row would need each child's journal. - Collapse state is per mount — folding a requirement away is a view preference of the open panel, not a stored one, so it resets when the panel remounts.
- A page of a non-selected session holds a stale badge — frames refresh the selected session and whatever a visible page watches; a page pinned to another session that is neither visible nor selected keeps reporting its last count until it is shown again.
- The sidebar surface is verified against a stub — the foundation is an ecosystem plugin outside this workspace and cannot be booted in the test lanes, so registration, mutual exclusion, and the fetch gating are proven against a stubbed service and the page's rendering in jsdom; the real sidebar is checked by hand.