dsh-adapt-packs
Verifieddsh-adapt-packs ยท v0.3.6 ยท MIT ยท Web UI
Opt-in adaptation packs for the DSH mobile surface (a host-aware 44px touch floor, icon-button width, width reclaim, floating-widget clearance) plus a compatibility list of third-party plugins on a phone.
Install
dsh plugin add dsh-adapt-packs Confirm the layer applied with dsh --profile default --dump-config โ see the install guide.
Source
Tags
Readme
dsh-adapt-packs
Opt-in adaptation packs for the DSH mobile surface.
Third-party plugin panels on a phone have three problems a plugin cannot fix from inside its own component: touch targets a thumb cannot hit, a panel root wider than the phone's content box, and rows hidden underneath a floating widget. This repository is a small registry of fixes for exactly those, delivered as packs that dsh-mobile loads through its public extensions/ directory โ plus a compatibility list recording, per third-party plugin, whether it is usable on a phone as shipped, needs one of these packs, should be fixed upstream, or cannot be fixed from outside at all.
Nothing here forks or patches an installed DSH or dsh-mobile. A pack is a directory:
$DSH_HOME/mobile-access/extensions/<id>/
โโโ extension.json # schemaVersion, id, name, version, description โ exactly these five
โโโ mobile.css # injected by the host
โโโ mobile.js # optional; window.dshMobile.define({ apiVersion: 1, id, activate })
โโโ README.md # ignored at runtime
Copy it in and the host picks it up within two seconds; move it out and it is gone. No restart, no configuration file, no second auth model.
The packs
| pack | scope | what it does |
|---|---|---|
core-panel |
plugin panels | 44px hit floor inside a panel โ the only source on 0.8.x, and a fallback that backs off once the host ships its own floor (#319); icon-only button width; width reclaim |
shell-chrome |
the shell itself | the open drawer's sidebar rows (36 โ 44px); the "back to conversation" bar becomes a rise-only floor that never shrinks the host's own 48px |
floaters |
floating widgets | measures bottom-right fixed widgets, reserves their height, so the last rows stop hiding underneath |
dshmarket-mobile |
the plugin market panel | a 44px touch floor for dshmarket 1.73.x: buttons, icon buttons and the search field, scoped to [data-dsh-market-root] |
Every pack is experimental and off by default. catalog.json records, per pack, what has actually been verified and what has not โ the evidence field is meant to be read before trusting one.
The compatibility list
Not every plugin can be fixed from the outside โ and "this one is fine on a phone" is worth writing down too. compat.json records one verdict per third-party plugin:
dsh-adapt-packs compat # the whole list
dsh-adapt-packs compat --verdict pack # only entries this repository has a pack for
| verdict | meaning |
|---|---|
native |
usable on a phone as shipped |
pack |
this repository has a pack for it (pack names it) |
upstream |
fixable, but only by the plugin author |
blocked |
not fixable from outside (canvas, native widgets, no reachable DOM) |
Every entry carries the version it was judged on, what the phone actually does (numbers where possible) and how strong the evidence is โ measured, code-read, or not verified. Format and rules: docs/ๅ
ผๅฎนๆธ
ๅ.md. To suggest an entry, open the compat suggestion issue and bring numbers rather than adjectives.
dsh-adapt-packs status answers the other question โ which packs this machine has installed, which are disabled, and which are in the catalog but not installed.
Install
From npm
npm install -g dsh-adapt-packs
dsh-adapt-packs list # what is in the catalog
dsh-adapt-packs install core-panel --dry-run # plan only
dsh-adapt-packs install core-panel --yes # write into $DSH_HOME
dsh-adapt-packs uninstall core-panel --yes # move it out (reversible)
The published tarball carries packs/, catalog.json, docs/ and the tooling,
including the evidence screenshots under packs/<id>/shots/ (tarball โ 700 KB).
dsh-adapt-packs check runs the same harness as the repository.
Inside DSH (the settings panel)
The package is also a DSH bundle: install it the usual way and a ๆไปถ้้ section appears in Settings, where the catalog, the installed state and the compatibility list are one click apart.
dsh plugin add dsh-adapt-packs # or install the tarball from the market
It uses the same lib/store.mjs as the CLI, so the panel cannot disagree with dsh-adapt-packs status. The host route is /api/adapt-packs/{state,install,uninstall}; nothing else is exposed.
From a checkout
node tools/check-pack.mjs # validate every pack first
node tools/install.mjs pack core-panel --dry-run
node tools/install.mjs pack core-panel --yes
node tools/install.mjs --uninstall core-panel --yes
install.mjs defaults to a dry run, resolves $DSH_HOME (or ~/.dsh), refuses to overwrite an existing pack, and moves an uninstalled pack to mobile-access-adapt-disabled/ so it can be restored.
Windows
tools/ are plain Node scripts (Node 20+); nothing here assumes a POSIX shell, /tmp, or case-sensitive paths, and the commands work unchanged in PowerShell. The fixture checker needs Playwright and its Chromium build:
npm install --no-save --no-package-lock playwright
npx playwright install chromium # downloads into %LOCALAPPDATA%\ms-playwright
check-pack.mjs resolves Playwright in this order and lists every path it tried when it fails: DSH_PLAYWRIGHT (a playwright/index.js file or the playwright package directory) โ $DSH_HOME/profiles/{web,desktop,headless}/node_modules/playwright โ this repository's own node_modules โ normal module resolution. A missing Chromium produces a message that points at npx playwright install chromium and at the expected browser cache (%LOCALAPPDATA%\ms-playwright on Windows).
Set the home directory with PowerShell syntax โ the POSIX export form does not apply:
$env:DSH_HOME = 'C:\Users\you\.dsh' # default when unset: %USERPROFILE%\.dsh
install.mjs derives mobile-access\extensions\<id> from it and moves an uninstalled pack to mobile-access-adapt-disabled\<id>. Paths with a leading ~ are expanded, and \ and / are both accepted where a pack path is expected. Existing pack directories are resolved case-insensitively (PACKS\CORE-PANEL is packs/core-panel), while pack ids and catalog.json lookups stay lowercase. CRLF checkouts are supported: the windows-latest job in CI runs the whole fixture suite from a CRLF working tree on every push/PR.
One path is not exercised by a normal install: the EXDEV fallback in install.mjs (copy + delete instead of rename). Install source and target both live under the same $DSH_HOME, so a plain rename is what actually runs; the fallback stays for unusually mounted homes and is documented rather than claimed as tested.
Targeted fixtures
The built-in fixture measures a generic, deliberately desktop-first plugin panel. A pack aimed at one specific plugin can ship packs/<id>/fixture.html with that plugin's own DOM; check-pack then runs every round (baseline, pack, opt-out, desktop zero-regression) against it instead. Without the file the built-in fixture is used and the report says which one ran โ human output prints fixture๏ผๅ
็ฝฎ๏ผๅ้ๅ
็ฝฎ fixture๏ผ and --json carries fixture.kind.
node tools/check-pack.mjs docs/examples/fixture-pack --desktop # runnable example
The contract โ allowed markup (DOM + inline styles only, no scripts/event handlers/external or data: references, โค 256 KB), the required shell/panel hooks, how target / usesHostMarkers / evidence must describe the fixture โ is in docs/ๅฎๅ-fixture.md. docs/examples/fixture-pack/ is a runnable example, not a real pack: it lives outside packs/, is not in catalog.json, and therefore reports one harmless catalog warning.
Opt out
<html data-dsh-adapt="off">
Each pack stops applying entirely โ panel spacing returns to its own values, shell rows return to the shell's sizes. This is checked by the harness, not asserted in prose.
What has been verified
| state | |
|---|---|
| Fixture measurement: 390ร844 coarse pointer, 1280ร800 fine pointer zero-regression, opt-out | โ
every pack (node tools/check-pack.mjs) |
Fixture measurement on Windows 11 + Chromium (node tools/check-pack.mjs --desktop) |
โ
every pack (2026-10-31, earlier suite: 87 passed / 0 failed / 8 skipped; the suite changed since โ CI on windows-latest runs the current one) |
| Real runtime on dsh-mobile 0.8.0 | โ
measured on the real gateway (390ร844, coarse pointer, Plugins panel) โ see ๅฎๆต-0.8.0-20261031.md in the workspace |
| Real runtime on 0.8.1+ (contains #319) | โณ shipped 2026-11-01; our gate (:not([data-dsh-panel])) backs the height floor off once the host writes the marker โ verified by check-pack host-probe on a synthetic host state, not re-measured on a real 0.8.1 host (this box still runs 0.8.0) |
| Real runtime on 0.7.1 | โ historically (2026-10-31 earlier run); the 122px / 36โ44px numbers were the same as 0.8.0 |
| Physical device | โ
Android App measured (2026-11-01, Redmi K90 Max / Android 17 / dsh-mobile App 0.7.1): with core-panel installed (or with the full set) the slot reaches 141/44/0 where the no-pack baseline is 141/14/141 (dshmarket-mobile alone only fixes the market root); real env(safe-area-inset-*) is 0 because this App is not edge-to-edge; the soft keyboard shrinks the viewport 786โ472. See docs/็ๆบ้ช่ฏ.md. iOS, thumb-reach feel and edge-to-edge apps remain unverified |
Two release lines: 0.8.0 vs main (#319)
dsh-mobile merged #319 on 2026-10-31 (6c50b13), after v0.8.0 was published (2026-10-30), and shipped it in v0.8.1 (2026-11-01). So there are two host lines โ and our packs have to behave on both:
| release 0.8.0 | main after #319 | |
|---|---|---|
host writes data-dsh-panel |
no (grep: 0 hits) | yes, on .dshm-main |
| 44px hit floor for plugin panel controls | no (94/94 controls < 44px measured) | yes, host-provided |
| panel root width clamp | no | yes |
icon-only button min-width |
no | no |
| bottom safe area on panel pages | no | no |
core-panel therefore gates its height floor and width clamp on .dshm-main:not([data-dsh-panel]): on 0.8.x it is the only source, and on a host that owns that attribute it steps aside instead of duplicating (and never writes the host's attribute โ it keeps its own data-dshm-adapt-panel). check-pack proves the gate with a simulated host-owned attribute (runtime.hostGate.*).
That is why the packs stay experimental rather than candidate. Measuring is a separate problem, and there is a tool for it: dsh-ui-lab opens a DSH surface at real device proportions, captures a panel, and gates a matrix run on a pixel diff.
The dependency this cannot escape
These packs name dsh-mobile's own class names โ .dshm-shell, .dshm-main, .dshm-mainContent, .dshm-drawer, .dshm-panelNav, [data-slot="sidebar"]. dsh-mobile does not promise to keep them, and its documentation explicitly rules out maintaining a general override table keyed on third-party class names. catalog.json lists the markers each pack touches (the usesHostMarkers field) precisely so a break is traceable to a pack, but a redesign can still break them.
The durable fix is a contract on the host side: stable attributes for panel state, for a plugin's own chrome, and for opting out. Until that exists, this repository is a compatibility layer that is expected to need maintenance โ not something the dsh-mobile maintainers ship or support.
Contributing
A new pack starts from packs/_template/ and has to pass node tools/check-pack.mjs packs/<id>. The rules โ which capabilities may be claimed, how a pack must be scoped, what opt-out means, what a pack may not touch โ are in docs/ๆถๅฝๆ ๅ.md (Chinese; the check harness is the executable version of it).
docs/phone-instance.md describes how to drive the real mobile page headlessly, which is how a pack gets verified beyond the fixture.
Releasing
Push a tag that matches package.json and .github/workflows/publish.yml
validates the catalog, then publishes with npm provenance.
npm version patch --no-git-tag-version
git commit -am "chore: 0.1.1"
git tag v0.1.1 && git push origin main v0.1.1
The job needs the repository secret NPM_TOKEN (a granular token with "Read and
write" publish permission for dsh-adapt-packs). workflow_dispatch defaults to
npm publish --dry-run.
License
MIT โ see LICENSE.