dsh-plugin-archive-manager
piaohua/dsh-plugin-archive-manager
(DSH) Web plugin that makes session archiving reversible and visible
설치
dsh plugin --profile web add github:piaohua/dsh-plugin-archive-managerREADME
dsh-plugin-archive-manager
A DeepSeek Harness (DSH) Web plugin that makes session archiving reversible and visible:
- View archived sessions in place — archived sessions reappear in the workspace list at their original position (workspace accounting slots are preserved by DSH), with their titles dimmed compared to unarchived ones.
- Filter group in the view options — the workspace view options menu gains a Filter group with two independently checkable items: Archived and Not archived (default: Not archived checked). Check Archived to see archived sessions; uncheck Not archived to see archived sessions only.
- Unarchive from the row menu — for an archived session the row action becomes Unarchive (with a dedicated unarchive icon) instead of Archive session; clicking it restores the session durably.
中文说明见 README.zh.md。
Why this exists
DSH already archives sessions (they disappear from every grouping surface), but the shipped UI has no way to view or unarchive archived sessions — the official dsh-client-ui-workspace README states: "sessions can be archived, but archived sessions have no viewing or unarchive surface." The underlying data model was built for unarchiving (an archived session keeps its workspace accounting slot; the registry comment says "unarchiving restores its position"), but no API or UI exists.
This plugin fills that gap.
How it works
Two halves, one npm package:
| Half | File | What it does |
|---|---|---|
| Host (node) | lib/index.js | Patches ctx.workspaceRegistry with the missing unarchiveSession(sessionId) (mirrors the official archiveSession: idempotent, durable, same domain/changed → host/archived-sessions-changed broadcast chain), and registers an exact HTTP route POST /api/dsh-archive-manager/unarchive for the browser half. |
| Browser (web) | lib/client.js | Shadows the sidebar.workspaces slot (priority -1 vs the official 0; lowest priority renders — a framework-supported mechanism) with a faithful re-implementation of the workspace browsing region: section header + view options, search, grouped/flat lists, drag reorder, rename/fork/archive dialogs, workspace rename/delete — plus the Filter group, dimmed archived titles, and the Unarchive row action. |
The unarchive data flow
- Click Unarchive on an archived session row.
- The browser half
fetchesPOST /api/dsh-archive-manager/unarchive(same origin) with{ sessionId }and the required custom headerx-dsh-archive-manager: 1. - The host route calls the patched
unarchiveSession, which writes the durable registry state (removing the id from the global archive set) through the samesetStatepath the official archive uses. - The registry write emits
domain/changed; the host API proxy diffs the archive set and broadcastshost/archived-sessions-changedto every connected client (including other tabs). - The client runtime updates
archivedSessionIds; the browsing region re-renders — the row un-dims, the menu swaps back to Archive session, and the filter rules apply immediately.
Because the mutation goes through the official persistence path, everything is durable across restarts and consistent across tabs — no custom RPC protocol, no event plumbing of our own.
Viewing an archived session's conversation
Stock DSH force-clears the conversation selection whenever the current session is archived (that is part of "archived sessions have no viewing surface"), so clicking an archived row would instantly bounce back to the empty New Session view. This plugin disables that rule (a small patch on the client WorkspaceRuntime.project() projection, removed again on uninstall), so clicking an archived session opens and reads its conversation normally. Behavior change that comes with it: archiving the current session no longer auto-returns the conversation to New Session — the session stays open and remains visible as a dimmed row.
Filter semantics
A session is visible when (archived && showArchived) || (!archived && showUnarchived). Defaults: showUnarchived: true, showArchived: false — identical to the stock behavior. Both can be checked at once (see everything); both unchecked shows an empty list. Filter state is persisted in the plugin's own localStorage key and survives reloads. Grouping/ordering preferences are migrated once from the official dsh.workspace.view.v5 key.
Install
The plugin targets DSH 0.1.0-rc.x (tested on 0.1.0-rc.6).
From GitHub (recommended)
npx @deepseek-ai/dsh plugin --profile web add github:piaohua/dsh-plugin-archive-manager
From npm (once published)
npx @deepseek-ai/dsh plugin --profile web add dsh-plugin-archive-manager
Then restart dsh web. The plugin is a profile bundle (it ships a cordis.patch.yml that inserts its loader row), so it is picked up by the normal dsh plugin reconcile flow.
To uninstall, run dsh plugin --profile web remove dsh-plugin-archive-manager and restart — the stock workspace browser returns exactly as before (shadowing is reversible by design).
Local development
# in this repository
npm run build # assemble lib/client.js from src/ (client bundle + embedded CSS)
npm run verify # pre-publish structural checks
node scripts/smoke.mjs # execute the bundle factory in a stubbed browser environment
# install the local checkout into your web profile (path specs are anchored to your cwd)
npx @deepseek-ai/dsh plugin --profile web add file:/absolute/path/to/dsh-plugin-archive-manager
Package layout
dsh-plugin-archive-manager/
├── package.json # dsh.bundle.patch + dsh.client declaration
├── cordis.patch.yml # composition patch: inserts this plugin's loader row
├── lib/
│ ├── index.js # Host half: registry unarchiveSession + exact HTTP route
│ └── client.js # Browser half: __ModuleLoader__ bundle (shadow browser + new UI)
├── scripts/
│ ├── build.mjs # assemble lib/client.js from src/
│ ├── verify.mjs # pre-publish checks
│ └── smoke.mjs # bundle factory smoke test
├── src/
│ ├── client.src.js # browser bundle source (CSS placeholder)
│ ├── rows.css # official row styles (re-tagged, self-contained)
│ ├── browser.css # official browser styles (re-tagged, self-contained)
│ ├── picker.css # official picker styles (re-tagged, self-contained)
│ └── extra.css # plugin-only styles (dimmed archived titles)
├── README.md # this file
├── README.zh.md # 中文说明
└── LICENSE # MIT
Publishing
The built artifacts (lib/) are committed, so the repository itself is installable via the GitHub route above. To also publish to the npm registry:
npm publish
Install from npm as shown above.
Known trade-offs & compatibility
- The browsing region is a faithful re-implementation, not the official component. DSH 0.1.0-rc.x exposes no extension slots inside the workspace browser (only the two directory-flow holes), so the only supported way to change its behavior is to shadow the slot. The implementation copies the official logic and styles (MIT, re-tagged CSS injected independently), so visuals and interactions match; but future DSH UI changes to the workspace browser will not automatically flow into this plugin — update the plugin to track DSH releases.
- "Add workspace" uses the host native directory picker (
pickDirectory) with a path-input dialog fallback, instead of the official directory-flow hole (which is declared by the shadowed entry and therefore cannot be rendered by this plugin). The conversation empty-state picker is unaffected. - The row menu keeps Rename / Fork for archived sessions (both remain valid on archived sessions).
- Removing the plugin restores the stock browser; the plugin's filter state lives in its own
localStoragekey and leaves no residue.
License
MIT