@hangox/mg-cli 1.0.2 → 1.0.4

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/dist/cli.js CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/index.ts
4
- import { Command as Command8 } from "commander";
4
+ import { Command as Command9 } from "commander";
5
5
 
6
6
  // src/cli/commands/server.ts
7
7
  import { Command } from "commander";
8
8
 
9
9
  // src/server/daemon.ts
10
10
  import { spawn } from "child_process";
11
- import { fileURLToPath } from "url";
12
- import { dirname as dirname3, join as join2 } from "path";
11
+ import { fileURLToPath as fileURLToPath2 } from "url";
12
+ import { dirname as dirname4, join as join3 } from "path";
13
13
 
14
14
  // src/shared/utils.ts
15
15
  import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
@@ -175,6 +175,152 @@ function extractFileId(input) {
175
175
  }
176
176
  return extractFileIdFromUrl(trimmed);
177
177
  }
178
+ var NUMERIC_FIELDS = [
179
+ "x",
180
+ "y",
181
+ "width",
182
+ "height",
183
+ "rotation",
184
+ "opacity",
185
+ "cornerRadius",
186
+ "topLeftRadius",
187
+ "topRightRadius",
188
+ "bottomLeftRadius",
189
+ "bottomRightRadius",
190
+ "strokeWeight",
191
+ "strokeTopWeight",
192
+ "strokeLeftWeight",
193
+ "strokeBottomWeight",
194
+ "strokeRightWeight",
195
+ "paddingTop",
196
+ "paddingRight",
197
+ "paddingBottom",
198
+ "paddingLeft",
199
+ "itemSpacing",
200
+ "crossAxisSpacing",
201
+ "flexGrow"
202
+ ];
203
+ function roundToOneDecimal(value) {
204
+ return Math.round(value * 10) / 10;
205
+ }
206
+ var NODE_DEFAULTS = {
207
+ // Scene Node 属性
208
+ visible: true,
209
+ isVisible: true,
210
+ isLocked: false,
211
+ // Blend 属性
212
+ opacity: 1,
213
+ blendMode: "NORMAL",
214
+ isMask: false,
215
+ isMaskOutline: false,
216
+ isMaskVisible: false,
217
+ effectStyleId: "",
218
+ // Geometry 属性
219
+ strokeStyle: "SOLID",
220
+ strokeWeight: 0,
221
+ strokeTopWeight: 0,
222
+ strokeLeftWeight: 0,
223
+ strokeBottomWeight: 0,
224
+ strokeRightWeight: 0,
225
+ strokeAlign: "CENTER",
226
+ strokeCap: "NONE",
227
+ strokeJoin: "MITER",
228
+ dashCap: "NONE",
229
+ fillStyleId: "",
230
+ strokeStyleId: "",
231
+ // Corner 属性
232
+ cornerSmooth: 0,
233
+ cornerRadius: 0,
234
+ topLeftRadius: 0,
235
+ topRightRadius: 0,
236
+ bottomLeftRadius: 0,
237
+ bottomRightRadius: 0,
238
+ // Layout 属性
239
+ rotation: 0,
240
+ flexGrow: 0,
241
+ alignSelf: "INHERIT",
242
+ layoutPositioning: "AUTO",
243
+ constrainProportions: false,
244
+ // 容器专属属性 (FrameNode)
245
+ flexMode: "NONE",
246
+ flexWrap: "NO_WRAP",
247
+ itemSpacing: 0,
248
+ crossAxisSpacing: 0,
249
+ paddingTop: 0,
250
+ paddingRight: 0,
251
+ paddingBottom: 0,
252
+ paddingLeft: 0,
253
+ clipsContent: false,
254
+ itemReverseZIndex: false,
255
+ strokesIncludedInLayout: false,
256
+ // 其他属性
257
+ componentPropertyReferences: null
258
+ };
259
+ var EMPTY_ARRAY_FIELDS = [
260
+ "fills",
261
+ "strokes",
262
+ "effects",
263
+ "strokeDashes",
264
+ "exportSettings",
265
+ "reactions",
266
+ "attachedConnectors"
267
+ ];
268
+ function isEmptyArray(value) {
269
+ return Array.isArray(value) && value.length === 0;
270
+ }
271
+ function isEqual(a, b) {
272
+ if (a === b) return true;
273
+ if (a === null || b === null) return a === b;
274
+ if (typeof a !== typeof b) return false;
275
+ return false;
276
+ }
277
+ function trimNodeDefaults(node) {
278
+ const result = {};
279
+ for (const [key, value] of Object.entries(node)) {
280
+ if (key === "children" && Array.isArray(value)) {
281
+ const trimmedChildren = value.map(
282
+ (child) => typeof child === "object" && child !== null ? trimNodeDefaults(child) : child
283
+ );
284
+ if (trimmedChildren.length > 0) {
285
+ result[key] = trimmedChildren;
286
+ }
287
+ continue;
288
+ }
289
+ if (EMPTY_ARRAY_FIELDS.includes(key) && isEmptyArray(value)) {
290
+ continue;
291
+ }
292
+ if (NUMERIC_FIELDS.includes(key) && typeof value === "number") {
293
+ const roundedValue = roundToOneDecimal(value);
294
+ if (key in NODE_DEFAULTS && isEqual(roundedValue, NODE_DEFAULTS[key])) {
295
+ continue;
296
+ }
297
+ result[key] = roundedValue;
298
+ continue;
299
+ }
300
+ if (key in NODE_DEFAULTS) {
301
+ const defaultValue = NODE_DEFAULTS[key];
302
+ if (isEqual(value, defaultValue)) {
303
+ continue;
304
+ }
305
+ }
306
+ result[key] = value;
307
+ }
308
+ return result;
309
+ }
310
+ function extractSpaceInfo(node) {
311
+ const result = {
312
+ id: node.id,
313
+ name: node.name,
314
+ x: roundToOneDecimal(typeof node.x === "number" ? node.x : 0),
315
+ y: roundToOneDecimal(typeof node.y === "number" ? node.y : 0),
316
+ width: roundToOneDecimal(typeof node.width === "number" ? node.width : 0),
317
+ height: roundToOneDecimal(typeof node.height === "number" ? node.height : 0)
318
+ };
319
+ if (node.children && Array.isArray(node.children) && node.children.length > 0) {
320
+ result.children = node.children.map((child) => extractSpaceInfo(child));
321
+ }
322
+ return result;
323
+ }
178
324
 
179
325
  // src/shared/errors.ts
180
326
  var ErrorNames = {
@@ -608,6 +754,44 @@ var RequestHandler = class {
608
754
  }
609
755
  };
610
756
 
757
+ // src/shared/version.ts
758
+ import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
759
+ import { fileURLToPath } from "url";
760
+ import { dirname as dirname3, join as join2 } from "path";
761
+ var cachedVersion = null;
762
+ function getVersion() {
763
+ if (cachedVersion !== null) {
764
+ return cachedVersion;
765
+ }
766
+ try {
767
+ const currentFile = fileURLToPath(import.meta.url);
768
+ const currentDir = dirname3(currentFile);
769
+ const possiblePaths = [
770
+ join2(currentDir, "..", "package.json"),
771
+ // dist/xxx.js -> ../package.json
772
+ join2(currentDir, "..", "..", "package.json")
773
+ // src/shared/version.ts -> ../../package.json
774
+ ];
775
+ for (const packageJsonPath of possiblePaths) {
776
+ if (existsSync3(packageJsonPath)) {
777
+ const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
778
+ if (packageJson.name === "@hangox/mg-cli") {
779
+ cachedVersion = packageJson.version || "0.0.0";
780
+ return cachedVersion;
781
+ }
782
+ }
783
+ }
784
+ cachedVersion = "0.0.0";
785
+ return cachedVersion;
786
+ } catch {
787
+ cachedVersion = "0.0.0";
788
+ return cachedVersion;
789
+ }
790
+ }
791
+ function isVersionMatch(version1, version2) {
792
+ return version1 === version2;
793
+ }
794
+
611
795
  // src/server/websocket-server.ts
