DeepSeek Harness plugin

dsh-new-session-cards

DSH Web client plugin: card-based new-session configuration wizard (immersive step guide) to prevent silent default configurations

Jump to install

Source facts

Repository
supergameboy/dsh-new-session-cards
Latest update
Aug 16, 2026
Category
Memory
GitHub stars
0
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/supergameboy/dsh-new-session-cards
Plugin: dsh-new-session-cards
Author: supergameboy

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer3 files
README.en.mdSource · read only
README language

dsh-new-session-cards

中文 | English

A standalone plugin that turns the new-session screen of DSH (DeepSeek Harness) Web GUI into a four-step card wizard — so you can never silently start a task with the default task mode or model.

Zero modification to DSH itself: ships as an independent bundle — dsh plugin add to install, remove to uninstall.

---

Why DSH is fun

The whole DSH product is a tree of Cordis plugins — there is no core to "operate on"; everything can be replaced from the outside:

  • Composer takeover chain: the new-session input area is a selector-routed chain. Any plugin can take it over — turning it into a full-screen UI (that is exactly what this plugin does) — and then step aside so the original input bar comes back automatically.
  • Slot system: sidebar, settings pages, session headers, message rows… all expose injectable slots. Plugins snap onto them like building blocks.
  • Theme tokens: the --dsw-alias-* semantic palette — plugin styles use zero literal colors and adapt to light/dark automatically.
  • Bundle distribution: two manifests (dsh.bundle + dsh.client), installable from a local directory, a tarball, or directly from GitHub.
  • Plugin is code: a client plugin is plain JS/TSX bundled into a browser bundle, loaded under the exact same contract as the built-in plugins.

You do not need to fork DSH to deeply reshape its UI. This plugin is a complete worked example: take over → configure → step aside.

What this plugin does

The original new-session screen (workspace chip, agent-preset chip, small model selector in the corner of the input card) all fall back to deployment defaults silently, so users easily skip configuration and send. This plugin replaces the new-session screen with:

1. Step 1 — Task mode: agent-preset card grid (single-select); the default preset carries a «默认/Default» badge 2. Step 2 — Model: model card grid (single-select, provider tag); the default model carries a «默认/Default» badge 3. Step 3 — Other settings: workspace (full width) + access mode / plan mode (side by side) 4. Step 4 — Message: after «确认配置并开始/Confirm and start», an in-wizard message composer — input box + Send + the "/" command menu, running on the exact same input machine and command pipeline as the standard input bar. Sending the first message lets the wizard step aside naturally and enter the conversation.

Confirming itself never sends a message. No configuration is ever used without your knowledge.

You can return to the original hero at any time: the «使用标准输入框/Use the standard input bar» link inside the wizard, or Settings → General → New-session configuration wizard toggle (preference stored in browser localStorage).

Install

# Prerequisite: DSH CLI installed with an initialized profile (e.g. web)
dsh plugin --profile web add github:supergameboy/dsh-new-session-cards

A GitHub install fetches sources, and pnpm ≥10 requires explicitly allowing build scripts (only allow sources you trust):

# <profile dir>/pnpm-workspace.yaml
allowBuilds:
  dsh-new-session-cards: true

Then re-run add (the prepare script builds lib/ automatically). Local directory or tarball installs need no build allowance:

dsh plugin --profile web add ./dsh-new-session-cards            # local dir (run pnpm build first)
dsh plugin --profile web add ./dsh-new-session-cards-0.1.0.tgz

Verify and enable:

dsh --profile web --dump-config   # should show a "# == dsh-new-session-cards" layer
dsh --profile web                 # open a new session screen to see the wizard

> Already installed and changed the code? The profile links the checkout, so a browser refresh is enough — the server reads the latest bundle file on every request; no service restart needed.

Uninstall:

dsh plugin --profile web remove dsh-new-session-cards

Build from source

pnpm install
pnpm build          # tsdown: lib/index.js (node half) + lib/client.js (browser bundle)
pnpm typecheck      # requires the DSH source tree at ../deepseek-harness (see pitfall #1)

---

Pitfalls (for DSH plugin authors)

Real pitfalls hit while developing this plugin, recorded as "pitfall → symptom → fix". Read this first if you want to get productive quickly with DSH client plugins.

1. The @deepseek-ai/* dependency graph on npm is incomplete

  • Pitfall: the rc versions of @deepseek-ai/* on the npm registry have missing transitive dependencies (e.g. dsh-user-interaction is unpublished) — pnpm install 404s.
  • Fix: declare no @deepseek-ai dependency in package.json. Runtime needs none — the client bundle's externals (react, dsh-client-runtime/client, and the other platform modules) resolve from the shell's module table and everything else is inlined; the build needs none either (import type is erased). Type-checking resolves them through tsconfig paths pointing at the DSH source tree's build output (../deepseek-harness/packages/*/*/lib/types).

