dataclaw-agent-kit 0.0.0-stage → 0.1.1
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 +92 -2
- package/bin/dataclaw-agent-kit.js +2 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +39 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk-CPFAA7NN.js +1212 -0
- package/dist/chunk-CPFAA7NN.js.map +1 -0
- package/dist/index.d.ts +199 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -4
|
@@ -0,0 +1,1212 @@
|
|
|
1
|
+
// src/mcp/client.ts
|
|
2
|
+
import { setTimeout as sleep } from "timers/promises";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import crypto from "crypto";
|
|
6
|
+
import { Readable } from "stream";
|
|
7
|
+
function getErrorMessage(error) {
|
|
8
|
+
if (error instanceof Error) return error.message;
|
|
9
|
+
if (typeof error === "string") return error;
|
|
10
|
+
return "\u672A\u77E5\u9519\u8BEF";
|
|
11
|
+
}
|
|
12
|
+
function formatBytes(bytes) {
|
|
13
|
+
if (!bytes || bytes <= 0) return "";
|
|
14
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
15
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
16
|
+
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
17
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
|
18
|
+
}
|
|
19
|
+
function formatSegmentsToSrt(segments) {
|
|
20
|
+
const pad = (n, width = 2) => String(n).padStart(width, "0");
|
|
21
|
+
return segments.filter((s) => Boolean(s.text && s.text.trim())).map((s, index) => {
|
|
22
|
+
const startMs = Math.round(Number(s.start || 0) * 1e3);
|
|
23
|
+
const endMs = Math.round(Number(s.end ?? Number(s.start || 0) + 2) * 1e3);
|
|
24
|
+
const sH = Math.floor(startMs / 36e5);
|
|
25
|
+
const sM = Math.floor(startMs % 36e5 / 6e4);
|
|
26
|
+
const sS = Math.floor(startMs % 6e4 / 1e3);
|
|
27
|
+
const sMs = startMs % 1e3;
|
|
28
|
+
const eH = Math.floor(endMs / 36e5);
|
|
29
|
+
const eM = Math.floor(endMs % 36e5 / 6e4);
|
|
30
|
+
const eS = Math.floor(endMs % 6e4 / 1e3);
|
|
31
|
+
const eMs = endMs % 1e3;
|
|
32
|
+
const startTime = `${pad(sH)}:${pad(sM)}:${pad(sS)},${pad(sMs, 3)}`;
|
|
33
|
+
const endTime = `${pad(eH)}:${pad(eM)}:${pad(eS)},${pad(eMs, 3)}`;
|
|
34
|
+
return `${index + 1}
|
|
35
|
+
${startTime} --> ${endTime}
|
|
36
|
+
${s.text?.trim() || ""}
|
|
37
|
+
`;
|
|
38
|
+
}).join("\n");
|
|
39
|
+
}
|
|
40
|
+
var DY_SEARCH_SORT = {
|
|
41
|
+
general: "0",
|
|
42
|
+
most_liked: "1",
|
|
43
|
+
most_recent: "2"
|
|
44
|
+
};
|
|
45
|
+
var DY_AWEME_RE = /(?:modal_id|vid|item_id|aweme_id)=([0-9]{6,})|(?:video|slides|note|photo|article|shipin)\/([0-9]{6,})/;
|
|
46
|
+
function douyinAwemeId(raw) {
|
|
47
|
+
const text = raw?.trim();
|
|
48
|
+
if (!text) return void 0;
|
|
49
|
+
if (/^\d+$/.test(text)) return text;
|
|
50
|
+
const match = text.match(DY_AWEME_RE);
|
|
51
|
+
return match?.[1] || match?.[2];
|
|
52
|
+
}
|
|
53
|
+
function douyinVideoUrl(input) {
|
|
54
|
+
const direct = input.url?.trim() || input.share_url?.trim();
|
|
55
|
+
if (direct) return direct;
|
|
56
|
+
const id = douyinAwemeId(input.aweme_id);
|
|
57
|
+
if (id) return `https://www.douyin.com/video/${id}`;
|
|
58
|
+
throw new Error("\u8BF7\u63D0\u4F9B url \u6216 aweme_id");
|
|
59
|
+
}
|
|
60
|
+
function douyinCommentTarget(input) {
|
|
61
|
+
const direct = input.url?.trim() || input.share_url?.trim();
|
|
62
|
+
const awemeId = douyinAwemeId(input.aweme_id) || douyinAwemeId(direct);
|
|
63
|
+
if (awemeId) {
|
|
64
|
+
const url = direct && /^https?:\/\//i.test(direct) ? direct : `https://www.douyin.com/video/${awemeId}`;
|
|
65
|
+
return { url, video_id: awemeId };
|
|
66
|
+
}
|
|
67
|
+
if (direct) return { url: direct };
|
|
68
|
+
throw new Error("\u8BF7\u63D0\u4F9B url \u6216 aweme_id");
|
|
69
|
+
}
|
|
70
|
+
var DataClawClient = class {
|
|
71
|
+
apiKey;
|
|
72
|
+
baseUrl;
|
|
73
|
+
ossPublicBase;
|
|
74
|
+
constructor(config = {}) {
|
|
75
|
+
this.apiKey = config.apiKey || process.env.DATACLAW_API_KEY || "";
|
|
76
|
+
this.baseUrl = (config.baseUrl || process.env.DATACLAW_BASE_URL || "https://www.geodataclaw.com").replace(/\/+$/, "");
|
|
77
|
+
this.ossPublicBase = (process.env.DATACLAW_OSS_BASE_URL || "https://oss.geodataclaw.com").replace(/\/+$/, "");
|
|
78
|
+
}
|
|
79
|
+
get isConfigured() {
|
|
80
|
+
return Boolean(this.apiKey);
|
|
81
|
+
}
|
|
82
|
+
async request(endpoint, options = {}) {
|
|
83
|
+
if (!this.apiKey) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
"\u3010\u672A\u914D\u7F6E API-Key\u3011\u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF DATACLAW_API_KEY\uFF0C\u6216\u8FD0\u884C `npx dataclaw-agent-kit init` \u91CD\u65B0\u914D\u7F6E\u3002"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const url = `${this.baseUrl}${endpoint.startsWith("/") ? endpoint : `/${endpoint}`}`;
|
|
89
|
+
const headers = new Headers(options.headers || {});
|
|
90
|
+
headers.set("Authorization", `Bearer ${this.apiKey}`);
|
|
91
|
+
headers.set("X-API-Key", this.apiKey);
|
|
92
|
+
headers.set("X-Client-Website", "dataclaw");
|
|
93
|
+
if (!headers.has("Content-Type") && !(options.body instanceof FormData)) {
|
|
94
|
+
headers.set("Content-Type", "application/json");
|
|
95
|
+
}
|
|
96
|
+
let response;
|
|
97
|
+
try {
|
|
98
|
+
response = await fetch(url, {
|
|
99
|
+
...options,
|
|
100
|
+
headers
|
|
101
|
+
});
|
|
102
|
+
} catch (err) {
|
|
103
|
+
throw new Error(`\u8BF7\u6C42 DataClaw \u670D\u52A1\u5931\u8D25 (${url}): ${getErrorMessage(err)}`);
|
|
104
|
+
}
|
|
105
|
+
if (response.status === 401) {
|
|
106
|
+
throw new Error("\u3010\u9274\u6743\u5931\u8D25\u3011\u60A8\u7684 DataClaw API-Key \u65E0\u6548\u6216\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u524D\u5F80\u5B98\u7F51\u4E2A\u4EBA\u4E2D\u5FC3\u91CD\u65B0\u751F\u6210\u3002");
|
|
107
|
+
}
|
|
108
|
+
if (response.status === 402) {
|
|
109
|
+
throw new Error("\u3010\u79EF\u5206\u4E0D\u8DB3\u3011\u60A8\u7684 DataClaw \u8D26\u6237\u79EF\u5206\u4E0D\u8DB3\u4EE5\u652F\u4ED8\u672C\u6B21\u64CD\u4F5C\uFF0C\u8BF7\u524D\u5F80\u4E2A\u4EBA\u4E2D\u5FC3\u5145\u503C\u3002");
|
|
110
|
+
}
|
|
111
|
+
const resJson = await response.json().catch(() => null);
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
let errMsg = `HTTP \u9519\u8BEF: ${response.status} ${response.statusText}`;
|
|
114
|
+
if (resJson && typeof resJson === "object") {
|
|
115
|
+
if ("message" in resJson && typeof resJson.message === "string") {
|
|
116
|
+
errMsg = resJson.message;
|
|
117
|
+
} else if ("error" in resJson && typeof resJson.error === "string") {
|
|
118
|
+
errMsg = resJson.error;
|
|
119
|
+
} else if ("detail" in resJson && typeof resJson.detail === "string") {
|
|
120
|
+
errMsg = resJson.detail;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (/credit|积分|balance/i.test(errMsg)) {
|
|
124
|
+
throw new Error(`\u3010\u79EF\u5206\u4E0D\u8DB3\u3011${errMsg}\u3002\u8BF7\u524D\u5F80 DataClaw \u4E2A\u4EBA\u4E2D\u5FC3\u5145\u503C\u3002`);
|
|
125
|
+
}
|
|
126
|
+
throw new Error(`DataClaw API \u9519\u8BEF: ${errMsg}`);
|
|
127
|
+
}
|
|
128
|
+
if (resJson && typeof resJson === "object" && "success" in resJson && resJson.success === false) {
|
|
129
|
+
const msg = "message" in resJson && typeof resJson.message === "string" ? resJson.message : "\u672A\u77E5\u4E1A\u52A1\u9519\u8BEF";
|
|
130
|
+
if (/credit|积分|balance/i.test(msg)) {
|
|
131
|
+
throw new Error(`\u3010\u79EF\u5206\u4E0D\u8DB3\u3011${msg}\u3002\u8BF7\u524D\u5F80 DataClaw \u4E2A\u4EBA\u4E2D\u5FC3\u5145\u503C\u3002`);
|
|
132
|
+
}
|
|
133
|
+
throw new Error(`\u4E1A\u52A1\u9519\u8BEF: ${msg}`);
|
|
134
|
+
}
|
|
135
|
+
if (resJson && typeof resJson === "object" && "data" in resJson) {
|
|
136
|
+
return resJson.data;
|
|
137
|
+
}
|
|
138
|
+
return resJson;
|
|
139
|
+
}
|
|
140
|
+
// ==========================================
|
|
141
|
+
// 用户鉴权与信息校验
|
|
142
|
+
// ==========================================
|
|
143
|
+
async getMe() {
|
|
144
|
+
const res = await this.request("/api/auth/me", { method: "GET" });
|
|
145
|
+
const user = res && typeof res === "object" && "user" in res ? res.user : res;
|
|
146
|
+
return {
|
|
147
|
+
id: typeof user?.id === "number" ? user.id : 0,
|
|
148
|
+
username: typeof user?.username === "string" ? user.username : "",
|
|
149
|
+
credit: typeof user?.credit === "number" ? user.credit : void 0,
|
|
150
|
+
role: typeof user?.role === "string" ? user.role : void 0
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// ==========================================
|
|
154
|
+
// 本地文件预签名直传 R2 / OSS (temp/mcp/ 规范)
|
|
155
|
+
// ==========================================
|
|
156
|
+
async uploadLocalFileToR2(localFilePath) {
|
|
157
|
+
if (!fs.existsSync(localFilePath)) {
|
|
158
|
+
throw new Error(`\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728: ${localFilePath}`);
|
|
159
|
+
}
|
|
160
|
+
const stat = fs.statSync(localFilePath);
|
|
161
|
+
if (!stat.isFile()) {
|
|
162
|
+
throw new Error(`\u6307\u5B9A\u7684\u8DEF\u5F84\u4E0D\u662F\u666E\u901A\u6587\u4EF6: ${localFilePath}`);
|
|
163
|
+
}
|
|
164
|
+
const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
|
|
165
|
+
const ext = path.extname(localFilePath) || ".mp4";
|
|
166
|
+
const uniqueId = crypto.randomUUID();
|
|
167
|
+
const objectKey = `temp/mcp/${dateStr}/${uniqueId}${ext}`;
|
|
168
|
+
const uploadInfo = await this.request("/api/upload/url", {
|
|
169
|
+
method: "POST",
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
key: objectKey,
|
|
172
|
+
contentType: "application/octet-stream",
|
|
173
|
+
expireSeconds: 3600
|
|
174
|
+
})
|
|
175
|
+
});
|
|
176
|
+
if (!uploadInfo?.url) {
|
|
177
|
+
throw new Error("\u83B7\u53D6\u5BF9\u8C61\u5B58\u50A8\u9884\u7B7E\u540D\u4E0A\u4F20 URL \u5931\u8D25");
|
|
178
|
+
}
|
|
179
|
+
const fileStream = Readable.toWeb(fs.createReadStream(localFilePath));
|
|
180
|
+
const putRes = await fetch(uploadInfo.url, {
|
|
181
|
+
method: uploadInfo.method || "PUT",
|
|
182
|
+
headers: {
|
|
183
|
+
"Content-Type": "application/octet-stream",
|
|
184
|
+
"Content-Length": stat.size.toString()
|
|
185
|
+
},
|
|
186
|
+
body: fileStream,
|
|
187
|
+
duplex: "half"
|
|
188
|
+
});
|
|
189
|
+
if (!putRes.ok) {
|
|
190
|
+
throw new Error(`\u672C\u5730\u6587\u4EF6\u76F4\u4F20\u5B58\u50A8\u5931\u8D25: ${putRes.status} ${putRes.statusText}`);
|
|
191
|
+
}
|
|
192
|
+
return `${this.ossPublicBase}/${objectKey}`;
|
|
193
|
+
}
|
|
194
|
+
// ==========================================
|
|
195
|
+
// 多媒体域 Tools
|
|
196
|
+
// ==========================================
|
|
197
|
+
async resolveVideo(params) {
|
|
198
|
+
const rawUrl = params.url.trim();
|
|
199
|
+
if (!rawUrl) {
|
|
200
|
+
throw new Error("\u8BF7\u63D0\u4F9B\u9700\u8981\u89E3\u6790\u7684\u89C6\u9891\u5206\u4EAB\u94FE\u63A5\u6216\u5305\u542B\u94FE\u63A5\u7684\u6587\u6848");
|
|
201
|
+
}
|
|
202
|
+
const batchRes = await this.request("/api/task/remove-watermark", {
|
|
203
|
+
method: "POST",
|
|
204
|
+
body: JSON.stringify({
|
|
205
|
+
title: "MCP\u89C6\u9891\u53BB\u6C34\u5370\u89E3\u6790",
|
|
206
|
+
links: [rawUrl],
|
|
207
|
+
enqueue: true
|
|
208
|
+
})
|
|
209
|
+
});
|
|
210
|
+
const task = batchRes?.tasks?.[0];
|
|
211
|
+
if (!task?.task_id) {
|
|
212
|
+
throw new Error("\u521B\u5EFA\u53BB\u6C34\u5370\u89E3\u6790\u4EFB\u52A1\u5931\u8D25\uFF0C\u672A\u8FD4\u56DE task_id");
|
|
213
|
+
}
|
|
214
|
+
const maxAttempts = 40;
|
|
215
|
+
const intervalMs = 1e3;
|
|
216
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
217
|
+
await sleep(intervalMs);
|
|
218
|
+
const taskInfo = await this.request(`/api/v2/task/info?task_id=${encodeURIComponent(task.task_id)}`, {
|
|
219
|
+
method: "GET"
|
|
220
|
+
});
|
|
221
|
+
console.error(
|
|
222
|
+
`[DataClaw] \u4EFB\u52A1 ${task.task_id} \u8F6E\u8BE2\u72B6\u6001: ${taskInfo.status} (${attempt + 1}/${maxAttempts})`
|
|
223
|
+
);
|
|
224
|
+
const isCompleted = taskInfo.status === "completed" || taskInfo.status === "success" || taskInfo.status === "partial_completed";
|
|
225
|
+
if (isCompleted) {
|
|
226
|
+
const tr = taskInfo.task_result || {};
|
|
227
|
+
const meta = tr.metadata || tr;
|
|
228
|
+
const video = tr.video || meta.video || {};
|
|
229
|
+
const rawStreams = video.streams || [];
|
|
230
|
+
const streams = rawStreams.map((s) => {
|
|
231
|
+
const sizeNum = typeof s.size === "number" ? s.size : void 0;
|
|
232
|
+
return {
|
|
233
|
+
quality: s.quality || "default",
|
|
234
|
+
type: s.type || "video",
|
|
235
|
+
size: sizeNum,
|
|
236
|
+
size_formatted: sizeNum ? formatBytes(sizeNum) : void 0,
|
|
237
|
+
url: s.url || "",
|
|
238
|
+
proxy_url: s.proxy_url || ""
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
const availableResolutions = streams.filter((s) => s.type === "video" || !s.type).map((s) => `${s.quality}${s.size_formatted ? ` (${s.size_formatted})` : ""}`);
|
|
242
|
+
const playUrl = video.play_url || streams.find((s) => s.type === "video" && s.url)?.url || video.play_proxy_url || "";
|
|
243
|
+
const proxyUrl = video.play_proxy_url || streams.find((s) => s.type === "video" && s.proxy_url)?.proxy_url || "";
|
|
244
|
+
const durationSeconds = video.duration || ("duration" in meta && typeof meta.duration === "number" ? meta.duration : 0);
|
|
245
|
+
const durationFormatted = durationSeconds > 0 ? `${Math.floor(durationSeconds / 60)}\u5206${durationSeconds % 60}\u79D2` : void 0;
|
|
246
|
+
const coverUrl = tr.cover_url || meta.cover_url || "";
|
|
247
|
+
const images = tr.images || tr.proxy_images || meta.images || [];
|
|
248
|
+
return {
|
|
249
|
+
platform: taskInfo.task_params?.platform || "auto",
|
|
250
|
+
title: tr.title || meta.title || taskInfo.title || "",
|
|
251
|
+
author: tr.author || meta.author || "",
|
|
252
|
+
cover_url: coverUrl,
|
|
253
|
+
duration: durationSeconds,
|
|
254
|
+
duration_formatted: durationFormatted,
|
|
255
|
+
video_play_url: playUrl,
|
|
256
|
+
video_download_proxy_url: proxyUrl,
|
|
257
|
+
available_resolutions: availableResolutions,
|
|
258
|
+
streams,
|
|
259
|
+
images,
|
|
260
|
+
content: tr.content || "",
|
|
261
|
+
statistics: tr.statistics || meta.statistics || {},
|
|
262
|
+
task_id: task.task_id
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (taskInfo.status === "failed") {
|
|
266
|
+
const reason = taskInfo.error_message || taskInfo.error || "\u672A\u77E5\u89E3\u6790\u9519\u8BEF";
|
|
267
|
+
throw new Error(`\u89C6\u9891\u89E3\u6790\u4EFB\u52A1\u5931\u8D25: ${reason}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
throw new Error("\u89C6\u9891\u53BB\u6C34\u5370\u89E3\u6790\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5");
|
|
271
|
+
}
|
|
272
|
+
async fetchSubtitleFromOss(r2Key) {
|
|
273
|
+
const key = r2Key.replace(/^\//, "");
|
|
274
|
+
const url = /^https?:\/\//i.test(key) ? key : `${this.ossPublicBase}/${key}`;
|
|
275
|
+
try {
|
|
276
|
+
const res = await fetch(url, { cache: "no-store" });
|
|
277
|
+
if (!res.ok) return null;
|
|
278
|
+
const data = await res.json();
|
|
279
|
+
return data;
|
|
280
|
+
} catch {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async transcribeAudio(params) {
|
|
285
|
+
const rawUrl = params.local_file_path ? await this.uploadLocalFileToR2(params.local_file_path) : (params.media_url || "").trim();
|
|
286
|
+
if (!rawUrl) {
|
|
287
|
+
throw new Error("\u5FC5\u987B\u63D0\u4F9B media_url \u6216 local_file_path \u4E4B\u4E00");
|
|
288
|
+
}
|
|
289
|
+
const isFinder = /channels\.weixin\.qq\.com|weixin\.qq\.com\/sph\/|finder\.video\.qq\.com/i.test(rawUrl);
|
|
290
|
+
let taskId = "";
|
|
291
|
+
if (params.local_file_path) {
|
|
292
|
+
const fileName = path.basename(params.local_file_path);
|
|
293
|
+
const batchRes = await this.request("/api/task/create/batch", {
|
|
294
|
+
method: "POST",
|
|
295
|
+
body: JSON.stringify({
|
|
296
|
+
title: `\u672C\u5730\u6587\u4EF6\u8F6C\u6587\u672C-${fileName}`,
|
|
297
|
+
task_type: "local_media_transcribe",
|
|
298
|
+
links: [rawUrl],
|
|
299
|
+
task_params: {
|
|
300
|
+
platform: "local",
|
|
301
|
+
options: {
|
|
302
|
+
original_name: fileName
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
enqueue: true
|
|
306
|
+
})
|
|
307
|
+
});
|
|
308
|
+
taskId = batchRes?.tasks?.[0]?.task_id || "";
|
|
309
|
+
} else if (isFinder) {
|
|
310
|
+
const batchRes = await this.request("/api/task/create/batch", {
|
|
311
|
+
method: "POST",
|
|
312
|
+
body: JSON.stringify({
|
|
313
|
+
title: "MCP\u89C6\u9891\u53F7\u8F6C\u6587\u672C",
|
|
314
|
+
task_type: "finder_link_to_text",
|
|
315
|
+
links: [rawUrl],
|
|
316
|
+
task_params: { platform: "finder" },
|
|
317
|
+
enqueue: true
|
|
318
|
+
})
|
|
319
|
+
});
|
|
320
|
+
taskId = batchRes?.tasks?.[0]?.task_id || "";
|
|
321
|
+
} else {
|
|
322
|
+
const batchRes = await this.request("/api/task/link-to-text", {
|
|
323
|
+
method: "POST",
|
|
324
|
+
body: JSON.stringify({
|
|
325
|
+
title: "MCP\u94FE\u63A5\u8F6C\u6587\u672C",
|
|
326
|
+
links: [rawUrl],
|
|
327
|
+
enqueue: true
|
|
328
|
+
})
|
|
329
|
+
});
|
|
330
|
+
taskId = batchRes?.tasks?.[0]?.task_id || "";
|
|
331
|
+
}
|
|
332
|
+
if (!taskId) {
|
|
333
|
+
throw new Error("\u521B\u5EFA\u8F6C\u6587\u6848\u4EFB\u52A1\u5931\u8D25\uFF0C\u672A\u8FD4\u56DE task_id");
|
|
334
|
+
}
|
|
335
|
+
const maxAttempts = params.local_file_path ? 1800 : 60;
|
|
336
|
+
const intervalMs = params.local_file_path ? 2e3 : 1e3;
|
|
337
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
338
|
+
await sleep(intervalMs);
|
|
339
|
+
const taskInfo = await this.request(`/api/v2/task/info?task_id=${encodeURIComponent(taskId)}`, {
|
|
340
|
+
method: "GET"
|
|
341
|
+
});
|
|
342
|
+
console.error(
|
|
343
|
+
`[DataClaw] \u8F6C\u6587\u6848\u4EFB\u52A1 ${taskId} \u8F6E\u8BE2\u72B6\u6001: ${taskInfo.status} (${attempt + 1}/${maxAttempts})`
|
|
344
|
+
);
|
|
345
|
+
const isCompleted = taskInfo.status === "completed" || taskInfo.status === "success" || taskInfo.status === "partial_completed";
|
|
346
|
+
if (isCompleted) {
|
|
347
|
+
const tr = taskInfo.task_result || {};
|
|
348
|
+
const meta = tr.metadata || {};
|
|
349
|
+
const video = tr.video || meta.video || {};
|
|
350
|
+
const subtitle = video.subtitle || {};
|
|
351
|
+
let text = subtitle.text || "";
|
|
352
|
+
let segments = subtitle.segments || [];
|
|
353
|
+
if ((!text || segments.length === 0) && subtitle.r2_key) {
|
|
354
|
+
const ossData = await this.fetchSubtitleFromOss(subtitle.r2_key);
|
|
355
|
+
if (ossData) {
|
|
356
|
+
text = text || ossData.text || "";
|
|
357
|
+
segments = segments.length > 0 ? segments : ossData.segments || [];
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (!text) {
|
|
361
|
+
text = tr.content || tr.desc || "";
|
|
362
|
+
}
|
|
363
|
+
const rawStreams = video.streams || [];
|
|
364
|
+
const streams = rawStreams.map((s) => {
|
|
365
|
+
const sizeNum = typeof s.size === "number" ? s.size : void 0;
|
|
366
|
+
return {
|
|
367
|
+
quality: s.quality || "default",
|
|
368
|
+
type: s.type || "video",
|
|
369
|
+
size: sizeNum,
|
|
370
|
+
size_formatted: sizeNum ? formatBytes(sizeNum) : void 0,
|
|
371
|
+
url: s.url || "",
|
|
372
|
+
proxy_url: s.proxy_url || ""
|
|
373
|
+
};
|
|
374
|
+
});
|
|
375
|
+
const availableResolutions = streams.filter((s) => s.type === "video" || !s.type).map((s) => `${s.quality}${s.size_formatted ? ` (${s.size_formatted})` : ""}`);
|
|
376
|
+
const playUrl = video.play_url || streams.find((s) => s.type === "video" && s.url)?.url || video.play_proxy_url || "";
|
|
377
|
+
const proxyUrl = video.play_proxy_url || streams.find((s) => s.type === "video" && s.proxy_url)?.proxy_url || "";
|
|
378
|
+
const durationSeconds = video.duration || meta.duration || 0;
|
|
379
|
+
const durationFormatted = durationSeconds > 0 ? `${Math.floor(durationSeconds / 60)}\u5206${durationSeconds % 60}\u79D2` : void 0;
|
|
380
|
+
const coverUrl = tr.cover_url || meta.cover_url || "";
|
|
381
|
+
const title = tr.title || meta.title || taskInfo.title || "";
|
|
382
|
+
const author = tr.author || meta.author || "";
|
|
383
|
+
const srt = formatSegmentsToSrt(segments);
|
|
384
|
+
if (params.output_format === "srt") {
|
|
385
|
+
return {
|
|
386
|
+
title,
|
|
387
|
+
author,
|
|
388
|
+
cover_url: coverUrl,
|
|
389
|
+
duration: durationSeconds,
|
|
390
|
+
duration_formatted: durationFormatted,
|
|
391
|
+
srt: srt || text,
|
|
392
|
+
video_play_url: playUrl,
|
|
393
|
+
video_download_proxy_url: proxyUrl,
|
|
394
|
+
available_resolutions: availableResolutions,
|
|
395
|
+
streams,
|
|
396
|
+
task_id: taskId
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
if (params.output_format === "verbose_json") {
|
|
400
|
+
return {
|
|
401
|
+
title,
|
|
402
|
+
author,
|
|
403
|
+
cover_url: coverUrl,
|
|
404
|
+
duration: durationSeconds,
|
|
405
|
+
duration_formatted: durationFormatted,
|
|
406
|
+
text,
|
|
407
|
+
srt,
|
|
408
|
+
segments,
|
|
409
|
+
video_play_url: playUrl,
|
|
410
|
+
video_download_proxy_url: proxyUrl,
|
|
411
|
+
available_resolutions: availableResolutions,
|
|
412
|
+
streams,
|
|
413
|
+
statistics: tr.statistics || meta.statistics || {},
|
|
414
|
+
task_id: taskId
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
title,
|
|
419
|
+
author,
|
|
420
|
+
cover_url: coverUrl,
|
|
421
|
+
duration: durationSeconds,
|
|
422
|
+
duration_formatted: durationFormatted,
|
|
423
|
+
text: text || "\uFF08\u672A\u68C0\u6D4B\u5230\u53E3\u64AD\u8BED\u97F3\uFF09",
|
|
424
|
+
video_play_url: playUrl,
|
|
425
|
+
video_download_proxy_url: proxyUrl,
|
|
426
|
+
available_resolutions: availableResolutions,
|
|
427
|
+
streams,
|
|
428
|
+
statistics: tr.statistics || meta.statistics || {},
|
|
429
|
+
task_id: taskId
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
if (taskInfo.status === "failed") {
|
|
433
|
+
const reason = taskInfo.error_message || taskInfo.error || "\u672A\u77E5\u8F6C\u5199\u9519\u8BEF";
|
|
434
|
+
throw new Error(`\u89C6\u9891\u8F6C\u6587\u6848\u4EFB\u52A1\u5931\u8D25: ${reason}`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
throw new Error("\u8F6C\u6587\u6848\u4EFB\u52A1\u5904\u7406\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u524D\u5F80 DataClaw \u7F51\u9875\u7AEF\u67E5\u770B\u8BE6\u60C5");
|
|
438
|
+
}
|
|
439
|
+
// ==========================================
|
|
440
|
+
// 抖音域 Tools
|
|
441
|
+
// ==========================================
|
|
442
|
+
async searchDyVideos(params) {
|
|
443
|
+
const body = {
|
|
444
|
+
keyword: params.keyword,
|
|
445
|
+
sort_type: DY_SEARCH_SORT[params.sort_type] ?? "0",
|
|
446
|
+
publish_time: params.publish_time ?? "0",
|
|
447
|
+
cursor: params.cursor ?? 0
|
|
448
|
+
};
|
|
449
|
+
if (params.search_id) body.search_id = params.search_id;
|
|
450
|
+
if (params.backtrace) body.backtrace = params.backtrace;
|
|
451
|
+
return this.request("/api/v2/dy/search/video", {
|
|
452
|
+
method: "POST",
|
|
453
|
+
body: JSON.stringify(body)
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
async getDyVideoDetail(params) {
|
|
457
|
+
return this.request("/api/v2/dy/detail", {
|
|
458
|
+
method: "POST",
|
|
459
|
+
body: JSON.stringify({ url: douyinVideoUrl(params) })
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
async getDyPlayStats(params) {
|
|
463
|
+
return this.request("/api/dy/video/play-stats", {
|
|
464
|
+
method: "POST",
|
|
465
|
+
body: JSON.stringify({ url: douyinVideoUrl(params) })
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
async getDyComments(params) {
|
|
469
|
+
const target = douyinCommentTarget(params);
|
|
470
|
+
return this.request("/api/v2/dy/video/comments", {
|
|
471
|
+
method: "POST",
|
|
472
|
+
body: JSON.stringify({
|
|
473
|
+
url: target.url,
|
|
474
|
+
...target.video_id ? { video_id: target.video_id } : {},
|
|
475
|
+
cursor: params.cursor ?? 0,
|
|
476
|
+
count: params.count ?? 50
|
|
477
|
+
})
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
async getDyUserProfile(params) {
|
|
481
|
+
return this.request("/api/v2/dy/user/detail", {
|
|
482
|
+
method: "POST",
|
|
483
|
+
body: JSON.stringify({
|
|
484
|
+
sec_user_id: params.sec_user_id,
|
|
485
|
+
url: params.url || params.profile_url
|
|
486
|
+
})
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
// ==========================================
|
|
490
|
+
// 视频号域 Tools
|
|
491
|
+
// ==========================================
|
|
492
|
+
async searchChannelsAuthors(params) {
|
|
493
|
+
const query = params.keyword.trim();
|
|
494
|
+
if (!query) throw new Error("\u8BF7\u63D0\u4F9B\u641C\u7D22\u5173\u952E\u8BCD");
|
|
495
|
+
return this.request("/api/v2/mp/finder/search-authors", {
|
|
496
|
+
method: "POST",
|
|
497
|
+
body: JSON.stringify({
|
|
498
|
+
query,
|
|
499
|
+
count: params.count ?? 20,
|
|
500
|
+
buffer: params.buffer ?? "",
|
|
501
|
+
scene: params.scene ?? 1
|
|
502
|
+
})
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
async getChannelsAuthorFeeds(params) {
|
|
506
|
+
const username = params.finder_username.trim();
|
|
507
|
+
if (!username) throw new Error("\u8BF7\u63D0\u4F9B finder_username");
|
|
508
|
+
return this.request("/api/v2/mp/finder/feeds", {
|
|
509
|
+
method: "POST",
|
|
510
|
+
body: JSON.stringify({
|
|
511
|
+
username,
|
|
512
|
+
buffer: params.last_buffer?.trim() ?? "",
|
|
513
|
+
count: 15,
|
|
514
|
+
scene: 0
|
|
515
|
+
})
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
async resolveChannelsShareUrl(params) {
|
|
519
|
+
return this.request("/api/v2/mp/finder/video-by-share-url", {
|
|
520
|
+
method: "POST",
|
|
521
|
+
body: JSON.stringify(params)
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
// src/types.ts
|
|
527
|
+
import { z } from "zod";
|
|
528
|
+
var VideoResolveSchema = z.object({
|
|
529
|
+
url: z.string().describe("\u6296\u97F3\u3001\u89C6\u9891\u53F7\u3001\u5C0F\u7EA2\u4E66\u3001\u5FEB\u624B\u3001B\u7AD9\u7B49\u5404\u5927\u5E73\u53F0\u7684\u5206\u4EAB\u6587\u6848\u6216\u94FE\u63A5\uFF08\u652F\u6301\u5B8C\u6574\u94FE\u63A5\u3001\u77ED\u94FE\u6216\u5305\u542B\u5206\u4EAB\u6587\u672C\u7684\u6574\u6BB5\u6587\u5B57\uFF09")
|
|
530
|
+
});
|
|
531
|
+
var AudioTranscribeSchema = z.object({
|
|
532
|
+
media_url: z.string().optional().describe("\u7F51\u7EDC\u97F3\u89C6\u9891\u76F4\u94FE URL \u6216\u77ED\u89C6\u9891\u5206\u4EAB\u6587\u6848/\u94FE\u63A5\uFF08\u652F\u6301\u666E\u901A\u77ED\u89C6\u9891\u4E0E\u5FAE\u4FE1\u89C6\u9891\u53F7\uFF0C\u4E0E local_file_path \u4E8C\u9009\u4E00\uFF09"),
|
|
533
|
+
local_file_path: z.string().optional().describe("\u672C\u5730\u97F3\u89C6\u9891\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u4E0E media_url \u4E8C\u9009\u4E00\uFF1B\u4F1A\u5148\u4E0A\u4F20\u5230\u5BF9\u8C61\u5B58\u50A8\uFF0C\u518D\u521B\u5EFA\u5F02\u6B65\u8F6C\u5199\u4EFB\u52A1\uFF09"),
|
|
534
|
+
output_format: z.enum(["text", "srt", "verbose_json"]).default("text").describe("\u8FD4\u56DE\u683C\u5F0F\uFF1A\u7EAF\u6587\u672C\u3001SRT\u5B57\u5E55\u3001\u6216\u5E26\u65F6\u95F4\u6233\u7684\u6BB5\u843D\u8BE6\u60C5")
|
|
535
|
+
});
|
|
536
|
+
var DySearchVideosSchema = z.object({
|
|
537
|
+
keyword: z.string().describe("\u641C\u7D22\u5173\u952E\u8BCD"),
|
|
538
|
+
sort_type: z.enum(["general", "most_recent", "most_liked"]).default("general").describe("\u6392\u5E8F\uFF1A\u7EFC\u5408(general\u21920)\u3001\u6700\u591A\u70B9\u8D5E(most_liked\u21921)\u3001\u6700\u65B0(most_recent\u21922)"),
|
|
539
|
+
publish_time: z.enum(["0", "1", "7", "180"]).default("0").describe("\u53D1\u5E03\u65F6\u95F4\uFF1A0 \u4E0D\u9650\uFF0C1 \u6700\u8FD1\u4E00\u5929\uFF0C7 \u6700\u8FD1\u4E00\u5468\uFF0C180 \u6700\u8FD1\u534A\u5E74"),
|
|
540
|
+
count: z.number().min(1).max(20).default(10).describe("\u517C\u5BB9\u5B57\u6BB5\u3002\u4E0A\u6E38\u9875\u5927\u5C0F\u56FA\u5B9A\uFF0C\u8C03\u7528\u65F6\u5FFD\u7565"),
|
|
541
|
+
cursor: z.number().optional().describe("\u5206\u9875\u6E38\u6807\uFF0C\u9996\u9875\u4E0D\u4F20\u6216\u4F20 0\uFF0C\u4E0B\u4E00\u9875\u4F7F\u7528\u4E0A\u6B21\u8FD4\u56DE\u7684 cursor"),
|
|
542
|
+
search_id: z.string().optional().describe("\u7FFB\u9875\u65F6\u5E26\u56DE\u4E0A\u6B21\u8FD4\u56DE\u7684 search_id"),
|
|
543
|
+
backtrace: z.string().optional().describe("\u7FFB\u9875\u65F6\u5E26\u56DE\u4E0A\u6B21\u8FD4\u56DE\u7684 backtrace")
|
|
544
|
+
});
|
|
545
|
+
var DyGetVideoDetailSchema = z.object({
|
|
546
|
+
url: z.string().optional().describe("\u6296\u97F3\u89C6\u9891\u94FE\u63A5\u6216\u5206\u4EAB\u6587\u6848\u3002\u8BF7\u6C42\u4F53\u5B57\u6BB5\u5C31\u662F url\uFF0C\u4F8B\u5982 https://www.douyin.com/video/ID \u6216 https://www.douyin.com/jingxuan?modal_id=ID"),
|
|
547
|
+
aweme_id: z.string().optional().describe("\u6296\u97F3\u89C6\u9891 ID\u3002\u672A\u4F20 url \u65F6\u8F6C\u6210 https://www.douyin.com/video/{aweme_id}")
|
|
548
|
+
});
|
|
549
|
+
var DyGetPlayStatsSchema = z.object({
|
|
550
|
+
url: z.string().optional().describe("\u6296\u97F3\u89C6\u9891\u94FE\u63A5\u6216\u5206\u4EAB\u6587\u6848\u3002\u8BF7\u6C42\u4F53\u5B57\u6BB5\u5C31\u662F url"),
|
|
551
|
+
aweme_id: z.string().optional().describe("\u6296\u97F3\u89C6\u9891 ID\u3002\u672A\u4F20 url \u65F6\u8F6C\u6210\u89C6\u9891\u957F\u94FE")
|
|
552
|
+
});
|
|
553
|
+
var DyGetCommentsSchema = z.object({
|
|
554
|
+
url: z.string().optional().describe("\u6296\u97F3\u89C6\u9891\u94FE\u63A5\u6216\u5206\u4EAB\u6587\u6848\u3002\u4F8B\u5982 https://www.douyin.com/video/ID \u6216 https://www.douyin.com/jingxuan?modal_id=ID"),
|
|
555
|
+
aweme_id: z.string().optional().describe("\u6296\u97F3\u89C6\u9891 ID\u3002\u672A\u4F20 url \u65F6\u4F7F\u7528\uFF0C\u4E0D\u8981\u628A\u6574\u6BB5\u94FE\u63A5\u586B\u5728\u8FD9\u91CC"),
|
|
556
|
+
cursor: z.number().default(0).describe("\u5206\u9875\u6E38\u6807\uFF0C\u7B2C\u4E00\u9875\u4F20 0"),
|
|
557
|
+
count: z.number().min(1).max(50).default(50).describe("\u6BCF\u9875\u8BC4\u8BBA\u6570\uFF0C\u9ED8\u8BA4 50\uFF0C\u6700\u5927 50")
|
|
558
|
+
});
|
|
559
|
+
var DyGetUserProfileSchema = z.object({
|
|
560
|
+
sec_user_id: z.string().optional().describe("\u535A\u4E3B sec_user_id\uFF08\u4E0E url \u4E8C\u9009\u4E00\uFF09"),
|
|
561
|
+
url: z.string().optional().describe("\u535A\u4E3B\u4E3B\u9875\u94FE\u63A5\u3001\u5206\u4EAB\u77ED\u94FE\u6216\u5206\u4EAB\u6587\u6848\uFF08\u4E0E sec_user_id \u4E8C\u9009\u4E00\uFF09"),
|
|
562
|
+
profile_url: z.string().optional().describe("\uFF08\u522B\u540D\u517C\u5BB9\uFF09\u535A\u4E3B\u4E3B\u9875\u94FE\u63A5")
|
|
563
|
+
});
|
|
564
|
+
var ChannelsSearchAuthorsSchema = z.object({
|
|
565
|
+
keyword: z.string().describe("\u521B\u4F5C\u8005\u5173\u952E\u8BCD\u6216\u535A\u4E3B\u6635\u79F0"),
|
|
566
|
+
count: z.number().int().min(1).max(50).default(20).describe("\u6BCF\u9875\u4F5C\u8005\u6570\u91CF\uFF0C\u9ED8\u8BA4 20"),
|
|
567
|
+
buffer: z.string().default("").describe("\u5206\u9875\u6E38\u6807\uFF0C\u9996\u9875\u4E3A\u7A7A\uFF0C\u4E0B\u4E00\u9875\u4F7F\u7528\u4E0A\u6B21\u8FD4\u56DE\u7684 buffer"),
|
|
568
|
+
scene: z.number().int().default(1).describe("\u641C\u7D22\u573A\u666F\uFF0C\u9ED8\u8BA4 1")
|
|
569
|
+
});
|
|
570
|
+
var ChannelsGetAuthorFeedsSchema = z.object({
|
|
571
|
+
finder_username: z.string().describe("\u89C6\u9891\u53F7\u4F5C\u8005\u552F\u4E00\u6807\u8BC6 finder_username"),
|
|
572
|
+
last_buffer: z.string().optional().describe("\u7FFB\u9875 buffer\uFF08\u9996\u9875\u65E0\u9700\u4F20\uFF09")
|
|
573
|
+
});
|
|
574
|
+
var ChannelsResolveShareUrlSchema = z.object({
|
|
575
|
+
share_url: z.string().describe("\u5FAE\u4FE1\u89C6\u9891\u53F7\u5206\u4EAB\u94FE\u63A5\uFF0C\u4F8B\u5982\u5305\u542B finder.video.qq.com \u6216\u77ED\u94FE\u63A5")
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
// src/mcp/server.ts
|
|
579
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
580
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
581
|
+
|
|
582
|
+
// src/mcp/tools/media.ts
|
|
583
|
+
function registerMediaTools(server, client) {
|
|
584
|
+
server.registerTool(
|
|
585
|
+
"dataclaw_video_resolve",
|
|
586
|
+
{
|
|
587
|
+
description: "\u4F20\u5165\u6296\u97F3\u3001\u89C6\u9891\u53F7\u3001\u5C0F\u7EA2\u4E66\u3001\u5FEB\u624B\u3001B\u7AD9\u7B49\u5404\u5927\u5E73\u53F0\u7684\u5206\u4EAB\u6587\u6848\u6216\u94FE\u63A5\uFF0C\u81EA\u52A8\u8BC6\u522B\u5E73\u53F0\u53BB\u6C34\u5370\u89E3\u6790\uFF0C\u63D0\u53D6\u65E0\u6C34\u5370\u9AD8\u6E05\u89C6\u9891\u64AD\u653E\u76F4\u94FE\u3001\u5C01\u9762\u56FE\u3001\u6807\u9898\u3001\u4F5C\u8005\u53CA\u65F6\u957F\u6570\u636E\uFF08\u5BF9\u5E94 /tools/material/remove-watermark \u9875\u9762\uFF09",
|
|
588
|
+
inputSchema: VideoResolveSchema.shape
|
|
589
|
+
},
|
|
590
|
+
async (args) => {
|
|
591
|
+
try {
|
|
592
|
+
const result = await client.resolveVideo(args);
|
|
593
|
+
return {
|
|
594
|
+
content: [
|
|
595
|
+
{
|
|
596
|
+
type: "text",
|
|
597
|
+
text: JSON.stringify(result, null, 2)
|
|
598
|
+
}
|
|
599
|
+
]
|
|
600
|
+
};
|
|
601
|
+
} catch (err) {
|
|
602
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
603
|
+
return {
|
|
604
|
+
isError: true,
|
|
605
|
+
content: [{ type: "text", text: `\u89C6\u9891\u89E3\u6790\u5931\u8D25: ${message}` }]
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
);
|
|
610
|
+
server.registerTool(
|
|
611
|
+
"dataclaw_audio_transcribe",
|
|
612
|
+
{
|
|
613
|
+
description: "\u4F20\u5165\u77ED\u89C6\u9891\u5206\u4EAB\u6587\u6848/\u94FE\u63A5\uFF08\u81EA\u52A8\u8BC6\u522B\u6296\u97F3\u3001\u5C0F\u7EA2\u4E66\u3001\u5FEB\u624B\u7B49\u666E\u901A\u89C6\u9891\u4E0E\u5FAE\u4FE1\u89C6\u9891\u53F7\u5E76\u81EA\u52A8\u89E3\u5BC6\u8F6C\u5199\uFF0C\u5BF9\u5E94 /tools/copy/extract \u548C /tools/copy/extract-finder\uFF09\uFF0C\u6216\u672C\u5730\u97F3\u89C6\u9891\u6587\u4EF6\uFF08\u5148\u76F4\u4F20\u5BF9\u8C61\u5B58\u50A8\uFF0C\u518D\u521B\u5EFA\u5F02\u6B65\u8F6C\u5199\u4EFB\u52A1\uFF09\uFF0C\u8F6C\u5199\u4E3A\u7EAF\u6587\u672C\u3001SRT\u5B57\u5E55\u6216\u5E26\u65F6\u95F4\u6233\u6BB5\u843D\u8BE6\u60C5",
|
|
614
|
+
inputSchema: AudioTranscribeSchema.shape
|
|
615
|
+
},
|
|
616
|
+
async (args) => {
|
|
617
|
+
try {
|
|
618
|
+
const result = await client.transcribeAudio(args);
|
|
619
|
+
return {
|
|
620
|
+
content: [
|
|
621
|
+
{
|
|
622
|
+
type: "text",
|
|
623
|
+
text: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
624
|
+
}
|
|
625
|
+
]
|
|
626
|
+
};
|
|
627
|
+
} catch (err) {
|
|
628
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
629
|
+
return {
|
|
630
|
+
isError: true,
|
|
631
|
+
content: [{ type: "text", text: `\u97F3\u9891\u8F6C\u5199\u5931\u8D25: ${message}` }]
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/mcp/tools/douyin.ts
|
|
639
|
+
function registerDouyinTools(server, client) {
|
|
640
|
+
server.registerTool(
|
|
641
|
+
"dataclaw_dy_search_videos",
|
|
642
|
+
{
|
|
643
|
+
description: "\u5173\u952E\u8BCD\u641C\u7D22\u6296\u97F3\u70ED\u95E8\u89C6\u9891\uFF0C\u652F\u6301\u6309\u7EFC\u5408\u3001\u6700\u65B0\u3001\u6700\u591A\u70B9\u8D5E\u6392\u5E8F\u53CA\u53D1\u5E03\u65F6\u95F4\u7B5B\u9009\uFF0C\u8FD4\u56DE\u5305\u542B\u70B9\u8D5E\u3001\u64AD\u653E\u3001\u6807\u9898\u548C\u4F5C\u8005\u7684\u4F5C\u54C1\u5217\u8868",
|
|
644
|
+
inputSchema: DySearchVideosSchema.shape
|
|
645
|
+
},
|
|
646
|
+
async (args) => {
|
|
647
|
+
try {
|
|
648
|
+
const result = await client.searchDyVideos(args);
|
|
649
|
+
return {
|
|
650
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
651
|
+
};
|
|
652
|
+
} catch (err) {
|
|
653
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
654
|
+
return {
|
|
655
|
+
isError: true,
|
|
656
|
+
content: [{ type: "text", text: `\u6296\u97F3\u89C6\u9891\u641C\u7D22\u5931\u8D25: ${message}` }]
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
);
|
|
661
|
+
server.registerTool(
|
|
662
|
+
"dataclaw_dy_get_video_detail",
|
|
663
|
+
{
|
|
664
|
+
description: "\u83B7\u53D6\u6307\u5B9A\u6296\u97F3\u89C6\u9891\u8BE6\u60C5\uFF1A\u6807\u9898\u3001\u4F5C\u8005\u3001\u5C01\u9762\u3001\u64AD\u653E\u5730\u5740\uFF0C\u4EE5\u53CA\u70B9\u8D5E\u3001\u8BC4\u8BBA\u3001\u5206\u4EAB\u3001\u6536\u85CF\u6570\u3002\u4E0D\u542B\u64AD\u653E\u91CF\uFF0C\u4E5F\u4E0D\u542B\u79D2\u7EA7\u4E92\u52A8\u8D8B\u52BF\u3002\u53EA\u4F20 url",
|
|
665
|
+
inputSchema: DyGetVideoDetailSchema.shape
|
|
666
|
+
},
|
|
667
|
+
async (args) => {
|
|
668
|
+
try {
|
|
669
|
+
const result = await client.getDyVideoDetail(args);
|
|
670
|
+
return {
|
|
671
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
672
|
+
};
|
|
673
|
+
} catch (err) {
|
|
674
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
675
|
+
return {
|
|
676
|
+
isError: true,
|
|
677
|
+
content: [{ type: "text", text: `\u83B7\u53D6\u6296\u97F3\u89C6\u9891\u8BE6\u60C5\u5931\u8D25: ${message}` }]
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
);
|
|
682
|
+
server.registerTool(
|
|
683
|
+
"dataclaw_dy_get_play_stats",
|
|
684
|
+
{
|
|
685
|
+
description: "\u67E5\u8BE2\u6296\u97F3\u89C6\u9891\u64AD\u653E\u91CF\u3001\u5B8C\u64AD\u7387\u7B49\u661F\u56FE\u7EDF\u8BA1\u3002\u8BE6\u60C5\u63A5\u53E3\u4E0D\u542B\u64AD\u653E\u91CF\uFF0C\u5FC5\u987B\u5355\u72EC\u8C03\u7528\u672C\u5DE5\u5177\u3002\u53EA\u4F20 url\uFF0C\u6216 aweme_id\uFF08\u4F1A\u8F6C\u6210 url\uFF09",
|
|
686
|
+
inputSchema: DyGetPlayStatsSchema.shape
|
|
687
|
+
},
|
|
688
|
+
async (args) => {
|
|
689
|
+
try {
|
|
690
|
+
const result = await client.getDyPlayStats(args);
|
|
691
|
+
return {
|
|
692
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
693
|
+
};
|
|
694
|
+
} catch (err) {
|
|
695
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
696
|
+
return {
|
|
697
|
+
isError: true,
|
|
698
|
+
content: [{ type: "text", text: `\u83B7\u53D6\u6296\u97F3\u64AD\u653E\u91CF\u5931\u8D25: ${message}` }]
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
);
|
|
703
|
+
server.registerTool(
|
|
704
|
+
"dataclaw_dy_get_comments",
|
|
705
|
+
{
|
|
706
|
+
description: "\u83B7\u53D6\u6307\u5B9A\u6296\u97F3\u89C6\u9891\u7684\u4E00\u7EA7\u8BC4\u8BBA\uFF08\u542B\u7F6E\u9876\u3001\u70B9\u8D5E\u6570\u3001\u56DE\u590D\u6570\uFF09\u3002\u4F20 url \u6216 aweme_id\uFF0C\u4E0D\u8981\u628A\u6574\u6BB5\u94FE\u63A5\u586B\u8FDB aweme_id",
|
|
707
|
+
inputSchema: DyGetCommentsSchema.shape
|
|
708
|
+
},
|
|
709
|
+
async (args) => {
|
|
710
|
+
try {
|
|
711
|
+
const result = await client.getDyComments(args);
|
|
712
|
+
return {
|
|
713
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
714
|
+
};
|
|
715
|
+
} catch (err) {
|
|
716
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
717
|
+
return {
|
|
718
|
+
isError: true,
|
|
719
|
+
content: [{ type: "text", text: `\u83B7\u53D6\u6296\u97F3\u8BC4\u8BBA\u5931\u8D25: ${message}` }]
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
);
|
|
724
|
+
server.registerTool(
|
|
725
|
+
"dataclaw_dy_get_user_profile",
|
|
726
|
+
{
|
|
727
|
+
description: "\u83B7\u53D6\u6296\u97F3\u535A\u4E3B\u4E3B\u9875\u8D44\u6599\uFF1A\u6635\u79F0\u3001\u7C89\u4E1D\u6570\u3001\u4F5C\u54C1\u6570\u3001\u7B80\u4ECB\u3002\u4E0D\u542B\u7C89\u4E1D\u753B\u50CF\u548C\u5386\u53F2\u4F5C\u54C1\u5217\u8868",
|
|
728
|
+
inputSchema: DyGetUserProfileSchema.shape
|
|
729
|
+
},
|
|
730
|
+
async (args) => {
|
|
731
|
+
try {
|
|
732
|
+
const result = await client.getDyUserProfile(args);
|
|
733
|
+
return {
|
|
734
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
735
|
+
};
|
|
736
|
+
} catch (err) {
|
|
737
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
738
|
+
return {
|
|
739
|
+
isError: true,
|
|
740
|
+
content: [{ type: "text", text: `\u83B7\u53D6\u6296\u97F3\u535A\u4E3B\u4FE1\u606F\u5931\u8D25: ${message}` }]
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// src/mcp/tools/channels.ts
|
|
748
|
+
function registerChannelsTools(server, client) {
|
|
749
|
+
server.registerTool(
|
|
750
|
+
"dataclaw_channels_search_authors",
|
|
751
|
+
{
|
|
752
|
+
description: "\u5173\u952E\u8BCD\u641C\u7D22\u5FAE\u4FE1\u89C6\u9891\u53F7\u521B\u4F5C\u8005/\u535A\u4E3B\uFF0C\u83B7\u53D6\u535A\u4E3B finder_username\u3001\u5934\u50CF\u53CA\u8BA4\u8BC1\u7B80\u4ECB",
|
|
753
|
+
inputSchema: ChannelsSearchAuthorsSchema.shape
|
|
754
|
+
},
|
|
755
|
+
async (args) => {
|
|
756
|
+
try {
|
|
757
|
+
const result = await client.searchChannelsAuthors(args);
|
|
758
|
+
return {
|
|
759
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
760
|
+
};
|
|
761
|
+
} catch (err) {
|
|
762
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
763
|
+
return {
|
|
764
|
+
isError: true,
|
|
765
|
+
content: [{ type: "text", text: `\u641C\u7D22\u89C6\u9891\u53F7\u521B\u4F5C\u8005\u5931\u8D25: ${message}` }]
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
);
|
|
770
|
+
server.registerTool(
|
|
771
|
+
"dataclaw_channels_get_author_feeds",
|
|
772
|
+
{
|
|
773
|
+
description: "\u6839\u636E\u4F5C\u8005 finder_username \u83B7\u53D6\u89C6\u9891\u53F7\u4F5C\u54C1 Feed\uFF0C\u6BCF\u9875 15 \u6761\u3002\u9996\u9875\u4E0D\u4F20 last_buffer\uFF0C\u4E0B\u4E00\u9875\u4F20\u4E0A\u6B21\u8FD4\u56DE\u7684 buffer",
|
|
774
|
+
inputSchema: ChannelsGetAuthorFeedsSchema.shape
|
|
775
|
+
},
|
|
776
|
+
async (args) => {
|
|
777
|
+
try {
|
|
778
|
+
const result = await client.getChannelsAuthorFeeds(args);
|
|
779
|
+
return {
|
|
780
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
781
|
+
};
|
|
782
|
+
} catch (err) {
|
|
783
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
784
|
+
return {
|
|
785
|
+
isError: true,
|
|
786
|
+
content: [{ type: "text", text: `\u83B7\u53D6\u89C6\u9891\u53F7\u4F5C\u54C1\u5217\u8868\u5931\u8D25: ${message}` }]
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
);
|
|
791
|
+
server.registerTool(
|
|
792
|
+
"dataclaw_channels_resolve_share_url",
|
|
793
|
+
{
|
|
794
|
+
description: "\u6839\u636E\u5FAE\u4FE1\u89C6\u9891\u53F7\u5206\u4EAB\u6587\u672C\u6216\u77ED\u94FE\u89E3\u6790\u4F5C\u54C1\u5168\u91CF\u6570\u636E\u3001\u4E92\u52A8\u6307\u6807\u53CA\u65E0\u6C34\u5370\u9AD8\u6E05\u89C6\u9891\u6E90",
|
|
795
|
+
inputSchema: ChannelsResolveShareUrlSchema.shape
|
|
796
|
+
},
|
|
797
|
+
async (args) => {
|
|
798
|
+
try {
|
|
799
|
+
const result = await client.resolveChannelsShareUrl(args);
|
|
800
|
+
return {
|
|
801
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
802
|
+
};
|
|
803
|
+
} catch (err) {
|
|
804
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
805
|
+
return {
|
|
806
|
+
isError: true,
|
|
807
|
+
content: [{ type: "text", text: `\u89E3\u6790\u89C6\u9891\u53F7\u5206\u4EAB\u94FE\u63A5\u5931\u8D25: ${message}` }]
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// src/mcp/server.ts
|
|
815
|
+
function createMcpServer(client = new DataClawClient()) {
|
|
816
|
+
const server = new McpServer({
|
|
817
|
+
name: "dataclaw-agent-kit",
|
|
818
|
+
version: "0.1.1"
|
|
819
|
+
});
|
|
820
|
+
registerMediaTools(server, client);
|
|
821
|
+
registerDouyinTools(server, client);
|
|
822
|
+
registerChannelsTools(server, client);
|
|
823
|
+
return server;
|
|
824
|
+
}
|
|
825
|
+
async function startMcpServer(client = new DataClawClient()) {
|
|
826
|
+
const server = createMcpServer(client);
|
|
827
|
+
const transport = new StdioServerTransport();
|
|
828
|
+
console.error("\u{1F99E} [DataClaw MCP Server] \u6B63\u5728\u542F\u52A8 (stdio \u4F20\u8F93\u534F\u8BAE)...");
|
|
829
|
+
if (!client.isConfigured) {
|
|
830
|
+
console.error(
|
|
831
|
+
"\u26A0\uFE0F [DataClaw] \u672A\u68C0\u6D4B\u5230 DATACLAW_API_KEY \u73AF\u5883\u53D8\u91CF\u3002\u8BF7\u786E\u4FDD\u5728 MCP Client \u914D\u7F6E\u4E2D\u6B63\u786E\u4F20\u9012\u4E86 env.DATACLAW_API_KEY\u3002"
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
await server.connect(transport);
|
|
835
|
+
console.error("\u{1F680} [DataClaw MCP Server] \u8FD0\u884C\u5C31\u7EEA\uFF0C\u5DF2\u6CE8\u518C 10 \u4E2A\u6807\u51C6\u5316 Tools\u3002");
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// src/cli/detect.ts
|
|
839
|
+
import fs2 from "fs";
|
|
840
|
+
import path2 from "path";
|
|
841
|
+
import os from "os";
|
|
842
|
+
function detectIdeEnvironments(targetDir = process.cwd()) {
|
|
843
|
+
const home = os.homedir();
|
|
844
|
+
const platform = process.platform;
|
|
845
|
+
const cursorLocal = path2.join(targetDir, ".cursor");
|
|
846
|
+
const cursorGlobal = path2.join(home, ".cursor");
|
|
847
|
+
const cursorDetected = fs2.existsSync(cursorLocal) || fs2.existsSync(cursorGlobal);
|
|
848
|
+
const cursorInfo = {
|
|
849
|
+
id: "cursor",
|
|
850
|
+
name: "Cursor (.cursor/rules + mcp.json)",
|
|
851
|
+
detected: cursorDetected,
|
|
852
|
+
configPath: path2.join(targetDir, ".cursor", "mcp.json"),
|
|
853
|
+
skillsDir: path2.join(targetDir, ".cursor", "rules")
|
|
854
|
+
};
|
|
855
|
+
let claudeDesktopConfigPath = "";
|
|
856
|
+
if (platform === "darwin") {
|
|
857
|
+
claudeDesktopConfigPath = path2.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
858
|
+
} else if (platform === "win32") {
|
|
859
|
+
const appData = process.env.APPDATA || path2.join(home, "AppData", "Roaming");
|
|
860
|
+
claudeDesktopConfigPath = path2.join(appData, "Claude", "claude_desktop_config.json");
|
|
861
|
+
} else {
|
|
862
|
+
claudeDesktopConfigPath = path2.join(home, ".config", "Claude", "claude_desktop_config.json");
|
|
863
|
+
}
|
|
864
|
+
const claudeDesktopDetected = fs2.existsSync(path2.dirname(claudeDesktopConfigPath));
|
|
865
|
+
const claudeDesktopInfo = {
|
|
866
|
+
id: "claude-desktop",
|
|
867
|
+
name: "Claude Desktop (claude_desktop_config.json)",
|
|
868
|
+
detected: claudeDesktopDetected,
|
|
869
|
+
configPath: claudeDesktopConfigPath
|
|
870
|
+
};
|
|
871
|
+
const claudeCodeLocal = path2.join(targetDir, ".claude");
|
|
872
|
+
const claudeCodeGlobal = path2.join(home, ".claude");
|
|
873
|
+
const claudeCodeDetected = fs2.existsSync(claudeCodeLocal) || fs2.existsSync(claudeCodeGlobal);
|
|
874
|
+
const claudeCodeInfo = {
|
|
875
|
+
id: "claude-code",
|
|
876
|
+
name: "Claude Code (.claude/skills)",
|
|
877
|
+
detected: claudeCodeDetected,
|
|
878
|
+
configPath: path2.join(targetDir, ".claude", "mcp.json"),
|
|
879
|
+
skillsDir: path2.join(targetDir, ".claude", "skills")
|
|
880
|
+
};
|
|
881
|
+
const windsurfGlobalConfig = path2.join(home, ".codeium", "windsurf", "mcp_config.json");
|
|
882
|
+
const windsurfLocal = path2.join(targetDir, ".windsurf");
|
|
883
|
+
const windsurfDetected = fs2.existsSync(windsurfLocal) || fs2.existsSync(path2.dirname(windsurfGlobalConfig));
|
|
884
|
+
const windsurfInfo = {
|
|
885
|
+
id: "windsurf",
|
|
886
|
+
name: "Windsurf (mcp_config.json)",
|
|
887
|
+
detected: windsurfDetected,
|
|
888
|
+
configPath: windsurfGlobalConfig,
|
|
889
|
+
skillsDir: path2.join(targetDir, ".windsurf", "rules")
|
|
890
|
+
};
|
|
891
|
+
return [cursorInfo, claudeDesktopInfo, claudeCodeInfo, windsurfInfo];
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// src/cli/generator.ts
|
|
895
|
+
import fs3 from "fs";
|
|
896
|
+
import path3 from "path";
|
|
897
|
+
var MEDIA_SKILL_TEMPLATE = `---
|
|
898
|
+
description: \u89C6\u9891\u53BB\u6C34\u5370\u4E0B\u8F7D\u3001\u5168\u5E73\u53F0\u56FE\u96C6\u63D0\u53D6\u4E0E\u97F3\u89C6\u9891\u667A\u80FD\u8F6C\u6587\u6848 SOP
|
|
899
|
+
globs:
|
|
900
|
+
---
|
|
901
|
+
|
|
902
|
+
# \u89C6\u9891\u53BB\u6C34\u5370\u4E0B\u8F7D\u4E0E\u6587\u6848\u63D0\u53D6 SOP (Video Download & Transcribe)
|
|
903
|
+
|
|
904
|
+
\u5F53\u7528\u6237\u610F\u56FE\u6D89\u53CA\u201C\u4E0B\u8F7D\u89C6\u9891/\u65E0\u6C34\u5370\u63D0\u53D6\u201D\u3001\u201C\u63D0\u53D6\u6296\u97F3/\u89C6\u9891\u53F7/\u5C0F\u7EA2\u4E66\u7B49\u5E73\u53F0\u6587\u6848\u201D\u3001\u201C\u628A\u89C6\u9891\u8F6C\u6210\u6587\u5B57/\u63D0\u53D6\u5B57\u5E55/\u603B\u7ED3\u5927\u610F\u201D\u65F6\uFF0C\u8BF7\u4E25\u683C\u6309\u4EE5\u4E0B\u5206\u652F\u7B56\u7565\u8C03\u7528 DataClaw MCP \u5DE5\u5177\uFF1A
|
|
905
|
+
|
|
906
|
+
## \u5206\u652F\u7B56\u7565\u4E0E\u6267\u884C\u6D41\u7A0B
|
|
907
|
+
|
|
908
|
+
### \u5206\u652F A\uFF1A\u7528\u6237\u9700\u8981\u63D0\u53D6\u6587\u6848 / \u5B57\u5E55 / \u603B\u7ED3\u89C6\u9891\u5927\u610F\uFF08\u4E00\u6B65\u76F4\u8FBE\uFF09
|
|
909
|
+
**\u6838\u5FC3\u539F\u5219**\uFF1A\u8F6C\u6587\u6848**\u65E0\u9700**\u5148\u8C03\u7528\u89E3\u6790\u5DE5\u5177\u83B7\u53D6\u76F4\u94FE\uFF0C\u76F4\u63A5\u8C03\u7528 \\\`dataclaw_audio_transcribe\\\` \u4E00\u6B65\u76F4\u8FBE\uFF0C\u8017\u65F6\u66F4\u77ED\u4E14\u652F\u6301\u5B98\u65B9\u5B57\u5E55\u7F13\u5B58\u79D2\u56DE\u3002
|
|
910
|
+
|
|
911
|
+
1. **\u76F4\u63A5\u8C03\u7528\u8F6C\u6587\u6848\u5DE5\u5177** \\\`dataclaw_audio_transcribe\\\`\uFF1A
|
|
912
|
+
- **\u7F51\u7EDC\u77ED\u89C6\u9891**\uFF1A\u4F20\u53C2 \\\`media_url = <\u7528\u6237\u63D0\u4F9B\u7684\u5206\u4EAB\u94FE\u63A5\u6216\u6587\u6848>\\\`\u3002
|
|
913
|
+
- \u652F\u6301\u6296\u97F3\u3001\u5C0F\u7EA2\u4E66\u3001\u5FEB\u624B\u3001B\u7AD9\u7B49\u666E\u901A\u77ED\u89C6\u9891\uFF08\u7CFB\u7EDF\u81EA\u52A8\u8D70 \\\`/tools/copy/extract\\\` \u94FE\u8DEF\uFF09\u3002
|
|
914
|
+
- \u652F\u6301\u5FAE\u4FE1\u89C6\u9891\u53F7\u77ED\u94FE\uFF08\u7CFB\u7EDF\u81EA\u52A8\u8D70 \\\`/tools/copy/extract-finder\\\` \u94FE\u8DEF\uFF0C\u81EA\u52A8\u5B8C\u6210 WASM \u89E3\u5BC6\uFF09\u3002
|
|
915
|
+
- **\u672C\u5730\u97F3\u89C6\u9891\u6587\u4EF6**\uFF1A\u4F20\u53C2 local_file_path = <\u672C\u5730\u7EDD\u5BF9\u8DEF\u5F84>\uFF1BMCP \u4F1A\u5148\u76F4\u4F20\u5BF9\u8C61\u5B58\u50A8\uFF0C\u518D\u521B\u5EFA\u5F02\u6B65\u8F6C\u5199\u4EFB\u52A1\uFF0C\u957F\u6587\u4EF6\u7B49\u5F85\u4EFB\u52A1\u5B8C\u6210\u3002
|
|
916
|
+
- **\u8F93\u51FA\u683C\u5F0F\u9009\u62E9**\uFF1A
|
|
917
|
+
- \u7528\u6237\u9700\u8981\u7EAF\u6587\u672C/\u603B\u7ED3\u5927\u610F\uFF1A\u4F20 \\\`output_format = "text"\\\`\u3002
|
|
918
|
+
- \u7528\u6237\u9700\u8981\u5B57\u5E55/\u65F6\u95F4\u8F74\uFF1A\u4F20 \\\`output_format = "srt"\\\`\u3002
|
|
919
|
+
- \u7528\u6237\u9700\u8981\u8BE6\u7EC6\u65F6\u95F4\u5207\u7247\u6570\u636E\uFF1A\u4F20 \\\`output_format = "verbose_json"\\\`\u3002
|
|
920
|
+
|
|
921
|
+
2. **\u6587\u6848\u6392\u7248\u4E0E\u63D0\u70BC\u8F93\u51FA**\uFF1A
|
|
922
|
+
- \u63D0\u53D6\u6587\u6848\u540E\uFF0C\u4E3A\u7528\u6237\u6309\u4EE5\u4E0B\u7ED3\u6784\u6574\u7406\u5448\u73B0\uFF1A
|
|
923
|
+
- **\u3010\u4E3B\u9898\u6982\u8981\u3011**\uFF1A\u4E00\u53E5\u8BDD\u6982\u62EC\u89C6\u9891\u6838\u5FC3\u5185\u5BB9\u3002
|
|
924
|
+
- **\u3010\u5173\u952E\u91D1\u53E5 / \u6838\u5FC3\u77E5\u8BC6\u70B9\u3011**\uFF1A3~5 \u6761\u9AD8\u4EF7\u503C\u8981\u70B9\u3002
|
|
925
|
+
- **\u3010\u9010\u6BB5\u9010\u53E5\u6587\u6848\u3011**\uFF1A\u6E05\u6D17\u53BB\u9664\u53E3\u7656\u5206\u6BB5\u6587\u7A3F\uFF08\u82E5\u9009\u4E86 srt \u5219\u63D0\u4F9B\u6807\u51C6\u5E26\u65F6\u95F4\u8F74\u5B57\u5E55\u683C\u5F0F\uFF09\u3002
|
|
926
|
+
|
|
927
|
+
---
|
|
928
|
+
|
|
929
|
+
### \u5206\u652F B\uFF1A\u7528\u6237\u9700\u8981\u4E0B\u8F7D\u65E0\u6C34\u5370\u89C6\u9891 / \u83B7\u53D6\u9AD8\u6E05\u56FE\u96C6
|
|
930
|
+
\u5F53\u7528\u6237\u610F\u56FE\u662F\u201C\u4E0B\u8F7D\u89C6\u9891\u201D\u3001\u201C\u4FDD\u5B58\u539F\u753B\u7D20\u6750\u201D\u3001\u201C\u53BB\u9664\u6C34\u5370\u201D\u6216\u201C\u4E0B\u8F7D\u5C0F\u7EA2\u4E66/\u6296\u97F3\u56FE\u96C6\u201D\u65F6\uFF1A
|
|
931
|
+
|
|
932
|
+
1. **\u8C03\u7528\u901A\u7528\u53BB\u6C34\u5370\u5DE5\u5177** \\\`dataclaw_video_resolve\\\`\uFF1A
|
|
933
|
+
- \u4F20\u53C2 \\\`url = <\u7528\u6237\u63D0\u4F9B\u7684\u94FE\u63A5\u6216\u5305\u542B\u94FE\u63A5\u7684\u6587\u6848>\\\`\u3002
|
|
934
|
+
- \u7CFB\u7EDF\u81EA\u52A8\u8BC6\u522B\u5E73\u53F0\uFF08\u5BF9\u5E94 \\\`/tools/material/remove-watermark\\\`\uFF09\uFF0C\u652F\u6301\u6296\u97F3\u3001\u89C6\u9891\u53F7\u3001\u5C0F\u7EA2\u4E66\u3001\u5FEB\u624B\u3001TikTok \u7B49\u5168\u5E73\u53F0\u3002
|
|
935
|
+
2. **\u4E0B\u8F7D\u5F15\u5BFC\u5448\u73B0**\uFF1A
|
|
936
|
+
- **\u82E5\u662F\u89C6\u9891**\uFF1A\u8FD4\u56DE\u65E0\u6C34\u5370\u9AD8\u6E05\u76F4\u94FE \\\`video_play_url\\\`\u3001\u89C6\u9891\u5C01\u9762 \\\`cover_url\\\`\u3001\u6807\u9898 \\\`title\\\`\u3001\u4F5C\u8005 \\\`author\\\` \u53CA\u65F6\u957F \\\`duration\\\`\u3002
|
|
937
|
+
- **\u82E5\u662F\u56FE\u96C6**\uFF1A\u8FD4\u56DE\u5168\u91CF\u65E0\u6C34\u5370\u9AD8\u6E05\u56FE\u7247\u76F4\u94FE\u5217\u8868 \\\`images\\\`\u3002
|
|
938
|
+
- \u5F15\u5BFC\u7528\u6237\u5728\u6D4F\u89C8\u5668\u4E2D\u70B9\u51FB\u4E0B\u8F7D\uFF0C\u6216\u63D0\u4F9B\u7EC8\u7AEF \\\`curl / wget\\\` \u4E0B\u8F7D\u547D\u4EE4\u3002
|
|
939
|
+
`;
|
|
940
|
+
var DOUYIN_SKILL_TEMPLATE = `---
|
|
941
|
+
description: \u6296\u97F3\u70ED\u95E8\u89C6\u9891\u590D\u76D8\u3001\u7206\u6B3E\u6587\u6848\u62C6\u89E3\u4E0E\u8BC4\u8BBA\u533A\u75DB\u70B9\u6316\u6398 SOP
|
|
942
|
+
globs:
|
|
943
|
+
---
|
|
944
|
+
|
|
945
|
+
# \u6296\u97F3\u7206\u6B3E\u89C6\u9891\u590D\u76D8\u4E0E\u75DB\u70B9\u5206\u6790 SOP (Douyin Hot Video Audit)
|
|
946
|
+
|
|
947
|
+
\u5F53\u7528\u6237\u610F\u56FE\u6D89\u53CA\u201C\u5206\u6790\u6296\u97F3\u4E0A\u505A [\u54C1\u7C7B/\u884C\u4E1A] \u7684\u7206\u6B3E\u89C6\u9891\u201D\u3001\u201C\u8C03\u7814\u7ADE\u54C1\u8BC4\u8BBA\u533A\u75DB\u70B9/\u7528\u6237\u53CD\u9988\u201D\u3001\u201C\u62C6\u89E3\u5BF9\u6807\u8D26\u53F7\u7684\u9AD8\u8D5E\u811A\u672C\u201D\u65F6\uFF0C\u8BF7\u4E25\u683C\u9075\u5FAA\u4EE5\u4E0B\u6B65\u9AA4\uFF1A
|
|
948
|
+
|
|
949
|
+
## \u6267\u884C\u6D41\u7A0B
|
|
950
|
+
|
|
951
|
+
1. **\u5173\u952E\u8BCD\u68C0\u7D22\u70ED\u95E8\u89C6\u9891**\uFF1A
|
|
952
|
+
- \u8C03\u7528\u5DE5\u5177 \\\`dataclaw_dy_search_videos\\\`\uFF1A
|
|
953
|
+
- \\\`keyword\\\`: \u7528\u6237\u7684\u76EE\u6807\u884C\u4E1A\u3001\u4EA7\u54C1\u6216\u4E3B\u9898\u5173\u952E\u8BCD\u3002
|
|
954
|
+
- \\\`sort_type\\\`: \u4F18\u5148\u4F20 \\\`"most_liked"\\\`\uFF08\u6700\u591A\u70B9\u8D5E\uFF09\u6216 \\\`"most_recent"\\\`\uFF08\u6700\u65B0\uFF09\u3002
|
|
955
|
+
- \\\`publish_time\\\`: \\\`"0"\\\` \u4E0D\u9650\uFF0C\\\`"1"\\\` \u6700\u8FD1\u4E00\u5929\uFF0C\\\`"7"\\\` \u6700\u8FD1\u4E00\u5468\uFF0C\\\`"180"\\\` \u6700\u8FD1\u534A\u5E74\u3002
|
|
956
|
+
- \u9875\u5927\u5C0F\u56FA\u5B9A\uFF0C\u4E0D\u8981\u4F9D\u8D56 \\\`count\\\`\u3002\u7FFB\u9875\u5E26\u56DE\u4E0A\u6B21\u8FD4\u56DE\u7684 \\\`cursor\\\`\u3001\\\`search_id\\\`\u3001\\\`backtrace\\\`\u3002
|
|
957
|
+
- \u7B5B\u9009\u51FA\u70B9\u8D5E\u91CF\u4E0E\u4E92\u52A8\u6700\u9AD8\u7684 TOP 3~5 \u4E2A\u89C6\u9891\u4F5C\u54C1\u3002
|
|
958
|
+
|
|
959
|
+
2. **\u83B7\u53D6\u4F5C\u54C1\u8BE6\u60C5\u4E0E\u4E92\u52A8\u6307\u6807**\uFF1A
|
|
960
|
+
- \u9488\u5BF9\u7B5B\u9009\u51FA\u7684\u76EE\u6807\u89C6\u9891\uFF0C\u8C03\u7528 \\\`dataclaw_dy_get_video_detail\\\`\u3002
|
|
961
|
+
- \u53EA\u62FF\u6807\u9898\u3001\u4F5C\u8005\u3001\u5C01\u9762\u3001\u64AD\u653E\u5730\u5740\u548C\u70B9\u8D5E\u3001\u8BC4\u8BBA\u3001\u5206\u4EAB\u3001\u6536\u85CF\u6570\u3002\u6CA1\u6709\u64AD\u653E\u91CF\uFF0C\u4E5F\u6CA1\u6709\u79D2\u7EA7\u4E92\u52A8\u8D8B\u52BF\u3002
|
|
962
|
+
- \u9700\u8981\u64AD\u653E\u91CF\u6216\u5B8C\u64AD\u7387\u65F6\uFF0C\u53E6\u8C03 \\\`dataclaw_dy_get_play_stats\\\`\uFF0C\u4F20\u540C\u4E00\u4E2A \\\`url\\\`\u3002\u8BE6\u60C5\u548C\u64AD\u653E\u91CF\u7684\u8BF7\u6C42\u4F53\u5B57\u6BB5\u90FD\u662F \\\`url\\\`\uFF0C\u4E0D\u8981\u4F20 \\\`share_url\\\`\u3002
|
|
963
|
+
|
|
964
|
+
3. **\u6293\u53D6\u8BC4\u8BBA**\uFF1A
|
|
965
|
+
- \u9488\u5BF9\u76EE\u6807\u89C6\u9891\uFF0C\u8C03\u7528 \\\`dataclaw_dy_get_comments\\\`\uFF0C\u4F20 \\\`url\\\` \u6216\u7EAF\u6570\u5B57 \\\`aweme_id\\\`\u3002\u6BCF\u9875\u9ED8\u8BA4 50 \u6761\uFF0C\u6700\u5927 50\u3002\u8981\u66F4\u591A\u5C31\u7528\u4E0A\u6B21\u8FD4\u56DE\u7684 \\\`cursor\\\` \u518D\u7FFB\u9875\u3002
|
|
966
|
+
- \u91CD\u70B9\u63D0\u53D6\u9AD8\u8D5E\u70ED\u8BC4\u4E0E\u69FD\u70B9\u3002
|
|
967
|
+
|
|
968
|
+
4. **\u7206\u6B3E\u811A\u672C\u9010\u5B57\u6587\u6848\u63D0\u70BC\uFF08\u6309\u9700\uFF09**\uFF1A
|
|
969
|
+
- \u82E5\u7528\u6237\u9700\u8981\u6DF1\u5165\u62C6\u89E3\u7206\u6B3E\u7684\u53F0\u8BCD\u811A\u672C\u6216\u94A9\u5B50\u8BBE\u8BA1\uFF0C\u76F4\u63A5\u8C03\u7528 \\\`dataclaw_audio_transcribe\\\`\uFF08\u4F20\u5165\u8BE5\u89C6\u9891\u7684 share_url\uFF09\uFF0C\u83B7\u53D6\u9010\u5B57\u53E3\u64AD\u7A3F\u3002
|
|
970
|
+
|
|
971
|
+
5. **\u7EFC\u5408\u590D\u76D8\u5206\u6790\u8F93\u51FA**\uFF1A
|
|
972
|
+
- \u7EFC\u5408\u4EE5\u4E0A\u6570\u636E\uFF0C\u4E3A\u7528\u6237\u8F93\u51FA\u6DF1\u5EA6\u590D\u76D8\u62A5\u544A\uFF1A
|
|
973
|
+
- **\u3010\u9EC4\u91D1\u5F00\u5934\u62C6\u89E3\u3011**\uFF1A\u524D 3 \u79D2\u94A9\u5B50\u89C6\u89C9\u4E0E\u6587\u6848\u8BBE\u8BA1\uFF0C\u5206\u6790\u5176\u9AD8\u5B8C\u64AD\u539F\u56E0\u3002
|
|
974
|
+
- **\u3010\u811A\u672C\u7ED3\u6784\u62C6\u89E3\u3011**\uFF1A\u75DB\u70B9\u5F15\u53D1 -> \u4EF7\u503C\u9610\u8FF0 -> \u884C\u52A8\u53EC\u5524 (CTA) \u7684\u8282\u594F\u5206\u5E03\u3002
|
|
975
|
+
- **\u3010\u9AD8\u9891\u5171\u9E23\u8BCD\u4E91\u3011**\uFF1A\u89C2\u4F17\u8BA8\u8BBA\u6700\u70ED\u70C8\u7684\u5173\u952E\u8BCD\u4E0E\u60C5\u7EEA\u503E\u5411\u3002
|
|
976
|
+
- **\u3010\u75DB\u70B9\u4E0E\u672A\u6EE1\u8DB3\u9700\u6C42\u3011**\uFF1A\u8BC4\u8BBA\u533A\u9AD8\u8D5E\u5410\u69FD\u3001\u7591\u95EE\u53CA\u6F5C\u5728\u4E70\u70B9\u3002
|
|
977
|
+
- **\u3010\u7206\u6B3E\u53EF\u590D\u5236\u5EFA\u8BAE\u3011**\uFF1A\u603B\u7ED3 3 \u6761\u53EF\u76F4\u63A5\u843D\u5730\u7684\u811A\u672C\u521B\u4F5C\u5EFA\u8BAE\u3002
|
|
978
|
+
`;
|
|
979
|
+
var CHANNELS_SKILL_TEMPLATE = `---
|
|
980
|
+
description: \u5FAE\u4FE1\u89C6\u9891\u53F7\u521B\u4F5C\u8005\u6DF1\u5EA6\u62C6\u89E3\u3001\u7206\u6B3E Feed \u4E0E\u4E92\u52A8\u76D1\u63A7 SOP
|
|
981
|
+
globs:
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
# \u5FAE\u4FE1\u89C6\u9891\u53F7\u8FBE\u4EBA\u4E0E\u4F5C\u54C1\u76D1\u63A7 SOP (Channels Creator Monitor)
|
|
985
|
+
|
|
986
|
+
\u5F53\u7528\u6237\u610F\u56FE\u6D89\u53CA\u201C\u62C6\u89E3\u8FD9\u4E2A\u89C6\u9891\u53F7\u535A\u4E3B\u201D\u3001\u201C\u770B\u770B\u8FD9\u4E2A\u89C6\u9891\u53F7\u6700\u8FD1\u53D1\u4E86\u4EC0\u4E48\u201D\u3001\u201C\u5206\u6790\u89C6\u9891\u53F7\u7ADE\u54C1\u8D26\u53F7\u7684\u8868\u73B0\u201D\u65F6\uFF0C\u8BF7\u4E25\u683C\u9075\u5FAA\u4EE5\u4E0B\u6B65\u9AA4\uFF1A
|
|
987
|
+
|
|
988
|
+
## \u6267\u884C\u6D41\u7A0B
|
|
989
|
+
|
|
990
|
+
1. **\u521B\u4F5C\u8005\u68C0\u7D22\u4E0E\u5B9A\u4F4D**\uFF1A
|
|
991
|
+
- \u82E5\u7528\u6237\u63D0\u4F9B\u4E86\u535A\u4E3B\u6635\u79F0\u6216\u5173\u952E\u8BCD\uFF0C\u8C03\u7528 \\\`dataclaw_channels_search_authors\\\` \u8FDB\u884C\u641C\u7D22\u3002
|
|
992
|
+
- \u786E\u8BA4\u76EE\u6807\u4F5C\u8005\uFF0C\u83B7\u53D6\u5176\u552F\u4E00\u6807\u8BC6 \\\`finder_username\\\`\u3001\u5934\u50CF\u53CA\u8BA4\u8BC1\u7B80\u4ECB\u3002
|
|
993
|
+
|
|
994
|
+
2. **\u62C9\u53D6\u8FD1\u671F\u4F5C\u54C1 Feed**\uFF1A
|
|
995
|
+
- \u8C03\u7528 \\\`dataclaw_channels_get_author_feeds\\\`\uFF0C\u4F20\u5165\u4F5C\u8005 \\\`finder_username\\\`\u3002
|
|
996
|
+
- \u6BCF\u9875 15 \u6761\u3002\u8981 10~30 \u6761\u5C31\u518D\u4F20\u4E0A\u6B21\u8FD4\u56DE\u7684 \\\`last_buffer\\\` / \\\`buffer\\\` \u7FFB\u4E00\u9875\u3002
|
|
997
|
+
|
|
998
|
+
3. **\u4F5C\u54C1\u5168\u91CF\u6570\u636E\u4E0E\u6587\u6848/\u89C6\u9891\u63D0\u53D6\uFF08\u6309\u9700\uFF09**\uFF1A
|
|
999
|
+
- **\u82E5\u9700\u63D0\u53D6\u89C6\u9891\u53E3\u64AD\u6587\u6848**\uFF1A\u76F4\u63A5\u8C03\u7528 \\\`dataclaw_audio_transcribe\\\`\uFF08\u4F20\u5165\u4F5C\u54C1\u5206\u4EAB\u77ED\u94FE\uFF0C\u7CFB\u7EDF\u5E95\u5C42\u81EA\u52A8\u901A\u8FC7 WASM \u89E3\u5BC6\u89C6\u9891\u53F7\u52A0\u5BC6\u89C6\u9891\u6D41\u5E76\u8F6C\u5199\u4E3A\u6587\u6848\u6216 SRT \u5B57\u5E55\uFF09\u3002
|
|
1000
|
+
- **\u82E5\u9700\u65E0\u6C34\u5370\u4E0B\u8F7D\u89C6\u9891**\uFF1A\u8C03\u7528 \\\`dataclaw_video_resolve\\\`\uFF08\u4F20\u5165\u89C6\u9891\u53F7\u5206\u4EAB\u77ED\u94FE\uFF09\uFF0C\u63D0\u53D6\u9AD8\u6E05\u4E0B\u8F7D\u76F4\u94FE\u3002
|
|
1001
|
+
|
|
1002
|
+
4. **\u8FBE\u4EBA\u77E9\u9635\u4E0E\u8FD0\u8425\u7B56\u7565\u63D0\u70BC**\uFF1A
|
|
1003
|
+
- \u4E3A\u7528\u6237\u8F93\u51FA\u6DF1\u5EA6\u5206\u6790\u62A5\u544A\uFF1A
|
|
1004
|
+
- **\u3010\u53D1\u6587\u8282\u594F\u4E0E\u504F\u597D\u3011**\uFF1A\u8FD1\u671F\u66F4\u65B0\u9891\u7387\u3001\u53D1\u5E03\u65F6\u95F4\u6BB5\u504F\u597D\u3002
|
|
1005
|
+
- **\u3010\u7206\u6B3E\u5185\u5BB9\u7279\u5F81\u3011**\uFF1A\u70B9\u8D5E/\u8F6C\u53D1\u7834\u4E07\u7684\u9898\u6750\u7279\u5F81\u4E0E\u5C01\u9762\u6587\u6848\u5957\u8DEF\u3002
|
|
1006
|
+
- **\u3010\u53E3\u64AD\u53F0\u8BCD\u5957\u8DEF\u3011**\uFF1A\u9488\u5BF9\u4EE3\u8868\u4F5C\u63D0\u53D6\u7684\u53F0\u8BCD\u811A\u672C\u8282\u594F\u4E0E\u8BDD\u672F\u62C6\u89E3\u3002
|
|
1007
|
+
- **\u3010\u4E92\u52A8\u8F6C\u5316\u5206\u6790\u3011**\uFF1A\u8BC4\u8BBA\u533A\u4E92\u52A8\u70ED\u70B9\u4E0E\u7528\u6237\u79C1\u57DF\u8F6C\u5316\u5F15\u5BFC\u65B9\u5F0F\u3002
|
|
1008
|
+
- **\u3010\u6A21\u4EFF\u4E0E\u8D85\u8D8A\u5EFA\u8BAE\u3011**\uFF1A\u5BF9\u6807\u540C\u884C\u7684\u5DEE\u5F02\u5316\u5B9A\u4F4D\u7B56\u7565\u3002
|
|
1009
|
+
`;
|
|
1010
|
+
function writeMcpConfig(configFilePath, apiKey, customBaseUrl) {
|
|
1011
|
+
const dir = path3.dirname(configFilePath);
|
|
1012
|
+
if (!fs3.existsSync(dir)) {
|
|
1013
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1014
|
+
}
|
|
1015
|
+
let existingJson = {};
|
|
1016
|
+
if (fs3.existsSync(configFilePath)) {
|
|
1017
|
+
try {
|
|
1018
|
+
const content = fs3.readFileSync(configFilePath, "utf-8");
|
|
1019
|
+
const parsed = JSON.parse(content);
|
|
1020
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1021
|
+
existingJson = parsed;
|
|
1022
|
+
}
|
|
1023
|
+
} catch {
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
const existingMcpServers = existingJson.mcpServers && typeof existingJson.mcpServers === "object" && !Array.isArray(existingJson.mcpServers) ? existingJson.mcpServers : {};
|
|
1027
|
+
const envVars = {
|
|
1028
|
+
DATACLAW_API_KEY: apiKey
|
|
1029
|
+
};
|
|
1030
|
+
if (customBaseUrl) {
|
|
1031
|
+
envVars.DATACLAW_BASE_URL = customBaseUrl;
|
|
1032
|
+
}
|
|
1033
|
+
existingMcpServers.dataclaw = {
|
|
1034
|
+
command: "npx",
|
|
1035
|
+
args: ["-y", "dataclaw-agent-kit", "mcp"],
|
|
1036
|
+
env: envVars
|
|
1037
|
+
};
|
|
1038
|
+
existingJson.mcpServers = existingMcpServers;
|
|
1039
|
+
fs3.writeFileSync(configFilePath, JSON.stringify(existingJson, null, 2), "utf-8");
|
|
1040
|
+
}
|
|
1041
|
+
function writeSkillsToDir(skillsDir, skillKeys, extension = ".mdc") {
|
|
1042
|
+
if (!fs3.existsSync(skillsDir)) {
|
|
1043
|
+
fs3.mkdirSync(skillsDir, { recursive: true });
|
|
1044
|
+
}
|
|
1045
|
+
const written = [];
|
|
1046
|
+
if (skillKeys.includes("media")) {
|
|
1047
|
+
const file = path3.join(skillsDir, `dataclaw-media${extension}`);
|
|
1048
|
+
fs3.writeFileSync(file, MEDIA_SKILL_TEMPLATE, "utf-8");
|
|
1049
|
+
written.push(file);
|
|
1050
|
+
}
|
|
1051
|
+
if (skillKeys.includes("douyin")) {
|
|
1052
|
+
const file = path3.join(skillsDir, `dataclaw-douyin${extension}`);
|
|
1053
|
+
fs3.writeFileSync(file, DOUYIN_SKILL_TEMPLATE, "utf-8");
|
|
1054
|
+
written.push(file);
|
|
1055
|
+
}
|
|
1056
|
+
if (skillKeys.includes("channels")) {
|
|
1057
|
+
const file = path3.join(skillsDir, `dataclaw-channels${extension}`);
|
|
1058
|
+
fs3.writeFileSync(file, CHANNELS_SKILL_TEMPLATE, "utf-8");
|
|
1059
|
+
written.push(file);
|
|
1060
|
+
}
|
|
1061
|
+
return written;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// src/cli/index.ts
|
|
1065
|
+
import path4 from "path";
|
|
1066
|
+
import pc from "picocolors";
|
|
1067
|
+
import prompts from "prompts";
|
|
1068
|
+
async function runInitWizard() {
|
|
1069
|
+
console.log(
|
|
1070
|
+
pc.cyan(`
|
|
1071
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
1072
|
+
\u2502 \u{1F99E} DataClaw AI Agent Kit (MCP & Skills) \u5B89\u88C5\u5411\u5BFC \u2502
|
|
1073
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
1074
|
+
`)
|
|
1075
|
+
);
|
|
1076
|
+
const defaultApiKey = process.env.DATACLAW_API_KEY || "";
|
|
1077
|
+
const detectedIdes = detectIdeEnvironments();
|
|
1078
|
+
const keyResponse = await prompts({
|
|
1079
|
+
type: "password",
|
|
1080
|
+
name: "apiKey",
|
|
1081
|
+
message: "\u8BF7\u8F93\u5165\u60A8\u7684 DataClaw API-Key (\u4ECE\u4E2A\u4EBA\u4E2D\u5FC3\u83B7\u53D6):",
|
|
1082
|
+
initial: defaultApiKey,
|
|
1083
|
+
validate: (val) => val.trim().length > 0 ? true : "API-Key \u4E0D\u80FD\u4E3A\u7A7A"
|
|
1084
|
+
});
|
|
1085
|
+
const apiKey = keyResponse.apiKey?.trim();
|
|
1086
|
+
if (!apiKey) {
|
|
1087
|
+
console.log(pc.yellow("\u5DF2\u53D6\u6D88\u5B89\u88C5\u5411\u5BFC\u3002"));
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
const client = new DataClawClient({ apiKey });
|
|
1091
|
+
console.log(pc.dim("\u6B63\u5728\u9A8C\u8BC1 API-Key \u6709\u6548\u6027..."));
|
|
1092
|
+
try {
|
|
1093
|
+
const me = await client.getMe();
|
|
1094
|
+
console.log(
|
|
1095
|
+
pc.green(`\u2714 \u9274\u6743\u9A8C\u8BC1\u6210\u529F\uFF01\u5F53\u524D\u7528\u6237: ${me.username} (\u79EF\u5206\u4F59\u989D: ${me.credit ?? "\u65E0\u9650\u5236"} \u70B9)`)
|
|
1096
|
+
);
|
|
1097
|
+
} catch (err) {
|
|
1098
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1099
|
+
console.log(pc.yellow(`\u26A0\uFE0F \u9274\u6743\u9A8C\u8BC1\u672A\u901A\u8FC7: ${errorMsg}`));
|
|
1100
|
+
const confirm = await prompts({
|
|
1101
|
+
type: "confirm",
|
|
1102
|
+
name: "continueAnyway",
|
|
1103
|
+
message: "\u662F\u5426\u4ECD\u8981\u7EE7\u7EED\u4F7F\u7528\u6B64 API-Key \u5B8C\u6210\u5B89\u88C5\uFF1F",
|
|
1104
|
+
initial: true
|
|
1105
|
+
});
|
|
1106
|
+
if (!confirm.continueAnyway) {
|
|
1107
|
+
console.log(pc.yellow("\u5DF2\u53D6\u6D88\u5B89\u88C5\u3002"));
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
const ideChoices = detectedIdes.map((ide) => ({
|
|
1112
|
+
title: ide.name,
|
|
1113
|
+
value: ide.id,
|
|
1114
|
+
selected: ide.detected
|
|
1115
|
+
}));
|
|
1116
|
+
const ideResponse = await prompts({
|
|
1117
|
+
type: "multiselect",
|
|
1118
|
+
name: "targets",
|
|
1119
|
+
message: "\u8BF7\u9009\u62E9\u9700\u8981\u6CE8\u5165\u914D\u7F6E\u7684 AI \u5BBF\u4E3B\u73AF\u5883:",
|
|
1120
|
+
choices: ideChoices,
|
|
1121
|
+
min: 1,
|
|
1122
|
+
hint: "- \u7A7A\u683C\u5207\u6362\u9009\u4E2D\uFF0C\u56DE\u8F66\u786E\u8BA4"
|
|
1123
|
+
});
|
|
1124
|
+
const selectedTargets = ideResponse.targets || [];
|
|
1125
|
+
if (selectedTargets.length === 0) {
|
|
1126
|
+
console.log(pc.yellow("\u672A\u9009\u62E9\u4EFB\u4F55\u5BBF\u4E3B\u73AF\u5883\uFF0C\u5DF2\u9000\u51FA\u3002"));
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
const skillResponse = await prompts({
|
|
1130
|
+
type: "multiselect",
|
|
1131
|
+
name: "skills",
|
|
1132
|
+
message: "\u8BF7\u52FE\u9009\u9700\u8981\u542F\u7528\u7684\u7B2C\u4E00\u671F\u573A\u666F\u6280\u80FD:",
|
|
1133
|
+
choices: [
|
|
1134
|
+
{
|
|
1135
|
+
title: "[\u89C6\u9891\u5904\u7406] \u89C6\u9891\u65E0\u6C34\u5370\u76F4\u94FE\u63D0\u53D6\u4E0E\u97F3\u9891\u667A\u80FD\u8BED\u97F3\u8F6C\u5199 SOP",
|
|
1136
|
+
value: "media",
|
|
1137
|
+
selected: true
|
|
1138
|
+
},
|
|
1139
|
+
{
|
|
1140
|
+
title: "[\u6296\u97F3\u5206\u6790] \u70ED\u95E8\u89C6\u9891\u68C0\u7D22\u3001\u7206\u6B3E\u6587\u6848\u4E0E\u8BC4\u8BBA\u75DB\u70B9\u6316\u6398 SOP",
|
|
1141
|
+
value: "douyin",
|
|
1142
|
+
selected: true
|
|
1143
|
+
},
|
|
1144
|
+
{
|
|
1145
|
+
title: "[\u5FAE\u4FE1\u89C6\u9891\u53F7] \u8FBE\u4EBA\u4E3B\u9875\u6DF1\u5EA6\u62C6\u89E3\u4E0E\u4F5C\u54C1\u52A8\u6001\u76D1\u63A7 SOP",
|
|
1146
|
+
value: "channels",
|
|
1147
|
+
selected: true
|
|
1148
|
+
}
|
|
1149
|
+
],
|
|
1150
|
+
min: 1
|
|
1151
|
+
});
|
|
1152
|
+
const selectedSkills = skillResponse.skills || [];
|
|
1153
|
+
if (selectedSkills.length === 0) {
|
|
1154
|
+
console.log(pc.yellow("\u672A\u9009\u62E9\u4EFB\u4F55\u6280\u80FD\uFF0C\u5DF2\u9000\u51FA\u3002"));
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
console.log("");
|
|
1158
|
+
for (const target of selectedTargets) {
|
|
1159
|
+
const ideMeta = detectedIdes.find((item) => item.id === target);
|
|
1160
|
+
if (!ideMeta) continue;
|
|
1161
|
+
if (ideMeta.configPath) {
|
|
1162
|
+
try {
|
|
1163
|
+
writeMcpConfig(ideMeta.configPath, apiKey);
|
|
1164
|
+
console.log(pc.green(`\u2714 \u914D\u7F6E\u6587\u4EF6\u5DF2\u5199\u5165: ${path4.relative(process.cwd(), ideMeta.configPath) || ideMeta.configPath}`));
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
console.error(pc.red(`\u2716 \u5199\u5165\u914D\u7F6E\u6587\u4EF6\u5931\u8D25 (${ideMeta.configPath}): ${err instanceof Error ? err.message : String(err)}`));
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
if (ideMeta.skillsDir) {
|
|
1170
|
+
try {
|
|
1171
|
+
const ext = target === "cursor" ? ".mdc" : ".md";
|
|
1172
|
+
const writtenFiles = writeSkillsToDir(ideMeta.skillsDir, selectedSkills, ext);
|
|
1173
|
+
for (const f of writtenFiles) {
|
|
1174
|
+
console.log(pc.green(`\u2714 \u573A\u666F\u6280\u80FD\u5DF2\u751F\u6210: ${path4.relative(process.cwd(), f) || f}`));
|
|
1175
|
+
}
|
|
1176
|
+
} catch (err) {
|
|
1177
|
+
console.error(pc.red(`\u2716 \u5199\u5165\u6280\u80FD\u6587\u4EF6\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`));
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
console.log(
|
|
1182
|
+
pc.cyan(`
|
|
1183
|
+
\u{1F389} \u5B89\u88C5\u5B8C\u6210\uFF01\u5728 Cursor Composer \u6216 Claude \u4E2D\u76F4\u63A5\u63D0\u95EE\u4F53\u9A8C:
|
|
1184
|
+
"\u5E2E\u6211\u628A\u8FD9\u4E2A\u6296\u97F3\u94FE\u63A5\u7684\u5185\u5BB9\u8F6C\u6210\u6587\u7AE0: https://v.douyin.com/..."
|
|
1185
|
+
"\u5206\u6790\u6296\u97F3\u4E0A\u505A\u5C0F\u5403\u52A0\u76DF\u7684\u70B9\u8D5E\u6700\u9AD8\u89C6\u9891\u4E0E\u8BC4\u8BBA\u75DB\u70B9"
|
|
1186
|
+
`)
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
export {
|
|
1191
|
+
DataClawClient,
|
|
1192
|
+
VideoResolveSchema,
|
|
1193
|
+
AudioTranscribeSchema,
|
|
1194
|
+
DySearchVideosSchema,
|
|
1195
|
+
DyGetVideoDetailSchema,
|
|
1196
|
+
DyGetPlayStatsSchema,
|
|
1197
|
+
DyGetCommentsSchema,
|
|
1198
|
+
DyGetUserProfileSchema,
|
|
1199
|
+
ChannelsSearchAuthorsSchema,
|
|
1200
|
+
ChannelsGetAuthorFeedsSchema,
|
|
1201
|
+
ChannelsResolveShareUrlSchema,
|
|
1202
|
+
createMcpServer,
|
|
1203
|
+
startMcpServer,
|
|
1204
|
+
detectIdeEnvironments,
|
|
1205
|
+
MEDIA_SKILL_TEMPLATE,
|
|
1206
|
+
DOUYIN_SKILL_TEMPLATE,
|
|
1207
|
+
CHANNELS_SKILL_TEMPLATE,
|
|
1208
|
+
writeMcpConfig,
|
|
1209
|
+
writeSkillsToDir,
|
|
1210
|
+
runInitWizard
|
|
1211
|
+
};
|
|
1212
|
+
//# sourceMappingURL=chunk-CPFAA7NN.js.map
|