z-mcp-codesign 0.1.2 → 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.
Files changed (3) hide show
  1. package/README.md +12 -8
  2. package/dist/index.js +155 -154
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -28,8 +28,8 @@
28
28
  | 工具名 | 说明 |
29
29
  | ------ | ---- |
30
30
  | `codesign_open_login` | 有界面打开 CoDesign 登录页,用于在本机 Edge 用户数据目录中完成登录 |
31
- | `codesign_screen_inspect` | 打开指定 CoDesign 页面,截取最大的可见 `.screen-inspect` 区域,以 PNG 的 base64 返回 |
32
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
33
  | `codesign_screen_list` | 获取 CoDesign 设计页面左侧菜单中的所有页面名称和访问地址 |
34
34
 
35
35
  # 使用示例
@@ -37,30 +37,34 @@
37
37
  **打开登录页(用于后续抓图)**
38
38
 
39
39
  ```bash
40
- 请在本机用可见浏览器打开 CoDesign 登录页
40
+ 使用MCP 打开 CoDesign 登录页
41
41
  ```
42
42
 
43
43
  **列出当前项目的页面列表**
44
44
 
45
45
  ```bash
46
- 请打开这个 CoDesign inspect 链接,并把左侧菜单里的页面列表整理出来(包含每个页面的名称和对应的 inspect 访问地址):https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
46
+ 使用MCP 获取CoDesign所有页面列表使用表格展示。
47
+ URL为:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
47
48
  ```
48
49
 
49
- **抓图并返回图片(base64)**
50
+ **抓图并保存到本地**
50
51
 
51
52
  ```bash
52
- 请打开这个 CoDesign inspect 链接 把截图以 base64 返回给我:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
53
+ 使用MCP 获取CoDesign页面图片,把截图保存到本地,并告诉我保存路径。
54
+ URL为:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
53
55
  ```
54
56
 
55
- **抓图并保存到本地**
57
+ **通过页面“下载图片”保存到本地**
56
58
 
57
59
  ```bash
58
- 请打开这个 CoDesign inspect 链接,获取图片,把截图保存到本地,并告诉我保存路径:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
60
+ 使用MCP 打开CoDesign页面,下载图片保存到本地,并告诉我保存路径。
61
+ URL为:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
59
62
  ```
60
63
 
61
64
  **生成项目**
62
65
 
63
66
  ```bash
64
- 请打开这个 CoDesign inspect 链接,获取图片,把截图保存到本地,并识别图片内容生成Vue3+Vite项目:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
67
+ 使用MCP 打开CoDesign页面,下载图片保存到本地,并识别图片内容生成Vue3+Vite项目。
68
+ URL为:https://codesign.qq.com/app/design/<projectId>/<pageId>/inspect
65
69
  ```
