Skip to content

dsh-ab-publish

Verified

dsh-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 โ€” open url, fill the named form fields, upload any files, click the submit control, wait for the result, and report status. Reuses a saved login session so credentials survive daemon restarts.
  • login_to_site โ€” authenticate once and persist the session (cookies + storage state) under the workspace; returns a session id 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 by id / 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 status needs_human instead 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 later publish_to_site via session.
  • 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 through submitPosition.
  • 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 a douyin-image preset.

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