DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

alitrack /

alitrack/dsh-wechat-article

Verified

Markdown -> WeChat Official Account draft from inside DeepSeek Harness (dsh): inline-style HTML, 900x383 cover, draft push with read-back. Zero dependencies.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@3c6af2e9

dsh-wechat-article

English | 简体中文

Turn Markdown into a WeChat Official Account (公众号) draft from inside DeepSeek Harness — inline-style HTML, a 2.35:1 cover card, and a draft-box push that reads itself back. Zero dependencies.

license dsh node

This is an article production chain, not an IM bridge. dsh-wechat (a different, unrelated package) connects an iLink bot to dsh for chat. This plugin never touches messages — it takes a Markdown file and produces a publishable article draft.

What it does

Tool Purpose
wechat_draft Markdown → WeChat-editor-safe HTML: every rule inline, no <style>, no class, images centred with captions, tables wrapped for horizontal scroll
wechat_cover 900x383 (2.35:1) cover card PNG — kicker, wrapped title, subtitle, four-colour chip row
wechat_push Create a draft in the 草稿箱 with a generated cover, then read it back and verify title + content length

The chain ends at the draft box. Nothing in this plugin publishes: 发表 is a decision for the human who owns the account.

Install

dsh plugin --profile web add dsh-wechat-article

Or straight from GitHub:

dsh plugin --profile web add github:alitrack/dsh-wechat-article

Credentials

wechat_draft and wechat_cover need no credentials at all. wechat_push needs an AppID/AppSecret pair with the 草稿箱 permission (a verified 订阅号/服务号):

# option A — environment
export DSH_WECHAT_APPID=wx...
export DSH_WECHAT_APPSECRET=...

# option B — local file (recommended for a desktop agent)
mkdir -p ~/.dsh-wechat
printf '{"appId":"wx...","appSecret":"..."}' > ~/.dsh-wechat/credentials.json
chmod 600 ~/.dsh-wechat/credentials.json

Overrides: DSH_WECHAT_CREDENTIALS points at a different file; DSH_WECHAT_CHROME pins the Chrome/Chromium binary used for covers.

Credentials are never accepted as tool arguments. That is deliberate: tool arguments travel through the model's context, the session transcript and the tool-call log. If the model could pass an AppSecret, the secret would end up in all three.

WeChat also requires the calling IP to be whitelisted (公众号后台 → 开发 → 基本配置 → IP白名单). A 40164 error means exactly that, and the plugin says so instead of echoing invalid ip.

Usage

Ask the agent, or call the tools directly:

1. wechat_draft  markdown_path=/ws/article.md out_path=/ws/out/article.html
2. wechat_cover  title="一条命令推到草稿箱" out_path=/ws/out/cover.png
3. wechat_push   title="…" markdown_path=/ws/article.md

wechat_push also accepts html= (the fragment wechat_draft returned), thumb_media_id= (an existing cover), or cover_path=; with none of them it generates and uploads a cover itself. dry_run=true validates titles, digests, limits and the cover without touching the network.

Supported Markdown

Headings, paragraphs, emphasis, inline code, fenced code (with a language label), blockquotes, ordered/unordered lists with two levels of nesting, GFM tables with alignment, images, ---, and the :::tip / :::info / :::warning / :::danger callout syntax. Frontmatter (title, author, digest, summary) feeds the draft's metadata. Anything outside this subset degrades to text rather than disappearing.

Two cover renderers

  1. headless Chrome/Chromium (auto-detected) — real font stack, so CJK titles render. Snap-packaged Chromium works: the renderer stages its files where a confined snap can actually write, and verifies the PNG's dimensions before accepting it.
  2. built-in rasteriser (lib/png.js + lib/font5x7.js) — always available, no Chrome needed. Draws the full card, but only has glyphs for digits and uppercase Latin; a CJK title comes back with a CJK_TEXT_NOT_RENDERED warning instead of boxes.

Both produce a real 900x383 PNG, and both stay under WeChat's 64KB thumb-material cap.

Security model

  • Workspace confinement. Every path is absolute and must resolve inside the calling session's workspace (exec.agent.session.header.cwd). .. traversal, symlinks pointing outside, absolute paths outside the root, directories and missing files are rejected with distinct error codes.
  • No publish path. Only draft/add and draft/get are implemented; freepublish is not.
  • Idempotent pushes. The same title+content hash is pushed once per workspace — a retrying agent cannot flood the draft box. State lives in <workspace>/.dsh-wechat/state.json (0600) and is capped at 200 entries.
  • Rate limiting. Consecutive pushes are spaced by at least 2s, and the plugin never retries in a loop on 45009.
  • Read-back verification. A 200 from draft/add means "accepted", not "correct". The plugin immediately fetches the draft and compares the title and the visible text length (5% tolerance, because WeChat rewrites HTML); readback_ok is false with a warning whenever they disagree. It never reports success it has not seen.
  • Secret hygiene. Error text is scrubbed of AppSecrets and access tokens before it reaches the model; the AppID is masked to wx12***cd.

Editorial pre-flight

wechat_draft reports warnings, never edits:

  • no images at all (a wall of text),
  • images not hosted on mmbiz.qpic.cn (the editor strips external images on save),
  • external <a href> links (unverified accounts lose them on publish),
  • tables wider than four columns,
  • placeholder tokens ([[待写]], TODO, 待补),
  • numeric consistency: the same quantity written two ways (1,234 vs 1234), a unit whose values span ≥1000x (usually 人 vs 人次, or 总数 vs 子集), large numbers with no unit, and numbers that appear only once and therefore cannot cross-check anything.

The numbers check is a checklist generator, not a fact checker — it surfaces candidates, the author decides.

Local development

npm install --no-save @deepseek-ai/dsh-tools@0.0.1-rc.1
node --test                      # 77 unit tests
node tests/e2e/keyless.mjs       # contract + guards, no model, no network

YAML overlays avoid pnpm entirely during development:

# local-overlay.yml
- insert:
    - id: dsh-wechat-article
      name: '/absolute/path/to/dsh-wechat-article/index.js'
npx @deepseek-ai/dsh@0.2.1-rc.2 --patch ./local-overlay.yml "把 article.md 排成公众号 HTML"

Full headless e2e (real dsh runtime + a local OpenAI-compatible model, so no API key): bash tests/e2e/run_e2e.sh.

Version gate

dsh refuses to load a plugin whose peerDependencies do not match the runtime. This plugin declares @deepseek-ai/dsh-tools: ^0.0.1-rc.1 and is tested against dsh 0.2.1-rc.2. The exemption is a profile-local compatibility.json mapping an exact name@version to exact dsh versions — dsh plugin allow-version is not a real command, despite the error message suggesting it.

Limitations (honest list)

  • Drafts only. No publish, no comment settings management beyond the create-time flags, no material library management.
  • Images are not uploaded. Article images must already live on WeChat's CDN; only the cover is uploaded (as thumb material). An image-upload helper is the obvious next step.
  • No syntax highlighting. Code blocks get one dark palette, not per-token colours.
  • CJK covers need Chrome. Without it you get a clean card with an ASCII title and an explicit warning.
  • Chinese-only account model. WeChat's draft API limits (64-char title, 16-char author, 120-char digest, 1MB content) are enforced locally so failures surface before a network call.

License

MIT.

—/ 5

No ratings yet

Verified DSH bundle

Commit 3c6af2e950b1

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout