{"id":"ca11d9af-6f6a-4aab-8204-abdcb838ff01","entityType":"agent","slug":"clawhub-jimliu-baoyu-post-to-wechat","name":"Baoyu Post To Wechat","canonicalUrl":"https://www.xpersona.co/agent/clawhub-jimliu-baoyu-post-to-wechat","canonicalPath":"/agent/clawhub-jimliu-baoyu-post-to-wechat","generatedAt":"2026-10-09T23:21:14.334Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-09T04:04:41.627Z","emptyReason":null},"description":"Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-tex... Skill: Baoyu Post To Wechat Owner: jimliu Summary: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-tex... Tags: latest:1.118.2 Version history: v1.118.2 | 2026-06-13T05:01:20.839Z | auto baoyu-post-to-wechat v1.118.2 - Updated internal logic in wechat-api.ts for improved API handling. - Documentation improvements","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 5.4K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s17dfbhg0khk4fvtnx0stqg0yx83j25z:baoyu-post-to-wechat","sourceUrl":"https://clawhub.ai/jimliu/baoyu-post-to-wechat","homepage":"https://clawhub.ai/jimliu/skills/baoyu-post-to-wechat","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/jimliu/baoyu-post-to-wechat","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/jimliu/skills/baoyu-post-to-wechat","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":64,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-tex..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:04:41.627Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:04:41.627Z","emptyReason":null},"stars":null,"forks":null,"downloads":5361,"packageName":null,"latestVersion":"1.118.2","tractionLabel":"5.4K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:04:41.627Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T04:04:41.627Z","lastCrawledAt":"2026-10-09T04:04:41.627Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T04:04:41.627Z","lastVerifiedAt":null,"highlights":[{"version":"1.118.2","createdAt":"2026-06-13T05:01:20.839Z","changelog":"baoyu-post-to-wechat v1.118.2 - Updated internal logic in wechat-api.ts for improved API handling. - Documentation improvements in SKILL.md for clarity and accuracy. - Removed legacy file skill-card.md.","fileCount":31,"zipByteSize":103063},{"version":"1.118.1","createdAt":"2026-06-01T03:31:16.016Z","changelog":"Fix stale npm shared package dependency pins for baoyu-md and baoyu-chrome-cdp 0.1.1.","fileCount":31,"zipByteSize":102646},{"version":"1.117.5","createdAt":"2026-05-21T13:55:44.599Z","changelog":"Credit to Dame5211 <1079825614@qq.com> for the baoyu-post-to-wechat remote API publishing update.","fileCount":31,"zipByteSize":101595},{"version":"1.117.4","createdAt":"2026-05-21T13:53:38.223Z","changelog":"Sync latest baoyu-skills updates, including baoyu-post-to-wechat remote API publishing via SSH SOCKS5 tunnel.","fileCount":30,"zipByteSize":100160},{"version":"1.117.3","createdAt":"2026-05-19T18:43:48.197Z","changelog":"## baoyu-post-to-wechat 1.117.3 - Updated SKILL.md to set version to 1.117.3. - No logic or behavior changes; documentation updated only.","fileCount":23,"zipByteSize":82939},{"version":"1.117.2","createdAt":"2026-05-18T02:15:45.841Z","changelog":"## 1.117.2 - 2026-05-17 ### Documentation - `baoyu-cover-image`: ban programmatic text repair on generated bitmaps — disallow ImageMagick / Pillow / Canvas / SVG / HTML overlays to cover, rewrite, or replace title/subtitle text; regenerate from a corrected prompt or switch to a lower-text or no-title variant instead - `baoyu-article-illustrator`, `baoyu-comic`, `baoyu-image-cards`, `baoyu-xhs-images`, `baoyu-infographic`, `baoyu-slide-deck`: sync the same text-repair ban with skill-specific text categories (labels/captions, dialogue/sound effects, titles/body/tags, headings/data values, slide titles/bullets)","fileCount":23,"zipByteSize":82938},{"version":"1.116.5","createdAt":"2026-05-14T06:50:55.561Z","changelog":"## 1.116.5 - 2026-05-14 ### Features - `baoyu-post-to-wechat`: send WeChat login QR code to Telegram when `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` env vars are set, enabling headless / remote login flows (by @beforesun) ### Refactor - `baoyu-post-to-wechat`: harden Telegram QR notification — add 10s fetch timeout, defer the 2s QR-render wait until env vars are configured, and use viewport screenshot as fallback","fileCount":21,"zipByteSize":78109},{"version":"1.115.4","createdAt":"2026-05-11T23:49:31.159Z","changelog":"### Documentation - Image generation backend selection: emphasize Codex `imagegen` as the priority runtime-native tool (invoke via the `Skill` tool with `skill: \"imagegen\"`) and forbid SVG/HTML/canvas substitution when no raster backend can be resolved — fall through to asking the user instead of silently emitting code-based art. Updated in `docs/image-generation-tools.md` and inlined into `baoyu-article-illustrator`, `baoyu-comic`, `baoyu-cover-image`, `baoyu-image-cards`, `baoyu-infographic`, `baoyu-slide-deck`, and `baoyu-xhs-images`.","fileCount":21,"zipByteSize":76786}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17dfbhg0khk4fvtnx0stqg0yx83j25z:baoyu-post-to-wechat","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T23:21:14.330Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jimliu-baoyu-post-to-wechat/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-09T04:04:41.627Z","emptyReason":null},"readme":"Skill: Baoyu Post To Wechat\n\nOwner: jimliu\n\nSummary: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-tex...\n\nTags: latest:1.118.2\n\nVersion history:\n\nv1.118.2 | 2026-06-13T05:01:20.839Z | auto\n\nbaoyu-post-to-wechat v1.118.2\n\n- Updated internal logic in wechat-api.ts for improved API handling.\n- Documentation improvements in SKILL.md for clarity and accuracy.\n- Removed legacy file skill-card.md.\n\nv1.118.1 | 2026-06-01T03:31:16.016Z | user\n\nFix stale npm shared package dependency pins for baoyu-md and baoyu-chrome-cdp 0.1.1.\n\nv1.117.5 | 2026-05-21T13:55:44.599Z | user\n\nCredit to Dame5211 <1079825614@qq.com> for the baoyu-post-to-wechat remote API publishing update.\n\nv1.117.4 | 2026-05-21T13:53:38.223Z | user\n\nSync latest baoyu-skills updates, including baoyu-post-to-wechat remote API publishing via SSH SOCKS5 tunnel.\n\nv1.117.3 | 2026-05-19T18:43:48.197Z | auto\n\n## baoyu-post-to-wechat 1.117.3\n\n- Updated SKILL.md to set version to 1.117.3.\n- No logic or behavior changes; documentation updated only.\n\nv1.117.2 | 2026-05-18T02:15:45.841Z | user\n\n## 1.117.2 - 2026-05-17\n\n### Documentation\n- `baoyu-cover-image`: ban programmatic text repair on generated bitmaps — disallow ImageMagick / Pillow / Canvas / SVG / HTML overlays to cover, rewrite, or replace title/subtitle text; regenerate from a corrected prompt or switch to a lower-text or no-title variant instead\n- `baoyu-article-illustrator`, `baoyu-comic`, `baoyu-image-cards`, `baoyu-xhs-images`, `baoyu-infographic`, `baoyu-slide-deck`: sync the same text-repair ban with skill-specific text categories (labels/captions, dialogue/sound effects, titles/body/tags, headings/data values, slide titles/bullets)\n\nv1.116.5 | 2026-05-14T06:50:55.561Z | user\n\n## 1.116.5 - 2026-05-14\n\n### Features\n- `baoyu-post-to-wechat`: send WeChat login QR code to Telegram when `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` env vars are set, enabling headless / remote login flows (by @beforesun)\n\n### Refactor\n- `baoyu-post-to-wechat`: harden Telegram QR notification — add 10s fetch timeout, defer the 2s QR-render wait until env vars are configured, and use viewport screenshot as fallback\n\nv1.115.4 | 2026-05-11T23:49:31.159Z | user\n\n### Documentation\n- Image generation backend selection: emphasize Codex `imagegen` as the priority runtime-native tool (invoke via the `Skill` tool with `skill: \"imagegen\"`) and forbid SVG/HTML/canvas substitution when no raster backend can be resolved — fall through to asking the user instead of silently emitting code-based art. Updated in `docs/image-generation-tools.md` and inlined into `baoyu-article-illustrator`, `baoyu-comic`, `baoyu-cover-image`, `baoyu-image-cards`, `baoyu-infographic`, `baoyu-slide-deck`, and `baoyu-xhs-images`.\n\nv1.115.3 | 2026-05-11T21:25:20.302Z | user\n\n## 1.115.3 - 2026-05-11\n\n### Fixes\n- `baoyu-post-to-wechat`: ensure tab activation before copy/paste in WeChat editor (by @fengxiaodong28)\n- `baoyu-post-to-x`: use toolbar media upload instead of image clipboard paste for X Articles\n\nv1.103.2 | 2026-04-21T22:03:07.853Z | auto\n\nMajor update: Multi-account support & enhanced user experience.\n\n- Added support for multiple WeChat Official Accounts in EXTEND.md, including per-account credentials and settings.\n- Removed bundled vendor packages; now expects dependencies installed separately.\n- Introduced clear user input tool selection rules and improved prompts, supporting various agent runtimes.\n- Step-by-step publishing workflow clarified, with stricter input type handling and validation of required metadata.\n- New configuration and usage references added: API setup, multi-account guide, and environmental check instructions.\n- Markdown/HTML conversion and article image handling further standardized (never pre-convert; let scripts handle).\n\nv1.103.1 | 2026-04-13T16:17:30.759Z | user\n\n## 1.103.1 - 2026-04-13\n\n### Fixes\n- `baoyu-markdown-to-html`: decode HTML entities and strip tags from article summary\n- `baoyu-post-to-weibo`: decode HTML entities and strip tags from article summary\n\nv1.103.0 | 2026-04-13T01:22:17.715Z | user\n\n## 1.103.0 - 2026-04-12\n\n### Features\n- baoyu-diagram: add multi-diagram mode for article-wide diagram generation\n\n### Fixes\n- baoyu-article-illustrator: prevent color names and hex codes from appearing as visible text in generated images\n- baoyu-cover-image: prevent color names and hex codes from appearing as visible text in generated images\n- baoyu-image-cards: prevent color names from appearing as visible text in generated images\n- baoyu-post-to-wechat: decode HTML entities and strip tags from article summary\n\nv1.89.3 | 2026-04-09T16:28:35.851Z | auto\n\n- Improved: Refactored wechat-api.ts and wechat-image-processor.ts for stability or maintainability.\n- Removed: Deleted unused files bun.lock and LICENSE from vendor/baoyu-md/src.\n- General update: Reduced repository clutter by removing outdated or redundant files.\n\nv1.89.2 | 2026-04-04T04:37:15.282Z | user\n\n- Use fallback chain for article summary field\n\nv1.76.2 | 2026-03-25T21:33:16.291Z | auto\n\n- Added a test file for `wechat-extend-config` to improve test coverage.\n- Updated `wechat-api.ts` and `wechat-extend-config.ts` with changes, possibly refactoring or bug fixes.\n- Removed unnecessary files: `bun.lock` and a vendor LICENSE file.\n\nv1.76.1 | 2026-03-22T04:24:19.845Z | auto\n\n- Improved HTML builder logic and test coverage for Markdown to WeChat conversion.\n- Added and updated tests to better validate document and theme generation.\n- Refined theme handling in the HTML builder for more robust and customizable output.\n- Minor code and structure improvements in the core markdown-to-WeChat rendering pipeline.\n\nv1.73.3 | 2026-03-21T00:39:16.071Z | user\n\n### Fixes\n- Fix placeholder replacement to avoid shorter placeholders matching longer numbered variants\n\nv1.73.2 | 2026-03-20T19:47:12.222Z | user\n\n## 1.73.2 - 2026-03-20\n\n### Fixes\n- `baoyu-post-to-wechat`: fix body image upload to correctly use media/uploadimg API with format and size validation (by @AICreator-Wind)\n\n### Refactor\n- `baoyu-post-to-wechat`: extract image processor module for local format conversion (WebP/BMP/GIF → JPEG/PNG) instead of material API fallback\n\nv1.69.1 | 2026-03-16T18:01:22.471Z | user\n\n## 1.69.1 - 2026-03-16\n\n### Fixes\n- `baoyu-chrome-cdp`: tighten chrome auto-connect logic to reduce false positives\n\nv1.65.0 | 2026-03-13T15:56:58.743Z | user\n\n## 1.65.0 - 2026-03-13\n\n### Features\n- `baoyu-post-to-wechat`: add placeholder image upload support with deduplication for markdown-embedded images\n\n### Fixes\n- `baoyu-post-to-wechat`: fix frontmatter parsing to allow leading whitespace and optional trailing newline\n\n### Refactor\n- `baoyu-post-to-wechat`: replace `renderMarkdownToHtml` with `renderMarkdownWithPlaceholders` for structured output\n\nv1.60.0 | 2026-03-12T03:45:42.361Z | user\n\n## 1.60.0 - 2026-03-11\n\n### Features\n- `baoyu-url-to-markdown`: support reusing existing Chrome CDP instances and fix port detection order\n\n### Fixes\n- `baoyu-post-to-x`: add missing `fs` import in x-article\n\n### Refactor\n- Unify all CDP skills to use shared `baoyu-chrome-cdp` package with vendored copies\n- Simplify CLAUDE.md, move detailed documentation to `docs/` directory\n- Publish skills directly from synced vendor, removing separate artifact preparation step\n\nv1.0.0 | 2026-03-09T17:19:52.740Z | auto\n\nbaoyu-post-to-wechat 1.0.0 – Initial Release\n\n- Post content to WeChat Official Account via API or Chrome CDP, supporting both article and image-text (formerly 图文) formats.\n- Handles HTML, markdown, and plain text; markdown inputs auto-convert external links into WeChat-friendly footnotes.\n- Loads and prioritizes publishing preferences from EXTEND.md at project, XDG, or user level.\n- Offers environment readiness checking and detailed troubleshooting guidance.\n- Supports custom themes, color schemes, and author metadata via configuration.\n- Includes publishing workflow and command-line usage examples for quick start.\n\nArchive index:\n\nArchive v1.118.2: 31 files, 103063 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (6317b), references/image-text-posting.md (2833b), references/multi-account.md (5807b), scripts/bun.lock (38871b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard-mac.test.ts (916b), scripts/copy-to-clipboard.ts (14377b), scripts/md-to-wechat.ts (5803b), scripts/package.json (244b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (31007b), scripts/wechat-article-focus.test.ts (2741b), scripts/wechat-article.ts (48947b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (10079b), scripts/wechat-extend-config.ts (14593b), scripts/wechat-http.test.ts (5100b), scripts/wechat-http.ts (2677b), scripts/wechat-image-loader.ts (2526b), scripts/wechat-image-processor.ts (8524b), scripts/wechat-remote-publish.test.ts (5647b), scripts/wechat-remote-publish.ts (8007b), scripts/wechat-socks-http.test.ts (6837b), scripts/wechat-socks-http.ts (6917b), skill-card.md (2902b), SKILL.md (14864b), _meta.json (141b)\n\nFile v1.118.2:SKILL.md\n\n---\nname: baoyu-post-to-wechat\ndescription: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-text posting (贴图, formerly 图文) with multiple images. Markdown article workflows default to converting ordinary external links into bottom citations for WeChat-friendly output. Use when user mentions \"发布公众号\", \"post to wechat\", \"微信公众号\", or \"贴图/图文/文章\".\nversion: 1.118.2\nmetadata:\n  openclaw:\n    homepage: https://github.com/JimLiu/baoyu-skills#baoyu-post-to-wechat\n    requires:\n      anyBins:\n        - bun\n        - npx\n---\n\n# Post to WeChat Official Account\n\n## User Input Tools\n\nWhen this skill prompts the user, follow this tool-selection rule (priority order):\n\n1. **Prefer built-in user-input tools** exposed by the current agent runtime — e.g., `AskUserQuestion`, `request_user_input`, `clarify`, `ask_user`, or any equivalent.\n2. **Fallback**: if no such tool exists, emit a numbered plain-text message and ask the user to reply with the chosen number/answer for each question.\n3. **Batching**: if the tool supports multiple questions per call, combine all applicable questions into a single call; if only single-question, ask them one at a time in priority order.\n\nConcrete `AskUserQuestion` references below are examples — substitute the local equivalent in other runtimes.\n\n## Language\n\nRespond in the user's language. If they write in Chinese, reply in Chinese; if English, English. Keep technical tokens (paths, flags, field names) in English.\n\n## Script Directory\n\n`{baseDir}` = this SKILL.md's directory. Resolve `${BUN_X}`: prefer `bun`; else `npx -y bun`; else suggest `brew install oven-sh/bun/bun`.\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/wechat-browser.ts` | Image-text posts (图文) |\n| `scripts/wechat-article.ts` | Article posting via browser (文章) |\n| `scripts/wechat-api.ts` | Article posting via API (文章) |\n| `scripts/md-to-wechat.ts` | Markdown → WeChat-ready HTML with image placeholders |\n| `scripts/check-permissions.ts` | Verify environment & permissions |\n\n## Preferences (EXTEND.md)\n\nCheck these paths in order; first hit wins:\n\n| Path | Scope |\n|------|-------|\n| `.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | Project |\n| `${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | XDG |\n| `$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | User home |\n\nFound → read, parse, apply. Not found → run first-time setup (`references/config/first-time-setup.md`) before anything else.\n\n**Minimum keys** (case-insensitive, accept `1/0` or `true/false`):\n\n| Key | Default | Mapping |\n|-----|---------|---------|\n| `default_author` | empty | Fallback for `author` when CLI/frontmatter not provided |\n| `need_open_comment` | `1` | `articles[].need_open_comment` in `draft/add` |\n| `only_fans_can_comment` | `0` | `articles[].only_fans_can_comment` in `draft/add` |\n\n**Recommended EXTEND.md**:\n\n```md\ndefault_theme: default\ndefault_color: blue\ndefault_publish_method: browser\ndefault_author: 宝玉\nneed_open_comment: 1\nonly_fans_can_comment: 0\nchrome_profile_path: /path/to/chrome/profile\n\n# Remote API publishing (optional) — only set if WeChat's IP allowlist\n# excludes your local machine. See \"Remote API Method\" below.\n# remote_publish_host: server.example.com\n# remote_publish_user: deploy\n# remote_publish_port: 22\n# remote_publish_identity_file: ~/.ssh/id_ed25519\n# remote_publish_known_hosts_file: ~/.ssh/known_hosts\n# remote_publish_strict_host_key_checking: accept-new\n# remote_publish_connect_timeout: 10\n# remote_publish_proxy_jump: bastion.example.com\n```\n\nRaw `ssh` / `scp` options are intentionally not supported; only the typed keys above are honored. Authentication is SSH key only (no passwords).\n\n**Theme options**: default, grace, simple, modern. **Color presets**: blue, green, vermilion, yellow, purple, sky, rose, olive, black, gray, pink, red, orange (or hex).\n\n**Value priority**: CLI args → frontmatter → EXTEND.md (account-level → global) → skill defaults.\n\n## Multi-Account Support\n\nEXTEND.md supports an `accounts:` block for managing multiple Official Accounts. With 2+ entries, the workflow inserts a Step 0.5 to prompt for account selection (or auto-selects based on `default: true` or `--account <alias>`).\n\nFull details — compatibility rules, per-account keys, credential resolution, per-account Chrome profiles, CLI usage — in `references/multi-account.md`.\n\n## Pre-flight Check (Optional)\n\nBefore first use, suggest the environment check (user can skip):\n\n```bash\n${BUN_X} {baseDir}/scripts/check-permissions.ts\n```\n\nChecks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, API credentials, Chrome conflicts.\n\n| Check fails | Fix |\n|-------------|-----|\n| Chrome | Install Chrome or set `WECHAT_BROWSER_CHROME_PATH` |\n| Profile dir | Shared profile at `baoyu-skills/chrome-profile` |\n| Bun runtime | `brew install oven-sh/bun/bun` or `npm install -g bun` |\n| Accessibility (macOS) | System Settings → Privacy & Security → Accessibility → enable terminal app |\n| Clipboard copy | Ensure Swift/AppKit (macOS: `xcode-select --install`) |\n| Paste keystroke (Linux) | Install `xdotool` (X11) or `ydotool` (Wayland) |\n| API credentials | Follow guided setup in Step 2, or set in `.baoyu-skills/.env` |\n\n## Image-Text Posting (图文)\n\nShort posts with multiple images (up to 9):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown article.md --images ./images/\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --title \"标题\" --content \"内容\" --image img.png --submit\n```\n\nDetails: `references/image-text-posting.md`.\n\n## Article Posting Workflow (文章)\n\n```\n- [ ] Step 0: Load preferences (EXTEND.md)\n- [ ] Step 0.5: Resolve account (multi-account only — see references/multi-account.md)\n- [ ] Step 1: Determine input type\n- [ ] Step 2: Select method and configure credentials\n- [ ] Step 3: Resolve theme/color and validate metadata\n- [ ] Step 4: Publish to WeChat\n- [ ] Step 5: Report completion\n```\n\n### Step 0: Load Preferences\n\nCheck and load EXTEND.md (see \"Preferences\" above). If not found, complete first-time setup before any other questions. Resolve and cache for later steps: `default_theme`, `default_color`, `default_author`, `need_open_comment`, `only_fans_can_comment`.\n\n### Step 1: Determine Input Type\n\n| Input | Detection | Next |\n|-------|-----------|------|\n| HTML file | Path ends `.html`, file exists | Skip to Step 3 |\n| Markdown file | Path ends `.md`, file exists | Step 2 |\n| Plain text | Not a file path, or file doesn't exist | Save to markdown, then Step 2 |\n\n**Plain-text handling**:\n\n1. Generate slug (first 2-4 meaningful words, kebab-case; translate Chinese to English for the slug).\n2. Save to `post-to-wechat/YYYY-MM-DD/<slug>.md` (create directory if needed).\n3. Continue as a markdown file.\n\n### Step 2: Select Publishing Method and Configure\n\nAsk method unless specified in EXTEND.md or CLI:\n\n| Method | Speed | Requires |\n|--------|-------|----------|\n| `api` (Recommended) | Fast | API credentials (local IP allowlisted) |\n| `browser` | Slow | Chrome + logged-in session |\n| `remote-api` | Fast | API credentials + an SSH-reachable server whose IP is on the WeChat allowlist |\n\n**API selected + missing credentials** → run guided setup per `references/api-setup.md` (writes to `.baoyu-skills/.env`).\n\n**`remote-api` method**: WeChat's \"公众号设置 → IP 白名单\" often limits API access to one or two fixed IPs. If your local machine's IP is not on that list but a cloud server's is, use `remote-api`: all markdown rendering, image processing, draft assembly, and HTML rewriting still happen locally, and only the outbound HTTPS calls to `api.weixin.qq.com` (token, uploadimg, add_material, draft/add) are tunneled through an SSH SOCKS5 dynamic port forward (`ssh -N -D`) so that WeChat sees the remote server as the source IP. No files are written to the remote host; `AppSecret` never leaves the local process. Requires only `sshd` and outbound network on the remote host — no Python, no agent process. See \"Remote API Method\" below.\n\n### Step 3: Resolve Theme/Color and Validate Metadata\n\n1. **Theme**: CLI `--theme` → EXTEND.md `default_theme` → `default` (first match wins; do NOT ask if resolved).\n2. **Color**: CLI `--color` → EXTEND.md `default_color` → omit (theme default applies).\n3. **Validate metadata** (frontmatter for markdown, meta tags for HTML):\n\n| Field | Missing → |\n|-------|-----------|\n| Title | Ask, or press Enter to auto-generate from content |\n| Summary | Frontmatter `description` → `summary` → ask or auto-generate |\n| Author | CLI `--author` → frontmatter `author` → EXTEND.md `default_author` |\n| Source URL | CLI `--source-url` → frontmatter `sourceUrl`/`contentSourceUrl`/`content_source_url` |\n\nAuto-generation: title = first H1/H2 or first sentence; summary = first paragraph, truncated to 120 chars.\n\n4. **Cover image** (required for API `article_type=news`): CLI `--cover` → frontmatter (`coverImage` / `featureImage` / `cover` / `image`) → `imgs/cover.png` → first inline image → stop and request one if still missing.\n\n### Step 4: Publish\n\n**Important — never pre-convert markdown to HTML.** Publishing scripts handle the conversion internally and the two methods render images differently: API renders `<img>` tags for upload, browser uses placeholders for paste-and-replace. Passing a pre-converted HTML breaks one or the other.\n\n**Markdown citation default**: for markdown input, ordinary external links are converted to bottom citations by default. Use `--no-cite` only if the user explicitly wants to keep inline links. Existing HTML input is left as-is.\n\n**API method** (accepts `.md` or `.html`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>] [--source-url <url>] [--no-cite]\n```\n\nAlways pass `--theme` even if it's `default`. Only pass `--color` when explicitly set by the user or EXTEND.md.\n\n**Remote API method** (same script, adds `--remote`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> --remote [--remote-host <host>] [--remote-user <user>] [--remote-port <port>] [--remote-identity-file <path>] [--remote-known-hosts-file <path>] [--remote-strict-host-key-checking yes|no|accept-new] [--remote-connect-timeout <s>] [--remote-proxy-jump <spec>]\n```\n\nAny `--remote-*` flag implies `--remote`. CLI values override account-level then global `remote_publish_*` keys from EXTEND.md. Setting `default_publish_method: remote-api` also enables remote mode without `--remote`.\n\n**`draft/add` payload rules**:\n- Endpoint: `POST https://api.weixin.qq.com/cgi-bin/draft/add?access_token=ACCESS_TOKEN`\n- `article_type`: `news` (default) or `newspic`\n- For `news`, include `thumb_media_id` (cover required)\n- Always include `need_open_comment` (default `1`) and `only_fans_can_comment` (default `0`) in the request body, even if the CLI doesn't expose them\n- For `news`, optionally include `content_source_url` (original article URL, shown as \"阅读原文\" link, max 1KB). Provide via `--source-url` CLI flag or frontmatter `sourceUrl`/`contentSourceUrl`/`content_source_url`\n\n**Browser method** (accepts `--markdown` or `--html`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>] [--no-cite]\n${BUN_X} {baseDir}/scripts/wechat-article.ts --html <html_file>\n```\n\n### Step 5: Completion Report\n\n```\nWeChat Publishing Complete!\n\nInput: [type] - [path]\nMethod: [API | Browser]\nTheme: [theme] [color if set]\n\nArticle:\n• Title: [title]\n• Summary: [summary]\n• Images: [N] inline\n• Comments: [open/closed], [fans-only/all]    ← API method only\n\nResult:\n✓ Draft saved to WeChat Official Account\n• media_id: [media_id]                         ← API method only\n\nNext Steps (API):\n→ Manage drafts: https://mp.weixin.qq.com (登录后进入「内容管理」→「草稿箱」)\n\nFiles created:\n[• post-to-wechat/YYYY-MM-DD/slug.md (if plain text input)]\n[• slug.html (converted)]\n```\n\n## Feature Comparison\n\n| Feature | Image-Text | Article (API) | Article (Remote API) | Article (Browser) |\n|---------|:---:|:---:|:---:|:---:|\n| Plain text input | ✗ | ✓ | ✓ | ✓ |\n| HTML input | ✗ | ✓ | ✓ | ✓ |\n| Markdown input | Title/content | ✓ | ✓ | ✓ |\n| Multiple images | ✓ (up to 9) | ✓ (inline) | ✓ (inline) | ✓ (inline) |\n| Themes | ✗ | ✓ | ✓ | ✓ |\n| Auto-generate metadata | ✗ | ✓ | ✓ | ✓ |\n| Default cover fallback (`imgs/cover.png`) | ✗ | ✓ | ✓ | ✗ |\n| Comment control | ✗ | ✓ | ✓ | ✗ |\n| Requires Chrome | ✓ | ✗ | ✗ | ✓ |\n| Requires API credentials | ✗ | ✓ | ✓ | ✗ |\n| Requires SSH-reachable server with allowlisted IP | ✗ | ✗ | ✓ | ✗ |\n| Speed | Medium | Fast | Fast | Slow |\n\n## Troubleshooting\n\n| Issue | Fix |\n|-------|-----|\n| Missing API credentials | Follow guided setup in Step 2 |\n| Access token error | Verify credentials valid and not expired |\n| Not logged in (browser) | First run opens browser — scan QR to log in. Set `TELEGRAM_BOT_TOKEN` + `TELEGRAM_CHAT_ID` to receive the QR image via Telegram |\n| Chrome not found | Set `WECHAT_BROWSER_CHROME_PATH` |\n| Title/summary missing | Use auto-generation or provide manually |\n| No cover image | Add frontmatter cover or place `imgs/cover.png` in article directory |\n| Wrong comment defaults | Check `need_open_comment` / `only_fans_can_comment` in EXTEND.md |\n| Paste fails | Check system clipboard permissions |\n| `Remote publish host is required` | Set `--remote-host` or `remote_publish_host` in EXTEND.md |\n| `SOCKS proxy on 127.0.0.1:… not ready` | SSH could not start the tunnel — check key, host, `StrictHostKeyChecking`, or use `--remote-connect-timeout` |\n| `ssh exited early` during remote publish | Verify the user can `ssh` non-interactively to the server; raise `--remote-connect-timeout` if the link is slow |\n| Remote API call returns `errcode 40164` (invalid IP) | The remote server's egress IP is not on WeChat's allowlist; add it in 公众号设置 → IP 白名单 |\n\n## References\n\n| File | Content |\n|------|---------|\n| `references/image-text-posting.md` | Image-text parameters, auto-compression |\n| `references/article-posting.md` | Article themes, image handling |\n| `references/multi-account.md` | Multi-account compatibility, credentials, Chrome profiles, CLI |\n| `references/api-setup.md` | Guided credential setup |\n| `references/config/first-time-setup.md` | First-time EXTEND.md setup |\n\n## Extension Support\n\nCustom configurations via EXTEND.md. See \"Preferences\" for paths and supported options.\n\nFile v1.118.2:_meta.json\n\n{\n  \"ownerId\": \"kn7csrrndw79hpke5d0gsnx93d82k67r\",\n  \"slug\": \"baoyu-post-to-wechat\",\n  \"version\": \"1.118.2\",\n  \"publishedAt\": 1781326880839\n}\n\nFile v1.118.2:references/api-setup.md\n\n# API Credential Setup\n\nGuided setup when `WECHAT_APP_ID` / `WECHAT_APP_SECRET` are missing. Invoked by Step 2 of the article-posting workflow.\n\n## Detection\n\nLook for the credentials in this order:\n\n1. Env vars `WECHAT_APP_ID` / `WECHAT_APP_SECRET`\n2. `<cwd>/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n3. `$HOME/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n\nIf none are present, run the guided setup below.\n\n## Guided Setup\n\nShow this message to the user and ask where to save:\n\n```\nWeChat API credentials not found.\n\nTo obtain credentials:\n1. Visit https://mp.weixin.qq.com\n2. Go to: 开发 → 基本配置\n3. Copy AppID and AppSecret\n\nWhere to save?\nA) Project-level: .baoyu-skills/.env (this project only)\nB) User-level: ~/.baoyu-skills/.env (all projects)\n```\n\nAfter they choose a location, collect the values (prefer a user-input tool, fall back to a numbered prompt per the User Input Tools rule in SKILL.md) and append:\n\n```\nWECHAT_APP_ID=<user_input>\nWECHAT_APP_SECRET=<user_input>\n```\n\n## Multi-Account Variant\n\nIf the user has multiple accounts configured (`accounts:` block in EXTEND.md), use prefixed keys instead — see `multi-account.md` → \"Credential Resolution\".\n\nFile v1.118.2:references/article-posting.md\n\n# Article Posting (文章发表)\n\nPost markdown articles to WeChat Official Account with full formatting support.\n\n## Usage\n\n```bash\n# Post markdown article\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md\n\n# With theme\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --theme grace\n\n# Disable bottom citations for ordinary external links\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --no-cite\n\n# With explicit options\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --author \"作者名\" --summary \"摘要\"\n```\n\n## Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `--markdown <path>` | Markdown file to convert and post |\n| `--theme <name>` | Theme: default, grace, simple, modern |\n| `--no-cite` | Keep ordinary external links inline instead of converting them to bottom citations |\n| `--title <text>` | Override title (auto-extracted from markdown) |\n| `--author <name>` | Author name |\n| `--summary <text>` | Article summary |\n| `--html <path>` | Pre-rendered HTML file (alternative to markdown) |\n| `--profile <dir>` | Chrome profile directory |\n\n## Markdown Format\n\n```markdown\n---\ntitle: Article Title\nauthor: Author Name\n---\n\n# Title (becomes article title)\n\nRegular paragraph with **bold** and *italic*.\n\n## Section Header\n\n![Image description](./image.png)\n\n- List item 1\n- List item 2\n\n> Blockquote text\n\n[Link text](https://example.com)\n```\n\nMarkdown mode converts ordinary external links into bottom citations by default for WeChat-friendly output. Use `--no-cite` to disable that behavior.\n\n## Image Handling\n\n1. **Parse**: Images in markdown are replaced with `WECHATIMGPH_N`\n2. **Render**: HTML is generated with placeholders in text\n3. **Paste**: HTML content is pasted into WeChat editor\n4. **Replace**: For each placeholder:\n   - Find and select the placeholder text\n   - Scroll into view\n   - Press Backspace to delete the placeholder\n   - Paste the image from clipboard\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `wechat-article.ts` | Main article publishing script |\n| `md-to-wechat.ts` | Markdown to HTML with placeholders |\n| `md/render.ts` | Markdown rendering with themes |\n\n## Example Session\n\n```\nUser: /post-to-wechat --markdown ./article.md\n\nClaude:\n1. Parses markdown, finds 5 images\n2. Generates HTML with placeholders\n3. Opens Chrome, navigates to WeChat editor\n4. Pastes HTML content\n5. For each image:\n   - Selects WECHATIMGPH_1\n   - Scrolls into view\n   - Presses Backspace to delete\n   - Pastes image\n6. Reports: \"Article composed with 5 images.\"\n```\n\nFile v1.118.2:references/config/first-time-setup.md\n\n---\nname: first-time-setup\ndescription: First-time setup flow for baoyu-post-to-wechat preferences\n---\n\n# First-Time Setup\n\n## Overview\n\nWhen no EXTEND.md is found, guide user through preference setup.\n\n**BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:\n- Ask about content or files to publish\n- Ask about themes or publishing methods\n- Proceed to content conversion or publishing\n\nONLY ask the questions in this setup flow, save EXTEND.md, then continue.\n\n## Setup Flow\n\n```\nNo EXTEND.md found\n        |\n        v\n+---------------------+\n| AskUserQuestion     |\n| (all questions)     |\n+---------------------+\n        |\n        v\n+---------------------+\n| Create EXTEND.md    |\n+---------------------+\n        |\n        v\n    Continue to Step 1\n```\n\n## Questions\n\n**Language**: Use user's input language or saved language preference.\n\nUse AskUserQuestion with ALL questions in ONE call:\n\n### Question 1: Default Theme\n\n```yaml\nheader: \"Theme\"\nquestion: \"Default theme for article conversion?\"\noptions:\n  - label: \"default (Recommended)\"\n    description: \"Classic layout - centered title with border, white-on-color H2 (default: blue)\"\n  - label: \"grace\"\n    description: \"Elegant - text shadows, rounded cards, refined blockquotes (default: purple)\"\n  - label: \"simple\"\n    description: \"Minimal modern - asymmetric rounded corners, clean whitespace (default: green)\"\n  - label: \"modern\"\n    description: \"Large rounded corners, pill headings, spacious (default: orange)\"\n```\n\n### Question 2: Default Color\n\n```yaml\nheader: \"Color\"\nquestion: \"Default color preset? (theme default if not set)\"\noptions:\n  - label: \"Theme default (Recommended)\"\n    description: \"Use the theme's built-in default color\"\n  - label: \"blue\"\n    description: \"#0F4C81 经典蓝\"\n  - label: \"red\"\n    description: \"#A93226 中国红\"\n  - label: \"green\"\n    description: \"#009874 翡翠绿\"\n```\n\nNote: User can choose \"Other\" to type any preset name (vermilion, yellow, purple, sky, rose, olive, black, gray, pink, orange) or hex value.\n\n### Question 3: Default Publishing Method\n\n```yaml\nheader: \"Method\"\nquestion: \"Default publishing method?\"\noptions:\n  - label: \"api (Recommended)\"\n    description: \"Fast, requires API credentials (AppID + AppSecret)\"\n  - label: \"browser\"\n    description: \"Slow, requires Chrome and login session\"\n  - label: \"remote-api\"\n    description: \"Fast, tunnels WeChat API calls through SSH to a server whose IP is on the WeChat allowlist\"\n```\n\nIf the user selects `remote-api`, prompt for `remote_publish_host` and (optionally) `remote_publish_user`, `remote_publish_identity_file`. These can also be filled in later by editing EXTEND.md.\n\n### Question 4: Default Author\n\n```yaml\nheader: \"Author\"\nquestion: \"Default author name for articles?\"\noptions:\n  - label: \"No default\"\n    description: \"Leave empty, specify per article\"\n```\n\nNote: User will likely choose \"Other\" to type their author name.\n\n### Question 5: Open Comments\n\n```yaml\nheader: \"Comments\"\nquestion: \"Enable comments on articles by default?\"\noptions:\n  - label: \"Yes (Recommended)\"\n    description: \"Allow readers to comment on articles\"\n  - label: \"No\"\n    description: \"Disable comments by default\"\n```\n\n### Question 6: Fans-Only Comments\n\n```yaml\nheader: \"Fans only\"\nquestion: \"Restrict comments to followers only?\"\noptions:\n  - label: \"No (Recommended)\"\n    description: \"All readers can comment\"\n  - label: \"Yes\"\n    description: \"Only followers can comment\"\n```\n\n### Question 7: Save Location\n\n```yaml\nheader: \"Save\"\nquestion: \"Where to save preferences?\"\noptions:\n  - label: \"Project (Recommended)\"\n    description: \".baoyu-skills/ (this project only)\"\n  - label: \"User\"\n    description: \"~/.baoyu-skills/ (all projects)\"\n```\n\n## Save Locations\n\n| Choice | Path | Scope |\n|--------|------|-------|\n| Project | `.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | Current project |\n| User | `~/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | All projects |\n\n## After Setup\n\n1. Create directory if needed\n2. Write EXTEND.md\n3. Confirm: \"Preferences saved to [path]\"\n4. Continue to Step 0 (load the saved preferences)\n\n## EXTEND.md Template\n\n### Single Account (Default)\n\n```md\ndefault_theme: [default/grace/simple/modern]\ndefault_color: [preset name, hex, or empty for theme default]\ndefault_publish_method: [api/browser/remote-api]\ndefault_author: [author name or empty]\nneed_open_comment: [1/0]\nonly_fans_can_comment: [1/0]\nchrome_profile_path:\n\n# Remote API publishing — only fill in if default_publish_method is remote-api\n# or you plan to pass --remote on the CLI.\nremote_publish_host:\nremote_publish_user:\nremote_publish_port:\nremote_publish_identity_file:\nremote_publish_known_hosts_file:\nremote_publish_strict_host_key_checking:\nremote_publish_connect_timeout:\nremote_publish_proxy_jump:\n```\n\nRaw `ssh` / `scp` options are intentionally not supported; only the typed keys above are honored. Authentication is SSH key only.\n\n### Multi-Account\n\n```md\ndefault_theme: [default/grace/simple/modern]\ndefault_color: [preset name, hex, or empty for theme default]\n\naccounts:\n  - name: [display name]\n    alias: [short key, e.g. \"baoyu\"]\n    default: true\n    default_publish_method: [api/browser/remote-api]\n    default_author: [author name]\n    need_open_comment: [1/0]\n    only_fans_can_comment: [1/0]\n    app_id: [WeChat App ID, optional]\n    app_secret: [WeChat App Secret, optional]\n    # Remote API publishing (optional, per-account override of globals)\n    remote_publish_host:\n    remote_publish_user:\n    remote_publish_identity_file:\n  - name: [second account name]\n    alias: [short key, e.g. \"ai-tools\"]\n    default_publish_method: [api/browser/remote-api]\n    default_author: [author name]\n    need_open_comment: [1/0]\n    only_fans_can_comment: [1/0]\n```\n\n## Adding More Accounts Later\n\nAfter initial setup, users can add accounts by editing EXTEND.md:\n\n1. Add an `accounts:` block with list items\n2. Move per-account settings (author, publish method, comments) into each account entry\n3. Keep global settings (theme, color) at the top level\n4. Each account needs a unique `alias` (used for CLI `--account` arg and Chrome profile naming)\n5. Set `default: true` on the primary account\n\n## Modifying Preferences Later\n\nUsers can edit EXTEND.md directly or delete it to trigger setup again.\n\nFile v1.118.2:references/image-text-posting.md\n\n# Image-Text Posting (贴图发表, formerly 图文)\n\nPost image-text messages with multiple images to WeChat Official Account.\n\n> **Note**: WeChat has renamed \"图文\" to \"贴图\" in the Official Account menu (as of 2026).\n\n## Usage\n\n```bash\n# Post with images and markdown file (title/content extracted automatically)\n${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/\n\n# Post with explicit title and content\n${BUN_X} ./scripts/wechat-browser.ts --title \"标题\" --content \"内容\" --image img1.png --image img2.png\n\n# Save as draft\n${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/ --submit\n```\n\n## Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `--markdown <path>` | Markdown file for title/content extraction |\n| `--images <dir>` | Directory containing images (sorted by name) |\n| `--title <text>` | Article title (max 20 chars, auto-compressed if too long) |\n| `--content <text>` | Article content (max 1000 chars, auto-compressed if too long) |\n| `--image <path>` | Single image file (can be repeated) |\n| `--submit` | Save as draft (default: preview only) |\n| `--profile <dir>` | Chrome profile directory |\n\n## Auto Title/Content from Markdown\n\nWhen using `--markdown`, the script:\n\n1. **Parses frontmatter** for title and author:\n   ```yaml\n   ---\n   title: 文章标题\n   author: 作者名\n   ---\n   ```\n\n2. **Falls back to H1** if no frontmatter title:\n   ```markdown\n   # 这将成为标题\n   ```\n\n3. **Compresses title** to 20 characters if too long:\n   - Original: \"如何在一天内彻底重塑你的人生\"\n   - Compressed: \"一天彻底重塑你的人生\"\n\n4. **Extracts first paragraphs** as content (max 1000 chars)\n\n## Image Directory Mode\n\nWhen using `--images <dir>`:\n\n- All PNG/JPG files in directory are uploaded\n- Files are sorted alphabetically by name\n- Naming convention: `01-cover.png`, `02-content.png`, etc.\n\n## Constraints\n\n| Field | Max Length | Notes |\n|-------|------------|-------|\n| Title | 20 chars | Auto-compressed if longer |\n| Content | 1000 chars | Auto-compressed if longer |\n| Images | 9 max | WeChat limit |\n\n## Example Session\n\n```\nUser: /post-to-wechat --markdown ./article.md --images ./xhs-images/\n\nClaude:\n1. Parses markdown meta:\n   - Title: \"如何在一天内彻底重塑你的人生\" → \"一天内重塑你的人生\"\n   - Author: from frontmatter or default\n2. Extracts content from first paragraphs\n3. Finds 7 images in xhs-images/\n4. Opens Chrome, navigates to WeChat \"图文\" editor\n5. Uploads all images\n6. Fills title and content\n7. Reports: \"Image-text posted with 7 images.\"\n```\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `wechat-browser.ts` | Main image-text posting script |\n| `cdp.ts` | Chrome DevTools Protocol utilities |\n| `copy-to-clipboard.ts` | Clipboard operations |\n\nFile v1.118.2:references/multi-account.md\n\n# Multi-Account Support\n\nDetails for managing multiple WeChat Official Accounts through one EXTEND.md. SKILL.md only covers single-account flow and the selection prompt — read this file when the user has an `accounts:` block, asks to publish to a specific account, or needs per-account credentials.\n\n## Compatibility\n\n| Condition | Mode | Behavior |\n|-----------|------|----------|\n| No `accounts` block | Single-account | Original behavior, no changes |\n| `accounts` with 1 entry | Single-account | Auto-select, no prompt |\n| `accounts` with 2+ entries | Multi-account | Prompt to select before publishing |\n| `accounts` with `default: true` | Multi-account | Pre-select default; user can switch |\n\n## EXTEND.md Example\n\n```md\ndefault_theme: default\ndefault_color: blue\n\naccounts:\n  - name: 宝玉的技术分享\n    alias: baoyu\n    default: true\n    default_publish_method: api\n    default_author: 宝玉\n    need_open_comment: 1\n    only_fans_can_comment: 0\n    app_id: your_wechat_app_id\n    app_secret: your_wechat_app_secret\n  - name: AI工具集\n    alias: ai-tools\n    default_publish_method: browser\n    default_author: AI工具集\n    need_open_comment: 1\n    only_fans_can_comment: 0\n```\n\n## Per-Account vs Global Keys\n\n**Per-account** (also accepted globally as fallback): `default_publish_method`, `default_author`, `need_open_comment`, `only_fans_can_comment`, `app_id`, `app_secret`, `chrome_profile_path`, `remote_publish_host`, `remote_publish_user`, `remote_publish_port`, `remote_publish_identity_file`, `remote_publish_known_hosts_file`, `remote_publish_strict_host_key_checking`, `remote_publish_connect_timeout`, `remote_publish_proxy_jump`.\n\n**Global-only** (always shared): `default_theme`, `default_color`.\n\n## Account Selection (Step 0.5)\n\nInsert between Step 0 (Load EXTEND.md) and Step 1 (Determine input type):\n\n```\nif no accounts block:\n    → single-account mode (original behavior)\nelif accounts.length == 1:\n    → auto-select the only account\nelif --account <alias> CLI arg:\n    → select matching account\nelif one account has default: true:\n    → pre-select, display: \"Using account: <name> (--account to switch)\"\nelse:\n    → prompt user to choose from the list\n```\n\n## Credential Resolution (API Method)\n\nFor the selected account with alias `{alias}`, try in this order (first hit wins):\n\n1. `app_id` / `app_secret` inline in the EXTEND.md account block\n2. Env vars `WECHAT_{ALIAS}_APP_ID` / `WECHAT_{ALIAS}_APP_SECRET` (alias uppercased, hyphens → underscores)\n3. `.baoyu-skills/.env` with the prefixed key `WECHAT_{ALIAS}_APP_ID`\n4. `~/.baoyu-skills/.env` with the prefixed key\n5. Fallback to unprefixed `WECHAT_APP_ID` / `WECHAT_APP_SECRET`\n\n### .env Multi-Account Example\n\n```bash\n# Account: baoyu\nWECHAT_BAOYU_APP_ID=your_wechat_app_id\nWECHAT_BAOYU_APP_SECRET=your_wechat_app_secret\n\n# Account: ai-tools\nWECHAT_AI_TOOLS_APP_ID=your_ai_tools_wechat_app_id\nWECHAT_AI_TOOLS_APP_SECRET=your_ai_tools_wechat_app_secret\n```\n\n## Chrome Profile (Browser Method)\n\nEach account uses an isolated Chrome profile so logins don't collide.\n\n| Source | Path |\n|--------|------|\n| Account `chrome_profile_path` in EXTEND.md | Use as-is |\n| Auto-generated from alias | `{shared_profile_parent}/wechat-{alias}/` |\n| Single-account fallback | Shared default profile |\n\n## CLI `--account` Flag\n\nAll publishing scripts accept `--account <alias>`:\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account ai-tools\n${BUN_X} {baseDir}/scripts/wechat-article.ts --markdown <file> --theme default --account baoyu\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown <file> --images ./photos/ --account baoyu\n```\n\n## Remote API Publishing\n\n`wechat-api.ts` supports a `remote-api` mode that tunnels WeChat API calls through an SSH SOCKS5 dynamic port forward to a server whose IP is on WeChat's allowlist. Markdown rendering, image processing, draft assembly, and HTML rewriting still happen locally; only outbound HTTPS calls to `api.weixin.qq.com` traverse the tunnel. No files are written to the remote host and `AppSecret` never leaves the local process. The remote host needs only `sshd` and outbound network access.\n\n### Per-Account Configuration\n\n```md\ndefault_theme: default\ndefault_color: blue\ndefault_publish_method: browser   # browser remains the default\n\naccounts:\n  - name: 宝玉的技术分享\n    alias: baoyu\n    default: true\n    default_publish_method: api\n    default_author: 宝玉\n    app_id: your_wechat_app_id\n    app_secret: your_wechat_app_secret\n  - name: AI工具集\n    alias: ai-tools\n    default_publish_method: remote-api\n    default_author: AI工具集\n    app_id: your_ai_tools_app_id\n    app_secret: your_ai_tools_app_secret\n    remote_publish_host: ai-tools-server.example.com\n    remote_publish_user: deploy\n    remote_publish_port: 22\n    remote_publish_identity_file: /home/me/.ssh/id_ed25519\n    remote_publish_known_hosts_file: /home/me/.ssh/known_hosts\n    remote_publish_strict_host_key_checking: accept-new\n```\n\nAccount-level `remote_publish_*` values override top-level globals. CLI `--remote-*` flags override both.\n\n### CLI Usage\n\n```bash\n# Use the account's default_publish_method (remote-api here):\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account ai-tools\n\n# Force remote mode regardless of default_publish_method:\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account baoyu --remote --remote-host other-server.example.com\n```\n\n### Security Notes\n\n- Authentication is SSH key only. Passwords and `ssh-askpass` are not used.\n- Only the typed `remote_publish_*` keys are read; raw `ssh` / `scp` options are intentionally not supported.\n- The tunnel forwards raw TCP; TLS verification for `api.weixin.qq.com` is still performed end-to-end by the local process.\n\nFile v1.118.2:scripts/package.json\n\n{\n  \"name\": \"baoyu-post-to-wechat-scripts\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@jsquash/webp\": \"^1.5.0\",\n    \"baoyu-chrome-cdp\": \"^0.1.1\",\n    \"baoyu-md\": \"^0.1.1\",\n    \"jimp\": \"^1.6.0\",\n    \"socks\": \"^2.8.9\"\n  }\n}\n\nFile v1.118.2:skill-card.md\n\n## Description:\n\nPosts content to WeChat Official Account via API or Chrome CDP, supporting article posting from HTML, Markdown, or plain text and image-text posting with multiple images.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[jimliu](https://clawhub.ai/user/jimliu)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and content operators use this skill to prepare and publish WeChat Official Account drafts from Markdown, HTML, plain text, or image collections. It supports local browser publishing, direct WeChat API publishing, remote API publishing through an allowlisted server, and multi-account configuration.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill handles WeChat login sessions and AppSecrets during publishing workflows.\n\nMitigation: Install only when the publisher is trusted, keep AppSecrets in a protected secret store or locked-down local file, and avoid enabling Telegram QR forwarding unless the bot and chat are fully controlled.\n\nRisk: Untrusted Markdown or image URLs could affect the content prepared for publication.\n\nMitigation: Review article inputs and image sources before publishing, and process only content from trusted sources.\n\nRisk: Remote API publishing depends on SSH tunneling through a server whose IP is allowlisted by WeChat.\n\nMitigation: Use key-only SSH access, verify the remote host configuration, and confirm the allowlisted server is controlled by the operator.\n\nRisk: Runtime installation through npx can execute a freshly resolved Bun runtime.\n\nMitigation: Prefer a preinstalled trusted Bun runtime over invoking npx to fetch Bun at execution time.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/jimliu/skills/baoyu-post-to-wechat)\n- [Project homepage](https://github.com/JimLiu/baoyu-skills#baoyu-post-to-wechat)\n- [API credential setup](references/api-setup.md)\n- [Article posting](references/article-posting.md)\n- [Image-text posting](references/image-text-posting.md)\n- [Multi-account support](references/multi-account.md)\n- [First-time setup](references/config/first-time-setup.md)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Configuration, Markdown, Text, Files]\n\n**Output Format:** [Markdown guidance with inline shell commands and status reports]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May create local Markdown drafts and preference files, and may trigger browser or WeChat API publishing workflows when the agent executes the skill.]\n\n## Skill Version(s):\n\n1.118.2 (source: frontmatter and server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.118.1: 31 files, 102646 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (6317b), references/image-text-posting.md (2833b), references/multi-account.md (5807b), scripts/bun.lock (38871b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard-mac.test.ts (916b), scripts/copy-to-clipboard.ts (14377b), scripts/md-to-wechat.ts (5803b), scripts/package.json (244b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (30130b), scripts/wechat-article-focus.test.ts (2741b), scripts/wechat-article.ts (48947b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (10079b), scripts/wechat-extend-config.ts (14593b), scripts/wechat-http.test.ts (5100b), scripts/wechat-http.ts (2677b), scripts/wechat-image-loader.ts (2526b), scripts/wechat-image-processor.ts (8524b), scripts/wechat-remote-publish.test.ts (5647b), scripts/wechat-remote-publish.ts (8007b), scripts/wechat-socks-http.test.ts (6837b), scripts/wechat-socks-http.ts (6917b), skill-card.md (2579b), SKILL.md (14519b), _meta.json (141b)\n\nFile v1.118.1:SKILL.md\n\n---\nname: baoyu-post-to-wechat\ndescription: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-text posting (贴图, formerly 图文) with multiple images. Markdown article workflows default to converting ordinary external links into bottom citations for WeChat-friendly output. Use when user mentions \"发布公众号\", \"post to wechat\", \"微信公众号\", or \"贴图/图文/文章\".\nversion: 1.118.1\nmetadata:\n  openclaw:\n    homepage: https://github.com/JimLiu/baoyu-skills#baoyu-post-to-wechat\n    requires:\n      anyBins:\n        - bun\n        - npx\n---\n\n# Post to WeChat Official Account\n\n## User Input Tools\n\nWhen this skill prompts the user, follow this tool-selection rule (priority order):\n\n1. **Prefer built-in user-input tools** exposed by the current agent runtime — e.g., `AskUserQuestion`, `request_user_input`, `clarify`, `ask_user`, or any equivalent.\n2. **Fallback**: if no such tool exists, emit a numbered plain-text message and ask the user to reply with the chosen number/answer for each question.\n3. **Batching**: if the tool supports multiple questions per call, combine all applicable questions into a single call; if only single-question, ask them one at a time in priority order.\n\nConcrete `AskUserQuestion` references below are examples — substitute the local equivalent in other runtimes.\n\n## Language\n\nRespond in the user's language. If they write in Chinese, reply in Chinese; if English, English. Keep technical tokens (paths, flags, field names) in English.\n\n## Script Directory\n\n`{baseDir}` = this SKILL.md's directory. Resolve `${BUN_X}`: prefer `bun`; else `npx -y bun`; else suggest `brew install oven-sh/bun/bun`.\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/wechat-browser.ts` | Image-text posts (图文) |\n| `scripts/wechat-article.ts` | Article posting via browser (文章) |\n| `scripts/wechat-api.ts` | Article posting via API (文章) |\n| `scripts/md-to-wechat.ts` | Markdown → WeChat-ready HTML with image placeholders |\n| `scripts/check-permissions.ts` | Verify environment & permissions |\n\n## Preferences (EXTEND.md)\n\nCheck these paths in order; first hit wins:\n\n| Path | Scope |\n|------|-------|\n| `.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | Project |\n| `${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | XDG |\n| `$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | User home |\n\nFound → read, parse, apply. Not found → run first-time setup (`references/config/first-time-setup.md`) before anything else.\n\n**Minimum keys** (case-insensitive, accept `1/0` or `true/false`):\n\n| Key | Default | Mapping |\n|-----|---------|---------|\n| `default_author` | empty | Fallback for `author` when CLI/frontmatter not provided |\n| `need_open_comment` | `1` | `articles[].need_open_comment` in `draft/add` |\n| `only_fans_can_comment` | `0` | `articles[].only_fans_can_comment` in `draft/add` |\n\n**Recommended EXTEND.md**:\n\n```md\ndefault_theme: default\ndefault_color: blue\ndefault_publish_method: browser\ndefault_author: 宝玉\nneed_open_comment: 1\nonly_fans_can_comment: 0\nchrome_profile_path: /path/to/chrome/profile\n\n# Remote API publishing (optional) — only set if WeChat's IP allowlist\n# excludes your local machine. See \"Remote API Method\" below.\n# remote_publish_host: server.example.com\n# remote_publish_user: deploy\n# remote_publish_port: 22\n# remote_publish_identity_file: ~/.ssh/id_ed25519\n# remote_publish_known_hosts_file: ~/.ssh/known_hosts\n# remote_publish_strict_host_key_checking: accept-new\n# remote_publish_connect_timeout: 10\n# remote_publish_proxy_jump: bastion.example.com\n```\n\nRaw `ssh` / `scp` options are intentionally not supported; only the typed keys above are honored. Authentication is SSH key only (no passwords).\n\n**Theme options**: default, grace, simple, modern. **Color presets**: blue, green, vermilion, yellow, purple, sky, rose, olive, black, gray, pink, red, orange (or hex).\n\n**Value priority**: CLI args → frontmatter → EXTEND.md (account-level → global) → skill defaults.\n\n## Multi-Account Support\n\nEXTEND.md supports an `accounts:` block for managing multiple Official Accounts. With 2+ entries, the workflow inserts a Step 0.5 to prompt for account selection (or auto-selects based on `default: true` or `--account <alias>`).\n\nFull details — compatibility rules, per-account keys, credential resolution, per-account Chrome profiles, CLI usage — in `references/multi-account.md`.\n\n## Pre-flight Check (Optional)\n\nBefore first use, suggest the environment check (user can skip):\n\n```bash\n${BUN_X} {baseDir}/scripts/check-permissions.ts\n```\n\nChecks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, API credentials, Chrome conflicts.\n\n| Check fails | Fix |\n|-------------|-----|\n| Chrome | Install Chrome or set `WECHAT_BROWSER_CHROME_PATH` |\n| Profile dir | Shared profile at `baoyu-skills/chrome-profile` |\n| Bun runtime | `brew install oven-sh/bun/bun` or `npm install -g bun` |\n| Accessibility (macOS) | System Settings → Privacy & Security → Accessibility → enable terminal app |\n| Clipboard copy | Ensure Swift/AppKit (macOS: `xcode-select --install`) |\n| Paste keystroke (Linux) | Install `xdotool` (X11) or `ydotool` (Wayland) |\n| API credentials | Follow guided setup in Step 2, or set in `.baoyu-skills/.env` |\n\n## Image-Text Posting (图文)\n\nShort posts with multiple images (up to 9):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown article.md --images ./images/\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --title \"标题\" --content \"内容\" --image img.png --submit\n```\n\nDetails: `references/image-text-posting.md`.\n\n## Article Posting Workflow (文章)\n\n```\n- [ ] Step 0: Load preferences (EXTEND.md)\n- [ ] Step 0.5: Resolve account (multi-account only — see references/multi-account.md)\n- [ ] Step 1: Determine input type\n- [ ] Step 2: Select method and configure credentials\n- [ ] Step 3: Resolve theme/color and validate metadata\n- [ ] Step 4: Publish to WeChat\n- [ ] Step 5: Report completion\n```\n\n### Step 0: Load Preferences\n\nCheck and load EXTEND.md (see \"Preferences\" above). If not found, complete first-time setup before any other questions. Resolve and cache for later steps: `default_theme`, `default_color`, `default_author`, `need_open_comment`, `only_fans_can_comment`.\n\n### Step 1: Determine Input Type\n\n| Input | Detection | Next |\n|-------|-----------|------|\n| HTML file | Path ends `.html`, file exists | Skip to Step 3 |\n| Markdown file | Path ends `.md`, file exists | Step 2 |\n| Plain text | Not a file path, or file doesn't exist | Save to markdown, then Step 2 |\n\n**Plain-text handling**:\n\n1. Generate slug (first 2-4 meaningful words, kebab-case; translate Chinese to English for the slug).\n2. Save to `post-to-wechat/YYYY-MM-DD/<slug>.md` (create directory if needed).\n3. Continue as a markdown file.\n\n### Step 2: Select Publishing Method and Configure\n\nAsk method unless specified in EXTEND.md or CLI:\n\n| Method | Speed | Requires |\n|--------|-------|----------|\n| `api` (Recommended) | Fast | API credentials (local IP allowlisted) |\n| `browser` | Slow | Chrome + logged-in session |\n| `remote-api` | Fast | API credentials + an SSH-reachable server whose IP is on the WeChat allowlist |\n\n**API selected + missing credentials** → run guided setup per `references/api-setup.md` (writes to `.baoyu-skills/.env`).\n\n**`remote-api` method**: WeChat's \"公众号设置 → IP 白名单\" often limits API access to one or two fixed IPs. If your local machine's IP is not on that list but a cloud server's is, use `remote-api`: all markdown rendering, image processing, draft assembly, and HTML rewriting still happen locally, and only the outbound HTTPS calls to `api.weixin.qq.com` (token, uploadimg, add_material, draft/add) are tunneled through an SSH SOCKS5 dynamic port forward (`ssh -N -D`) so that WeChat sees the remote server as the source IP. No files are written to the remote host; `AppSecret` never leaves the local process. Requires only `sshd` and outbound network on the remote host — no Python, no agent process. See \"Remote API Method\" below.\n\n### Step 3: Resolve Theme/Color and Validate Metadata\n\n1. **Theme**: CLI `--theme` → EXTEND.md `default_theme` → `default` (first match wins; do NOT ask if resolved).\n2. **Color**: CLI `--color` → EXTEND.md `default_color` → omit (theme default applies).\n3. **Validate metadata** (frontmatter for markdown, meta tags for HTML):\n\n| Field | Missing → |\n|-------|-----------|\n| Title | Ask, or press Enter to auto-generate from content |\n| Summary | Frontmatter `description` → `summary` → ask or auto-generate |\n| Author | CLI `--author` → frontmatter `author` → EXTEND.md `default_author` |\n\nAuto-generation: title = first H1/H2 or first sentence; summary = first paragraph, truncated to 120 chars.\n\n4. **Cover image** (required for API `article_type=news`): CLI `--cover` → frontmatter (`coverImage` / `featureImage` / `cover` / `image`) → `imgs/cover.png` → first inline image → stop and request one if still missing.\n\n### Step 4: Publish\n\n**Important — never pre-convert markdown to HTML.** Publishing scripts handle the conversion internally and the two methods render images differently: API renders `<img>` tags for upload, browser uses placeholders for paste-and-replace. Passing a pre-converted HTML breaks one or the other.\n\n**Markdown citation default**: for markdown input, ordinary external links are converted to bottom citations by default. Use `--no-cite` only if the user explicitly wants to keep inline links. Existing HTML input is left as-is.\n\n**API method** (accepts `.md` or `.html`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>] [--no-cite]\n```\n\nAlways pass `--theme` even if it's `default`. Only pass `--color` when explicitly set by the user or EXTEND.md.\n\n**Remote API method** (same script, adds `--remote`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> --remote [--remote-host <host>] [--remote-user <user>] [--remote-port <port>] [--remote-identity-file <path>] [--remote-known-hosts-file <path>] [--remote-strict-host-key-checking yes|no|accept-new] [--remote-connect-timeout <s>] [--remote-proxy-jump <spec>]\n```\n\nAny `--remote-*` flag implies `--remote`. CLI values override account-level then global `remote_publish_*` keys from EXTEND.md. Setting `default_publish_method: remote-api` also enables remote mode without `--remote`.\n\n**`draft/add` payload rules**:\n- Endpoint: `POST https://api.weixin.qq.com/cgi-bin/draft/add?access_token=ACCESS_TOKEN`\n- `article_type`: `news` (default) or `newspic`\n- For `news`, include `thumb_media_id` (cover required)\n- Always include `need_open_comment` (default `1`) and `only_fans_can_comment` (default `0`) in the request body, even if the CLI doesn't expose them\n\n**Browser method** (accepts `--markdown` or `--html`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>] [--no-cite]\n${BUN_X} {baseDir}/scripts/wechat-article.ts --html <html_file>\n```\n\n### Step 5: Completion Report\n\n```\nWeChat Publishing Complete!\n\nInput: [type] - [path]\nMethod: [API | Browser]\nTheme: [theme] [color if set]\n\nArticle:\n• Title: [title]\n• Summary: [summary]\n• Images: [N] inline\n• Comments: [open/closed], [fans-only/all]    ← API method only\n\nResult:\n✓ Draft saved to WeChat Official Account\n• media_id: [media_id]                         ← API method only\n\nNext Steps (API):\n→ Manage drafts: https://mp.weixin.qq.com (登录后进入「内容管理」→「草稿箱」)\n\nFiles created:\n[• post-to-wechat/YYYY-MM-DD/slug.md (if plain text input)]\n[• slug.html (converted)]\n```\n\n## Feature Comparison\n\n| Feature | Image-Text | Article (API) | Article (Remote API) | Article (Browser) |\n|---------|:---:|:---:|:---:|:---:|\n| Plain text input | ✗ | ✓ | ✓ | ✓ |\n| HTML input | ✗ | ✓ | ✓ | ✓ |\n| Markdown input | Title/content | ✓ | ✓ | ✓ |\n| Multiple images | ✓ (up to 9) | ✓ (inline) | ✓ (inline) | ✓ (inline) |\n| Themes | ✗ | ✓ | ✓ | ✓ |\n| Auto-generate metadata | ✗ | ✓ | ✓ | ✓ |\n| Default cover fallback (`imgs/cover.png`) | ✗ | ✓ | ✓ | ✗ |\n| Comment control | ✗ | ✓ | ✓ | ✗ |\n| Requires Chrome | ✓ | ✗ | ✗ | ✓ |\n| Requires API credentials | ✗ | ✓ | ✓ | ✗ |\n| Requires SSH-reachable server with allowlisted IP | ✗ | ✗ | ✓ | ✗ |\n| Speed | Medium | Fast | Fast | Slow |\n\n## Troubleshooting\n\n| Issue | Fix |\n|-------|-----|\n| Missing API credentials | Follow guided setup in Step 2 |\n| Access token error | Verify credentials valid and not expired |\n| Not logged in (browser) | First run opens browser — scan QR to log in. Set `TELEGRAM_BOT_TOKEN` + `TELEGRAM_CHAT_ID` to receive the QR image via Telegram |\n| Chrome not found | Set `WECHAT_BROWSER_CHROME_PATH` |\n| Title/summary missing | Use auto-generation or provide manually |\n| No cover image | Add frontmatter cover or place `imgs/cover.png` in article directory |\n| Wrong comment defaults | Check `need_open_comment` / `only_fans_can_comment` in EXTEND.md |\n| Paste fails | Check system clipboard permissions |\n| `Remote publish host is required` | Set `--remote-host` or `remote_publish_host` in EXTEND.md |\n| `SOCKS proxy on 127.0.0.1:… not ready` | SSH could not start the tunnel — check key, host, `StrictHostKeyChecking`, or use `--remote-connect-timeout` |\n| `ssh exited early` during remote publish | Verify the user can `ssh` non-interactively to the server; raise `--remote-connect-timeout` if the link is slow |\n| Remote API call returns `errcode 40164` (invalid IP) | The remote server's egress IP is not on WeChat's allowlist; add it in 公众号设置 → IP 白名单 |\n\n## References\n\n| File | Content |\n|------|---------|\n| `references/image-text-posting.md` | Image-text parameters, auto-compression |\n| `references/article-posting.md` | Article themes, image handling |\n| `references/multi-account.md` | Multi-account compatibility, credentials, Chrome profiles, CLI |\n| `references/api-setup.md` | Guided credential setup |\n| `references/config/first-time-setup.md` | First-time EXTEND.md setup |\n\n## Extension Support\n\nCustom configurations via EXTEND.md. See \"Preferences\" for paths and supported options.\n\nFile v1.118.1:_meta.json\n\n{\n  \"ownerId\": \"kn7csrrndw79hpke5d0gsnx93d82k67r\",\n  \"slug\": \"baoyu-post-to-wechat\",\n  \"version\": \"1.118.1\",\n  \"publishedAt\": 1780284676016\n}\n\nFile v1.118.1:references/api-setup.md\n\n# API Credential Setup\n\nGuided setup when `WECHAT_APP_ID` / `WECHAT_APP_SECRET` are missing. Invoked by Step 2 of the article-posting workflow.\n\n## Detection\n\nLook for the credentials in this order:\n\n1. Env vars `WECHAT_APP_ID` / `WECHAT_APP_SECRET`\n2. `<cwd>/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n3. `$HOME/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n\nIf none are present, run the guided setup below.\n\n## Guided Setup\n\nShow this message to the user and ask where to save:\n\n```\nWeChat API credentials not found.\n\nTo obtain credentials:\n1. Visit https://mp.weixin.qq.com\n2. Go to: 开发 → 基本配置\n3. Copy AppID and AppSecret\n\nWhere to save?\nA) Project-level: .baoyu-skills/.env (this project only)\nB) User-level: ~/.baoyu-skills/.env (all projects)\n```\n\nAfter they choose a location, collect the values (prefer a user-input tool, fall back to a numbered prompt per the User Input Tools rule in SKILL.md) and append:\n\n```\nWECHAT_APP_ID=<user_input>\nWECHAT_APP_SECRET=<user_input>\n```\n\n## Multi-Account Variant\n\nIf the user has multiple accounts configured (`accounts:` block in EXTEND.md), use prefixed keys instead — see `multi-account.md` → \"Credential Resolution\".\n\nFile v1.118.1:references/article-posting.md\n\n# Article Posting (文章发表)\n\nPost markdown articles to WeChat Official Account with full formatting support.\n\n## Usage\n\n```bash\n# Post markdown article\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md\n\n# With theme\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --theme grace\n\n# Disable bottom citations for ordinary external links\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --no-cite\n\n# With explicit options\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --author \"作者名\" --summary \"摘要\"\n```\n\n## Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `--markdown <path>` | Markdown file to convert and post |\n| `--theme <name>` | Theme: default, grace, simple, modern |\n| `--no-cite` | Keep ordinary external links inline instead of converting them to bottom citations |\n| `--title <text>` | Override title (auto-extracted from markdown) |\n| `--author <name>` | Author name |\n| `--summary <text>` | Article summary |\n| `--html <path>` | Pre-rendered HTML file (alternative to markdown) |\n| `--profile <dir>` | Chrome profile directory |\n\n## Markdown Format\n\n```markdown\n---\ntitle: Article Title\nauthor: Author Name\n---\n\n# Title (becomes article title)\n\nRegular paragraph with **bold** and *italic*.\n\n## Section Header\n\n![Image description](./image.png)\n\n- List item 1\n- List item 2\n\n> Blockquote text\n\n[Link text](https://example.com)\n```\n\nMarkdown mode converts ordinary external links into bottom citations by default for WeChat-friendly output. Use `--no-cite` to disable that behavior.\n\n## Image Handling\n\n1. **Parse**: Images in markdown are replaced with `WECHATIMGPH_N`\n2. **Render**: HTML is generated with placeholders in text\n3. **Paste**: HTML content is pasted into WeChat editor\n4. **Replace**: For each placeholder:\n   - Find and select the placeholder text\n   - Scroll into view\n   - Press Backspace to delete the placeholder\n   - Paste the image from clipboard\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `wechat-article.ts` | Main article publishing script |\n| `md-to-wechat.ts` | Markdown to HTML with placeholders |\n| `md/render.ts` | Markdown rendering with themes |\n\n## Example Session\n\n```\nUser: /post-to-wechat --markdown ./article.md\n\nClaude:\n1. Parses markdown, finds 5 images\n2. Generates HTML with placeholders\n3. Opens Chrome, navigates to WeChat editor\n4. Pastes HTML content\n5. For each image:\n   - Selects WECHATIMGPH_1\n   - Scrolls into view\n   - Presses Backspace to delete\n   - Pastes image\n6. Reports: \"Article composed with 5 images.\"\n```\n\nFile v1.118.1:references/config/first-time-setup.md\n\n---\nname: first-time-setup\ndescription: First-time setup flow for baoyu-post-to-wechat preferences\n---\n\n# First-Time Setup\n\n## Overview\n\nWhen no EXTEND.md is found, guide user through preference setup.\n\n**BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:\n- Ask about content or files to publish\n- Ask about themes or publishing methods\n- Proceed to content conversion or publishing\n\nONLY ask the questions in this setup flow, save EXTEND.md, then continue.\n\n## Setup Flow\n\n```\nNo EXTEND.md found\n        |\n        v\n+---------------------+\n| AskUserQuestion     |\n| (all questions)     |\n+---------------------+\n        |\n        v\n+---------------------+\n| Create EXTEND.md    |\n+---------------------+\n        |\n        v\n    Continue to Step 1\n```\n\n## Questions\n\n**Language**: Use user's input language or saved language preference.\n\nUse AskUserQuestion with ALL questions in ONE call:\n\n### Question 1: Default Theme\n\n```yaml\nheader: \"Theme\"\nquestion: \"Default theme for article conversion?\"\noptions:\n  - label: \"default (Recommended)\"\n    description: \"Classic layout - centered title with border, white-on-color H2 (default: blue)\"\n  - label: \"grace\"\n    description: \"Elegant - text shadows, rounded cards, refined blockquotes (default: purple)\"\n  - label: \"simple\"\n    description: \"Minimal modern - asymmetric rounded corners, clean whitespace (default: green)\"\n  - label: \"modern\"\n    description: \"Large rounded corners, pill headings, spacious (default: orange)\"\n```\n\n### Question 2: Default Color\n\n```yaml\nheader: \"Color\"\nquestion: \"Default color preset? (theme default if not set)\"\noptions:\n  - label: \"Theme default (Recommended)\"\n    description: \"Use the theme's built-in default color\"\n  - label: \"blue\"\n    description: \"#0F4C81 经典蓝\"\n  - label: \"red\"\n    description: \"#A93226 中国红\"\n  - label: \"green\"\n    description: \"#009874 翡翠绿\"\n```\n\nNote: User can choose \"Other\" to type any preset name (vermilion, yellow, purple, sky, rose, olive, black, gray, pink, orange) or hex value.\n\n### Question 3: Default Publishing Method\n\n```yaml\nheader: \"Method\"\nquestion: \"Default publishing method?\"\noptions:\n  - label: \"api (Recommended)\"\n    description: \"Fast, requires API credentials (AppID + AppSecret)\"\n  - label: \"browser\"\n    description: \"Slow, requires Chrome and login session\"\n  - label: \"remote-api\"\n    description: \"Fast, tunnels WeChat API calls through SSH to a server whose IP is on the WeChat allowlist\"\n```\n\nIf the user selects `remote-api`, prompt for `remote_publish_host` and (optionally) `remote_publish_user`, `remote_publish_identity_file`. These can also be filled in later by editing EXTEND.md.\n\n### Question 4: Default Author\n\n```yaml\nheader: \"Author\"\nquestion: \"Default author name for articles?\"\noptions:\n  - label: \"No default\"\n    description: \"Leave empty, specify per article\"\n```\n\nNote: User will likely choose \"Other\" to type their author name.\n\n### Question 5: Open Comments\n\n```yaml\nheader: \"Comments\"\nquestion: \"Enable comments on articles by default?\"\noptions:\n  - label: \"Yes (Recommended)\"\n    description: \"Allow readers to comment on articles\"\n  - label: \"No\"\n    description: \"Disable comments by default\"\n```\n\n### Question 6: Fans-Only Comments\n\n```yaml\nheader: \"Fans only\"\nquestion: \"Restrict comments to followers only?\"\noptions:\n  - label: \"No (Recommended)\"\n    description: \"All readers can comment\"\n  - label: \"Yes\"\n    description: \"Only followers can comment\"\n```\n\n### Question 7: Save Location\n\n```yaml\nheader: \"Save\"\nquestion: \"Where to save preferences?\"\noptions:\n  - label: \"Project (Recommended)\"\n    description: \".baoyu-skills/ (this project only)\"\n  - label: \"User\"\n    description: \"~/.baoyu-skills/ (all projects)\"\n```\n\n## Save Locations\n\n| Choice | Path | Scope |\n|--------|------|-------|\n| Project | `.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | Current project |\n| User | `~/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | All projects |\n\n## After Setup\n\n1. Create directory if needed\n2. Write EXTEND.md\n3. Confirm: \"Preferences saved to [path]\"\n4. Continue to Step 0 (load the saved preferences)\n\n## EXTEND.md Template\n\n### Single Account (Default)\n\n```md\ndefault_theme: [default/grace/simple/modern]\ndefault_color: [preset name, hex, or empty for theme default]\ndefault_publish_method: [api/browser/remote-api]\ndefault_author: [author name or empty]\nneed_open_comment: [1/0]\nonly_fans_can_comment: [1/0]\nchrome_profile_path:\n\n# Remote API publishing — only fill in if default_publish_method is remote-api\n# or you plan to pass --remote on the CLI.\nremote_publish_host:\nremote_publish_user:\nremote_publish_port:\nremote_publish_identity_file:\nremote_publish_known_hosts_file:\nremote_publish_strict_host_key_checking:\nremote_publish_connect_timeout:\nremote_publish_proxy_jump:\n```\n\nRaw `ssh` / `scp` options are intentionally not supported; only the typed keys above are honored. Authentication is SSH key only.\n\n### Multi-Account\n\n```md\ndefault_theme: [default/grace/simple/modern]\ndefault_color: [preset name, hex, or empty for theme default]\n\naccounts:\n  - name: [display name]\n    alias: [short key, e.g. \"baoyu\"]\n    default: true\n    default_publish_method: [api/browser/remote-api]\n    default_author: [author name]\n    need_open_comment: [1/0]\n    only_fans_can_comment: [1/0]\n    app_id: [WeChat App ID, optional]\n    app_secret: [WeChat App Secret, optional]\n    # Remote API publishing (optional, per-account override of globals)\n    remote_publish_host:\n    remote_publish_user:\n    remote_publish_identity_file:\n  - name: [second account name]\n    alias: [short key, e.g. \"ai-tools\"]\n    default_publish_method: [api/browser/remote-api]\n    default_author: [author name]\n    need_open_comment: [1/0]\n    only_fans_can_comment: [1/0]\n```\n\n## Adding More Accounts Later\n\nAfter initial setup, users can add accounts by editing EXTEND.md:\n\n1. Add an `accounts:` block with list items\n2. Move per-account settings (author, publish method, comments) into each account entry\n3. Keep global settings (theme, color) at the top level\n4. Each account needs a unique `alias` (used for CLI `--account` arg and Chrome profile naming)\n5. Set `default: true` on the primary account\n\n## Modifying Preferences Later\n\nUsers can edit EXTEND.md directly or delete it to trigger setup again.\n\nFile v1.118.1:references/image-text-posting.md\n\n# Image-Text Posting (贴图发表, formerly 图文)\n\nPost image-text messages with multiple images to WeChat Official Account.\n\n> **Note**: WeChat has renamed \"图文\" to \"贴图\" in the Official Account menu (as of 2026).\n\n## Usage\n\n```bash\n# Post with images and markdown file (title/content extracted automatically)\n${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/\n\n# Post with explicit title and content\n${BUN_X} ./scripts/wechat-browser.ts --title \"标题\" --content \"内容\" --image img1.png --image img2.png\n\n# Save as draft\n${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/ --submit\n```\n\n## Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `--markdown <path>` | Markdown file for title/content extraction |\n| `--images <dir>` | Directory containing images (sorted by name) |\n| `--title <text>` | Article title (max 20 chars, auto-compressed if too long) |\n| `--content <text>` | Article content (max 1000 chars, auto-compressed if too long) |\n| `--image <path>` | Single image file (can be repeated) |\n| `--submit` | Save as draft (default: preview only) |\n| `--profile <dir>` | Chrome profile directory |\n\n## Auto Title/Content from Markdown\n\nWhen using `--markdown`, the script:\n\n1. **Parses frontmatter** for title and author:\n   ```yaml\n   ---\n   title: 文章标题\n   author: 作者名\n   ---\n   ```\n\n2. **Falls back to H1** if no frontmatter title:\n   ```markdown\n   # 这将成为标题\n   ```\n\n3. **Compresses title** to 20 characters if too long:\n   - Original: \"如何在一天内彻底重塑你的人生\"\n   - Compressed: \"一天彻底重塑你的人生\"\n\n4. **Extracts first paragraphs** as content (max 1000 chars)\n\n## Image Directory Mode\n\nWhen using `--images <dir>`:\n\n- All PNG/JPG files in directory are uploaded\n- Files are sorted alphabetically by name\n- Naming convention: `01-cover.png`, `02-content.png`, etc.\n\n## Constraints\n\n| Field | Max Length | Notes |\n|-------|------------|-------|\n| Title | 20 chars | Auto-compressed if longer |\n| Content | 1000 chars | Auto-compressed if longer |\n| Images | 9 max | WeChat limit |\n\n## Example Session\n\n```\nUser: /post-to-wechat --markdown ./article.md --images ./xhs-images/\n\nClaude:\n1. Parses markdown meta:\n   - Title: \"如何在一天内彻底重塑你的人生\" → \"一天内重塑你的人生\"\n   - Author: from frontmatter or default\n2. Extracts content from first paragraphs\n3. Finds 7 images in xhs-images/\n4. Opens Chrome, navigates to WeChat \"图文\" editor\n5. Uploads all images\n6. Fills title and content\n7. Reports: \"Image-text posted with 7 images.\"\n```\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `wechat-browser.ts` | Main image-text posting script |\n| `cdp.ts` | Chrome DevTools Protocol utilities |\n| `copy-to-clipboard.ts` | Clipboard operations |\n\nFile v1.118.1:references/multi-account.md\n\n# Multi-Account Support\n\nDetails for managing multiple WeChat Official Accounts through one EXTEND.md. SKILL.md only covers single-account flow and the selection prompt — read this file when the user has an `accounts:` block, asks to publish to a specific account, or needs per-account credentials.\n\n## Compatibility\n\n| Condition | Mode | Behavior |\n|-----------|------|----------|\n| No `accounts` block | Single-account | Original behavior, no changes |\n| `accounts` with 1 entry | Single-account | Auto-select, no prompt |\n| `accounts` with 2+ entries | Multi-account | Prompt to select before publishing |\n| `accounts` with `default: true` | Multi-account | Pre-select default; user can switch |\n\n## EXTEND.md Example\n\n```md\ndefault_theme: default\ndefault_color: blue\n\naccounts:\n  - name: 宝玉的技术分享\n    alias: baoyu\n    default: true\n    default_publish_method: api\n    default_author: 宝玉\n    need_open_comment: 1\n    only_fans_can_comment: 0\n    app_id: your_wechat_app_id\n    app_secret: your_wechat_app_secret\n  - name: AI工具集\n    alias: ai-tools\n    default_publish_method: browser\n    default_author: AI工具集\n    need_open_comment: 1\n    only_fans_can_comment: 0\n```\n\n## Per-Account vs Global Keys\n\n**Per-account** (also accepted globally as fallback): `default_publish_method`, `default_author`, `need_open_comment`, `only_fans_can_comment`, `app_id`, `app_secret`, `chrome_profile_path`, `remote_publish_host`, `remote_publish_user`, `remote_publish_port`, `remote_publish_identity_file`, `remote_publish_known_hosts_file`, `remote_publish_strict_host_key_checking`, `remote_publish_connect_timeout`, `remote_publish_proxy_jump`.\n\n**Global-only** (always shared): `default_theme`, `default_color`.\n\n## Account Selection (Step 0.5)\n\nInsert between Step 0 (Load EXTEND.md) and Step 1 (Determine input type):\n\n```\nif no accounts block:\n    → single-account mode (original behavior)\nelif accounts.length == 1:\n    → auto-select the only account\nelif --account <alias> CLI arg:\n    → select matching account\nelif one account has default: true:\n    → pre-select, display: \"Using account: <name> (--account to switch)\"\nelse:\n    → prompt user to choose from the list\n```\n\n## Credential Resolution (API Method)\n\nFor the selected account with alias `{alias}`, try in this order (first hit wins):\n\n1. `app_id` / `app_secret` inline in the EXTEND.md account block\n2. Env vars `WECHAT_{ALIAS}_APP_ID` / `WECHAT_{ALIAS}_APP_SECRET` (alias uppercased, hyphens → underscores)\n3. `.baoyu-skills/.env` with the prefixed key `WECHAT_{ALIAS}_APP_ID`\n4. `~/.baoyu-skills/.env` with the prefixed key\n5. Fallback to unprefixed `WECHAT_APP_ID` / `WECHAT_APP_SECRET`\n\n### .env Multi-Account Example\n\n```bash\n# Account: baoyu\nWECHAT_BAOYU_APP_ID=your_wechat_app_id\nWECHAT_BAOYU_APP_SECRET=your_wechat_app_secret\n\n# Account: ai-tools\nWECHAT_AI_TOOLS_APP_ID=your_ai_tools_wechat_app_id\nWECHAT_AI_TOOLS_APP_SECRET=your_ai_tools_wechat_app_secret\n```\n\n## Chrome Profile (Browser Method)\n\nEach account uses an isolated Chrome profile so logins don't collide.\n\n| Source | Path |\n|--------|------|\n| Account `chrome_profile_path` in EXTEND.md | Use as-is |\n| Auto-generated from alias | `{shared_profile_parent}/wechat-{alias}/` |\n| Single-account fallback | Shared default profile |\n\n## CLI `--account` Flag\n\nAll publishing scripts accept `--account <alias>`:\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account ai-tools\n${BUN_X} {baseDir}/scripts/wechat-article.ts --markdown <file> --theme default --account baoyu\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown <file> --images ./photos/ --account baoyu\n```\n\n## Remote API Publishing\n\n`wechat-api.ts` supports a `remote-api` mode that tunnels WeChat API calls through an SSH SOCKS5 dynamic port forward to a server whose IP is on WeChat's allowlist. Markdown rendering, image processing, draft assembly, and HTML rewriting still happen locally; only outbound HTTPS calls to `api.weixin.qq.com` traverse the tunnel. No files are written to the remote host and `AppSecret` never leaves the local process. The remote host needs only `sshd` and outbound network access.\n\n### Per-Account Configuration\n\n```md\ndefault_theme: default\ndefault_color: blue\ndefault_publish_method: browser   # browser remains the default\n\naccounts:\n  - name: 宝玉的技术分享\n    alias: baoyu\n    default: true\n    default_publish_method: api\n    default_author: 宝玉\n    app_id: your_wechat_app_id\n    app_secret: your_wechat_app_secret\n  - name: AI工具集\n    alias: ai-tools\n    default_publish_method: remote-api\n    default_author: AI工具集\n    app_id: your_ai_tools_app_id\n    app_secret: your_ai_tools_app_secret\n    remote_publish_host: ai-tools-server.example.com\n    remote_publish_user: deploy\n    remote_publish_port: 22\n    remote_publish_identity_file: /home/me/.ssh/id_ed25519\n    remote_publish_known_hosts_file: /home/me/.ssh/known_hosts\n    remote_publish_strict_host_key_checking: accept-new\n```\n\nAccount-level `remote_publish_*` values override top-level globals. CLI `--remote-*` flags override both.\n\n### CLI Usage\n\n```bash\n# Use the account's default_publish_method (remote-api here):\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account ai-tools\n\n# Force remote mode regardless of default_publish_method:\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account baoyu --remote --remote-host other-server.example.com\n```\n\n### Security Notes\n\n- Authentication is SSH key only. Passwords and `ssh-askpass` are not used.\n- Only the typed `remote_publish_*` keys are read; raw `ssh` / `scp` options are intentionally not supported.\n- The tunnel forwards raw TCP; TLS verification for `api.weixin.qq.com` is still performed end-to-end by the local process.\n\nFile v1.118.1:scripts/package.json\n\n{\n  \"name\": \"baoyu-post-to-wechat-scripts\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@jsquash/webp\": \"^1.5.0\",\n    \"baoyu-chrome-cdp\": \"^0.1.1\",\n    \"baoyu-md\": \"^0.1.1\",\n    \"jimp\": \"^1.6.0\",\n    \"socks\": \"^2.8.9\"\n  }\n}\n\nFile v1.118.1:skill-card.md\n\n## Description: <br>\nPosts content to WeChat Official Account (微信公众号) via API or Chrome CDP. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[jimliu](https://clawhub.ai/user/jimliu) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and content operators use this skill to prepare and publish Markdown, HTML, plain-text, or image-text content to WeChat Official Accounts through browser automation or the WeChat API. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can perform high-impact WeChat account actions through browser automation or API calls. <br>\nMitigation: Review the generated draft and selected account before publishing, and use a dedicated WeChat Chrome profile for this workflow. <br>\nRisk: WeChat login QR images may be sent to Telegram if TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID are configured. <br>\nMitigation: Leave Telegram variables unset unless QR forwarding to that chat is intentional. <br>\nRisk: WeChat AppSecret values and remote publishing logs may expose sensitive account information. <br>\nMitigation: Keep secrets out of tracked project files and treat logs from API or remote publishing runs as sensitive. <br>\n\n\n## Reference(s): <br>\n- [Project homepage](https://github.com/JimLiu/baoyu-skills#baoyu-post-to-wechat) <br>\n- [WeChat Official Accounts platform](https://mp.weixin.qq.com) <br>\n- [API Credential Setup](references/api-setup.md) <br>\n- [Article Posting](references/article-posting.md) <br>\n- [First-Time Setup](references/config/first-time-setup.md) <br>\n- [Image-Text Posting](references/image-text-posting.md) <br>\n- [Multi-Account Support](references/multi-account.md) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown guidance with inline shell commands and configuration values] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May create local Markdown drafts and use configured WeChat credentials, Chrome profiles, clipboard access, or an SSH SOCKS tunnel depending on the selected publishing method.] <br>\n\n## Skill Version(s): <br>\n1.118.1 (source: frontmatter and release evidence) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v1.117.5: 31 files, 101595 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (6317b), references/image-text-posting.md (2833b), references/multi-account.md (5807b), scripts/bun.lock (38871b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard-mac.test.ts (916b), scripts/copy-to-clipboard.ts (14377b), scripts/md-to-wechat.ts (4904b), scripts/package.json (244b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (28291b), scripts/wechat-article-focus.test.ts (2741b), scripts/wechat-article.ts (48947b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (10079b), scripts/wechat-extend-config.ts (14593b), scripts/wechat-http.test.ts (5100b), scripts/wechat-http.ts (2677b), scripts/wechat-image-loader.ts (2526b), scripts/wechat-image-processor.ts (8524b), scripts/wechat-remote-publish.test.ts (5647b), scripts/wechat-remote-publish.ts (8007b), scripts/wechat-socks-http.test.ts (6837b), scripts/wechat-socks-http.ts (6917b), skill-card.md (2904b), SKILL.md (14519b), _meta.json (141b)\n\nFile v1.117.5:SKILL.md\n\n---\nname: baoyu-post-to-wechat\ndescription: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-text posting (贴图, formerly 图文) with multiple images. Markdown article workflows default to converting ordinary external links into bottom citations for WeChat-friendly output. Use when user mentions \"发布公众号\", \"post to wechat\", \"微信公众号\", or \"贴图/图文/文章\".\nversion: 1.117.5\nmetadata:\n  openclaw:\n    homepage: https://github.com/JimLiu/baoyu-skills#baoyu-post-to-wechat\n    requires:\n      anyBins:\n        - bun\n        - npx\n---\n\n# Post to WeChat Official Account\n\n## User Input Tools\n\nWhen this skill prompts the user, follow this tool-selection rule (priority order):\n\n1. **Prefer built-in user-input tools** exposed by the current agent runtime — e.g., `AskUserQuestion`, `request_user_input`, `clarify`, `ask_user`, or any equivalent.\n2. **Fallback**: if no such tool exists, emit a numbered plain-text message and ask the user to reply with the chosen number/answer for each question.\n3. **Batching**: if the tool supports multiple questions per call, combine all applicable questions into a single call; if only single-question, ask them one at a time in priority order.\n\nConcrete `AskUserQuestion` references below are examples — substitute the local equivalent in other runtimes.\n\n## Language\n\nRespond in the user's language. If they write in Chinese, reply in Chinese; if English, English. Keep technical tokens (paths, flags, field names) in English.\n\n## Script Directory\n\n`{baseDir}` = this SKILL.md's directory. Resolve `${BUN_X}`: prefer `bun`; else `npx -y bun`; else suggest `brew install oven-sh/bun/bun`.\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/wechat-browser.ts` | Image-text posts (图文) |\n| `scripts/wechat-article.ts` | Article posting via browser (文章) |\n| `scripts/wechat-api.ts` | Article posting via API (文章) |\n| `scripts/md-to-wechat.ts` | Markdown → WeChat-ready HTML with image placeholders |\n| `scripts/check-permissions.ts` | Verify environment & permissions |\n\n## Preferences (EXTEND.md)\n\nCheck these paths in order; first hit wins:\n\n| Path | Scope |\n|------|-------|\n| `.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | Project |\n| `${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | XDG |\n| `$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | User home |\n\nFound → read, parse, apply. Not found → run first-time setup (`references/config/first-time-setup.md`) before anything else.\n\n**Minimum keys** (case-insensitive, accept `1/0` or `true/false`):\n\n| Key | Default | Mapping |\n|-----|---------|---------|\n| `default_author` | empty | Fallback for `author` when CLI/frontmatter not provided |\n| `need_open_comment` | `1` | `articles[].need_open_comment` in `draft/add` |\n| `only_fans_can_comment` | `0` | `articles[].only_fans_can_comment` in `draft/add` |\n\n**Recommended EXTEND.md**:\n\n```md\ndefault_theme: default\ndefault_color: blue\ndefault_publish_method: browser\ndefault_author: 宝玉\nneed_open_comment: 1\nonly_fans_can_comment: 0\nchrome_profile_path: /path/to/chrome/profile\n\n# Remote API publishing (optional) — only set if WeChat's IP allowlist\n# excludes your local machine. See \"Remote API Method\" below.\n# remote_publish_host: server.example.com\n# remote_publish_user: deploy\n# remote_publish_port: 22\n# remote_publish_identity_file: ~/.ssh/id_ed25519\n# remote_publish_known_hosts_file: ~/.ssh/known_hosts\n# remote_publish_strict_host_key_checking: accept-new\n# remote_publish_connect_timeout: 10\n# remote_publish_proxy_jump: bastion.example.com\n```\n\nRaw `ssh` / `scp` options are intentionally not supported; only the typed keys above are honored. Authentication is SSH key only (no passwords).\n\n**Theme options**: default, grace, simple, modern. **Color presets**: blue, green, vermilion, yellow, purple, sky, rose, olive, black, gray, pink, red, orange (or hex).\n\n**Value priority**: CLI args → frontmatter → EXTEND.md (account-level → global) → skill defaults.\n\n## Multi-Account Support\n\nEXTEND.md supports an `accounts:` block for managing multiple Official Accounts. With 2+ entries, the workflow inserts a Step 0.5 to prompt for account selection (or auto-selects based on `default: true` or `--account <alias>`).\n\nFull details — compatibility rules, per-account keys, credential resolution, per-account Chrome profiles, CLI usage — in `references/multi-account.md`.\n\n## Pre-flight Check (Optional)\n\nBefore first use, suggest the environment check (user can skip):\n\n```bash\n${BUN_X} {baseDir}/scripts/check-permissions.ts\n```\n\nChecks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, API credentials, Chrome conflicts.\n\n| Check fails | Fix |\n|-------------|-----|\n| Chrome | Install Chrome or set `WECHAT_BROWSER_CHROME_PATH` |\n| Profile dir | Shared profile at `baoyu-skills/chrome-profile` |\n| Bun runtime | `brew install oven-sh/bun/bun` or `npm install -g bun` |\n| Accessibility (macOS) | System Settings → Privacy & Security → Accessibility → enable terminal app |\n| Clipboard copy | Ensure Swift/AppKit (macOS: `xcode-select --install`) |\n| Paste keystroke (Linux) | Install `xdotool` (X11) or `ydotool` (Wayland) |\n| API credentials | Follow guided setup in Step 2, or set in `.baoyu-skills/.env` |\n\n## Image-Text Posting (图文)\n\nShort posts with multiple images (up to 9):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown article.md --images ./images/\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --title \"标题\" --content \"内容\" --image img.png --submit\n```\n\nDetails: `references/image-text-posting.md`.\n\n## Article Posting Workflow (文章)\n\n```\n- [ ] Step 0: Load preferences (EXTEND.md)\n- [ ] Step 0.5: Resolve account (multi-account only — see references/multi-account.md)\n- [ ] Step 1: Determine input type\n- [ ] Step 2: Select method and configure credentials\n- [ ] Step 3: Resolve theme/color and validate metadata\n- [ ] Step 4: Publish to WeChat\n- [ ] Step 5: Report completion\n```\n\n### Step 0: Load Preferences\n\nCheck and load EXTEND.md (see \"Preferences\" above). If not found, complete first-time setup before any other questions. Resolve and cache for later steps: `default_theme`, `default_color`, `default_author`, `need_open_comment`, `only_fans_can_comment`.\n\n### Step 1: Determine Input Type\n\n| Input | Detection | Next |\n|-------|-----------|------|\n| HTML file | Path ends `.html`, file exists | Skip to Step 3 |\n| Markdown file | Path ends `.md`, file exists | Step 2 |\n| Plain text | Not a file path, or file doesn't exist | Save to markdown, then Step 2 |\n\n**Plain-text handling**:\n\n1. Generate slug (first 2-4 meaningful words, kebab-case; translate Chinese to English for the slug).\n2. Save to `post-to-wechat/YYYY-MM-DD/<slug>.md` (create directory if needed).\n3. Continue as a markdown file.\n\n### Step 2: Select Publishing Method and Configure\n\nAsk method unless specified in EXTEND.md or CLI:\n\n| Method | Speed | Requires |\n|--------|-------|----------|\n| `api` (Recommended) | Fast | API credentials (local IP allowlisted) |\n| `browser` | Slow | Chrome + logged-in session |\n| `remote-api` | Fast | API credentials + an SSH-reachable server whose IP is on the WeChat allowlist |\n\n**API selected + missing credentials** → run guided setup per `references/api-setup.md` (writes to `.baoyu-skills/.env`).\n\n**`remote-api` method**: WeChat's \"公众号设置 → IP 白名单\" often limits API access to one or two fixed IPs. If your local machine's IP is not on that list but a cloud server's is, use `remote-api`: all markdown rendering, image processing, draft assembly, and HTML rewriting still happen locally, and only the outbound HTTPS calls to `api.weixin.qq.com` (token, uploadimg, add_material, draft/add) are tunneled through an SSH SOCKS5 dynamic port forward (`ssh -N -D`) so that WeChat sees the remote server as the source IP. No files are written to the remote host; `AppSecret` never leaves the local process. Requires only `sshd` and outbound network on the remote host — no Python, no agent process. See \"Remote API Method\" below.\n\n### Step 3: Resolve Theme/Color and Validate Metadata\n\n1. **Theme**: CLI `--theme` → EXTEND.md `default_theme` → `default` (first match wins; do NOT ask if resolved).\n2. **Color**: CLI `--color` → EXTEND.md `default_color` → omit (theme default applies).\n3. **Validate metadata** (frontmatter for markdown, meta tags for HTML):\n\n| Field | Missing → |\n|-------|-----------|\n| Title | Ask, or press Enter to auto-generate from content |\n| Summary | Frontmatter `description` → `summary` → ask or auto-generate |\n| Author | CLI `--author` → frontmatter `author` → EXTEND.md `default_author` |\n\nAuto-generation: title = first H1/H2 or first sentence; summary = first paragraph, truncated to 120 chars.\n\n4. **Cover image** (required for API `article_type=news`): CLI `--cover` → frontmatter (`coverImage` / `featureImage` / `cover` / `image`) → `imgs/cover.png` → first inline image → stop and request one if still missing.\n\n### Step 4: Publish\n\n**Important — never pre-convert markdown to HTML.** Publishing scripts handle the conversion internally and the two methods render images differently: API renders `<img>` tags for upload, browser uses placeholders for paste-and-replace. Passing a pre-converted HTML breaks one or the other.\n\n**Markdown citation default**: for markdown input, ordinary external links are converted to bottom citations by default. Use `--no-cite` only if the user explicitly wants to keep inline links. Existing HTML input is left as-is.\n\n**API method** (accepts `.md` or `.html`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>] [--no-cite]\n```\n\nAlways pass `--theme` even if it's `default`. Only pass `--color` when explicitly set by the user or EXTEND.md.\n\n**Remote API method** (same script, adds `--remote`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> --remote [--remote-host <host>] [--remote-user <user>] [--remote-port <port>] [--remote-identity-file <path>] [--remote-known-hosts-file <path>] [--remote-strict-host-key-checking yes|no|accept-new] [--remote-connect-timeout <s>] [--remote-proxy-jump <spec>]\n```\n\nAny `--remote-*` flag implies `--remote`. CLI values override account-level then global `remote_publish_*` keys from EXTEND.md. Setting `default_publish_method: remote-api` also enables remote mode without `--remote`.\n\n**`draft/add` payload rules**:\n- Endpoint: `POST https://api.weixin.qq.com/cgi-bin/draft/add?access_token=ACCESS_TOKEN`\n- `article_type`: `news` (default) or `newspic`\n- For `news`, include `thumb_media_id` (cover required)\n- Always include `need_open_comment` (default `1`) and `only_fans_can_comment` (default `0`) in the request body, even if the CLI doesn't expose them\n\n**Browser method** (accepts `--markdown` or `--html`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>] [--no-cite]\n${BUN_X} {baseDir}/scripts/wechat-article.ts --html <html_file>\n```\n\n### Step 5: Completion Report\n\n```\nWeChat Publishing Complete!\n\nInput: [type] - [path]\nMethod: [API | Browser]\nTheme: [theme] [color if set]\n\nArticle:\n• Title: [title]\n• Summary: [summary]\n• Images: [N] inline\n• Comments: [open/closed], [fans-only/all]    ← API method only\n\nResult:\n✓ Draft saved to WeChat Official Account\n• media_id: [media_id]                         ← API method only\n\nNext Steps (API):\n→ Manage drafts: https://mp.weixin.qq.com (登录后进入「内容管理」→「草稿箱」)\n\nFiles created:\n[• post-to-wechat/YYYY-MM-DD/slug.md (if plain text input)]\n[• slug.html (converted)]\n```\n\n## Feature Comparison\n\n| Feature | Image-Text | Article (API) | Article (Remote API) | Article (Browser) |\n|---------|:---:|:---:|:---:|:---:|\n| Plain text input | ✗ | ✓ | ✓ | ✓ |\n| HTML input | ✗ | ✓ | ✓ | ✓ |\n| Markdown input | Title/content | ✓ | ✓ | ✓ |\n| Multiple images | ✓ (up to 9) | ✓ (inline) | ✓ (inline) | ✓ (inline) |\n| Themes | ✗ | ✓ | ✓ | ✓ |\n| Auto-generate metadata | ✗ | ✓ | ✓ | ✓ |\n| Default cover fallback (`imgs/cover.png`) | ✗ | ✓ | ✓ | ✗ |\n| Comment control | ✗ | ✓ | ✓ | ✗ |\n| Requires Chrome | ✓ | ✗ | ✗ | ✓ |\n| Requires API credentials | ✗ | ✓ | ✓ | ✗ |\n| Requires SSH-reachable server with allowlisted IP | ✗ | ✗ | ✓ | ✗ |\n| Speed | Medium | Fast | Fast | Slow |\n\n## Troubleshooting\n\n| Issue | Fix |\n|-------|-----|\n| Missing API credentials | Follow guided setup in Step 2 |\n| Access token error | Verify credentials valid and not expired |\n| Not logged in (browser) | First run opens browser — scan QR to log in. Set `TELEGRAM_BOT_TOKEN` + `TELEGRAM_CHAT_ID` to receive the QR image via Telegram |\n| Chrome not found | Set `WECHAT_BROWSER_CHROME_PATH` |\n| Title/summary missing | Use auto-generation or provide manually |\n| No cover image | Add frontmatter cover or place `imgs/cover.png` in article directory |\n| Wrong comment defaults | Check `need_open_comment` / `only_fans_can_comment` in EXTEND.md |\n| Paste fails | Check system clipboard permissions |\n| `Remote publish host is required` | Set `--remote-host` or `remote_publish_host` in EXTEND.md |\n| `SOCKS proxy on 127.0.0.1:… not ready` | SSH could not start the tunnel — check key, host, `StrictHostKeyChecking`, or use `--remote-connect-timeout` |\n| `ssh exited early` during remote publish | Verify the user can `ssh` non-interactively to the server; raise `--remote-connect-timeout` if the link is slow |\n| Remote API call returns `errcode 40164` (invalid IP) | The remote server's egress IP is not on WeChat's allowlist; add it in 公众号设置 → IP 白名单 |\n\n## References\n\n| File | Content |\n|------|---------|\n| `references/image-text-posting.md` | Image-text parameters, auto-compression |\n| `references/article-posting.md` | Article themes, image handling |\n| `references/multi-account.md` | Multi-account compatibility, credentials, Chrome profiles, CLI |\n| `references/api-setup.md` | Guided credential setup |\n| `references/config/first-time-setup.md` | First-time EXTEND.md setup |\n\n## Extension Support\n\nCustom configurations via EXTEND.md. See \"Preferences\" for paths and supported options.\n\nFile v1.117.5:_meta.json\n\n{\n  \"ownerId\": \"kn7csrrndw79hpke5d0gsnx93d82k67r\",\n  \"slug\": \"baoyu-post-to-wechat\",\n  \"version\": \"1.117.5\",\n  \"publishedAt\": 1779371744599\n}\n\nFile v1.117.5:references/api-setup.md\n\n# API Credential Setup\n\nGuided setup when `WECHAT_APP_ID` / `WECHAT_APP_SECRET` are missing. Invoked by Step 2 of the article-posting workflow.\n\n## Detection\n\nLook for the credentials in this order:\n\n1. Env vars `WECHAT_APP_ID` / `WECHAT_APP_SECRET`\n2. `<cwd>/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n3. `$HOME/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n\nIf none are present, run the guided setup below.\n\n## Guided Setup\n\nShow this message to the user and ask where to save:\n\n```\nWeChat API credentials not found.\n\nTo obtain credentials:\n1. Visit https://mp.weixin.qq.com\n2. Go to: 开发 → 基本配置\n3. Copy AppID and AppSecret\n\nWhere to save?\nA) Project-level: .baoyu-skills/.env (this project only)\nB) User-level: ~/.baoyu-skills/.env (all projects)\n```\n\nAfter they choose a location, collect the values (prefer a user-input tool, fall back to a numbered prompt per the User Input Tools rule in SKILL.md) and append:\n\n```\nWECHAT_APP_ID=<user_input>\nWECHAT_APP_SECRET=<user_input>\n```\n\n## Multi-Account Variant\n\nIf the user has multiple accounts configured (`accounts:` block in EXTEND.md), use prefixed keys instead — see `multi-account.md` → \"Credential Resolution\".\n\nFile v1.117.5:references/article-posting.md\n\n# Article Posting (文章发表)\n\nPost markdown articles to WeChat Official Account with full formatting support.\n\n## Usage\n\n```bash\n# Post markdown article\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md\n\n# With theme\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --theme grace\n\n# Disable bottom citations for ordinary external links\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --no-cite\n\n# With explicit options\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --author \"作者名\" --summary \"摘要\"\n```\n\n## Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `--markdown <path>` | Markdown file to convert and post |\n| `--theme <name>` | Theme: default, grace, simple, modern |\n| `--no-cite` | Keep ordinary external links inline instead of converting them to bottom citations |\n| `--title <text>` | Override title (auto-extracted from markdown) |\n| `--author <name>` | Author name |\n| `--summary <text>` | Article summary |\n| `--html <path>` | Pre-rendered HTML file (alternative to markdown) |\n| `--profile <dir>` | Chrome profile directory |\n\n## Markdown Format\n\n```markdown\n---\ntitle: Article Title\nauthor: Author Name\n---\n\n# Title (becomes article title)\n\nRegular paragraph with **bold** and *italic*.\n\n## Section Header\n\n![Image description](./image.png)\n\n- List item 1\n- List item 2\n\n> Blockquote text\n\n[Link text](https://example.com)\n```\n\nMarkdown mode converts ordinary external links into bottom citations by default for WeChat-friendly output. Use `--no-cite` to disable that behavior.\n\n## Image Handling\n\n1. **Parse**: Images in markdown are replaced with `WECHATIMGPH_N`\n2. **Render**: HTML is generated with placeholders in text\n3. **Paste**: HTML content is pasted into WeChat editor\n4. **Replace**: For each placeholder:\n   - Find and select the placeholder text\n   - Scroll into view\n   - Press Backspace to delete the placeholder\n   - Paste the image from clipboard\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `wechat-article.ts` | Main article publishing script |\n| `md-to-wechat.ts` | Markdown to HTML with placeholders |\n| `md/render.ts` | Markdown rendering with themes |\n\n## Example Session\n\n```\nUser: /post-to-wechat --markdown ./article.md\n\nClaude:\n1. Parses markdown, finds 5 images\n2. Generates HTML with placeholders\n3. Opens Chrome, navigates to WeChat editor\n4. Pastes HTML content\n5. For each image:\n   - Selects WECHATIMGPH_1\n   - Scrolls into view\n   - Presses Backspace to delete\n   - Pastes image\n6. Reports: \"Article composed with 5 images.\"\n```\n\nFile v1.117.5:references/config/first-time-setup.md\n\n---\nname: first-time-setup\ndescription: First-time setup flow for baoyu-post-to-wechat preferences\n---\n\n# First-Time Setup\n\n## Overview\n\nWhen no EXTEND.md is found, guide user through preference setup.\n\n**BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:\n- Ask about content or files to publish\n- Ask about themes or publishing methods\n- Proceed to content conversion or publishing\n\nONLY ask the questions in this setup flow, save EXTEND.md, then continue.\n\n## Setup Flow\n\n```\nNo EXTEND.md found\n        |\n        v\n+---------------------+\n| AskUserQuestion     |\n| (all questions)     |\n+---------------------+\n        |\n        v\n+---------------------+\n| Create EXTEND.md    |\n+---------------------+\n        |\n        v\n    Continue to Step 1\n```\n\n## Questions\n\n**Language**: Use user's input language or saved language preference.\n\nUse AskUserQuestion with ALL questions in ONE call:\n\n### Question 1: Default Theme\n\n```yaml\nheader: \"Theme\"\nquestion: \"Default theme for article conversion?\"\noptions:\n  - label: \"default (Recommended)\"\n    description: \"Classic layout - centered title with border, white-on-color H2 (default: blue)\"\n  - label: \"grace\"\n    description: \"Elegant - text shadows, rounded cards, refined blockquotes (default: purple)\"\n  - label: \"simple\"\n    description: \"Minimal modern - asymmetric rounded corners, clean whitespace (default: green)\"\n  - label: \"modern\"\n    description: \"Large rounded corners, pill headings, spacious (default: orange)\"\n```\n\n### Question 2: Default Color\n\n```yaml\nheader: \"Color\"\nquestion: \"Default color preset? (theme default if not set)\"\noptions:\n  - label: \"Theme default (Recommended)\"\n    description: \"Use the theme's built-in default color\"\n  - label: \"blue\"\n    description: \"#0F4C81 经典蓝\"\n  - label: \"red\"\n    description: \"#A93226 中国红\"\n  - label: \"green\"\n    description: \"#009874 翡翠绿\"\n```\n\nNote: User can choose \"Other\" to type any preset name (vermilion, yellow, purple, sky, rose, olive, black, gray, pink, orange) or hex value.\n\n### Question 3: Default Publishing Method\n\n```yaml\nheader: \"Method\"\nquestion: \"Default publishing method?\"\noptions:\n  - label: \"api (Recommended)\"\n    description: \"Fast, requires API credentials (AppID + AppSecret)\"\n  - label: \"browser\"\n    description: \"Slow, requires Chrome and login session\"\n  - label: \"remote-api\"\n    description: \"Fast, tunnels WeChat API calls through SSH to a server whose IP is on the WeChat allowlist\"\n```\n\nIf the user selects `remote-api`, prompt for `remote_publish_host` and (optionally) `remote_publish_user`, `remote_publish_identity_file`. These can also be filled in later by editing EXTEND.md.\n\n### Question 4: Default Author\n\n```yaml\nheader: \"Author\"\nquestion: \"Default author name for articles?\"\noptions:\n  - label: \"No default\"\n    description: \"Leave empty, specify per article\"\n```\n\nNote: User will likely choose \"Other\" to type their author name.\n\n### Question 5: Open Comments\n\n```yaml\nheader: \"Comments\"\nquestion: \"Enable comments on articles by default?\"\noptions:\n  - label: \"Yes (Recommended)\"\n    description: \"Allow readers to comment on articles\"\n  - label: \"No\"\n    description: \"Disable comments by default\"\n```\n\n### Question 6: Fans-Only Comments\n\n```yaml\nheader: \"Fans only\"\nquestion: \"Restrict comments to followers only?\"\noptions:\n  - label: \"No (Recommended)\"\n    description: \"All readers can comment\"\n  - label: \"Yes\"\n    description: \"Only followers can comment\"\n```\n\n### Question 7: Save Location\n\n```yaml\nheader: \"Save\"\nquestion: \"Where to save preferences?\"\noptions:\n  - label: \"Project (Recommended)\"\n    description: \".baoyu-skills/ (this project only)\"\n  - label: \"User\"\n    description: \"~/.baoyu-skills/ (all projects)\"\n```\n\n## Save Locations\n\n| Choice | Path | Scope |\n|--------|------|-------|\n| Project | `.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | Current project |\n| User | `~/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | All projects |\n\n## After Setup\n\n1. Create directory if needed\n2. Write EXTEND.md\n3. Confirm: \"Preferences saved to [path]\"\n4. Continue to Step 0 (load the saved preferences)\n\n## EXTEND.md Template\n\n### Single Account (Default)\n\n```md\ndefault_theme: [default/grace/simple/modern]\ndefault_color: [preset name, hex, or empty for theme default]\ndefault_publish_method: [api/browser/remote-api]\ndefault_author: [author name or empty]\nneed_open_comment: [1/0]\nonly_fans_can_comment: [1/0]\nchrome_profile_path:\n\n# Remote API publishing — only fill in if default_publish_method is remote-api\n# or you plan to pass --remote on the CLI.\nremote_publish_host:\nremote_publish_user:\nremote_publish_port:\nremote_publish_identity_file:\nremote_publish_known_hosts_file:\nremote_publish_strict_host_key_checking:\nremote_publish_connect_timeout:\nremote_publish_proxy_jump:\n```\n\nRaw `ssh` / `scp` options are intentionally not supported; only the typed keys above are honored. Authentication is SSH key only.\n\n### Multi-Account\n\n```md\ndefault_theme: [default/grace/simple/modern]\ndefault_color: [preset name, hex, or empty for theme default]\n\naccounts:\n  - name: [display name]\n    alias: [short key, e.g. \"baoyu\"]\n    default: true\n    default_publish_method: [api/browser/remote-api]\n    default_author: [author name]\n    need_open_comment: [1/0]\n    only_fans_can_comment: [1/0]\n    app_id: [WeChat App ID, optional]\n    app_secret: [WeChat App Secret, optional]\n    # Remote API publishing (optional, per-account override of globals)\n    remote_publish_host:\n    remote_publish_user:\n    remote_publish_identity_file:\n  - name: [second account name]\n    alias: [short key, e.g. \"ai-tools\"]\n    default_publish_method: [api/browser/remote-api]\n    default_author: [author name]\n    need_open_comment: [1/0]\n    only_fans_can_comment: [1/0]\n```\n\n## Adding More Accounts Later\n\nAfter initial setup, users can add accounts by editing EXTEND.md:\n\n1. Add an `accounts:` block with list items\n2. Move per-account settings (author, publish method, comments) into each account entry\n3. Keep global settings (theme, color) at the top level\n4. Each account needs a unique `alias` (used for CLI `--account` arg and Chrome profile naming)\n5. Set `default: true` on the primary account\n\n## Modifying Preferences Later\n\nUsers can edit EXTEND.md directly or delete it to trigger setup again.\n\nFile v1.117.5:references/image-text-posting.md\n\n# Image-Text Posting (贴图发表, formerly 图文)\n\nPost image-text messages with multiple images to WeChat Official Account.\n\n> **Note**: WeChat has renamed \"图文\" to \"贴图\" in the Official Account menu (as of 2026).\n\n## Usage\n\n```bash\n# Post with images and markdown file (title/content extracted automatically)\n${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/\n\n# Post with explicit title and content\n${BUN_X} ./scripts/wechat-browser.ts --title \"标题\" --content \"内容\" --image img1.png --image img2.png\n\n# Save as draft\n${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/ --submit\n```\n\n## Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `--markdown <path>` | Markdown file for title/content extraction |\n| `--images <dir>` | Directory containing images (sorted by name) |\n| `--title <text>` | Article title (max 20 chars, auto-compressed if too long) |\n| `--content <text>` | Article content (max 1000 chars, auto-compressed if too long) |\n| `--image <path>` | Single image file (can be repeated) |\n| `--submit` | Save as draft (default: preview only) |\n| `--profile <dir>` | Chrome profile directory |\n\n## Auto Title/Content from Markdown\n\nWhen using `--markdown`, the script:\n\n1. **Parses frontmatter** for title and author:\n   ```yaml\n   ---\n   title: 文章标题\n   author: 作者名\n   ---\n   ```\n\n2. **Falls back to H1** if no frontmatter title:\n   ```markdown\n   # 这将成为标题\n   ```\n\n3. **Compresses title** to 20 characters if too long:\n   - Original: \"如何在一天内彻底重塑你的人生\"\n   - Compressed: \"一天彻底重塑你的人生\"\n\n4. **Extracts first paragraphs** as content (max 1000 chars)\n\n## Image Directory Mode\n\nWhen using `--images <dir>`:\n\n- All PNG/JPG files in directory are uploaded\n- Files are sorted alphabetically by name\n- Naming convention: `01-cover.png`, `02-content.png`, etc.\n\n## Constraints\n\n| Field | Max Length | Notes |\n|-------|------------|-------|\n| Title | 20 chars | Auto-compressed if longer |\n| Content | 1000 chars | Auto-compressed if longer |\n| Images | 9 max | WeChat limit |\n\n## Example Session\n\n```\nUser: /post-to-wechat --markdown ./article.md --images ./xhs-images/\n\nClaude:\n1. Parses markdown meta:\n   - Title: \"如何在一天内彻底重塑你的人生\" → \"一天内重塑你的人生\"\n   - Author: from frontmatter or default\n2. Extracts content from first paragraphs\n3. Finds 7 images in xhs-images/\n4. Opens Chrome, navigates to WeChat \"图文\" editor\n5. Uploads all images\n6. Fills title and content\n7. Reports: \"Image-text posted with 7 images.\"\n```\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `wechat-browser.ts` | Main image-text posting script |\n| `cdp.ts` | Chrome DevTools Protocol utilities |\n| `copy-to-clipboard.ts` | Clipboard operations |\n\nFile v1.117.5:references/multi-account.md\n\n# Multi-Account Support\n\nDetails for managing multiple WeChat Official Accounts through one EXTEND.md. SKILL.md only covers single-account flow and the selection prompt — read this file when the user has an `accounts:` block, asks to publish to a specific account, or needs per-account credentials.\n\n## Compatibility\n\n| Condition | Mode | Behavior |\n|-----------|------|----------|\n| No `accounts` block | Single-account | Original behavior, no changes |\n| `accounts` with 1 entry | Single-account | Auto-select, no prompt |\n| `accounts` with 2+ entries | Multi-account | Prompt to select before publishing |\n| `accounts` with `default: true` | Multi-account | Pre-select default; user can switch |\n\n## EXTEND.md Example\n\n```md\ndefault_theme: default\ndefault_color: blue\n\naccounts:\n  - name: 宝玉的技术分享\n    alias: baoyu\n    default: true\n    default_publish_method: api\n    default_author: 宝玉\n    need_open_comment: 1\n    only_fans_can_comment: 0\n    app_id: your_wechat_app_id\n    app_secret: your_wechat_app_secret\n  - name: AI工具集\n    alias: ai-tools\n    default_publish_method: browser\n    default_author: AI工具集\n    need_open_comment: 1\n    only_fans_can_comment: 0\n```\n\n## Per-Account vs Global Keys\n\n**Per-account** (also accepted globally as fallback): `default_publish_method`, `default_author`, `need_open_comment`, `only_fans_can_comment`, `app_id`, `app_secret`, `chrome_profile_path`, `remote_publish_host`, `remote_publish_user`, `remote_publish_port`, `remote_publish_identity_file`, `remote_publish_known_hosts_file`, `remote_publish_strict_host_key_checking`, `remote_publish_connect_timeout`, `remote_publish_proxy_jump`.\n\n**Global-only** (always shared): `default_theme`, `default_color`.\n\n## Account Selection (Step 0.5)\n\nInsert between Step 0 (Load EXTEND.md) and Step 1 (Determine input type):\n\n```\nif no accounts block:\n    → single-account mode (original behavior)\nelif accounts.length == 1:\n    → auto-select the only account\nelif --account <alias> CLI arg:\n    → select matching account\nelif one account has default: true:\n    → pre-select, display: \"Using account: <name> (--account to switch)\"\nelse:\n    → prompt user to choose from the list\n```\n\n## Credential Resolution (API Method)\n\nFor the selected account with alias `{alias}`, try in this order (first hit wins):\n\n1. `app_id` / `app_secret` inline in the EXTEND.md account block\n2. Env vars `WECHAT_{ALIAS}_APP_ID` / `WECHAT_{ALIAS}_APP_SECRET` (alias uppercased, hyphens → underscores)\n3. `.baoyu-skills/.env` with the prefixed key `WECHAT_{ALIAS}_APP_ID`\n4. `~/.baoyu-skills/.env` with the prefixed key\n5. Fallback to unprefixed `WECHAT_APP_ID` / `WECHAT_APP_SECRET`\n\n### .env Multi-Account Example\n\n```bash\n# Account: baoyu\nWECHAT_BAOYU_APP_ID=your_wechat_app_id\nWECHAT_BAOYU_APP_SECRET=your_wechat_app_secret\n\n# Account: ai-tools\nWECHAT_AI_TOOLS_APP_ID=your_ai_tools_wechat_app_id\nWECHAT_AI_TOOLS_APP_SECRET=your_ai_tools_wechat_app_secret\n```\n\n## Chrome Profile (Browser Method)\n\nEach account uses an isolated Chrome profile so logins don't collide.\n\n| Source | Path |\n|--------|------|\n| Account `chrome_profile_path` in EXTEND.md | Use as-is |\n| Auto-generated from alias | `{shared_profile_parent}/wechat-{alias}/` |\n| Single-account fallback | Shared default profile |\n\n## CLI `--account` Flag\n\nAll publishing scripts accept `--account <alias>`:\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account ai-tools\n${BUN_X} {baseDir}/scripts/wechat-article.ts --markdown <file> --theme default --account baoyu\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown <file> --images ./photos/ --account baoyu\n```\n\n## Remote API Publishing\n\n`wechat-api.ts` supports a `remote-api` mode that tunnels WeChat API calls through an SSH SOCKS5 dynamic port forward to a server whose IP is on WeChat's allowlist. Markdown rendering, image processing, draft assembly, and HTML rewriting still happen locally; only outbound HTTPS calls to `api.weixin.qq.com` traverse the tunnel. No files are written to the remote host and `AppSecret` never leaves the local process. The remote host needs only `sshd` and outbound network access.\n\n### Per-Account Configuration\n\n```md\ndefault_theme: default\ndefault_color: blue\ndefault_publish_method: browser   # browser remains the default\n\naccounts:\n  - name: 宝玉的技术分享\n    alias: baoyu\n    default: true\n    default_publish_method: api\n    default_author: 宝玉\n    app_id: your_wechat_app_id\n    app_secret: your_wechat_app_secret\n  - name: AI工具集\n    alias: ai-tools\n    default_publish_method: remote-api\n    default_author: AI工具集\n    app_id: your_ai_tools_app_id\n    app_secret: your_ai_tools_app_secret\n    remote_publish_host: ai-tools-server.example.com\n    remote_publish_user: deploy\n    remote_publish_port: 22\n    remote_publish_identity_file: /home/me/.ssh/id_ed25519\n    remote_publish_known_hosts_file: /home/me/.ssh/known_hosts\n    remote_publish_strict_host_key_checking: accept-new\n```\n\nAccount-level `remote_publish_*` values override top-level globals. CLI `--remote-*` flags override both.\n\n### CLI Usage\n\n```bash\n# Use the account's default_publish_method (remote-api here):\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account ai-tools\n\n# Force remote mode regardless of default_publish_method:\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account baoyu --remote --remote-host other-server.example.com\n```\n\n### Security Notes\n\n- Authentication is SSH key only. Passwords and `ssh-askpass` are not used.\n- Only the typed `remote_publish_*` keys are read; raw `ssh` / `scp` options are intentionally not supported.\n- The tunnel forwards raw TCP; TLS verification for `api.weixin.qq.com` is still performed end-to-end by the local process.\n\nFile v1.117.5:scripts/package.json\n\n{\n  \"name\": \"baoyu-post-to-wechat-scripts\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@jsquash/webp\": \"^1.5.0\",\n    \"baoyu-chrome-cdp\": \"^0.1.0\",\n    \"baoyu-md\": \"^0.1.0\",\n    \"jimp\": \"^1.6.0\",\n    \"socks\": \"^2.8.9\"\n  }\n}\n\nFile v1.117.5:skill-card.md\n\n## Description: <br>\nPosts content to WeChat Official Account via API or Chrome CDP, supporting article posting with HTML, markdown, or plain text input and image-text posting with multiple images. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[jimliu](https://clawhub.ai/user/jimliu) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and content operators use this skill to prepare and publish articles or image-text posts to a WeChat Official Account, including markdown conversion, metadata handling, image processing, browser posting, API posting, and optional remote API routing. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The skill can automate a live WeChat Official Account, upload selected local files and images, create drafts, and use sensitive WeChat API credentials. <br>\nMitigation: Use a test account first, review selected files before publishing, and keep .baoyu-skills/.env and EXTEND.md out of shared folders and version control. <br>\nRisk: If Telegram QR delivery is configured, WeChat login QR codes can be sent to the configured Telegram chat. <br>\nMitigation: Set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID only when QR delivery to that Telegram chat is intentional. <br>\nRisk: Remote API publishing routes WeChat API traffic through an SSH host. <br>\nMitigation: Use remote-api only with an SSH host you trust and verify the configured host, user, identity file, known-hosts behavior, and proxy settings before use. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/jimliu/baoyu-post-to-wechat) <br>\n- [Project homepage](https://github.com/JimLiu/baoyu-skills#baoyu-post-to-wechat) <br>\n- [API credential setup](references/api-setup.md) <br>\n- [Article posting](references/article-posting.md) <br>\n- [First-time setup](references/config/first-time-setup.md) <br>\n- [Image-text posting](references/image-text-posting.md) <br>\n- [Multi-account support](references/multi-account.md) <br>\n- [WeChat Official Account platform](https://mp.weixin.qq.com) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown guidance with inline shell commands and local configuration values] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May create local markdown drafts, HTML conversions, image assets, and WeChat draft records depending on the selected workflow.] <br>\n\n## Skill Version(s): <br>\n1.117.5 (source: frontmatter and server release metadata) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nArchive v1.117.4: 30 files, 100160 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (6317b), references/image-text-posting.md (2833b), references/multi-account.md (5807b), scripts/bun.lock (38871b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard-mac.test.ts (916b), scripts/copy-to-clipboard.ts (14377b), scripts/md-to-wechat.ts (4904b), scripts/package.json (244b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (28291b), scripts/wechat-article-focus.test.ts (2741b), scripts/wechat-article.ts (48947b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (10079b), scripts/wechat-extend-config.ts (14593b), scripts/wechat-http.test.ts (5100b), scripts/wechat-http.ts (2677b), scripts/wechat-image-loader.ts (2526b), scripts/wechat-image-processor.ts (8524b), scripts/wechat-remote-publish.test.ts (5647b), scripts/wechat-remote-publish.ts (8007b), scripts/wechat-socks-http.test.ts (6837b), scripts/wechat-socks-http.ts (6917b), SKILL.md (14519b), _meta.json (141b)\n\nFile v1.117.4:SKILL.md\n\n---\nname: baoyu-post-to-wechat\ndescription: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-text posting (贴图, formerly 图文) with multiple images. Markdown article workflows default to converting ordinary external links into bottom citations for WeChat-friendly output. Use when user mentions \"发布公众号\", \"post to wechat\", \"微信公众号\", or \"贴图/图文/文章\".\nversion: 1.117.4\nmetadata:\n  openclaw:\n    homepage: https://github.com/JimLiu/baoyu-skills#baoyu-post-to-wechat\n    requires:\n      anyBins:\n        - bun\n        - npx\n---\n\n# Post to WeChat Official Account\n\n## User Input Tools\n\nWhen this skill prompts the user, follow this tool-selection rule (priority order):\n\n1. **Prefer built-in user-input tools** exposed by the current agent runtime — e.g., `AskUserQuestion`, `request_user_input`, `clarify`, `ask_user`, or any equivalent.\n2. **Fallback**: if no such tool exists, emit a numbered plain-text message and ask the user to reply with the chosen number/answer for each question.\n3. **Batching**: if the tool supports multiple questions per call, combine all applicable questions into a single call; if only single-question, ask them one at a time in priority order.\n\nConcrete `AskUserQuestion` references below are examples — substitute the local equivalent in other runtimes.\n\n## Language\n\nRespond in the user's language. If they write in Chinese, reply in Chinese; if English, English. Keep technical tokens (paths, flags, field names) in English.\n\n## Script Directory\n\n`{baseDir}` = this SKILL.md's directory. Resolve `${BUN_X}`: prefer `bun`; else `npx -y bun`; else suggest `brew install oven-sh/bun/bun`.\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/wechat-browser.ts` | Image-text posts (图文) |\n| `scripts/wechat-article.ts` | Article posting via browser (文章) |\n| `scripts/wechat-api.ts` | Article posting via API (文章) |\n| `scripts/md-to-wechat.ts` | Markdown → WeChat-ready HTML with image placeholders |\n| `scripts/check-permissions.ts` | Verify environment & permissions |\n\n## Preferences (EXTEND.md)\n\nCheck these paths in order; first hit wins:\n\n| Path | Scope |\n|------|-------|\n| `.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | Project |\n| `${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | XDG |\n| `$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | User home |\n\nFound → read, parse, apply. Not found → run first-time setup (`references/config/first-time-setup.md`) before anything else.\n\n**Minimum keys** (case-insensitive, accept `1/0` or `true/false`):\n\n| Key | Default | Mapping |\n|-----|---------|---------|\n| `default_author` | empty | Fallback for `author` when CLI/frontmatter not provided |\n| `need_open_comment` | `1` | `articles[].need_open_comment` in `draft/add` |\n| `only_fans_can_comment` | `0` | `articles[].only_fans_can_comment` in `draft/add` |\n\n**Recommended EXTEND.md**:\n\n```md\ndefault_theme: default\ndefault_color: blue\ndefault_publish_method: browser\ndefault_author: 宝玉\nneed_open_comment: 1\nonly_fans_can_comment: 0\nchrome_profile_path: /path/to/chrome/profile\n\n# Remote API publishing (optional) — only set if WeChat's IP allowlist\n# excludes your local machine. See \"Remote API Method\" below.\n# remote_publish_host: server.example.com\n# remote_publish_user: deploy\n# remote_publish_port: 22\n# remote_publish_identity_file: ~/.ssh/id_ed25519\n# remote_publish_known_hosts_file: ~/.ssh/known_hosts\n# remote_publish_strict_host_key_checking: accept-new\n# remote_publish_connect_timeout: 10\n# remote_publish_proxy_jump: bastion.example.com\n```\n\nRaw `ssh` / `scp` options are intentionally not supported; only the typed keys above are honored. Authentication is SSH key only (no passwords).\n\n**Theme options**: default, grace, simple, modern. **Color presets**: blue, green, vermilion, yellow, purple, sky, rose, olive, black, gray, pink, red, orange (or hex).\n\n**Value priority**: CLI args → frontmatter → EXTEND.md (account-level → global) → skill defaults.\n\n## Multi-Account Support\n\nEXTEND.md supports an `accounts:` block for managing multiple Official Accounts. With 2+ entries, the workflow inserts a Step 0.5 to prompt for account selection (or auto-selects based on `default: true` or `--account <alias>`).\n\nFull details — compatibility rules, per-account keys, credential resolution, per-account Chrome profiles, CLI usage — in `references/multi-account.md`.\n\n## Pre-flight Check (Optional)\n\nBefore first use, suggest the environment check (user can skip):\n\n```bash\n${BUN_X} {baseDir}/scripts/check-permissions.ts\n```\n\nChecks: Chrome, profile isolation, Bun, Accessibility, clipboard, paste keystroke, API credentials, Chrome conflicts.\n\n| Check fails | Fix |\n|-------------|-----|\n| Chrome | Install Chrome or set `WECHAT_BROWSER_CHROME_PATH` |\n| Profile dir | Shared profile at `baoyu-skills/chrome-profile` |\n| Bun runtime | `brew install oven-sh/bun/bun` or `npm install -g bun` |\n| Accessibility (macOS) | System Settings → Privacy & Security → Accessibility → enable terminal app |\n| Clipboard copy | Ensure Swift/AppKit (macOS: `xcode-select --install`) |\n| Paste keystroke (Linux) | Install `xdotool` (X11) or `ydotool` (Wayland) |\n| API credentials | Follow guided setup in Step 2, or set in `.baoyu-skills/.env` |\n\n## Image-Text Posting (图文)\n\nShort posts with multiple images (up to 9):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown article.md --images ./images/\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --title \"标题\" --content \"内容\" --image img.png --submit\n```\n\nDetails: `references/image-text-posting.md`.\n\n## Article Posting Workflow (文章)\n\n```\n- [ ] Step 0: Load preferences (EXTEND.md)\n- [ ] Step 0.5: Resolve account (multi-account only — see references/multi-account.md)\n- [ ] Step 1: Determine input type\n- [ ] Step 2: Select method and configure credentials\n- [ ] Step 3: Resolve theme/color and validate metadata\n- [ ] Step 4: Publish to WeChat\n- [ ] Step 5: Report completion\n```\n\n### Step 0: Load Preferences\n\nCheck and load EXTEND.md (see \"Preferences\" above). If not found, complete first-time setup before any other questions. Resolve and cache for later steps: `default_theme`, `default_color`, `default_author`, `need_open_comment`, `only_fans_can_comment`.\n\n### Step 1: Determine Input Type\n\n| Input | Detection | Next |\n|-------|-----------|------|\n| HTML file | Path ends `.html`, file exists | Skip to Step 3 |\n| Markdown file | Path ends `.md`, file exists | Step 2 |\n| Plain text | Not a file path, or file doesn't exist | Save to markdown, then Step 2 |\n\n**Plain-text handling**:\n\n1. Generate slug (first 2-4 meaningful words, kebab-case; translate Chinese to English for the slug).\n2. Save to `post-to-wechat/YYYY-MM-DD/<slug>.md` (create directory if needed).\n3. Continue as a markdown file.\n\n### Step 2: Select Publishing Method and Configure\n\nAsk method unless specified in EXTEND.md or CLI:\n\n| Method | Speed | Requires |\n|--------|-------|----------|\n| `api` (Recommended) | Fast | API credentials (local IP allowlisted) |\n| `browser` | Slow | Chrome + logged-in session |\n| `remote-api` | Fast | API credentials + an SSH-reachable server whose IP is on the WeChat allowlist |\n\n**API selected + missing credentials** → run guided setup per `references/api-setup.md` (writes to `.baoyu-skills/.env`).\n\n**`remote-api` method**: WeChat's \"公众号设置 → IP 白名单\" often limits API access to one or two fixed IPs. If your local machine's IP is not on that list but a cloud server's is, use `remote-api`: all markdown rendering, image processing, draft assembly, and HTML rewriting still happen locally, and only the outbound HTTPS calls to `api.weixin.qq.com` (token, uploadimg, add_material, draft/add) are tunneled through an SSH SOCKS5 dynamic port forward (`ssh -N -D`) so that WeChat sees the remote server as the source IP. No files are written to the remote host; `AppSecret` never leaves the local process. Requires only `sshd` and outbound network on the remote host — no Python, no agent process. See \"Remote API Method\" below.\n\n### Step 3: Resolve Theme/Color and Validate Metadata\n\n1. **Theme**: CLI `--theme` → EXTEND.md `default_theme` → `default` (first match wins; do NOT ask if resolved).\n2. **Color**: CLI `--color` → EXTEND.md `default_color` → omit (theme default applies).\n3. **Validate metadata** (frontmatter for markdown, meta tags for HTML):\n\n| Field | Missing → |\n|-------|-----------|\n| Title | Ask, or press Enter to auto-generate from content |\n| Summary | Frontmatter `description` → `summary` → ask or auto-generate |\n| Author | CLI `--author` → frontmatter `author` → EXTEND.md `default_author` |\n\nAuto-generation: title = first H1/H2 or first sentence; summary = first paragraph, truncated to 120 chars.\n\n4. **Cover image** (required for API `article_type=news`): CLI `--cover` → frontmatter (`coverImage` / `featureImage` / `cover` / `image`) → `imgs/cover.png` → first inline image → stop and request one if still missing.\n\n### Step 4: Publish\n\n**Important — never pre-convert markdown to HTML.** Publishing scripts handle the conversion internally and the two methods render images differently: API renders `<img>` tags for upload, browser uses placeholders for paste-and-replace. Passing a pre-converted HTML breaks one or the other.\n\n**Markdown citation default**: for markdown input, ordinary external links are converted to bottom citations by default. Use `--no-cite` only if the user explicitly wants to keep inline links. Existing HTML input is left as-is.\n\n**API method** (accepts `.md` or `.html`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>] [--no-cite]\n```\n\nAlways pass `--theme` even if it's `default`. Only pass `--color` when explicitly set by the user or EXTEND.md.\n\n**Remote API method** (same script, adds `--remote`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> --remote [--remote-host <host>] [--remote-user <user>] [--remote-port <port>] [--remote-identity-file <path>] [--remote-known-hosts-file <path>] [--remote-strict-host-key-checking yes|no|accept-new] [--remote-connect-timeout <s>] [--remote-proxy-jump <spec>]\n```\n\nAny `--remote-*` flag implies `--remote`. CLI values override account-level then global `remote_publish_*` keys from EXTEND.md. Setting `default_publish_method: remote-api` also enables remote mode without `--remote`.\n\n**`draft/add` payload rules**:\n- Endpoint: `POST https://api.weixin.qq.com/cgi-bin/draft/add?access_token=ACCESS_TOKEN`\n- `article_type`: `news` (default) or `newspic`\n- For `news`, include `thumb_media_id` (cover required)\n- Always include `need_open_comment` (default `1`) and `only_fans_can_comment` (default `0`) in the request body, even if the CLI doesn't expose them\n\n**Browser method** (accepts `--markdown` or `--html`):\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-article.ts --markdown <markdown_file> --theme <theme> [--color <color>] [--no-cite]\n${BUN_X} {baseDir}/scripts/wechat-article.ts --html <html_file>\n```\n\n### Step 5: Completion Report\n\n```\nWeChat Publishing Complete!\n\nInput: [type] - [path]\nMethod: [API | Browser]\nTheme: [theme] [color if set]\n\nArticle:\n• Title: [title]\n• Summary: [summary]\n• Images: [N] inline\n• Comments: [open/closed], [fans-only/all]    ← API method only\n\nResult:\n✓ Draft saved to WeChat Official Account\n• media_id: [media_id]                         ← API method only\n\nNext Steps (API):\n→ Manage drafts: https://mp.weixin.qq.com (登录后进入「内容管理」→「草稿箱」)\n\nFiles created:\n[• post-to-wechat/YYYY-MM-DD/slug.md (if plain text input)]\n[• slug.html (converted)]\n```\n\n## Feature Comparison\n\n| Feature | Image-Text | Article (API) | Article (Remote API) | Article (Browser) |\n|---------|:---:|:---:|:---:|:---:|\n| Plain text input | ✗ | ✓ | ✓ | ✓ |\n| HTML input | ✗ | ✓ | ✓ | ✓ |\n| Markdown input | Title/content | ✓ | ✓ | ✓ |\n| Multiple images | ✓ (up to 9) | ✓ (inline) | ✓ (inline) | ✓ (inline) |\n| Themes | ✗ | ✓ | ✓ | ✓ |\n| Auto-generate metadata | ✗ | ✓ | ✓ | ✓ |\n| Default cover fallback (`imgs/cover.png`) | ✗ | ✓ | ✓ | ✗ |\n| Comment control | ✗ | ✓ | ✓ | ✗ |\n| Requires Chrome | ✓ | ✗ | ✗ | ✓ |\n| Requires API credentials | ✗ | ✓ | ✓ | ✗ |\n| Requires SSH-reachable server with allowlisted IP | ✗ | ✗ | ✓ | ✗ |\n| Speed | Medium | Fast | Fast | Slow |\n\n## Troubleshooting\n\n| Issue | Fix |\n|-------|-----|\n| Missing API credentials | Follow guided setup in Step 2 |\n| Access token error | Verify credentials valid and not expired |\n| Not logged in (browser) | First run opens browser — scan QR to log in. Set `TELEGRAM_BOT_TOKEN` + `TELEGRAM_CHAT_ID` to receive the QR image via Telegram |\n| Chrome not found | Set `WECHAT_BROWSER_CHROME_PATH` |\n| Title/summary missing | Use auto-generation or provide manually |\n| No cover image | Add frontmatter cover or place `imgs/cover.png` in article directory |\n| Wrong comment defaults | Check `need_open_comment` / `only_fans_can_comment` in EXTEND.md |\n| Paste fails | Check system clipboard permissions |\n| `Remote publish host is required` | Set `--remote-host` or `remote_publish_host` in EXTEND.md |\n| `SOCKS proxy on 127.0.0.1:… not ready` | SSH could not start the tunnel — check key, host, `StrictHostKeyChecking`, or use `--remote-connect-timeout` |\n| `ssh exited early` during remote publish | Verify the user can `ssh` non-interactively to the server; raise `--remote-connect-timeout` if the link is slow |\n| Remote API call returns `errcode 40164` (invalid IP) | The remote server's egress IP is not on WeChat's allowlist; add it in 公众号设置 → IP 白名单 |\n\n## References\n\n| File | Content |\n|------|---------|\n| `references/image-text-posting.md` | Image-text parameters, auto-compression |\n| `references/article-posting.md` | Article themes, image handling |\n| `references/multi-account.md` | Multi-account compatibility, credentials, Chrome profiles, CLI |\n| `references/api-setup.md` | Guided credential setup |\n| `references/config/first-time-setup.md` | First-time EXTEND.md setup |\n\n## Extension Support\n\nCustom configurations via EXTEND.md. See \"Preferences\" for paths and supported options.\n\nFile v1.117.4:_meta.json\n\n{\n  \"ownerId\": \"kn7csrrndw79hpke5d0gsnx93d82k67r\",\n  \"slug\": \"baoyu-post-to-wechat\",\n  \"version\": \"1.117.4\",\n  \"publishedAt\": 1779371618223\n}\n\nFile v1.117.4:references/api-setup.md\n\n# API Credential Setup\n\nGuided setup when `WECHAT_APP_ID` / `WECHAT_APP_SECRET` are missing. Invoked by Step 2 of the article-posting workflow.\n\n## Detection\n\nLook for the credentials in this order:\n\n1. Env vars `WECHAT_APP_ID` / `WECHAT_APP_SECRET`\n2. `<cwd>/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n3. `$HOME/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n\nIf none are present, run the guided setup below.\n\n## Guided Setup\n\nShow this message to the user and ask where to save:\n\n```\nWeChat API credentials not found.\n\nTo obtain credentials:\n1. Visit https://mp.weixin.qq.com\n2. Go to: 开发 → 基本配置\n3. Copy AppID and AppSecret\n\nWhere to save?\nA) Project-level: .baoyu-skills/.env (this project only)\nB) User-level: ~/.baoyu-skills/.env (all projects)\n```\n\nAfter they choose a location, collect the values (prefer a user-input tool, fall back to a numbered prompt per the User Input Tools rule in SKILL.md) and append:\n\n```\nWECHAT_APP_ID=<user_input>\nWECHAT_APP_SECRET=<user_input>\n```\n\n## Multi-Account Variant\n\nIf the user has multiple accounts configured (`accounts:` block in EXTEND.md), use prefixed keys instead — see `multi-account.md` → \"Credential Resolution\".\n\nFile v1.117.4:references/article-posting.md\n\n# Article Posting (文章发表)\n\nPost markdown articles to WeChat Official Account with full formatting support.\n\n## Usage\n\n```bash\n# Post markdown article\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md\n\n# With theme\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --theme grace\n\n# Disable bottom citations for ordinary external links\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --no-cite\n\n# With explicit options\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --author \"作者名\" --summary \"摘要\"\n```\n\n## Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `--markdown <path>` | Markdown file to convert and post |\n| `--theme <name>` | Theme: default, grace, simple, modern |\n| `--no-cite` | Keep ordinary external links inline instead of converting them to bottom citations |\n| `--title <text>` | Override title (auto-extracted from markdown) |\n| `--author <name>` | Author name |\n| `--summary <text>` | Article summary |\n| `--html <path>` | Pre-rendered HTML file (alternative to markdown) |\n| `--profile <dir>` | Chrome profile directory |\n\n## Markdown Format\n\n```markdown\n---\ntitle: Article Title\nauthor: Author Name\n---\n\n# Title (becomes article title)\n\nRegular paragraph with **bold** and *italic*.\n\n## Section Header\n\n![Image description](./image.png)\n\n- List item 1\n- List item 2\n\n> Blockquote text\n\n[Link text](https://example.com)\n```\n\nMarkdown mode converts ordinary external links into bottom citations by default for WeChat-friendly output. Use `--no-cite` to disable that behavior.\n\n## Image Handling\n\n1. **Parse**: Images in markdown are replaced with `WECHATIMGPH_N`\n2. **Render**: HTML is generated with placeholders in text\n3. **Paste**: HTML content is pasted into WeChat editor\n4. **Replace**: For each placeholder:\n   - Find and select the placeholder text\n   - Scroll into view\n   - Press Backspace to delete the placeholder\n   - Paste the image from clipboard\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `wechat-article.ts` | Main article publishing script |\n| `md-to-wechat.ts` | Markdown to HTML with placeholders |\n| `md/render.ts` | Markdown rendering with themes |\n\n## Example Session\n\n```\nUser: /post-to-wechat --markdown ./article.md\n\nClaude:\n1. Parses markdown, finds 5 images\n2. Generates HTML with placeholders\n3. Opens Chrome, navigates to WeChat editor\n4. Pastes HTML content\n5. For each image:\n   - Selects WECHATIMGPH_1\n   - Scrolls into view\n   - Presses Backspace to delete\n   - Pastes image\n6. Reports: \"Article composed with 5 images.\"\n```\n\nFile v1.117.4:references/config/first-time-setup.md\n\n---\nname: first-time-setup\ndescription: First-time setup flow for baoyu-post-to-wechat preferences\n---\n\n# First-Time Setup\n\n## Overview\n\nWhen no EXTEND.md is found, guide user through preference setup.\n\n**BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:\n- Ask about content or files to publish\n- Ask about themes or publishing methods\n- Proceed to content conversion or publishing\n\nONLY ask the questions in this setup flow, save EXTEND.md, then continue.\n\n## Setup Flow\n\n```\nNo EXTEND.md found\n        |\n        v\n+---------------------+\n| AskUserQuestion     |\n| (all questions)     |\n+---------------------+\n        |\n        v\n+---------------------+\n| Create EXTEND.md    |\n+---------------------+\n        |\n        v\n    Continue to Step 1\n```\n\n## Questions\n\n**Language**: Use user's input language or saved language preference.\n\nUse AskUserQuestion with ALL questions in ONE call:\n\n### Question 1: Default Theme\n\n```yaml\nheader: \"Theme\"\nquestion: \"Default theme for article conversion?\"\noptions:\n  - label: \"default (Recommended)\"\n    description: \"Classic layout - centered title with border, white-on-color H2 (default: blue)\"\n  - label: \"grace\"\n    description: \"Elegant - text shadows, rounded cards, refined blockquotes (default: purple)\"\n  - label: \"simple\"\n    description: \"Minimal modern - asymmetric rounded corners, clean whitespace (default: green)\"\n  - label: \"modern\"\n    description: \"Large rounded corners, pill headings, spacious (default: orange)\"\n```\n\n### Question 2: Default Color\n\n```yaml\nheader: \"Color\"\nquestion: \"Default color preset? (theme default if not set)\"\noptions:\n  - label: \"Theme default (Recommended)\"\n    description: \"Use the theme's built-in default color\"\n  - label: \"blue\"\n    description: \"#0F4C81 经典蓝\"\n  - label: \"red\"\n    description: \"#A93226 中国红\"\n  - label: \"green\"\n    description: \"#009874 翡翠绿\"\n```\n\nNote: User can choose \"Other\" to type any preset name (vermilion, yellow, purple, sky, rose, olive, black, gray, pink, orange) or hex value.\n\n### Question 3: Default Publishing Method\n\n```yaml\nheader: \"Method\"\nquestion: \"Default publishing method?\"\noptions:\n  - label: \"api (Recommended)\"\n    description: \"Fast, requires API credentials (AppID + AppSecret)\"\n  - label: \"browser\"\n    description: \"Slow, requires Chrome and login session\"\n  - label: \"remote-api\"\n    description: \"Fast, tunnels WeChat API calls through SSH to a server whose IP is on the WeChat allowlist\"\n```\n\nIf the user selects `remote-api`, prompt for `remote_publish_host` and (optionally) `remote_publish_user`, `remote_publish_identity_file`. These can also be filled in later by editing EXTEND.md.\n\n### Question 4: Default Author\n\n```yaml\nheader: \"Author\"\nquestion: \"Default author name for articles?\"\noptions:\n  - label: \"No default\"\n    description: \"Leave empty, specify per article\"\n```\n\nNote: User will likely choose \"Other\" to type their author name.\n\n### Question 5: Open Comments\n\n```yaml\nheader: \"Comments\"\nquestion: \"Enable comments on articles by default?\"\noptions:\n  - label: \"Yes (Recommended)\"\n    description: \"Allow readers to comment on articles\"\n  - label: \"No\"\n    description: \"Disable comments by default\"\n```\n\n### Question 6: Fans-Only Comments\n\n```yaml\nheader: \"Fans only\"\nquestion: \"Restrict comments to followers only?\"\noptions:\n  - label: \"No (Recommended)\"\n    description: \"All readers can comment\"\n  - label: \"Yes\"\n    description: \"Only followers can comment\"\n```\n\n### Question 7: Save Location\n\n```yaml\nheader: \"Save\"\nquestion: \"Where to save preferences?\"\noptions:\n  - label: \"Project (Recommended)\"\n    description: \".baoyu-skills/ (this project only)\"\n  - label: \"User\"\n    description: \"~/.baoyu-skills/ (all projects)\"\n```\n\n## Save Locations\n\n| Choice | Path | Scope |\n|--------|------|-------|\n| Project | `.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | Current project |\n| User | `~/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | All projects |\n\n## After Setup\n\n1. Create directory if needed\n2. Write EXTEND.md\n3. Confirm: \"Preferences saved to [path]\"\n4. Continue to Step 0 (load the saved preferences)\n\n## EXTEND.md Template\n\n### Single Account (Default)\n\n```md\ndefault_theme: [default/grace/simple/modern]\ndefault_color: [preset name, hex, or empty for theme default]\ndefault_publish_method: [api/browser/remote-api]\ndefault_author: [author name or empty]\nneed_open_comment: [1/0]\nonly_fans_can_comment: [1/0]\nchrome_profile_path:\n\n# Remote API publishing — only fill in if default_publish_method is remote-api\n# or you plan to pass --remote on the CLI.\nremote_publish_host:\nremote_publish_user:\nremote_publish_port:\nremote_publish_identity_file:\nremote_publish_known_hosts_file:\nremote_publish_strict_host_key_checking:\nremote_publish_connect_timeout:\nremote_publish_proxy_jump:\n```\n\nRaw `ssh` / `scp` options are intentionally not supported; only the typed keys above are honored. Authentication is SSH key only.\n\n### Multi-Account\n\n```md\ndefault_theme: [default/grace/simple/modern]\ndefault_color: [preset name, hex, or empty for theme default]\n\naccounts:\n  - name: [display name]\n    alias: [short key, e.g. \"baoyu\"]\n    default: true\n    default_publish_method: [api/browser/remote-api]\n    default_author: [author name]\n    need_open_comment: [1/0]\n    only_fans_can_comment: [1/0]\n    app_id: [WeChat App ID, optional]\n    app_secret: [WeChat App Secret, optional]\n    # Remote API publishing (optional, per-account override of globals)\n    remote_publish_host:\n    remote_publish_user:\n    remote_publish_identity_file:\n  - name: [second account name]\n    alias: [short key, e.g. \"ai-tools\"]\n    default_publish_method: [api/browser/remote-api]\n    default_author: [author name]\n    need_open_comment: [1/0]\n    only_fans_can_comment: [1/0]\n```\n\n## Adding More Accounts Later\n\nAfter initial setup, users can add accounts by editing EXTEND.md:\n\n1. Add an `accounts:` block with list items\n2. Move per-account settings (author, publish method, comments) into each account entry\n3. Keep global settings (theme, color) at the top level\n4. Each account needs a unique `alias` (used for CLI `--account` arg and Chrome profile naming)\n5. Set `default: true` on the primary account\n\n## Modifying Preferences Later\n\nUsers can edit EXTEND.md directly or delete it to trigger setup again.\n\nFile v1.117.4:references/image-text-posting.md\n\n# Image-Text Posting (贴图发表, formerly 图文)\n\nPost image-text messages with multiple images to WeChat Official Account.\n\n> **Note**: WeChat has renamed \"图文\" to \"贴图\" in the Official Account menu (as of 2026).\n\n## Usage\n\n```bash\n# Post with images and markdown file (title/content extracted automatically)\n${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/\n\n# Post with explicit title and content\n${BUN_X} ./scripts/wechat-browser.ts --title \"标题\" --content \"内容\" --image img1.png --image img2.png\n\n# Save as draft\n${BUN_X} ./scripts/wechat-browser.ts --markdown source.md --images ./images/ --submit\n```\n\n## Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `--markdown <path>` | Markdown file for title/content extraction |\n| `--images <dir>` | Directory containing images (sorted by name) |\n| `--title <text>` | Article title (max 20 chars, auto-compressed if too long) |\n| `--content <text>` | Article content (max 1000 chars, auto-compressed if too long) |\n| `--image <path>` | Single image file (can be repeated) |\n| `--submit` | Save as draft (default: preview only) |\n| `--profile <dir>` | Chrome profile directory |\n\n## Auto Title/Content from Markdown\n\nWhen using `--markdown`, the script:\n\n1. **Parses frontmatter** for title and author:\n   ```yaml\n   ---\n   title: 文章标题\n   author: 作者名\n   ---\n   ```\n\n2. **Falls back to H1** if no frontmatter title:\n   ```markdown\n   # 这将成为标题\n   ```\n\n3. **Compresses title** to 20 characters if too long:\n   - Original: \"如何在一天内彻底重塑你的人生\"\n   - Compressed: \"一天彻底重塑你的人生\"\n\n4. **Extracts first paragraphs** as content (max 1000 chars)\n\n## Image Directory Mode\n\nWhen using `--images <dir>`:\n\n- All PNG/JPG files in directory are uploaded\n- Files are sorted alphabetically by name\n- Naming convention: `01-cover.png`, `02-content.png`, etc.\n\n## Constraints\n\n| Field | Max Length | Notes |\n|-------|------------|-------|\n| Title | 20 chars | Auto-compressed if longer |\n| Content | 1000 chars | Auto-compressed if longer |\n| Images | 9 max | WeChat limit |\n\n## Example Session\n\n```\nUser: /post-to-wechat --markdown ./article.md --images ./xhs-images/\n\nClaude:\n1. Parses markdown meta:\n   - Title: \"如何在一天内彻底重塑你的人生\" → \"一天内重塑你的人生\"\n   - Author: from frontmatter or default\n2. Extracts content from first paragraphs\n3. Finds 7 images in xhs-images/\n4. Opens Chrome, navigates to WeChat \"图文\" editor\n5. Uploads all images\n6. Fills title and content\n7. Reports: \"Image-text posted with 7 images.\"\n```\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `wechat-browser.ts` | Main image-text posting script |\n| `cdp.ts` | Chrome DevTools Protocol utilities |\n| `copy-to-clipboard.ts` | Clipboard operations |\n\nFile v1.117.4:references/multi-account.md\n\n# Multi-Account Support\n\nDetails for managing multiple WeChat Official Accounts through one EXTEND.md. SKILL.md only covers single-account flow and the selection prompt — read this file when the user has an `accounts:` block, asks to publish to a specific account, or needs per-account credentials.\n\n## Compatibility\n\n| Condition | Mode | Behavior |\n|-----------|------|----------|\n| No `accounts` block | Single-account | Original behavior, no changes |\n| `accounts` with 1 entry | Single-account | Auto-select, no prompt |\n| `accounts` with 2+ entries | Multi-account | Prompt to select before publishing |\n| `accounts` with `default: true` | Multi-account | Pre-select default; user can switch |\n\n## EXTEND.md Example\n\n```md\ndefault_theme: default\ndefault_color: blue\n\naccounts:\n  - name: 宝玉的技术分享\n    alias: baoyu\n    default: true\n    default_publish_method: api\n    default_author: 宝玉\n    need_open_comment: 1\n    only_fans_can_comment: 0\n    app_id: your_wechat_app_id\n    app_secret: your_wechat_app_secret\n  - name: AI工具集\n    alias: ai-tools\n    default_publish_method: browser\n    default_author: AI工具集\n    need_open_comment: 1\n    only_fans_can_comment: 0\n```\n\n## Per-Account vs Global Keys\n\n**Per-account** (also accepted globally as fallback): `default_publish_method`, `default_author`, `need_open_comment`, `only_fans_can_comment`, `app_id`, `app_secret`, `chrome_profile_path`, `remote_publish_host`, `remote_publish_user`, `remote_publish_port`, `remote_publish_identity_file`, `remote_publish_known_hosts_file`, `remote_publish_strict_host_key_checking`, `remote_publish_connect_timeout`, `remote_publish_proxy_jump`.\n\n**Global-only** (always shared): `default_theme`, `default_color`.\n\n## Account Selection (Step 0.5)\n\nInsert between Step 0 (Load EXTEND.md) and Step 1 (Determine input type):\n\n```\nif no accounts block:\n    → single-account mode (original behavior)\nelif accounts.length == 1:\n    → auto-select the only account\nelif --account <alias> CLI arg:\n    → select matching account\nelif one account has default: true:\n    → pre-select, display: \"Using account: <name> (--account to switch)\"\nelse:\n    → prompt user to choose from the list\n```\n\n## Credential Resolution (API Method)\n\nFor the selected account with alias `{alias}`, try in this order (first hit wins):\n\n1. `app_id` / `app_secret` inline in the EXTEND.md account block\n2. Env vars `WECHAT_{ALIAS}_APP_ID` / `WECHAT_{ALIAS}_APP_SECRET` (alias uppercased, hyphens → underscores)\n3. `.baoyu-skills/.env` with the prefixed key `WECHAT_{ALIAS}_APP_ID`\n4. `~/.baoyu-skills/.env` with the prefixed key\n5. Fallback to unprefixed `WECHAT_APP_ID` / `WECHAT_APP_SECRET`\n\n### .env Multi-Account Example\n\n```bash\n# Account: baoyu\nWECHAT_BAOYU_APP_ID=your_wechat_app_id\nWECHAT_BAOYU_APP_SECRET=your_wechat_app_secret\n\n# Account: ai-tools\nWECHAT_AI_TOOLS_APP_ID=your_ai_tools_wechat_app_id\nWECHAT_AI_TOOLS_APP_SECRET=your_ai_tools_wechat_app_secret\n```\n\n## Chrome Profile (Browser Method)\n\nEach account uses an isolated Chrome profile so logins don't collide.\n\n| Source | Path |\n|--------|------|\n| Account `chrome_profile_path` in EXTEND.md | Use as-is |\n| Auto-generated from alias | `{shared_profile_parent}/wechat-{alias}/` |\n| Single-account fallback | Shared default profile |\n\n## CLI `--account` Flag\n\nAll publishing scripts accept `--account <alias>`:\n\n```bash\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account ai-tools\n${BUN_X} {baseDir}/scripts/wechat-article.ts --markdown <file> --theme default --account baoyu\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown <file> --images ./photos/ --account baoyu\n```\n\n## Remote API Publishing\n\n`wechat-api.ts` supports a `remote-api` mode that tunnels WeChat API calls through an SSH SOCKS5 dynamic port forward to a server whose IP is on WeChat's allowlist. Markdown rendering, image processing, draft assembly, and HTML rewriting still happen locally; only outbound HTTPS calls to `api.weixin.qq.com` traverse the tunnel. No files are written to the remote host and `AppSecret` never leaves the local process. The remote host needs only `sshd` and outbound network access.\n\n### Per-Account Configuration\n\n```md\ndefault_theme: default\ndefault_color: blue\ndefault_publish_method: browser   # browser remains the default\n\naccounts:\n  - name: 宝玉的技术分享\n    alias: baoyu\n    default: true\n    default_publish_method: api\n    default_author: 宝玉\n    app_id: your_wechat_app_id\n    app_secret: your_wechat_app_secret\n  - name: AI工具集\n    alias: ai-tools\n    default_publish_method: remote-api\n    default_author: AI工具集\n    app_id: your_ai_tools_app_id\n    app_secret: your_ai_tools_app_secret\n    remote_publish_host: ai-tools-server.example.com\n    remote_publish_user: deploy\n    remote_publish_port: 22\n    remote_publish_identity_file: /home/me/.ssh/id_ed25519\n    remote_publish_known_hosts_file: /home/me/.ssh/known_hosts\n    remote_publish_strict_host_key_checking: accept-new\n```\n\nAccount-level `remote_publish_*` values override top-level globals. CLI `--remote-*` flags override both.\n\n### CLI Usage\n\n```bash\n# Use the account's default_publish_method (remote-api here):\n${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme default --account ai-tools\n\n# Force remote mode regardless of default_publish_method:\n${BUN_X} {baseDir}/scripts/wechat-api.ts <\n\nArchive v1.117.3: 23 files, 82939 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (5316b), references/image-text-posting.md (2833b), references/multi-account.md (3425b), scripts/bun.lock (38334b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard-mac.test.ts (916b), scripts/copy-to-clipboard.ts (14377b), scripts/md-to-wechat.ts (4904b), scripts/package.json (221b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (26530b), scripts/wechat-article-focus.test.ts (2741b), scripts/wechat-article.ts (48947b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (4370b), scripts/wechat-extend-config.ts (10018b), scripts/wechat-image-processor.ts (8524b), SKILL.md (11649b), _meta.json (141b)\n\nArchive v1.117.2: 23 files, 82938 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (5316b), references/image-text-posting.md (2833b), references/multi-account.md (3425b), scripts/bun.lock (38334b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard-mac.test.ts (916b), scripts/copy-to-clipboard.ts (14377b), scripts/md-to-wechat.ts (4904b), scripts/package.json (221b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (26530b), scripts/wechat-article-focus.test.ts (2741b), scripts/wechat-article.ts (48947b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (4370b), scripts/wechat-extend-config.ts (10018b), scripts/wechat-image-processor.ts (8524b), SKILL.md (11648b), _meta.json (141b)\n\nArchive v1.116.5: 21 files, 78109 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (5316b), references/image-text-posting.md (2833b), references/multi-account.md (3425b), scripts/bun.lock (38334b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard.ts (12179b), scripts/md-to-wechat.ts (4904b), scripts/package.json (221b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (26530b), scripts/wechat-article.ts (39145b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (4370b), scripts/wechat-extend-config.ts (10018b), scripts/wechat-image-processor.ts (8524b), SKILL.md (11648b), _meta.json (141b)\n\nArchive v1.115.4: 21 files, 76786 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (5316b), references/image-text-posting.md (2833b), references/multi-account.md (3425b), scripts/bun.lock (38334b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard.ts (12179b), scripts/md-to-wechat.ts (4904b), scripts/package.json (221b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (26530b), scripts/wechat-article.ts (35123b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (4370b), scripts/wechat-extend-config.ts (10018b), scripts/wechat-image-processor.ts (8524b), SKILL.md (11564b), _meta.json (141b)\n\nArchive v1.115.3: 21 files, 76786 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (5316b), references/image-text-posting.md (2833b), references/multi-account.md (3425b), scripts/bun.lock (38334b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard.ts (12179b), scripts/md-to-wechat.ts (4904b), scripts/package.json (221b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (26530b), scripts/wechat-article.ts (35123b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (4370b), scripts/wechat-extend-config.ts (10018b), scripts/wechat-image-processor.ts (8524b), SKILL.md (11564b), _meta.json (141b)\n\nArchive v1.103.2: 21 files, 76738 bytes\n\nFiles: references/api-setup.md (1186b), references/article-posting.md (2567b), references/config/first-time-setup.md (5316b), references/image-text-posting.md (2833b), references/multi-account.md (3425b), scripts/bun.lock (38334b), scripts/cdp.ts (8405b), scripts/check-permissions.ts (8833b), scripts/copy-to-clipboard.ts (12179b), scripts/md-to-wechat.ts (4904b), scripts/package.json (221b), scripts/paste-from-clipboard.ts (5659b), scripts/wechat-agent-browser.ts (11400b), scripts/wechat-api.ts (26530b), scripts/wechat-article.ts (34787b), scripts/wechat-browser.ts (28393b), scripts/wechat-extend-config.test.ts (4370b), scripts/wechat-extend-config.ts (10018b), scripts/wechat-image-processor.ts (8524b), SKILL.md (11564b), _meta.json (141b)","readmeExcerpt":"Skill: Baoyu Post To Wechat Owner: jimliu Summary: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-tex... Tags: latest:1.118.2 Version history: v1.118.2 | 2026-06-13T05:01:20.839Z | auto baoyu-post-to-wechat v1.118.2 - Updated internal logic in wechat-api.ts for improved API handling. - Documentation improvements","codeSnippets":[],"executableExamples":[{"language":"md","snippet":"default_theme: default\ndefault_color: blue\ndefault_publish_method: browser\ndefault_author: 宝玉\nneed_open_comment: 1\nonly_fans_can_comment: 0\nchrome_profile_path: /path/to/chrome/profile\n\n# Remote API publishing (optional) — only set if WeChat's IP allowlist\n# excludes your local machine. See \"Remote API Method\" below.\n# remote_publish_host: server.example.com\n# remote_publish_user: deploy\n# remote_publish_port: 22\n# remote_publish_identity_file: ~/.ssh/id_ed25519\n# remote_publish_known_hosts_file: ~/.ssh/known_hosts\n# remote_publish_strict_host_key_checking: accept-new\n# remote_publish_connect_timeout: 10\n# remote_publish_proxy_jump: bastion.example.com"},{"language":"bash","snippet":"${BUN_X} {baseDir}/scripts/check-permissions.ts"},{"language":"bash","snippet":"${BUN_X} {baseDir}/scripts/wechat-browser.ts --markdown article.md --images ./images/\n${BUN_X} {baseDir}/scripts/wechat-browser.ts --title \"标题\" --content \"内容\" --image img.png --submit"},{"language":"text","snippet":"- [ ] Step 0: Load preferences (EXTEND.md)\n- [ ] Step 0.5: Resolve account (multi-account only — see references/multi-account.md)\n- [ ] Step 1: Determine input type\n- [ ] Step 2: Select method and configure credentials\n- [ ] Step 3: Resolve theme/color and validate metadata\n- [ ] Step 4: Publish to WeChat\n- [ ] Step 5: Report completion"},{"language":"bash","snippet":"${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> [--color <color>] [--title <title>] [--summary <summary>] [--author <author>] [--cover <cover_path>] [--source-url <url>] [--no-cite]"},{"language":"bash","snippet":"${BUN_X} {baseDir}/scripts/wechat-api.ts <file> --theme <theme> --remote [--remote-host <host>] [--remote-user <user>] [--remote-port <port>] [--remote-identity-file <path>] [--remote-known-hosts-file <path>] [--remote-strict-host-key-checking yes|no|accept-new] [--remote-connect-timeout <s>] [--remote-proxy-jump <spec>]"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: baoyu-post-to-wechat\ndescription: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-text posting (贴图, formerly 图文) with multiple images. Markdown article workflows default to converting ordinary external links into bottom citations for WeChat-friendly output. Use when user mentions \"发布公众号\", \"post to wechat\", \"微信公众号\", or \"贴图/图文/文章\".\nversion: 1.118.2\nmetadata:\n  openclaw:\n    homepage: https://github.com/JimLiu/baoyu-skills#baoyu-post-to-wechat\n    requires:\n      anyBins:\n        - bun\n        - npx\n---\n\n# Post to WeChat Official Account\n\n## User Input Tools\n\nWhen this skill prompts the user, follow this tool-selection rule (priority order):\n\n1. **Prefer built-in user-input tools** exposed by the current agent runtime — e.g., `AskUserQuestion`, `request_user_input`, `clarify`, `ask_user`, or any equivalent.\n2. **Fallback**: if no such tool exists, emit a numbered plain-text message and ask the user to reply with the chosen number/answer for each question.\n3. **Batching**: if the tool supports multiple questions per call, combine all applicable questions into a single call; if only single-question, ask them one at a time in priority order.\n\nConcrete `AskUserQuestion` references below are examples — substitute the local equivalent in other runtimes.\n\n## Language\n\nRespond in the user's language. If they write in Chinese, reply in Chinese; if English, English. Keep technical tokens (paths, flags, field names) in English.\n\n## Script Directory\n\n`{baseDir}` = this SKILL.md's directory. Resolve `${BUN_X}`: prefer `bun`; else `npx -y bun`; else suggest `brew install oven-sh/bun/bun`.\n\n| Script | Purpose |\n|--------|---------|\n| `scripts/wechat-browser.ts` | Image-text posts (图文) |\n| `scripts/wechat-article.ts` | Article posting via browser (文章) |\n| `scripts/wechat-api.ts` | Article posting via API (文章) |\n| `scripts/md-to-wechat.ts` | Markdown → WeChat-ready HTML with image placeholders |\n| `scripts/check-permissions.ts` | Verify environment & permissions |\n\n## Preferences (EXTEND.md)\n\nCheck these paths in order; first hit wins:\n\n| Path | Scope |\n|------|-------|\n| `.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | Project |\n| `${XDG_CONFIG_HOME:-$HOME/.config}/baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | XDG |\n| `$HOME/.baoyu-skills/baoyu-post-to-wechat/EXTEND.md` | User home |\n\nFound → read, parse, apply. Not found → run first-time setup (`references/config/first-time-setup.md`) before anything else.\n\n**Minimum keys** (case-insensitive, accept `1/0` or `true/false`):\n\n| Key | Default | Mapping |\n|-----|---------|---------|\n| `default_author` | empty | Fallback for `author` when CLI/frontmatter not provided |\n| `need_open_comment` | `1` | `articles[].need_open_comment` in `draft/add` |\n| `only_fans_can_comment` | `0` | `articles[].only_fans_can_comment` in `draft/add` |\n\n**Recommended EXTEND.md**:\n\n```md\ndefault_theme: default\ndefault_color: bl"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7csrrndw79hpke5d0gsnx93d82k67r\",\n  \"slug\": \"baoyu-post-to-wechat\",\n  \"version\": \"1.118.2\",\n  \"publishedAt\": 1781326880839\n}"},{"path":"references/api-setup.md","content":"# API Credential Setup\n\nGuided setup when `WECHAT_APP_ID` / `WECHAT_APP_SECRET` are missing. Invoked by Step 2 of the article-posting workflow.\n\n## Detection\n\nLook for the credentials in this order:\n\n1. Env vars `WECHAT_APP_ID` / `WECHAT_APP_SECRET`\n2. `<cwd>/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n3. `$HOME/.baoyu-skills/.env` with `WECHAT_APP_ID=...`\n\nIf none are present, run the guided setup below.\n\n## Guided Setup\n\nShow this message to the user and ask where to save:\n\n```\nWeChat API credentials not found.\n\nTo obtain credentials:\n1. Visit https://mp.weixin.qq.com\n2. Go to: 开发 → 基本配置\n3. Copy AppID and AppSecret\n\nWhere to save?\nA) Project-level: .baoyu-skills/.env (this project only)\nB) User-level: ~/.baoyu-skills/.env (all projects)\n```\n\nAfter they choose a location, collect the values (prefer a user-input tool, fall back to a numbered prompt per the User Input Tools rule in SKILL.md) and append:\n\n```\nWECHAT_APP_ID=<user_input>\nWECHAT_APP_SECRET=<user_input>\n```\n\n## Multi-Account Variant\n\nIf the user has multiple accounts configured (`accounts:` block in EXTEND.md), use prefixed keys instead — see `multi-account.md` → \"Credential Resolution\"."},{"path":"references/article-posting.md","content":"# Article Posting (文章发表)\n\nPost markdown articles to WeChat Official Account with full formatting support.\n\n## Usage\n\n```bash\n# Post markdown article\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md\n\n# With theme\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --theme grace\n\n# Disable bottom citations for ordinary external links\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --no-cite\n\n# With explicit options\n${BUN_X} ./scripts/wechat-article.ts --markdown article.md --author \"作者名\" --summary \"摘要\"\n```\n\n## Parameters\n\n| Parameter | Description |\n|-----------|-------------|\n| `--markdown <path>` | Markdown file to convert and post |\n| `--theme <name>` | Theme: default, grace, simple, modern |\n| `--no-cite` | Keep ordinary external links inline instead of converting them to bottom citations |\n| `--title <text>` | Override title (auto-extracted from markdown) |\n| `--author <name>` | Author name |\n| `--summary <text>` | Article summary |\n| `--html <path>` | Pre-rendered HTML file (alternative to markdown) |\n| `--profile <dir>` | Chrome profile directory |\n\n## Markdown Format\n\n```markdown\n---\ntitle: Article Title\nauthor: Author Name\n---\n\n# Title (becomes article title)\n\nRegular paragraph with **bold** and *italic*.\n\n## Section Header\n\n![Image description](./image.png)\n\n- List item 1\n- List item 2\n\n> Blockquote text\n\n[Link text](https://example.com)\n```\n\nMarkdown mode converts ordinary external links into bottom citations by default for WeChat-friendly output. Use `--no-cite` to disable that behavior.\n\n## Image Handling\n\n1. **Parse**: Images in markdown are replaced with `WECHATIMGPH_N`\n2. **Render**: HTML is generated with placeholders in text\n3. **Paste**: HTML content is pasted into WeChat editor\n4. **Replace**: For each placeholder:\n   - Find and select the placeholder text\n   - Scroll into view\n   - Press Backspace to delete the placeholder\n   - Paste the image from clipboard\n\n## Scripts\n\n| Script | Purpose |\n|--------|---------|\n| `wechat-article.ts` | Main article publishing script |\n| `md-to-wechat.ts` | Markdown to HTML with placeholders |\n| `md/render.ts` | Markdown rendering with themes |\n\n## Example Session\n\n```\nUser: /post-to-wechat --markdown ./article.md\n\nClaude:\n1. Parses markdown, finds 5 images\n2. Generates HTML with placeholders\n3. Opens Chrome, navigates to WeChat editor\n4. Pastes HTML content\n5. For each image:\n   - Selects WECHATIMGPH_1\n   - Scrolls into view\n   - Presses Backspace to delete\n   - Pastes image\n6. Reports: \"Article composed with 5 images.\"\n```"},{"path":"references/config/first-time-setup.md","content":"---\nname: first-time-setup\ndescription: First-time setup flow for baoyu-post-to-wechat preferences\n---\n\n# First-Time Setup\n\n## Overview\n\nWhen no EXTEND.md is found, guide user through preference setup.\n\n**BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:\n- Ask about content or files to publish\n- Ask about themes or publishing methods\n- Proceed to content conversion or publishing\n\nONLY ask the questions in this setup flow, save EXTEND.md, then continue.\n\n## Setup Flow\n\n```\nNo EXTEND.md found\n        |\n        v\n+---------------------+\n| AskUserQuestion     |\n| (all questions)     |\n+---------------------+\n        |\n        v\n+---------------------+\n| Create EXTEND.md    |\n+---------------------+\n        |\n        v\n    Continue to Step 1\n```\n\n## Questions\n\n**Language**: Use user's input language or saved language preference.\n\nUse AskUserQuestion with ALL questions in ONE call:\n\n### Question 1: Default Theme\n\n```yaml\nheader: \"Theme\"\nquestion: \"Default theme for article conversion?\"\noptions:\n  - label: \"default (Recommended)\"\n    description: \"Classic layout - centered title with border, white-on-color H2 (default: blue)\"\n  - label: \"grace\"\n    description: \"Elegant - text shadows, rounded cards, refined blockquotes (default: purple)\"\n  - label: \"simple\"\n    description: \"Minimal modern - asymmetric rounded corners, clean whitespace (default: green)\"\n  - label: \"modern\"\n    description: \"Large rounded corners, pill headings, spacious (default: orange)\"\n```\n\n### Question 2: Default Color\n\n```yaml\nheader: \"Color\"\nquestion: \"Default color preset? (theme default if not set)\"\noptions:\n  - label: \"Theme default (Recommended)\"\n    description: \"Use the theme's built-in default color\"\n  - label: \"blue\"\n    description: \"#0F4C81 经典蓝\"\n  - label: \"red\"\n    description: \"#A93226 中国红\"\n  - label: \"green\"\n    description: \"#009874 翡翠绿\"\n```\n\nNote: User can choose \"Other\" to type any preset name (vermilion, yellow, purple, sky, rose, olive, black, gray, pink, orange) or hex value.\n\n### Question 3: Default Publishing Method\n\n```yaml\nheader: \"Method\"\nquestion: \"Default publishing method?\"\noptions:\n  - label: \"api (Recommended)\"\n    description: \"Fast, requires API credentials (AppID + AppSecret)\"\n  - label: \"browser\"\n    description: \"Slow, requires Chrome and login session\"\n  - label: \"remote-api\"\n    description: \"Fast, tunnels WeChat API calls through SSH to a server whose IP is on the WeChat allowlist\"\n```\n\nIf the user selects `remote-api`, prompt for `remote_publish_host` and (optionally) `remote_publish_user`, `remote_publish_identity_file`. These can also be filled in later by editing EXTEND.md.\n\n### Question 4: Default Author\n\n```yaml\nheader: \"Author\"\nquestion: \"Default author name for articles?\"\noptions:\n  - label: \"No default\"\n    description: \"Leave empty, specify per article\"\n```\n\nNote: User will likely choose \"Other\" to type their author name.\n\n### Question 5: Open Comments\n\n```yaml\nheader: \"Comments\"\nquestion: \"Enabl"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-tex... Skill: Baoyu Post To Wechat Owner: jimliu Summary: Posts content to WeChat Official Account (微信公众号) via API or Chrome CDP. Supports article posting (文章) with HTML, markdown, or plain text input, and image-tex... Tags: latest:1.118.2 Version history: v1.118.2 | 2026-06-13T05:01:20.839Z | auto baoyu-post-to-wechat v1.118.2 - Updated internal logic in wechat-api.ts for improved API handling. - Documentation improvements","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1506,"uniquenessScore":47,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T04:04:41.627Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T04:04:41.627Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T23:21:14.334Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}