DeepSeek Harness Plugin

Choi-Peng/dsh-footer-order

Stars ★ 1 Downloads (30d) 453 Category UI Enhancements Added 2026-08-19 npm @choi-p/dsh-footer-order

DSH sidebar footer ordering: forces the sidebar.footer.action slot into a vertical stack and lets users configure the top-to-bottom order of its entries.

Install

# from npm (prebuilt)

dsh plugin --profile web add @choi-p/dsh-footer-order

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:Choi-Peng/dsh-footer-order

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

A DeepSeek Harness web plugin that fixes the sidebar footer (sidebar.footer.action slot) squeezing multiple plugin entries into one row, and lets you configure their top-to-bottom order.

[!NOTE] AI-generated disclaimer: this plugin was generated by AI; review the code and test it before use. Issues and PRs are welcome.

[!COMPAT] Version compatibility: the core features (vertical footer stacking, entry top-to-bottom ordering, and the settings-row settings repositioning) work on dsh ≥ 0.1.1-rc.2. The settingsArea internal arrangement (settingsLayout / settingsGap / settingsAlign / settingsOrder) depends on shell DOM details present from dsh 0.1.2-rc.1 (the settings button, the connection-status indicator, etc.) and does not work on dsh 0.1.1-rc.2 — on that version the group is silently skipped and the rest of the plugin keeps working. Upgrade to dsh ≥ 0.1.2-rc.1 to use it.

Problem

After installing several plugins, each registers content into the sidebar.footer.action slot. The slot anchor div[data-slot="sidebar.footer.action"] gets the inline style display: contents from the dsh web-react renderer, so every entry's root element participates directly in the parent's layout (.footerActions, display: flex, row direction) — multiple footer plugins end up crammed into one horizontal row.

This plugin injects an !important stylesheet rule that turns the anchor into a vertical flex stack (display: flex; flex-direction: column), so the entries are arranged top to bottom.

