kylernunan/dsh-split-session ↗★ 0

dsh-split-session

Quad-pane split session view for the DeepSeek Harness Web GUI: up to four live Conversations, launch by default, drag Sessions in from the sidebar.

패키지
dsh-split-session
호환성
미검증
버전
0.3.1
라이선스
MIT
최근 업데이트
2026. 10. 28.

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add https://github.com/kylernunan/dsh-split-session/releases/download/v0.3.1/dsh-split-session-0.3.1.tgz

dsh-split-session

A DeepSeek Harness Web plugin that turns the main window into a quad session view: up to four live Conversations in one window, each pane running a native embedded Conversation (not an iframe, not a copied transcript). It opens by default at launch, and Sessions can be dragged in from the sidebar.

┌─ Split view ─────────────────────── +  Swap  Stack  ✕ ─┐
│ [Session A ▾]           │ [Session B ▾]                  │
│                         │                                │
│   live conversation A   │   live conversation B          │
│                         │                                │
├─────────────────────────┼────────────────────────────────┤
│ [Session C ▾]           │ [Session D ▾]                  │
│                         │                                │
│   live conversation C   │   live conversation D          │
│                         │                                │
└─────────────────────────┴────────────────────────────────┘

Features

  • 2 to 4 panes, one window. Add panes up to a 2×2 quad; close any pane back down to two. Layouts: side-by-side, stacked, two-over-one, quad.
  • Native Conversations. Each pane binds its own Session reference through the standard SessionProvider seat and renders the Conversation package's public conversation.content Factory in its embedded variant. Streaming, the composer, slash commands, approvals, queued turns, todos, and plugin views all work per pane.
  • Fuzzy drag targets. Drag any Session row onto the panel: every pane shows its half/quarter label, the zone under the pointer lights up, and a wide dead band along both dividers keeps the target from flickering. Dropping one pane's Session on another swaps them.
  • Launch by default. The panel is the main view at page launch, and the current workspace group is expanded in the sidebar so rows are ready to drag.
  • Resize both axes. Drag the column and row dividers, use the arrow keys on a focused divider, Home/double-click to reset one axis.
  • Per-pane picker. Click a pane title to switch that pane, with running spinners and the other panes' Sessions excluded.
  • Persists. Pane list, both axis ratios, and the two-pane orientation live in localStorage; the layout survives reloads.
  • Focus-safe. Opening or switching a pane does not yank the keyboard into its composer.
  • Dark/light and English/Chinese through the host's theme and locale.

Install

From GitHub (the checkout ships the built client bundle, so no build step runs):

dsh plugin --profile desktop add github:kylernunan/dsh-split-session

From the prebuilt release tarball:

dsh plugin --profile desktop add https://github.com/kylernunan/dsh-split-session/releases/download/v0.3.1/dsh-split-session-0.3.1.tgz

From a local checkout:

dsh plugin --profile desktop add /path/to/dsh-split-session

From npm, once published:

dsh plugin --profile desktop add dsh-split-session

Then reload the page (or restart the app). Toggle it later under Plugins → Installed plugins → Split session view.

Remove it with:

dsh plugin --profile desktop remove dsh-split-session

Use

  • Add a pane: the grid + button in the panel header, up to four panes.
  • Close a pane: the ✕ in a pane's title row (available while more than two panes are open).
  • Switch a pane: click its title; the picker lists top-level Sessions by recent activity.
  • Drag a Session in: drag a row from the sidebar onto any pane. Each pane labels its half or quarter and highlights under the pointer; drag a pane's Session onto another pane to swap them.
  • Add by dropping: while fewer than four panes are open, move the drag onto the panel header — it becomes a Drop to add a pane lane — and release to add the dragged Session as a new pane. Repeat to build the quad, then drop Sessions into the labeled quarters.
  • Resize: drag a divider, focus it and use the arrow keys (±2%), press Home or double-click to reset that axis.
  • Side-by-side / stacked: for two panes, the panel header toggles the axis.
  • Swap: exchange the two panes (two-pane layouts).
  • Close the view: the header ✕ returns to the Conversation without changing the selected Session.

The layout persists per browser in localStorage under dsh.split-session.v2 (the two-pane v1 layout migrates automatically).

To start on the Conversation instead of the split view:

localStorage.setItem('dsh.split-session.open-on-launch', 'false')

Remove that key to restore the launch behavior.

How it composes

The package has no Host behavior. Its browser half:

  1. registers a main panel keyed split plus the sidebar.panellist entry;
  2. declares one session-scoped child slot, split.pane ({ kind: 'single', scope: 'session' }), whose occupant renders the shared Conversation under that pane's Session binding;
  3. retains a Session reference per pane through the Session Controller and binds it with the standard SessionProvider seat;
  4. renders conversation.content in its embedded variant with the same phase rules as the main Conversation;
  5. lays the panes out on one CSS grid with two ratiometric dividers.

It never imports another feature plugin's values: the Conversation arrives through a Factory, Session state through standard seats, and Session retention through the sessions service. It requests no non-baseline modules — React and @deepseek-ai/dsh-client-ui-primitives come from the shell's shared module table — so the package needs no dsh.client.external declaration.

Launching selects the panel once per page lifetime (the tag is the page's performance.timeOrigin, so a browser reload re-opens it and a bundle reload does not), then expands the current workspace group that the sidebar's own Conversation-only effect would otherwise have expanded. Drag-and-drop rides the sidebar's own draggable rows: the panel listens for dragstart on [data-row-key^="session:"], tracks the pointer over its own surface, and assigns the nearest pane — it never modifies the sidebar's rows or order.

Alternatives

The split-view space already has capable plugins; this one is deliberately smaller and native-rendered:

PluginShape
mhlywxl/dsh-split-workspaceUnlimited native panes, side-by-side, stacked, 2×2 and automatic grids. Closest overlap.
dsh-split-screenNative panes, drag-to-edge splitting, many panes, always-on workspace.
dsh-split-viewNested splits, one full DSH client per iframe, hibernation, settings.
@syncended/dsh-split-screeniTerm-style multiplexer, nested splits, tabs, up to 12 panes.
yuloop/dsh-web-splitDraggable panes with unread dots and per-browser layout.
dsh-split-sessionQuad cap, native embedded Conversations, launch-default, sidebar drag, zero external peers.

Files

FileRole
package.jsonBundle + dsh.client manifest, display metadata, icon.
cordis.patch.ymlThe bundle layer that inserts the plugin row.
lib/index.jsInert Host half; the feature is browser-only.
lib/client.jsBrowser bundle: panel, pane host, pickers, grid, styles, copy.
locale/en.json, locale/zh.jsonPlugin Manager title and description.
scripts/smoke.mjsLoads the browser bundle against stubs and checks its plugin face.

lib/client.js is plain browser JavaScript in the Web module-loader factory form, so the package ships ready to load with no client build step. Check that face without a shell with npm run smoke.

Limits

  • Four panes is the cap, and panes form one flat grid: no nested splits and no tabs inside a pane.
  • The picker lists top-level Sessions; subagent conversations are reached through their parent.
  • Blank and archived sidebar rows are not draggable by the sidebar (use the pane picker).
  • Clicking a Session row (without dragging) returns to the Conversation and leaves the split panel; use the pane titles or drag the row while split.
  • The right sidebar docks with the Conversation, so it is hidden while the split panel is selected.
  • One Session cannot occupy two panes; each picker excludes the other panes' Sessions and a drop on an occupied pane swaps them.
  • The plugin adds no model-facing input and no Session events.

License

MIT