Commit Graph

19 Commits

Author SHA1 Message Date
Jim Liu 宝玉 e0b861c148 fix(baoyu-post-to-wechat): make remote-api work under Bun & validate config strictly
The initial remote-api implementation (3b29f3c) relied on
`https.request({ agent: SocksProxyAgent })` to route token/upload/draft
calls through the SSH tunnel. Bun's `https.request` does not honor
Node's `http.Agent` contract, so the agent was silently bypassed and
requests still originated from the local IP — defeating the entire
IP-allowlist purpose. Two follow-on issues compounded it: tests read
the real `~/.baoyu-skills/.env` because Bun's `os.homedir()` ignores
test-time `process.env.HOME` mutations, and invalid config values were
silently coerced to defaults.

P1 — Bun-portable SOCKS routing:
- Drop `socks-proxy-agent` dependency. Add `socks` direct dep.
- New `wechat-socks-http.ts`: raw TCP via `SocksClient.createConnection`
  + `tls.connect({ socket, servername })` + hand-built HTTP/1.1 (status
  line parser, case-insensitive headers, chunked & content-length body
  framing). Works identically under Node and Bun because it avoids
  `http.Agent` entirely.
- Rewrite `wechat-http.ts` as a fetch-based local client and expose
  a `WechatClient = (url, init?) => Promise<WechatHttpResponse>`
  functional abstraction.
- `wechat-api.ts`: replace `agent?: http.Agent` with
  `client: WechatClient = wechatHttp` on the five HTTP-touching
  functions; `withSshTunnel` now yields a `WechatClient`.
- New `wechat-socks-http.test.ts` stands up a real SOCKS5 server
  stub + HTTP echo server and asserts `connectionCount === 1`,
  proving bytes actually traverse the proxy under both runtimes.

P2 — `HOME` honored under Bun:
- `homeDir()` reads `process.env.HOME` / `USERPROFILE` first, falling
  back to `os.homedir()`. `loadWechatExtendConfig` and `loadCredentials`
  use it, restoring test isolation.

P3 — Strict config validation:
- Replace lenient `toOptional*` helpers with `parsePort` /
  `parsePositiveInt` / `parseStrictHostKeyChecking` that throw with
  the key name. `loadWechatExtendConfig` only catches file-read
  errors so parse errors surface to the caller. Flip the corresponding
  test cases.

Verification:
- `npm test`: 261/261 pass.
- `bun test` in `scripts/`: 39/39 pass.

Co-authored-by: Dame5211 <1079825614@qq.com>
2026-05-21 02:10:23 -05:00
Jim Liu 宝玉 3b29f3c57c feat(baoyu-post-to-wechat): add remote-api publishing via SSH SOCKS5 tunnel
Re-implements PR #156 (remote WeChat API publishing for IP-allowlist
constraints) with a fully local code path: spawn a background `ssh -N -D`
SOCKS5 dynamic forward, wrap a `SocksProxyAgent`, and thread it through
the existing token/upload/draft flow. No Python helper, no SCP, no
remote files, no `AppSecret` ever leaving the local process.

Reusing `uploadImagesInHtml` (which replaces the matched `<img>` fullTag
rather than substring-replacing `src`) naturally avoids the original
PR's `html.replace(src, url)` HTML-replacement bug.

Changes:
- New `wechat-remote-publish.ts`: typed-whitelist SSH args, free-port
  allocation, SOCKS readiness polling, signal-handler-backed cleanup.
- New `wechat-http.ts`: minimal `https.request`-backed HTTP helper so a
  `SocksProxyAgent` can be passed through (undici `fetch` ignores agent).
- New `wechat-image-loader.ts`: extracts `loadUploadAsset` for reuse.
- `wechat-api.ts`: thread optional `agent?` through token/upload/draft;
  add `--remote*` CLI flags; dispatch via `withSshTunnel` when remote
  mode is selected by flag or `default_publish_method: remote-api`.
- `wechat-extend-config.ts`: add typed `remote_publish_*` keys with
  account-over-global fallback and value validation.
- Docs: SKILL.md, references/multi-account.md, references/config/
  first-time-setup.md, README.md, README.zh.md.
- Tests: 17 new node:test cases covering config parsing, SSH arg
  whitelisting, free-port allocation, multipart assembly, and HTTP
  agent threading.

