Version Packages - #147
Merged
Merged
Conversation
73 tasks
kyan-du
added a commit
to kyan-du/agent-wechat
that referenced
this pull request
Aug 13, 2026
* Log WeChat crash/recovery in health monitor (#115) The health monitor silently ignored when WeChat's process disappeared (segfault, etc.) — no logs were emitted. Now it logs when the process disappears and when it comes back. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct status display for WeChat connection (fixes #74) (#114) Two changes: 1. status.ts: `!snapshot.connected` → `snapshot.connected === false` The CLI-side status check builds snapshots without runtime state, so `connected` is undefined. The falsy check treated undefined as disconnected, reporting WARN even when WeChat was working. 2. channel.ts: Add status.buildAccountSnapshot hook. Merges monitor runtime state (connected, linked, running) into daemon-side snapshots. Without this, the gateway only included static config fields in the snapshot passed to collectWeChatStatusIssues. Added status.test.ts with 7 test cases covering connected/disconnected/ undefined/auth/linked scenarios. Co-authored-by: Kyan Du <kyan.du@icloud.com> * Add changeset for health monitor crash logging (#115) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Version Packages (#112) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Move WeChat restart from entrypoint to health monitor (#116) * Move WeChat restart from entrypoint to health monitor The entrypoint bash restart loop was unreliable — WeChat would crash and not get restarted. Move the restart logic into the agent-server health monitor which already detects when the process disappears. The health monitor now spawns WeChat directly when it detects the process is gone, with the same crash loop protection (5 restarts within 60s triggers a 30s backoff). The entrypoint still does the initial launch but no longer loops. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Extract shared launch-wechat.sh script for entrypoint and health monitor Both the entrypoint (initial launch) and health monitor (restart after crash) now call the same script, so WeChat env vars stay in one place. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Move launch-wechat script to docker/tools/ (on PATH) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * Version Packages (#117) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Replace x86_64 NativeFunction lookup with pure memory hashmap walk (#118) The enumerate_sessions step previously called a WeChat function (0x392c1d0) from Frida's thread to find the session vector. This risked corrupting shared state and crashing WeChat. Now walks the unordered_map linked list with pure pointer reads instead. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * Version Packages (#119) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Move server setup to first step in wechat extension README (#120) The server needs to be running before installing the extension or configuring the channel, so it belongs as step 1 in the setup flow. https://claude.ai/code/session_016yXZUhTChJsbPR7mENH3x9 Co-authored-by: Claude <noreply@anthropic.com> * Remove port 5900 references from docs — VNC web viewer is served at /vnc/ (#122) Port 5900 (raw VNC) is no longer exposed to the host. The browser-based VNC viewer is proxied through the agent server at /vnc/ on port 6174. https://claude.ai/code/session_019cYxiPfAUR2YYTTz2713W9 Co-authored-by: Claude <noreply@anthropic.com> * Add Starlight docs site with full documentation structure Set up an Astro Starlight documentation site in docs/ with pages covering: - Getting started (overview, quickstart) - Architecture (how the FSM engine and container work) - Container setup (CLI, Docker Compose, building from source) - CLI reference (installation, full command list) - OpenClaw integration (setup, configuration, local vs container) - Wechaty integration (puppet setup) - Operations (VNC, tokens, data/storage, proxy, restarting/recovery) - Hosting (requirements, self-hosting, managed hosting) - Reference (REST API, environment variables, troubleshooting) Moved existing dev-notes (release.md, rust-server-investigation.md) to dev-notes/ to make room for the docs site. https://claude.ai/code/session_01EGmcCx8qrMU8kYzAAp7AZt * Add docs site with GitHub Pages deployment, custom styling, and link fixes - Starlight docs site with IBM Plex Sans + JetBrains Mono theme - GitHub Actions workflow for automatic deployment on push to main - Remark plugin to auto-prefix internal links with base path - Custom CSS: dark/light themes, table styling, code blocks, sidebar - Content updates: Docker prerequisites, managed hosting links, remote OpenClaw setup, Wechaty gateway mode, simplified QR scan tips - Documentation links added to root and package READMEs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update GitHub Actions to latest versions (node22 runtime) - dorny/paths-filter v3 → v4 - docker/setup-buildx-action v3 → v4 - docker/login-action v3 → v4 - actions/upload-pages-artifact v3 → v4 - Remove pinned pnpm version (auto-detects from packageManager) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix WeChat a11y by using inherited D-Bus session address (#124) * fix: use inherited DBUS_SESSION_BUS_ADDRESS for WeChat restarts instead of DB value The health monitor was passing session.dbus_address from the DB when restarting WeChat, but this could differ from the D-Bus session that AT-SPI is actually connected to (set up by entrypoint.sh). This caused restarted WeChat instances to connect to the wrong D-Bus bus, making the a11y tree empty and triggering a kill loop. Now spawn_wechat inherits DBUS_SESSION_BUS_ADDRESS from the agent-server process environment (which got it from the entrypoint), ensuring WeChat uses the same D-Bus session as AT-SPI. https://claude.ai/code/session_012RruowqggbS2heNSDuWVGh * chore: add changeset for DBUS_SESSION_BUS_ADDRESS fix https://claude.ai/code/session_012RruowqggbS2heNSDuWVGh * chore: add agent-server to changeset tracking Add package.json for the Rust binary so changesets can track its version alongside the other packages. Add it to the fixed version group. https://claude.ai/code/session_012RruowqggbS2heNSDuWVGh * revert: remove agent-server from changeset tracking The Rust binary version is managed by Cargo.toml, not changesets. https://claude.ai/code/session_012RruowqggbS2heNSDuWVGh * chore: add agent-server to changeset version tracking - Add package.json for agent-server-rust so changesets can track its version - Add it to the fixed version group (all packages version together) - Sync Cargo.toml to current version (0.11.5) - Add sync-cargo-version.sh script to update Cargo.toml after changeset bumps - Update version-packages script to run the sync - Update changeset to reference @agent-wechat/agent-server https://claude.ai/code/session_012RruowqggbS2heNSDuWVGh --------- Co-authored-by: Claude <noreply@anthropic.com> * Version Packages (#125) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Add social share preview (Open Graph + Twitter Card) for doc pages (thisnick#127) Adds an OG image and configures Starlight head meta tags so doc pages render a branded preview when shared on Twitter/X, LinkedIn, Discord, Slack, etc. https://claude.ai/code/session_01N6RBY1UsP4sjWe2YbuRtEv Co-authored-by: Claude <noreply@anthropic.com> * Add social share preview (Open Graph + Twitter Card) for doc pages (thisnick#128) * Add social share preview (Open Graph + Twitter Card) for doc pages Adds an OG image and configures Starlight head meta tags so doc pages render a branded preview when shared on Twitter/X, LinkedIn, Discord, Slack, etc. https://claude.ai/code/session_01N6RBY1UsP4sjWe2YbuRtEv Convert OG image from SVG to PNG at build time using sharp - Add Astro integration that converts public/og-image.svg → PNG during both dev and build via sharp - Fix duplicate opacity attributes in SVG that broke sharp parsing - Update meta tags to reference .png instead of .svg for universal social platform compatibility - Add generated og-image.png to .gitignore (build artifact) https://claude.ai/code/session_01N6RBY1UsP4sjWe2YbuRtEv Redesign OG image and clean up integration code - Replace AI-slop SVG (gradients, grid, rainbow pills) with minimal design: solid dark bg, WeChat green accent bar, bold type, terminal snippet - Fix integration: remove unused imports, pass file path to sharp instead of reading buffer, add mtime check to skip reconversion, use fileURLToPath for cross-platform safety, add error handling - Derive og:image URL from site+base constants instead of hardcoding - Export OG_WIDTH/OG_HEIGHT from integration to share with config https://claude.ai/code/session_01N6RBY1UsP4sjWe2YbuRtEv Generate dynamic per-page OG images with satori at build time Each doc page now gets its own OG image with its title and description rendered via satori (JSX→SVG) + sharp (SVG→PNG). Images are generated during astro:config:setup and cached with mtime checks. - Add satori dependency - Rewrite og-image integration to iterate content/docs, parse frontmatter, and generate public/og/[slug].png per page - Add custom Head.astro component override to inject per-page og:image/twitter:image based on the current route - Remove static og-image.svg (design now lives in code template) - Remove static head entries from Starlight config https://claude.ai/code/session_01N6RBY1UsP4sjWe2YbuRtEv Add project context to per-page OG images Non-root pages now show "agent-wechat — Programmable WeChat for AI agents" above the page title so shared links have brand context. Root page is unchanged. https://claude.ai/code/session_01N6RBY1UsP4sjWe2YbuRtEv * Add docs build job to CI Runs `pnpm build` for the docs package on PRs that touch docs/, pnpm-lock.yaml, or the CI workflow. Uses the same path-filter pattern as the existing ts and rust jobs. https://claude.ai/code/session_01N6RBY1UsP4sjWe2YbuRtEv --------- Co-authored-by: Claude <noreply@anthropic.com> * Update sync-cargo-version.sh to also update Cargo.lock (thisnick#130) After syncing the version from package.json to Cargo.toml, run `cargo update --workspace` so Cargo.lock stays consistent with the bumped version in the Version PR created by changesets. https://claude.ai/code/session_012RBQP5qtwp7DkQ5edLUo9e Co-authored-by: Claude <noreply@anthropic.com> * Fix noVNC token handling in WebSocket connection (thisnick#129) * Fix VNC redirect encoding: pass token as separate query param The injected noVNC script was embedding the token inside the `path` query parameter (e.g. `path=vnc/websockify?token=...`), but `searchParams.set()` percent-encodes the value, turning `?` into `%3F` and `=` into `%3D`. This broke noVNC's ability to parse the token. Fix: set `path` to just `vnc/websockify` and keep `token` as a separate URL query parameter. noVNC natively recognizes the `token` param and passes it to the WebSocket connection. https://claude.ai/code/session_01TMLTZQ9HssUWawScCmeZGT * Update Cargo.lock with current version https://claude.ai/code/session_01TMLTZQ9HssUWawScCmeZGT * Add changeset for VNC redirect params fix https://claude.ai/code/session_01TMLTZQ9HssUWawScCmeZGT --------- Co-authored-by: Claude <noreply@anthropic.com> * Version Packages (thisnick#131) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Fix VNC WebSocket auth: embed token in path param for noVNC (thisnick#132) The upstream fix incorrectly removed the token from the noVNC `path` query parameter, expecting noVNC to pass the `token` URL param to the WebSocket connection natively. It doesn't — noVNC only uses the `path` param to build the WebSocket URL. This broke auth on the websockify endpoint. Restore embedding the token inside the `path` param (vnc/websockify?token=...) so it reaches the auth middleware, and delete it from the visible URL to keep it out of browser history. https://claude.ai/code/session_01TMLTZQ9HssUWawScCmeZGT Co-authored-by: Claude <noreply@anthropic.com> * Version Packages (thisnick#133) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Keep token query param in VNC URL for direct access (thisnick#134) The JS was deleting the top-level `token` param from the URL after embedding it in the `path` param. This broke direct access to the transformed URL because the server's `has_token` check looks for a top-level `token=` query param. Keep `token` in the URL so the page works when bookmarked or shared. https://claude.ai/code/session_01TMLTZQ9HssUWawScCmeZGT Co-authored-by: Claude <noreply@anthropic.com> * Version Packages (thisnick#135) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore: update openclaw dependency to latest (thisnick#137) * chore: update openclaw dependency to latest - Update openclaw from >=2026.3.2 to 2026.3.23-2 - Fix breaking import changes in plugin SDK: - buildChannelKeyCandidates, resolveChannelEntryMatchWithFallback → openclaw/plugin-sdk/channel-targets - resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy → openclaw/plugin-sdk/config-runtime - resolveSenderCommandAuthorization → openclaw/plugin-sdk/command-auth - DEFAULT_ACCOUNT_ID → openclaw/plugin-sdk/account-id - createReplyPrefixOptions → createChannelReplyPipeline from openclaw/plugin-sdk/channel-reply-pipeline - ChannelMeta type → ChannelPlugin["meta"] (no longer separately exported) - Remove onboarding adapter (dropped from ChannelPlugin type) * chore: add changeset for openclaw dependency update * chore: use semver range for openclaw dependency * chore: update lockfile * Version Packages (thisnick#138) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Add new WeChat build offsets (3eda8254, eba86b80) and detach hook after use (thisnick#139) - Add chat selection profiles for builds 3eda8254 (aarch64) and eba86b80 (x86_64) - Add image XOR masks for the same builds in extract-keys - Detach Frida hook in onLeave instead of count-based guard to restore function prologue Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Version Packages (thisnick#140) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Return "pending" for voice media not yet available in DB (thisnick#141) When voice data hasn't been written to media_*.db yet, return type="pending" instead of "unsupported". The extension's pollMedia already retries when data is missing — but short-circuits on "unsupported". This lets voice messages be retried correctly. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Version Packages (thisnick#142) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix: handle non-ASCII filenames in file send (thisnick#143) * fix: handle non-ASCII filenames in file send Two issues caused file sends with non-ASCII filenames (e.g. CJK characters) to silently fail: 1. paste-file: The file:// URI passed to xclip contained raw non-ASCII bytes. WeChat's Qt under POSIX locale cannot resolve such URIs. Fix: detect non-ASCII paths and copy the file to an ASCII-safe temp path before pasting. 2. messages.rs: If std::fs::write failed (or base64 decode failed), file_path stayed None and the handler returned success:true without actually sending anything. Fix: sanitize the filename to ASCII for the temp path, and return proper error responses on failure instead of silently succeeding. * address review: portable iconv check, clarify safe_name comment, add changeset - Replace GNU grep -P with iconv for portable non-ASCII detection (paste-file) - Add comment clarifying dot preservation in safe_name sanitization (messages.rs) - Add patch changeset for @agent-wechat/agent-server --------- Co-authored-by: Kyan Du <kyan.du@icloud.com> * fix: detect @-mentions in type-49 (appmsg) content XML (thisnick#145) For reference/quote messages (type=49), WeChat may place <atuserlist> inside the content XML rather than the source column. This caused @-mentions in quoted replies to be silently missed. Now falls back to checking content XML for type-49 messages when source XML has no mention, ensuring quoted replies with @-mentions are properly detected. Fixes: group chat replies via quote not triggering bot response Co-authored-by: Kyan Du <kyan.du@icloud.com> * Version Packages (thisnick#147) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore: remove dead onboarding adapter The onboarding adapter was deprecated and removed from imports in v0.11.10 but the file was never deleted. No code references it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: add changeset for onboarding removal Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ci): remove npm upgrade step that breaks on Node 22.22.2 The bundled npm on Node 22 already supports OIDC provenance. The `npm install -g npm@latest` step fails with a missing `promise-retry` module on certain GitHub Actions runner images. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Version Packages * fix(ci): pin npm@11.12.1 for OIDC trusted publishing The bundled npm 10.x on Node 22 doesn't support OIDC trusted publishing. Pin to npm@11.12.1 instead of `npm@latest` to avoid the broken `promise-retry` module issue on certain runner images. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Version Packages * feat(openclaw): migrate plugin to openclaw 2026.5 contracts - Add channelConfigs metadata to openclaw.plugin.json so the gateway can validate config and load setup surfaces before the plugin runtime imports (silences "channel plugin manifest declares wechat without channelConfigs metadata" warning). - Replace deprecated runtime.config.loadConfig() with config.current(). - Add a message adapter via createChannelMessageAdapterFromOutbound from openclaw/plugin-sdk/channel-message; keep the legacy outbound adapter for older openclaw versions. - Update access-control test scenario to match openclaw 2026.5's intentional new semantics (pairing-store allowFrom is consulted only for non-"open"/"allowlist" DM policies). - Bump openclaw devDep floor to ^2026.5.12. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(ci): skip npm self-install when runner ships compatible npm The previous unconditional `npm install -g npm@11.12.1` step failed on ubuntu-latest with Node 22.22.2, which already ships a compatible npm 11.x but breaks during self-install with `Cannot find module 'promise-retry'`. Only install when the active npm is older than the OIDC-required floor (11.5). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(ci): activate npm 11.12.1 via Corepack The previous version-checked install still failed: the runner ships npm 10.9.7, and any `npm install` (including self-install) hits `MODULE_NOT_FOUND: 'promise-retry'` at the arborist rebuild step. Use Corepack to activate npm 11.12.1, which downloads the package manager independently of the broken bundled npm. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: establish downstream maintenance baseline * feat: parse merged-forward (chat history) messages (thisnick#126) Parse appmsg subtype 19 (merged forward / chat history) by extracting the XML-escaped <recorditem> content and rendering each <dataitem> as 'sender: message'. Previously only the title was shown, making these messages opaque to agents. Closes thisnick#126 (cherry picked from commit 36c9c30) * fix: sync /api/status loginState with actual logged_in_user from DB Before this fix, /api/status always returned loginState.status as 'logged_out' regardless of actual login state. This caused inconsistency where: - /api/status → logged_out - /api/status/auth → logged_in - sending messages failed with NOT_LOGGED_IN Now get_status() reads the session's logged_in_user from the database and derives the loginState.status from that, which is consistent with how auth_status() determines login state. Fixes: #110 (similar issue with login state inconsistency) (cherry picked from commit a29517e) * fix(send_message): pick active composer when ghost frames exist WeChat's accessibility tree can contain multiple edit+send pairs: the live main-window composer plus stale "ghost" frames left behind by chats previously detached into separate windows. The old depth-first "take the first pair" logic grabbed the wrong (ghost) composer, whose input never received text and whose Send button stayed DISABLED forever, causing the plan to loop and ultimately fail with "No action selected". Collect every candidate edit+send pair and rank them so the genuinely active composer wins: 1. editable currently FOCUSED (strongest signal) 2. Send button NOT disabled (composer already has text) 3. pair under the main "Weixin" frame (not a ghost/detached frame) DFS order breaks any remaining ties. This makes 'wx messages send' reliable even when stale frames are present, removing the need to restart the container to clear ghost windows. (cherry picked from commit 88cbbb6) * fix(chat-select): bounded non-blocking reads and shared composer finder - chat-select.py: replace blocking readline() loops with a select()-based read_lines_until() so deadlines hold even when the frida child stays alive but silent; short-circuit when the target chat is already selected regardless of force, since clicking the selected item never fires the selectSession hook - move the ghost-frame-aware edit+send composer finder from send_message.rs into ia::helpers and reuse it in chat_open.rs, ranking candidates lexicographically (focused > send-enabled > main frame) - send_message: always run chat-select even in "chat" state; the open chat may not be the target and chat-select skips when it already is Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 209cb02) * test: cover adopted message and composer fixes * fix: decode nested entities in merged-forward items * Disable downstream release publishing --------- Co-authored-by: Nick Yu <wiseyu@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Kyan Du <kyan.du@icloud.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: OpenClaw Agent <openclaw@agent.local> Co-authored-by: longxboy <longxboyhi@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or setup this action to publish automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@agent-wechat/cli@0.11.13
@agent-wechat/wechat@0.11.13
@agent-wechat/wechaty-puppet@0.11.13
@agent-wechat/agent-server@0.11.13
Patch Changes
#143
ba19907Thanks @kyan-du! - fix: handle non-ASCII filenames in file sendiconvcheck instead of GNU-onlygrep -Pfor non-ASCII path detection in paste-file@agent-wechat/wechaty-gateway@0.11.13
Patch Changes