DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-host-web-compat

k

dsh-host-web-compat

Discovered★ 4

dsh 宿主插件——经 webserver 钩子向页面注入旧内核浏览器 polyfill。

Machine translated

dsh-host-web-compat

🌐 中文说明 / 中文 README

DeepSeek Harness × Android ecosystem · dsh-mobile-apk (shell APK) · dsh-shell-termux (shell) · dsh-client-ui-responsive (mobile UI)

Host plugin for DeepSeek Harness that injects legacy-browser polyfills into every served page via the webserver tapIndex hook, and bridges the shell APK's directory picker and path-open channels.

Background

Older kernels (MuMu's bundled browser, older WebViews) lack APIs the host page calls directly:

  • missing AbortSignal.any() breaks the workspace directory picker's concurrent RPC cancellation;
  • missing Promise.withResolvers() breaks the host boot-ready tail script, failing the plugin tree;
  • missing global Iterator (Chrome 122+) makes upstream 0.1.5 client bundles (documentpreview and others) throw Iterator is not defined at import time ("Failed to load plugins").

The plugin injects idempotent polyfills at the HTML level — no browser-side changes needed.

Quick start

1. Install — package into the profile's node_modules.

2. Mount — in the profile's cordis.patch.yml:

- insert:
    - id: web-compat
      name: '@dsh-android/dsh-host-web-compat'
      disabled: !!js process.platform !== 'android'

3. Restart the service; the picker works again in old kernels.

Polyfills injected

APIconditionnote
AbortSignal.anymissingChrome 116+ / Node 20.3+
AbortSignal.timeoutmissingChrome 103+ / Node 17.3+
structuredClonemissingChrome 98+ / Node 17+
Object.hasOwnmissingChrome 93+ / Safari 15.4+
Array.prototype.atmissingChrome 92+
String.prototype.replaceAllmissingChrome 85+
crypto.randomUUIDmissingChrome 92+, secure context required
Promise.withResolversmissingChrome 119+; the host boot-ready tail depends on it
global Iterator + iterator helpersmissingChrome 122+ (map/filter/take/drop/flatMap/toArray/forEach/some/every/find/reduce + Iterator.from)
Object.groupBy / Map.groupBymissingChrome 117+
Set.prototype set methodsmissingChrome 122+ (union/intersection/difference/symmetricDifference/isSubsetOf/isSupersetOf/isDisjointFrom)
Array.fromAsyncmissingChrome 121+

Idempotent: skipped when already present. Every snippet shares one <script> element, so each one must end on a complete statement (see Development constraints).

Other injections

  • Directory-picker bridge (__dshBridge plus the /api/android/dir-pick/* polling endpoints that return real SAF paths);
  • open-path (window.__dshOpenPath: chat mentions and tool-row paths into the shell chooser) — 0.14 makes resolution session-scoped (relative paths resolve against the active session cwd);
  • theme bridge (__dshThemeBridge: system light/dark into page theme variables);
  • agent tool-row path recognition — 0.14 keys on DOM facts (not CSS-module class names) when clicking an absolute path in a tool row hands it to the shell chooser;
  • clipboard fallback (2026-10-03): a global wrapper over navigator.clipboard.writeText. Android WebView denies the async Clipboard API (NotAllowedError: Write permission denied; WebView has no permission prompt), and upstream writeClipboard returns false from its catch — it only falls back to execCommand('copy') when the API is absent — so every copy button wrote nothing and showed nothing. The wrapper falls back to the shell bridge window.androidBridge.copyText (ClipboardManager), then to execCommand('copy'), and emits one plain-language notice when all three fail. Patching the API instead of each caller covers CodeBlock / MessageIconActions / TerminalBlock / HoverCard / user-questions / trajectory and third-party plugins, which all read the API at click time;
  • boot watchdog: 40s stuck diagnostics plus the three contract lines the shell APK parses by field position ([dsh-boot-stall] stuck, [dsh-boot-ready] really rendered, [dsh-boot-failed] client plugin tree failed) — see Boot diagnostics contract.

Boot diagnostics contract

The watchdog reports on the console.error channel. The shell APK matches the line prefix and then reads the remaining fields by position, so the field order below is part of the interface:

linemeaningfields after the prefix
[dsh-boot-stall] dsh-boot-diag source=page-stall ...40s without a renderpageSideRuntime=<folded JSON> detail=<folded k=v>
[dsh-boot-ready] dsh-boot-diag source=page-ready ...#root rendered and the boot page is gonepageSideRuntime=<folded JSON>
[dsh-boot-failed] dsh-boot-diag source=page-plugin-fail ...client plugin tree faileddetail=reason=<first line, 200 chars> takenMs=<ms> failedCount=<N> rendered=<bool>, failedIds=<comma list or ->, pageSideRuntime=<folded JSON, last>

failedIds keeps only items that look like a loader entry id (/^[@A-Za-z0-9][@A-Za-z0-9._\/-]*$/, at most 120 characters), at most 8 items, unquoted and space-free; - when none is readable. It sits before pageSideRuntime because fold truncates at 2048 characters and a truncated JSON tail cannot be parsed at all.

Readiness is rendered() && !bootPagePresent(). A failed client plugin tree renders a boot page that still gives #root children, so the old rendered()-only criterion reported it as ready: the shell stopped its stall timer and the failure stayed silent. The failure line is published from two idempotent trigger points — the MutationObserver callback (2s debounce) and every readyWatch tick, which covers a failure page that reached its final state before the observer was installed. pendingBoot() is unchanged, so a failure page deliberately does not raise the 40s overlay: it exits through [dsh-boot-failed] instead.

Development constraints

Snippets live in the POLYFILLS array; the assembly rule is POLYFILL_SCRIPT_BODY in lib/index.js:

  • Every snippet must end with ; or }. All snippets share one <script> element, and a single syntax error makes the parser reject the whole element: the page then behaves as if no polyfill existed while the served HTML still contains the snippet text (measured 2026-09-10 — the Set-methods IIFE ended with })() against the next snippet's if (, so WebView 110 reported Iterator is not defined at import time).
  • apply() parse-checks the assembled markup with new Function at load and throws on failure (loud failure beats a silent downgrade).
  • Shim the real structure, not just the name: the global Iterator must be a constructor whose .prototype IS %IteratorPrototype% (bundled code such as pdfjs patches Iterator.prototype.x directly), and iterator wrappers must inherit that same prototype or chained helpers break.

Tests

node scripts/smoke-injections.mjs   # assembly + per-script parse + page-marker assertions, no install needed
node scripts/boot-watchdog.test.mjs # watchdog behaviour: pendingBoot / ready / failure contract line

The script loads the real plugin against a stubbed cordis, runs one tapIndex transform, and parses every served script element — the only check that catches an assembly syntax error (grepping the text does not).

Comments

Loading…

Similar plugins

dsh-usage-dashboard

by SJTUMalPan

DSH 宿主插件:把 dsh-usage-stats 生成的用量报表挂到宿主 Web 的 /usage,鉴权复用宿主登录态(零依赖)

Development & InfrastructureManifest valid

★ 0

MIT

JavaScript

Sep 27, 2026

dsh plugin --profile web add dsh-usage-dashboard

by tingaidehua

DSH plugin: publish /app/<slug>/ and /demo/<slug>/ static or proxy sites

Manifest valid

★ 0

JavaScript

Oct 12, 2026

dsh plugin --profile web add dsh-deploy-web

by iasiv5

DSH 插件:(Web Profile 专用)自动跳过 BrowserAuth,访问 Web 地址即可直接使用,无需每次复制启动 URL 中的随机 Token 到浏览器。

Security & AuditManifest valid

★ 3

↓ 1.3k/wk

MIT

JavaScript

Oct 28, 2026

dsh plugin --profile web add @iasiv5/dsh-skip-browser-auth

by buhuikongpan

DSH 分层插件管理器:原生插件按 系统层/WebUI 层/工具层 只读展示,用户扩展支持停用/启用、补登记、卸载与可编辑描述。

UI & ExperienceManifest valid

★ 8

JavaScript

Aug 20, 2026

dsh plugin --profile web add dsh-pluginmanager

by KaiYuan0422

一个简单的dsh插件:可以创建一个直接双击启动dsh web界面的脚本,可以自定义图标

Manifest valid

★ 0

MIT

JavaScript

Aug 15, 2026

dsh plugin --profile web add dsh-launcher

by WSGsety

DSH web plugin manager — enable/disable installed plugins from Settings. · DSH 网页插件管理:设置页直接启停已安装插件。

Manifest valid

★ 0

MIT

JavaScript

Aug 15, 2026

dsh plugin --profile web add @wsgsety/dsh-plugin-manager