socialdatax-skills 0.2.11 → 0.2.13

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  This public package provides the unified skill installer and direct CLI helper for SocialDataX services.
4
4
 
5
- The current public tools support 小红书 / Xiaohongshu / XHS / RedNote, 抖音 / Douyin, 快手 / Kuaishou / Kwai, 微博 / Weibo, and 视频号 / WeChat Channels content research and analysis workflows. The public skill layer is intentionally named by media capability so supported platforms can evolve without changing the installation model.
5
+ The current public tools support 小红书 / Xiaohongshu / XHS / RedNote, 抖音 / Douyin, 快手 / Kuaishou / Kwai, 微博 / Weibo, and 视频号 / WeChat Channels content research and analysis workflows, plus SocialDataX 敏感检测 text checks. The public skill layer is intentionally named by capability so supported services can evolve without changing the installation model.
6
6
 
7
7
  - direct `npx` JSON commands for agents that can run shell commands
8
8
  - AgentSkills-compatible installers split by capability for OpenClaw, Hermes Agent, Codex, Claude Code, and general agent skill directories
@@ -39,14 +39,19 @@ Common search phrases for this skill package:
39
39
  - `视频号 skills`
40
40
  - `SocialDataX content research`
41
41
  - `content research assistant`
42
+ - `敏感检测 SocialDataX`
43
+ - `sensitive check skill`
44
+ - `content safety skill`
45
+ - `text safety check`
42
46
 
43
47
  ## Platform MCPs
44
48
 
45
- - XHS hosted MCP endpoint: `https://mcp.52choujiang.com/xhs/mcp`
46
- - Douyin hosted MCP endpoint: `https://mcp.52choujiang.com/douyin/mcp`
47
- - Kuaishou hosted MCP endpoint: `https://mcp.52choujiang.com/kuaishou/mcp`
48
- - Weibo hosted MCP endpoint: `https://mcp.52choujiang.com/weibo/mcp`
49
- - WeChat Channels hosted MCP endpoint: `https://mcp.52choujiang.com/wechat/mcp`
49
+ - XHS hosted MCP endpoint: `https://mcp.socialdatax.com/xhs/mcp`
50
+ - Douyin hosted MCP endpoint: `https://mcp.socialdatax.com/douyin/mcp`
51
+ - Kuaishou hosted MCP endpoint: `https://mcp.socialdatax.com/kuaishou/mcp`
52
+ - Weibo hosted MCP endpoint: `https://mcp.socialdatax.com/weibo/mcp`
53
+ - WeChat Channels hosted MCP endpoint: `https://mcp.socialdatax.com/wechat/mcp`
54
+ - Sensitive Check hosted MCP endpoint: `https://mcp.socialdatax.com/sensitive-check/mcp`
50
55
  - Hosted transport: `streamable-http`
51
56
  - Authentication: `Authorization: Bearer <SOCIALDATAX_API_KEY>`
52
57
  - Website: <https://socialdatax.com>
@@ -60,8 +65,10 @@ Common search phrases for this skill package:
60
65
  - Weibo future platform MCP registry name: `com.socialdatax/weibo-insights`
61
66
  - WeChat Channels current platform MCP registry name: `com.52choujiang/wechat-channels-insights`
62
67
  - WeChat Channels future platform MCP registry name: `com.socialdatax/wechat-channels-insights`
68
+ - Sensitive Check MCP server name: `sensitive-check`
69
+ - Sensitive Check future MCP registry name: `com.socialdatax/sensitive-check`
63
70
  - Unified MCP registry name: none; this package installs skills and calls explicit platform services.
64
- - Current public capability version: `0.2.11`
71
+ - Current public capability version: `0.2.13`
65
72
 
66
73
  ## Direct CLI
67
74
 
@@ -71,6 +78,7 @@ Examples:
71
78
 
72
79
  ```bash
73
80
  npx -y socialdatax-skills@latest xhs search --keyword "露营" --pretty
81
+ npx -y socialdatax-skills@latest xhs search --keyword "露营" --since-days 7 --pages 2 --pretty
74
82
  npx -y socialdatax-skills@latest xhs hot-search --pretty
75
83
  npx -y socialdatax-skills@latest xhs detail --note-id "<note_id>" --pretty
76
84
  npx -y socialdatax-skills@latest xhs comments --note-id "<note_id>" --pretty
@@ -78,6 +86,7 @@ npx -y socialdatax-skills@latest xhs comments --note-id "<note_id>" --all --incl
78
86
  npx -y socialdatax-skills@latest xhs sub-comments --note-id "<note_id>" --comment-id "<comment_id>" --pretty
79
87
  npx -y socialdatax-skills@latest xhs user-info --user-id "<user_id>" --pretty
80
88
  npx -y socialdatax-skills@latest xhs user-posts --user-id "<user_id>" --pretty
89
+ npx -y socialdatax-skills@latest xhs user-posts --user-id "<user_id>" --since-days 30 --pretty
81
90
  npx -y socialdatax-skills@latest douyin hot-search --pretty
82
91
  npx -y socialdatax-skills@latest douyin search --keyword "露营" --pretty
83
92
  npx -y socialdatax-skills@latest douyin detail --aweme-id "<aweme_id>" --pretty
@@ -127,14 +136,17 @@ npx -y socialdatax-skills@latest wechat replies --object-id "<object_id>" --obje
127
136
  npx -y socialdatax-skills@latest wechat user-info --user-id "<finder_user_id>" --pretty
128
137
  npx -y socialdatax-skills@latest wechat user-posts --user-id "<finder_user_id>" --pretty
129
138
  npx -y socialdatax-skills@latest wechat user-posts --url "<wechat_video_url_or_share_text>" --pretty
139
+ npx -y socialdatax-skills@latest sensitive-check text --text "<content>" --platform xhs --pretty
130
140
  ```
131
141
 
132
- The direct CLI prints a JSON envelope with `platform`, `tool`, `arguments`, and `data`.
142
+ Most direct CLI commands print a JSON envelope with `platform`, `tool`, `arguments`, and `data`. `sensitive-check` prints `platform`, `tool`, and `data` only; it does not echo the original text in CLI output.
133
143
 
134
144
  For XHS outputs with a returned `note_url` field, when `note_url` is non-null, preserve it exactly as the full URL, including `xsec_token` query parameters, such as in final answers or display. Do not modify, truncate, redact, normalize, rebuild, or replace it with a link assembled from `note_id`. If `note_url` is null, do not synthesize a public link from `note_id`.
135
145
 
136
146
  For list-style commands, use `--pages <n>` to fetch N pages from the current starting point and `--max-items <n>` to cap the merged `data.items` output. Search commands support `--pages` but not `--all`, because search has no stable complete-result boundary.
137
147
 
148
+ For search and creator content-list commands, use `--since-days <1-365>` to keep only items whose public `publish_time` is within the last N days. Search remains bounded by `--pages` and does not promise complete platform coverage; creator content lists continue until the publish-time boundary when `--pages` is omitted.
149
+
138
150
  For comments, replies, creator content lists, and Douyin creator series, use `--all` to continue until the returned `next_page_token` is empty. `--all` has no default item or page cap; add `--max-items <n>` or use `--pages <n>` when you want a bounded run.
139
151
 
140
152
  For first-level comments, add `--include-replies` to fetch the second-level replies under each returned first-level comment. Multi-page output keeps `data.items` as the merged first-level list; each item gets `replies`, `replies_page_count`, and `replies_next_page_token`.
@@ -192,6 +204,7 @@ SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" node cli.mjs douyin search --keyword
192
204
  SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" node cli.mjs kuaishou search --keyword "露营" --pretty
193
205
  SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" node cli.mjs weibo search --keyword "露营" --pretty
194
206
  SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" node cli.mjs wechat search --keyword "露营" --pretty
