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
settingsrepositioning) 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.actioncontent 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.orderincordis.patch.yml, or reorder with ↑/↓ in the Settings → Plugins → Sidebar Footer Order card. - The shell's Settings row (
settingsArea/ thesidebar.settingsslot) joins the same order list under the reserved idsettings— 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), andsettingsOrder(↑/↓ 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), andalign(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'scordis.patch.ymlbase 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
orderare theideach plugin passes toslots.register({ name, id, ... })forsidebar.footer.action— not package names. The settings card lists all currently registered ids and lets you reorder them with ↑/↓.
settingsis a reserved id: it stands for the shell's Settings row (thesidebar.settingsslot rendered insidediv.settingsArea). List it anywhere inorder— 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 idsettings, 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
- Open dsh web — the footer entries below the sidebar stack vertically.
- 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
Links
More in this category
zhu1090093659/dsh-web#packages/dsh-task-board★ 8296
Task board for the dsh web GUI: a sidebar multi-column kanban whose cards run in real DSH agent sessions and can also be scheduled with cron expressions, executed host-side even with the browser closed.
zhu1090093659/dsh-web#packages/dsh-web-all★ 8296
Plugin and skin collection for the DSH Web UI: task board, Git graph, right-side panel, remote mobile UI, pet, live token stats, and a skin center.
omdsh-dev/DSH-better-sidebar★ 3968
Full sidebar workbench with file rendering and editing, terminal, Git, and subagents; third-party plugins can register new tabs.
ccch1mneyyy/dsh-TUI★ 3948
Claude Code-style full-screen terminal UI: pixel-whale header, live status line, and streaming thought expansion.
MeteorNOX/DeepSeek-Balance-Whale-Widget★ 3877
A fixed-corner whale widget for the DSH web GUI — balance, today's usage and per-turn cost with peak/off-peak pricing, editable balance-alert and daily-budget bubbles, a module-based custom bubble queue with A/B weighted choices and random lines or images, 30+ vendor templates (OpenAI, OpenRouter, Kimi, SiliconFlow, Ark, Zhipu, MiniMax and more) with per-model balance and subscription quota, plus task-end sound, imported audio, custom roles and a resource manager. Local-only, no telemetry.
Devin-AXIS/deepseek-design#deepseek-idesign★ 1413
Visual design studio for websites, app prototypes, posters, cards, reports, and magazines, with templates, direct element editing, selection-aware AI draft handoff, and export.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.