2. --dsw-alias-brand-primary is ink, not brand blue

  • Pitfall: brand-primary resolves to neutral-bluish-1000 (near-black ink). Using it as a button background with label-primary (also ink) as text → ink on ink — button text completely invisible.
  • Fix: use --dsw-alias-state-business-primary (the DeepSeek brand blue) for emphasis/selection — the InputBar source itself comments: "Business blue, not brand-primary: that token resolves to ink in this sheet"; for primary buttons use --dsw-alias-button-primary-fill background + --dsw-alias-label-primary-foreground (white) text — better yet, just reuse the Button component from ui-primitives.

3. Data loading is not automatic

  • Pitfall: an injected load callback is only defined — nothing ever calls it, so cards stay on skeletons forever (no text) and the Next button stays disabled (it depends on status === 'ready') — the user is stuck in the wizard.
  • Fix: call load() on mount: useEffect(() => { load() }, [load]) (copy the shipped ModelSelect pattern).

4. Under a composer takeover, the fallback input bar is hidden, not unmounted

  • Pitfall: conversation.composer.bar keeps its DOM and is only CSS-hidden during a takeover (the textarea is always "in" the DOM). Everything anchored to it hides with it: the conversation.input.overlay slot (command menu MenuView, popupSelect shell) anchors inside the hidden InputBar and is not portaled.
  • Fix: render your own "/" command menu in the takeover UI — but reuse the pipeline: sessions.scope(sessionId) gets the session scope, inputTriggers.sessionOf(actx) gets the per-session controller (menu store / track / arbitrate / pick), and the menu UI renders from the menu store.

5. Chain re-routing needs a "change" to trigger

  • Pitfall: chain selectors are pure (owner props only). After confirmation the state changed but the owner props did not → no re-route → the wizard never leaves.
  • Fix: make ConversationRoot re-render. Two working triggers: (a) conversation.blocks.set(sessionId, undefined) (the root subscribes to block changes); (b) after sending the first message, composerPhase flips from blank to active (what this plugin finally uses: Step4 send naturally steps aside, no manual flip needed).

6. Locale namespaces need declaration merging

  • Pitfall: ctx.locale.register(NS, ...) is typed N extends keyof LocaleNamespaceMap — a custom NS fails to compile.
  • Fix: in the plugin, declare module '@deepseek-ai/dsh-client-ui-slots' { interface LocaleNamespaceMap { myNs: MyKeyUnion } }. In components use PropsLocale<typeof NS> (NS is a value — needs typeof).

7. RpcResult discriminant narrowing dies inside immer callbacks

  • Pitfall: response.result.ok narrowing fails inside store.update((draft) => { ... response.result.error.message }) (TS does not propagate narrowing into the mutator callback) → "Property 'error' does not exist".
  • Fix: extract to a local first: const message = response.result.error.message, use message in the callback.

8. A client-only plugin cannot register a host settings namespace

  • Pitfall: settings persistence goes through settingsScope.bind(), but namespaces are registered host-side (needs host plugin code); a client-only plugin's namespace is always unavailable.
  • Fix: store the preference in browser localStorage (e.g. dsh-new-session-cards:useWizard), wrapped in a createSnapshotStore reactive mirror; the settings row (settings.general.item) reads/writes it — the UI is identical to the built-in settings rows.

9. Build-configuration nitpicks (tsdown / tsc)

  • CSS Modules virtual ids must resolve absolute paths from the importer (resolve(dirname(importer), source)), otherwise ENOENT.
  • The node half needs fixedExtension: false, otherwise it emits index.mjs while package.json exports point at .js.
  • tsconfig paths wildcards allow only **one * per pattern** (packages/*/*/lib/types won't work — expand per group).
  • Type-checking against the DSH source tree needs: allowImportingTsExtensions, lib: ["ES2023"] (source uses findLast), types: ["node"], and a CSS Modules declaration file (src/css-modules.d.ts).
  • Installing @deepseek-ai/cordis from npm (4.x exists) is not required: cordis types are resolved from vendor/cordis via paths as well.

10. Distribution-chain pitfalls

  • GitHub installs are source installs: you need a prepare script (runs after pnpm ≥10's allowBuilds) that builds self-contained — no monorepo sibling context may be assumed.
  • The dsh.client manifest's exports["./client"] must point at a real bundle file (clientModules validates at boot; a miss fails the plugin).
  • Profile bundle order = configuration layer order: when several plugins are installed, later layers override same-id rows from earlier ones.

---

How it works (30 seconds)

flowchart LR
    A[New-session hero] -->|conversation.composer takeover chain| B[Four-step wizard]
    B -->|Confirm| C[Step 4 Message]
    C -->|Send first message| D[Conversation]
    D -->|New session| A
  • Takeover: registers a conversation.composer chain entry; the selector matches only "blank session + preference on + not confirmed"; sending flips blank → active and the chain steps aside automatically
  • Data: presets via agentPresets.list/select RPC; models via the modelDirectories service; workspace/sessions via the standard stores; the command menu reuses the inputTriggers pipeline
  • Styling: all --dsw-alias-* tokens, CSS Modules, WCAG 2.1 AA, prefers-reduced-motion fallbacks, zh/en copy
  • Preference: localStorage (useWizard toggle), one row in Settings → General

Design docs

[docs/design/](docs/design/) holds the full fractal UI design documents (L0 decision chain → page → component library → style spec, two rounds of independent validation passed).

License

MIT