207
+ SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" node cli.mjs sensitive-check text --text "<content>" --platform xhs --pretty
195
208
  ```
196
209
 
197
210
  ### Docker Run
@@ -203,6 +216,7 @@ docker run --rm -i -e SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" socialdatax-sk
203
216
  docker run --rm -i -e SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" socialdatax-skills kuaishou search --keyword "露营" --pretty
204
217
  docker run --rm -i -e SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" socialdatax-skills weibo search --keyword "露营" --pretty
205
218
  docker run --rm -i -e SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" socialdatax-skills wechat search --keyword "露营" --pretty
219
+ docker run --rm -i -e SOCIALDATAX_API_KEY="<SOCIALDATAX_API_KEY>" socialdatax-skills sensitive-check text --text "<content>" --platform xhs --pretty
206
220
  ```
207
221
 
208
222
  If Docker Hub is slow from your network, keep the default image unchanged for normal use and override only during local builds:
@@ -245,6 +259,7 @@ npx -y socialdatax-skills@latest weibo hot-search --pretty
245
259
  npx -y socialdatax-skills@latest weibo search --keyword "露营" --pretty
246
260
  npx -y socialdatax-skills@latest wechat hot-search --pretty
247
261
  npx -y socialdatax-skills@latest wechat search --keyword "露营" --pretty
262
+ npx -y socialdatax-skills@latest sensitive-check text --text "<content>" --platform xhs --pretty
248
263
  ```
249
264
 
250
265
  Available skills:
@@ -256,6 +271,7 @@ Available skills:
256
271
  - `media-transcript`: submit and check video 口播转文字 / speech-to-text transcript jobs through hosted MCP tools; supports XHS, Douyin, Kuaishou, Weibo, and WeChat Channels.
257
272
  - `media-user-info`: retrieve creator profile information; supports XHS, Douyin, Kuaishou, Weibo, and WeChat Channels creators.
258
273
  - `media-user-posts`: retrieve creator content lists; supports XHS notes, Douyin works, Kuaishou works, Weibo posts, WeChat Channels videos, and Douyin creator short-drama series.
274
+ - `sensitive-check`: run 敏感检测 text checks; supports `generic`, `xhs`, `douyin`, and `kuaishou` platform contexts.
259
275
 
260
276
  Default install locations:
261
277
 
@@ -336,6 +352,13 @@ Current WeChat Channels / 视频号 workflows include:
336
352
  - Fetch paginated creator video lists from a finder user_id or a video link/share text.
337
353
  - Submit and check WeChat Channels / 视频号 video 口播转文字 / speech-to-text transcript jobs; submit tools 提交完成后最多短等 15 秒.
338
354
 
355
+ Current Sensitive Check workflows include:
356
+
357
+ - Check draft text for 敏感检测 / sensitive-content risks before publishing.
358
+ - Choose a platform context with `--platform generic`, `--platform xhs`, `--platform douyin`, or `--platform kuaishou`.
359
+ - Return structured fields such as `violation`, `risk_level`, `types`, `highlights`, `summary`, `platform`, and `suggestions` when available.
360
+ - Text checks are read-only. Image sensitive detection is reserved for a future separate tool.
361
+
339
362
  ## XHS Tools
340
363
 
341
364
  | Tool | Public purpose |
@@ -432,6 +455,12 @@ Current WeChat Channels / 视频号 workflows include:
432
455
  | `wechat_submit_video_speech_text_by_encrypted_object_id` | Submit a WeChat Channels / 视频号 video speech-to-text transcript job when encrypted_object_id is already known; submit waits up to 15 seconds. |
433
456
  | `wechat_get_video_speech_text_job` | Check a WeChat Channels / 视频号 speech-to-text transcript job by job_id without creating a new task. |
434
457
 
458
+ ## Sensitive Check Tools
459
+
460
+ | Tool | Public purpose |
461
+ | --- | --- |
462
+ | `check_sensitive_text` | Check text for 敏感检测 / sensitive-content risks with `generic`, `xhs`, `douyin`, or `kuaishou` context. |
463
+
435
464
  ## Quick Start
436
465
 
437
466
  For agents that can execute shell commands, use the direct CLI. This is the recommended default for installed skills:
@@ -443,9 +472,10 @@ npx -y socialdatax-skills@latest douyin search --keyword "露营" --pretty
443
472
  npx -y socialdatax-skills@latest kuaishou search --keyword "露营" --pretty
444
473
  npx -y socialdatax-skills@latest weibo search --keyword "露营" --pretty
445
474
  npx -y socialdatax-skills@latest wechat search --keyword "露营" --pretty
475
+ npx -y socialdatax-skills@latest sensitive-check text --text "<content>" --platform xhs --pretty
446
476
  ```
447
477
 
448
- MCP client configuration belongs to platform MCP listings. For XHS, use the `xhs-insights` docs; for Douyin, use the `douyin-insights` listing; for Kuaishou, use the `kuaishou-insights` listing; for Weibo, use the `weibo-insights` listing; for WeChat Channels / 视频号, use the `wechat-channels-insights` listing.
478
+ MCP client configuration belongs to platform or capability MCP listings. For XHS, use the `xhs-insights` docs; for Douyin, use the `douyin-insights` listing; for Kuaishou, use the `kuaishou-insights` listing; for Weibo, use the `weibo-insights` listing; for WeChat Channels / 视频号, use the `wechat-channels-insights` listing; for 敏感检测, use the `sensitive-check` server.
449
479
 
450
480
  Aily is treated as an OpenClaw / AgentSkills ecosystem channel for this package. Use the OpenClaw skill install flow for now; a dedicated `--target aily` will be added only after its official skill import or package format is confirmed.
451
481
 
@@ -461,7 +491,7 @@ Use the key as a Bearer token in the `Authorization` request header. Do not comm
461
491
 
462
492
  Public metadata files in this repository:
463
493
 
464
- - [skills](skills): AgentSkills-compatible skills split by social media capability and currently backed by XHS, Douyin, Kuaishou, Weibo, and WeChat Channels tools.
494
+ - [skills](skills): AgentSkills-compatible skills split by capability and currently backed by XHS, Douyin, Kuaishou, Weibo, WeChat Channels, and Sensitive Check tools.
465
495
 
466
496
  ## License
467
497
 
package/cli.mjs CHANGED
@@ -7,7 +7,7 @@ import { dirname, join, resolve } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
 
9
9
  const PACKAGE_NAME = "socialdatax-skills";
10
- const PACKAGE_VERSION = "0.2.11";
10
+ const PACKAGE_VERSION = "0.2.13";
11
11
  const PACKAGE_SPEC = `${PACKAGE_NAME}@latest`;
12
12
  const LOG_PREFIX = `[${PACKAGE_NAME}]`;
13
13
  const MIN_NODE_VERSION = "20.18.1";
@@ -58,6 +58,12 @@ const AVAILABLE_SKILLS = [
58
58
  "Retrieve creator content lists for XHS, Douyin, Kuaishou, Weibo, and WeChat Channels, including Douyin creator short-drama series.",
59
59
  emoji: "🗂️",
60
60
  },
61
+ {
62
+ name: "sensitive-check",
63
+ summary:
64
+ "Check text content for generic, XHS, Douyin, and Kuaishou sensitive-content risks.",
65
+ emoji: "🛡️",
66
+ },
61
67
  ];
62
68
  const AVAILABLE_SKILL_NAMES = AVAILABLE_SKILLS.map((skill) => skill.name);
