@fwgi/fwgi-x-tool 1.1.0 → 1.2.0
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.
- package/SKILL.md +126 -6
- package/index.ts +649 -2
- package/package.json +2 -2
package/SKILL.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fwgi-x-tool
|
|
3
|
-
description: X(Twitter) 营销管理助手 —
|
|
4
|
-
version: 1.
|
|
3
|
+
description: X(Twitter) 营销管理助手 — 账号信息、受众管理、活动管理、收件箱/私信
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
你是 **X 营销管理助手**,帮用户在 X (Twitter)
|
|
7
|
+
你是 **X 营销管理助手**,帮用户在 X (Twitter) 平台上高效管理营销账号、受众资源、营销活动和 DM 私信。
|
|
8
8
|
|
|
9
9
|
## ⚡ 使用前须知
|
|
10
10
|
|
|
@@ -47,6 +47,36 @@ version: 1.1.0
|
|
|
47
47
|
| x_audience_add_to_activity | 将受众添加到营销活动(异步) | 🟡 慢 |
|
|
48
48
|
| x_audience_activity_progress | 查询活动添加进度 | 🟢 快 |
|
|
49
49
|
|
|
50
|
+
### 活动管理(共 6 个)
|
|
51
|
+
|
|
52
|
+
| 工具 | 用途 | 速度 |
|
|
53
|
+
|------|------|------|
|
|
54
|
+
| x_activity_list | 获取活动列表(支持按状态筛选和分页) | 🟢 快 |
|
|
55
|
+
| x_activity_detail | 获取活动详情(含发送统计和消息历史) | 🟢 快 |
|
|
56
|
+
| x_activity_create | 创建营销活动(立即/定时发送) | 🟢 快 |
|
|
57
|
+
| x_activity_update | 更新活动配置 | 🟢 快 |
|
|
58
|
+
| x_activity_delete | 删除活动 ⚠️不可逆 | 🟢 快 |
|
|
59
|
+
| x_activity_regenerate_content | 为活动用户重新生成个性化消息 | 🟡 慢 |
|
|
60
|
+
|
|
61
|
+
### 收件箱/私信(共 14 个)
|
|
62
|
+
|
|
63
|
+
| 工具 | 用途 | 速度 |
|
|
64
|
+
|------|------|------|
|
|
65
|
+
| x_inbox_search | 搜索收件箱(按用户名模糊查询) | 🟢 快 |
|
|
66
|
+
| x_dm_history | 获取 DM 发送历史 | 🟢 快 |
|
|
67
|
+
| x_dm_conversations_by_sessions | 按会话 ID 批量查询 | 🟢 快 |
|
|
68
|
+
| x_dm_conversation | 获取 DM 会话实时数据(外部 API) | 🟡 慢 |
|
|
69
|
+
| x_dm_conversation_detail | 获取单个会话详情(本地数据库) | 🟢 快 |
|
|
70
|
+
| x_dm_activity_messages | 获取活动下的消息列表 | 🟢 快 |
|
|
71
|
+
| x_dm_send_message | 发送单条 DM ⚠️不可撤回 | 🟡 慢 |
|
|
72
|
+
| x_dm_refresh_replies | 刷新会话回复(拉取最新) | 🟡 慢 |
|
|
73
|
+
| x_dm_reply_stats | 获取会话回复统计 | 🟢 快 |
|
|
74
|
+
| x_dm_reply_save | 保存手动回复记录 | 🟢 快 |
|
|
75
|
+
| x_dm_replies | 获取回复历史列表 | 🟢 快 |
|
|
76
|
+
| x_dm_history_soft_delete | 软删除发送历史 | 🟢 快 |
|
|
77
|
+
| x_dm_history_remark | 更新发送历史备注 | 🟢 快 |
|
|
78
|
+
| x_dm_daily_send_stats | 获取今日 DM 发送统计和剩余额度 | 🟢 快 |
|
|
79
|
+
|
|
50
80
|
---
|
|
51
81
|
|
|
52
82
|
## 📋 标准操作流程
|
|
@@ -134,13 +164,103 @@ version: 1.1.0
|
|
|
134
164
|
← 进度:已完成/总计
|
|
135
165
|
```
|
|
136
166
|
|
|
167
|
+
### 第 3 步:活动管理
|
|
168
|
+
|
|
169
|
+
#### 3.1 查看和创建活动
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
→ x_activity_list { account_id: 255, status: "all" }
|
|
173
|
+
← 活动列表(含名称、状态、发送统计)
|
|
174
|
+
|
|
175
|
+
→ x_activity_create { account_id: 255, name: "春季促销", content: "推广新产品", target_user_ids: [100,101] }
|
|
176
|
+
← ✅ 活动创建成功 活动ID: 26
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### 3.2 管理活动
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
→ x_activity_detail { account_id: 255, task_id: 26 }
|
|
183
|
+
← 详情(含 stats 和 recent_history)
|
|
184
|
+
|
|
185
|
+
→ x_activity_update { account_id: 255, task_id: 26, name: "更新后名称" }
|
|
186
|
+
← ✅ 活动更新成功
|
|
187
|
+
|
|
188
|
+
→ x_activity_regenerate_content { account_id: 255, activity_id: 26, user_ids: [100], preview_only: true }
|
|
189
|
+
← 预览生成的个性化消息
|
|
190
|
+
|
|
191
|
+
→ x_activity_delete { account_id: 255, task_id: 26 } ⚠️ 不可逆
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 第 4 步:收件箱/私信管理
|
|
195
|
+
|
|
196
|
+
#### 4.1 浏览收件箱
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
→ x_inbox_search { account_id: 255 }
|
|
200
|
+
← 全部会话列表(含 session_id、target_user_name、status)
|
|
201
|
+
|
|
202
|
+
→ x_inbox_search { account_id: 255, username: "john" }
|
|
203
|
+
← 按用户名筛选
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### 4.2 查看会话内容
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
→ x_dm_conversation_detail { account_id: 255, session_id: "xxx-yyy" }
|
|
210
|
+
← is_first_send, 首次发送内容, 消息列表
|
|
211
|
+
|
|
212
|
+
→ x_dm_conversation { account_id: 255, dm_twitter_id: "1275249432" }
|
|
213
|
+
← 实时 Twitter DM 数据
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### 4.3 发送消息
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
→ x_dm_daily_send_stats { account_id: 255 }
|
|
220
|
+
← 今日已发: 10, 上限: 150, 剩余: 140
|
|
221
|
+
|
|
222
|
+
→ x_dm_send_message { account_id: 255, history_id: 4149 } ⚠️ 不可撤回
|
|
223
|
+
← ✅ 消息发送成功
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### 4.4 回复管理
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
→ x_dm_refresh_replies { account_id: 255, session_id: "xxx-yyy" }
|
|
230
|
+
← 新回复数: 2
|
|
231
|
+
|
|
232
|
+
→ x_dm_reply_stats { account_id: 255, session_id: "xxx-yyy" }
|
|
233
|
+
← reply_count: 3, last_reply_time: ...
|
|
234
|
+
|
|
235
|
+
→ x_dm_replies { account_id: 255, send_history_id: 4149 }
|
|
236
|
+
← 回复历史列表
|
|
237
|
+
|
|
238
|
+
→ x_dm_reply_save { account_id: 255, send_history_id: 4149, reply_content: "感谢回复!" }
|
|
239
|
+
← ✅ 回复已保存
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### 4.5 发送历史管理
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
→ x_dm_history { account_id: 255, status: "success" }
|
|
246
|
+
← 已发送的历史记录
|
|
247
|
+
|
|
248
|
+
→ x_dm_history_remark { account_id: 255, send_history_id: 4149, remark: "潜在客户" }
|
|
249
|
+
← ✅ 备注已更新
|
|
250
|
+
|
|
251
|
+
→ x_dm_history_soft_delete { account_id: 255, send_history_id: 999 }
|
|
252
|
+
← ✅ 已软删除
|
|
253
|
+
```
|
|
254
|
+
|
|
137
255
|
---
|
|
138
256
|
|
|
139
257
|
## ⚠️ 注意事项
|
|
140
258
|
|
|
141
259
|
1. **API Key** — 所有操作依赖 x-api-key,验证失败时引导用户执行 `openclaw config set plugins.entries.fwgi-x-tool.config.apiKey "KEY"` 配置
|
|
142
260
|
2. **频率限制** — search-by-keyword 有严格限制(code 5006),建议间隔 30 秒以上
|
|
143
|
-
3. **慢速操作** — import_url、interactive_users、search_keyword、add_to_activity 超时为 60s
|
|
144
|
-
4. **分页** — audience_list
|
|
145
|
-
5. **不可逆操作** — group_delete
|
|
261
|
+
3. **慢速操作** — import_url、interactive_users、search_keyword、add_to_activity、dm_send_message、dm_conversation、dm_refresh_replies、regenerate_content 超时为 60s
|
|
262
|
+
4. **分页** — audience_list、activity_list、dm_history、inbox_search 等支持 page/page_size;import_url 使用 cursor 分页
|
|
263
|
+
5. **不可逆操作** — group_delete 删除分组不可恢复;activity_delete 删除活动不可恢复;dm_send_message 发送私信不可撤回
|
|
146
264
|
6. **interactive_users 限制** — 依赖 RapidAPI 外部服务,部分环境可能返回 total=0
|
|
265
|
+
7. **DM 每日限额** — 每日 DM 发送有上限(默认 150 条),发送前建议检查 x_dm_daily_send_stats
|
|
266
|
+
8. **参数名区分** — 活动相关操作用 `task_id`,但 regenerate_content 用 `activity_id`;DM 历史写操作(save/delete/remark)用 `send_history_id`,而 send_message 用 `history_id`
|
package/index.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* fwgi-x-tool OpenClaw Plugin
|
|
3
|
-
* X(Twitter) 营销管理助手 —
|
|
3
|
+
* X(Twitter) 营销管理助手 — 账号信息查看、受众管理、活动管理、收件箱/私信
|
|
4
4
|
*
|
|
5
5
|
* 认证方式:通过 x-api-key 请求头调用后端 API(api-backend.fwgi.ai),
|
|
6
6
|
* 启动时调用 /v1/api/checkLogin 验证 API Key 有效性并获取用户信息。
|
|
7
7
|
* 验证通过后,所有后续请求自动携带 x-api-key 头。
|
|
8
8
|
*
|
|
9
|
-
* v1.
|
|
9
|
+
* v1.2.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import * as https from "node:https";
|
|
@@ -874,4 +874,651 @@ export default function register(api: any) {
|
|
|
874
874
|
}
|
|
875
875
|
},
|
|
876
876
|
});
|
|
877
|
+
|
|
878
|
+
// ═══════════════════════════════════════════
|
|
879
|
+
// D. 活动管理模块
|
|
880
|
+
// ═══════════════════════════════════════════
|
|
881
|
+
|
|
882
|
+
api.registerTool({
|
|
883
|
+
name: "x_activity_list",
|
|
884
|
+
description: "获取营销活动列表。支持按状态筛选和分页。返回活动名称、状态、发送统计等信息。",
|
|
885
|
+
parameters: {
|
|
886
|
+
type: "object",
|
|
887
|
+
properties: {
|
|
888
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
889
|
+
status: { type: "string", description: "活动状态筛选: pending / in_progress / completed / failed / all(默认 all)" },
|
|
890
|
+
page: { type: "number", description: "页码(默认 1)" },
|
|
891
|
+
page_size: { type: "number", description: "每页数量(默认 20)" },
|
|
892
|
+
},
|
|
893
|
+
required: ["account_id"],
|
|
894
|
+
},
|
|
895
|
+
async execute(_id: string, params: any) {
|
|
896
|
+
try {
|
|
897
|
+
const config = resolveRuntimeConfig(api);
|
|
898
|
+
await verifyApiKey(config);
|
|
899
|
+
const query: Record<string, string> = { account_id: String(params.account_id) };
|
|
900
|
+
if (params.status) query.status = params.status;
|
|
901
|
+
if (params.page) query.page = String(params.page);
|
|
902
|
+
if (params.page_size) query.page_size = String(params.page_size);
|
|
903
|
+
const resp = await apiRequest(config, "GET", "/v1/api/marketing/activity/list", { query });
|
|
904
|
+
return formatResponse(resp.data);
|
|
905
|
+
} catch (e: any) {
|
|
906
|
+
return err(classifyError(e.message));
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
api.registerTool({
|
|
912
|
+
name: "x_activity_detail",
|
|
913
|
+
description: "获取营销活动详情,包含发送统计(total_sent/success/failed/pending)和最近的消息历史。",
|
|
914
|
+
parameters: {
|
|
915
|
+
type: "object",
|
|
916
|
+
properties: {
|
|
917
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
918
|
+
task_id: { type: "number", description: "活动 ID" },
|
|
919
|
+
},
|
|
920
|
+
required: ["account_id", "task_id"],
|
|
921
|
+
},
|
|
922
|
+
async execute(_id: string, params: any) {
|
|
923
|
+
try {
|
|
924
|
+
const config = resolveRuntimeConfig(api);
|
|
925
|
+
await verifyApiKey(config);
|
|
926
|
+
const resp = await apiRequest(config, "GET", "/v1/api/marketing/activity/detail", {
|
|
927
|
+
query: { account_id: String(params.account_id), task_id: String(params.task_id) },
|
|
928
|
+
});
|
|
929
|
+
return formatResponse(resp.data);
|
|
930
|
+
} catch (e: any) {
|
|
931
|
+
return err(classifyError(e.message));
|
|
932
|
+
}
|
|
933
|
+
},
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
api.registerTool({
|
|
937
|
+
name: "x_activity_create",
|
|
938
|
+
description: "创建营销活动。可指定目标用户列表或筛选条件,支持立即发送或定时发送。",
|
|
939
|
+
parameters: {
|
|
940
|
+
type: "object",
|
|
941
|
+
properties: {
|
|
942
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
943
|
+
name: { type: "string", description: "活动名称" },
|
|
944
|
+
content: { type: "string", description: "营销内容描述" },
|
|
945
|
+
template_id: { type: "number", description: "模板 ID" },
|
|
946
|
+
agent_id: { type: "number", description: "Agent(智能体)ID" },
|
|
947
|
+
send_type: { type: "string", description: "发送类型: immediate(立即)/ scheduled(定时),默认 immediate" },
|
|
948
|
+
send_time: { type: "string", description: "定时发送时间(ISO 格式,send_type=scheduled 时必填)" },
|
|
949
|
+
target_user_ids: { type: "array", items: { type: "number" }, description: "目标用户 ID 列表(twitter_following 表 id),与 filter_conditions 二选一" },
|
|
950
|
+
filter_conditions: { type: "object", description: "筛选条件对象(可含 keyword/can_dm/bot_score/interest_tags/activity_min/activity_max/activity_days),与 target_user_ids 二选一" },
|
|
951
|
+
},
|
|
952
|
+
required: ["account_id", "content"],
|
|
953
|
+
},
|
|
954
|
+
async execute(_id: string, params: any) {
|
|
955
|
+
try {
|
|
956
|
+
const config = resolveRuntimeConfig(api);
|
|
957
|
+
await verifyApiKey(config);
|
|
958
|
+
const body: any = { account_id: params.account_id, content: params.content };
|
|
959
|
+
if (params.name) body.name = params.name;
|
|
960
|
+
if (params.template_id) body.template_id = params.template_id;
|
|
961
|
+
if (params.agent_id) body.agent_id = params.agent_id;
|
|
962
|
+
if (params.send_type) body.send_type = params.send_type;
|
|
963
|
+
if (params.send_time) body.send_time = params.send_time;
|
|
964
|
+
if (params.target_user_ids) body.target_user_ids = params.target_user_ids;
|
|
965
|
+
if (params.filter_conditions) body.filter_conditions = params.filter_conditions;
|
|
966
|
+
const resp = await apiRequest(config, "POST", "/v1/api/marketing/activity/create", { body });
|
|
967
|
+
if (resp.data?.code === 200) {
|
|
968
|
+
const d = resp.data.data;
|
|
969
|
+
return ok(
|
|
970
|
+
`✅ 活动创建成功\n` +
|
|
971
|
+
`活动ID: ${d?.task_id ?? d?.activity_id}\n` +
|
|
972
|
+
`名称: ${d?.name ?? params.name ?? ""}\n` +
|
|
973
|
+
`状态: ${d?.status ?? "pending"}`,
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
return formatResponse(resp.data);
|
|
977
|
+
} catch (e: any) {
|
|
978
|
+
return err(classifyError(e.message));
|
|
979
|
+
}
|
|
980
|
+
},
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
api.registerTool({
|
|
984
|
+
name: "x_activity_update",
|
|
985
|
+
description: "更新营销活动的名称、内容、模板、Agent、发送方式等配置。",
|
|
986
|
+
parameters: {
|
|
987
|
+
type: "object",
|
|
988
|
+
properties: {
|
|
989
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
990
|
+
task_id: { type: "number", description: "活动 ID" },
|
|
991
|
+
name: { type: "string", description: "活动名称" },
|
|
992
|
+
content: { type: "string", description: "营销内容描述" },
|
|
993
|
+
template_id: { type: "number", description: "模板 ID" },
|
|
994
|
+
agent_id: { type: "number", description: "Agent ID" },
|
|
995
|
+
send_type: { type: "string", description: "发送类型: immediate / scheduled" },
|
|
996
|
+
send_time: { type: "string", description: "定时发送时间(ISO 格式)" },
|
|
997
|
+
status: { type: "string", description: "活动状态: pending / in_progress / completed / failed" },
|
|
998
|
+
},
|
|
999
|
+
required: ["account_id", "task_id"],
|
|
1000
|
+
},
|
|
1001
|
+
async execute(_id: string, params: any) {
|
|
1002
|
+
try {
|
|
1003
|
+
const config = resolveRuntimeConfig(api);
|
|
1004
|
+
await verifyApiKey(config);
|
|
1005
|
+
const body: any = { account_id: params.account_id, task_id: params.task_id };
|
|
1006
|
+
for (const key of ["name", "content", "template_id", "agent_id", "send_type", "send_time", "status"]) {
|
|
1007
|
+
if (params[key] !== undefined) body[key] = params[key];
|
|
1008
|
+
}
|
|
1009
|
+
const resp = await apiRequest(config, "POST", "/v1/api/marketing/activity/update", { body });
|
|
1010
|
+
if (resp.data?.code === 200) {
|
|
1011
|
+
return ok(`✅ 活动 ${params.task_id} 更新成功`);
|
|
1012
|
+
}
|
|
1013
|
+
return formatResponse(resp.data);
|
|
1014
|
+
} catch (e: any) {
|
|
1015
|
+
return err(classifyError(e.message));
|
|
1016
|
+
}
|
|
1017
|
+
},
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
api.registerTool({
|
|
1021
|
+
name: "x_activity_delete",
|
|
1022
|
+
description: "删除营销活动。⚠️ 此操作不可逆,删除后活动及其消息历史将无法恢复。",
|
|
1023
|
+
parameters: {
|
|
1024
|
+
type: "object",
|
|
1025
|
+
properties: {
|
|
1026
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1027
|
+
task_id: { type: "number", description: "活动 ID" },
|
|
1028
|
+
},
|
|
1029
|
+
required: ["account_id", "task_id"],
|
|
1030
|
+
},
|
|
1031
|
+
async execute(_id: string, params: any) {
|
|
1032
|
+
try {
|
|
1033
|
+
const config = resolveRuntimeConfig(api);
|
|
1034
|
+
await verifyApiKey(config);
|
|
1035
|
+
const resp = await apiRequest(config, "POST", "/v1/api/marketing/activity/delete", {
|
|
1036
|
+
body: { account_id: params.account_id, task_id: params.task_id },
|
|
1037
|
+
});
|
|
1038
|
+
if (resp.data?.code === 200) {
|
|
1039
|
+
return ok(`✅ 活动 ${params.task_id} 已删除`);
|
|
1040
|
+
}
|
|
1041
|
+
if (resp.data?.code === 4007) {
|
|
1042
|
+
return err("活动不存在,请检查 task_id 是否正确。");
|
|
1043
|
+
}
|
|
1044
|
+
return formatResponse(resp.data);
|
|
1045
|
+
} catch (e: any) {
|
|
1046
|
+
return err(classifyError(e.message));
|
|
1047
|
+
}
|
|
1048
|
+
},
|
|
1049
|
+
});
|
|
1050
|
+
|
|
1051
|
+
api.registerTool({
|
|
1052
|
+
name: "x_activity_regenerate_content",
|
|
1053
|
+
description: "为营销活动中的指定用户重新生成个性化消息内容。支持预览模式(不保存)。",
|
|
1054
|
+
parameters: {
|
|
1055
|
+
type: "object",
|
|
1056
|
+
properties: {
|
|
1057
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1058
|
+
activity_id: { type: "number", description: "活动 ID" },
|
|
1059
|
+
user_ids: { type: "array", items: { type: "number" }, description: "要生成内容的目标用户 ID 列表" },
|
|
1060
|
+
preview_only: { type: "boolean", description: "是否仅预览不保存(默认 false)" },
|
|
1061
|
+
},
|
|
1062
|
+
required: ["account_id", "activity_id", "user_ids"],
|
|
1063
|
+
},
|
|
1064
|
+
async execute(_id: string, params: any) {
|
|
1065
|
+
try {
|
|
1066
|
+
const config = resolveRuntimeConfig(api);
|
|
1067
|
+
await verifyApiKey(config);
|
|
1068
|
+
const body: any = {
|
|
1069
|
+
account_id: params.account_id,
|
|
1070
|
+
activity_id: params.activity_id,
|
|
1071
|
+
user_ids: params.user_ids,
|
|
1072
|
+
};
|
|
1073
|
+
if (params.preview_only !== undefined) body.preview_only = params.preview_only;
|
|
1074
|
+
const resp = await apiRequest(config, "POST", "/v1/api/marketing/activity/regenerate-content", {
|
|
1075
|
+
body,
|
|
1076
|
+
timeoutMs: SLOW_TIMEOUT_MS,
|
|
1077
|
+
});
|
|
1078
|
+
return formatResponse(resp.data);
|
|
1079
|
+
} catch (e: any) {
|
|
1080
|
+
return err(classifyError(e.message));
|
|
1081
|
+
}
|
|
1082
|
+
},
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
// ═══════════════════════════════════════════
|
|
1086
|
+
// E. 收件箱 / DM 模块
|
|
1087
|
+
// ═══════════════════════════════════════════
|
|
1088
|
+
|
|
1089
|
+
api.registerTool({
|
|
1090
|
+
name: "x_inbox_search",
|
|
1091
|
+
description: "搜索收件箱。按目标用户名模糊查询 DM 会话列表,不传 username 则返回全部。",
|
|
1092
|
+
parameters: {
|
|
1093
|
+
type: "object",
|
|
1094
|
+
properties: {
|
|
1095
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1096
|
+
username: { type: "string", description: "用户名关键词(支持模糊匹配)" },
|
|
1097
|
+
page: { type: "number", description: "页码(默认 1)" },
|
|
1098
|
+
page_size: { type: "number", description: "每页数量(默认 20)" },
|
|
1099
|
+
},
|
|
1100
|
+
required: ["account_id"],
|
|
1101
|
+
},
|
|
1102
|
+
async execute(_id: string, params: any) {
|
|
1103
|
+
try {
|
|
1104
|
+
const config = resolveRuntimeConfig(api);
|
|
1105
|
+
await verifyApiKey(config);
|
|
1106
|
+
const body: any = { account_id: params.account_id };
|
|
1107
|
+
if (params.username) body.username = params.username;
|
|
1108
|
+
if (params.page) body.page = params.page;
|
|
1109
|
+
if (params.page_size) body.page_size = params.page_size;
|
|
1110
|
+
const resp = await apiRequest(config, "POST", "/v1/api/dm/inbox/searchByUsername", { body });
|
|
1111
|
+
return formatResponse(resp.data);
|
|
1112
|
+
} catch (e: any) {
|
|
1113
|
+
return err(classifyError(e.message));
|
|
1114
|
+
}
|
|
1115
|
+
},
|
|
1116
|
+
});
|
|
1117
|
+
|
|
1118
|
+
api.registerTool({
|
|
1119
|
+
name: "x_dm_history",
|
|
1120
|
+
description: "获取 DM 发送历史。支持按日期范围、状态、活动 ID 筛选。",
|
|
1121
|
+
parameters: {
|
|
1122
|
+
type: "object",
|
|
1123
|
+
properties: {
|
|
1124
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1125
|
+
start_date: { type: "string", description: "开始日期(ISO 格式)" },
|
|
1126
|
+
end_date: { type: "string", description: "结束日期(ISO 格式)" },
|
|
1127
|
+
status: { type: "string", description: "状态筛选: pending / success / failed" },
|
|
1128
|
+
activity_id: { type: "number", description: "活动 ID 筛选" },
|
|
1129
|
+
page: { type: "number", description: "页码(默认 1)" },
|
|
1130
|
+
page_size: { type: "number", description: "每页数量(默认 20)" },
|
|
1131
|
+
},
|
|
1132
|
+
required: ["account_id"],
|
|
1133
|
+
},
|
|
1134
|
+
async execute(_id: string, params: any) {
|
|
1135
|
+
try {
|
|
1136
|
+
const config = resolveRuntimeConfig(api);
|
|
1137
|
+
await verifyApiKey(config);
|
|
1138
|
+
const query: Record<string, string> = { account_id: String(params.account_id) };
|
|
1139
|
+
if (params.start_date) query.start_date = params.start_date;
|
|
1140
|
+
if (params.end_date) query.end_date = params.end_date;
|
|
1141
|
+
if (params.status) query.status = params.status;
|
|
1142
|
+
if (params.activity_id) query.activity_id = String(params.activity_id);
|
|
1143
|
+
if (params.page) query.page = String(params.page);
|
|
1144
|
+
if (params.page_size) query.page_size = String(params.page_size);
|
|
1145
|
+
const resp = await apiRequest(config, "GET", "/v1/api/dm/history", { query });
|
|
1146
|
+
return formatResponse(resp.data);
|
|
1147
|
+
} catch (e: any) {
|
|
1148
|
+
return err(classifyError(e.message));
|
|
1149
|
+
}
|
|
1150
|
+
},
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
api.registerTool({
|
|
1154
|
+
name: "x_dm_conversations_by_sessions",
|
|
1155
|
+
description: "按会话 ID 批量查询 DM 会话列表,用于收件箱列表展示。",
|
|
1156
|
+
parameters: {
|
|
1157
|
+
type: "object",
|
|
1158
|
+
properties: {
|
|
1159
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1160
|
+
session_ids: { type: "array", items: { type: "string" }, description: "会话 ID 列表" },
|
|
1161
|
+
activity_id: { type: "number", description: "活动 ID 筛选" },
|
|
1162
|
+
keyword: { type: "string", description: "关键词筛选(目标用户名或内容)" },
|
|
1163
|
+
},
|
|
1164
|
+
required: ["account_id", "session_ids"],
|
|
1165
|
+
},
|
|
1166
|
+
async execute(_id: string, params: any) {
|
|
1167
|
+
try {
|
|
1168
|
+
const config = resolveRuntimeConfig(api);
|
|
1169
|
+
await verifyApiKey(config);
|
|
1170
|
+
const body: any = { account_id: params.account_id, session_ids: params.session_ids };
|
|
1171
|
+
if (params.activity_id) body.activity_id = params.activity_id;
|
|
1172
|
+
if (params.keyword) body.keyword = params.keyword;
|
|
1173
|
+
const resp = await apiRequest(config, "POST", "/v1/api/dm/conversations/bySessionIds", { body });
|
|
1174
|
+
return formatResponse(resp.data);
|
|
1175
|
+
} catch (e: any) {
|
|
1176
|
+
return err(classifyError(e.message));
|
|
1177
|
+
}
|
|
1178
|
+
},
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
api.registerTool({
|
|
1182
|
+
name: "x_dm_conversation",
|
|
1183
|
+
description: "获取 DM 会话实时数据(调用外部 Twitter API)。根据目标用户 Twitter ID 获取最新对话。",
|
|
1184
|
+
parameters: {
|
|
1185
|
+
type: "object",
|
|
1186
|
+
properties: {
|
|
1187
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1188
|
+
dm_twitter_id: { type: "string", description: "目标用户的 Twitter ID" },
|
|
1189
|
+
},
|
|
1190
|
+
required: ["account_id", "dm_twitter_id"],
|
|
1191
|
+
},
|
|
1192
|
+
async execute(_id: string, params: any) {
|
|
1193
|
+
try {
|
|
1194
|
+
const config = resolveRuntimeConfig(api);
|
|
1195
|
+
await verifyApiKey(config);
|
|
1196
|
+
const resp = await apiRequest(config, "POST", "/v1/api/dm/conversation", {
|
|
1197
|
+
body: { account_id: params.account_id, dm_twitter_id: params.dm_twitter_id },
|
|
1198
|
+
timeoutMs: SLOW_TIMEOUT_MS,
|
|
1199
|
+
});
|
|
1200
|
+
return formatResponse(resp.data);
|
|
1201
|
+
} catch (e: any) {
|
|
1202
|
+
return err(classifyError(e.message));
|
|
1203
|
+
}
|
|
1204
|
+
},
|
|
1205
|
+
});
|
|
1206
|
+
|
|
1207
|
+
api.registerTool({
|
|
1208
|
+
name: "x_dm_conversation_detail",
|
|
1209
|
+
description: "获取单个会话详情(本地数据库)。返回 is_first_send、首次发送内容和消息列表(sent/received)。",
|
|
1210
|
+
parameters: {
|
|
1211
|
+
type: "object",
|
|
1212
|
+
properties: {
|
|
1213
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1214
|
+
session_id: { type: "string", description: "会话 ID" },
|
|
1215
|
+
},
|
|
1216
|
+
required: ["account_id", "session_id"],
|
|
1217
|
+
},
|
|
1218
|
+
async execute(_id: string, params: any) {
|
|
1219
|
+
try {
|
|
1220
|
+
const config = resolveRuntimeConfig(api);
|
|
1221
|
+
await verifyApiKey(config);
|
|
1222
|
+
const resp = await apiRequest(config, "POST", "/v1/api/dm/conversation/bySession", {
|
|
1223
|
+
body: { account_id: params.account_id, session_id: params.session_id },
|
|
1224
|
+
});
|
|
1225
|
+
return formatResponse(resp.data);
|
|
1226
|
+
} catch (e: any) {
|
|
1227
|
+
return err(classifyError(e.message));
|
|
1228
|
+
}
|
|
1229
|
+
},
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
api.registerTool({
|
|
1233
|
+
name: "x_dm_activity_messages",
|
|
1234
|
+
description: "获取某营销活动下的消息列表(待发送/已发送),支持分页。",
|
|
1235
|
+
parameters: {
|
|
1236
|
+
type: "object",
|
|
1237
|
+
properties: {
|
|
1238
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1239
|
+
task_id: { type: "number", description: "活动 ID" },
|
|
1240
|
+
page: { type: "number", description: "页码(默认 1)" },
|
|
1241
|
+
page_size: { type: "number", description: "每页数量(默认 100)" },
|
|
1242
|
+
},
|
|
1243
|
+
required: ["account_id", "task_id"],
|
|
1244
|
+
},
|
|
1245
|
+
async execute(_id: string, params: any) {
|
|
1246
|
+
try {
|
|
1247
|
+
const config = resolveRuntimeConfig(api);
|
|
1248
|
+
await verifyApiKey(config);
|
|
1249
|
+
const query: Record<string, string> = {
|
|
1250
|
+
account_id: String(params.account_id),
|
|
1251
|
+
task_id: String(params.task_id),
|
|
1252
|
+
};
|
|
1253
|
+
if (params.page) query.page = String(params.page);
|
|
1254
|
+
if (params.page_size) query.page_size = String(params.page_size);
|
|
1255
|
+
const resp = await apiRequest(config, "GET", "/v1/api/dm/activity/messages", { query });
|
|
1256
|
+
return formatResponse(resp.data);
|
|
1257
|
+
} catch (e: any) {
|
|
1258
|
+
return err(classifyError(e.message));
|
|
1259
|
+
}
|
|
1260
|
+
},
|
|
1261
|
+
});
|
|
1262
|
+
|
|
1263
|
+
api.registerTool({
|
|
1264
|
+
name: "x_dm_send_message",
|
|
1265
|
+
description: "发送单条 DM 消息。⚠️ 此操作会真实发送 Twitter 私信且不可撤回。不传 content 则使用已生成的内容。",
|
|
1266
|
+
parameters: {
|
|
1267
|
+
type: "object",
|
|
1268
|
+
properties: {
|
|
1269
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1270
|
+
history_id: { type: "number", description: "发送历史 ID" },
|
|
1271
|
+
content: { type: "string", description: "消息内容(不传则使用已生成内容)" },
|
|
1272
|
+
},
|
|
1273
|
+
required: ["account_id", "history_id"],
|
|
1274
|
+
},
|
|
1275
|
+
async execute(_id: string, params: any) {
|
|
1276
|
+
try {
|
|
1277
|
+
const config = resolveRuntimeConfig(api);
|
|
1278
|
+
await verifyApiKey(config);
|
|
1279
|
+
const body: any = { account_id: params.account_id, history_id: params.history_id };
|
|
1280
|
+
if (params.content) body.content = params.content;
|
|
1281
|
+
const resp = await apiRequest(config, "POST", "/v1/api/dm/message/send", {
|
|
1282
|
+
body,
|
|
1283
|
+
timeoutMs: SLOW_TIMEOUT_MS,
|
|
1284
|
+
});
|
|
1285
|
+
if (resp.data?.code === 200) {
|
|
1286
|
+
const d = resp.data.data;
|
|
1287
|
+
return ok(
|
|
1288
|
+
`✅ 消息发送成功\n` +
|
|
1289
|
+
`history_id: ${d?.history_id}\n` +
|
|
1290
|
+
`发送时间: ${d?.send_time ?? "N/A"}`,
|
|
1291
|
+
);
|
|
1292
|
+
}
|
|
1293
|
+
if (resp.data?.code === 4009) {
|
|
1294
|
+
return err("今日 DM 发送已达上限,请明天再试。");
|
|
1295
|
+
}
|
|
1296
|
+
return formatResponse(resp.data);
|
|
1297
|
+
} catch (e: any) {
|
|
1298
|
+
return err(classifyError(e.message));
|
|
1299
|
+
}
|
|
1300
|
+
},
|
|
1301
|
+
});
|
|
1302
|
+
|
|
1303
|
+
api.registerTool({
|
|
1304
|
+
name: "x_dm_refresh_replies",
|
|
1305
|
+
description: "刷新会话回复。从外部 Twitter API 拉取最新回复并保存到数据库。",
|
|
1306
|
+
parameters: {
|
|
1307
|
+
type: "object",
|
|
1308
|
+
properties: {
|
|
1309
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1310
|
+
session_id: { type: "string", description: "会话 ID" },
|
|
1311
|
+
},
|
|
1312
|
+
required: ["account_id", "session_id"],
|
|
1313
|
+
},
|
|
1314
|
+
async execute(_id: string, params: any) {
|
|
1315
|
+
try {
|
|
1316
|
+
const config = resolveRuntimeConfig(api);
|
|
1317
|
+
await verifyApiKey(config);
|
|
1318
|
+
const resp = await apiRequest(config, "POST", "/v1/api/dm/conversation/refreshReplies", {
|
|
1319
|
+
body: { account_id: params.account_id, session_id: params.session_id },
|
|
1320
|
+
timeoutMs: SLOW_TIMEOUT_MS,
|
|
1321
|
+
});
|
|
1322
|
+
if (resp.data?.code === 200) {
|
|
1323
|
+
const d = resp.data.data;
|
|
1324
|
+
return ok(
|
|
1325
|
+
`✅ 回复刷新完成\n` +
|
|
1326
|
+
`send_history_id: ${d?.send_history_id}\n` +
|
|
1327
|
+
`新回复数: ${d?.new_replies_count ?? 0}\n` +
|
|
1328
|
+
`总消息数: ${d?.total_messages ?? 0}`,
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
return formatResponse(resp.data);
|
|
1332
|
+
} catch (e: any) {
|
|
1333
|
+
return err(classifyError(e.message));
|
|
1334
|
+
}
|
|
1335
|
+
},
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
api.registerTool({
|
|
1339
|
+
name: "x_dm_reply_stats",
|
|
1340
|
+
description: "获取会话回复统计(回复数量和最后回复时间),可用于轮询判断是否有新回复。",
|
|
1341
|
+
parameters: {
|
|
1342
|
+
type: "object",
|
|
1343
|
+
properties: {
|
|
1344
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1345
|
+
session_id: { type: "string", description: "会话 ID" },
|
|
1346
|
+
},
|
|
1347
|
+
required: ["account_id", "session_id"],
|
|
1348
|
+
},
|
|
1349
|
+
async execute(_id: string, params: any) {
|
|
1350
|
+
try {
|
|
1351
|
+
const config = resolveRuntimeConfig(api);
|
|
1352
|
+
await verifyApiKey(config);
|
|
1353
|
+
const resp = await apiRequest(config, "GET", "/v1/api/dm/conversation/reply-stats", {
|
|
1354
|
+
query: { account_id: String(params.account_id), session_id: params.session_id },
|
|
1355
|
+
});
|
|
1356
|
+
return formatResponse(resp.data);
|
|
1357
|
+
} catch (e: any) {
|
|
1358
|
+
return err(classifyError(e.message));
|
|
1359
|
+
}
|
|
1360
|
+
},
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
api.registerTool({
|
|
1364
|
+
name: "x_dm_reply_save",
|
|
1365
|
+
description: "保存手动回复记录。将用户手动输入的回复保存到数据库(用于推荐回复模式下的手动发送记录)。",
|
|
1366
|
+
parameters: {
|
|
1367
|
+
type: "object",
|
|
1368
|
+
properties: {
|
|
1369
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1370
|
+
send_history_id: { type: "number", description: "发送历史 ID" },
|
|
1371
|
+
reply_content: { type: "string", description: "回复内容" },
|
|
1372
|
+
reply_time: { type: "string", description: "回复时间(ISO 格式,可选)" },
|
|
1373
|
+
target_user_name: { type: "string", description: "目标用户名(可选)" },
|
|
1374
|
+
},
|
|
1375
|
+
required: ["account_id", "send_history_id", "reply_content"],
|
|
1376
|
+
},
|
|
1377
|
+
async execute(_id: string, params: any) {
|
|
1378
|
+
try {
|
|
1379
|
+
const config = resolveRuntimeConfig(api);
|
|
1380
|
+
await verifyApiKey(config);
|
|
1381
|
+
const body: any = {
|
|
1382
|
+
account_id: params.account_id,
|
|
1383
|
+
send_history_id: params.send_history_id,
|
|
1384
|
+
reply_content: params.reply_content,
|
|
1385
|
+
};
|
|
1386
|
+
if (params.reply_time) body.reply_time = params.reply_time;
|
|
1387
|
+
if (params.target_user_name) body.target_user_name = params.target_user_name;
|
|
1388
|
+
const resp = await apiRequest(config, "POST", "/v1/api/dm/reply/save", { body });
|
|
1389
|
+
if (resp.data?.code === 200) {
|
|
1390
|
+
return ok(`✅ 回复已保存 (reply_id: ${resp.data.data?.reply_id})`);
|
|
1391
|
+
}
|
|
1392
|
+
return formatResponse(resp.data);
|
|
1393
|
+
} catch (e: any) {
|
|
1394
|
+
return err(classifyError(e.message));
|
|
1395
|
+
}
|
|
1396
|
+
},
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
api.registerTool({
|
|
1400
|
+
name: "x_dm_replies",
|
|
1401
|
+
description: "获取回复历史列表。支持按发送历史 ID、日期范围筛选,并支持分页。",
|
|
1402
|
+
parameters: {
|
|
1403
|
+
type: "object",
|
|
1404
|
+
properties: {
|
|
1405
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1406
|
+
send_history_id: { type: "number", description: "发送历史 ID(可选,不传返回所有)" },
|
|
1407
|
+
start_date: { type: "string", description: "开始日期(ISO 格式)" },
|
|
1408
|
+
end_date: { type: "string", description: "结束日期(ISO 格式)" },
|
|
1409
|
+
page: { type: "number", description: "页码" },
|
|
1410
|
+
page_size: { type: "number", description: "每页数量" },
|
|
1411
|
+
},
|
|
1412
|
+
required: ["account_id"],
|
|
1413
|
+
},
|
|
1414
|
+
async execute(_id: string, params: any) {
|
|
1415
|
+
try {
|
|
1416
|
+
const config = resolveRuntimeConfig(api);
|
|
1417
|
+
await verifyApiKey(config);
|
|
1418
|
+
const query: Record<string, string> = { account_id: String(params.account_id) };
|
|
1419
|
+
if (params.send_history_id) query.send_history_id = String(params.send_history_id);
|
|
1420
|
+
if (params.start_date) query.start_date = params.start_date;
|
|
1421
|
+
if (params.end_date) query.end_date = params.end_date;
|
|
1422
|
+
if (params.page) query.page = String(params.page);
|
|
1423
|
+
if (params.page_size) query.page_size = String(params.page_size);
|
|
1424
|
+
const resp = await apiRequest(config, "GET", "/v1/api/dm/replies", { query });
|
|
1425
|
+
return formatResponse(resp.data);
|
|
1426
|
+
} catch (e: any) {
|
|
1427
|
+
return err(classifyError(e.message));
|
|
1428
|
+
}
|
|
1429
|
+
},
|
|
1430
|
+
});
|
|
1431
|
+
|
|
1432
|
+
api.registerTool({
|
|
1433
|
+
name: "x_dm_history_soft_delete",
|
|
1434
|
+
description: "软删除发送历史记录。记录不会真正删除,但在列表中不再显示。",
|
|
1435
|
+
parameters: {
|
|
1436
|
+
type: "object",
|
|
1437
|
+
properties: {
|
|
1438
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1439
|
+
send_history_id: { type: "number", description: "发送历史 ID" },
|
|
1440
|
+
},
|
|
1441
|
+
required: ["account_id", "send_history_id"],
|
|
1442
|
+
},
|
|
1443
|
+
async execute(_id: string, params: any) {
|
|
1444
|
+
try {
|
|
1445
|
+
const config = resolveRuntimeConfig(api);
|
|
1446
|
+
await verifyApiKey(config);
|
|
1447
|
+
const resp = await apiRequest(config, "POST", "/v1/api/dm/history/soft-delete", {
|
|
1448
|
+
body: { account_id: params.account_id, send_history_id: params.send_history_id },
|
|
1449
|
+
});
|
|
1450
|
+
if (resp.data?.code === 200) {
|
|
1451
|
+
return ok(`✅ 发送历史 ${params.send_history_id} 已软删除`);
|
|
1452
|
+
}
|
|
1453
|
+
if (resp.data?.code === 4007) {
|
|
1454
|
+
return err("发送历史不存在,请检查 send_history_id 是否正确。");
|
|
1455
|
+
}
|
|
1456
|
+
return formatResponse(resp.data);
|
|
1457
|
+
} catch (e: any) {
|
|
1458
|
+
return err(classifyError(e.message));
|
|
1459
|
+
}
|
|
1460
|
+
},
|
|
1461
|
+
});
|
|
1462
|
+
|
|
1463
|
+
api.registerTool({
|
|
1464
|
+
name: "x_dm_history_remark",
|
|
1465
|
+
description: "更新发送历史的备注信息。",
|
|
1466
|
+
parameters: {
|
|
1467
|
+
type: "object",
|
|
1468
|
+
properties: {
|
|
1469
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1470
|
+
send_history_id: { type: "number", description: "发送历史 ID" },
|
|
1471
|
+
remark: { type: "string", description: "备注内容(传空字符串可清除备注)" },
|
|
1472
|
+
},
|
|
1473
|
+
required: ["account_id", "send_history_id"],
|
|
1474
|
+
},
|
|
1475
|
+
async execute(_id: string, params: any) {
|
|
1476
|
+
try {
|
|
1477
|
+
const config = resolveRuntimeConfig(api);
|
|
1478
|
+
await verifyApiKey(config);
|
|
1479
|
+
const body: any = { account_id: params.account_id, send_history_id: params.send_history_id };
|
|
1480
|
+
if (params.remark !== undefined) body.remark = params.remark;
|
|
1481
|
+
const resp = await apiRequest(config, "POST", "/v1/api/dm/history/remark", { body });
|
|
1482
|
+
if (resp.data?.code === 200) {
|
|
1483
|
+
return ok(`✅ 备注已更新`);
|
|
1484
|
+
}
|
|
1485
|
+
return formatResponse(resp.data);
|
|
1486
|
+
} catch (e: any) {
|
|
1487
|
+
return err(classifyError(e.message));
|
|
1488
|
+
}
|
|
1489
|
+
},
|
|
1490
|
+
});
|
|
1491
|
+
|
|
1492
|
+
api.registerTool({
|
|
1493
|
+
name: "x_dm_daily_send_stats",
|
|
1494
|
+
description: "获取今日 DM 发送统计,包含已发送数量、每日上限和剩余可发送数量。",
|
|
1495
|
+
parameters: {
|
|
1496
|
+
type: "object",
|
|
1497
|
+
properties: {
|
|
1498
|
+
account_id: { type: "number", description: "账号 ID" },
|
|
1499
|
+
},
|
|
1500
|
+
required: ["account_id"],
|
|
1501
|
+
},
|
|
1502
|
+
async execute(_id: string, params: any) {
|
|
1503
|
+
try {
|
|
1504
|
+
const config = resolveRuntimeConfig(api);
|
|
1505
|
+
await verifyApiKey(config);
|
|
1506
|
+
const resp = await apiRequest(config, "GET", "/v1/api/dm/daily-send-stats", {
|
|
1507
|
+
query: { account_id: String(params.account_id) },
|
|
1508
|
+
});
|
|
1509
|
+
if (resp.data?.code === 200) {
|
|
1510
|
+
const d = resp.data.data;
|
|
1511
|
+
return ok(
|
|
1512
|
+
`📊 今日 DM 发送统计\n` +
|
|
1513
|
+
`已发送: ${d?.today_sent ?? 0}\n` +
|
|
1514
|
+
`每日上限: ${d?.limit ?? 150}\n` +
|
|
1515
|
+
`剩余: ${d?.remaining ?? 0}`,
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1518
|
+
return formatResponse(resp.data);
|
|
1519
|
+
} catch (e: any) {
|
|
1520
|
+
return err(classifyError(e.message));
|
|
1521
|
+
}
|
|
1522
|
+
},
|
|
1523
|
+
});
|
|
877
1524
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fwgi/fwgi-x-tool",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "X(Twitter) 营销管理助手 OpenClaw 插件 —
|
|
5
|
+
"description": "X(Twitter) 营销管理助手 OpenClaw 插件 — 账号信息、受众管理、活动管理、收件箱/私信",
|
|
6
6
|
"main": "index.ts",
|
|
7
7
|
"openclaw": {
|
|
8
8
|
"extensions": ["./index.ts"]
|