612
796
  var MGServer = class {
613
797
  wss = null;
@@ -616,6 +800,7 @@ var MGServer = class {
616
800
  requestHandler;
617
801
  port;
618
802
  isRunning = false;
803
+ startedAt = null;
619
804
  constructor(options = {}) {
620
805
  this.port = options.port || DEFAULT_PORT;
621
806
  this.logger = options.logger || createLogger();
@@ -630,14 +815,15 @@ var MGServer = class {
630
815
  throw new MGError("E016" /* SERVER_ALREADY_RUNNING */, "Server \u5DF2\u5728\u8FD0\u884C\u4E2D");
631
816
  }
632
817
  const port = await this.findAvailablePort();
633
- return new Promise((resolve7, reject) => {
818
+ return new Promise((resolve8, reject) => {
634
819
  this.wss = new WebSocketServer({ port });
635
820
  this.wss.on("listening", () => {
636
821
  this.port = port;
637
822
  this.isRunning = true;
823
+ this.startedAt = /* @__PURE__ */ new Date();
638
824
  this.logger.info(`Server \u542F\u52A8\u6210\u529F\uFF0C\u76D1\u542C\u7AEF\u53E3: ${port}`);
639
825
  this.connectionManager.startHeartbeatCheck(HEARTBEAT_INTERVAL);
640
- resolve7(port);
826
+ resolve8(port);
641
827
  });
642
828
  this.wss.on("error", (error) => {
643
829
  this.logger.error("Server \u9519\u8BEF:", error);
@@ -668,14 +854,14 @@ var MGServer = class {
668
854
  * 检查端口是否可用
669
855
  */
670
856
  isPortAvailable(port) {
671
- return new Promise((resolve7) => {
857
+ return new Promise((resolve8) => {
672
858
  const testServer = new WebSocketServer({ port });
673
859
  testServer.on("listening", () => {
674
860
  testServer.close();
675
- resolve7(true);
861
+ resolve8(true);
676
862
  });
677
863
  testServer.on("error", () => {
678
- resolve7(false);
864
+ resolve8(false);
679
865
  });
680
866
  });
681
867
  }
@@ -735,7 +921,8 @@ var MGServer = class {
735
921
  success: true,
736
922
  data: {
737
923
  connectionId: managedWs.connectionId,
738
- pageUrl
924
+ pageUrl,
925
+ serverVersion: getVersion()
739
926
  }
740
927
  };
741
928
  ws.send(JSON.stringify(ack));
@@ -749,6 +936,9 @@ var MGServer = class {
749
936
  case "ping" /* PING */:
750
937
  this.handlePing(ws, message);
751
938
  break;
939
+ case "get_server_status" /* GET_SERVER_STATUS */:
940
+ this.handleGetServerStatus(ws, message);
941
+ break;
752
942
  case "response" /* RESPONSE */:
753
943
  case "error" /* ERROR */:
754
944
  this.requestHandler.handleResponse(message);
@@ -770,6 +960,37 @@ var MGServer = class {
770
960
  };
771
961
  ws.send(JSON.stringify(pong));
772
962
  }
963
+ /**
964
+ * 处理 Server 状态查询
965
+ */
966
+ handleGetServerStatus(ws, message) {
967
+ const providers = this.connectionManager.getAllProviders();
968
+ const stats = this.connectionManager.getStats();
969
+ const connectedPages = providers.map((info) => ({
970
+ pageUrl: info.pageUrl || "",
971
+ connectedAt: info.connectedAt.toISOString(),
972
+ lastActiveAt: info.lastActiveAt.toISOString()
973
+ }));
974
+ const uptimeMs = this.startedAt ? Date.now() - this.startedAt.getTime() : 0;
975
+ const statusData = {
976
+ running: this.isRunning,
977
+ port: this.port,
978
+ pid: process.pid,
979
+ startedAt: this.startedAt?.toISOString() || "",
980
+ uptime: formatDuration(uptimeMs),
981
+ version: getVersion(),
982
+ stats,
983
+ connectedPages
984
+ };
985
+ const response = {
986
+ id: message.id || "",
987
+ type: "response" /* RESPONSE */,
988
+ success: true,
989
+ data: statusData
990
+ };
991
+ ws.send(JSON.stringify(response));
992
+ this.logger.info("\u8FD4\u56DE Server \u72B6\u6001\u4FE1\u606F");
993
+ }
773
994
  /**
774
995
  * 停止服务器
775
996
  */
@@ -780,12 +1001,12 @@ var MGServer = class {
780
1001
  this.logger.info("\u6B63\u5728\u505C\u6B62 Server...");
781
1002
  this.requestHandler.cleanupAll();
782
1003
  this.connectionManager.closeAll();
783
- return new Promise((resolve7) => {
1004
+ return new Promise((resolve8) => {
784
1005
  this.wss.close(() => {
785
1006
  this.isRunning = false;
786
1007
  this.wss = null;
787
1008
  this.logger.info("Server \u5DF2\u505C\u6B62");
788
- resolve7();
1009
+ resolve8();
789
1010
  });
790
1011
  });
791
1012
  }
@@ -860,7 +1081,8 @@ async function startServerForeground(port) {
860
1081
  writeServerInfo({
861
1082
  port: actualPort,
862
1083
  pid: process.pid,
863
- startedAt: getCurrentISOTime()
1084
+ startedAt: getCurrentISOTime(),
1085
+ version: getVersion()
864
1086
  });
865
1087
  console.log(`
866
1088
  MG Server \u542F\u52A8\u6210\u529F`);
@@ -883,9 +1105,9 @@ async function startServerDaemon(port) {
883
1105
  );
884
1106
  }
885
1107
  ensureConfigDir();
886
- const currentFile = fileURLToPath(import.meta.url);
887
- const currentDir = dirname3(currentFile);
888
- const serverScript = join2(currentDir, "daemon-runner.js");
1108
+ const currentFile = fileURLToPath2(import.meta.url);
1109
+ const currentDir = dirname4(currentFile);
1110
+ const serverScript = join3(currentDir, "daemon-runner.js");
889
1111
  const args = ["--foreground"];
890
1112
  if (port) {
891
1113
  args.push("--port", String(port));
@@ -901,7 +1123,7 @@ async function startServerDaemon(port) {
901
1123
  child.unref();
902
1124
  const startTime = Date.now();
903
1125
  while (Date.now() - startTime < SERVER_START_TIMEOUT) {
904
- await new Promise((resolve7) => setTimeout(resolve7, 200));
1126
+ await new Promise((resolve8) => setTimeout(resolve8, 200));
905
1127
  const { running: running2, info: info2 } = isServerRunning();
906
1128
  if (running2 && info2) {
907
1129
  return info2;
@@ -922,7 +1144,7 @@ function stopServer() {
922
1144
  }
923
1145
  async function restartServer(port) {
924
1146
  const { info: oldInfo } = stopServer();
925
- await new Promise((resolve7) => setTimeout(resolve7, 500));
1147
+ await new Promise((resolve8) => setTimeout(resolve8, 500));
926
1148
  return startServerDaemon(port || oldInfo?.port);
927
1149
  }
928
1150
  function getServerStatus() {
@@ -936,98 +1158,11 @@ function getServerStatus() {
936
1158
  port: info.port,
937
1159
  pid: info.pid,
938
1160
  startedAt: info.startedAt,
939
- uptime: formatDuration(uptimeMs)
1161
+ uptime: formatDuration(uptimeMs),
1162
+ version: info.version
940
1163
  };
941
1164
  }
942
1165
 
943
- // src/cli/commands/server.ts
944
- function createServerCommand() {
945
- const serverCmd = new Command("server").description("Server \u7BA1\u7406\u547D\u4EE4");
946
- serverCmd.command("start").description("\u542F\u52A8 MG Server").option("--port <number>", "\u6307\u5B9A\u542F\u52A8\u7AEF\u53E3", (value) => parseInt(value, 10)).option("--foreground", "\u524D\u53F0\u6A21\u5F0F\u8FD0\u884C\uFF08\u4E0D\u4F5C\u4E3A\u5B88\u62A4\u8FDB\u7A0B\uFF09", false).action(async (options) => {
947
- try {
948
- if (options.foreground) {
949
- await startServerForeground(options.port);
950
- } else {
951
- const info = await startServerDaemon(options.port);
952
- console.log("MG Server \u542F\u52A8\u6210\u529F");
953
- console.log(`\u76D1\u542C\u7AEF\u53E3: ${info.port}`);
954
- console.log(`\u8FDB\u7A0B PID: ${info.pid}`);
955
- console.log(`\u8FD0\u884C\u6A21\u5F0F: \u5B88\u62A4\u8FDB\u7A0B`);
956
- }
957
- } catch (error) {
958
- console.error(`\u9519\u8BEF: ${error.message}`);
959
- process.exit(1);
960
- }
961
- });
962
- serverCmd.command("stop").description("\u505C\u6B62 MG Server").action(() => {
963
- try {
964
- const { stopped, info } = stopServer();
965
- if (stopped && info) {
966
- console.log("MG Server \u5DF2\u505C\u6B62");
967
- console.log(`PID: ${info.pid}`);
968
- const uptimeMs = Date.now() - new Date(info.startedAt).getTime();
969
- const seconds = Math.floor(uptimeMs / 1e3);
970
- const minutes = Math.floor(seconds / 60);
971
- const hours = Math.floor(minutes / 60);
972
- let uptime = "";
973
- if (hours > 0) {
974
- uptime = `${hours} \u5C0F\u65F6 ${minutes % 60} \u5206\u949F`;
975
- } else if (minutes > 0) {
976
- uptime = `${minutes} \u5206\u949F ${seconds % 60} \u79D2`;
977
- } else {
978
- uptime = `${seconds} \u79D2`;
979
- }
980
- console.log(`\u8FD0\u884C\u65F6\u957F: ${uptime}`);
981
- } else {
982
- console.log("MG Server \u672A\u8FD0\u884C");
983
- }
984
- } catch (error) {
985
- console.error(`\u9519\u8BEF: ${error.message}`);
986
- process.exit(1);
987
- }
988
- });
989
- serverCmd.command("restart").description("\u91CD\u542F MG Server").option("--port <number>", "\u91CD\u542F\u540E\u4F7F\u7528\u7684\u7AEF\u53E3", (value) => parseInt(value, 10)).action(async (options) => {
990
- try {
991
- const status = getServerStatus();
992
- if (status.running) {
993
- console.log(`\u6B63\u5728\u505C\u6B62 MG Server (PID: ${status.pid})...`);
994
- }
995
- const info = await restartServer(options.port);
996
- console.log("MG Server \u5DF2\u91CD\u542F");
997
- console.log(`\u76D1\u542C\u7AEF\u53E3: ${info.port}`);
998
- console.log(`\u65B0\u8FDB\u7A0B PID: ${info.pid}`);
999
- } catch (error) {
1000
- console.error(`\u9519\u8BEF: ${error.message}`);
1001
- process.exit(1);
1002
- }
1003
- });
1004
- serverCmd.command("status").description("\u67E5\u770B Server \u8FD0\u884C\u72B6\u6001").action(() => {
1005
- try {
1006
- const status = getServerStatus();
1007
- if (status.running) {
1008
- console.log("MG Server \u72B6\u6001: \u8FD0\u884C\u4E2D \u2713");
1009
- console.log(`\u76D1\u542C\u7AEF\u53E3: ${status.port}`);
1010
- console.log(`\u8FDB\u7A0B PID: ${status.pid}`);
1011
- console.log(`\u542F\u52A8\u65F6\u95F4: ${status.startedAt}`);
1012
- console.log(`\u8FD0\u884C\u65F6\u957F: ${status.uptime}`);
1013
- } else {
1014
- console.log("MG Server \u72B6\u6001: \u672A\u8FD0\u884C \u2717");
1015
- console.log("\u63D0\u793A: \u4F7F\u7528 'mg-cli server start' \u542F\u52A8 Server");
1016
- }
1017
- } catch (error) {
1018
- console.error(`\u9519\u8BEF: ${error.message}`);
1019
- process.exit(1);
1020
- }
1021
- });
1022
- return serverCmd;
1023
- }
1024
-
1025
- // src/cli/commands/get-node-by-id.ts
1026
- import { Command as Command2 } from "commander";
1027
- import { writeFileSync as writeFileSync2 } from "fs";
1028
- import { resolve as resolve2, dirname as dirname4 } from "path";
1029
- import { mkdirSync as mkdirSync3 } from "fs";
1030
-
1031
1166
  // src/cli/client.ts
1032
1167
  import WebSocket2 from "ws";
1033
1168
  var MGClient = class {
@@ -1042,10 +1177,28 @@ var MGClient = class {
1042
1177
  async connect() {
1043
1178
  const serverInfo = readServerInfo();
1044
1179
  if (serverInfo) {
1045
- try {
1046
- await this.tryConnect(serverInfo.port);
1047
- return;
1048
- } catch {
1180
+ if (isProcessRunning(serverInfo.pid)) {
1181
+ const currentVersion = getVersion();
1182
+ if (!isVersionMatch(currentVersion, serverInfo.version)) {
1183
+ console.log(`\u7248\u672C\u4E0D\u5339\u914D: CLI ${currentVersion} vs Server ${serverInfo.version}`);
1184
+ console.log("\u6B63\u5728\u91CD\u542F Server \u4EE5\u5BF9\u9F50\u7248\u672C...");
1185
+ try {
1186
+ const newInfo = await restartServer(serverInfo.port);
1187
+ console.log(`Server \u5DF2\u91CD\u542F\uFF0C\u7248\u672C: ${newInfo.version}`);
1188
+ await this.waitForServer(newInfo.port);
1189
+ return;
1190
+ } catch (error) {
1191
+ throw new MGError(
1192
+ "E015" /* SERVER_START_FAILED */,
1193
+ `\u91CD\u542F Server \u5931\u8D25: ${error instanceof Error ? error.message : error}`
1194
+ );
1195
+ }
1196
+ }
1197
+ try {
1198
+ await this.tryConnect(serverInfo.port);
1199
+ return;
1200
+ } catch {
1201
+ }
1049
1202
  }
1050
1203
  }
1051
1204
  for (let port = PORT_RANGE_START; port <= PORT_RANGE_END; port++) {
@@ -1075,7 +1228,7 @@ var MGClient = class {
1075
1228
  * 尝试连接指定端口
1076
1229
  */
1077
1230
  tryConnect(port) {
1078
- return new Promise((resolve7, reject) => {
1231
+ return new Promise((resolve8, reject) => {
1079
1232
  const ws = new WebSocket2(`ws://localhost:${port}`);
1080
1233
  const timer = setTimeout(() => {
1081
1234
  ws.close();
@@ -1085,7 +1238,7 @@ var MGClient = class {
1085
1238
  clearTimeout(timer);
1086
1239
  this.ws = ws;
1087
1240
  this.register();
1088
- resolve7();
1241
+ resolve8();
1089
1242
  });
1090
1243
  ws.on("error", (error) => {
1091
1244
  clearTimeout(timer);
@@ -1138,7 +1291,7 @@ var MGClient = class {
1138
1291
  pageUrl,
1139
1292
  timestamp: Date.now()
1140
1293
  };
1141
- return new Promise((resolve7, reject) => {
1294
+ return new Promise((resolve8, reject) => {
1142
1295
  const timer = setTimeout(() => {
1143
1296
  reject(new MGError("E012" /* REQUEST_TIMEOUT */, ErrorMessages["E012" /* REQUEST_TIMEOUT */]));
1144
1297
  }, REQUEST_TIMEOUT);
@@ -1149,7 +1302,7 @@ var MGClient = class {
1149
1302
  clearTimeout(timer);
1150
1303
  this.ws?.off("message", messageHandler);
1151
1304
  if (response.success) {
1152
- resolve7(response.data);
1305
+ resolve8(response.data);
1153
1306
  } else {
1154
1307
  const error = response.error;
1155
1308
  reject(
@@ -1209,9 +1362,132 @@ var MGClient = class {
1209
1362
  }
1210
1363
  };
1211
1364
 
1365
+ // src/cli/commands/server.ts
1366
+ function createServerCommand() {
1367
+ const serverCmd = new Command("server").description("Server \u7BA1\u7406\u547D\u4EE4");
1368
+ serverCmd.command("start").description("\u542F\u52A8 MG Server").option("--port <number>", "\u6307\u5B9A\u542F\u52A8\u7AEF\u53E3", (value) => parseInt(value, 10)).option("--foreground", "\u524D\u53F0\u6A21\u5F0F\u8FD0\u884C\uFF08\u4E0D\u4F5C\u4E3A\u5B88\u62A4\u8FDB\u7A0B\uFF09", false).action(async (options) => {
1369
+ try {
1370
+ if (options.foreground) {
1371
+ await startServerForeground(options.port);
1372
+ } else {
1373
+ const info = await startServerDaemon(options.port);
1374
+ console.log("MG Server \u542F\u52A8\u6210\u529F");
1375
+ console.log(`\u7248\u672C: ${info.version}`);
1376
+ console.log(`\u76D1\u542C\u7AEF\u53E3: ${info.port}`);
1377
+ console.log(`\u8FDB\u7A0B PID: ${info.pid}`);
1378
+ console.log(`\u8FD0\u884C\u6A21\u5F0F: \u5B88\u62A4\u8FDB\u7A0B`);
1379
+ }
1380
+ } catch (error) {
1381
+ console.error(`\u9519\u8BEF: ${error.message}`);
1382
+ process.exit(1);
1383
+ }
1384
+ });
1385
+ serverCmd.command("stop").description("\u505C\u6B62 MG Server").action(() => {
1386
+ try {
1387
+ const { stopped, info } = stopServer();
1388
+ if (stopped && info) {
1389
+ console.log("MG Server \u5DF2\u505C\u6B62");
1390
+ console.log(`PID: ${info.pid}`);
1391
+ const uptimeMs = Date.now() - new Date(info.startedAt).getTime();
1392
+ const seconds = Math.floor(uptimeMs / 1e3);
1393
+ const minutes = Math.floor(seconds / 60);
1394
+ const hours = Math.floor(minutes / 60);
1395
+ let uptime = "";
1396
+ if (hours > 0) {
1397
+ uptime = `${hours} \u5C0F\u65F6 ${minutes % 60} \u5206\u949F`;
1398
+ } else if (minutes > 0) {
1399
+ uptime = `${minutes} \u5206\u949F ${seconds % 60} \u79D2`;
1400
+ } else {
1401
+ uptime = `${seconds} \u79D2`;
1402
+ }
1403
+ console.log(`\u8FD0\u884C\u65F6\u957F: ${uptime}`);
1404
+ } else {
1405
+ console.log("MG Server \u672A\u8FD0\u884C");
1406
+ }
1407
+ } catch (error) {
1408
+ console.error(`\u9519\u8BEF: ${error.message}`);
1409
+ process.exit(1);
1410
+ }
1411
+ });
1412
+ serverCmd.command("restart").description("\u91CD\u542F MG Server").option("--port <number>", "\u91CD\u542F\u540E\u4F7F\u7528\u7684\u7AEF\u53E3", (value) => parseInt(value, 10)).action(async (options) => {
1413
+ try {
1414
+ const status = getServerStatus();
1415
+ if (status.running) {
1416
+ console.log(`\u6B63\u5728\u505C\u6B62 MG Server (PID: ${status.pid})...`);
1417
+ }
1418
+ const info = await restartServer(options.port);
1419
+ console.log("MG Server \u5DF2\u91CD\u542F");
1420
+ console.log(`\u7248\u672C: ${info.version}`);
1421
+ console.log(`\u76D1\u542C\u7AEF\u53E3: ${info.port}`);
1422
+ console.log(`\u65B0\u8FDB\u7A0B PID: ${info.pid}`);
1423
+ } catch (error) {
1424
+ console.error(`\u9519\u8BEF: ${error.message}`);
1425
+ process.exit(1);
1426
+ }
1427
+ });
1428
+ serverCmd.command("status").description("\u67E5\u770B Server \u8FD0\u884C\u72B6\u6001").action(async () => {
1429
+ try {
1430
+ const basicStatus = getServerStatus();
1431
+ if (!basicStatus.running) {
1432
+ console.log("MG Server \u72B6\u6001: \u672A\u8FD0\u884C \u2717");
1433
+ console.log("\u63D0\u793A: \u4F7F\u7528 'mg-cli server start' \u542F\u52A8 Server");
1434
+ return;
1435
+ }
1436
+ try {
1437
+ const client = new MGClient({ noAutoStart: true });
1438
+ await client.connect();
1439
+ const status = await client.request(
1440
+ "get_server_status" /* GET_SERVER_STATUS */
1441
+ );
1442
+ client.close();
1443
+ console.log("MG Server \u72B6\u6001: \u8FD0\u884C\u4E2D \u2713");
1444
+ console.log(`\u7248\u672C: ${status.version}`);
1445
+ console.log(`\u76D1\u542C\u7AEF\u53E3: ${status.port}`);
1446
+ console.log(`\u8FDB\u7A0B PID: ${status.pid}`);
1447
+ console.log(`\u542F\u52A8\u65F6\u95F4: ${status.startedAt}`);
1448
+ console.log(`\u8FD0\u884C\u65F6\u957F: ${status.uptime}`);
1449
+ console.log(``);
1450
+ console.log(`\u8FDE\u63A5\u7EDF\u8BA1:`);
1451
+ console.log(` Provider \u6570\u91CF: ${status.stats.providers}`);
1452
+ console.log(` Consumer \u6570\u91CF: ${status.stats.consumers}`);
1453
+ if (status.connectedPages.length > 0) {
1454
+ console.log(``);
1455
+ console.log(`\u5DF2\u8FDE\u63A5\u9875\u9762 (${status.connectedPages.length}):`);
1456
+ for (const page of status.connectedPages) {
1457
+ console.log(` - ${page.pageUrl}`);
1458
+ }
1459
+ } else {
1460
+ console.log(``);
1461
+ console.log(`\u5DF2\u8FDE\u63A5\u9875\u9762: \u65E0`);
1462
+ console.log(`\u63D0\u793A: \u8BF7\u5728 Chrome \u4E2D\u6253\u5F00 MasterGo \u9875\u9762\u5E76\u786E\u4FDD\u63D2\u4EF6\u5DF2\u542F\u7528`);
1463
+ }
1464
+ } catch {
1465
+ console.log("MG Server \u72B6\u6001: \u8FD0\u884C\u4E2D \u2713");
1466
+ if (basicStatus.version) {
1467
+ console.log(`\u7248\u672C: ${basicStatus.version}`);
1468
+ }
1469
+ console.log(`\u76D1\u542C\u7AEF\u53E3: ${basicStatus.port}`);
1470
+ console.log(`\u8FDB\u7A0B PID: ${basicStatus.pid}`);
1471
+ console.log(`\u542F\u52A8\u65F6\u95F4: ${basicStatus.startedAt}`);
1472
+ console.log(`\u8FD0\u884C\u65F6\u957F: ${basicStatus.uptime}`);
1473
+ console.log(``);
1474
+ console.log(`\u6CE8\u610F: \u65E0\u6CD5\u83B7\u53D6\u8BE6\u7EC6\u8FDE\u63A5\u4FE1\u606F`);
1475
+ }
1476
+ } catch (error) {
1477
+ console.error(`\u9519\u8BEF: ${error.message}`);
1478
+ process.exit(1);
1479
+ }
1480
+ });
1481
+ return serverCmd;
1482
+ }
1483
+
1212
1484
  // src/cli/commands/get-node-by-id.ts
1485
+ import { Command as Command2 } from "commander";
1486
+ import { writeFileSync as writeFileSync2 } from "fs";
1487
+ import { resolve as resolve2, dirname as dirname5 } from "path";
1488
+ import { mkdirSync as mkdirSync3 } from "fs";
1213
1489
  function createGetNodeByIdCommand() {
1214
- return new Command2("get_node_by_id").description("\u6839\u636E\u8282\u70B9 ID \u83B7\u53D6\u8282\u70B9\u8BE6\u7EC6\u4FE1\u606F\u3002\u6570\u636E\u4FDD\u5B58\u5230\u6307\u5B9A JSON \u6587\u4EF6\uFF0C\u8FD4\u56DE\u6587\u4EF6\u8DEF\u5F84\u548C\u5927\u5C0F\u4FE1\u606F\u3002\u5982\u9700\u901A\u8FC7\u94FE\u63A5\u83B7\u53D6\uFF0C\u8BF7\u4F7F\u7528 get_node_by_link \u547D\u4EE4").requiredOption("--nodeId <id>", "\u8282\u70B9 ID\uFF0C\u683C\u5F0F\u5982 123:456\u3002\u53EF\u4ECE MasterGo \u6D6E\u7A97\u94FE\u63A5\u4E2D\u83B7\u53D6").requiredOption("--output <path>", "\u8F93\u51FA JSON \u6587\u4EF6\u8DEF\u5F84\u3002\u652F\u6301\u7EDD\u5BF9\u8DEF\u5F84\u6216\u76F8\u5BF9\u8DEF\u5F84").option("--domain <domain>", "MasterGo \u57DF\u540D\uFF0C\u9ED8\u8BA4 mastergo.netease.com\u3002\u4E0E --fileId \u914D\u5408\u4F7F\u7528", "mastergo.netease.com").option("--fileId <id>", "\u6587\u4EF6 ID\uFF08\u7EAF\u6570\u5B57\uFF09\uFF0C\u4E0E --domain \u914D\u5408\u6307\u5B9A\u76EE\u6807\u9875\u9762").option("--maxDepth <number>", "\u904D\u5386\u6DF1\u5EA6\uFF0C\u9ED8\u8BA4 1\u3002\u589E\u52A0\u6DF1\u5EA6\u4F1A\u663E\u8457\u589E\u52A0\u6570\u636E\u91CF", "1").option("--includeInvisible", "\u5305\u542B\u4E0D\u53EF\u89C1\u8282\u70B9\uFF08visible: false\uFF09\uFF0C\u9ED8\u8BA4\u4E0D\u5305\u542B", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
1490
+ return new Command2("get_node_by_id").description("\u6839\u636E\u8282\u70B9 ID \u83B7\u53D6\u8282\u70B9\u8BE6\u7EC6\u4FE1\u606F\u3002\u6570\u636E\u4FDD\u5B58\u5230\u6307\u5B9A JSON \u6587\u4EF6\uFF0C\u8FD4\u56DE\u6587\u4EF6\u8DEF\u5F84\u548C\u5927\u5C0F\u4FE1\u606F\u3002\u5982\u9700\u901A\u8FC7\u94FE\u63A5\u83B7\u53D6\uFF0C\u8BF7\u4F7F\u7528 get_node_by_link \u547D\u4EE4").requiredOption("--nodeId <id>", "\u8282\u70B9 ID\uFF0C\u683C\u5F0F\u5982 123:456\u3002\u53EF\u4ECE MasterGo \u6D6E\u7A97\u94FE\u63A5\u4E2D\u83B7\u53D6").requiredOption("--output <path>", "\u8F93\u51FA JSON \u6587\u4EF6\u8DEF\u5F84\u3002\u652F\u6301\u7EDD\u5BF9\u8DEF\u5F84\u6216\u76F8\u5BF9\u8DEF\u5F84").option("--domain <domain>", "MasterGo \u57DF\u540D\uFF0C\u9ED8\u8BA4 mastergo.netease.com\u3002\u4E0E --fileId \u914D\u5408\u4F7F\u7528", "mastergo.netease.com").option("--fileId <id>", "\u6587\u4EF6 ID\uFF08\u7EAF\u6570\u5B57\uFF09\uFF0C\u4E0E --domain \u914D\u5408\u6307\u5B9A\u76EE\u6807\u9875\u9762").option("--maxDepth <number>", "\u904D\u5386\u6DF1\u5EA6\uFF0C\u9ED8\u8BA4 1\u3002\u589E\u52A0\u6DF1\u5EA6\u4F1A\u663E\u8457\u589E\u52A0\u6570\u636E\u91CF", "1").option("--includeInvisible", "\u5305\u542B\u4E0D\u53EF\u89C1\u8282\u70B9\uFF08visible: false\uFF09\uFF0C\u9ED8\u8BA4\u4E0D\u5305\u542B", false).option("--raw", "\u4FDD\u7559\u539F\u59CB\u6570\u636E\uFF0C\u4E0D\u7CBE\u7B80\u9ED8\u8BA4\u503C\u5B57\u6BB5", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
1215
1491
  await handleGetNodeById(options);
1216
1492
  });
1217
1493
  }
@@ -1233,10 +1509,11 @@ async function handleGetNodeById(options) {
1233
1509
  includeInvisible: options.includeInvisible || false
1234
1510
  };
1235
1511
  const data = await client.requestWithRetry("get_node_by_id" /* GET_NODE_BY_ID */, params, pageUrl);
1512
+ const outputData = options.raw ? data : trimNodeDefaults(data);
1236
1513
  const outputPath = resolve2(options.output);
1237
- const outputDir = dirname4(outputPath);
1514
+ const outputDir = dirname5(outputPath);
1238
1515
  mkdirSync3(outputDir, { recursive: true });
1239
- const jsonContent = JSON.stringify(data, null, 2);
1516
+ const jsonContent = JSON.stringify(outputData, null, 2);
1240
1517
  writeFileSync2(outputPath, jsonContent, "utf-8");
1241
1518
  const size = jsonContent.length;
1242
1519
  const sizeKB = (size / 1024).toFixed(2);
@@ -1244,6 +1521,9 @@ async function handleGetNodeById(options) {
1244
1521
  console.log(`\u8282\u70B9 ID: ${options.nodeId}`);
1245
1522
  console.log(`\u6570\u636E\u5927\u5C0F: ${size.toLocaleString()} \u5B57\u7B26 (\u7EA6 ${sizeKB} KB)`);
1246
1523
  console.log(`\u8282\u70B9\u6DF1\u5EA6: ${params.maxDepth}`);
1524
+ if (!options.raw) {
1525
+ console.log(`\u6570\u636E\u6A21\u5F0F: \u7CBE\u7B80\u6A21\u5F0F (\u4F7F\u7528 --raw \u83B7\u53D6\u5B8C\u6574\u6570\u636E)`);
1526
+ }
1247
1527
  } catch (error) {
1248
1528
  console.error(`\u9519\u8BEF: ${error instanceof Error ? error.message : error}`);
1249
1529
  process.exit(1);
@@ -1255,10 +1535,10 @@ async function handleGetNodeById(options) {
1255
1535
  // src/cli/commands/get-node-by-link.ts
1256
1536
  import { Command as Command3 } from "commander";
1257
1537
  import { writeFileSync as writeFileSync3 } from "fs";
1258
- import { resolve as resolve3, dirname as dirname5 } from "path";
1538
+ import { resolve as resolve3, dirname as dirname6 } from "path";
1259
1539
  import { mkdirSync as mkdirSync4 } from "fs";
1260
1540
  function createGetNodeByLinkCommand() {
1261
- return new Command3("get_node_by_link").description("\u89E3\u6790 mgp:// \u534F\u8BAE\u94FE\u63A5\u5E76\u83B7\u53D6\u8282\u70B9\u4FE1\u606F").requiredOption("--link <url>", "mgp:// \u534F\u8BAE\u94FE\u63A5").requiredOption("--output <path>", "\u8F93\u51FA JSON \u6587\u4EF6\u8DEF\u5F84").option("--maxDepth <number>", "\u904D\u5386\u6DF1\u5EA6", "1").option("--includeInvisible", "\u5305\u542B\u4E0D\u53EF\u89C1\u8282\u70B9", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
1541
+ return new Command3("get_node_by_link").description("\u89E3\u6790 mgp:// \u534F\u8BAE\u94FE\u63A5\u5E76\u83B7\u53D6\u8282\u70B9\u4FE1\u606F").requiredOption("--link <url>", "mgp:// \u534F\u8BAE\u94FE\u63A5").requiredOption("--output <path>", "\u8F93\u51FA JSON \u6587\u4EF6\u8DEF\u5F84").option("--maxDepth <number>", "\u904D\u5386\u6DF1\u5EA6", "1").option("--includeInvisible", "\u5305\u542B\u4E0D\u53EF\u89C1\u8282\u70B9", false).option("--raw", "\u4FDD\u7559\u539F\u59CB\u6570\u636E\uFF0C\u4E0D\u7CBE\u7B80\u9ED8\u8BA4\u503C\u5B57\u6BB5", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
1262
1542
  await handleGetNodeByLink(options);
1263
1543
  });
1264
1544
  }
@@ -1287,10 +1567,11 @@ async function handleGetNodeByLink(options) {
1287
1567
  params,
1288
1568
  pageUrl
1289
1569
  );
1570
+ const outputData = options.raw ? data : trimNodeDefaults(data);
1290
1571
  const outputPath = resolve3(options.output);
1291
- const outputDir = dirname5(outputPath);
1572
+ const outputDir = dirname6(outputPath);
1292
1573
  mkdirSync4(outputDir, { recursive: true });
1293
- const jsonContent = JSON.stringify(data, null, 2);
1574
+ const jsonContent = JSON.stringify(outputData, null, 2);
1294
1575
  writeFileSync3(outputPath, jsonContent, "utf-8");
1295
1576
  const size = jsonContent.length;
1296
1577
  const sizeKB = (size / 1024).toFixed(2);
@@ -1300,6 +1581,9 @@ async function handleGetNodeByLink(options) {
1300
1581
  console.log(`\u8282\u70B9 ID: ${nodeId}`);
1301
1582
  console.log(`\u6570\u636E\u5927\u5C0F: ${size.toLocaleString()} \u5B57\u7B26 (\u7EA6 ${sizeKB} KB)`);
1302
1583
  console.log(`\u8282\u70B9\u6DF1\u5EA6: ${params.maxDepth}`);
1584
+ if (!options.raw) {
1585
+ console.log(`\u6570\u636E\u6A21\u5F0F: \u7CBE\u7B80\u6A21\u5F0F (\u4F7F\u7528 --raw \u83B7\u53D6\u5B8C\u6574\u6570\u636E)`);
1586
+ }
1303
1587
  } catch (error) {
1304
1588
  if (error instanceof MGError) {
1305
1589
  console.error(`\u9519\u8BEF [${error.code}]: ${error.message}`);
@@ -1315,10 +1599,10 @@ async function handleGetNodeByLink(options) {
1315
1599
  // src/cli/commands/get-all-nodes.ts
1316
1600
  import { Command as Command4 } from "commander";
1317
1601
  import { writeFileSync as writeFileSync4 } from "fs";
1318
- import { resolve as resolve4, dirname as dirname6 } from "path";
1602
+ import { resolve as resolve4, dirname as dirname7 } from "path";
1319
1603
  import { mkdirSync as mkdirSync5 } from "fs";
1320
1604
  function createGetAllNodesCommand() {
1321
- return new Command4("get_all_nodes").description("\u83B7\u53D6\u5F53\u524D\u9875\u9762\u7684\u6240\u6709\u8282\u70B9\u6811\u3002\u8B66\u544A\uFF1A\u6DF1\u5EA6\u6BCF\u589E\u52A0 1\uFF0C\u6570\u636E\u91CF\u53EF\u80FD\u5448\u6307\u6570\u7EA7\u589E\u957F\u3002\u5EFA\u8BAE\u4ECE maxDepth=1 \u5F00\u59CB").requiredOption("--output <path>", "\u8F93\u51FA JSON \u6587\u4EF6\u8DEF\u5F84\u3002\u652F\u6301\u7EDD\u5BF9\u8DEF\u5F84\u6216\u76F8\u5BF9\u8DEF\u5F84").option("--maxDepth <number>", "\u6700\u5927\u6DF1\u5EA6\uFF0C\u9ED8\u8BA4 1\u3002\u6DF1\u5EA6 2 \u53EF\u80FD\u4EA7\u751F 100KB-500KB\uFF0C\u6DF1\u5EA6 3 \u53EF\u80FD\u8D85\u8FC7 1MB", "1").option("--includeInvisible", "\u5305\u542B\u4E0D\u53EF\u89C1\u8282\u70B9\uFF08visible: false\uFF09\uFF0C\u9ED8\u8BA4\u4E0D\u5305\u542B", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
1605
+ return new Command4("get_all_nodes").description("\u83B7\u53D6\u5F53\u524D\u9875\u9762\u7684\u6240\u6709\u8282\u70B9\u6811\u3002\u8B66\u544A\uFF1A\u6DF1\u5EA6\u6BCF\u589E\u52A0 1\uFF0C\u6570\u636E\u91CF\u53EF\u80FD\u5448\u6307\u6570\u7EA7\u589E\u957F\u3002\u5EFA\u8BAE\u4ECE maxDepth=1 \u5F00\u59CB").requiredOption("--output <path>", "\u8F93\u51FA JSON \u6587\u4EF6\u8DEF\u5F84\u3002\u652F\u6301\u7EDD\u5BF9\u8DEF\u5F84\u6216\u76F8\u5BF9\u8DEF\u5F84").option("--maxDepth <number>", "\u6700\u5927\u6DF1\u5EA6\uFF0C\u9ED8\u8BA4 1\u3002\u6DF1\u5EA6 2 \u53EF\u80FD\u4EA7\u751F 100KB-500KB\uFF0C\u6DF1\u5EA6 3 \u53EF\u80FD\u8D85\u8FC7 1MB", "1").option("--includeInvisible", "\u5305\u542B\u4E0D\u53EF\u89C1\u8282\u70B9\uFF08visible: false\uFF09\uFF0C\u9ED8\u8BA4\u4E0D\u5305\u542B", false).option("--raw", "\u4FDD\u7559\u539F\u59CB\u6570\u636E\uFF0C\u4E0D\u7CBE\u7B80\u9ED8\u8BA4\u503C\u5B57\u6BB5", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
1322
1606
  await handleGetAllNodes(options);
1323
1607
  });
1324
1608
  }
@@ -1334,10 +1618,11 @@ async function handleGetAllNodes(options) {
1334
1618
  includeInvisible: options.includeInvisible || false
1335
1619
  };
1336
1620
  const data = await client.requestWithRetry("get_all_nodes" /* GET_ALL_NODES */, params);
1621
+ const outputData = options.raw ? data : Array.isArray(data) ? data.map((node) => trimNodeDefaults(node)) : trimNodeDefaults(data);
1337
1622
  const outputPath = resolve4(options.output);
1338
- const outputDir = dirname6(outputPath);
1623
+ const outputDir = dirname7(outputPath);
1339
1624
  mkdirSync5(outputDir, { recursive: true });
1340
- const jsonContent = JSON.stringify(data, null, 2);
1625
+ const jsonContent = JSON.stringify(outputData, null, 2);
1341
1626
  writeFileSync4(outputPath, jsonContent, "utf-8");
1342
1627
  const size = jsonContent.length;
1343
1628
  const sizeKB = (size / 1024).toFixed(2);
@@ -1346,6 +1631,9 @@ async function handleGetAllNodes(options) {
1346
1631
  console.log(`\u8282\u70B9\u6570\u91CF: ${nodeCount}`);
1347
1632
  console.log(`\u6570\u636E\u5927\u5C0F: ${size.toLocaleString()} \u5B57\u7B26 (\u7EA6 ${sizeKB} KB)`);
1348
1633
  console.log(`\u8282\u70B9\u6DF1\u5EA6: ${params.maxDepth}`);
1634
+ if (!options.raw) {
1635
+ console.log(`\u6570\u636E\u6A21\u5F0F: \u7CBE\u7B80\u6A21\u5F0F (\u4F7F\u7528 --raw \u83B7\u53D6\u5B8C\u6574\u6570\u636E)`);
1636
+ }
1349
1637
  } catch (error) {
1350
1638
  console.error(`\u9519\u8BEF: ${error instanceof Error ? error.message : error}`);
1351
1639
  process.exit(1);
@@ -1357,11 +1645,11 @@ async function handleGetAllNodes(options) {
1357
1645
  // src/cli/commands/export-image.ts
1358
1646
  import { Command as Command5 } from "commander";
1359
1647
  import { writeFileSync as writeFileSync5 } from "fs";
1360
- import { resolve as resolve5, dirname as dirname7, extname } from "path";
1648
+ import { resolve as resolve5, dirname as dirname8, extname } from "path";
1361
1649
  import { mkdirSync as mkdirSync6 } from "fs";
1362
1650
  import { tmpdir } from "os";
1363
1651
  function createExportImageCommand() {
1364
- return new Command5("export_image").description("\u5BFC\u51FA MasterGo \u8282\u70B9\u4E3A\u56FE\u7247\u6587\u4EF6\u3002\u5F3A\u70C8\u5EFA\u8BAE\u6307\u5B9A --output\uFF0C\u5426\u5219\u4FDD\u5B58\u5230\u4E34\u65F6\u76EE\u5F55\u53EF\u80FD\u88AB\u7CFB\u7EDF\u6E05\u7406").option("--output <path>", "\u8F93\u51FA\u6587\u4EF6\u8DEF\u5F84\u3002\u5F3A\u70C8\u5EFA\u8BAE\u6307\u5B9A\uFF0C\u5426\u5219\u4FDD\u5B58\u5230\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55\u53EF\u80FD\u88AB\u6E05\u7406").option("--link <mgp-link>", "mgp:// \u534F\u8BAE\u94FE\u63A5\u3002\u4E0D\u6307\u5B9A\u5219\u5BFC\u51FA\u5F53\u524D\u9009\u4E2D\u8282\u70B9").option("--format <type>", "\u5BFC\u51FA\u683C\u5F0F\uFF1APNG\uFF08\u65E0\u635F\u900F\u660E\uFF09\u3001JPG\uFF08\u6709\u635F\uFF09\u3001SVG\uFF08\u77E2\u91CF\uFF09\u3001PDF\u3001WEBP", "PNG").option("--scale <number>", "\u7F29\u653E\u500D\u7387\uFF08\u5982 1\u30012\u30013\uFF09\u3002\u4E0E width/height \u4E92\u65A5").option("--width <number>", "\u56FA\u5B9A\u5BBD\u5EA6\uFF08\u50CF\u7D20\uFF09\u3002\u4E0E scale/height \u4E92\u65A5").option("--height <number>", "\u56FA\u5B9A\u9AD8\u5EA6\uFF08\u50CF\u7D20\uFF09\u3002\u4E0E scale/width \u4E92\u65A5").option("--useAbsoluteBounds", "\u4F7F\u7528\u5B8C\u6574\u5C3A\u5BF8\u3002true: \u5305\u542B\u88AB\u88C1\u526A\u90E8\u5206\uFF0Cfalse: \u53EA\u5BFC\u51FA\u53EF\u89C1\u533A\u57DF", false).option("--no-use-render-bounds", "\u4E0D\u5305\u542B\u7279\u6548\u548C\u5916\u63CF\u8FB9\u3002\u9ED8\u8BA4\u5305\u542B\u9634\u5F71\u3001\u5916\u63CF\u8FB9\u7B49").option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
1652
+ return new Command5("export_image").description("\u5BFC\u51FA MasterGo \u8282\u70B9\u4E3A\u56FE\u7247\u6587\u4EF6\u3002\u5F3A\u70C8\u5EFA\u8BAE\u6307\u5B9A --output\uFF0C\u5426\u5219\u4FDD\u5B58\u5230\u4E34\u65F6\u76EE\u5F55\u53EF\u80FD\u88AB\u7CFB\u7EDF\u6E05\u7406").option("--output <path>", "\u8F93\u51FA\u6587\u4EF6\u8DEF\u5F84\u3002\u5F3A\u70C8\u5EFA\u8BAE\u6307\u5B9A\uFF0C\u5426\u5219\u4FDD\u5B58\u5230\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55\u53EF\u80FD\u88AB\u6E05\u7406").option("--link <mgp-link>", "mgp:// \u534F\u8BAE\u94FE\u63A5\u3002\u4E0E --nodeId/--domain/--fileId \u4E8C\u9009\u4E00").option("--nodeId <id>", "\u8282\u70B9 ID\uFF0C\u683C\u5F0F\u5982 123:456\u3002\u4E0E --domain/--fileId \u914D\u5408\u4F7F\u7528").option("--domain <domain>", "MasterGo \u57DF\u540D\uFF0C\u9ED8\u8BA4 mastergo.netease.com", "mastergo.netease.com").option("--fileId <id>", "\u6587\u4EF6 ID\uFF08\u7EAF\u6570\u5B57\uFF09\uFF0C\u4E0E --domain \u914D\u5408\u6307\u5B9A\u76EE\u6807\u9875\u9762").option("--format <type>", "\u5BFC\u51FA\u683C\u5F0F\uFF1APNG\uFF08\u65E0\u635F\u900F\u660E\uFF09\u3001JPG\uFF08\u6709\u635F\uFF09\u3001SVG\uFF08\u77E2\u91CF\uFF09\u3001PDF\u3001WEBP", "PNG").option("--scale <number>", "\u7F29\u653E\u500D\u7387\uFF08\u5982 1\u30012\u30013\uFF09\u3002\u4E0E width/height \u4E92\u65A5").option("--width <number>", "\u56FA\u5B9A\u5BBD\u5EA6\uFF08\u50CF\u7D20\uFF09\u3002\u4E0E scale/height \u4E92\u65A5").option("--height <number>", "\u56FA\u5B9A\u9AD8\u5EA6\uFF08\u50CF\u7D20\uFF09\u3002\u4E0E scale/width \u4E92\u65A5").option("--useAbsoluteBounds", "\u4F7F\u7528\u5B8C\u6574\u5C3A\u5BF8\u3002true: \u5305\u542B\u88AB\u88C1\u526A\u90E8\u5206\uFF0Cfalse: \u53EA\u5BFC\u51FA\u53EF\u89C1\u533A\u57DF", false).option("--no-use-render-bounds", "\u4E0D\u5305\u542B\u7279\u6548\u548C\u5916\u63CF\u8FB9\u3002\u9ED8\u8BA4\u5305\u542B\u9634\u5F71\u3001\u5916\u63CF\u8FB9\u7B49").option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
1365
1653
  await handleExportImage(options);
1366
1654
  });
1367
1655
  }
@@ -1378,16 +1666,30 @@ async function handleExportImage(options) {
1378
1666
  console.error("\u9519\u8BEF: scale\u3001width\u3001height \u4E09\u8005\u4E92\u65A5\uFF0C\u53EA\u80FD\u6307\u5B9A\u5176\u4E2D\u4E00\u4E2A");
1379
1667
  process.exit(1);
1380
1668
  }
1669
+ if (options.link && (options.nodeId || options.fileId)) {
1670
+ console.error(`\u9519\u8BEF [${"E011" /* INVALID_PARAMS */}]: --link \u548C --nodeId/--fileId \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528`);
1671
+ process.exit(1);
1672
+ }
1381
1673
  let pageUrl;
1382
1674
  let nodeId;
1383
1675
  if (options.link) {
1384
1676
  const linkInfo = parseMgpLink(options.link);
1385
1677
  if (!linkInfo) {
1386
- console.error(`\u9519\u8BEF: \u65E0\u6548\u7684 mgp:// \u94FE\u63A5\u683C\u5F0F: ${options.link}`);
1678
+ console.error(`\u9519\u8BEF [${"E010" /* INVALID_LINK */}]: \u65E0\u6548\u7684 mgp:// \u94FE\u63A5\u683C\u5F0F`);
1679
+ console.error(`\u63D0\u4F9B\u7684\u94FE\u63A5: ${options.link}`);
1680
+ console.error(`\u671F\u671B\u683C\u5F0F: mgp://[mastergo_page_url]?nodeId=xxx`);
1387
1681
  process.exit(1);
1388
1682
  }
1389
1683
  pageUrl = linkInfo.pageUrl;
1390
1684
  nodeId = linkInfo.nodeId;
1685
+ } else {
1686
+ if (options.nodeId) {
1687
+ nodeId = options.nodeId;
1688
+ }
1689
+ if (options.fileId) {
1690
+ const domain = options.domain || "mastergo.netease.com";
1691
+ pageUrl = `${domain}/file/${options.fileId}`;
1692
+ }
1391
1693
  }
1392
1694
  const client = new MGClient({
1393
1695
  noAutoStart: options.noAutoStart,
@@ -1429,7 +1731,7 @@ async function handleExportImage(options) {
1429
1731
  outputPath = resolve5(tmpdir(), filename);
1430
1732
  console.log("\u8B66\u544A: \u672A\u6307\u5B9A --output\uFF0C\u6587\u4EF6\u5C06\u4FDD\u5B58\u5230\u4E34\u65F6\u76EE\u5F55\uFF0C\u53EF\u80FD\u4F1A\u88AB\u7CFB\u7EDF\u6E05\u7406");
1431
1733
  }
1432
- const outputDir = dirname7(outputPath);
1734
+ const outputDir = dirname8(outputPath);
1433
1735
  mkdirSync6(outputDir, { recursive: true });
1434
1736
  const buffer = Buffer.from(response.data, "base64");
1435
1737
  writeFileSync5(outputPath, buffer);
@@ -1470,18 +1772,36 @@ function getExtension(format) {
1470
1772
  // src/cli/commands/execute-code.ts
1471
1773
  import { Command as Command6 } from "commander";
1472
1774
  function createExecuteCodeCommand() {
1473
- return new Command6("execute_code").description("\u5728 MasterGo \u9875\u9762\u6267\u884C\u81EA\u5B9A\u4E49 JavaScript \u4EE3\u7801\u3002\u901A\u8FC7 mg \u53D8\u91CF\u8BBF\u95EE MasterGo API\uFF0C\u7ED3\u679C\u4F1A\u88AB JSON \u5E8F\u5217\u5316\u8FD4\u56DE").argument("<code>", "\u8981\u6267\u884C\u7684\u4EE3\u7801\u3002\u53EF\u4F7F\u7528 mg \u53D8\u91CF\uFF0C\u5982 mg.currentPage.name\u3001mg.currentPage.selection").option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (code, options) => {
1775
+ return new Command6("execute_code").description("\u5728 MasterGo \u9875\u9762\u6267\u884C\u81EA\u5B9A\u4E49 JavaScript \u4EE3\u7801\u3002\u901A\u8FC7 mg \u53D8\u91CF\u8BBF\u95EE MasterGo API\uFF0C\u7ED3\u679C\u4F1A\u88AB JSON \u5E8F\u5217\u5316\u8FD4\u56DE").argument("<code>", "\u8981\u6267\u884C\u7684\u4EE3\u7801\u3002\u53EF\u4F7F\u7528 mg \u53D8\u91CF\uFF0C\u5982 mg.currentPage.name\u3001mg.currentPage.selection").option("--link <url>", "mgp:// \u534F\u8BAE\u94FE\u63A5\uFF0C\u7528\u4E8E\u6307\u5B9A\u76EE\u6807\u9875\u9762\u3002\u4E0E --domain/--fileId \u4E8C\u9009\u4E00").option("--domain <domain>", "MasterGo \u57DF\u540D\uFF0C\u9ED8\u8BA4 mastergo.netease.com", "mastergo.netease.com").option("--fileId <id>", "\u6587\u4EF6 ID\uFF08\u7EAF\u6570\u5B57\uFF09\uFF0C\u4E0E --domain \u914D\u5408\u6307\u5B9A\u76EE\u6807\u9875\u9762").option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (code, options) => {
1474
1776
  await handleExecuteCode(code, options);
1475
1777
  });
1476
1778
  }
1477
1779
  async function handleExecuteCode(code, options) {
1780
+ if (options.link && options.fileId) {
1781
+ console.error(`\u9519\u8BEF [${"E011" /* INVALID_PARAMS */}]: --link \u548C --fileId \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528`);
1782
+ process.exit(1);
1783
+ }
1784
+ let pageUrl;
1785
+ if (options.link) {
1786
+ const parsed = parseMgpLink(options.link);
1787
+ if (!parsed) {
1788
+ console.error(`\u9519\u8BEF [${"E010" /* INVALID_LINK */}]: \u65E0\u6548\u7684 mgp:// \u94FE\u63A5\u683C\u5F0F`);
1789
+ console.error(`\u63D0\u4F9B\u7684\u94FE\u63A5: ${options.link}`);
1790
+ console.error(`\u671F\u671B\u683C\u5F0F: mgp://[mastergo_page_url]?nodeId=xxx`);
1791
+ process.exit(1);
1792
+ }
1793
+ pageUrl = parsed.pageUrl;
1794
+ } else if (options.fileId) {
1795
+ const domain = options.domain || "mastergo.netease.com";
1796
+ pageUrl = `${domain}/file/${options.fileId}`;
1797
+ }
1478
1798
  const client = new MGClient({
1479
1799
  noAutoStart: options.noAutoStart,
1480
1800
  noRetry: options.noRetry
1481
1801
  });
1482
1802
  try {
1483
1803
  await client.connect();
1484
- const result = await client.requestWithRetry("execute_code" /* EXECUTE_CODE */, { code });
1804
+ const result = await client.requestWithRetry("execute_code" /* EXECUTE_CODE */, { code }, pageUrl);
1485
1805
  if (result === null || result === void 0) {
1486
1806
  console.log("\u6267\u884C\u5B8C\u6210\uFF08\u65E0\u8FD4\u56DE\u503C\uFF09");
1487
1807
  } else if (typeof result === "object") {
@@ -1500,7 +1820,7 @@ async function handleExecuteCode(code, options) {
1500
1820
  // src/cli/commands/get-all-pages.ts
1501
1821
  import { Command as Command7 } from "commander";
1502
1822
  import { writeFileSync as writeFileSync6 } from "fs";
1503
- import { resolve as resolve6, dirname as dirname8 } from "path";
1823
+ import { resolve as resolve6, dirname as dirname9 } from "path";
1504
1824
  import { mkdirSync as mkdirSync7 } from "fs";
1505
1825
  import { tmpdir as tmpdir2 } from "os";
1506
1826
  function createGetAllPagesCommand() {
@@ -1548,7 +1868,7 @@ async function handleGetAllPages(options) {
1548
1868
  const filename = `pages_${fileId || "current"}_${Date.now()}.json`;
1549
1869
  outputPath = resolve6(tmpdir2(), filename);
1550
1870
  }
1551
- const outputDir = dirname8(outputPath);
1871
+ const outputDir = dirname9(outputPath);
1552
1872
  mkdirSync7(outputDir, { recursive: true });
1553
1873
  const jsonContent = JSON.stringify(data, null, 2);
1554
1874
  writeFileSync6(outputPath, jsonContent, "utf-8");
@@ -1566,8 +1886,91 @@ async function handleGetAllPages(options) {
1566
1886
  }
1567
1887
  }
1568
1888
 
1889
+ // src/cli/commands/get-node-for-space.ts
1890
+ import { Command as Command8 } from "commander";
1891
+ import { writeFileSync as writeFileSync7 } from "fs";
1892
+ import { resolve as resolve7, dirname as dirname10 } from "path";
1893
+ import { mkdirSync as mkdirSync8 } from "fs";
1894
+ function createGetNodeForSpaceCommand() {
1895
+ return new Command8("get_node_for_space").description("\u83B7\u53D6\u8282\u70B9\u7684\u7A7A\u95F4\u4F4D\u7F6E\u4FE1\u606F\uFF08id\u3001name\u3001x\u3001y\u3001width\u3001height\uFF09\uFF0C\u7528\u4E8E AI \u7406\u89E3\u5143\u7D20\u5E03\u5C40\u3002\u9ED8\u8BA4\u83B7\u53D6\u6700\u6DF1\u5C42\u7EA7").option("--nodeId <id>", "\u8282\u70B9 ID\uFF0C\u683C\u5F0F\u5982 123:456\u3002\u4E0E --link \u4E8C\u9009\u4E00").option("--link <url>", "mgp:// \u534F\u8BAE\u94FE\u63A5\u3002\u4E0E --nodeId \u4E8C\u9009\u4E00").requiredOption("--output <path>", "\u8F93\u51FA JSON \u6587\u4EF6\u8DEF\u5F84").option("--domain <domain>", "MasterGo \u57DF\u540D\uFF0C\u9ED8\u8BA4 mastergo.netease.com\u3002\u4E0E --nodeId \u914D\u5408\u4F7F\u7528", "mastergo.netease.com").option("--fileId <id>", "\u6587\u4EF6 ID\uFF08\u7EAF\u6570\u5B57\uFF09\uFF0C\u4E0E --domain \u548C --nodeId \u914D\u5408\u4F7F\u7528").option("--maxDepth <number>", "\u904D\u5386\u6DF1\u5EA6\uFF0C\u9ED8\u8BA4 99\uFF08\u83B7\u53D6\u6700\u6DF1\u5C42\u7EA7\uFF09", "99").option("--includeInvisible", "\u5305\u542B\u4E0D\u53EF\u89C1\u8282\u70B9", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
1896
+ await handleGetNodeForSpace(options);
1897
+ });
1898
+ }
1899
+ async function handleGetNodeForSpace(options) {
1900
+ if (!options.nodeId && !options.link) {
1901
+ console.error(`\u9519\u8BEF [${"E011" /* INVALID_PARAMS */}]: \u5FC5\u987B\u63D0\u4F9B --nodeId \u6216 --link \u53C2\u6570`);
1902
+ process.exit(1);
1903
+ }
1904
+ if (options.nodeId && options.link) {
1905
+ console.error(`\u9519\u8BEF [${"E011" /* INVALID_PARAMS */}]: --nodeId \u548C --link \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528`);
1906
+ process.exit(1);
1907
+ }
1908
+ let pageUrl;
1909
+ let nodeId;
1910
+ if (options.link) {
1911
+ const parsed = parseMgpLink(options.link);
1912
+ if (!parsed) {
1913
+ console.error(`\u9519\u8BEF [${"E010" /* INVALID_LINK */}]: \u65E0\u6548\u7684 mgp:// \u94FE\u63A5\u683C\u5F0F`);
1914
+ console.error(`\u63D0\u4F9B\u7684\u94FE\u63A5: ${options.link}`);
1915
+ console.error(`\u671F\u671B\u683C\u5F0F: mgp://[mastergo_page_url]?nodeId=xxx`);
1916
+ process.exit(1);
1917
+ }
1918
+ pageUrl = parsed.pageUrl;
1919
+ nodeId = parsed.nodeId;
1920
+ } else {
1921
+ nodeId = options.nodeId;
1922
+ if (options.fileId) {
1923
+ const domain = options.domain || "mastergo.netease.com";
1924
+ pageUrl = `${domain}/file/${options.fileId}`;
1925
+ }
1926
+ }
1927
+ const client = new MGClient({
1928
+ noAutoStart: options.noAutoStart,
1929
+ noRetry: options.noRetry
1930
+ });
1931
+ try {
1932
+ await client.connect();
1933
+ const params = {
1934
+ nodeId,
1935
+ maxDepth: parseInt(options.maxDepth || "99", 10),
1936
+ includeInvisible: options.includeInvisible || false
1937
+ };
1938
+ const data = await client.requestWithRetry(
1939
+ "get_node_by_id" /* GET_NODE_BY_ID */,
1940
+ params,
1941
+ pageUrl
1942
+ );
1943
+ const spaceData = extractSpaceInfo(data);
1944
+ const outputPath = resolve7(options.output);
1945
+ const outputDir = dirname10(outputPath);
1946
+ mkdirSync8(outputDir, { recursive: true });
1947
+ const jsonContent = JSON.stringify(spaceData, null, 2);
1948
+ writeFileSync7(outputPath, jsonContent, "utf-8");
1949
+ const size = jsonContent.length;
1950
+ const sizeKB = (size / 1024).toFixed(2);
1951
+ console.log(`\u6587\u4EF6\u8DEF\u5F84: ${outputPath}`);
1952
+ if (options.link) {
1953
+ console.log(`Link: ${options.link}`);
1954
+ console.log(`\u9875\u9762 URL: ${pageUrl}`);
1955
+ }
1956
+ console.log(`\u8282\u70B9 ID: ${nodeId}`);
1957
+ console.log(`\u6570\u636E\u5927\u5C0F: ${size.toLocaleString()} \u5B57\u7B26 (\u7EA6 ${sizeKB} KB)`);
1958
+ console.log(`\u8282\u70B9\u6DF1\u5EA6: ${params.maxDepth}`);
1959
+ console.log(`\u6570\u636E\u6A21\u5F0F: \u7A7A\u95F4\u4FE1\u606F (\u4EC5 id, name, x, y, width, height)`);
1960
+ } catch (error) {
1961
+ if (error instanceof MGError) {
1962
+ console.error(`\u9519\u8BEF [${error.code}]: ${error.message}`);
1963
+ } else {
1964
+ console.error(`\u9519\u8BEF: ${error instanceof Error ? error.message : error}`);
1965
+ }
1966
+ process.exit(1);
1967
+ } finally {
1968
+ client.close();
1969
+ }
1970
+ }
1971
+
1569
1972
  // src/cli/index.ts
1570
- var program = new Command8();
1973
+ var program = new Command9();
1571
1974
  program.name("mg-cli").description("MasterGo CLI \u5DE5\u5177 - \u7528\u4E8E Claude Code \u4E0E MasterGo \u901A\u4FE1").version("1.0.0");
1572
1975
  program.addCommand(createServerCommand());
1573
1976
  program.addCommand(createGetNodeByIdCommand());
@@ -1576,5 +1979,6 @@ program.addCommand(createGetAllNodesCommand());
1576
1979
  program.addCommand(createExportImageCommand());
1577
1980
  program.addCommand(createExecuteCodeCommand());
1578
1981
  program.addCommand(createGetAllPagesCommand());
1982
+ program.addCommand(createGetNodeForSpaceCommand());
1579
1983
  program.parse();
1580
1984
  //# sourceMappingURL=cli.js.map