z-mcp-codesign 0.1.1 → 0.1.3
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 +32 -94
- package/dist/index.js +328 -225
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,132 +1,70 @@
|
|
|
1
1
|
# 前言
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
3
|
这是一个基于 `@modelcontextprotocol/sdk` 实现的 **MCP stdio 服务**,用于在本机通过 Edge 打开腾讯 CoDesign 页面并抓取当前画板图片。
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
5
|
# 配置说明
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
7
|
在 Cursor 工作区根目录创建或编辑 `.cursor/mcp.json`。保存后在 Cursor 的 MCP 相关设置中启用该服务,必要时重新加载窗口或刷新 MCP 列表。
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
|
|
17
9
|
**前提**:本机需已安装 **Microsoft Edge**;服务通过 Playwright 使用系统 Edge(`channel: "msedge"`)。
|
|
18
10
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
## 使用已发布的 npm 包(推荐)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
在任意项目中均可使用,无需克隆本仓库:
|
|
26
|
-
|
|
27
|
-
|
|
11
|
+
在任意项目中均可使用:
|
|
28
12
|
|
|
29
13
|
```json
|
|
30
|
-
|
|
31
14
|
{
|
|
32
|
-
|
|
33
15
|
"mcpServers": {
|
|
34
|
-
|
|
35
16
|
"z-mcp-codesign": {
|
|
36
|
-
|
|
37
17
|
"command": "npx",
|
|
38
|
-
|
|
39
18
|
"args": ["-y", "z-mcp-codesign", "--stdio"]
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## 使用本地源码(开发与调试)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
在克隆后的仓库根目录配置 `.cursor/mcp.json`,并先执行 `npm install` 与 `npm run build`(生成 `dist/`)。`args` 中的 `"."` 表示使用当前目录作为 npm 包:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
```json
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
"mcpServers": {
|
|
64
|
-
|
|
65
|
-
"z-mcp-codesign": {
|
|
66
|
-
|
|
67
|
-
"command": "npx",
|
|
68
|
-
|
|
69
|
-
"args": ["-y", ".", "--stdio"]
|
|
70
|
-
|
|
71
19
|
}
|
|
72
|
-
|
|
73
20
|
}
|
|
74
|
-
|
|
75
21
|
}
|
|
76
|
-
|
|
77
22
|
```
|
|
78
23
|
|
|
79
24
|
|
|
80
25
|
|
|
81
|
-
若 MCP 启动时工作目录不是仓库根目录,可在该条目中增加 `"cwd"`,值为本仓库的绝对路径(Windows 下 JSON 字符串里反斜杠需写成 `\\`)。
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
## 环境变量与用户数据目录
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
调用 **`codesign_open_login`** 成功后,进程会设置环境变量 **`Z_MCP_CODESIGN_EDGE_USER_DATA`**,指向本次使用的 Edge 用户数据根目录;随后在同一 MCP 会话里调用 **`codesign_screen_inspect`** 且不显式传 `userDataDir` 时,会自动复用该目录下的登录态。
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
也可在两条工具调用里显式传入相同的 **`userDataDir`**(绝对路径);若使用非 `Default` 的 Edge profile,请在登录与抓图两次调用中传入相同的 **`profileDirectory`**。
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
# 使用 MCP 登录 CoDesign
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
1. 按上文在 Cursor 中启用本 MCP 服务。
|
|
102
|
-
|
|
103
|
-
2. 在对话中让助手调用工具 **`codesign_open_login`**(参数可全部省略;默认打开 `https://codesign.qq.com/app/login`)。
|
|
104
|
-
|
|
105
|
-
3. 在弹出的 **Edge** 窗口中完成腾讯 CoDesign 登录(扫码或账号密码等)。
|
|
106
|
-
|
|
107
|
-
4. **关闭该 Edge 窗口**(释放用户数据目录锁),否则后续抓图可能启动失败。
|
|
108
|
-
|
|
109
|
-
5. 再调用 **`codesign_screen_inspect`**,传入目标 CoDesign 页面 **`url`**(例如设计稿 inspect 链接);返回的 JSON 中含 **`imageBase64`**(PNG),供客户端展示或落盘。
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
26
|
# 提供的工具
|
|
114
27
|
|
|
28
|
+
| 工具名 | 说明 |
|
|
29
|
+
| ------ | ---- |
|
|
30
|
+
| `codesign_open_login` | 有界面打开 CoDesign 登录页,用于在本机 Edge 用户数据目录中完成登录 |
|
|
31
|
+
| `codesign_screen_inspect_save` | 打开指定 CoDesign 页面,截取最大的可见 `.screen-inspect` 区域,保存为本地 PNG 文件并返回保存路径(默认保存到项目根目录 `.codesign_screen_imgs/`) |
|
|
32
|
+
| `codesign_screen_viewer_download_save` | 打开 CoDesign 页面,点击 `.screen-viewer__action` 选择“下载图片”,捕获下载并保存到项目根目录 `.codesign_screen_imgs/` |
|
|
33
|
+
| `codesign_screen_list` | 获取 CoDesign 设计页面左侧菜单中的所有页面名称和访问地址 |
|
|
115
34
|
|
|
35
|
+
# 使用示例
|
|
116
36
|
|
|
117
|
-
|
|
37
|
+
**打开登录页(用于后续抓图)**
|
|
118
38
|
|
|
119
|
-
|
|
39
|
+
```bash
|
|
40
|
+
使用MCP 打开 CoDesign 登录页
|
|
41
|
+
```
|
|
120
42
|
|
|
121
|
-
|
|
43
|
+
**列出当前项目的页面列表**
|
|
122
44
|
|
|
123
|
-
|
|
45
|
+
```bash
|
|
46
|
+
使用MCP 获取CoDesign所有页面列表使用表格展示。
|
|
47
|
+
URL为:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
|
|
48
|
+
```
|
|
124
49
|
|
|
50
|
+
**抓图并保存到本地**
|
|
125
51
|
|
|
52
|
+
```bash
|
|
53
|
+
使用MCP 获取CoDesign页面图片,把截图保存到本地,并告诉我保存路径。
|
|
54
|
+
URL为:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
|
|
55
|
+
```
|
|
126
56
|
|
|
127
|
-
|
|
57
|
+
**通过页面“下载图片”保存到本地**
|
|
128
58
|
|
|
59
|
+
```bash
|
|
60
|
+
使用MCP 打开CoDesign页面,下载图片保存到本地,并告诉我保存路径。
|
|
61
|
+
URL为:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
|
|
62
|
+
```
|
|
129
63
|
|
|
64
|
+
**生成项目**
|
|
130
65
|
|
|
131
|
-
|
|
66
|
+
```bash
|
|
67
|
+
使用MCP 打开CoDesign页面,下载图片保存到本地,并识别图片内容生成Vue3+Vite项目。
|
|
68
|
+
URL为:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
|
|
69
|
+
```
|
|
132
70
|
|
package/dist/index.js
CHANGED
|
@@ -2980,7 +2980,7 @@ var require_compile = __commonJS({
|
|
|
2980
2980
|
const schOrFunc = root.refs[ref];
|
|
2981
2981
|
if (schOrFunc)
|
|
2982
2982
|
return schOrFunc;
|
|
2983
|
-
let _sch =
|
|
2983
|
+
let _sch = resolve5.call(this, root, ref);
|
|
2984
2984
|
if (_sch === void 0) {
|
|
2985
2985
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
2986
2986
|
const { schemaId } = this.opts;
|
|
@@ -3007,7 +3007,7 @@ var require_compile = __commonJS({
|
|
|
3007
3007
|
function sameSchemaEnv(s1, s2) {
|
|
3008
3008
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3009
3009
|
}
|
|
3010
|
-
function
|
|
3010
|
+
function resolve5(root, ref) {
|
|
3011
3011
|
let sch;
|
|
3012
3012
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3013
3013
|
ref = sch;
|
|
@@ -3222,8 +3222,8 @@ var require_utils = __commonJS({
|
|
|
3222
3222
|
}
|
|
3223
3223
|
return ind;
|
|
3224
3224
|
}
|
|
3225
|
-
function removeDotSegments(
|
|
3226
|
-
let input =
|
|
3225
|
+
function removeDotSegments(path3) {
|
|
3226
|
+
let input = path3;
|
|
3227
3227
|
const output = [];
|
|
3228
3228
|
let nextSlash = -1;
|
|
3229
3229
|
let len = 0;
|
|
@@ -3422,8 +3422,8 @@ var require_schemes = __commonJS({
|
|
|
3422
3422
|
wsComponent.secure = void 0;
|
|
3423
3423
|
}
|
|
3424
3424
|
if (wsComponent.resourceName) {
|
|
3425
|
-
const [
|
|
3426
|
-
wsComponent.path =
|
|
3425
|
+
const [path3, query] = wsComponent.resourceName.split("?");
|
|
3426
|
+
wsComponent.path = path3 && path3 !== "/" ? path3 : void 0;
|
|
3427
3427
|
wsComponent.query = query;
|
|
3428
3428
|
wsComponent.resourceName = void 0;
|
|
3429
3429
|
}
|
|
@@ -3582,7 +3582,7 @@ var require_fast_uri = __commonJS({
|
|
|
3582
3582
|
}
|
|
3583
3583
|
return uri;
|
|
3584
3584
|
}
|
|
3585
|
-
function
|
|
3585
|
+
function resolve5(baseURI, relativeURI, options) {
|
|
3586
3586
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3587
3587
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
3588
3588
|
schemelessOptions.skipEscape = true;
|
|
@@ -3809,7 +3809,7 @@ var require_fast_uri = __commonJS({
|
|
|
3809
3809
|
var fastUri = {
|
|
3810
3810
|
SCHEMES,
|
|
3811
3811
|
normalize,
|
|
3812
|
-
resolve:
|
|
3812
|
+
resolve: resolve5,
|
|
3813
3813
|
resolveComponent,
|
|
3814
3814
|
equal,
|
|
3815
3815
|
serialize,
|
|
@@ -6800,7 +6800,7 @@ var require_dist = __commonJS({
|
|
|
6800
6800
|
|
|
6801
6801
|
// src/index.ts
|
|
6802
6802
|
import { createRequire } from "node:module";
|
|
6803
|
-
import { dirname
|
|
6803
|
+
import { dirname, join as join4 } from "node:path";
|
|
6804
6804
|
import { fileURLToPath } from "node:url";
|
|
6805
6805
|
|
|
6806
6806
|
// node_modules/zod/v3/external.js
|
|
@@ -7281,8 +7281,8 @@ function getErrorMap() {
|
|
|
7281
7281
|
|
|
7282
7282
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
7283
7283
|
var makeIssue = (params) => {
|
|
7284
|
-
const { data, path, errorMaps, issueData } = params;
|
|
7285
|
-
const fullPath = [...
|
|
7284
|
+
const { data, path: path3, errorMaps, issueData } = params;
|
|
7285
|
+
const fullPath = [...path3, ...issueData.path || []];
|
|
7286
7286
|
const fullIssue = {
|
|
7287
7287
|
...issueData,
|
|
7288
7288
|
path: fullPath
|
|
@@ -7398,11 +7398,11 @@ var errorUtil;
|
|
|
7398
7398
|
|
|
7399
7399
|
// node_modules/zod/v3/types.js
|
|
7400
7400
|
var ParseInputLazyPath = class {
|
|
7401
|
-
constructor(parent, value,
|
|
7401
|
+
constructor(parent, value, path3, key) {
|
|
7402
7402
|
this._cachedPath = [];
|
|
7403
7403
|
this.parent = parent;
|
|
7404
7404
|
this.data = value;
|
|
7405
|
-
this._path =
|
|
7405
|
+
this._path = path3;
|
|
7406
7406
|
this._key = key;
|
|
7407
7407
|
}
|
|
7408
7408
|
get path() {
|
|
@@ -11039,10 +11039,10 @@ function assignProp(target, prop, value) {
|
|
|
11039
11039
|
configurable: true
|
|
11040
11040
|
});
|
|
11041
11041
|
}
|
|
11042
|
-
function getElementAtPath(obj,
|
|
11043
|
-
if (!
|
|
11042
|
+
function getElementAtPath(obj, path3) {
|
|
11043
|
+
if (!path3)
|
|
11044
11044
|
return obj;
|
|
11045
|
-
return
|
|
11045
|
+
return path3.reduce((acc, key) => acc?.[key], obj);
|
|
11046
11046
|
}
|
|
11047
11047
|
function promiseAllObject(promisesObj) {
|
|
11048
11048
|
const keys = Object.keys(promisesObj);
|
|
@@ -11362,11 +11362,11 @@ function aborted(x, startIndex = 0) {
|
|
|
11362
11362
|
}
|
|
11363
11363
|
return false;
|
|
11364
11364
|
}
|
|
11365
|
-
function prefixIssues(
|
|
11365
|
+
function prefixIssues(path3, issues) {
|
|
11366
11366
|
return issues.map((iss) => {
|
|
11367
11367
|
var _a;
|
|
11368
11368
|
(_a = iss).path ?? (_a.path = []);
|
|
11369
|
-
iss.path.unshift(
|
|
11369
|
+
iss.path.unshift(path3);
|
|
11370
11370
|
return iss;
|
|
11371
11371
|
});
|
|
11372
11372
|
}
|
|
@@ -18875,7 +18875,7 @@ var Protocol = class {
|
|
|
18875
18875
|
return;
|
|
18876
18876
|
}
|
|
18877
18877
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
18878
|
-
await new Promise((
|
|
18878
|
+
await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
|
|
18879
18879
|
options?.signal?.throwIfAborted();
|
|
18880
18880
|
}
|
|
18881
18881
|
} catch (error2) {
|
|
@@ -18892,7 +18892,7 @@ var Protocol = class {
|
|
|
18892
18892
|
*/
|
|
18893
18893
|
request(request, resultSchema, options) {
|
|
18894
18894
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
18895
|
-
return new Promise((
|
|
18895
|
+
return new Promise((resolve5, reject) => {
|
|
18896
18896
|
const earlyReject = (error2) => {
|
|
18897
18897
|
reject(error2);
|
|
18898
18898
|
};
|
|
@@ -18970,7 +18970,7 @@ var Protocol = class {
|
|
|
18970
18970
|
if (!parseResult.success) {
|
|
18971
18971
|
reject(parseResult.error);
|
|
18972
18972
|
} else {
|
|
18973
|
-
|
|
18973
|
+
resolve5(parseResult.data);
|
|
18974
18974
|
}
|
|
18975
18975
|
} catch (error2) {
|
|
18976
18976
|
reject(error2);
|
|
@@ -19231,12 +19231,12 @@ var Protocol = class {
|
|
|
19231
19231
|
}
|
|
19232
19232
|
} catch {
|
|
19233
19233
|
}
|
|
19234
|
-
return new Promise((
|
|
19234
|
+
return new Promise((resolve5, reject) => {
|
|
19235
19235
|
if (signal.aborted) {
|
|
19236
19236
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
19237
19237
|
return;
|
|
19238
19238
|
}
|
|
19239
|
-
const timeoutId = setTimeout(
|
|
19239
|
+
const timeoutId = setTimeout(resolve5, interval);
|
|
19240
19240
|
signal.addEventListener("abort", () => {
|
|
19241
19241
|
clearTimeout(timeoutId);
|
|
19242
19242
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -20336,7 +20336,7 @@ var McpServer = class {
|
|
|
20336
20336
|
let task = createTaskResult.task;
|
|
20337
20337
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
20338
20338
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
20339
|
-
await new Promise((
|
|
20339
|
+
await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
|
|
20340
20340
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
20341
20341
|
if (!updatedTask) {
|
|
20342
20342
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -20979,12 +20979,12 @@ var StdioServerTransport = class {
|
|
|
20979
20979
|
this.onclose?.();
|
|
20980
20980
|
}
|
|
20981
20981
|
send(message) {
|
|
20982
|
-
return new Promise((
|
|
20982
|
+
return new Promise((resolve5) => {
|
|
20983
20983
|
const json = serializeMessage(message);
|
|
20984
20984
|
if (this._stdout.write(json)) {
|
|
20985
|
-
|
|
20985
|
+
resolve5();
|
|
20986
20986
|
} else {
|
|
20987
|
-
this._stdout.once("drain",
|
|
20987
|
+
this._stdout.once("drain", resolve5);
|
|
20988
20988
|
}
|
|
20989
20989
|
});
|
|
20990
20990
|
}
|
|
@@ -21207,7 +21207,7 @@ var codesignLoginInput = external_exports.object({
|
|
|
21207
21207
|
loginUrl: external_exports.string().url().optional().describe(`\u53EF\u9009\uFF1B\u9ED8\u8BA4 ${DEFAULT_CODESIGN_LOGIN_URL}`),
|
|
21208
21208
|
userDataDir: external_exports.string().optional().describe("\u6D4F\u89C8\u5668\u7528\u6237\u6570\u636E\u6839\u76EE\u5F55\uFF1B\u672A\u4F20\u65F6\u540C\u6293\u56FE\u5DE5\u5177\uFF08\u73AF\u5883\u53D8\u91CF\u6216\u4E34\u65F6\u76EE\u5F55\uFF09\u3002"),
|
|
21209
21209
|
profileDirectory: external_exports.string().optional().describe(
|
|
21210
|
-
"User Data \u4E0B Edge profile \u76EE\u5F55\u540D\uFF08\u5982 Default\uFF09\uFF1B\u4E0E\u6293\u56FE\u5DE5\u5177
|
|
21210
|
+
"User Data \u4E0B Edge profile \u76EE\u5F55\u540D\uFF08\u5982 Default\uFF09\uFF1B\u4E0E\u6293\u56FE\u5DE5\u5177\u4F7F\u7528\u540C\u4E00\u76EE\u5F55\u65F6\u987B\u4F20\u76F8\u540C\u503C\u3002"
|
|
21211
21211
|
)
|
|
21212
21212
|
});
|
|
21213
21213
|
function registerOpenLoginTool(mcpServer2, deps2) {
|
|
@@ -21243,7 +21243,7 @@ function registerOpenLoginTool(mcpServer2, deps2) {
|
|
|
21243
21243
|
{
|
|
21244
21244
|
loginUrl,
|
|
21245
21245
|
userDataDir: resolve4(persistentDir),
|
|
21246
|
-
hint: "\u5728\u5F39\u51FA\u7684\u6D4F\u89C8\u5668\u4E2D\u5B8C\u6210\u767B\u5F55\u540E\u5173\u95ED\u7A97\u53E3\uFF0C\u518D\u8C03\u7528
|
|
21246
|
+
hint: "\u5728\u5F39\u51FA\u7684\u6D4F\u89C8\u5668\u4E2D\u5B8C\u6210\u767B\u5F55\u540E\u5173\u95ED\u7A97\u53E3\uFF0C\u518D\u8C03\u7528\u6293\u56FE\u5DE5\u5177\uFF08\u5982 codesign_screen_inspect_save\uFF09\u3002"
|
|
21247
21247
|
},
|
|
21248
21248
|
null,
|
|
21249
21249
|
2
|
|
@@ -21253,79 +21253,65 @@ function registerOpenLoginTool(mcpServer2, deps2) {
|
|
|
21253
21253
|
);
|
|
21254
21254
|
}
|
|
21255
21255
|
|
|
21256
|
-
// src/tools/save
|
|
21257
|
-
import { resolve as resolve5, dirname, extname } from "node:path";
|
|
21256
|
+
// src/tools/screen-inspect-save.ts
|
|
21258
21257
|
import { mkdir as mkdir2, writeFile } from "node:fs/promises";
|
|
21259
|
-
|
|
21260
|
-
|
|
21261
|
-
|
|
21262
|
-
|
|
21263
|
-
|
|
21264
|
-
|
|
21265
|
-
|
|
21266
|
-
|
|
21267
|
-
|
|
21268
|
-
|
|
21269
|
-
|
|
21270
|
-
|
|
21271
|
-
|
|
21272
|
-
|
|
21273
|
-
|
|
21274
|
-
|
|
21275
|
-
|
|
21276
|
-
const
|
|
21277
|
-
const
|
|
21278
|
-
|
|
21279
|
-
|
|
21280
|
-
|
|
21281
|
-
|
|
21282
|
-
|
|
21283
|
-
|
|
21284
|
-
|
|
21285
|
-
}
|
|
21286
|
-
|
|
21287
|
-
|
|
21288
|
-
|
|
21289
|
-
|
|
21290
|
-
|
|
21291
|
-
|
|
21292
|
-
|
|
21293
|
-
|
|
21294
|
-
|
|
21295
|
-
|
|
21296
|
-
|
|
21297
|
-
|
|
21298
|
-
const
|
|
21299
|
-
if (!extname(filePath) && inferredExt) {
|
|
21300
|
-
filePath += inferredExt;
|
|
21301
|
-
}
|
|
21302
|
-
const absPath = resolve5(filePath);
|
|
21303
|
-
await mkdir2(dirname(absPath), { recursive: true });
|
|
21304
|
-
let buf;
|
|
21258
|
+
import path from "node:path";
|
|
21259
|
+
|
|
21260
|
+
// src/lib/codesign-page.ts
|
|
21261
|
+
import { chromium as chromium2 } from "playwright";
|
|
21262
|
+
var DEFAULT_CODESIGN_PAGE_DEFAULTS = {
|
|
21263
|
+
headless: true,
|
|
21264
|
+
timeoutMs: 6e4,
|
|
21265
|
+
afterLoadWaitMs: 1e3,
|
|
21266
|
+
networkIdleMaxWaitMs: 3e4
|
|
21267
|
+
};
|
|
21268
|
+
async function withCodesignPage(deps2, input, fn, opts = {}) {
|
|
21269
|
+
const merged = {
|
|
21270
|
+
...DEFAULT_CODESIGN_PAGE_DEFAULTS,
|
|
21271
|
+
...opts.defaults ?? {}
|
|
21272
|
+
};
|
|
21273
|
+
const url = input.url;
|
|
21274
|
+
const headless = input.headless ?? merged.headless;
|
|
21275
|
+
const timeoutMs = input.timeoutMs ?? merged.timeoutMs;
|
|
21276
|
+
const persistentDir = resolveEdgeUserDataDir(input.userDataDir);
|
|
21277
|
+
const context = await chromium2.launchPersistentContext(
|
|
21278
|
+
persistentDir,
|
|
21279
|
+
persistentBrowserContextOptions({
|
|
21280
|
+
headless,
|
|
21281
|
+
profileDirectory: input.profileDirectory,
|
|
21282
|
+
channel: deps2.browserChannel,
|
|
21283
|
+
edgeExecutablePath: deps2.edgeExecutableArg
|
|
21284
|
+
})
|
|
21285
|
+
);
|
|
21286
|
+
try {
|
|
21287
|
+
const page = await context.newPage();
|
|
21288
|
+
page.setDefaultTimeout(timeoutMs);
|
|
21289
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
21290
|
+
try {
|
|
21291
|
+
await page.waitForLoadState("networkidle", {
|
|
21292
|
+
timeout: Math.max(5e3, Math.min(timeoutMs, merged.networkIdleMaxWaitMs))
|
|
21293
|
+
});
|
|
21294
|
+
} catch {
|
|
21295
|
+
}
|
|
21296
|
+
if (opts.waitForSelector?.selector) {
|
|
21297
|
+
const waitTimeout = opts.waitForSelector.timeoutMs ?? Math.max(5e3, Math.floor(timeoutMs * 2 / 3));
|
|
21305
21298
|
try {
|
|
21306
|
-
|
|
21299
|
+
await page.waitForSelector(opts.waitForSelector.selector, {
|
|
21300
|
+
state: opts.waitForSelector.state ?? "attached",
|
|
21301
|
+
timeout: Math.min(timeoutMs, waitTimeout)
|
|
21302
|
+
});
|
|
21307
21303
|
} catch {
|
|
21308
|
-
return toolError("base64 \u89E3\u7801\u5931\u8D25\uFF08\u8BF7\u786E\u8BA4\u4E0D\u662F\u88AB\u622A\u65AD/\u4E0D\u662F base64\uFF09\u3002");
|
|
21309
21304
|
}
|
|
21310
|
-
if (buf.length === 0) return toolError("base64 \u89E3\u7801\u540E\u4E3A\u7A7A\uFF08\u8BF7\u786E\u8BA4\u8F93\u5165\u6B63\u786E\uFF09\u3002");
|
|
21311
|
-
await writeFile(absPath, buf);
|
|
21312
|
-
return toolResult(
|
|
21313
|
-
JSON.stringify(
|
|
21314
|
-
{
|
|
21315
|
-
savedPath: absPath,
|
|
21316
|
-
bytes: buf.length
|
|
21317
|
-
},
|
|
21318
|
-
null,
|
|
21319
|
-
2
|
|
21320
|
-
)
|
|
21321
|
-
);
|
|
21322
21305
|
}
|
|
21323
|
-
|
|
21306
|
+
if (merged.afterLoadWaitMs > 0) {
|
|
21307
|
+
await page.waitForTimeout(merged.afterLoadWaitMs);
|
|
21308
|
+
}
|
|
21309
|
+
return await fn(page, { persistentDir, headless, timeoutMs });
|
|
21310
|
+
} finally {
|
|
21311
|
+
await context.close();
|
|
21312
|
+
}
|
|
21324
21313
|
}
|
|
21325
21314
|
|
|
21326
|
-
// src/tools/screen-inspect.ts
|
|
21327
|
-
import { chromium as chromium2 } from "playwright";
|
|
21328
|
-
|
|
21329
21315
|
// src/lib/screen-inspect-png.ts
|
|
21330
21316
|
async function screenshotLargestScreenInspectPng(page) {
|
|
21331
21317
|
const handles = await page.$$(SCREEN_INSPECT_SELECTOR);
|
|
@@ -21342,8 +21328,26 @@ async function screenshotLargestScreenInspectPng(page) {
|
|
|
21342
21328
|
return { buffer, boundingBox: best.box };
|
|
21343
21329
|
}
|
|
21344
21330
|
|
|
21345
|
-
// src/tools/screen-inspect.ts
|
|
21346
|
-
|
|
21331
|
+
// src/tools/screen-inspect-save.ts
|
|
21332
|
+
function safeSegment(s) {
|
|
21333
|
+
return s.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
21334
|
+
}
|
|
21335
|
+
function timestampCompact(d) {
|
|
21336
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
21337
|
+
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}_${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
|
|
21338
|
+
}
|
|
21339
|
+
function deriveCodesignIds(url) {
|
|
21340
|
+
try {
|
|
21341
|
+
const u = new URL(url);
|
|
21342
|
+
const parts = u.pathname.split("/").filter(Boolean);
|
|
21343
|
+
const projectId = parts.find((p) => /^\d{10,}$/.test(p));
|
|
21344
|
+
const pageId = parts.find((p) => /^\d+$/.test(p));
|
|
21345
|
+
return { projectId, pageId };
|
|
21346
|
+
} catch {
|
|
21347
|
+
return {};
|
|
21348
|
+
}
|
|
21349
|
+
}
|
|
21350
|
+
var screenInspectSaveInput = external_exports.object({
|
|
21347
21351
|
url: external_exports.string().url().describe("CoDesign \u9875\u9762\u5730\u5740"),
|
|
21348
21352
|
headless: external_exports.boolean().optional().describe("\u65E0\u5934\u6A21\u5F0F\uFF0C\u9ED8\u8BA4 true"),
|
|
21349
21353
|
timeoutMs: external_exports.number().int().positive().optional().describe("\u6574\u4F53\u8D85\u65F6\u6BEB\u79D2\u6570\uFF0C\u9ED8\u8BA4 60000"),
|
|
@@ -21352,171 +21356,270 @@ var screenInspectInput = external_exports.object({
|
|
|
21352
21356
|
),
|
|
21353
21357
|
profileDirectory: external_exports.string().optional().describe("User Data \u4E0B\u914D\u7F6E\u540D\uFF0C\u5982 Default\u3002")
|
|
21354
21358
|
});
|
|
21355
|
-
async function
|
|
21356
|
-
|
|
21357
|
-
|
|
21358
|
-
|
|
21359
|
-
|
|
21360
|
-
|
|
21361
|
-
|
|
21362
|
-
|
|
21363
|
-
|
|
21364
|
-
|
|
21365
|
-
|
|
21366
|
-
|
|
21367
|
-
|
|
21368
|
-
|
|
21369
|
-
|
|
21370
|
-
|
|
21371
|
-
|
|
21372
|
-
|
|
21373
|
-
|
|
21374
|
-
await
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
|
|
21379
|
-
|
|
21380
|
-
|
|
21381
|
-
|
|
21382
|
-
|
|
21359
|
+
async function runScreenInspectSave(deps2, input) {
|
|
21360
|
+
return withCodesignPage(
|
|
21361
|
+
deps2,
|
|
21362
|
+
input,
|
|
21363
|
+
async (page) => {
|
|
21364
|
+
const shot = await screenshotLargestScreenInspectPng(page);
|
|
21365
|
+
if (!shot) {
|
|
21366
|
+
return toolError("\u672A\u627E\u5230\u53EF\u89C1\u7684 .screen-inspect \u533A\u57DF\u3002");
|
|
21367
|
+
}
|
|
21368
|
+
const outDir = path.resolve(process.cwd(), ".codesign_screen_imgs");
|
|
21369
|
+
const { projectId, pageId } = deriveCodesignIds(input.url);
|
|
21370
|
+
const filenameParts = [
|
|
21371
|
+
"codesign",
|
|
21372
|
+
projectId ? `p${safeSegment(projectId)}` : void 0,
|
|
21373
|
+
pageId ? `s${safeSegment(pageId)}` : void 0,
|
|
21374
|
+
timestampCompact(/* @__PURE__ */ new Date())
|
|
21375
|
+
].filter(Boolean);
|
|
21376
|
+
const finalPath = path.join(outDir, `${filenameParts.join("_")}.png`);
|
|
21377
|
+
await mkdir2(path.dirname(finalPath), { recursive: true });
|
|
21378
|
+
await writeFile(finalPath, shot.buffer);
|
|
21379
|
+
return toolResult(
|
|
21380
|
+
JSON.stringify(
|
|
21381
|
+
{
|
|
21382
|
+
url: input.url,
|
|
21383
|
+
title: await page.title(),
|
|
21384
|
+
mimeType: "image/png",
|
|
21385
|
+
savedPath: finalPath,
|
|
21386
|
+
boundingBox: shot.boundingBox
|
|
21387
|
+
},
|
|
21388
|
+
null,
|
|
21389
|
+
2
|
|
21390
|
+
)
|
|
21391
|
+
);
|
|
21392
|
+
},
|
|
21393
|
+
{
|
|
21394
|
+
waitForSelector: { selector: ".screen-inspect", state: "visible" },
|
|
21395
|
+
defaults: { afterLoadWaitMs: 250 }
|
|
21383
21396
|
}
|
|
21384
|
-
|
|
21385
|
-
JSON.stringify(
|
|
21386
|
-
{
|
|
21387
|
-
url,
|
|
21388
|
-
title: await page.title(),
|
|
21389
|
-
mimeType: "image/png",
|
|
21390
|
-
imageBase64: shot.buffer.toString("base64"),
|
|
21391
|
-
boundingBox: shot.boundingBox
|
|
21392
|
-
},
|
|
21393
|
-
null,
|
|
21394
|
-
2
|
|
21395
|
-
)
|
|
21396
|
-
);
|
|
21397
|
-
} finally {
|
|
21398
|
-
await context.close();
|
|
21399
|
-
}
|
|
21397
|
+
);
|
|
21400
21398
|
}
|
|
21401
|
-
function
|
|
21399
|
+
function registerScreenInspectSaveTool(mcpServer2, deps2) {
|
|
21402
21400
|
mcpServer2.registerTool(
|
|
21403
|
-
"
|
|
21401
|
+
"codesign_screen_inspect_save",
|
|
21404
21402
|
{
|
|
21405
|
-
description: "\u6253\u5F00 CoDesign \u9875\u9762\uFF0C\u4EC5\u622A\u53D6\u9762\u79EF\u6700\u5927\u7684\u53EF\u89C1 .screen-inspect \u533A\u57DF\uFF0C\
|
|
21406
|
-
inputSchema:
|
|
21403
|
+
description: "\u6253\u5F00 CoDesign \u9875\u9762\uFF0C\u4EC5\u622A\u53D6\u9762\u79EF\u6700\u5927\u7684\u53EF\u89C1 .screen-inspect \u533A\u57DF\uFF0C\u4FDD\u5B58\u4E3A\u672C\u5730 PNG \u6587\u4EF6\u5E76\u8FD4\u56DE\u8DEF\u5F84\uFF08\u9ED8\u8BA4\u4FDD\u5B58\u5230\u9879\u76EE\u6839\u76EE\u5F55 .codesign_screen_imgs\uFF09\u3002",
|
|
21404
|
+
inputSchema: screenInspectSaveInput
|
|
21407
21405
|
},
|
|
21408
|
-
(input) =>
|
|
21406
|
+
(input) => runScreenInspectSave(deps2, input)
|
|
21409
21407
|
);
|
|
21410
21408
|
}
|
|
21411
21409
|
|
|
21412
21410
|
// src/tools/screen-list.ts
|
|
21413
|
-
import { chromium as chromium3 } from "playwright";
|
|
21414
21411
|
var screenListInput = external_exports.object({
|
|
21415
|
-
url: external_exports.string().url().describe(
|
|
21412
|
+
url: external_exports.string().url().describe(
|
|
21413
|
+
"CoDesign \u8BBE\u8BA1\u9875\u9762\u5730\u5740\uFF0C\u5982 https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect"
|
|
21414
|
+
),
|
|
21416
21415
|
headless: external_exports.boolean().optional().describe("\u65E0\u5934\u6A21\u5F0F\uFF0C\u9ED8\u8BA4 true"),
|
|
21417
21416
|
timeoutMs: external_exports.number().int().positive().optional().describe("\u6574\u4F53\u8D85\u65F6\u6BEB\u79D2\u6570\uFF0C\u9ED8\u8BA4 60000"),
|
|
21418
|
-
userDataDir: external_exports.string().optional().describe(
|
|
21419
|
-
"\u6D4F\u89C8\u5668\u7528\u6237\u6570\u636E\u6839\u76EE\u5F55\uFF1B\u672A\u4F20\u65F6\u540C\u6293\u56FE\u5DE5\u5177\uFF08\u73AF\u5883\u53D8\u91CF\u6216\u4E34\u65F6\u76EE\u5F55\uFF09\u3002"
|
|
21420
|
-
),
|
|
21417
|
+
userDataDir: external_exports.string().optional().describe("\u6D4F\u89C8\u5668\u7528\u6237\u6570\u636E\u6839\u76EE\u5F55\uFF1B\u672A\u4F20\u65F6\u540C\u6293\u56FE\u5DE5\u5177\uFF08\u73AF\u5883\u53D8\u91CF\u6216\u4E34\u65F6\u76EE\u5F55\uFF09\u3002"),
|
|
21421
21418
|
profileDirectory: external_exports.string().optional().describe("User Data \u4E0B\u914D\u7F6E\u540D\uFF0C\u5982 Default\u3002")
|
|
21422
21419
|
});
|
|
21423
21420
|
async function runScreenList(deps2, input) {
|
|
21424
|
-
|
|
21425
|
-
|
|
21426
|
-
|
|
21427
|
-
|
|
21428
|
-
|
|
21429
|
-
|
|
21430
|
-
|
|
21431
|
-
|
|
21432
|
-
|
|
21433
|
-
|
|
21434
|
-
|
|
21435
|
-
|
|
21436
|
-
|
|
21437
|
-
|
|
21438
|
-
|
|
21439
|
-
|
|
21440
|
-
|
|
21441
|
-
|
|
21442
|
-
|
|
21443
|
-
|
|
21421
|
+
return withCodesignPage(
|
|
21422
|
+
deps2,
|
|
21423
|
+
input,
|
|
21424
|
+
async (page) => {
|
|
21425
|
+
const pages = await page.evaluate(() => {
|
|
21426
|
+
const items = document.querySelectorAll(".screen-list__item");
|
|
21427
|
+
const result = [];
|
|
21428
|
+
for (const item of items) {
|
|
21429
|
+
const id = item.getAttribute("id") || "";
|
|
21430
|
+
const match = id.match(/^screen-(\d+)$/);
|
|
21431
|
+
if (!match) continue;
|
|
21432
|
+
const pageId = match[1];
|
|
21433
|
+
let name = "";
|
|
21434
|
+
const nameEl = item.querySelector(
|
|
21435
|
+
"[class*='name'], [class*='title'], [class*='label']"
|
|
21436
|
+
);
|
|
21437
|
+
if (nameEl) {
|
|
21438
|
+
name = nameEl.textContent?.trim() || "";
|
|
21439
|
+
}
|
|
21440
|
+
if (!name) {
|
|
21441
|
+
name = item.textContent?.trim().replace(/\s+/g, " ") || "";
|
|
21442
|
+
}
|
|
21443
|
+
result.push({
|
|
21444
|
+
name,
|
|
21445
|
+
pageId
|
|
21446
|
+
});
|
|
21447
|
+
}
|
|
21448
|
+
return result;
|
|
21444
21449
|
});
|
|
21445
|
-
|
|
21450
|
+
if (pages.length === 0) {
|
|
21451
|
+
return toolError("\u672A\u627E\u5230\u5DE6\u4FA7\u83DC\u5355\u4E2D\u7684\u9875\u9762\u5217\u8868\u3002");
|
|
21452
|
+
}
|
|
21453
|
+
const currentUrl = new URL(input.url);
|
|
21454
|
+
const pathParts = currentUrl.pathname.split("/");
|
|
21455
|
+
const projectId = pathParts.find((p) => /^\d{10,}$/.test(p)) || "";
|
|
21456
|
+
const currentPageId = pathParts.find((p) => /^\d+$/.test(p)) || "";
|
|
21457
|
+
const resultData = pages.map((p) => ({
|
|
21458
|
+
name: p.name,
|
|
21459
|
+
pageId: p.pageId,
|
|
21460
|
+
url: projectId ? `https://codesign.qq.com/app/design/${projectId}/${p.pageId}/inspect` : currentPageId ? input.url.replace(`/${currentPageId}/`, `/${p.pageId}/`) : input.url
|
|
21461
|
+
}));
|
|
21462
|
+
return toolResult(
|
|
21463
|
+
JSON.stringify(
|
|
21464
|
+
{
|
|
21465
|
+
projectId,
|
|
21466
|
+
totalCount: resultData.length,
|
|
21467
|
+
pages: resultData
|
|
21468
|
+
},
|
|
21469
|
+
null,
|
|
21470
|
+
2
|
|
21471
|
+
)
|
|
21472
|
+
);
|
|
21473
|
+
},
|
|
21474
|
+
{
|
|
21475
|
+
waitForSelector: { selector: ".screen-list__item", state: "attached" },
|
|
21476
|
+
defaults: { afterLoadWaitMs: 250 }
|
|
21446
21477
|
}
|
|
21447
|
-
|
|
21448
|
-
const pages = await page.evaluate(() => {
|
|
21449
|
-
const items = document.querySelectorAll(".screen-list__item");
|
|
21450
|
-
const result = [];
|
|
21451
|
-
for (const item of items) {
|
|
21452
|
-
const id = item.getAttribute("id") || "";
|
|
21453
|
-
const match = id.match(/^screen-(\d+)$/);
|
|
21454
|
-
if (!match) continue;
|
|
21455
|
-
const pageId = match[1];
|
|
21456
|
-
let name = "";
|
|
21457
|
-
const nameEl = item.querySelector("[class*='name'], [class*='title'], [class*='label']");
|
|
21458
|
-
if (nameEl) {
|
|
21459
|
-
name = nameEl.textContent?.trim() || "";
|
|
21460
|
-
}
|
|
21461
|
-
if (!name) {
|
|
21462
|
-
name = item.textContent?.trim().replace(/\s+/g, " ") || "";
|
|
21463
|
-
}
|
|
21464
|
-
result.push({
|
|
21465
|
-
name,
|
|
21466
|
-
pageId
|
|
21467
|
-
});
|
|
21468
|
-
}
|
|
21469
|
-
return result;
|
|
21470
|
-
});
|
|
21471
|
-
if (pages.length === 0) {
|
|
21472
|
-
return toolError("\u672A\u627E\u5230\u5DE6\u4FA7\u83DC\u5355\u4E2D\u7684\u9875\u9762\u5217\u8868\u3002");
|
|
21473
|
-
}
|
|
21474
|
-
const currentUrl = new URL(url);
|
|
21475
|
-
const pathParts = currentUrl.pathname.split("/");
|
|
21476
|
-
const projectId = pathParts.find((p) => /^\d{10,}$/.test(p)) || "";
|
|
21477
|
-
const resultData = pages.map((p) => ({
|
|
21478
|
-
name: p.name,
|
|
21479
|
-
pageId: p.pageId,
|
|
21480
|
-
url: projectId ? `https://codesign.qq.com/app/design/${projectId}/${p.pageId}/inspect` : p.url.replace("PROJECT_ID", projectId)
|
|
21481
|
-
}));
|
|
21482
|
-
return toolResult(
|
|
21483
|
-
JSON.stringify(
|
|
21484
|
-
{
|
|
21485
|
-
projectId,
|
|
21486
|
-
totalCount: resultData.length,
|
|
21487
|
-
pages: resultData
|
|
21488
|
-
},
|
|
21489
|
-
null,
|
|
21490
|
-
2
|
|
21491
|
-
)
|
|
21492
|
-
);
|
|
21493
|
-
} finally {
|
|
21494
|
-
await context.close();
|
|
21495
|
-
}
|
|
21478
|
+
);
|
|
21496
21479
|
}
|
|
21497
21480
|
function registerScreenListTool(mcpServer2, deps2) {
|
|
21498
21481
|
mcpServer2.registerTool(
|
|
21499
21482
|
"codesign_screen_list",
|
|
21500
21483
|
{
|
|
21501
|
-
description: "\u83B7\u53D6
|
|
21484
|
+
description: "\u6839\u636ECoDesign\u9875\u9762\u5730\u5740\u83B7\u53D6\u9879\u76EE\u6240\u6709\u9875\u9762\u5217\u8868\uFF0C\u8FD4\u56DE\u9879\u76EEID\u3001\u603B\u9875\u9762\u6570\u3001\u9875\u9762\u5217\u8868\u3002",
|
|
21502
21485
|
inputSchema: screenListInput
|
|
21503
21486
|
},
|
|
21504
21487
|
(input) => runScreenList(deps2, input)
|
|
21505
21488
|
);
|
|
21506
21489
|
}
|
|
21507
21490
|
|
|
21491
|
+
// src/tools/screen-viewer-download-save.ts
|
|
21492
|
+
import { mkdir as mkdir3 } from "node:fs/promises";
|
|
21493
|
+
import path2 from "node:path";
|
|
21494
|
+
function safeSegment2(s) {
|
|
21495
|
+
return s.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
21496
|
+
}
|
|
21497
|
+
function timestampCompact2(d) {
|
|
21498
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
21499
|
+
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}_${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
|
|
21500
|
+
}
|
|
21501
|
+
function deriveCodesignIds2(url) {
|
|
21502
|
+
try {
|
|
21503
|
+
const u = new URL(url);
|
|
21504
|
+
const parts = u.pathname.split("/").filter(Boolean);
|
|
21505
|
+
const projectId = parts.find((p) => /^\d{10,}$/.test(p));
|
|
21506
|
+
const pageId = parts.find((p) => /^\d+$/.test(p));
|
|
21507
|
+
return { projectId, pageId };
|
|
21508
|
+
} catch {
|
|
21509
|
+
return {};
|
|
21510
|
+
}
|
|
21511
|
+
}
|
|
21512
|
+
var screenViewerDownloadSaveInput = external_exports.object({
|
|
21513
|
+
url: external_exports.string().url().describe("CoDesign \u9875\u9762\u5730\u5740"),
|
|
21514
|
+
headless: external_exports.boolean().optional().describe("\u65E0\u5934\u6A21\u5F0F\uFF0C\u9ED8\u8BA4 true"),
|
|
21515
|
+
timeoutMs: external_exports.number().int().positive().optional().describe("\u6574\u4F53\u8D85\u65F6\u6BEB\u79D2\u6570\uFF0C\u9ED8\u8BA4 60000"),
|
|
21516
|
+
userDataDir: external_exports.string().optional().describe(
|
|
21517
|
+
"\u6D4F\u89C8\u5668\u7528\u6237\u6570\u636E\u6839\u76EE\u5F55\uFF08\u987B\u5148\u9000\u51FA\u5360\u7528\u8BE5\u76EE\u5F55\u7684\u6D4F\u89C8\u5668\uFF09\u3002\u672A\u4F20\u65F6\u4F7F\u7528\u73AF\u5883\u53D8\u91CF Z_MCP_CODESIGN_EDGE_USER_DATA \u6216\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55\u4E0B\u9ED8\u8BA4\u914D\u7F6E\u3002"
|
|
21518
|
+
),
|
|
21519
|
+
profileDirectory: external_exports.string().optional().describe("User Data \u4E0B\u914D\u7F6E\u540D\uFF0C\u5982 Default\u3002")
|
|
21520
|
+
});
|
|
21521
|
+
async function clickFirstVisibleText(page, candidates) {
|
|
21522
|
+
for (const text of candidates) {
|
|
21523
|
+
const loc = page.getByText(text, { exact: true }).first();
|
|
21524
|
+
try {
|
|
21525
|
+
if (await loc.isVisible()) {
|
|
21526
|
+
await loc.click();
|
|
21527
|
+
return true;
|
|
21528
|
+
}
|
|
21529
|
+
} catch {
|
|
21530
|
+
}
|
|
21531
|
+
}
|
|
21532
|
+
return false;
|
|
21533
|
+
}
|
|
21534
|
+
async function runScreenViewerDownloadSave(deps2, input) {
|
|
21535
|
+
return withCodesignPage(
|
|
21536
|
+
deps2,
|
|
21537
|
+
input,
|
|
21538
|
+
async (page) => {
|
|
21539
|
+
const action = page.locator(".screen-viewer__action").first();
|
|
21540
|
+
try {
|
|
21541
|
+
await action.waitFor({ state: "visible", timeout: 5e3 });
|
|
21542
|
+
} catch {
|
|
21543
|
+
return toolError(
|
|
21544
|
+
"\u672A\u627E\u5230\u53EF\u89C1\u7684 .screen-viewer__action\uFF08\u53EF\u80FD\u672A\u8FDB\u5165\u53EF\u4E0B\u8F7D\u7684\u753B\u677F\u89C6\u56FE\uFF09\u3002"
|
|
21545
|
+
);
|
|
21546
|
+
}
|
|
21547
|
+
const downloadPromise = page.waitForEvent("download", {
|
|
21548
|
+
timeout: Math.max(1e4, Math.min(45e3, input.timeoutMs ?? 6e4))
|
|
21549
|
+
});
|
|
21550
|
+
await action.click();
|
|
21551
|
+
const clicked = await clickFirstVisibleText(page, [
|
|
21552
|
+
"\u4E0B\u8F7D\u56FE\u7247",
|
|
21553
|
+
"\u4E0B\u8F7D\u539F\u56FE",
|
|
21554
|
+
"\u4E0B\u8F7D"
|
|
21555
|
+
]);
|
|
21556
|
+
if (!clicked) {
|
|
21557
|
+
return toolError(
|
|
21558
|
+
"\u672A\u627E\u5230\u201C\u4E0B\u8F7D\u56FE\u7247\u201D\u6309\u94AE/\u83DC\u5355\u9879\uFF08\u53EF\u80FD\u9875\u9762\u7ED3\u6784\u53D8\u66F4\u6216\u672A\u767B\u5F55\uFF09\u3002"
|
|
21559
|
+
);
|
|
21560
|
+
}
|
|
21561
|
+
let download;
|
|
21562
|
+
try {
|
|
21563
|
+
download = await downloadPromise;
|
|
21564
|
+
} catch {
|
|
21565
|
+
return toolError("\u672A\u6355\u83B7\u5230\u4E0B\u8F7D\u4E8B\u4EF6\uFF08\u70B9\u51FB\u540E\u672A\u89E6\u53D1\u4E0B\u8F7D\uFF09\u3002");
|
|
21566
|
+
}
|
|
21567
|
+
const suggested = download.suggestedFilename() || "codesign_download.png";
|
|
21568
|
+
const ext = path2.extname(suggested) || ".png";
|
|
21569
|
+
const outDir = path2.resolve(process.cwd(), ".codesign_screen_imgs");
|
|
21570
|
+
const { projectId, pageId } = deriveCodesignIds2(input.url);
|
|
21571
|
+
const filenameParts = [
|
|
21572
|
+
"codesign",
|
|
21573
|
+
"viewer_download",
|
|
21574
|
+
projectId ? `p${safeSegment2(projectId)}` : void 0,
|
|
21575
|
+
pageId ? `s${safeSegment2(pageId)}` : void 0,
|
|
21576
|
+
timestampCompact2(/* @__PURE__ */ new Date())
|
|
21577
|
+
].filter(Boolean);
|
|
21578
|
+
const finalPath = path2.join(outDir, `${filenameParts.join("_")}${ext}`);
|
|
21579
|
+
await mkdir3(path2.dirname(finalPath), { recursive: true });
|
|
21580
|
+
await download.saveAs(finalPath);
|
|
21581
|
+
return toolResult(
|
|
21582
|
+
JSON.stringify(
|
|
21583
|
+
{
|
|
21584
|
+
url: input.url,
|
|
21585
|
+
title: await page.title(),
|
|
21586
|
+
suggestedFilename: suggested,
|
|
21587
|
+
savedPath: finalPath
|
|
21588
|
+
},
|
|
21589
|
+
null,
|
|
21590
|
+
2
|
|
21591
|
+
)
|
|
21592
|
+
);
|
|
21593
|
+
},
|
|
21594
|
+
{
|
|
21595
|
+
waitForSelector: { selector: ".screen-viewer__action", state: "visible" },
|
|
21596
|
+
defaults: { afterLoadWaitMs: 600, networkIdleMaxWaitMs: 2e3 }
|
|
21597
|
+
}
|
|
21598
|
+
);
|
|
21599
|
+
}
|
|
21600
|
+
function registerScreenViewerDownloadSaveTool(mcpServer2, deps2) {
|
|
21601
|
+
mcpServer2.registerTool(
|
|
21602
|
+
"codesign_screen_viewer_download_save",
|
|
21603
|
+
{
|
|
21604
|
+
description: "\u6253\u5F00 CoDesign \u9875\u9762\uFF0C\u70B9\u51FB .screen-viewer__action \u540E\u9009\u62E9\u201C\u4E0B\u8F7D\u56FE\u7247\u201D\uFF0C\u6355\u83B7\u6D4F\u89C8\u5668\u4E0B\u8F7D\u5E76\u4FDD\u5B58\u5230\u9879\u76EE\u6839\u76EE\u5F55 .codesign_screen_imgs/\u3002",
|
|
21605
|
+
inputSchema: screenViewerDownloadSaveInput
|
|
21606
|
+
},
|
|
21607
|
+
(input) => runScreenViewerDownloadSave(deps2, input)
|
|
21608
|
+
);
|
|
21609
|
+
}
|
|
21610
|
+
|
|
21508
21611
|
// src/tools/register-all.ts
|
|
21509
21612
|
function registerAllCodesignTools(mcpServer2, deps2) {
|
|
21510
|
-
|
|
21613
|
+
registerScreenInspectSaveTool(mcpServer2, deps2);
|
|
21614
|
+
registerScreenViewerDownloadSaveTool(mcpServer2, deps2);
|
|
21511
21615
|
registerScreenListTool(mcpServer2, deps2);
|
|
21512
21616
|
registerOpenLoginTool(mcpServer2, deps2);
|
|
21513
|
-
registerSaveImageTool(mcpServer2);
|
|
21514
21617
|
}
|
|
21515
21618
|
|
|
21516
21619
|
// src/index.ts
|
|
21517
21620
|
var SERVER_NAME = "z-mcp-codesign";
|
|
21518
21621
|
var _require = createRequire(import.meta.url);
|
|
21519
|
-
var _dirname =
|
|
21622
|
+
var _dirname = dirname(fileURLToPath(import.meta.url));
|
|
21520
21623
|
var SERVER_VERSION = _require(join4(_dirname, "..", "package.json")).version ?? "1.0.0";
|
|
21521
21624
|
var USAGE = "npx -y z-mcp-codesign --stdio";
|
|
21522
21625
|
var args = process.argv.slice(2);
|