63
69
  const BOOLEAN_OPTIONS = new Set([
@@ -79,6 +85,7 @@ const XHS_DIRECT_ACTION_OPTIONS = {
79
85
  "pages",
80
86
  "all",
81
87
  "maxItems",
88
+ "sinceDays",
82
89
  "sortType",
83
90
  "noteType",
84
91
  "publishTimeRange",
@@ -106,7 +113,16 @@ const XHS_DIRECT_ACTION_OPTIONS = {
106
113
  "pretty",
107
114
  ],
108
115
  "user-info": ["userId", "profileUrl", "pretty"],
109
- "user-posts": ["userId", "profileUrl", "pageToken", "pages", "all", "maxItems", "pretty"],
116
+ "user-posts": [
117
+ "userId",
118
+ "profileUrl",
119
+ "pageToken",
120
+ "pages",
121
+ "all",
122
+ "maxItems",
123
+ "sinceDays",
124
+ "pretty",
125
+ ],
110
126
  };
111
127
  const XHS_DIRECT_ACTION_NAMES = Object.keys(XHS_DIRECT_ACTION_OPTIONS).join(", ");
112
128
  const XHS_OPTION_DISPLAY_NAMES = {
@@ -120,6 +136,7 @@ const XHS_OPTION_DISPLAY_NAMES = {
120
136
  pageToken: "--page-token",
121
137
  pages: "--pages",
122
138
  maxItems: "--max-items",
139
+ sinceDays: "--since-days",
123
140
  all: "--all",
124
141
  includeReplies: "--include-replies",
125
142
  profileUrl: "--profile-url",
@@ -145,6 +162,7 @@ const DOUYIN_DIRECT_ACTION_OPTIONS = {
145
162
  "pages",
146
163
  "all",
147
164
  "maxItems",
165
+ "sinceDays",
148
166
  "sortType",
149
167
  "publishTimeRange",
150
168
  "durationRange",
@@ -173,7 +191,16 @@ const DOUYIN_DIRECT_ACTION_OPTIONS = {
173
191
  "pretty",
174
192
  ],
175
193
  "user-info": ["secUserId", "profileUrl", "pretty"],
176
- "user-posts": ["secUserId", "profileUrl", "pageToken", "pages", "all", "maxItems", "pretty"],
194
+ "user-posts": [
195
+ "secUserId",
196
+ "profileUrl",
197
+ "pageToken",
198
+ "pages",
199
+ "all",
200
+ "maxItems",
201
+ "sinceDays",
202
+ "pretty",
203
+ ],
177
204
  "user-series": ["secUserId", "profileUrl", "pageToken", "pages", "all", "maxItems", "pretty"],
178
205
  };
179
206
  const DOUYIN_DIRECT_ACTION_NAMES = Object.keys(DOUYIN_DIRECT_ACTION_OPTIONS).join(", ");
@@ -191,6 +218,7 @@ const DOUYIN_OPTION_DISPLAY_NAMES = {
191
218
  pageToken: "--page-token",
192
219
  pages: "--pages",
193
220
  maxItems: "--max-items",
221
+ sinceDays: "--since-days",
194
222
  all: "--all",
195
223
  includeReplies: "--include-replies",
196
224
  sortType: "--sort-type",
@@ -205,7 +233,7 @@ const DOUYIN_OPTION_DISPLAY_NAMES = {
205
233
  };
206
234
  const KUAISHOU_DIRECT_ACTION_OPTIONS = {
207
235
  "hot-search": ["pretty"],
208
- search: ["keyword", "pageToken", "pages", "all", "maxItems", "pretty"],
236
+ search: ["keyword", "pageToken", "pages", "all", "maxItems", "sinceDays", "pretty"],
209
237
  detail: ["photoId", "url", "pretty"],
210
238
  comments: [
211
239
  "photoId",
@@ -228,7 +256,16 @@ const KUAISHOU_DIRECT_ACTION_OPTIONS = {
228
256
  "pretty",
229
257
  ],
230
258
  "user-info": ["userId", "profileUrl", "pretty"],
231
- "user-posts": ["userId", "profileUrl", "pageToken", "pages", "all", "maxItems", "pretty"],
259
+ "user-posts": [
260
+ "userId",
261
+ "profileUrl",
262
+ "pageToken",
263
+ "pages",
264
+ "all",
265
+ "maxItems",
266
+ "sinceDays",
267
+ "pretty",
268
+ ],
232
269
  };
233
270
  const KUAISHOU_DIRECT_ACTION_NAMES = Object.keys(KUAISHOU_DIRECT_ACTION_OPTIONS).join(", ");
234
271
  const KUAISHOU_OPTION_DISPLAY_NAMES = {
@@ -236,6 +273,7 @@ const KUAISHOU_OPTION_DISPLAY_NAMES = {
236
273
  pageToken: "--page-token",
237
274
  pages: "--pages",
238
275
  maxItems: "--max-items",
276
+ sinceDays: "--since-days",
239
277
  all: "--all",
240
278
  includeReplies: "--include-replies",
241
279
  url: "--url",
@@ -246,7 +284,7 @@ const KUAISHOU_OPTION_DISPLAY_NAMES = {
246
284
  };
247
285
  const WEIBO_DIRECT_ACTION_OPTIONS = {
248
286
  "hot-search": ["pretty"],
249
- search: ["keyword", "pageToken", "pages", "all", "maxItems", "pretty"],
287
+ search: ["keyword", "pageToken", "pages", "all", "maxItems", "sinceDays", "pretty"],
250
288
  detail: ["postId", "postUrl", "pretty"],
251
289
  comments: [
252
290
  "postId",
@@ -271,7 +309,16 @@ const WEIBO_DIRECT_ACTION_OPTIONS = {
271
309
  likers: ["postId", "pageToken", "pages", "all", "maxItems", "pretty"],
272
310
  reposts: ["postId", "pageToken", "pages", "all", "maxItems", "pretty"],
273
311
  "user-info": ["userId", "profileUrl", "pretty"],
274
- "user-posts": ["userId", "profileUrl", "pageToken", "pages", "all", "maxItems", "pretty"],
312
+ "user-posts": [
313
+ "userId",
314
+ "profileUrl",
315
+ "pageToken",
316
+ "pages",
317
+ "all",
318
+ "maxItems",
319
+ "sinceDays",
320
+ "pretty",
321
+ ],
275
322
  };
276
323
  const WEIBO_DIRECT_ACTION_NAMES = Object.keys(WEIBO_DIRECT_ACTION_OPTIONS).join(", ");
277
324
  const WEIBO_OPTION_DISPLAY_NAMES = {
@@ -279,6 +326,7 @@ const WEIBO_OPTION_DISPLAY_NAMES = {
279
326
  pageToken: "--page-token",
280
327
  pages: "--pages",
281
328
  maxItems: "--max-items",
329
+ sinceDays: "--since-days",
282
330
  all: "--all",
283
331
  includeReplies: "--include-replies",
284
332
  postId: "--post-id",
@@ -295,6 +343,7 @@ const WECHAT_DIRECT_ACTION_OPTIONS = {
295
343
  "pages",
296
344
  "all",
297
345
  "maxItems",
346
+ "sinceDays",
298
347
  "sortType",
299
348
  "durationRange",
300
349
  "pretty",
@@ -323,7 +372,16 @@ const WECHAT_DIRECT_ACTION_OPTIONS = {
323
372
  "pretty",
324
373
  ],
325
374
  "user-info": ["userId", "pretty"],
326
- "user-posts": ["userId", "url", "pageToken", "pages", "all", "maxItems", "pretty"],
375
+ "user-posts": [
376
+ "userId",
377
+ "url",
378
+ "pageToken",
379
+ "pages",
380
+ "all",
381
+ "maxItems",
382
+ "sinceDays",
383
+ "pretty",
384
+ ],
327
385
  };
328
386
  const WECHAT_DIRECT_ACTION_NAMES = Object.keys(WECHAT_DIRECT_ACTION_OPTIONS).join(", ");
329
387
  const WECHAT_SEARCH_SORT_TYPES = ["all", "latest", "popular"];
@@ -338,6 +396,7 @@ const WECHAT_OPTION_DISPLAY_NAMES = {
338
396
  pageToken: "--page-token",
339
397
  pages: "--pages",
340
398
  maxItems: "--max-items",
399
+ sinceDays: "--since-days",
341
400
  all: "--all",
342
401
  includeReplies: "--include-replies",
343
402
  sortType: "--sort-type",
@@ -349,6 +408,17 @@ const WECHAT_OPTION_DISPLAY_NAMES = {
349
408
  commentId: "--comment-id",
350
409
  userId: "--user-id",
351
410
  };
411
+ const SENSITIVE_CHECK_DIRECT_ACTION_OPTIONS = {
412
+ text: ["text", "platform", "pretty"],
413
+ };
414
+ const SENSITIVE_CHECK_DIRECT_ACTION_NAMES = Object.keys(
415
+ SENSITIVE_CHECK_DIRECT_ACTION_OPTIONS
416
+ ).join(", ");
417
+ const SENSITIVE_CHECK_PLATFORMS = ["generic", "xhs", "douyin", "kuaishou"];
418
+ const SENSITIVE_CHECK_OPTION_DISPLAY_NAMES = {
419
+ text: "--text",
420
+ platform: "--platform",
421
+ };
352
422
  const PLATFORMS = {
353
423
  xhs: {
354
424
  id: "xhs",
@@ -356,7 +426,7 @@ const PLATFORMS = {
356
426
  status: "public",
357
427
  registryName: "com.52choujiang/xhs-insights",
358
428
  futureRegistryName: "com.socialdatax/xhs-insights",
359
- endpoint: "https://mcp.52choujiang.com/xhs/mcp",
429
+ endpoint: "https://mcp.socialdatax.com/xhs/mcp",
360
430
  apiKeyEnv: API_KEY_ENV_NAMES,
361
431
  upstreamEnv: [
362
432
  "SOCIAL_MEDIA_XHS_MCP_UPSTREAM_URL",
@@ -438,7 +508,7 @@ const PLATFORMS = {
438
508
  status: "public",
439
509
  registryName: "com.52choujiang/douyin-insights",
440
510
  futureRegistryName: "com.socialdatax/douyin-insights",
441
- endpoint: "https://mcp.52choujiang.com/douyin/mcp",
511
+ endpoint: "https://mcp.socialdatax.com/douyin/mcp",
442
512
  apiKeyEnv: API_KEY_ENV_NAMES,
443
513
  upstreamEnv: [
444
514
  "SOCIAL_MEDIA_DOUYIN_MCP_UPSTREAM_URL",
@@ -522,7 +592,7 @@ const PLATFORMS = {
522
592
  status: "public",
523
593
  registryName: "com.52choujiang/kuaishou-insights",
524
594
  futureRegistryName: "com.socialdatax/kuaishou-insights",
525
- endpoint: "https://mcp.52choujiang.com/kuaishou/mcp",
595
+ endpoint: "https://mcp.socialdatax.com/kuaishou/mcp",
526
596
  apiKeyEnv: API_KEY_ENV_NAMES,
527
597
  upstreamEnv: [
528
598
  "SOCIAL_MEDIA_KUAISHOU_MCP_UPSTREAM_URL",
@@ -598,7 +668,7 @@ const PLATFORMS = {
598
668
  status: "public",
599
669
  registryName: "com.52choujiang/weibo-insights",
600
670
  futureRegistryName: "com.socialdatax/weibo-insights",
601
- endpoint: "https://mcp.52choujiang.com/weibo/mcp",
671
+ endpoint: "https://mcp.socialdatax.com/weibo/mcp",
602
672
  apiKeyEnv: API_KEY_ENV_NAMES,
603
673
  upstreamEnv: [
604
674
  "SOCIAL_MEDIA_WEIBO_MCP_UPSTREAM_URL",
@@ -682,7 +752,7 @@ const PLATFORMS = {
682
752
  status: "public",
683
753
  registryName: "com.52choujiang/wechat-channels-insights",
684
754
  futureRegistryName: "com.socialdatax/wechat-channels-insights",
685
- endpoint: "https://mcp.52choujiang.com/wechat/mcp",
755
+ endpoint: "https://mcp.socialdatax.com/wechat/mcp",
686
756
  apiKeyEnv: API_KEY_ENV_NAMES,
687
757
  upstreamEnv: [
688
758
  "SOCIAL_MEDIA_WECHAT_MCP_UPSTREAM_URL",
@@ -748,6 +818,27 @@ const PLATFORMS = {
748
818
  },
749
819
  ],
750
820
  },
821
+ "sensitive-check": {
822
+ id: "sensitive-check",
823
+ displayName: "Sensitive Check / 敏感检测",
824
+ status: "public",
825
+ registryName: "sensitive-check",
826
+ futureRegistryName: "com.socialdatax/sensitive-check",
827
+ endpoint: "https://mcp.socialdatax.com/sensitive-check/mcp",
828
+ apiKeyEnv: API_KEY_ENV_NAMES,
829
+ upstreamEnv: [
830
+ "SOCIALDATAX_SENSITIVE_CHECK_MCP_UPSTREAM_URL",
831
+ "SOCIAL_MEDIA_SENSITIVE_CHECK_MCP_UPSTREAM_URL",
832
+ "SOCIAL_MEDIA_MCP_UPSTREAM_URL",
833
+ ],
834
+ tools: [
835
+ {
836
+ name: "check_sensitive_text",
837
+ description:
838
+ "Check text content for generic, XHS, Douyin, or Kuaishou sensitive-content risks.",
839
+ },
840
+ ],
841
+ },
751
842
  };
752
843
  const currentDir = dirname(fileURLToPath(import.meta.url));
753
844
  let mcpSdkModules;
@@ -787,6 +878,8 @@ if (isMainModule()) {
787
878
  await runWeiboDirectCommand(cliArgs.slice(1));
788
879
  } else if (command === "wechat") {
789
880
  await runWechatDirectCommand(cliArgs.slice(1));
881
+ } else if (command === "sensitive-check") {
882
+ await runSensitiveCheckDirectCommand(cliArgs.slice(1));
790
883
  } else if (command === "--platform" || command?.startsWith("--platform=") || command === "print-config") {
791
884
  printRemovedMcpConfigHelp(command);
792
885
  process.exitCode = 1;
@@ -947,6 +1040,21 @@ function validateWechatDirectActionOptions(action, options) {
947
1040
  }
948
1041
  }
949
1042
 
1043
+ function validateSensitiveCheckDirectActionOptions(action, options) {
1044
+ const allowedOptions = SENSITIVE_CHECK_DIRECT_ACTION_OPTIONS[action];
1045
+ if (!allowedOptions) {
1046
+ return;
1047
+ }
1048
+
1049
+ validateKnownOptions(options, allowedOptions);
1050
+ validateFlagOption(options, "pretty", "--pretty");
1051
+ for (const key of allowedOptions) {
1052
+ if (!DIRECT_BOOLEAN_OPTIONS.has(key)) {
1053
+ requireOptionValue(options, key, SENSITIVE_CHECK_OPTION_DISPLAY_NAMES[key]);
1054
+ }
1055
+ }
1056
+ }
1057
+
950
1058
  function validateDirectPaginationOptions(platformId, action, options) {
951
1059
  validateFlagOption(options, "pretty", "--pretty");
952
1060
  validateFlagOption(options, "all", "--all");
@@ -960,6 +1068,9 @@ function validateDirectPaginationOptions(platformId, action, options) {
960
1068
  if (options.maxItems !== undefined) {
961
1069
  parsePositiveIntegerOption(options.maxItems, "--max-items");
962
1070
  }
1071
+ if (options.sinceDays !== undefined) {
1072
+ parseSinceDaysOption(options.sinceDays);
1073
+ }
963
1074
  if (options.all && action === "search") {
964
1075
  throw new Error(`--all is not supported for ${platformId} search. Use --pages instead.`);
965
1076
  }
@@ -980,6 +1091,37 @@ function parsePositiveIntegerOption(value, displayName) {
980
1091
  return parsed;
981
1092
  }
982
1093
 
1094
+ function parseSinceDaysOption(value) {
1095
+ const text = String(value);
1096
+ if (!/^\d+$/.test(text)) {
1097
+ throw new Error("--since-days must be an integer between 1 and 365.");
1098
+ }
1099
+ const parsed = Number(text);
1100
+ if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 365) {
1101
+ throw new Error("--since-days must be an integer between 1 and 365.");
1102
+ }
1103
+ return parsed;
1104
+ }
1105
+
1106
+ function parseOptionalSinceDays(options) {
1107
+ return options.sinceDays === undefined
1108
+ ? undefined
1109
+ : parseSinceDaysOption(options.sinceDays);
1110
+ }
1111
+
1112
+ function nativePublishTimeRangeForSinceDays(sinceDays) {
1113
+ if (sinceDays <= 1) {
1114
+ return "day";
1115
+ }
1116
+ if (sinceDays <= 7) {
1117
+ return "week";
1118
+ }
1119
+ if (sinceDays <= 180) {
1120
+ return "half_year";
1121
+ }
1122
+ return undefined;
1123
+ }
1124
+
983
1125
  function parseAllowedStringOption(value, displayName, allowedValues, label) {
984
1126
  const normalized = String(value).trim();
985
1127
  if (!allowedValues.includes(normalized)) {
@@ -1445,6 +1587,9 @@ function printHelp() {
1445
1587
  console.log(` npx -y ${PACKAGE_SPEC} xhs search --keyword "露营" --pretty`);
1446
1588
  console.log(" Call the XHS search tool directly and print JSON.");
1447
1589
  console.log("");
1590
+ console.log(` npx -y ${PACKAGE_SPEC} xhs search --keyword "露营" --since-days 7 --pages 2 --pretty`);
1591
+ console.log(" Search recent XHS results and keep items published in the last 7 days.");
1592
+ console.log("");
1448
1593
  console.log(` npx -y ${PACKAGE_SPEC} xhs hot-search --pretty`);
1449
1594
  console.log(" Call the XHS search hot list tool directly and print JSON.");
1450
1595
  console.log("");
@@ -1468,6 +1613,9 @@ function printHelp() {
1468
1613
  console.log(` npx -y ${PACKAGE_SPEC} xhs user-posts --user-id "<user_id>" --pretty`);
1469
1614
  console.log(" Call the XHS creator posts tool directly and print JSON.");
1470
1615
  console.log("");
1616
+ console.log(` npx -y ${PACKAGE_SPEC} xhs user-posts --user-id "<user_id>" --since-days 30 --pretty`);
1617
+ console.log(" Fetch recent creator posts until the publish-time boundary is reached.");
1618
+ console.log("");
1471
1619
  console.log(` npx -y ${PACKAGE_SPEC} douyin hot-search --pretty`);
1472
1620
  console.log(" Call the Douyin main hot search list tool directly and print JSON.");
1473
1621
  console.log("");
@@ -1615,6 +1763,9 @@ function printHelp() {
1615
1763
  console.log(` npx -y ${PACKAGE_SPEC} wechat user-posts --url "<wechat_video_url_or_share_text>" --pretty`);
1616
1764
  console.log(" Call the WeChat Channels / 视频号 creator videos tool from a video link or share text.");
1617
1765
  console.log("");
1766
+ console.log(` npx -y ${PACKAGE_SPEC} sensitive-check text --text "<content>" --platform xhs --pretty`);
1767
+ console.log(" Call the SocialDataX 敏感检测 text tool directly and print JSON.");
1768
+ console.log("");
1618
1769
  console.log(` npx -y ${PACKAGE_SPEC} list`);
1619
1770
  console.log(" List available skills.");
1620
1771
  console.log("");
@@ -1694,12 +1845,18 @@ function printHelp() {
1694
1845
  console.log(" --profile-url <profile-url-or-share-text>");
1695
1846
  console.log(" --user-id <user_id>");
1696
1847
  console.log(" --sec-user-id <sec_user_id>");
1848
+ console.log(" --text <content>");
1849
+ console.log(" Text content for sensitive-check text.");
1850
+ console.log(" --platform <generic|xhs|douyin|kuaishou>");
1851
+ console.log(" Target platform for sensitive-check text; default is generic.");
1697
1852
  console.log(" --pages <number>");
1698
1853
  console.log(" Fetch and merge N pages from the current starting point for search, comments, replies, creator content lists, and creator series.");
1699
1854
  console.log(" --all");
1700
1855
  console.log(" Continue comments, replies, creator content lists, and creator series until next_page_token is empty; not supported for search.");
1701
1856
  console.log(" --max-items <number>");
1702
1857
  console.log(" Stop after collecting this many primary items.");
1858
+ console.log(" --since-days <1-365>");
1859
+ console.log(" Keep search or creator content-list items with publish_time in the last N days. Search stays bounded by --pages; creator lists continue until the time boundary when --pages is omitted.");
1703
1860
  console.log(" --include-replies");
1704
1861
  console.log(" For comments commands, also fetch nested second-level replies for each returned first-level comment.");
1705
1862
  console.log(" --sort-type <general|time_descending|like_count_descending|comment_count_descending|collect_count_descending>");
@@ -1749,18 +1906,18 @@ function printRemovedMcpConfigHelp(command) {
1749
1906
  console.error(" com.socialdatax/wechat-channels-insights");
1750
1907
  console.error("");
1751
1908
  console.error("Use hosted streamable HTTP when your client supports remote MCP:");
1752
- console.error(" https://mcp.52choujiang.com/xhs/mcp");
1753
- console.error(" https://mcp.52choujiang.com/douyin/mcp");
1754
- console.error(" https://mcp.52choujiang.com/kuaishou/mcp");
1755
- console.error(" https://mcp.52choujiang.com/weibo/mcp");
1756
- console.error(" https://mcp.52choujiang.com/wechat/mcp");
1909
+ console.error(" https://mcp.socialdatax.com/xhs/mcp");
1910
+ console.error(" https://mcp.socialdatax.com/douyin/mcp");
1911
+ console.error(" https://mcp.socialdatax.com/kuaishou/mcp");
1912
+ console.error(" https://mcp.socialdatax.com/weibo/mcp");
1913
+ console.error(" https://mcp.socialdatax.com/wechat/mcp");
1757
1914
  console.error("");
1758
1915
  console.error("For command/stdio-only clients, use mcp-remote:");
1759
- console.error(` npx -y mcp-remote https://mcp.52choujiang.com/xhs/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1760
- console.error(` npx -y mcp-remote https://mcp.52choujiang.com/douyin/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1761
- console.error(` npx -y mcp-remote https://mcp.52choujiang.com/kuaishou/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1762
- console.error(` npx -y mcp-remote https://mcp.52choujiang.com/weibo/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1763
- console.error(` npx -y mcp-remote https://mcp.52choujiang.com/wechat/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1916
+ console.error(` npx -y mcp-remote https://mcp.socialdatax.com/xhs/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1917
+ console.error(` npx -y mcp-remote https://mcp.socialdatax.com/douyin/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1918
+ console.error(` npx -y mcp-remote https://mcp.socialdatax.com/kuaishou/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1919
+ console.error(` npx -y mcp-remote https://mcp.socialdatax.com/weibo/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1920
+ console.error(` npx -y mcp-remote https://mcp.socialdatax.com/wechat/mcp --header "Authorization: Bearer <${PRIMARY_API_KEY_ENV}>"`);
1764
1921
  }
1765
1922
 
1766
1923
  async function runXhsDirectCommand(args) {
@@ -1898,6 +2055,30 @@ async function runWechatDirectCommand(args) {
1898
2055
  process.stdout.write("\n");
1899
2056
  }
1900
2057
 
2058
+ async function runSensitiveCheckDirectCommand(args) {
2059
+ const { options, positional } = parseCommandArgs(args);
2060
+ const action = positional[0];
2061
+ if (!action) {
2062
+ throw new Error(
2063
+ `Missing sensitive-check command. Use ${SENSITIVE_CHECK_DIRECT_ACTION_NAMES}.`
2064
+ );
2065
+ }
2066
+ if (positional.length > 1) {
2067
+ throw new Error(`Unexpected argument: ${positional[1]}`);
2068
+ }
2069
+ validateSensitiveCheckDirectActionOptions(action, options);
2070
+
2071
+ const operation = buildSensitiveCheckOperation(action, options);
2072
+ const data = await callDirectOperation(operation);
2073
+ const envelope = {
2074
+ platform: operation.platform.id,
2075
+ tool: operation.tool,
2076
+ data,
2077
+ };
2078
+ process.stdout.write(JSON.stringify(envelope, null, options.pretty ? 2 : 0));
2079
+ process.stdout.write("\n");
2080
+ }
2081
+
1901
2082
  function buildXhsOperation(action, options) {
1902
2083
  switch (action) {
1903
2084
  case "hot-search":
@@ -2360,6 +2541,21 @@ function buildWechatOperation(action, options) {
2360
2541
  }
2361
2542
  }
2362
2543
 
2544
+ function buildSensitiveCheckOperation(action, options) {
2545
+ switch (action) {
2546
+ case "text":
2547
+ return buildDirectOperation(
2548
+ "text",
2549
+ buildSensitiveCheckTextCall(options),
2550
+ PLATFORMS["sensitive-check"]
2551
+ );
2552
+ default:
2553
+ throw new Error(
2554
+ `Unsupported sensitive-check command "${action}". Use ${SENSITIVE_CHECK_DIRECT_ACTION_NAMES}.`
2555
+ );
2556
+ }
2557
+ }
2558
+
2363
2559
  function buildDirectOperation(operation, { tool, toolArguments }, platform = PLATFORMS.xhs) {
2364
2560
  return {
2365
2561
  platform,
@@ -2374,8 +2570,13 @@ function buildXhsSearchCall(options) {
2374
2570
  if (!options.keyword) {
2375
2571
  throw new Error("Missing --keyword for xhs search.");
2376
2572
  }
2573
+ const sinceDays = parseOptionalSinceDays(options);
2574
+ const requestedSortType =
2575
+ options.sortType === undefined && sinceDays !== undefined
2576
+ ? "time_descending"
2577
+ : options.sortType || "general";
2377
2578
  const sortType = parseSemanticOption(
2378
- options.sortType || "general",
2579
+ requestedSortType,
2379
2580
  "--sort-type",
2380
2581
  XHS_SEARCH_SORT_TYPES,
2381
2582
  XHS_LEGACY_SEARCH_SORT_TYPE_ALIASES,
@@ -2403,12 +2604,19 @@ function buildXhsSearchCall(options) {
2403
2604
  }
2404
2605
  if (options.sortType !== undefined) {
2405
2606
  toolArguments.sort_type = sortType;
2607
+ } else if (sinceDays !== undefined) {
2608
+ toolArguments.sort_type = "time_descending";
2406
2609
  }
2407
2610
  if (options.noteType !== undefined) {
2408
2611
  toolArguments.note_type = noteType;
2409
2612
  }
2410
2613
  if (options.publishTimeRange !== undefined) {
2411
2614
  toolArguments.publish_time_range = publishTimeRange;
2615
+ } else if (sinceDays !== undefined) {
2616
+ const nativeRange = nativePublishTimeRangeForSinceDays(sinceDays);
2617
+ if (nativeRange) {
2618
+ toolArguments.publish_time_range = nativeRange;
2619
+ }
2412
2620
  }
2413
2621
  return {
2414
2622
  tool: "xhs_search_notes",
@@ -2475,6 +2683,7 @@ function buildDouyinSearchCall(options) {
2475
2683
  if (!options.keyword) {
2476
2684
  throw new Error("Missing --keyword for douyin search.");
2477
2685
  }
2686
+ const sinceDays = parseOptionalSinceDays(options);
2478
2687
  const toolArguments = {
2479
2688
  keyword: options.keyword,
2480
2689
  };
@@ -2485,6 +2694,8 @@ function buildDouyinSearchCall(options) {
2485
2694
  DOUYIN_SEARCH_SORT_TYPES,
2486
2695
  DOUYIN_SEARCH_SORT_TYPES.join(", ")
2487
2696
  );
2697
+ } else if (sinceDays !== undefined) {
2698
+ toolArguments.sort_type = "time_descending";
2488
2699
  }
2489
2700
  if (options.publishTimeRange !== undefined) {
2490
2701
  toolArguments.publish_time_range = parseAllowedStringOption(
@@ -2493,6 +2704,11 @@ function buildDouyinSearchCall(options) {
2493
2704
  DOUYIN_SEARCH_PUBLISH_TIME_RANGES,
2494
2705
  DOUYIN_SEARCH_PUBLISH_TIME_RANGES.join(", ")
2495
2706
  );
2707
+ } else if (sinceDays !== undefined) {
2708
+ const nativeRange = nativePublishTimeRangeForSinceDays(sinceDays);
2709
+ if (nativeRange) {
2710
+ toolArguments.publish_time_range = nativeRange;
2711
+ }
2496
2712
  }
2497
2713
  if (options.durationRange !== undefined) {
2498
2714
  toolArguments.duration_range = parseAllowedStringOption(
@@ -2555,6 +2771,7 @@ function buildWechatSearchCall(options) {
2555
2771
  if (!options.keyword) {
2556
2772
  throw new Error("Missing --keyword for wechat search.");
2557
2773
  }
2774
+ const sinceDays = parseOptionalSinceDays(options);
2558
2775
  const toolArguments = {
2559
2776
  keyword: options.keyword,
2560
2777
  };
@@ -2565,6 +2782,8 @@ function buildWechatSearchCall(options) {
2565
2782
  WECHAT_SEARCH_SORT_TYPES,
2566
2783
  WECHAT_SEARCH_SORT_TYPES.join(", ")
2567
2784
  );
2785
+ } else if (sinceDays !== undefined) {
2786
+ toolArguments.sort_type = "latest";
2568
2787
  }
2569
2788
  if (options.durationRange !== undefined) {
2570
2789
  toolArguments.duration_range = parseAllowedStringOption(
@@ -2583,6 +2802,25 @@ function buildWechatSearchCall(options) {
2583
2802
  };
2584
2803
  }
2585
2804
 
2805
+ function buildSensitiveCheckTextCall(options) {
2806
+ if (!options.text) {
2807
+ throw new Error("Missing --text for sensitive-check text.");
2808
+ }
2809
+ const platform = parseAllowedStringOption(
2810
+ options.platform || "generic",
2811
+ "--platform",
2812
+ SENSITIVE_CHECK_PLATFORMS,
2813
+ SENSITIVE_CHECK_PLATFORMS.join(", ")
2814
+ );
2815
+ return {
2816
+ tool: "check_sensitive_text",
2817
+ toolArguments: {
2818
+ text: options.text,
2819
+ platform,
2820
+ },
2821
+ };
2822
+ }
2823
+
2586
2824
  function buildDouyinRepliesCall(options) {
2587
2825
  if (!options.awemeId) {
2588
2826
  throw new Error("Missing --aweme-id for douyin replies.");
@@ -2755,7 +2993,8 @@ function shouldUsePaginatedDirectOutput(options) {
2755
2993
  options.all ||
2756
2994
  options.pages !== undefined ||
2757
2995
  options.maxItems !== undefined ||
2758
- options.includeReplies
2996
+ options.includeReplies ||
2997
+ options.sinceDays !== undefined
2759
2998
  );
2760
2999
  }
2761
3000
 
@@ -2777,6 +3016,7 @@ function parseDirectPaginationOptions(options) {
2777
3016
  options.maxItems === undefined
2778
3017
  ? undefined
2779
3018
  : parsePositiveIntegerOption(options.maxItems, "--max-items"),
3019
+ sinceDays: parseOptionalSinceDays(options),
2780
3020
  };
2781
3021
  }
2782
3022
 
@@ -2785,7 +3025,14 @@ async function collectPaginatedDirectData(
2785
3025
  pagination,
2786
3026
  { includeReplies = false } = {}
2787
3027
  ) {
2788
- const pageLimit = pagination.all ? Number.POSITIVE_INFINITY : pagination.pages || 1;
3028
+ const pageLimit =
3029
+ pagination.all || shouldAutoPaginateSinceDays(operation, pagination)
3030
+ ? Number.POSITIVE_INFINITY
3031
+ : pagination.pages || 1;
3032
+ const sinceDaysCutoff =
3033
+ pagination.sinceDays === undefined
3034
+ ? undefined
3035
+ : cutoffPublishTimeForSinceDays(pagination.sinceDays);
2789
3036
  const collectedItems = [];
2790
3037
  const itemDedupeState = createPaginatedItemDedupeState();
2791
3038
  const seenNextMarkers = initialPaginationMarkers(operation);
@@ -2794,6 +3041,7 @@ async function collectPaginatedDirectData(
2794
3041
  let nextMarker;
2795
3042
  let parentContextData = {};
2796
3043
  let currentOperation = cloneDirectOperation(operation);
3044
+ let stoppedBySinceDays = false;
2797
3045
 
2798
3046
  while (pageCount < pageLimit) {
2799
3047
  const pageData = await callDirectOperation(currentOperation);
@@ -2806,8 +3054,12 @@ async function collectPaginatedDirectData(
2806
3054
  directPageItems(pageData),
2807
3055
  itemDedupeState
2808
3056
  );
3057
+ const filteredPage = filterItemsBySinceDays(pageItems, sinceDaysCutoff);
3058
+ if (shouldStopAtSinceDaysBoundary(operation, sinceDaysCutoff, pageItems)) {
3059
+ stoppedBySinceDays = true;
3060
+ }
2809
3061
  const candidateItems = itemsForRemainingLimit(
2810
- pageItems,
3062
+ filteredPage.items,
2811
3063
  collectedItems.length,
2812
3064
  pagination.maxItems
2813
3065
  );
@@ -2828,6 +3080,7 @@ async function collectPaginatedDirectData(
2828
3080
  if (
2829
3081
  !nextMarker ||
2830
3082
  reachedMaxItems(collectedItems, pagination.maxItems) ||
3083
+ stoppedBySinceDays ||
2831
3084
  pageCount >= pageLimit
2832
3085
  ) {
2833
3086
  if (markerRepeated) {
@@ -2851,6 +3104,7 @@ async function collectPaginatedDirectData(
2851
3104
  items: collectedItems,
2852
3105
  pageCount,
2853
3106
  nextMarker,
3107
+ stoppedBySinceDays,
2854
3108
  });
2855
3109
  }
2856
3110
 
@@ -2865,6 +3119,54 @@ function directPageItems(pageData) {
2865
3119
  return Array.isArray(pageData?.items) ? pageData.items : [];
2866
3120
  }
2867
3121
 
3122
+ function shouldAutoPaginateSinceDays(operation, pagination) {
3123
+ return (
3124
+ operation.operation === "user-posts" &&
3125
+ pagination.sinceDays !== undefined &&
3126
+ pagination.pages === undefined
3127
+ );
3128
+ }
3129
+
3130
+ function cutoffPublishTimeForSinceDays(sinceDays) {
3131
+ return Math.floor(Date.now() / 1000) - sinceDays * 86400;
3132
+ }
3133
+
3134
+ function itemPublishTimeSeconds(item) {
3135
+ const value = item?.publish_time;
3136
+ const timestamp =
3137
+ typeof value === "number"
3138
+ ? value
3139
+ : typeof value === "string"
3140
+ ? Number(value)
3141
+ : NaN;
3142
+ if (!Number.isFinite(timestamp) || timestamp <= 0) {
3143
+ return undefined;
3144
+ }
3145
+ return timestamp;
3146
+ }
3147
+
3148
+ function filterItemsBySinceDays(items, cutoffPublishTime) {
3149
+ if (cutoffPublishTime === undefined) {
3150
+ return { items };
3151
+ }
3152
+ return {
3153
+ items: items.filter((item) => {
3154
+ const publishTime = itemPublishTimeSeconds(item);
3155
+ return publishTime !== undefined && publishTime >= cutoffPublishTime;
3156
+ }),
3157
+ };
3158
+ }
3159
+
3160
+ function shouldStopAtSinceDaysBoundary(operation, cutoffPublishTime, items) {
3161
+ if (operation.operation !== "user-posts" || cutoffPublishTime === undefined) {
3162
+ return false;
3163
+ }
3164
+ return items.some((item) => {
3165
+ const publishTime = itemPublishTimeSeconds(item);
3166
+ return publishTime !== undefined && publishTime < cutoffPublishTime;
3167
+ });
3168
+ }
3169
+
2868
3170
  function createPaginatedItemDedupeState() {
2869
3171
  return { seenKeys: new Set() };
2870
3172
  }
@@ -3084,6 +3386,7 @@ function buildPaginatedData({
3084
3386
  items,
3085
3387
  pageCount,
3086
3388
  nextMarker,
3389
+ stoppedBySinceDays,
3087
3390
  }) {
3088
3391
  const data = {
3089
3392
  ...(lastPageData && typeof lastPageData === "object" ? lastPageData : {}),
@@ -3094,6 +3397,9 @@ function buildPaginatedData({
3094
3397
  };
3095
3398
  delete data.next_page;
3096
3399
  data.next_page_token = nextMarker || "";
3400
+ if (stoppedBySinceDays) {
3401
+ data.stopped_by_since_days = true;
3402
+ }
3097
3403
  return data;
3098
3404
  }
3099
3405
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socialdatax-skills",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "SocialDataX / 社媒数据助手 skill installer and direct CLI helper for hosted platform social media MCP services.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -56,7 +56,12 @@
56
56
  "wechat",
57
57
  "wechat-channels",
58
58
  "wechat-channels-data",
59
- "wechat-channels-search"
59
+ "wechat-channels-search",
60
+ "sensitive-check",
61
+ "sensitive-checking",
62
+ "content-safety",
63
+ "text-safety",
64
+ "sensitive-detection"
60
65
  ],
61
66
  "homepage": "https://socialdatax.com",
62
67
  "bugs": {
@@ -71,5 +76,9 @@
71
76
  },
72
77
  "dependencies": {
73
78
  "@modelcontextprotocol/sdk": "^1.29.0"
79
+ },
80
+ "overrides": {
81
+ "hono": "4.12.27",
82
+ "qs": "6.15.3"
74
83
  }
75
84
  }
@@ -76,6 +76,7 @@ Optional arguments:
76
76
  - Douyin `--pages <n>`: fetch and merge N search pages from the current starting point; continue with returned `next_page_token`.
77
77
  - Kuaishou `--pages <n>`: fetch and merge N search pages from the current starting point; continue with returned `next_page_token`.
78
78
  - `--max-items <n>`: stop after collecting N search results.
79
+ - `--since-days <1-365>`: keep only results whose public `publish_time` is within the last N days. Search remains bounded by `--pages` and does not promise complete platform coverage.
79
80
  - `--pretty`: output formatting only.
80
81
  - Kuaishou `--page-token <next_page_token>`: opaque pagination token; omit it on the first search request. Continue only with the complete returned `next_page_token` from the same search pagination chain. Do not modify, truncate, redact, mask, omit, normalize, rebuild, generate, or replace the middle with ellipses.
81
82
  - Weibo `--page-token <next_page_token>`: opaque pagination token; omit it on the first search request. Continue only with the complete returned `next_page_token` from the same search pagination chain. Do not modify, truncate, redact, mask, omit, normalize, rebuild, generate, or replace the middle with ellipses.
@@ -126,6 +127,7 @@ Douyin content type filter values:
126
127
  - `image`: image/text posts.
127
128
 
128
129
  The command prints JSON with `platform`, `tool`, `arguments`, and `data`. Search supports `--pages` and `--max-items`, but not `--all`, because search has no stable complete-result boundary. Multi-page output keeps merged results in `data.items` and adds `page_count`, `item_count`, and the next-page marker.
130
+ With CLI `--since-days <n>`, XHS and Douyin search automatically prefer newest-first sorting and the closest native publish-time range unless the user explicitly sets sort or publish-time filters; WeChat Channels search defaults to `latest`; Kuaishou and Weibo only apply CLI-side `publish_time` filtering.
129
131
  Kuaishou search pagination:
130
132
  - Continue only when `next_page_token` is not empty.
131
133
  - Pass the complete returned `next_page_token` back unchanged as `page_token` for the same search pagination chain. Do not modify, truncate, redact, mask, omit, normalize, rebuild, generate, or replace the middle with ellipses.
@@ -198,6 +200,7 @@ Do not pass `page` to `wechat_search_videos`; omit `page_token` on the first req
198
200
  - `sort_type`: optional, one of `all`, `latest`, `popular`; omit it for the default sort.
199
201
  - `duration_range`: optional duration filter, one of `all`, `under_5_min`, `between_5_and_20_min`, `over_20_min`; omit it for no duration filter.
200
202
  Continue WeChat Channels pagination only when `next_page_token` is not empty. Pass the complete returned `next_page_token` back unchanged as `page_token` for the same keyword and filter chain.
203
+ `--since-days` uses CLI-side filtering only and is not an MCP tool argument; for MCP-only calls, request newest-first/native publish-time filters where available and filter returned `publish_time` values in your analysis.
201
204
 
202
205
  ## Output Guidance
203
206
 
@@ -73,6 +73,7 @@ Optional arguments:
73
73
  - `--pages <n>`: fetch and merge N pages of creator content or creator series.
74
74
  - `--all`: continue until `next_page_token` is empty; there is no default item or page cap.
75
75
  - `--max-items <n>`: stop after collecting N creator content or series items.
76
+ - `--since-days <1-365>`: keep only creator content whose public `publish_time` is within the last N days. When `--pages` is omitted, the CLI continues creator content lists until the publish-time boundary is reached.
76
77
  - `--pretty`: output formatting only.
77
78
  - Kuaishou `--user-id <user_id>`: preferred when the creator user_id is already known.
78
79
  - Kuaishou `--profile-url <profile_url_or_share_text>`: use for a profile URL, short link, or profile share text.
@@ -84,6 +85,7 @@ Optional arguments:
84
85
  Use either the ID option or the profile URL option for a single command, not both.
85
86
 
86
87
  The command prints JSON with `platform`, `tool`, `arguments`, and `data`. Multi-page output keeps merged creator content or series items in `data.items` and adds `page_count`, `item_count`, and `next_page_token`.
88
+ For recent creator research, prefer CLI `--since-days 30` or another user-specified day window. `--since-days` applies to creator content lists only, not Douyin `user-series`.
87
89
 
88
90
  ## Safety Boundary
89
91
 
@@ -124,6 +126,7 @@ Weibo creator post pagination uses opaque `page_token` values; pass the complete
124
126
  - `wechat_get_user_posted_videos_by_user_id`: preferred when the WeChat Channels / 视频号 `@finder` user_id is already known.
125
127
  - `wechat_get_user_posted_videos_by_url`: use a WeChat Channels / 视频号 video link or share text to resolve the author and list that creator's videos.
126
128
  WeChat Channels / 视频号 creator video pagination uses opaque `page_token` values; pass the complete returned `next_page_token` back unchanged for the same user. Do not modify, truncate, redact, mask, omit, normalize, rebuild, generate, or replace the middle with ellipses.
129
+ `--since-days` uses CLI-side filtering only and is not an MCP tool argument; for MCP-only calls, continue pages as needed and filter returned `publish_time` values in your analysis.
127
130
 
128
131
  ## Output Guidance
129
132
 
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: "sensitive-check"
3
+ description: "Check draft text for sensitive-content risks before publishing. Supports generic, xhs, douyin, and kuaishou contexts through SocialDataX."
4
+ metadata:
5
+ openclaw:
6
+ requires:
7
+ env:
8
+ - "SOCIALDATAX_API_KEY"
9
+ bins:
10
+ - "node"
11
+ - "npm"
12
+ primaryEnv: "SOCIALDATAX_API_KEY"
13
+ install:
14
+ - kind: "node"
15
+ package: "socialdatax-skills"
16
+ bins: []
17
+ emoji: "🛡️"
18
+ homepage: "https://socialdatax.com/?from=npm"
19
+ ---
20
+ <!-- AUTO-GENERATED from socialdatax-skill-source. Do not edit directly; run `node scripts/generate_socialdatax_skills.mjs`. -->
21
+
22
+ # 敏感检测 SocialDataX
23
+
24
+ Use this skill when the user wants 敏感检测, sensitive check, content safety review, or platform-aware review for text drafts before publishing.
25
+
26
+ Current platform support:
27
+
28
+ - Text sensitive-content detection through `check_sensitive_text` for `generic`, `xhs`, `douyin`, and `kuaishou` contexts.
29
+
30
+ ## API Key
31
+
32
+ Use `SOCIALDATAX_API_KEY` for SocialDataX requests. The only official website for requesting or managing API access is <https://socialdatax.com/?from=npm>. If a user asks where to get a key, provide only this URL; do not infer alternate domains.
33
+ 获取或管理 API Key:访问 <https://socialdatax.com/?from=npm>,按官网的 API Key 申请/管理入口操作。环境变量名固定使用 `SOCIALDATAX_API_KEY`;不要引导用户使用其他域名。
34
+
35
+ ## Preferred Direct CLI
36
+
37
+ Prefer the direct CLI when the agent can run shell commands. It does not require MCP server configuration:
38
+
39
+ ```bash
40
+ npx -y socialdatax-skills@latest sensitive-check text --text "<content>" --platform xhs --pretty
41
+ ```
42
+
43
+ Required arguments:
44
+
45
+ - `sensitive-check text --text <content>`: required text to check. Use the user's draft text for analysis, but do not store it in the skill.
46
+
47
+ Optional arguments:
48
+
49
+ - `--platform <generic|xhs|douyin|kuaishou>`: platform context; default is `generic`.
50
+ - `--pretty`: output formatting only.
51
+
52
+ Use this skill when the user wants 敏感检测, sensitive check, content safety review, or platform-aware preflight review for draft text.
53
+ The command prints JSON with `platform`, `tool`, and `data`; it does not echo the original text back in CLI arguments. The service returns `violation`, `risk_level`, `types`, `highlights`, `summary`, `platform`, and `suggestions` when available.
54
+ This v1 skill checks text only. Image sensitive detection is intentionally out of scope until a separate image tool is published.
55
+
56
+ ## Safety Boundary
57
+
58
+ This skill is read-only. It does not read local browser data, does not save API keys, and does not perform login, posting, liking, commenting, or account changes. Prefer the direct CLI; hosted MCP tools are optional when the current agent already supports authenticated streamable HTTP MCP.
59
+
60
+ ## MCP Tools
61
+
62
+ MCP tools matching the direct CLI commands above:
63
+
64
+ - `check_sensitive_text`
65
+
66
+ If MCP tools are already available in the current agent, call `check_sensitive_text` with `text` and optional `platform`: `generic`, `xhs`, `douyin`, or `kuaishou`.
67
+
68
+ ## Output Guidance
69
+
70
+ Report whether there is a violation, the risk level, detected types, brief highlights, and concrete rewrite suggestions.
71
+ Do not echo the full original text back unless the user explicitly asks; prefer short highlights and safer rewrite guidance.
@@ -0,0 +1,7 @@
1
+ interface:
2
+ display_name: "Sensitive Check"
3
+ short_description: "Check draft text risks"
4
+ default_prompt: "Use $sensitive-check to check text drafts for sensitive-content risks with SocialDataX."
5
+
6
+ policy:
7
+ allow_implicit_invocation: true
@@ -168,6 +168,7 @@ Optional arguments:
168
168
  - `--pages <n>`: fetch and merge N pages for search, comments, replies, creator posts, or creator series.
169
169
  - `--all`: fetch comments, replies, creator posts, or creator series until `next_page_token` is empty; do not use it for search.
170
170
  - `--max-items <n>`: stop after collecting N primary results.
171
+ - `--since-days <1-365>`: keep search or creator content-list items whose public `publish_time` is within the last N days. Search stays bounded by `--pages`; creator content lists continue until the publish-time boundary when `--pages` is omitted.
171
172
  - `--include-replies`: for first-level comments, also fetch nested second-level replies under each returned comment.
172
173
  - `--sort-type`, `--note-type`, `--publish-time-range`, `--duration-range`, and `--content-type`: apply only to XHS, Douyin, or WeChat Channels keyword research commands when the user asks for filtering; Kuaishou and Weibo search currently use `--keyword` and optional `--page-token`.
173
174
  - `--comment-id`: required for reply/sub-comment commands together with the content ID.
@@ -185,6 +186,7 @@ Optional arguments:
185
186
  ## Choose The Narrowest Entry
186
187
 
187
188
  Use the most specific direct CLI command for the user's task instead of forcing every request through keyword research. The command prints JSON with `platform`, `tool`, `arguments`, and `data`.
189
+ When the user asks for recent content, pass CLI `--since-days <n>` with bounded `--pages`; keep in mind this filters returned `publish_time` values and does not promise complete platform coverage.
188
190
 
189
191
  ## Safety Boundary
190
192