Bundle
@zljr/dsh-share
Session share plugin for DeepSeek Harness: generate a read-only LAN share link (frozen transcript snapshot) for the current session.
- Source
- zljr
- stars
- 3 stars
- License
- MIT
- Updated
- Updated 4 days ago
Readme
<div align="center">
# dsh-share
**Share a DeepSeek Harness session over your LAN as a read-only, token-guarded snapshot.**
[π δΈζζζ‘£](./README_CN.md)
</div>
`dsh-share` is a [DeepSeek Harness](https://github.com/deepseek-ai/DeepSeek-Harness) plugin that adds a **Share** button to the session header. One click freezes the current conversation into a self-contained, read-only HTML page and prints a LAN URL β e.g. `http://192.168.1.20:3081/s/<token>` β that any device on the same network can open in a browser.
The main harness keeps listening on `127.0.0.1` (and so never exposes the agent's command execution). Sharing is served by a **separate, read-only HTTP server** that only ever returns a pre-rendered snapshot page for a valid token.
## Features
- π **One-click share** β a **Share** button in the session header (beside the official "Session log" action).
- π **Read-only & isolated** β the share server binds `0.0.0.0:<port>` on its own; it exposes nothing but `GET /s/<token>`. No RPC, no writes, no session reads on view.
- π§ **Frozen snapshot** β the transcript *and* session stats are captured at share time; later edits or compactions never change an already-shared page.
- π **Revocable + optional expiry** β 128-bit random tokens; stop sharing anytime, or pick a 1h / 24h / 7d expiry.
- π **Markdown transcript** β user & assistant messages are Markdown-rendered (safe: raw HTML is escaped, `javascript:` URLs are blocked).
- πͺ **Readable** β long messages auto-fold behind a preview; consecutive tool calls collapse into one "π tool calls" group.
- π **Session stats header** β turns, steps, wall-clock duration, tool-call time, cache hits, input/output tokens, and current context occupancy with a per-category composition bar.
- π **Dark & light theme** β the share page follows `prefers-color-scheme`.
- πΎ **Persists across restarts** β shares are stored in `~/.dsh/dsh-share.json`.
- π‘ **Smart LAN address** β filters out virtual adapters (WSL / Hyper-V / Docker / VPN / β¦) and probes the default route so the phone-reachable IP is listed first.
## How it works
`dsh-share` is a dual-face `dsh` package, like other harness plugins:
| Half | Runs in | Role |
|------|---------|------|
| Host (`src/host`) | Node (harness process) | Folds the session event log into a transcript + stats, stores the frozen snapshot, and serves it over a separate `node:http` server at `/s/<token>`. Also exposes a `/dsh-share` RPC (`create` / `revoke` / `list`). |
| Client (`src/client`) | Browser | Registers the **Share** button in `conversation.session.header.utilities` and renders the dialog (expiry picker, copy / revoke / open). |
Token estimation for the context composition reuses the harness's own fixed-density heuristic (~4 chars β 1 token), matching [`dsh-context`](https://github.com/bowenliang123/dsh-context).
## Install
### From npm
```sh
dsh plugin --profile web add @zljr/dsh-share
dsh --profile web
```
That's it β the published package ships the built `lib/`, so end users never need a build step.
### From source (local development)
```sh
# 1. Build the package artifacts (lib/)
pnpm install
pnpm build
# 2. Install into the web profile (local path)
dsh plugin --profile web add /absolute/path/to/dsh-share
# 3. Restart the web UI
dsh --profile web
```
Open any session and click **Share** in the header. The share server starts lazily on first use.
## Configuration
Environment variables (or a config object supplied via `cordis.patch.yml`):
| Variable | Default | Description |
|----------|---------|-------------|
| `DSH_SHARE_HOST` | `0.0.0.0` | Bind address of the read-only share server. |
| `DSH_SHARE_PORT` | `3081` | Port of the share server. |
> On Windows, the first `0.0.0.0` listen may trigger a firewall prompt β allow it so other devices can reach the link.
## Security model
- The **main harness stays loopback-only**; only the read-only share surface is reachable from the LAN.
- Share tokens are **128-bit random** (unguessable) and can be **revoked** or set to **expire**.
- The share page contains **no JavaScript** and **no external assets**; message text is Markdown-rendered with raw HTML escaped and dangerous URLs rejected.
- The snapshot is **frozen** β it is not a live view of the session, and it is never re-read from the session store after creation.
## Development
```sh
pnpm install # dev dependencies (typescript, esbuild, react, jsdom, β¦)
pnpm build # bundle host (lib/index.js) + client (lib/client.js)
pnpm test # typecheck + host/client functional tests
pnpm typecheck # tsc --noEmit only
```
### Project structure
```
src/
shared/ # wire contract shared by both halves (type-only)
host/
index.ts # /dsh-share RPC + lazy share-server lifecycle
server.ts # read-only HTTP server + LAN address selection
store.ts # token β snapshot registry (persisted JSON)
transcript.ts # event log β human transcript
stats.ts # event log β session statistics
pricing.ts # token estimation heuristic
markdown.ts # safe Markdown rendering
html.ts # snapshot page rendering
client/
index.ts # header button registration
components/ # ShareButton + dialog
scripts/build.mjs # esbuild build (host ESM + client __ModuleLoader__ bundle)
tests/ # host/client functional tests (jsdom + real React)
```
## Publishing
```sh
npm login --registry=https://registry.npmjs.org
npm publish --registry=https://registry.npmjs.org
```
The `prepublishOnly` script rebuilds `lib/` before every publish, so the tarball always carries a fresh host + client bundle.
## License
[MIT](./LICENSE)
Install
dsh plugin --profile web add github:zljr/dsh-share
Profile: web
With the hub plugin installed, ask your agent to install it by name β it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install zljr-dsh-share from the hub
- 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.