David Li
7d2a54c416
chore: untrack .gsd/ runtime files from git index
2026-05-13 17:19:08 +08:00
David Li
11e7372258
fix: change default tracing log level from warn to info
2026-05-13 16:54:52 +08:00
David Li
7ab918adef
Merge milestone/M001: migrate to tracing for structured logging
...
# Conflicts:
# .gitignore
2026-05-13 16:10:47 +08:00
David Li
3d0dd9b8b9
feat: migrate from eprintln! to tracing for structured logging
...
- Add tracing + tracing-subscriber dependencies
- Initialize tracing in main() with env-filter (RUST_LOG support)
- Replace all eprintln! diagnostic messages with tracing macros:
- info! for lifecycle events (daemon startup, cache hits, scan progress)
- warn! for non-fatal errors (skipped DBs, scan limits, connection errors)
- error! for fatal errors (daemon startup failure)
- debug! for cache hits (hidden behind RUST_LOG=debug)
- Add #[tracing::instrument] to key paths:
- daemon::start_daemon — automatic startup timing
- query::{sessions, history, search, new_messages} — per-query timing
- crypto::full_decrypt — per-decrypt timing with page count
- Keep println! for user-facing CLI output (YAML/JSON, status messages)
- Keep eprintln! for test output and CLI progress indicators
2026-05-13 16:08:48 +08:00
David Li
5a4de7f83b
chore: auto-commit after worktree-switch
...
GSD-Unit: m001
2026-05-13 15:50:22 +08:00
David Li
59b2ebbff4
chore: auto-commit after complete-milestone
...
GSD-Unit: M001
2026-05-13 15:45:46 +08:00
David Li
e145090e74
chore: auto-commit after complete-milestone
...
GSD-Unit: M001
2026-05-13 14:54:00 +08:00
David Li
a8ac86452e
test: Added TCP vs local transport data comparison test that queries se…
...
- src/cli/transport.rs
GSD context:
- Milestone: M001 - TCP Transport
- Slice: S04
- Task: T02 - Added TCP vs local transport data comparison test that queries sessions via both transports and asserts deep equality
GSD-Task: S04/T02
2026-05-13 14:40:21 +08:00
David Li
7b50d6abd4
test: Added real TCP daemon integration tests that spawn the actual wx…
...
- src/cli/transport.rs
GSD context:
- Milestone: M001 - TCP Transport
- Slice: S04
- Task: T01 - Added real TCP daemon integration tests that spawn the actual wx binary, connect via TCP, verify ping round-trip, and test connection refused
GSD-Task: S04/T01
2026-05-13 14:37:59 +08:00
David Li
ee54abdc37
test: Added 3 integration tests (round-trip, connection refused, livene…
...
- src/cli/transport.rs
GSD context:
- Milestone: M001 - TCP Transport
- Slice: S03
- Task: T01 - Added 3 integration tests (round-trip, connection refused, liveness check) exercising send_tcp() and is_alive_tcp() against a mock TCP server
GSD-Task: S03/T01
2026-05-13 14:25:09 +08:00
David Li
57ad8f127f
test: All changes compile on native and Windows targets; 32 unit tests…
...
- (none)
GSD context:
- Milestone: M001 - TCP Transport
- Slice: S02
- Task: T03 - All changes compile on native and Windows targets; 32 unit tests pass including new TCP transport tests
GSD-Task: S02/T03
2026-05-13 14:11:42 +08:00
David Li
7681e69e68
feat: Wired --tcp into daemon stop command with manual-stop warning; st…
...
- src/cli/daemon_cmd.rs
GSD context:
- Milestone: M001 - TCP Transport
- Slice: S02
- Task: T02 - Wired --tcp into daemon stop command with manual-stop warning; status already reports TCP vs local
GSD-Task: S02/T02
2026-05-13 14:11:00 +08:00
David Li
2d11f69d5b
feat: Added global --tcp CLI flag and wired TCP transport with 15s conn…
...
- src/cli/mod.rs
- src/cli/transport.rs
- src/cli/daemon_cmd.rs
- src/cli/sessions.rs
- src/cli/history.rs
- src/cli/search.rs
- src/cli/contacts.rs
- src/cli/export.rs
GSD context:
- Milestone: M001 - TCP Transport
- Slice: S02
- Task: T01 - Added global --tcp CLI flag and wired TCP transport with 15s connect/120s read-write timeouts, no silent fallback
GSD-Task: S02/T01
2026-05-13 14:09:47 +08:00
David Li
1f7b843a1a
feat: Wired transport module into daemon server, added TCP listening al…
...
- src/daemon/server.rs
- src/daemon/mod.rs
- src/cli/daemon_cmd.rs
- src/cli/mod.rs
GSD context:
- Milestone: M001 - TCP Transport
- Slice: S01
- Task: T02 - Wired transport module into daemon server, added TCP listening alongside local transport, and implemented `wx daemon start [--tcp ADDR]` subcommand
GSD-Task: S01/T02
2026-05-13 13:57:12 +08:00
David Li
189110f36d
feat: Created transport module with object-safe Listener/Connector trai…
...
- src/transport/mod.rs
- src/main.rs
GSD context:
- Milestone: M001 - TCP Transport
- Slice: S01
- Task: T01 - Created transport module with object-safe Listener/Connector traits, generic handle_connection, and TcpListener/TcpConnector implementations
GSD-Task: S01/T01
2026-05-13 13:46:57 +08:00
jackwener
6659f48984
chore: bump version to 0.1.10
2026-04-19 21:27:59 +08:00
jakevin
c7e2775aa6
perf(sns): parse_post_xml 单走 roxmltree DOM,去掉 regex+DOM 双解析 ( #17 )
...
* perf(sns): parse_post_xml 单走 roxmltree DOM,去掉 regex+DOM 双解析
之前一份 SnsTimeLine.content 在 q_sns_feed / q_sns_search 全表扫描时
要被解两次:extract_xml_text 走字符串扫描取 createTime / contentDesc
/ username,parse_post_media 再 build 一次完整 roxmltree DOM 取媒体
列表。10k+ 行扫描时是显式的工作浪费。
本次重构:
- parse_post_xml 一次性 Document::parse,定位到 TimelineObject 之后所有
字段(createTime / contentDesc / username / media / location)共用同
一个 doc,roxmltree 只 build 一次。
- 把 parse_post_media 拆成 parse_media_from_timeline(node),避免外部
parse 之后又重新 parse;旧的 parse_post_media(&str) 单测专用,标
#[cfg(test)]。
- 删除 sns_location_re(不再需要 regex 抽 poiName)。
- 副作用:roxmltree 自动解码 XML entity,所以 content / location /
username 字段输出的是解码后文本(旧版字符串扫描原样保留 `<` 等)。
对下游是更正确的语义;新增 parse_decodes_xml_entities_in_content 单
测把行为锁住。
- 新增 parse_returns_defaults_for_malformed_xml 单测覆盖 DOM parse 失败
时的 fallback 路径(不 panic、author 走 column fallback)。
q_sns_search 的 LIKE 预筛仍走 extract_xml_text(contentDesc) 字符串扫描
做 false-positive 过滤——这一步比 build 一棵 DOM 更快,是真优化,保
留。q_sns_notifications 也仍用 extract_xml_text,本 PR 不动(每次只跑
~limit 条,DOM 化收益小,避免扩大 scope)。
验证:
- cargo check ×3 target ✅ (darwin / windows-gnu / linux-gnu)
- cargo test 39 passed ✅ (37 → 39,新增 2 个)
* refactor(sns): parse_post_xml dedup 两份 ParsedPost 早 return 块
merge 前自查发现 Document::parse 失败 / 找不到 TimelineObject 两条
fallback 路径写了完全相同的 9 行 ParsedPost 字面量。抽成 empty()
闭包,从 2×9 行降到 1×7 行 + 两个 return empty()。
行为完全等价(含 author = column fallback)。
* fix(sns): salvage scalar fields from malformed post xml
2026-04-19 13:56:55 +08:00
郭立lee
2b5d872f0b
feat(sns): sns-feed / sns-search 输出完整 media[] 字段 ( #15 )
...
在 #14 之上增量:把 sns-feed / sns-search 的 media_count 升级成完整 media[] 数组(含 url/thumb/key/token/md5/enc_idx/size + video_md5/duration),下游可直接做图片代理或离线渲染。
- 用 roxmltree(pure Rust,无 C 依赖)替代 regex 抽属性
- 字段命名对齐 artifacts 仓库 Python _parse_media,跨实现 diff 友好
- 14 个 sns 单测:作者新增 6 个 fixture(单图/三图/视频/纯文字/malformed/缺 totalSize)+ 已有 8 个保持
- 与之前 PR #14 的 --user XML fallback 修复 / SNS_MAX_LIMIT / SNS_MAX_SCAN / escape_like_pattern 完全兼容
Author: leeguooooo <guoli@zhihu.com>
Co-fixed-by: wx-cli-coder (rebase + 冲突解决 + 测试模块合并 + media_count 语义文档补充)
2026-04-19 02:22:55 +08:00
JL
e8939f315d
feat(sns): sns-notifications / sns-feed / sns-search ( #14 )
...
新增 3 个朋友圈相关命令:sns-notifications / sns-feed / sns-search。
PR review 修复(已 push 进同一分支):
- 修 --user 过滤与 XML <username> fallback 打架的 bug(@wx-cli-codex 发现)
- 加 SNS_MAX_LIMIT / SNS_MAX_SCAN 防御性上限
- 抽 escape_like_pattern() helper
- 补 8 个单测(parse_post_xml / escape_like_pattern)
Cargo check 三 target 全过:aarch64-darwin / x86_64-pc-windows-gnu / x86_64-unknown-linux-gnu。
Co-authored-by: fengliu222 <fengliu222@users.noreply.github.com>
2026-04-19 01:58:21 +08:00
郭立lee
f0dcd4ea05
docs(readme): explain how to fetch more than 500 messages ( #13 )
...
Clarify that the 500-message behavior is only a default limit, not a hard cap.
Document `-n/--limit` examples for history, search, and export in both README and SKILL.
2026-04-18 15:01:15 +08:00
jackwener
697d3fc720
chore: bump version to 0.1.9
2026-04-18 02:11:28 +08:00
jackwener
1e52014a6b
perf(daemon): Arc<Names> + tokio RwLock, O(1) clone per IPC request
...
Was: Arc<std::sync::RwLock<Names>>; each dispatch clone_names() copied
4 HashMaps (~100KB for a user with 2700 contacts) and used std RwLock
which blocks the tokio worker thread during the clone.
Now: Arc<tokio::sync::RwLock<Arc<Names>>>; dispatch takes the read
guard, does Arc::clone (pointer bump), drops the guard, then spawns
the query work. Names is immutable after daemon startup; Arc is ideal.
Smoke tested: `wx sessions --json` returns correct data including
chat_type; 8 concurrent clients finish in 12ms.
2026-04-18 02:10:45 +08:00
JL
e977007306
feat(unread): 按 chat_type 分类会话,新增 --filter ( #9 )
...
Before: wx unread / sessions / history 把公众号、订阅号折叠入口
(brandsessionholder)、折叠群聊(@placeholder_foldgroup)、认证服务号
全归为 is_group=false,与真私聊混在一起。甚至 username 形如 wxid_* 但
实为公众号的条目也完全分不出来。
改动:
- 新增 chat_type_of(username, names) helper,输出固定为
group / official_account / folded / private。
- 判据依次:@chatroom → group;brandsessionholder / @placeholder_foldgroup
→ folded;contact.verify_flag != 0 → official_account(覆盖 wxid_*
伪装为公众号的情况,以及银行/品牌服务号、qqsafe / mphelper 等认证账号);
gh_* / biz_* / @* 前缀兜底;其余为 private。
- load_names 顺带读 contact.verify_flag,Names::is_verified 封装查询。
- q_sessions / q_unread / q_history / q_new_messages / q_stats 输出
新增 chat_type 字段,is_group 保留向后兼容并统一由 chat_type 派生。
- wx unread 新增 --filter,clap value_parser 限制可选值为
all / private / group / official / folded,逗号分隔多选,默认 all。
例:wx unread --filter private,group 可过滤公众号与折叠入口。
- SKILL.md / README.md 补充新字段与用法说明。
- .gitignore 补 target/(Rust 项目标配)。
性能:默认 wx unread 的 SQL 与改动前相同(保留 LIMIT)。仅当传入
--filter 时改为全表扫再 Rust 侧过滤,否则 SQL LIMIT 会先把匹配
filter 的条目截断导致漏召。
2026-04-18 01:59:35 +08:00
jackwener
bfb7048cf0
fix: bind CLI --version to crate version (credit: @leeguooooo #4 )
2026-04-18 01:55:37 +08:00
jackwener
c564438994
chore: bump version to 0.1.8
2026-04-18 01:50:25 +08:00
jackwener
e44990ba01
fix: drop privileges after key scan to avoid root-owned ~/.wx-cli/ ( #7 #8 )
...
Root cause: `wx init` does two conceptually-separate things in one
privileged process: (1) scan WeChat memory for keys (needs root) and
(2) write ~/.wx-cli/{all_keys,config}.json (needs only user). When
run under sudo, the files inherit root ownership, so later the daemon
(forked as the user) can't create daemon.sock/log/pid → silent 15s
timeout.
Also: all_keys.json is the raw AES key; 0644 leaked it to every user
on the system.
Fix in init.rs: after the scan completes, immediately setgid+setuid
back to \$SUDO_UID/\$SUDO_GID and set umask 0o077 before any file I/O.
Files are then created as the real user with 0600 by default. Migrate
old broken installs by chown+chmod-recursive before the setuid call.
Fix in transport.rs: pre-check that ~/.wx-cli/ is writable before
spawning daemon; on EACCES print a clear "sudo chown -R ..." hint
instead of the useless "daemon 启动超时" message.
2026-04-18 01:48:42 +08:00
jackwener
ae74072b3f
docs: add Windows cross-check setup and IPC same-library rule
2026-04-17 16:43:05 +08:00
jackwener
4e6907c5cc
chore: bump version to 0.1.7
2026-04-17 16:42:02 +08:00
jackwener
6a2b23486a
fix: client connects via interprocess on Windows, not OpenOptions
...
Server uses interprocess::local_socket, but client was using
std::fs::OpenOptions("\\.\pipe\wx-cli-daemon") which fails to
connect to pipes created by interprocess's tokio listener.
Use the same interprocess client API on both sides for consistency.
Verified with: cargo check --target x86_64-pc-windows-gnu (mingw-w64).
2026-04-17 16:41:32 +08:00
jakevin
33758671d6
Merge pull request #2 from leeguooooo/fix/skill-md-frontmatter
...
fix(skill): add YAML frontmatter so `skills` CLI can detect SKILL.md
2026-04-17 16:36:33 +08:00
jackwener
fe71f1e9f8
chore: bump version to 0.1.6
2026-04-17 15:05:44 +08:00
jackwener
18daf5b22e
fix: Windows init and daemon startup (issue #5 )
...
Three related bugs caused "wx init" and daemon startup to fail on Windows:
1. init.rs: create ~/.wx-cli/ before writing all_keys.json (was created
only before config.json, so first write failed with ENOENT)
2. transport.rs (Windows): daemon.log was always empty because stderr
was never redirected, and log file open silently fell back to null
when parent dir didn't exist. Now mirror the Unix version: create
parent dir, try_clone to redirect both stdout and stderr.
3. server.rs (Windows): interprocess GenericNamespaced auto-prepends
\\.\pipe\ on Windows. Passing the full path caused a double-prefixed
pipe name that clients (using raw \\.\pipe\wx-cli-daemon) could
never connect to, leading to the 15s startup timeout.
2026-04-17 14:01:04 +08:00
leeguooooo
34698faa65
fix(skill): add YAML frontmatter to SKILL.md so `skills` CLI can detect it
...
The `skills` CLI (https://github.com/openclaw/skills ) requires a YAML
frontmatter block with `name` and `description` to recognize a SKILL.md
as a valid skill. The current file declares description as a Markdown
blockquote, which causes:
$ npx skills add jackwener/wx-cli -g
No valid skills found. Skills require a SKILL.md with name and description.
Switching to standard frontmatter makes installation work end-to-end.
Verified with `npx skills add . -l`:
Found 1 skill
wx-cli
2026-04-17 13:27:07 +09:00
jackwener
2c9df70d44
docs: emphasize YAML is more token-efficient, JSON for jq
2026-04-17 11:19:35 +08:00
jackwener
3473f47d1d
docs: use --query instead of -q for clarity
2026-04-17 11:18:32 +08:00
jackwener
e4bfc39c8f
fix: improve task_for_pid error message and document codesign steps
2026-04-17 10:46:55 +08:00
jackwener
0e2711dcf8
chore: bump to 0.1.5, fix publish to skip already-published versions
2026-04-17 09:25:04 +08:00
jackwener
7c27a83340
fix: add missing wx.js launcher to git (was gitignored by global config)
2026-04-17 09:13:03 +08:00
jackwener
a5de749f0a
chore: bump version to 0.1.4
2026-04-17 00:41:01 +08:00
jackwener
69c7a5666c
docs: add acknowledgment for ylytdeng/wechat-decrypt
2026-04-16 23:54:50 +08:00
jackwener
3eddfa0ffa
fix: add permissions:write, fix Windows copy to use PowerShell syntax
2026-04-16 23:49:00 +08:00
jackwener
a2239c0dca
ci: check linux only (windows needs MSVC tools, covered by build job)
2026-04-16 23:42:31 +08:00
jackwener
2170db93eb
ci: remove arm64 from check job (no cross-compiler available)
2026-04-16 23:40:28 +08:00
jackwener
ee1da2ffa6
docs: add CLAUDE.md and AGENTS.md with cross-platform check rules
2026-04-16 23:38:47 +08:00
jackwener
d8f4c6e87d
fix: replace macOS-only libc::__error() with std::io::Error::last_os_error()
2026-04-16 23:35:30 +08:00
jackwener
3413f6c8f4
fix: move anyhow/chrono/dirs/md5/regex back to [dependencies] section
2026-04-16 23:31:41 +08:00
jackwener
2afea74eb9
ci: add cross-platform cargo check job before build
2026-04-16 23:26:08 +08:00
jackwener
6931dfc4cc
chore: update Cargo.lock for v0.1.3
2026-04-16 23:25:02 +08:00
jackwener
ad256288e1
chore: bump version to 0.1.3
2026-04-16 23:15:48 +08:00
jackwener
59dd6bfa24
fix: Windows build errors (handle_connection, creation_flags, mkdir)
...
- server.rs: add handle_connection_windows for named pipe connections
- transport.rs: import CommandExt trait for creation_flags on Windows
- release.yml: mkdir -p before binary copy to npm bin dirs
2026-04-16 23:14:58 +08:00