66
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 = resolve6.call(this, root, ref);
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 resolve6(root, ref) {
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(path2) {
3226
- let input = path2;
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 [path2, query] = wsComponent.resourceName.split("?");
3426
- wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
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 resolve6(baseURI, relativeURI, options) {
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: resolve6,
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 as dirname2, join as join4 } from "node:path";
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: path2, errorMaps, issueData } = params;
7285
- const fullPath = [...path2, ...issueData.path || []];
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, path2, key) {
7401
+ constructor(parent, value, path3, key) {
7402
7402
  this._cachedPath = [];
7403
7403
  this.parent = parent;
7404
7404
  this.data = value;
7405
- this._path = path2;
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, path2) {
11043
- if (!path2)
11042
+ function getElementAtPath(obj, path3) {
11043
+ if (!path3)
11044
11044
  return obj;
11045
- return path2.reduce((acc, key) => acc?.[key], obj);
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(path2, issues) {
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(path2);
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((resolve6) => setTimeout(resolve6, pollInterval));
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((resolve6, reject) => {
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
- resolve6(parseResult.data);
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((resolve6, reject) => {
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(resolve6, interval);
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((resolve6) => setTimeout(resolve6, pollInterval));
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((resolve6) => {
20982
+ return new Promise((resolve5) => {
20983
20983
  const json = serializeMessage(message);
20984
20984
  if (this._stdout.write(json)) {
20985
- resolve6();
20985
+ resolve5();
20986
20986
  } else {
20987
- this._stdout.once("drain", resolve6);
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 codesign_screen_inspect \u4F7F\u7528\u540C\u4E00\u76EE\u5F55\u65F6\u987B\u4F20\u76F8\u540C\u503C\u3002"
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 codesign_screen_inspect\u3002"
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,75 +21253,9 @@ function registerOpenLoginTool(mcpServer2, deps2) {
21253
21253
  );
21254
21254
  }
21255
21255
 
21256
- // src/tools/save-image.ts
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
- var saveImageInput = external_exports.object({
21260
- imageBase64: external_exports.string().min(1).describe(
21261
- "\u56FE\u7247 base64\uFF1B\u652F\u6301\u7EAF base64\uFF0C\u6216 data URL\uFF08\u5982 data:image/png;base64,AAAA...\uFF09\u3002"
21262
- ),
21263
- filePath: external_exports.string().min(1).describe("\u4FDD\u5B58\u8DEF\u5F84\uFF08\u76F8\u5BF9\u6216\u7EDD\u5BF9\uFF09\uFF0C\u5982 ./out/shot.png \u6216 D:/tmp/shot.png"),
21264
- mimeType: external_exports.string().optional().describe("\u53EF\u9009\uFF1B\u7528\u4E8E\u63A8\u65AD\u6269\u5C55\u540D\uFF08\u5F53 filePath \u65E0\u6269\u5C55\u540D\u65F6\uFF09\u3002\u5982 image/png")
21265
- });
21266
- function extFromMime(mimeType) {
21267
- const m = (mimeType || "").trim().toLowerCase();
21268
- if (!m) return null;
21269
- if (m === "image/png") return ".png";
21270
- if (m === "image/jpeg" || m === "image/jpg") return ".jpg";
21271
- if (m === "image/webp") return ".webp";
21272
- if (m === "image/gif") return ".gif";
21273
- return null;
21274
- }
21275
- function parseBase64(input) {
21276
- const s = input.trim();
21277
- const m = s.match(/^data:([^;]+);base64,(.*)$/i);
21278
- if (m) {
21279
- const mimeType = m[1]?.trim();
21280
- const base642 = (m[2] || "").trim();
21281
- if (!base642) return null;
21282
- return { mimeType, base64: base642 };
21283
- }
21284
- return { base64: s };
21285
- }
21286
- function registerSaveImageTool(mcpServer2) {
21287
- mcpServer2.registerTool(
21288
- "codesign_save_image",
21289
- {
21290
- description: "\u5C06 base64 \u56FE\u7247\u4FDD\u5B58\u4E3A\u672C\u5730\u6587\u4EF6\u8DEF\u5F84\u3002",
21291
- inputSchema: saveImageInput
21292
- },
21293
- async (input) => {
21294
- const parsed = parseBase64(input.imageBase64);
21295
- if (!parsed) return toolError("imageBase64 \u4E3A\u7A7A\u6216\u4E0D\u662F\u5408\u6CD5\u7684 base64/dataURL\u3002");
21296
- let filePath = input.filePath.trim();
21297
- if (!filePath) return toolError("filePath \u4E0D\u80FD\u4E3A\u7A7A\u3002");
21298
- const inferredExt = extFromMime(parsed.mimeType) || extFromMime(input.mimeType);
21299
- if (!extname(filePath) && inferredExt) {
21300
- filePath += inferredExt;
21301
- }
21302
- const absPath = resolve5(filePath);
21303
- await mkdir2(dirname(absPath), { recursive: true });
21304
- let buf;
21305
- try {
21306
- buf = Buffer.from(parsed.base64, "base64");
21307
- } catch {
21308
- return toolError("base64 \u89E3\u7801\u5931\u8D25\uFF08\u8BF7\u786E\u8BA4\u4E0D\u662F\u88AB\u622A\u65AD/\u4E0D\u662F base64\uFF09\u3002");
21309
- }
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
- }
21323
- );
21324
- }
21258
+ import path from "node:path";
21325
21259
 
21326
21260
  // src/lib/codesign-page.ts
21327
21261
  import { chromium as chromium2 } from "playwright";
@@ -21394,59 +21328,7 @@ async function screenshotLargestScreenInspectPng(page) {
21394
21328
  return { buffer, boundingBox: best.box };
21395
21329
  }
21396
21330
 
21397
- // src/tools/screen-inspect.ts
21398
- var screenInspectInput = external_exports.object({
21399
- url: external_exports.string().url().describe("CoDesign \u9875\u9762\u5730\u5740"),
21400
- headless: external_exports.boolean().optional().describe("\u65E0\u5934\u6A21\u5F0F\uFF0C\u9ED8\u8BA4 true"),
21401
- timeoutMs: external_exports.number().int().positive().optional().describe("\u6574\u4F53\u8D85\u65F6\u6BEB\u79D2\u6570\uFF0C\u9ED8\u8BA4 60000"),
21402
- userDataDir: external_exports.string().optional().describe(
21403
- "\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"
21404
- ),
21405
- profileDirectory: external_exports.string().optional().describe("User Data \u4E0B\u914D\u7F6E\u540D\uFF0C\u5982 Default\u3002")
21406
- });
21407
- async function runScreenInspect(deps2, input) {
21408
- return withCodesignPage(
21409
- deps2,
21410
- input,
21411
- async (page) => {
21412
- const shot = await screenshotLargestScreenInspectPng(page);
21413
- if (!shot) {
21414
- return toolError("\u672A\u627E\u5230\u53EF\u89C1\u7684 .screen-inspect \u533A\u57DF\u3002");
21415
- }
21416
- return toolResult(
21417
- JSON.stringify(
21418
- {
21419
- url: input.url,
21420
- title: await page.title(),
21421
- mimeType: "image/png",
21422
- imageBase64: shot.buffer.toString("base64"),
21423
- boundingBox: shot.boundingBox
21424
- },
21425
- null,
21426
- 2
21427
- )
21428
- );
21429
- },
21430
- {
21431
- waitForSelector: { selector: ".screen-inspect", state: "visible" },
21432
- defaults: { afterLoadWaitMs: 250 }
21433
- }
21434
- );
21435
- }
21436
- function registerScreenInspectTool(mcpServer2, deps2) {
21437
- mcpServer2.registerTool(
21438
- "codesign_screen_inspect",
21439
- {
21440
- description: "\u6253\u5F00 CoDesign \u9875\u9762\uFF0C\u4EC5\u622A\u53D6\u9762\u79EF\u6700\u5927\u7684\u53EF\u89C1 .screen-inspect \u533A\u57DF\uFF0C\u4EE5 PNG \u7684 base64 \u8FD4\u56DE\u3002",
21441
- inputSchema: screenInspectInput
21442
- },
21443
- (input) => runScreenInspect(deps2, input)
21444
- );
21445
- }
21446
-
21447
21331
  // src/tools/screen-inspect-save.ts
21448
- import { mkdir as mkdir3, writeFile as writeFile2 } from "node:fs/promises";
21449
- import path from "node:path";
21450
21332
  function safeSegment(s) {
21451
21333
  return s.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
21452
21334
  }
@@ -21492,8 +21374,8 @@ async function runScreenInspectSave(deps2, input) {
21492
21374
  timestampCompact(/* @__PURE__ */ new Date())
21493
21375
  ].filter(Boolean);
21494
21376
  const finalPath = path.join(outDir, `${filenameParts.join("_")}.png`);
21495
- await mkdir3(path.dirname(finalPath), { recursive: true });
21496
- await writeFile2(finalPath, shot.buffer);
21377
+ await mkdir2(path.dirname(finalPath), { recursive: true });
21378
+ await writeFile(finalPath, shot.buffer);
21497
21379
  return toolResult(
21498
21380
  JSON.stringify(
21499
21381
  {
@@ -21606,19 +21488,138 @@ function registerScreenListTool(mcpServer2, deps2) {
21606
21488
  );
21607
21489
  }
21608
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
+
21609
21611
  // src/tools/register-all.ts
21610
21612
  function registerAllCodesignTools(mcpServer2, deps2) {
21611
- registerScreenInspectTool(mcpServer2, deps2);
21612
21613
  registerScreenInspectSaveTool(mcpServer2, deps2);
21614
+ registerScreenViewerDownloadSaveTool(mcpServer2, deps2);
21613
21615
  registerScreenListTool(mcpServer2, deps2);
21614
21616
  registerOpenLoginTool(mcpServer2, deps2);
21615
- registerSaveImageTool(mcpServer2);
21616
21617
  }
21617
21618
 
21618
21619
  // src/index.ts
21619
21620
  var SERVER_NAME = "z-mcp-codesign";
21620
21621
  var _require = createRequire(import.meta.url);
21621
- var _dirname = dirname2(fileURLToPath(import.meta.url));
21622
+ var _dirname = dirname(fileURLToPath(import.meta.url));
21622
21623
  var SERVER_VERSION = _require(join4(_dirname, "..", "package.json")).version ?? "1.0.0";
21623
21624
  var USAGE = "npx -y z-mcp-codesign --stdio";
21624
21625
  var args = process.argv.slice(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "z-mcp-codesign",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "An MCP server to capture images from Tencent CoDesign pages via Edge",
6
6
  "main": "dist/index.js",