wxq 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. wxq-1.0.0/LICENSE +21 -0
  2. wxq-1.0.0/PKG-INFO +286 -0
  3. wxq-1.0.0/README.md +250 -0
  4. wxq-1.0.0/pyproject.toml +69 -0
  5. wxq-1.0.0/setup.cfg +4 -0
  6. wxq-1.0.0/src/wxq/__init__.py +3 -0
  7. wxq-1.0.0/src/wxq/bin/find_all_keys_macos.arm64 +0 -0
  8. wxq-1.0.0/src/wxq/bin/find_all_keys_macos.c +319 -0
  9. wxq-1.0.0/src/wxq/cli.py +82 -0
  10. wxq-1.0.0/src/wxq/commands/__init__.py +1 -0
  11. wxq-1.0.0/src/wxq/commands/contacts.py +102 -0
  12. wxq-1.0.0/src/wxq/commands/export.py +118 -0
  13. wxq-1.0.0/src/wxq/commands/favorites.py +155 -0
  14. wxq-1.0.0/src/wxq/commands/history.py +104 -0
  15. wxq-1.0.0/src/wxq/commands/init.py +69 -0
  16. wxq-1.0.0/src/wxq/commands/members.py +72 -0
  17. wxq-1.0.0/src/wxq/commands/new_messages.py +173 -0
  18. wxq-1.0.0/src/wxq/commands/search.py +151 -0
  19. wxq-1.0.0/src/wxq/commands/sessions.py +89 -0
  20. wxq-1.0.0/src/wxq/commands/stats.py +93 -0
  21. wxq-1.0.0/src/wxq/commands/unread.py +91 -0
  22. wxq-1.0.0/src/wxq/core/__init__.py +1 -0
  23. wxq-1.0.0/src/wxq/core/config.py +225 -0
  24. wxq-1.0.0/src/wxq/core/contacts.py +239 -0
  25. wxq-1.0.0/src/wxq/core/context.py +69 -0
  26. wxq-1.0.0/src/wxq/core/crypto.py +170 -0
  27. wxq-1.0.0/src/wxq/core/db_cache.py +131 -0
  28. wxq-1.0.0/src/wxq/core/key_utils.py +63 -0
  29. wxq-1.0.0/src/wxq/exceptions.py +77 -0
  30. wxq-1.0.0/src/wxq/keys/__init__.py +47 -0
  31. wxq-1.0.0/src/wxq/keys/common.py +256 -0
  32. wxq-1.0.0/src/wxq/keys/scanner_linux.py +275 -0
  33. wxq-1.0.0/src/wxq/keys/scanner_macos.py +263 -0
  34. wxq-1.0.0/src/wxq/keys/scanner_windows.py +246 -0
  35. wxq-1.0.0/src/wxq/mcp/__init__.py +1 -0
  36. wxq-1.0.0/src/wxq/mcp/server.py +465 -0
  37. wxq-1.0.0/src/wxq/models/__init__.py +23 -0
  38. wxq-1.0.0/src/wxq/models/config.py +27 -0
  39. wxq-1.0.0/src/wxq/models/contact.py +85 -0
  40. wxq-1.0.0/src/wxq/models/keys.py +25 -0
  41. wxq-1.0.0/src/wxq/models/message.py +150 -0
  42. wxq-1.0.0/src/wxq/models/session.py +31 -0
  43. wxq-1.0.0/src/wxq/output/__init__.py +1 -0
  44. wxq-1.0.0/src/wxq/output/formatter.py +41 -0
  45. wxq-1.0.0/src/wxq/py.typed +0 -0
  46. wxq-1.0.0/src/wxq/services/__init__.py +1 -0
  47. wxq-1.0.0/src/wxq/services/message_parser.py +354 -0
  48. wxq-1.0.0/src/wxq/services/message_service.py +706 -0
  49. wxq-1.0.0/src/wxq.egg-info/PKG-INFO +286 -0
  50. wxq-1.0.0/src/wxq.egg-info/SOURCES.txt +68 -0
  51. wxq-1.0.0/src/wxq.egg-info/dependency_links.txt +1 -0
  52. wxq-1.0.0/src/wxq.egg-info/entry_points.txt +3 -0
  53. wxq-1.0.0/src/wxq.egg-info/requires.txt +12 -0
  54. wxq-1.0.0/src/wxq.egg-info/top_level.txt +1 -0
  55. wxq-1.0.0/tests/test_adversarial.py +150 -0
  56. wxq-1.0.0/tests/test_cli_integration.py +153 -0
  57. wxq-1.0.0/tests/test_cli_more.py +124 -0
  58. wxq-1.0.0/tests/test_config.py +103 -0
  59. wxq-1.0.0/tests/test_contacts.py +115 -0
  60. wxq-1.0.0/tests/test_crypto.py +123 -0
  61. wxq-1.0.0/tests/test_db_cache.py +108 -0
  62. wxq-1.0.0/tests/test_exceptions.py +65 -0
  63. wxq-1.0.0/tests/test_key_utils.py +70 -0
  64. wxq-1.0.0/tests/test_mcp_server.py +180 -0
  65. wxq-1.0.0/tests/test_message_parser.py +108 -0
  66. wxq-1.0.0/tests/test_message_parser_xml.py +231 -0
  67. wxq-1.0.0/tests/test_message_service.py +281 -0
  68. wxq-1.0.0/tests/test_models.py +160 -0
  69. wxq-1.0.0/tests/test_output.py +45 -0
  70. wxq-1.0.0/tests/test_skill_doc.py +100 -0
