xiaozhiaixue
dsh-archive-panel
View and unarchive archived sessions in DeepSeek Harness (DSH)
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 17, 2026
- Updated
- Aug 17, 2026
Introduction
dsh-archive-panel
View and unarchive archived sessions in DeepSeek Harness (DSH).
中文 | English
Why
DSH ships archiving but no unarchiving: workspaceRegistry.archiveSession(id) hides a session from every UI surface, while the official README admits "sessions can be archived, but archived sessions have no viewing or unarchive surface." The host design even reserved the semantics — "a future unarchive restores its position" — but never implemented it.
This plugin completes the loop:
- Host: an
unarchiveSessioninstance patch on the workspace registry that mirrors the shippedarchiveSessionwrite path (enqueueOperation → requireState → setState), so persistence, in-memory state, and thehost/archived-sessions-changedpush all stay consistent — a restored session reappears in the official sidebar at its original workspace position immediately. - Browser: a sidebar-footer entry (with a live count badge) opening a left drawer that lists every archived session and offers single / batch / restore-all actions, plus search and click-to-copy session IDs.
Features
- 📂 List all archived sessions: title, workspace, last activity,
cwd, session ID, recent-message preview - ♻️ Restore one, a selected batch, or all archived sessions
- 🔍 Instant client-side search over title / ID / path / workspace / preview
- 🔗 Click session ID to copy
- 🔢 Reactive count badge in the sidebar (updates as sessions are archived/restored)
- 🔒 Host endpoints guarded by a per-process random token injected into the index page
Install
A standard DSH profile bundle (the official external-plugin distribution path per docs/user/develop/basic/publish.md): the package declares
dsh.bundle.patch,dsh plugininstalls it, and the profile composes itscordis.patch.ymllayer. No build step — this package ships plain JS, so git installs need neither apreparescript nor anallowBuildsentry.
Option A — official dsh plugin (recommended)
# From a directory that contains this checkout:
dsh plugin --profile web add ./dsh-archive-panel
# or straight from GitHub (plain JS, no build permission needed):
# dsh plugin --profile web add github:realpkuasule/dsh-archive-panel
# Verify the composed layer without booting:
dsh --profile web --dump-config | grep -A2 dsh-archive-panel
dsh plugin links the package, records it in the profile's dependencies, and appends dsh-archive-panel to dsh.profile.bundles.
Option B — manual (no CLI)
# 1. Copy the package into your profile's node_modules
DSH_HOME="${DSH_HOME:-$HOME/.dsh}"
mkdir -p "$DSH_HOME/profiles/node_modules/dsh-archive-panel"
cp -R plugins/dsh-archive-panel/. "$DSH_HOME/profiles/node_modules/dsh-archive-panel/"
# (mirror the structure of dsh-session-id-footer in the same directory)
# 2. Add the bundle layer to $DSH_HOME/profiles/web/cordis.patch.yml
# (an `- insert:` list entry — same shape as the bundle's own patch file)
- id: dsh-archive-panel
name: dsh-archive-panel
# 3. Restart `dsh web`
Open the GUI: the sidebar footer now shows 已归档 (N) beside Settings. Click it to open the drawer.
Architecture
Browser (client.js, __ModuleLoader__ bundle)
├─ sidebar.footer.action entry ──▶ shell.overlay drawer
│ • useWorkspaces/useSessions store hooks → reactive list + count
│ • fetch → POST /archived/unarchive | /archived/preview
└─ x-archived-token header (window.__DSH_ARCHIVED_TOKEN__ injected by host)
Node (index.js, profile Cordis plugin)
├─ instance patch: registry.unarchiveSession(id)
│ same enqueue/requireState/setState path as shipped archiveSession
├─ POST /archived/unarchive → per-id idempotent removal
├─ POST /archived/preview → sessionQuery.filterEvents tail → 120-char preview
└─ apiProxy poller pushes host/archived-sessions-changed → official UI refreshes
- Listing data comes from the client stores (
useSessions/useWorkspaces), which already contain archived sessions — only the message preview needs a host read. - Unarchive goes through the registry's own serialized write queue, so the official sidebar updates with zero extra sync code.
- The token guard (random per process, injected via
tapIndex) keeps the HTTP endpoints callable only from pages served by this process.
Repository layout
dsh-archive-panel/
├── README.md # English
├── README.zh.md # 中文
├── DESIGN.md # full design doc: research, decisions, risks, verification
├── LICENSE # MIT
└── plugins/
└── dsh-archive-panel/
├── package.json # dsh.bundle.patch + dsh.client.platform: web declarations
├── cordis.patch.yml # the bundle's patch layer (inserts the plugin row)
└── lib/
├── index.js # host half
└── client.js # browser half (__ModuleLoader__ bundle)
License
MIT