Features

  • Stacks sidebar.footer.action content vertically (display: contents → flex column), fixing the squeezed row.
  • Configurable top-to-bottom order: write the plugin-id list in the plugin row's config.order in cordis.patch.yml, or reorder with ↑/↓ in the Settings → Plugins → Sidebar Footer Order card.
  • The shell's Settings row (settingsArea / the sidebar.settings slot) joins the same order list under the reserved id settings — put it above, between, or below the footer entries; leave it out and it stays exactly where the shell renders it.
  • settingsArea internal arrangement (requires dsh ≥ 0.1.2-rc.1; see the compatibility note at the top — on dsh 0.1.1-rc.2 this group is silently skipped): settingsLayout (row / column / row-reverse / column-reverse / contents), settingsGap (px, default 8), settingsAlign (center / stretch / start / end), and settingsOrder (↑/↓ reorder of the items inside settingsArea, e.g. the settings button and the connection-status indicator).
  • Configurable layout (column / row / contents), gap (px between entries), and align (cross-axis alignment).
  • Tolerates entries that render nothing (e.g. the shell's dormant cordis-panel, which returns null unless a dynamic plugin run needs attention): those entries are skipped by the ordering instead of blocking it when "registered ids ≠ DOM nodes".
  • Live config reload — saving from the card (settings service hot-publishes) takes effect instantly without restarting dsh web; editing the bundle's cordis.patch.yml base config reloads the fiber via patch-layer HMR.
  • Registers no visible footer entry itself — it only does layout + ordering, and cleans up its style sheet and observers on unload.

Architecture

Side File Role
Host lib/index.js Serves /footer-order/settings — a thin proxy over the footer-order settings namespace: GET returns the resolved config + revision + override flag; POST saves (update) or resets (replace {}) through the official dsh settings seam (ctx.settings). The deploy-time patch config becomes the namespace's base layer; runtime edits land in the user layer above it
Client lib/client.js Injects the override stylesheet (anchor → vertical flex); watches the DOM and reorders the anchor's blocks (footer entries +, when listed, the settings row) per config; registers the editable Sidebar Footer Order card in Settings → Plugins

Ordering: every registered entry renders as exactly one child of the anchor (the renderer outputs entries sorted by order), but some entries may render nothing (e.g. cordis-panel, or readouts hidden in the collapsed rail). The client pairs each child with the entry id from ctx.slots.entriesOfSlot('sidebar.footer.action') through three layers: ① label text — a child whose text contains an entry's label (e.g. the "Restart DSH" button) is that entry; ② previously confirmed pairings; ③ a subsequence heuristic over the remaining children (config-order match first, then minimal rank shift). It then re-sorts the children to the configured sequence — so ordering keeps working even while a dormant null-rendering entry stays registered.

The settings row is found without touching the shell's hashed CSS-module class: the sidebar.settings outlet anchor is display: contents, so its parent element is div.settingsArea. Whenever the reserved id settings appears in order, that block is moved into the footer column (the anchor this plugin already owns) and sorted alongside the entries; when it does not appear, the block is handed back to div.footArea as its last child — where the shell renders it — and is otherwise never touched. On unload the plugin restores it too, so nothing is left behind.

Configuration

The plugin follows dsh's official two-seam config model, and all changes apply live without restarting dsh web (core features compatible with dsh ≥ 0.1.1-rc.2; the settingsArea internal arrangement requires dsh ≥ 0.1.2-rc.1 — see the compatibility note at the top):

Layer Source How it takes effect
Default built into the schema —
base layer (deploy-time static config) the plugin bundle's own cordis.patch.yml inline config (dsh.bundle.patch, auto-mounted on install) dsh web watches the patch layer (HMR); editing it reloads this fiber with the new config
user layer (runtime settings) Settings → Plugins → Sidebar Footer Order save/reset, persisted via ctx.settings to $DSH_HOME/settings.yaml; reset = clear the user layer and fall back to base settings service hot-publishes, instant; the plugin no longer rewrites cordis.patch.yml

The base-layer config (what the bundle ships):

- insert:
    - id: footer-order
      name: '@choi-p/dsh-footer-order'
      config:
        layout: column   # column = vertical stack (default) | row = horizontal | contents = no override
        gap: 0           # gap between entries in px (>= 0)
        align: stretch   # stretch | start | center | end (cross-axis alignment when column)
        # order: []        # plugin-id list, top to bottom; unlisted entries keep default registration order below the listed ones
        order: [settings]  # the reserved id `settings` = the shell's Settings row (settingsArea)
        settingsLayout: contents  # contents = no override (default) | row | column | row-reverse | column-reverse
        settingsGap: 8            # gap between settingsArea items in px (default 8)
        settingsAlign: center     # center | stretch | start | end
        settingsOrder: []         # settingsArea internal item order, e.g. [settings, connection]

The ids in order are the id each plugin passes to slots.register({ name, id, ... }) for sidebar.footer.action — not package names. The settings card lists all currently registered ids and lets you reorder them with ↑/↓.

settings is a reserved id: it stands for the shell's Settings row (the sidebar.settings slot rendered inside div.settingsArea). List it anywhere in order — e.g. ['settings', 'deepseek-balance'] puts Settings above the balance readout — and the row is moved into the footer column at that position. Leave it out and the row stays exactly where the shell renders it: the bottom of the foot area, below the whole footer stack. (If a real footer entry happens to be registered under the id settings, it wins — the reserved id is only used when no entry owns it.)

The card exposes layout (dropdown: vertical / horizontal / leave untouched), gap, align, and order, with Save / Reset to defaults. Save uses optimistic-concurrency revision — if the config was changed elsewhere, you get a prompt and the latest value is loaded.

Installation

Via plugin registry / marketplace

Settings → Plugins → Install, source @choi-p/dsh-footer-order or github:Choi-Peng/dsh-footer-order.

Manual

dsh plugin --profile web add "github:Choi-Peng/dsh-footer-order"

The plugin package ships its own cordis.patch.yml (dsh.bundle.patch in package.json), which dsh mounts automatically on install. Restart dsh web to activate.

Uninstall

dsh plugin --profile web remove @choi-p/dsh-footer-order

The bundle mount disappears with the plugin. If you had previously written the row manually in the profile layer, remove it first.

Usage

  1. Open dsh web — the footer entries below the sidebar stack vertically.
  2. Settings → Plugins → Sidebar Footer Order card: adjust layout, gap, alignment, and order, then Save. The "Settings row (settingsArea)" entry in the order list can be moved anywhere with ↑/↓. All changes apply live without restarting dsh web. On dsh 0.1.1-rc.2 the settingsArea arrangement group does not take effect, but the rest of the card still works.

Development

pnpm install
node --check lib/index.js
node --check lib/client.js
node scripts/smoke-host.mjs    # host half: routes / persistence / validation smoke test
node scripts/smoke-client.mjs  # client half: CSS injection / ordering / pairing smoke test

License

MIT

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.