Co-authored-by: Dame5211 <1079825614@qq.com>
2026-05-21 00:59:36 -05:00
Jim Liu 宝玉 2a0bba6161 fix(baoyu-post-to-wechat): detect actual image format from buffer magic bytes
CDNs may serve WebP for URLs with .png extension. Detect real format
from magic bytes and correct content-type/extension before upload.
Also treat .webp as PNG-preferred for transparency handling.
2026-04-05 13:36:51 -05:00
Jim Liu 宝玉 e4cd8bfefc feat(baoyu-post-to-wechat): improve credential loading with multi-source resolution and diagnostics 2026-03-22 15:42:08 -05:00
Jim Liu 宝玉 eb416d174c fix(baoyu-post-to-wechat): prevent placeholder regex from matching longer numbered variants 2026-03-20 18:45:05 -05:00
Jim Liu 宝玉 0e6bfbcabd refactor: 提取图片处理模块,本地转换不支持的格式而非回退到material接口
将WeChat正文图片的格式转换和压缩逻辑提取到独立的wechat-image-processor模块,
使用jimp和@jsquash/webp在本地将WebP/BMP/GIF等不支持的格式转换为JPEG/PNG并
压缩到1MB以内,避免依赖material接口的回退策略。同时简化了news类型封面兜底逻辑。
2026-03-20 14:43:49 -05:00
浪不能停 79c289ca92 fix: 处理WebP等不支持的格式并优化回退逻辑
- 添加WebP、BMP、TIFF等格式到不支持列表
- 对于需要回退到material接口的情况,同时调用两个接口获取URL和media_id
- 提取uploadToWechat函数避免代码重复
2026-03-20 18:18:01 +08:00
浪不能停 fc5ad4b762 fix: 处理media/uploadimg接口的文件格式和大小限制
- 添加文件大小和格式检查常量
- GIF图片或大于1MB的图片自动回退使用material接口
- 确保向后兼容现有工作流
2026-03-20 14:25:48 +08:00
浪不能停 747977416d fix: 修复newspic类型图片上传和news类型封面兜底逻辑
- uploadImagesInHtml 函数添加 articleType 参数支持
- 为 newspic 类型正文图片额外调用 material 接口收集 media_id
- 返回 firstImageSource 用于 news 类型封面兜底逻辑
- 恢复 news 类型没有显式封面时使用第一张正文图作为封面的逻辑
2026-03-20 13:57:59 +08:00
浪不能停 e79a42fd94 fix: 正文图片上传使用 media/uploadimg 接口
- 区分正文图片和封面图片的上传接口
- 正文图片使用 media/uploadimg (返回 URL)
- 封面图片使用 material/add_material (返回 media_id)
- 添加 uploadType 参数支持两种上传方式
- 优化错误提示,告知用户 news 类型需要封面图
2026-03-18 17:23:48 +08:00
Jim Liu 宝玉 374a6b28fd feat(baoyu-post-to-wechat): add placeholder image upload and fix frontmatter parsing 2026-03-13 10:58:13 -05:00
Jim Liu 宝玉 5276fae6bd feat(baoyu-post-to-wechat): add multi-account support
Support multiple WeChat Official Accounts via EXTEND.md accounts block.
Each account gets isolated Chrome profile, credential resolution chain
(inline → prefixed env → unprefixed env), and --account CLI arg.
2026-03-11 23:24:02 -05:00
Jim Liu 宝玉 970f5e741a feat(baoyu-post-to-wechat): default bottom citations for markdown input
Enable bottom citations by default for markdown articles. Add --no-cite
flag to all posting scripts (wechat-api, wechat-article, md-to-wechat)
to optionally disable. WeChat mp links stay inline.
2026-03-06 23:38:23 -06:00
Jim Liu 宝玉 8787cbe85b feat(baoyu-post-to-wechat): internalize markdown conversion with modular renderer and color support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:01:05 -06:00
Jim Liu 宝玉 54103dfd7d refactor(baoyu-post-to-wechat): prioritize coverImage over featureImage in frontmatter lookup 2026-02-12 01:56:32 -06:00
Jim Liu 宝玉 569beebdd6 feat(baoyu-post-to-wechat): adapt to new WeChat UI and fix digest/cover handling
Rename 图文 to 贴图 throughout; add ProseMirror editor support with old editor
fallback; add fallback file input selector; add upload progress monitoring;
improve save button detection with toast verification; truncate digest > 120
chars at punctuation boundary; fix cover image relative path resolution.
2026-02-10 15:46:09 -06:00
Jim Liu 宝玉 e563bbae7b feat(baoyu-post-to-wechat): add newspic article type support
- Add ArticleOptions interface with news/newspic types
- Track all image media IDs for newspic format
- Restructure publishToDraft for dual article type handling
2026-02-01 19:49:14 -06:00
Jim Liu 宝玉 28a7db6129 chore: release v1.25.4 2026-01-29 17:17:58 -06:00
Jim Liu 宝玉 81e96ee43c feat(baoyu-post-to-wechat): add API publishing and external theme support
- Add wechat-api.ts for direct API-based article publishing
- Support plain text, HTML, and markdown inputs with auto-conversion
- Add external theme discovery from MD_THEME_DIR environment variable
- Improve CSS inlining with juice library integration
- Support WeChat API credentials via .baoyu-skills/.env
2026-01-28 21:37:40 -06:00