wxq-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 wxq contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
wxq-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,286 @@
1
+ Metadata-Version: 2.4
2
+ Name: wxq
3
+ Version: 1.0.0
4
+ Summary: 微信本地聊天记录查询工具 — WeChat local chat history query, CLI + MCP server for AI agents
5
+ Author: sakya
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/vpcoderli/wxq
8
+ Project-URL: Repository, https://github.com/vpcoderli/wxq
9
+ Project-URL: Issues, https://github.com/vpcoderli/wxq/issues
10
+ Project-URL: Changelog, https://github.com/vpcoderli/wxq/releases
11
+ Keywords: wechat,weixin,微信,chat-history,chat-export,chatlog,mcp,mcp-server,claude,ai-agents,cli,sqlcipher,sqlite,decryption
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Communications :: Chat
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: click<9,>=8.1
26
+ Requires-Dist: pycryptodome<4,>=3.19
27
+ Requires-Dist: zstandard<1,>=0.22
28
+ Provides-Extra: mcp
29
+ Requires-Dist: mcp<2,>=1.0; extra == "mcp"
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=8.0; extra == "dev"
32
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
33
+ Requires-Dist: mypy>=1.10; extra == "dev"
34
+ Requires-Dist: pyyaml>=6.0; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ # wxq — 微信本地聊天记录查询工具
38
+
39
+ [![CI](https://github.com/vpcoderli/wxq/actions/workflows/ci.yml/badge.svg)](https://github.com/vpcoderli/wxq/actions/workflows/ci.yml)
40
+ ![Python](https://img.shields.io/badge/python-3.10%20|%203.11%20|%203.12%20|%203.13-blue)
41
+ [![License](https://img.shields.io/badge/license-MIT-green)](https://github.com/vpcoderli/wxq/blob/main/LICENSE)
42
+
43
+ > WeChat local chat history query — CLI + MCP server for AI agents
44
+ > 微信聊天记录 · 本地数据库解密 · 命令行查询 · MCP 服务
45
+
46
+ `wxq` reads the encrypted WeChat SQLite databases on your machine, decrypts them locally, and
47
+ exposes messages, contacts, sessions, and statistics through a clean CLI and a Model Context
48
+ Protocol (MCP) server. Nothing leaves your machine.
49
+
50
+ Python-native by design: `pip install`-able, `import`-able, and typed — so it can be embedded
51
+ directly into Python agent frameworks rather than shelled out to as a binary.
52
+
53
+ ## Features
54
+
55
+ - **SQLCipher 4 decryption** — AES-256-CBC with HMAC-SHA512 verification, WAL support
56
+ - **Automatic key extraction** — scan WeChat process memory on macOS, Windows, and Linux
57
+ - **CLI with 11 subcommands** — sessions, history, search, contacts, stats, export, and more
58
+ - **MCP server mode** — expose WeChat data as 8 read-only tools for AI agents (Claude, etc.)
59
+ - **Incremental message tracking** — `new-messages` shows only what's arrived since last check
60
+ - **Time range filtering** — query by date/datetime across all commands
61
+ - **Message type filtering** — filter by text, image, video, voice, file, link, sticker, system
62
+ - **Group chat support** — member lists, per-sender stats, hourly activity breakdown
63
+ - **zstd decompression** — handles WCDB compressed content transparently
64
+ - **Mtime-based DB cache** — decrypted databases are cached and refreshed only when the source changes
65
+ - **Typed** — ships `py.typed`; `mypy --strict` passes clean
66
+
67
+ ## Requirements
68
+
69
+ - Python 3.10+
70
+ - WeChat desktop app (macOS, Windows, or Linux)
71
+ - WeChat must have been logged in at least once (so the local databases exist)
72
+
73
+ ## Installation
74
+
75
+ From source (works today):
76
+
77
+ ```bash
78
+ git clone https://github.com/vpcoderli/wxq.git
79
+ cd wxq
80
+ pip install -e ".[mcp]"
81
+ ```
82
+
83
+ Once published to PyPI:
84
+
85
+ ```bash
86
+ pip install wxq # core
87
+ pip install "wxq[mcp]" # with MCP server support
88
+ ```
89
+
90
+ For development, see [Testing](#testing) below.
91
+
92
+ ## Quick Start
93
+
94
+ ### 1. Extract encryption keys
95
+
96
+ ```bash
97
+ wxq init
98
+ ```
99
+
100
+ This scans the running WeChat process memory to extract database encryption keys and writes them
101
+ to `~/.wxq/`. On macOS and Linux this may require `sudo`.
102
+
103
+ ### 2. Query your data
104
+
105
+ ```bash
106
+ # Recent chat sessions
107
+ wxq sessions
108
+
109
+ # Unread messages
110
+ wxq unread
111
+
112
+ # Chat history with a contact
113
+ wxq history "Alice" --limit 50
114
+
115
+ # Search messages globally
116
+ wxq search "meeting notes"
117
+
118
+ # Search within a specific chat
119
+ wxq search "project" --chat "Work Group"
120
+
121
+ # Time-filtered history
122
+ wxq history "Alice" --start-time "2024-01-01" --end-time "2024-06-30"
123
+
124
+ # Contact list
125
+ wxq contacts --query "Li"
126
+
127
+ # Contact details
128
+ wxq contacts --detail "Alice"
129
+
130
+ # Group members
131
+ wxq members "Work Group"
132
+
133
+ # Chat statistics
134
+ wxq stats "Work Group"
135
+
136
+ # Export chat to file
137
+ wxq export "Alice" -o alice_chat.txt
138
+
139
+ # Incremental new messages (since last check)
140
+ wxq new-messages
141
+
142
+ # Favorites
143
+ wxq favorites
144
+ ```
145
+
146
+ ### 3. Output format
147
+
148
+ All commands return JSON by default; pass `--format text` for human-readable output:
149
+
150
+ ```bash
151
+ wxq sessions --format json
152
+ wxq history "Alice" --format text --limit 100
153
+ ```
154
+
155
+ Exit codes: `1` = target not found / no data, `2` = invalid arguments, `3` = decryption failure.
156
+
157
+ ## MCP Server
158
+
159
+ The MCP server exposes WeChat data as read-only tools, allowing AI agents to query your messages
160
+ and contacts.
161
+
162
+ ### Setup with Claude Desktop
163
+
164
+ Add to your Claude Desktop `claude_desktop_config.json`:
165
+
166
+ ```json
167
+ {
168
+ "mcpServers": {
169
+ "wxq": {
170
+ "command": "wxq-mcp"
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ ### Available MCP Tools
177
+
178
+ | Tool | Description |
179
+ |------|-------------|
180
+ | `get_sessions` | List recent chat sessions with last message preview |
181
+ | `get_unread` | List sessions with unread messages |
182
+ | `get_contacts` | Search or list contacts |
183
+ | `get_contact_detail` | Detailed info for a specific contact |
184
+ | `get_chat_history` | Retrieve message history with time/type filtering |
185
+ | `search_messages` | Search messages by keyword, optionally within a chat |
186
+ | `get_chat_stats` | Message count, type breakdown, top senders, hourly activity |
187
+ | `get_group_members` | List members of a group chat |
188
+
189
+ ## Architecture
190
+
191
+ ```
192
+ src/wxq/
193
+ cli.py # Click CLI entry point
194
+ exceptions.py # Exception hierarchy
195
+ core/
196
+ config.py # Configuration loading
197
+ context.py # AppContext — shared application state
198
+ crypto.py # SQLCipher 4 decryption (AES-256-CBC + HMAC-SHA512)
199
+ db_cache.py # Mtime-based decrypted DB cache
200
+ contacts.py # ContactStore — name resolution and contact queries
201
+ key_utils.py # Key file parsing and path safety
202
+ keys/
203
+ common.py # Cross-platform key scanning interface
204
+ scanner_macos.py # macOS: task_for_pid / mach_vm_read
205
+ scanner_windows.py # Windows: kernel32.ReadProcessMemory
206
+ scanner_linux.py # Linux: /proc/pid/mem
207
+ models/
208
+ contact.py # Contact, ContactDetail, GroupInfo dataclasses
209
+ message.py # Message, ChatContext, ChatStats, type enums
210
+ config.py # Configuration model
211
+ session.py # Session model
212
+ keys.py # Key metadata model
213
+ services/
214
+ message_service.py # Message querying, pagination, stats aggregation
215
+ message_parser.py # zstd decompression, type splitting, content parsing
216
+ commands/ # CLI subcommand implementations
217
+ mcp/
218
+ server.py # MCP server with 8 tools
219
+ output/
220
+ formatter.py # JSON / text output formatting
221
+ ```
222
+
223
+ The CLI and the MCP server are two thin front ends over the same service layer
224
+ (`services/message_service.py`), so both surfaces always expose identical behavior.
225
+
226
+ ## How Decryption Works
227
+
228
+ WeChat stores its data in SQLCipher 4 encrypted SQLite databases. The decryption process:
229
+
230
+ 1. **Key extraction** — The encryption key is stored in WeChat's process memory. `wxq init` scans
231
+ the process to find and verify the 32-byte key using HMAC-SHA512 page authentication.
232
+
233
+ 2. **Page-level decryption** — Each 4096-byte page is decrypted independently with AES-256-CBC.
234
+ The first 16 bytes of the 80-byte reserve area are the IV; the remaining 64 bytes are the
235
+ HMAC-SHA512 signature.
236
+
237
+ 3. **WAL handling** — Write-Ahead Log frames are decrypted and patched back into the main database
238
+ for a consistent view.
239
+
240
+ 4. **Caching** — Decrypted databases are cached in a temp directory, keyed by MD5 of the relative
241
+ path. The cache is invalidated when the source file's mtime changes.
242
+
243
+ ## Configuration
244
+
245
+ State lives in `~/.wxq/` — `config.json`, `all_keys.json`, and `last_check.json`. It is created
246
+ automatically by `wxq init`. Set `WXQ_CONFIG` (or pass `--config`) to override the config path.
247
+
248
+ > **Upgrading from `wechat-query`?** If `~/.wechat-cli/config.json` exists and `~/.wxq/` does not,
249
+ > `wxq` keeps reading the old location, so existing installs work without re-running `init`.
250
+ > Nothing is moved or deleted. The `WECHAT_QUERY_CONFIG` environment variable is still honored as
251
+ > a fallback. To migrate for real, just `mv ~/.wechat-cli ~/.wxq`.
252
+
253
+ ## Testing
254
+
255
+ This project uses a `src/` layout, so an editable install is required before the tests can import
256
+ the package:
257
+
258
+ ```bash
259
+ pip install -e ".[dev,mcp]" # required first — a bare pytest will fail to import wxq
260
+ pytest # run the suite
261
+ pytest tests/test_crypto.py # a single file
262
+ pytest tests/test_crypto.py::TestFullDecrypt::test_single_page_roundtrip # a single test
263
+ pytest --cov=wxq # with coverage
264
+ mypy src/wxq --strict # static type check (passes clean)
265
+ ```
266
+
267
+ 248 tests covering decryption (including corrupt/truncated/wrong-key cases), the SQLCipher
268
+ key-length guard, contacts, XML app-message and media parsing, the XXE safety guard,
269
+ SQL-injection-safe table handling, path-traversal rejection, the DB cache's mtime invalidation,
270
+ config loading, every CLI command end-to-end, and the MCP server handlers. The type checker runs
271
+ in `--strict` mode with no errors.
272
+
273
+ Uncovered code is concentrated in the platform-specific process-memory scanners (`keys/`), which
274
+ require a live WeChat process and OS-level memory access and so cannot run in CI.
275
+
276
+ CI runs the suite on Python 3.10–3.13 (Linux) plus one job each on macOS and Windows, then
277
+ `mypy --strict`, then a wheel build that asserts `py.typed` and the `bin/` scanner are packaged.
278
+
279
+ ## License
280
+
281
+ MIT
282
+
283
+ ---
284
+
285
+ <sub>Keywords: 微信 聊天记录 导出 查询 解密 · WeChat chat history export, WeChat database decrypt,
286
+ SQLCipher, MCP server, chatlog, wxq</sub>
wxq-1.0.0/README.md ADDED
@@ -0,0 +1,250 @@
1
+ # wxq — 微信本地聊天记录查询工具
2
+
3
+ [![CI](https://github.com/vpcoderli/wxq/actions/workflows/ci.yml/badge.svg)](https://github.com/vpcoderli/wxq/actions/workflows/ci.yml)
4
+ ![Python](https://img.shields.io/badge/python-3.10%20|%203.11%20|%203.12%20|%203.13-blue)
5
+ [![License](https://img.shields.io/badge/license-MIT-green)](https://github.com/vpcoderli/wxq/blob/main/LICENSE)
6
+
7
+ > WeChat local chat history query — CLI + MCP server for AI agents
8
+ > 微信聊天记录 · 本地数据库解密 · 命令行查询 · MCP 服务
9
+
10
+ `wxq` reads the encrypted WeChat SQLite databases on your machine, decrypts them locally, and
11
+ exposes messages, contacts, sessions, and statistics through a clean CLI and a Model Context
12
+ Protocol (MCP) server. Nothing leaves your machine.
13
+
14
+ Python-native by design: `pip install`-able, `import`-able, and typed — so it can be embedded
15
+ directly into Python agent frameworks rather than shelled out to as a binary.
16
+
17
+ ## Features
18
+
19
+ - **SQLCipher 4 decryption** — AES-256-CBC with HMAC-SHA512 verification, WAL support
20
+ - **Automatic key extraction** — scan WeChat process memory on macOS, Windows, and Linux
21
+ - **CLI with 11 subcommands** — sessions, history, search, contacts, stats, export, and more
22
+ - **MCP server mode** — expose WeChat data as 8 read-only tools for AI agents (Claude, etc.)
23
+ - **Incremental message tracking** — `new-messages` shows only what's arrived since last check
24
+ - **Time range filtering** — query by date/datetime across all commands
25
+ - **Message type filtering** — filter by text, image, video, voice, file, link, sticker, system
26
+ - **Group chat support** — member lists, per-sender stats, hourly activity breakdown
27
+ - **zstd decompression** — handles WCDB compressed content transparently
28
+ - **Mtime-based DB cache** — decrypted databases are cached and refreshed only when the source changes
29
+ - **Typed** — ships `py.typed`; `mypy --strict` passes clean
30
+
31
+ ## Requirements
32
+
33
+ - Python 3.10+
34
+ - WeChat desktop app (macOS, Windows, or Linux)
35
+ - WeChat must have been logged in at least once (so the local databases exist)
36
+
37
+ ## Installation
38
+
39
+ From source (works today):
40
+
41
+ ```bash
42
+ git clone https://github.com/vpcoderli/wxq.git
43
+ cd wxq
44
+ pip install -e ".[mcp]"
45
+ ```
46
+
47
+ Once published to PyPI:
48
+
49
+ ```bash
50
+ pip install wxq # core
51
+ pip install "wxq[mcp]" # with MCP server support
52
+ ```
53
+
54
+ For development, see [Testing](#testing) below.
55
+
56
+ ## Quick Start
57
+
58
+ ### 1. Extract encryption keys
59
+
60
+ ```bash
61
+ wxq init
62
+ ```
63
+
64
+ This scans the running WeChat process memory to extract database encryption keys and writes them
65
+ to `~/.wxq/`. On macOS and Linux this may require `sudo`.
66
+
67
+ ### 2. Query your data
68
+
69
+ ```bash
70
+ # Recent chat sessions
71
+ wxq sessions
72
+
73
+ # Unread messages
74
+ wxq unread
75
+
76
+ # Chat history with a contact
77
+ wxq history "Alice" --limit 50
78
+
79
+ # Search messages globally
80
+ wxq search "meeting notes"
81
+
82
+ # Search within a specific chat
83
+ wxq search "project" --chat "Work Group"
84
+
85
+ # Time-filtered history
86
+ wxq history "Alice" --start-time "2024-01-01" --end-time "2024-06-30"
87
+
88
+ # Contact list
89
+ wxq contacts --query "Li"
90
+
91
+ # Contact details
92
+ wxq contacts --detail "Alice"
93
+
94
+ # Group members
95
+ wxq members "Work Group"
96
+
97
+ # Chat statistics
98
+ wxq stats "Work Group"
99
+
100
+ # Export chat to file
101
+ wxq export "Alice" -o alice_chat.txt
102
+
103
+ # Incremental new messages (since last check)
104
+ wxq new-messages
105
+
106
+ # Favorites
107
+ wxq favorites
108
+ ```
109
+
110
+ ### 3. Output format
111
+
112
+ All commands return JSON by default; pass `--format text` for human-readable output:
113
+
114
+ ```bash
115
+ wxq sessions --format json
116
+ wxq history "Alice" --format text --limit 100
117
+ ```
118
+
119
+ Exit codes: `1` = target not found / no data, `2` = invalid arguments, `3` = decryption failure.
120
+
121
+ ## MCP Server
122
+
123
+ The MCP server exposes WeChat data as read-only tools, allowing AI agents to query your messages
124
+ and contacts.
125
+
126
+ ### Setup with Claude Desktop
127
+
128
+ Add to your Claude Desktop `claude_desktop_config.json`:
129
+
130
+ ```json
131
+ {
132
+ "mcpServers": {
133
+ "wxq": {
134
+ "command": "wxq-mcp"
135
+ }
136
+ }
137
+ }
138
+ ```
139
+
140
+ ### Available MCP Tools
141
+
142
+ | Tool | Description |
143
+ |------|-------------|
144
+ | `get_sessions` | List recent chat sessions with last message preview |
145
+ | `get_unread` | List sessions with unread messages |
146
+ | `get_contacts` | Search or list contacts |
147
+ | `get_contact_detail` | Detailed info for a specific contact |
148
+ | `get_chat_history` | Retrieve message history with time/type filtering |
149
+ | `search_messages` | Search messages by keyword, optionally within a chat |
150
+ | `get_chat_stats` | Message count, type breakdown, top senders, hourly activity |
151
+ | `get_group_members` | List members of a group chat |
152
+
153
+ ## Architecture
154
+
155
+ ```
156
+ src/wxq/
157
+ cli.py # Click CLI entry point
158
+ exceptions.py # Exception hierarchy
159
+ core/
160
+ config.py # Configuration loading
161
+ context.py # AppContext — shared application state
162
+ crypto.py # SQLCipher 4 decryption (AES-256-CBC + HMAC-SHA512)
163
+ db_cache.py # Mtime-based decrypted DB cache
164
+ contacts.py # ContactStore — name resolution and contact queries
165
+ key_utils.py # Key file parsing and path safety
166
+ keys/
167
+ common.py # Cross-platform key scanning interface
168
+ scanner_macos.py # macOS: task_for_pid / mach_vm_read
169
+ scanner_windows.py # Windows: kernel32.ReadProcessMemory
170
+ scanner_linux.py # Linux: /proc/pid/mem
171
+ models/
172
+ contact.py # Contact, ContactDetail, GroupInfo dataclasses
173
+ message.py # Message, ChatContext, ChatStats, type enums
174
+ config.py # Configuration model
175
+ session.py # Session model
176
+ keys.py # Key metadata model
177
+ services/
178
+ message_service.py # Message querying, pagination, stats aggregation
179
+ message_parser.py # zstd decompression, type splitting, content parsing
180
+ commands/ # CLI subcommand implementations
181
+ mcp/
182
+ server.py # MCP server with 8 tools
183
+ output/
184
+ formatter.py # JSON / text output formatting
185
+ ```
186
+
187
+ The CLI and the MCP server are two thin front ends over the same service layer
188
+ (`services/message_service.py`), so both surfaces always expose identical behavior.
189
+
190
+ ## How Decryption Works
191
+
192
+ WeChat stores its data in SQLCipher 4 encrypted SQLite databases. The decryption process:
193
+
194
+ 1. **Key extraction** — The encryption key is stored in WeChat's process memory. `wxq init` scans
195
+ the process to find and verify the 32-byte key using HMAC-SHA512 page authentication.
196
+
197
+ 2. **Page-level decryption** — Each 4096-byte page is decrypted independently with AES-256-CBC.
198
+ The first 16 bytes of the 80-byte reserve area are the IV; the remaining 64 bytes are the
199
+ HMAC-SHA512 signature.
200
+
201
+ 3. **WAL handling** — Write-Ahead Log frames are decrypted and patched back into the main database
202
+ for a consistent view.
203
+
204
+ 4. **Caching** — Decrypted databases are cached in a temp directory, keyed by MD5 of the relative
205
+ path. The cache is invalidated when the source file's mtime changes.
206
+
207
+ ## Configuration
208
+
209
+ State lives in `~/.wxq/` — `config.json`, `all_keys.json`, and `last_check.json`. It is created
210
+ automatically by `wxq init`. Set `WXQ_CONFIG` (or pass `--config`) to override the config path.
211
+
212
+ > **Upgrading from `wechat-query`?** If `~/.wechat-cli/config.json` exists and `~/.wxq/` does not,
213
+ > `wxq` keeps reading the old location, so existing installs work without re-running `init`.
214
+ > Nothing is moved or deleted. The `WECHAT_QUERY_CONFIG` environment variable is still honored as
215
+ > a fallback. To migrate for real, just `mv ~/.wechat-cli ~/.wxq`.
216
+
217
+ ## Testing
218
+
219
+ This project uses a `src/` layout, so an editable install is required before the tests can import
220
+ the package:
221
+
222
+ ```bash
223
+ pip install -e ".[dev,mcp]" # required first — a bare pytest will fail to import wxq
224
+ pytest # run the suite
225
+ pytest tests/test_crypto.py # a single file
226
+ pytest tests/test_crypto.py::TestFullDecrypt::test_single_page_roundtrip # a single test
227
+ pytest --cov=wxq # with coverage
228
+ mypy src/wxq --strict # static type check (passes clean)
229
+ ```
230
+
231
+ 248 tests covering decryption (including corrupt/truncated/wrong-key cases), the SQLCipher
232
+ key-length guard, contacts, XML app-message and media parsing, the XXE safety guard,
233
+ SQL-injection-safe table handling, path-traversal rejection, the DB cache's mtime invalidation,
234
+ config loading, every CLI command end-to-end, and the MCP server handlers. The type checker runs
235
+ in `--strict` mode with no errors.
236
+
237
+ Uncovered code is concentrated in the platform-specific process-memory scanners (`keys/`), which
238
+ require a live WeChat process and OS-level memory access and so cannot run in CI.
239
+
240
+ CI runs the suite on Python 3.10–3.13 (Linux) plus one job each on macOS and Windows, then
241
+ `mypy --strict`, then a wheel build that asserts `py.typed` and the `bin/` scanner are packaged.
242
+
243
+ ## License
244
+
245
+ MIT
246
+
247
+ ---
248
+
249
+ <sub>Keywords: 微信 聊天记录 导出 查询 解密 · WeChat chat history export, WeChat database decrypt,
250
+ SQLCipher, MCP server, chatlog, wxq</sub>
@@ -0,0 +1,69 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "wxq"
7
+ version = "1.0.0"
8
+ description = "微信本地聊天记录查询工具 — WeChat local chat history query, CLI + MCP server for AI agents"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ authors = [{ name = "sakya" }]
12
+ requires-python = ">=3.10"
13
+ keywords = [
14
+ "wechat", "weixin", "微信", "chat-history", "chat-export", "chatlog",
15
+ "mcp", "mcp-server", "claude", "ai-agents",
16
+ "cli", "sqlcipher", "sqlite", "decryption",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 4 - Beta",
20
+ "Environment :: Console",
21
+ "Intended Audience :: Developers",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Topic :: Communications :: Chat",
28
+ "Typing :: Typed",
29
+ ]
30
+ dependencies = [
31
+ "click>=8.1,<9",
32
+ "pycryptodome>=3.19,<4",
33
+ "zstandard>=0.22,<1",
34
+ ]
35
+
36
+ [project.optional-dependencies]
37
+ mcp = ["mcp>=1.0,<2"]
38
+ dev = [
39
+ "pytest>=8.0",
40
+ "pytest-cov>=5.0",
41
+ "mypy>=1.10",
42
+ "pyyaml>=6.0",
43
+ ]
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/vpcoderli/wxq"
47
+ Repository = "https://github.com/vpcoderli/wxq"
48
+ Issues = "https://github.com/vpcoderli/wxq/issues"
49
+ Changelog = "https://github.com/vpcoderli/wxq/releases"
50
+
51
+ [project.scripts]
52
+ wxq = "wxq.cli:main"
53
+ wxq-mcp = "wxq.mcp.server:main"
54
+
55
+ [tool.setuptools.packages.find]
56
+ where = ["src"]
57
+
58
+ [tool.setuptools.package-data]
59
+ wxq = ["py.typed", "bin/*"]
60
+
61
+ [tool.mypy]
62
+ python_version = "3.10"
63
+ strict = true
64
+ warn_return_any = true
65
+ warn_unused_configs = true
66
+
67
+ [tool.pytest.ini_options]
68
+ testpaths = ["tests"]
69
+ addopts = "-v --tb=short"
wxq-1.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """wxq — Query local WeChat data via CLI or MCP server."""
2
+
3
+ __version__ = "1.0.0"