Skip to content
dsh.fish
Bundle

dsh-session-handoff

Hand your long session over to a fresh one: /handoff summarizes the recent conversation with an LLM, creates a clean new session in the same workspace, injects the summary as its first message, and auto-opens it. The origin session is unchanged.

Source
WeiYe6
stars
4 stars
License
MIT
Updated
Updated 8 hours ago

Readme

# dsh-session-handoff

[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-green.svg)](package.json)
[![dsh](https://img.shields.io/badge/dsh-rc.5%E2%80%93rc.8%20%7C%200.1.1--rc.2-8a2be2.svg)](https://github.com/deepseek-ai/deepseek-harness)

English | [中文](README.zh-CN.md)

**Hand your long DSH session over to a clean one.** `/handoff` summarizes the recent
conversation with an LLM, creates a **brand-new session + agent** in the same workspace
(no history copied), injects a structured handoff document as its first message, and
**auto-opens** it — the model continues from the summary instead of replaying the whole
old history. The origin session is untouched.

## Features

- **One command** — `/handoff [<N>|all]` (defaults to the last 8 user messages; `all`
  covers everything)
- **Clean handoff** — a fresh session with the origin's workspace, model route, and
  agent preset (system prompt / tools / skills), no context bloat
- **Structured summary** — 任务目标 / 当前进度 / 关键决策 / 涉及文件 / 下一步 / 遗留问题
- **Auto-open** — the client half waits for the new session to be ready and navigates
  to it (each child auto-opens once; history replay never re-jumps)
- **Robust by default** — summaries run with thinking off (fast, cheap), oversized
  excerpts keep the newest messages instead of erroring, and finish reasons
  (`max-tokens` / `error` / `aborted`) are translated into actionable errors
- **Zero core changes** — a single `dsh.bundle.patch` row; only public services are used

## Install

```sh
# 1. Build the bundle from source (or grab a release tarball)
npm install && npm run build && npm pack     # → dsh-session-handoff-0.2.1.tgz

# 2. Install into your web profile
dsh plugin --profile web add ./dsh-session-handoff-0.2.1.tgz

# 3. Restart and verify the row is mounted
dsh web
dsh --profile web --dump-config | grep handoff
# expected: # == dsh-session-handoff / - id: handoff / - name: dsh-session-handoff
```

> Dev-time source link (`dsh plugin --profile web add D:/path/to/dsh-session-handoff`) requires
> the source dir's `node_modules` to resolve `@deepseek-ai/*` peers; prefer the tarball.

## Usage

Type in any conversation's input box:

```text
/handoff          # summarize the last 8 user messages (default)
/handoff 20       # summarize the last 20 (same as turns=20)
/handoff all      # summarize every user message (same as turns=all)
```

What happens:

1. A command card shows "summarizing…";
2. An LLM produces the handoff document (goal / progress / decisions / files / next
   steps / open questions), which becomes the new session's first message;
3. The new session **auto-opens**; the origin session stays intact and is linked back.

> ⚠️ **Privacy**: the recent conversation text (user + assistant messages in the
> requested window) is sent to the configured model to produce the summary.

## Configuration

```yaml
- id: handoff
  name: dsh-session-handoff
  config:
    turns: 8            # user-message rounds to extract (1–50)
    maxInputChars: 24000  # byte cap for the summary input (oldest dropped first)
    maxTokens: 2000     # summary output budget
    reasoningEffort: off  # off (default, fast/cheap) | high | max | inherit
    timeoutMs: 120000   # summary call timeout
    # provider: deepseek-official   # optional fixed model route
    # model: deepseek-v4-flash      # must be paired with provider
```

Without `provider`/`model`, the current session's latest logged model route
(`session.requestHeader()`) is used.

## How it works

- **Host half** (`index.mjs`, plain ESM): public services only — `commands`
  (`/handoff`), `llm` (`ctx.llm.stream`, following official `session-title-llm`),
  `agents` (`ctx.agents.create` — session **and** agent together, inheriting the
  origin's cwd / model route / agent preset via `agentPresets.mount`), plus
  `workspaceRegistry.attachSession` (same-workspace grouping) and
  `sessionTitle.rename` (a `handoff: <source>` title).
- **Client half** (`src/client/`, tsdown → `lib/client.js`): a `handoff`
  conversation node matches the `/handoff` success event and auto-opens the child
  session (polling until it is addressable, deduped via localStorage).

## Development

```sh
npm install        # devDeps: tsdown / typescript / @types/react / vitest / jsdom ...
npm test           # 22 tests: 17 host+client pure functions + 5 client component
npm run typecheck
npm run build      # tsdown → lib/client.js (CJS factory, official client-module format)
npm pack           # prepack runs typecheck + build automatically
```

Publish checklist: add the `dsh-plugin` GitHub topic → open a PR to
[awesome-deepseek-harness](https://github.com/0xsline/awesome-deepseek-harness) →
optionally `npm publish`.

## Known limitations

- The handoff document lives in the session only; it is not written to disk
  (`HANDOFF.md` is a future enhancement).
- Supports the DSH `0.1.0-rc.5` through `rc.8` line and `0.1.1-rc.2`.
  DSH `0.1.2-alpha.1` is intentionally excluded because its conversation UI/service
  split requires a separate client-side migration.
- The auto-open path has jsdom component coverage, but real browser timing still
  needs end-to-end verification.

## License

[MIT](./LICENSE)

Install

dsh plugin --profile web add github:WeiYe6/dsh-session-handoff

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source