dsh-ab-publish
Verifieddsh-ab-publish ยท v0.1.11 ยท MIT ยท Web UI
Browser-automation publishing tool that logs into and posts to arbitrary websites, in one publishable plugin package
Install
dsh plugin add dsh-ab-publish Confirm the layer applied with dsh --profile default --dump-config โ see the install guide.
Source
Published to npm without a public repository. Inspect the package contents before installing.
Tags
Readme
dsh-ab-publish
Publish information to an arbitrary website from a model tool call. The plugin
drives a real browser (Playwright, defaulting to the system Edge channel so
no Chromium download is required) to log in, fill a form, upload files, and submit
โ the same capability the agent-browser skill exposes, packaged as a first-class
DSH wire tool.
It is an out-of-tree, npm-publishable plugin: it never edits the deepseek-harness
framework source, mounts through cordis.patch.yml alone, and is installed purely
from the npm registry (no symlink / link:).
Tools
publish_to_siteโ openurl, fill the named form fields, upload anyfiles, click the submit control, wait for the result, and report status. Reuses a saved loginsessionso credentials survive daemon restarts.login_to_siteโ authenticate once and persist the session (cookies + storage state) under the workspace; returns asessionid the model can reuse.
The two tools are platform-agnostic: any site (Xiaohongshu, Douyin (ๆ้ณ), or your own
admin form) is driven by a site preset in sitesFile, not by code. Site-specific quirks
that the generic engine cannot express โ Xiaohongshu's QR-free phone login and shadow-root
publish button, Douyin's QR-scan login and image-text composer โ live as operator toolkits
under src/xhs/ and src/dy/ (see below).
Professional domain handling
- Robust field resolution (
selector.ts): each field key is tried as a CSS selector, then byid/name/placeholder/aria-label, then by a<label>whose text contains the key and points at the control. A form with no stable selectors still fills. - CAPTCHA / 2FA detection (
detect.ts): before submitting, the page is scanned for verification challenges (reCAPTCHA, hCaptcha, ้ช่ฏ็ , ๅ้่ฎค่ฏ, SMS/2FA). When one is present the call stops with statusneeds_humaninstead of burning a retry on a wall it cannot pass. - Login persistence (
store.ts): sessions are written under the session workspace root, so a scheduled publish that runs after the browser daemon restarts still has its credentials. - Human-in-the-loop login (
engine.ts): when a login preset marks a field with the__HUMAN__sentinel (an SMS code, 2FA, a slider), the engine skips that field, forces a visible browser, waits for the person to finish, and then saves the session โ so a phone-number login that needs a verification code becomes a one-time manual step, reused automatically on every laterpublish_to_siteviasession. - Retries with backoff, bounded field/file sizes, and a step log persisted next to each screenshot for auditability.
Configuration
Every bound is a .required() Schemastery guard, so a deployment states the size it
is willing to carry instead of inheriting a hidden default; omitting any of them
fails activation with $.<field>: missing required value. The install script writes
the deployment's values into the profile's cordis.patch.yml as an id-only row.
| Field | Meaning |
|---|---|
publishDir |
Workspace subdir for sessions, logs, and screenshots. |
maxRetries |
Submit attempts before giving up. |
timeoutMs |
Per-action timeout (navigation, fill, wait). |
headless |
Run the browser without a visible window. |
browserChannel |
Playwright channel; default msedge. |
waitNetworkIdleMs |
Idle wait after navigation / submit. |
maxFieldBytes |
Cap on one field value's length. |
maxFilesPerCall |
Most file uploads per call. |
maxFileBytes |
Cap on one uploaded file's size. |
Optional: defaultUserAgent, defaultLocale, humanWaitMs (most ms login_to_site
waits for a __HUMAN__ step; defaults to 300000).
Architecture
src/index.ts composition root: Config, Schemastery schema, self-aware
routing gate, agent/pre-step auto-invocation, the two tools
src/engine.ts pure publish pipeline (Playwright), no registry in sight
src/selector.ts field -> control resolution strategies
src/detect.ts CAPTCHA / 2FA / anti-bot challenge detection
src/store.ts persist sessions, step logs, screenshots under the workspace
src/sandbox.ts per-call sandbox fence (workspace-rooted writes)
src/trigger.ts auto-invocation intent detection
src/card.ts PublishCardMeta projector the browser card redraws from
src/client/* browser half: the publish result card
src/xhs/* Xiaohongshu operator toolkit (login / recon / verify scripts)
src/dy/* Douyin operator toolkit (login / recon / verify scripts)
The host and browser halves ship from one package; the browser half is built to the
out-of-tree window.__ModuleLoader__.load contract and the card redraws from the
logged call alone.
Site-specific toolkits
The generic engine carries no site knowledge, so each platform that needs a login or composer quirk the engine cannot express ships an operator toolkit inside the package:
src/xhs/README.mdโ Xiaohongshu (ๅฐ็บขไนฆ): phone-code login, media-first composer, shadow-root publish button resolved throughsubmitPosition.src/dy/README.mdโ Douyin (ๆ้ณ): QR-scan login (dy-login.mjs), image-text (ๅพๆ) composer whose title/caption appear only after upload (handled by the engine's deferred fill pass), and adouyin-imagepreset.
Both toolkits are .mjs scripts run by hand (pnpm run xhs:* / pnpm run dy:*); they are
not imported by src/index.ts and tsc never compiles them, so they cannot change how any
other site publishes.
Build & verify
pnpm install
pnpm verify # typecheck && build && test && lint