mirror of https://github.com/jackwener/wx-cli.git
Merge ea31bfb701 into d750ef6e9f
commit
e1d2f67594
|
|
@ -8,7 +8,7 @@
|
|||
[](#安装)
|
||||
[](https://www.rust-lang.org)
|
||||
|
||||
会话 · 聊天记录 · 搜索 · 联系人 · 群成员 · 收藏 · 统计 · 导出
|
||||
会话 · 聊天记录 · 搜索 · 发送 · 联系人 · 群成员 · 收藏 · 统计 · 导出
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -38,6 +38,7 @@ npx skills add jackwener/wx-cli -g
|
|||
- **毫秒级响应** — 后台 daemon 持久缓存解密数据库,mtime 不变则复用
|
||||
- **AI 友好** — 默认 YAML 输出,更省 token & 易读;`--json` 可切换为 JSON(方便 `jq` 处理等)
|
||||
- **完全本地** — 数据不出本机,实时解密,无需全量预解密
|
||||
- **macOS 发送** — 通过微信搜索快捷键打开聊天并发送文本消息(需辅助功能权限)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -150,10 +151,13 @@ wx history "AI群" --since 2026-04-01 --until 2026-04-15
|
|||
wx search "关键词" # 全库搜索
|
||||
wx search "关键词" -n 500 # 放宽搜索结果条数
|
||||
wx search "会议" --in "工作群" --since 2026-01-01
|
||||
wx send "张三" "你好,今晚 8 点见" # 发送消息(macOS)
|
||||
```
|
||||
|
||||
`history` / `search` / `export` 都支持 `-n` / `--limit` 指定条数。默认值只是为了避免一次性输出过多消息,不是硬上限。
|
||||
|
||||
`send` 是 macOS 屏幕自动化命令:它会激活微信,用 `⌘F` 聚焦搜索框,打开目标聊天后发送文本。使用前需保持微信已登录,并给当前终端或 agent 应用开启"辅助功能"权限;发送过程中会临时使用剪贴板。
|
||||
|
||||
会话/消息输出里都带 `chat_type` 字段,取值为 `private` / `group` / `official_account` / `folded`。`official_account` 涵盖公众号、订阅号、服务号及 `mphelper` / `qqsafe` 等系统通知;`folded` 对应微信里的"订阅号折叠"和"折叠群聊"两个聚合入口。
|
||||
|
||||
### 朋友圈(SNS)
|
||||
|
|
|
|||
10
SKILL.md
10
SKILL.md
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: wx-cli
|
||||
description: "wx-cli — 从本地微信数据库查询聊天记录、联系人、会话、收藏等。用户提到微信聊天记录、联系人、消息历史、群成员、收藏内容时,使用此 skill 安装并调用 wx-cli。"
|
||||
description: "wx-cli — 从本地微信数据库查询聊天记录、联系人、会话、收藏等,并可在 macOS 通过 WeChat 屏幕自动化发送消息。用户提到微信聊天记录、联系人、消息历史、群成员、收藏内容、发送微信消息或回复微信时,使用此 skill 安装并调用 wx-cli。"
|
||||
---
|
||||
|
||||
# wx-cli
|
||||
|
|
@ -16,6 +16,8 @@ description: "wx-cli — 从本地微信数据库查询聊天记录、联系人
|
|||
- wx-cli
|
||||
- 帮我看看微信里
|
||||
- 搜索微信消息
|
||||
- 发送微信消息
|
||||
- 回复微信
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
|
@ -23,6 +25,7 @@ description: "wx-cli — 从本地微信数据库查询聊天记录、联系人
|
|||
- 微信桌面版 4.x 已安装并登录
|
||||
- Node.js >= 14(npm 安装方式)或 curl(shell 安装方式)
|
||||
- 首次 `wx init` 需要 `sudo`(内存扫描提取密钥)
|
||||
- macOS 发送消息需要给当前终端或 agent 应用开启"辅助功能"权限
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -122,10 +125,15 @@ wx history "AI群" --since 2026-04-01 --until 2026-04-15 -n 100
|
|||
wx search "关键词"
|
||||
wx search "关键词" -n 500
|
||||
wx search "会议" --in "工作群" --since 2026-01-01
|
||||
|
||||
# 发送消息(macOS)
|
||||
wx send "张三" "你好"
|
||||
```
|
||||
|
||||
`history` / `search` / `export` 都支持 `-n` / `--limit` 指定返回条数。默认值只是为了避免一次输出过多,不是硬上限。
|
||||
|
||||
`send` 是 macOS 屏幕自动化命令:它会激活微信,用 `⌘F` 聚焦搜索框,打开目标聊天后发送文本。发送前必须由用户明确确认收件人和消息正文;命令会真实发送消息给第三方。发送过程中会临时使用文本剪贴板,并在常见情况下恢复原文本剪贴板内容。
|
||||
|
||||
`sessions` / `unread` / `history` / `new-messages` / `stats` 的输出都带 `chat_type` 字段,agent 可据此分流:
|
||||
|
||||
| 取值 | 含义 | username 特征 |
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ mod init;
|
|||
pub mod sessions;
|
||||
pub mod history;
|
||||
pub mod search;
|
||||
pub mod send;
|
||||
pub mod contacts;
|
||||
pub mod export;
|
||||
pub mod daemon_cmd;
|
||||
|
|
@ -92,6 +93,14 @@ enum Commands {
|
|||
#[arg(long)]
|
||||
json: bool,
|
||||
},
|
||||
/// 发送微信消息(macOS 屏幕自动化)
|
||||
Send {
|
||||
/// 聊天对象名称
|
||||
chat: String,
|
||||
/// 要发送的消息
|
||||
#[arg(allow_hyphen_values = true)]
|
||||
message: String,
|
||||
},
|
||||
/// 查看联系人
|
||||
Contacts {
|
||||
/// 按名字过滤
|
||||
|
|
@ -282,6 +291,7 @@ fn dispatch(cli: Cli) -> Result<()> {
|
|||
Commands::Search { keyword, chats, limit, since, until, msg_type, json } => {
|
||||
search::cmd_search(keyword, chats, limit, since, until, msg_type, json)
|
||||
}
|
||||
Commands::Send { chat, message } => send::cmd_send(chat, message),
|
||||
Commands::Contacts { query, limit, json } => contacts::cmd_contacts(query, limit, json),
|
||||
Commands::Export { chat, since, until, limit, format, output } => {
|
||||
export::cmd_export(chat, since, until, limit, format, output)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
use anyhow::Result;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
use anyhow::{bail, Context};
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::process::Command;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
const SEND_SCRIPT: &str = r#"
|
||||
on run argv
|
||||
if (count of argv) < 2 then error "chat and message are required"
|
||||
set chatName to item 1 of argv
|
||||
set messageText to item 2 of argv
|
||||
set previousClipboard to missing value
|
||||
try
|
||||
set previousClipboard to the clipboard as text
|
||||
end try
|
||||
try
|
||||
tell application id "com.tencent.xinWeChat" to activate
|
||||
delay 0.3
|
||||
tell application "System Events"
|
||||
set wxProc to first application process whose bundle identifier is "com.tencent.xinWeChat"
|
||||
set frontmost of wxProc to true
|
||||
delay 0.2
|
||||
keystroke "f" using command down
|
||||
delay 0.1
|
||||
keystroke "a" using command down
|
||||
delay 0.05
|
||||
my pasteText(chatName)
|
||||
delay 1.5
|
||||
key code 36
|
||||
delay 0.8
|
||||
my pasteText(messageText)
|
||||
delay 0.1
|
||||
key code 36
|
||||
end tell
|
||||
my restoreClipboard(previousClipboard)
|
||||
on error errorMessage number errorNumber
|
||||
my restoreClipboard(previousClipboard)
|
||||
error errorMessage number errorNumber
|
||||
end try
|
||||
end run
|
||||
|
||||
on pasteText(textValue)
|
||||
tell application "System Events"
|
||||
set the clipboard to textValue
|
||||
delay 0.05
|
||||
keystroke "v" using command down
|
||||
end tell
|
||||
end pasteText
|
||||
|
||||
on restoreClipboard(previousClipboard)
|
||||
if previousClipboard is not missing value then set the clipboard to previousClipboard
|
||||
end restoreClipboard
|
||||
"#;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn cmd_send(chat: String, message: String) -> Result<()> {
|
||||
if chat.trim().is_empty() {
|
||||
bail!("聊天对象名称不能为空");
|
||||
}
|
||||
if message.is_empty() {
|
||||
bail!("消息不能为空");
|
||||
}
|
||||
|
||||
let output = Command::new("osascript")
|
||||
.arg("-e")
|
||||
.arg(SEND_SCRIPT)
|
||||
.arg(&chat)
|
||||
.arg(&message)
|
||||
.output()
|
||||
.context("无法运行 osascript")?;
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
|
||||
let reason = if stderr.is_empty() {
|
||||
format!("osascript exited with status {}", output.status)
|
||||
} else {
|
||||
stderr
|
||||
};
|
||||
bail!(
|
||||
"发送微信消息失败:{}。请确认微信已登录,并已给当前终端/应用开启“辅助功能”权限",
|
||||
reason
|
||||
);
|
||||
}
|
||||
|
||||
println!("已发送到 {}", chat);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn cmd_send(_chat: String, _message: String) -> Result<()> {
|
||||
anyhow::bail!("send 命令目前只支持 macOS");
|
||||
}
|
||||
Loading…
Reference in New Issue