@hangox/mg-cli 1.0.9 → 1.1.0
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 +565 -107
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,139 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command13 } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/cli/version-check.ts
|
|
7
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { join as join2 } from "path";
|
|
10
|
+
import { execSync } from "child_process";
|
|
11
|
+
|
|
12
|
+
// src/shared/version.ts
|
|
13
|
+
import { readFileSync, existsSync } from "fs";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
import { dirname, join } from "path";
|
|
16
|
+
var cachedVersion = null;
|
|
17
|
+
function getVersion() {
|
|
18
|
+
if (cachedVersion !== null) {
|
|
19
|
+
return cachedVersion;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
23
|
+
const currentDir = dirname(currentFile);
|
|
24
|
+
const packageJsonPaths = [
|
|
25
|
+
join(currentDir, "..", "package.json"),
|
|
26
|
+
// dist/xxx.js -> ../package.json
|
|
27
|
+
join(currentDir, "..", "..", "package.json")
|
|
28
|
+
// src/shared/version.ts -> ../../package.json
|
|
29
|
+
];
|
|
30
|
+
for (const packageJsonPath of packageJsonPaths) {
|
|
31
|
+
if (existsSync(packageJsonPath)) {
|
|
32
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
33
|
+
if (packageJson.name === "@hangox/mg-cli") {
|
|
34
|
+
cachedVersion = packageJson.version || "0.0.0";
|
|
35
|
+
return cachedVersion;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
cachedVersion = "0.0.0";
|
|
40
|
+
return cachedVersion;
|
|
41
|
+
} catch {
|
|
42
|
+
cachedVersion = "0.0.0";
|
|
43
|
+
return cachedVersion;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
var DEV_VERSION = "9.9.9";
|
|
47
|
+
function isVersionMatch(version1, version2) {
|
|
48
|
+
if (version1 === DEV_VERSION || version2 === DEV_VERSION) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return version1 === version2;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/cli/version-check.ts
|
|
55
|
+
var CONFIG_DIR = join2(homedir(), ".config", "mg-cli");
|
|
56
|
+
var CHECK_FILE = join2(CONFIG_DIR, "last-version-check");
|
|
57
|
+
var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
|
|
58
|
+
function readCheckData() {
|
|
59
|
+
try {
|
|
60
|
+
if (!existsSync2(CHECK_FILE)) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const content = readFileSync2(CHECK_FILE, "utf-8");
|
|
64
|
+
return JSON.parse(content);
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function writeCheckData(data) {
|
|
70
|
+
try {
|
|
71
|
+
if (!existsSync2(CONFIG_DIR)) {
|
|
72
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
73
|
+
}
|
|
74
|
+
writeFileSync(CHECK_FILE, JSON.stringify(data), "utf-8");
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function getRemoteVersion() {
|
|
79
|
+
try {
|
|
80
|
+
const result = execSync("npm view @hangox/mg-cli version", {
|
|
81
|
+
encoding: "utf-8",
|
|
82
|
+
timeout: 5e3,
|
|
83
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
84
|
+
});
|
|
85
|
+
return result.trim();
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function isNewerVersion(local, remote) {
|
|
91
|
+
const localParts = local.split(".").map(Number);
|
|
92
|
+
const remoteParts = remote.split(".").map(Number);
|
|
93
|
+
for (let i = 0; i < 3; i++) {
|
|
94
|
+
const l = localParts[i] || 0;
|
|
95
|
+
const r = remoteParts[i] || 0;
|
|
96
|
+
if (r > l) return true;
|
|
97
|
+
if (r < l) return false;
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
function checkForUpdates() {
|
|
102
|
+
try {
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
const checkData = readCheckData();
|
|
105
|
+
if (checkData && now - checkData.timestamp < CHECK_INTERVAL) {
|
|
106
|
+
if (checkData.remoteVersion && isNewerVersion(getVersion(), checkData.remoteVersion)) {
|
|
107
|
+
printUpdateNotice(checkData.remoteVersion);
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const remoteVersion = getRemoteVersion();
|
|
112
|
+
if (remoteVersion) {
|
|
113
|
+
writeCheckData({
|
|
114
|
+
timestamp: now,
|
|
115
|
+
remoteVersion
|
|
116
|
+
});
|
|
117
|
+
if (isNewerVersion(getVersion(), remoteVersion)) {
|
|
118
|
+
printUpdateNotice(remoteVersion);
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
writeCheckData({
|
|
122
|
+
timestamp: now
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
} catch {
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function printUpdateNotice(remoteVersion) {
|
|
129
|
+
const localVersion = getVersion();
|
|
130
|
+
console.log("");
|
|
131
|
+
console.log(`\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510`);
|
|
132
|
+
console.log(`\u2502 \u53D1\u73B0\u65B0\u7248\u672C ${remoteVersion}\uFF08\u5F53\u524D ${localVersion}\uFF09`);
|
|
133
|
+
console.log(`\u2502 \u8FD0\u884C npm install -g @hangox/mg-cli \u66F4\u65B0`);
|
|
134
|
+
console.log(`\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518`);
|
|
135
|
+
console.log("");
|
|
136
|
+
}
|
|
5
137
|
|
|
6
138
|
// src/cli/commands/server.ts
|
|
7
139
|
import { Command } from "commander";
|
|
@@ -9,15 +141,15 @@ import { Command } from "commander";
|
|
|
9
141
|
// src/server/daemon.ts
|
|
10
142
|
import { spawn } from "child_process";
|
|
11
143
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12
|
-
import { dirname as dirname4, join as
|
|
144
|
+
import { dirname as dirname4, join as join4 } from "path";
|
|
13
145
|
|
|
14
146
|
// src/shared/utils.ts
|
|
15
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
16
|
-
import { dirname, resolve, isAbsolute } from "path";
|
|
147
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
148
|
+
import { dirname as dirname2, resolve, isAbsolute } from "path";
|
|
17
149
|
|
|
18
150
|
// src/shared/constants.ts
|
|
19
|
-
import { homedir } from "os";
|
|
20
|
-
import { join } from "path";
|
|
151
|
+
import { homedir as homedir2 } from "os";
|
|
152
|
+
import { join as join3 } from "path";
|
|
21
153
|
var IS_DEV_MODE = process.env.MG_DEV_MODE === "true";
|
|
22
154
|
var PROD_DEFAULT_PORT = 9527;
|
|
23
155
|
var PROD_PORT_RANGE_START = 9527;
|
|
@@ -29,10 +161,10 @@ var DEFAULT_PORT = IS_DEV_MODE ? DEV_DEFAULT_PORT : PROD_DEFAULT_PORT;
|
|
|
29
161
|
var PORT_RANGE_START = IS_DEV_MODE ? DEV_PORT_RANGE_START : PROD_PORT_RANGE_START;
|
|
30
162
|
var PORT_RANGE_END = IS_DEV_MODE ? DEV_PORT_RANGE_END : PROD_PORT_RANGE_END;
|
|
31
163
|
var PORT_SCAN_TIMEOUT = 500;
|
|
32
|
-
var
|
|
33
|
-
var SERVER_INFO_FILE =
|
|
34
|
-
var LOG_DIR =
|
|
35
|
-
var SERVER_LOG_FILE =
|
|
164
|
+
var CONFIG_DIR2 = join3(homedir2(), ".mg-plugin");
|
|
165
|
+
var SERVER_INFO_FILE = join3(CONFIG_DIR2, "server.json");
|
|
166
|
+
var LOG_DIR = join3(CONFIG_DIR2, "logs");
|
|
167
|
+
var SERVER_LOG_FILE = join3(LOG_DIR, "server.log");
|
|
36
168
|
var HEARTBEAT_INTERVAL = 3e4;
|
|
37
169
|
var HEARTBEAT_TIMEOUT = 9e4;
|
|
38
170
|
var REQUEST_TIMEOUT = 3e4;
|
|
@@ -42,20 +174,20 @@ var MAX_RETRY_COUNT = 3;
|
|
|
42
174
|
|
|
43
175
|
// src/shared/utils.ts
|
|
44
176
|
function ensureDir(dir) {
|
|
45
|
-
if (!
|
|
46
|
-
|
|
177
|
+
if (!existsSync3(dir)) {
|
|
178
|
+
mkdirSync2(dir, { recursive: true });
|
|
47
179
|
}
|
|
48
180
|
}
|
|
49
181
|
function ensureConfigDir() {
|
|
50
|
-
ensureDir(
|
|
182
|
+
ensureDir(CONFIG_DIR2);
|
|
51
183
|
ensureDir(LOG_DIR);
|
|
52
184
|
}
|
|
53
185
|
function readServerInfo() {
|
|
54
186
|
try {
|
|
55
|
-
if (!
|
|
187
|
+
if (!existsSync3(SERVER_INFO_FILE)) {
|
|
56
188
|
return null;
|
|
57
189
|
}
|
|
58
|
-
const content =
|
|
190
|
+
const content = readFileSync3(SERVER_INFO_FILE, "utf-8");
|
|
59
191
|
return JSON.parse(content);
|
|
60
192
|
} catch {
|
|
61
193
|
return null;
|
|
@@ -63,11 +195,11 @@ function readServerInfo() {
|
|
|
63
195
|
}
|
|
64
196
|
function writeServerInfo(info) {
|
|
65
197
|
ensureConfigDir();
|
|
66
|
-
|
|
198
|
+
writeFileSync2(SERVER_INFO_FILE, JSON.stringify(info, null, 2), "utf-8");
|
|
67
199
|
}
|
|
68
200
|
function deleteServerInfo() {
|
|
69
201
|
try {
|
|
70
|
-
if (
|
|
202
|
+
if (existsSync3(SERVER_INFO_FILE)) {
|
|
71
203
|
unlinkSync(SERVER_INFO_FILE);
|
|
72
204
|
}
|
|
73
205
|
} catch {
|
|
@@ -428,8 +560,8 @@ var MGError = class extends Error {
|
|
|
428
560
|
import { WebSocketServer } from "ws";
|
|
429
561
|
|
|
430
562
|
// src/server/logger.ts
|
|
431
|
-
import { appendFileSync, existsSync as
|
|
432
|
-
import { dirname as
|
|
563
|
+
import { appendFileSync, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
564
|
+
import { dirname as dirname3 } from "path";
|
|
433
565
|
var levelPriority = {
|
|
434
566
|
["DEBUG" /* DEBUG */]: 0,
|
|
435
567
|
["INFO" /* INFO */]: 1,
|
|
@@ -446,9 +578,9 @@ var Logger = class {
|
|
|
446
578
|
minLevel: options.minLevel ?? "INFO" /* INFO */
|
|
447
579
|
};
|
|
448
580
|
if (this.options.file) {
|
|
449
|
-
const dir =
|
|
450
|
-
if (!
|
|
451
|
-
|
|
581
|
+
const dir = dirname3(this.options.filePath);
|
|
582
|
+
if (!existsSync4(dir)) {
|
|
583
|
+
mkdirSync3(dir, { recursive: true });
|
|
452
584
|
}
|
|
453
585
|
}
|
|
454
586
|
}
|
|
@@ -889,48 +1021,6 @@ var RequestHandler = class {
|
|
|
889
1021
|
}
|
|
890
1022
|
};
|
|
891
1023
|
|
|
892
|
-
// src/shared/version.ts
|
|
893
|
-
import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
|
|
894
|
-
import { fileURLToPath } from "url";
|
|
895
|
-
import { dirname as dirname3, join as join2 } from "path";
|
|
896
|
-
var cachedVersion = null;
|
|
897
|
-
function getVersion() {
|
|
898
|
-
if (cachedVersion !== null) {
|
|
899
|
-
return cachedVersion;
|
|
900
|
-
}
|
|
901
|
-
try {
|
|
902
|
-
const currentFile = fileURLToPath(import.meta.url);
|
|
903
|
-
const currentDir = dirname3(currentFile);
|
|
904
|
-
const packageJsonPaths = [
|
|
905
|
-
join2(currentDir, "..", "package.json"),
|
|
906
|
-
// dist/xxx.js -> ../package.json
|
|
907
|
-
join2(currentDir, "..", "..", "package.json")
|
|
908
|
-
// src/shared/version.ts -> ../../package.json
|
|
909
|
-
];
|
|
910
|
-
for (const packageJsonPath of packageJsonPaths) {
|
|
911
|
-
if (existsSync3(packageJsonPath)) {
|
|
912
|
-
const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
|
|
913
|
-
if (packageJson.name === "@hangox/mg-cli") {
|
|
914
|
-
cachedVersion = packageJson.version || "0.0.0";
|
|
915
|
-
return cachedVersion;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
cachedVersion = "0.0.0";
|
|
920
|
-
return cachedVersion;
|
|
921
|
-
} catch {
|
|
922
|
-
cachedVersion = "0.0.0";
|
|
923
|
-
return cachedVersion;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
var DEV_VERSION = "9.9.9";
|
|
927
|
-
function isVersionMatch(version1, version2) {
|
|
928
|
-
if (version1 === DEV_VERSION || version2 === DEV_VERSION) {
|
|
929
|
-
return true;
|
|
930
|
-
}
|
|
931
|
-
return version1 === version2;
|
|
932
|
-
}
|
|
933
|
-
|
|
934
1024
|
// src/server/websocket-server.ts
|
|
935
1025
|
var MGServer = class {
|
|
936
1026
|
wss = null;
|
|
@@ -954,7 +1044,7 @@ var MGServer = class {
|
|
|
954
1044
|
throw new MGError("E016" /* SERVER_ALREADY_RUNNING */, "Server \u5DF2\u5728\u8FD0\u884C\u4E2D");
|
|
955
1045
|
}
|
|
956
1046
|
const port = await this.findAvailablePort();
|
|
957
|
-
return new Promise((
|
|
1047
|
+
return new Promise((resolve9, reject) => {
|
|
958
1048
|
this.wss = new WebSocketServer({ port });
|
|
959
1049
|
this.wss.on("listening", () => {
|
|
960
1050
|
this.port = port;
|
|
@@ -962,7 +1052,7 @@ var MGServer = class {
|
|
|
962
1052
|
this.startedAt = /* @__PURE__ */ new Date();
|
|
963
1053
|
this.logger.info(`Server \u542F\u52A8\u6210\u529F\uFF0C\u76D1\u542C\u7AEF\u53E3: ${port}`);
|
|
964
1054
|
this.connectionManager.startHeartbeatCheck(HEARTBEAT_INTERVAL);
|
|
965
|
-
|
|
1055
|
+
resolve9(port);
|
|
966
1056
|
});
|
|
967
1057
|
this.wss.on("error", (error) => {
|
|
968
1058
|
this.logger.error("Server \u9519\u8BEF:", error);
|
|
@@ -993,14 +1083,14 @@ var MGServer = class {
|
|
|
993
1083
|
* 检查端口是否可用
|
|
994
1084
|
*/
|
|
995
1085
|
isPortAvailable(port) {
|
|
996
|
-
return new Promise((
|
|
1086
|
+
return new Promise((resolve9) => {
|
|
997
1087
|
const testServer = new WebSocketServer({ port });
|
|
998
1088
|
testServer.on("listening", () => {
|
|
999
1089
|
testServer.close();
|
|
1000
|
-
|
|
1090
|
+
resolve9(true);
|
|
1001
1091
|
});
|
|
1002
1092
|
testServer.on("error", () => {
|
|
1003
|
-
|
|
1093
|
+
resolve9(false);
|
|
1004
1094
|
});
|
|
1005
1095
|
});
|
|
1006
1096
|
}
|
|
@@ -1318,12 +1408,12 @@ var MGServer = class {
|
|
|
1318
1408
|
this.logger.info("\u6B63\u5728\u505C\u6B62 Server...");
|
|
1319
1409
|
this.requestHandler.cleanupAll();
|
|
1320
1410
|
this.connectionManager.closeAll();
|
|
1321
|
-
return new Promise((
|
|
1411
|
+
return new Promise((resolve9) => {
|
|
1322
1412
|
this.wss.close(() => {
|
|
1323
1413
|
this.isRunning = false;
|
|
1324
1414
|
this.wss = null;
|
|
1325
1415
|
this.logger.info("Server \u5DF2\u505C\u6B62");
|
|
1326
|
-
|
|
1416
|
+
resolve9();
|
|
1327
1417
|
});
|
|
1328
1418
|
});
|
|
1329
1419
|
}
|
|
@@ -1424,7 +1514,7 @@ async function startServerDaemon(port) {
|
|
|
1424
1514
|
ensureConfigDir();
|
|
1425
1515
|
const currentFile = fileURLToPath2(import.meta.url);
|
|
1426
1516
|
const currentDir = dirname4(currentFile);
|
|
1427
|
-
const serverScript =
|
|
1517
|
+
const serverScript = join4(currentDir, "daemon-runner.js");
|
|
1428
1518
|
const args = ["--foreground"];
|
|
1429
1519
|
if (port) {
|
|
1430
1520
|
args.push("--port", String(port));
|
|
@@ -1440,7 +1530,7 @@ async function startServerDaemon(port) {
|
|
|
1440
1530
|
child.unref();
|
|
1441
1531
|
const startTime = Date.now();
|
|
1442
1532
|
while (Date.now() - startTime < SERVER_START_TIMEOUT) {
|
|
1443
|
-
await new Promise((
|
|
1533
|
+
await new Promise((resolve9) => setTimeout(resolve9, 200));
|
|
1444
1534
|
const { running: running2, info: info2 } = isServerRunning();
|
|
1445
1535
|
if (running2 && info2) {
|
|
1446
1536
|
return info2;
|
|
@@ -1461,7 +1551,7 @@ function stopServer() {
|
|
|
1461
1551
|
}
|
|
1462
1552
|
async function restartServer(port) {
|
|
1463
1553
|
const { info: oldInfo } = stopServer();
|
|
1464
|
-
await new Promise((
|
|
1554
|
+
await new Promise((resolve9) => setTimeout(resolve9, 500));
|
|
1465
1555
|
return startServerDaemon(port || oldInfo?.port);
|
|
1466
1556
|
}
|
|
1467
1557
|
function getServerStatus() {
|
|
@@ -1534,7 +1624,7 @@ var MGClient = class {
|
|
|
1534
1624
|
* 尝试连接指定端口
|
|
1535
1625
|
*/
|
|
1536
1626
|
tryConnect(port) {
|
|
1537
|
-
return new Promise((
|
|
1627
|
+
return new Promise((resolve9, reject) => {
|
|
1538
1628
|
const ws = new WebSocket2(`ws://localhost:${port}`);
|
|
1539
1629
|
const timer = setTimeout(() => {
|
|
1540
1630
|
ws.close();
|
|
@@ -1544,7 +1634,7 @@ var MGClient = class {
|
|
|
1544
1634
|
clearTimeout(timer);
|
|
1545
1635
|
this.ws = ws;
|
|
1546
1636
|
this.register();
|
|
1547
|
-
|
|
1637
|
+
resolve9();
|
|
1548
1638
|
});
|
|
1549
1639
|
ws.on("error", (error) => {
|
|
1550
1640
|
clearTimeout(timer);
|
|
@@ -1597,7 +1687,7 @@ var MGClient = class {
|
|
|
1597
1687
|
pageUrl,
|
|
1598
1688
|
timestamp: Date.now()
|
|
1599
1689
|
};
|
|
1600
|
-
return new Promise((
|
|
1690
|
+
return new Promise((resolve9, reject) => {
|
|
1601
1691
|
const timer = setTimeout(() => {
|
|
1602
1692
|
reject(new MGError("E012" /* REQUEST_TIMEOUT */, ErrorMessages["E012" /* REQUEST_TIMEOUT */]));
|
|
1603
1693
|
}, REQUEST_TIMEOUT);
|
|
@@ -1608,7 +1698,7 @@ var MGClient = class {
|
|
|
1608
1698
|
clearTimeout(timer);
|
|
1609
1699
|
this.ws?.off("message", messageHandler);
|
|
1610
1700
|
if (response.success) {
|
|
1611
|
-
|
|
1701
|
+
resolve9(response.data);
|
|
1612
1702
|
} else {
|
|
1613
1703
|
const error = response.error;
|
|
1614
1704
|
reject(
|
|
@@ -1790,9 +1880,9 @@ function createServerCommand() {
|
|
|
1790
1880
|
|
|
1791
1881
|
// src/cli/commands/get-node-by-id.ts
|
|
1792
1882
|
import { Command as Command2 } from "commander";
|
|
1793
|
-
import { writeFileSync as
|
|
1883
|
+
import { writeFileSync as writeFileSync3 } from "fs";
|
|
1794
1884
|
import { resolve as resolve2, dirname as dirname5 } from "path";
|
|
1795
|
-
import { mkdirSync as
|
|
1885
|
+
import { mkdirSync as mkdirSync4 } from "fs";
|
|
1796
1886
|
function createGetNodeByIdCommand() {
|
|
1797
1887
|
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("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
|
|
1798
1888
|
await handleGetNodeById(options);
|
|
@@ -1819,9 +1909,9 @@ async function handleGetNodeById(options) {
|
|
|
1819
1909
|
const outputData = options.raw ? data : trimNodeDefaults(data);
|
|
1820
1910
|
const outputPath = resolve2(options.output);
|
|
1821
1911
|
const outputDir = dirname5(outputPath);
|
|
1822
|
-
|
|
1912
|
+
mkdirSync4(outputDir, { recursive: true });
|
|
1823
1913
|
const jsonContent = JSON.stringify(outputData, null, options.pretty ? 2 : 0);
|
|
1824
|
-
|
|
1914
|
+
writeFileSync3(outputPath, jsonContent, "utf-8");
|
|
1825
1915
|
const size = jsonContent.length;
|
|
1826
1916
|
const sizeKB = (size / 1024).toFixed(2);
|
|
1827
1917
|
console.log(`\u6587\u4EF6\u8DEF\u5F84: ${outputPath}`);
|
|
@@ -1842,9 +1932,9 @@ async function handleGetNodeById(options) {
|
|
|
1842
1932
|
|
|
1843
1933
|
// src/cli/commands/get-node-by-link.ts
|
|
1844
1934
|
import { Command as Command3 } from "commander";
|
|
1845
|
-
import { writeFileSync as
|
|
1935
|
+
import { writeFileSync as writeFileSync4 } from "fs";
|
|
1846
1936
|
import { resolve as resolve3, dirname as dirname6 } from "path";
|
|
1847
|
-
import { mkdirSync as
|
|
1937
|
+
import { mkdirSync as mkdirSync5 } from "fs";
|
|
1848
1938
|
function createGetNodeByLinkCommand() {
|
|
1849
1939
|
return new Command3("get_node_by_link").description("\u89E3\u6790 mgp:// \u534F\u8BAE\u94FE\u63A5\u5E76\u83B7\u53D6\u8282\u70B9/\u9875\u9762\u4FE1\u606F").requiredOption("--link <url>", "mgp:// \u534F\u8BAE\u94FE\u63A5\uFF08\u652F\u6301 nodeId \u548C pageId\uFF09").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("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
|
|
1850
1940
|
await handleGetNodeByLink(options);
|
|
@@ -1895,9 +1985,9 @@ async function handleGetNodeByLink(options) {
|
|
|
1895
1985
|
const outputData = options.raw ? data : trimNodeDefaults(data);
|
|
1896
1986
|
const outputPath = resolve3(options.output);
|
|
1897
1987
|
const outputDir = dirname6(outputPath);
|
|
1898
|
-
|
|
1988
|
+
mkdirSync5(outputDir, { recursive: true });
|
|
1899
1989
|
const jsonContent = JSON.stringify(outputData, null, options.pretty ? 2 : 0);
|
|
1900
|
-
|
|
1990
|
+
writeFileSync4(outputPath, jsonContent, "utf-8");
|
|
1901
1991
|
const size = jsonContent.length;
|
|
1902
1992
|
const sizeKB = (size / 1024).toFixed(2);
|
|
1903
1993
|
console.log(`\u6587\u4EF6\u8DEF\u5F84: ${outputPath}`);
|
|
@@ -1930,9 +2020,9 @@ async function handleGetNodeByLink(options) {
|
|
|
1930
2020
|
|
|
1931
2021
|
// src/cli/commands/get-all-nodes.ts
|
|
1932
2022
|
import { Command as Command4 } from "commander";
|
|
1933
|
-
import { writeFileSync as
|
|
2023
|
+
import { writeFileSync as writeFileSync5 } from "fs";
|
|
1934
2024
|
import { resolve as resolve4, dirname as dirname7 } from "path";
|
|
1935
|
-
import { mkdirSync as
|
|
2025
|
+
import { mkdirSync as mkdirSync6 } from "fs";
|
|
1936
2026
|
function createGetAllNodesCommand() {
|
|
1937
2027
|
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("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
|
|
1938
2028
|
await handleGetAllNodes(options);
|
|
@@ -1953,9 +2043,9 @@ async function handleGetAllNodes(options) {
|
|
|
1953
2043
|
const outputData = options.raw ? data : Array.isArray(data) ? data.map((node) => trimNodeDefaults(node)) : trimNodeDefaults(data);
|
|
1954
2044
|
const outputPath = resolve4(options.output);
|
|
1955
2045
|
const outputDir = dirname7(outputPath);
|
|
1956
|
-
|
|
2046
|
+
mkdirSync6(outputDir, { recursive: true });
|
|
1957
2047
|
const jsonContent = JSON.stringify(outputData, null, options.pretty ? 2 : 0);
|
|
1958
|
-
|
|
2048
|
+
writeFileSync5(outputPath, jsonContent, "utf-8");
|
|
1959
2049
|
const size = jsonContent.length;
|
|
1960
2050
|
const sizeKB = (size / 1024).toFixed(2);
|
|
1961
2051
|
const nodeCount = Array.isArray(data) ? data.length : 1;
|
|
@@ -1977,9 +2067,9 @@ async function handleGetAllNodes(options) {
|
|
|
1977
2067
|
|
|
1978
2068
|
// src/cli/commands/export-image.ts
|
|
1979
2069
|
import { Command as Command5 } from "commander";
|
|
1980
|
-
import { writeFileSync as
|
|
2070
|
+
import { writeFileSync as writeFileSync6, unlinkSync as unlinkSync2 } from "fs";
|
|
1981
2071
|
import { resolve as resolve5, dirname as dirname8, extname, basename } from "path";
|
|
1982
|
-
import { mkdirSync as
|
|
2072
|
+
import { mkdirSync as mkdirSync7 } from "fs";
|
|
1983
2073
|
import { tmpdir } from "os";
|
|
1984
2074
|
import { vdConvert } from "vd-tool";
|
|
1985
2075
|
function createExportImageCommand() {
|
|
@@ -2069,23 +2159,23 @@ async function handleExportImage(options) {
|
|
|
2069
2159
|
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");
|
|
2070
2160
|
}
|
|
2071
2161
|
const outputDir = dirname8(outputPath);
|
|
2072
|
-
|
|
2162
|
+
mkdirSync7(outputDir, { recursive: true });
|
|
2073
2163
|
const buffer = Buffer.from(response.data, "base64");
|
|
2074
2164
|
let finalPath = outputPath;
|
|
2075
2165
|
let finalSize = buffer.length;
|
|
2076
2166
|
if (isVectorFormat) {
|
|
2077
2167
|
const tempSvgPath = resolve5(tmpdir(), `temp_${Date.now()}.svg`);
|
|
2078
|
-
|
|
2168
|
+
writeFileSync6(tempSvgPath, buffer);
|
|
2079
2169
|
try {
|
|
2080
2170
|
const vectorOutputDir = dirname8(outputPath);
|
|
2081
2171
|
const convertedPath = await convertSvgToVector(tempSvgPath, vectorOutputDir);
|
|
2082
2172
|
const expectedOutputName = basename(tempSvgPath, ".svg") + ".xml";
|
|
2083
2173
|
const expectedOutputPath = resolve5(vectorOutputDir, expectedOutputName);
|
|
2084
2174
|
if (expectedOutputPath !== outputPath) {
|
|
2085
|
-
const { renameSync, existsSync:
|
|
2086
|
-
if (
|
|
2175
|
+
const { renameSync, existsSync: existsSync5 } = await import("fs");
|
|
2176
|
+
if (existsSync5(expectedOutputPath)) {
|
|
2087
2177
|
renameSync(expectedOutputPath, outputPath);
|
|
2088
|
-
} else if (
|
|
2178
|
+
} else if (existsSync5(convertedPath)) {
|
|
2089
2179
|
renameSync(convertedPath, outputPath);
|
|
2090
2180
|
}
|
|
2091
2181
|
}
|
|
@@ -2099,7 +2189,7 @@ async function handleExportImage(options) {
|
|
|
2099
2189
|
}
|
|
2100
2190
|
}
|
|
2101
2191
|
} else {
|
|
2102
|
-
|
|
2192
|
+
writeFileSync6(outputPath, buffer);
|
|
2103
2193
|
}
|
|
2104
2194
|
const sizeKB = (finalSize / 1024).toFixed(2);
|
|
2105
2195
|
console.log(`\u6587\u4EF6\u8DEF\u5F84: ${finalPath}`);
|
|
@@ -2210,9 +2300,9 @@ async function handleExecuteCode(code, options) {
|
|
|
2210
2300
|
|
|
2211
2301
|
// src/cli/commands/get-all-pages.ts
|
|
2212
2302
|
import { Command as Command7 } from "commander";
|
|
2213
|
-
import { writeFileSync as
|
|
2303
|
+
import { writeFileSync as writeFileSync7 } from "fs";
|
|
2214
2304
|
import { resolve as resolve6, dirname as dirname9 } from "path";
|
|
2215
|
-
import { mkdirSync as
|
|
2305
|
+
import { mkdirSync as mkdirSync8 } from "fs";
|
|
2216
2306
|
import { tmpdir as tmpdir2 } from "os";
|
|
2217
2307
|
function createGetAllPagesCommand() {
|
|
2218
2308
|
return new Command7("get_all_pages").description("\u83B7\u53D6 MasterGo \u6587\u6863\u7684\u6240\u6709\u9875\u9762\u4FE1\u606F\u3002\u4E0D\u6307\u5B9A --output \u65F6\u4FDD\u5B58\u5230\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55").option("--link <url>", "\u9875\u9762\u94FE\u63A5\u3002\u652F\u6301\u5B8C\u6574 URL \u6216 mgp:// \u534F\u8BAE").option("--fileId <id>", "\u6587\u4EF6 ID\uFF08\u7EAF\u6570\u5B57\uFF09\u3002\u4ECE URL \u4E2D /file/ \u540E\u9762\u7684\u6570\u5B57").option("--domain <domain>", "MasterGo \u57DF\u540D\uFF0C\u9ED8\u8BA4 mastergo.netease.com\u3002\u4E0E --fileId \u914D\u5408\u4F7F\u7528", "mastergo.netease.com").option("--output <path>", "\u8F93\u51FA JSON \u6587\u4EF6\u8DEF\u5F84\u3002\u4E0D\u6307\u5B9A\u5219\u4FDD\u5B58\u5230\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55").option("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
|
|
@@ -2260,9 +2350,9 @@ async function handleGetAllPages(options) {
|
|
|
2260
2350
|
outputPath = resolve6(tmpdir2(), filename);
|
|
2261
2351
|
}
|
|
2262
2352
|
const outputDir = dirname9(outputPath);
|
|
2263
|
-
|
|
2353
|
+
mkdirSync8(outputDir, { recursive: true });
|
|
2264
2354
|
const jsonContent = JSON.stringify(data, null, options.pretty ? 2 : 0);
|
|
2265
|
-
|
|
2355
|
+
writeFileSync7(outputPath, jsonContent, "utf-8");
|
|
2266
2356
|
const size = jsonContent.length;
|
|
2267
2357
|
const sizeKB = (size / 1024).toFixed(2);
|
|
2268
2358
|
console.log(`\u6587\u4EF6\u8DEF\u5F84: ${outputPath}`);
|
|
@@ -2280,9 +2370,9 @@ async function handleGetAllPages(options) {
|
|
|
2280
2370
|
|
|
2281
2371
|
// src/cli/commands/get-node-for-space.ts
|
|
2282
2372
|
import { Command as Command8 } from "commander";
|
|
2283
|
-
import { writeFileSync as
|
|
2373
|
+
import { writeFileSync as writeFileSync8 } from "fs";
|
|
2284
2374
|
import { resolve as resolve7, dirname as dirname10 } from "path";
|
|
2285
|
-
import { mkdirSync as
|
|
2375
|
+
import { mkdirSync as mkdirSync9 } from "fs";
|
|
2286
2376
|
function createGetNodeForSpaceCommand() {
|
|
2287
2377
|
return new Command8("get_node_for_space").description("\u83B7\u53D6\u8282\u70B9\u6216\u9875\u9762\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\u3002\u652F\u6301 nodeId \u548C pageId \u94FE\u63A5").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\uFF08\u652F\u6301 nodeId \u548C pageId\uFF09\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("--pretty", "\u683C\u5F0F\u5316\u8F93\u51FA JSON\uFF08\u9ED8\u8BA4\u538B\u7F29\uFF09", false).option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
|
|
2288
2378
|
await handleGetNodeForSpace(options);
|
|
@@ -2362,9 +2452,9 @@ async function handleGetNodeForSpace(options) {
|
|
|
2362
2452
|
const spaceData = extractSpaceInfo(data);
|
|
2363
2453
|
const outputPath = resolve7(options.output);
|
|
2364
2454
|
const outputDir = dirname10(outputPath);
|
|
2365
|
-
|
|
2455
|
+
mkdirSync9(outputDir, { recursive: true });
|
|
2366
2456
|
const jsonContent = JSON.stringify(spaceData, null, options.pretty ? 2 : 0);
|
|
2367
|
-
|
|
2457
|
+
writeFileSync8(outputPath, jsonContent, "utf-8");
|
|
2368
2458
|
const size = jsonContent.length;
|
|
2369
2459
|
const sizeKB = (size / 1024).toFixed(2);
|
|
2370
2460
|
console.log(`\u6587\u4EF6\u8DEF\u5F84: ${outputPath}`);
|
|
@@ -2616,8 +2706,374 @@ async function handleNavigateToNode(options) {
|
|
|
2616
2706
|
}
|
|
2617
2707
|
}
|
|
2618
2708
|
|
|
2709
|
+
// src/cli/commands/visualize.ts
|
|
2710
|
+
import { Command as Command12 } from "commander";
|
|
2711
|
+
import { writeFileSync as writeFileSync9 } from "fs";
|
|
2712
|
+
import { resolve as resolve8, dirname as dirname11 } from "path";
|
|
2713
|
+
import { mkdirSync as mkdirSync10 } from "fs";
|
|
2714
|
+
|
|
2715
|
+
// src/shared/ascii-renderer.ts
|
|
2716
|
+
var defaultRenderOptions = {
|
|
2717
|
+
showId: true,
|
|
2718
|
+
showSize: true,
|
|
2719
|
+
showPadding: true,
|
|
2720
|
+
showRadius: true,
|
|
2721
|
+
showLayout: true,
|
|
2722
|
+
showGap: true,
|
|
2723
|
+
compact: true
|
|
2724
|
+
};
|
|
2725
|
+
function nodeToRenderNode(node) {
|
|
2726
|
+
const renderNode = {
|
|
2727
|
+
id: node.id,
|
|
2728
|
+
name: node.name,
|
|
2729
|
+
type: node.type,
|
|
2730
|
+
width: Math.round(node.width ?? 0),
|
|
2731
|
+
height: Math.round(node.height ?? 0),
|
|
2732
|
+
x: Math.round(node.x ?? 0),
|
|
2733
|
+
y: Math.round(node.y ?? 0)
|
|
2734
|
+
};
|
|
2735
|
+
const cornerRadius = node.cornerRadius;
|
|
2736
|
+
if (cornerRadius && cornerRadius > 0) {
|
|
2737
|
+
renderNode.cornerRadius = Math.round(cornerRadius);
|
|
2738
|
+
}
|
|
2739
|
+
const paddingTop = node.paddingTop;
|
|
2740
|
+
const paddingRight = node.paddingRight;
|
|
2741
|
+
const paddingBottom = node.paddingBottom;
|
|
2742
|
+
const paddingLeft = node.paddingLeft;
|
|
2743
|
+
if (paddingTop || paddingRight || paddingBottom || paddingLeft) {
|
|
2744
|
+
renderNode.padding = {
|
|
2745
|
+
top: Math.round(paddingTop ?? 0),
|
|
2746
|
+
right: Math.round(paddingRight ?? 0),
|
|
2747
|
+
bottom: Math.round(paddingBottom ?? 0),
|
|
2748
|
+
left: Math.round(paddingLeft ?? 0)
|
|
2749
|
+
};
|
|
2750
|
+
}
|
|
2751
|
+
const flexMode = node.flexMode;
|
|
2752
|
+
if (flexMode === "HORIZONTAL") {
|
|
2753
|
+
renderNode.flexMode = "H";
|
|
2754
|
+
} else if (flexMode === "VERTICAL") {
|
|
2755
|
+
renderNode.flexMode = "V";
|
|
2756
|
+
} else {
|
|
2757
|
+
renderNode.flexMode = "none";
|
|
2758
|
+
}
|
|
2759
|
+
const itemSpacing = node.itemSpacing;
|
|
2760
|
+
if (itemSpacing && itemSpacing > 0) {
|
|
2761
|
+
renderNode.itemSpacing = Math.round(itemSpacing);
|
|
2762
|
+
}
|
|
2763
|
+
if (node.type === "TEXT") {
|
|
2764
|
+
const textStyles = node.textStyles;
|
|
2765
|
+
if (textStyles && textStyles.length > 0) {
|
|
2766
|
+
const firstStyle = textStyles[0];
|
|
2767
|
+
const fontFamily = firstStyle.textStyle?.fontName?.family;
|
|
2768
|
+
const fontSize = firstStyle.textStyle?.fontSize;
|
|
2769
|
+
if (fontFamily && fontSize) {
|
|
2770
|
+
renderNode.font = {
|
|
2771
|
+
family: fontFamily,
|
|
2772
|
+
size: Math.round(fontSize)
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
if (node.children && node.children.length > 0) {
|
|
2778
|
+
renderNode.children = node.children.map(nodeToRenderNode);
|
|
2779
|
+
}
|
|
2780
|
+
return renderNode;
|
|
2781
|
+
}
|
|
2782
|
+
var CompactRenderer = class {
|
|
2783
|
+
options;
|
|
2784
|
+
treeChars = {
|
|
2785
|
+
branch: "\u251C\u2500 ",
|
|
2786
|
+
lastBranch: "\u2514\u2500 ",
|
|
2787
|
+
vertical: "\u2502 ",
|
|
2788
|
+
space: " "
|
|
2789
|
+
};
|
|
2790
|
+
gapChars = {
|
|
2791
|
+
vertical: "\u2195",
|
|
2792
|
+
horizontal: "\u2194"
|
|
2793
|
+
};
|
|
2794
|
+
constructor(options = {}) {
|
|
2795
|
+
this.options = { ...defaultRenderOptions, ...options, compact: true };
|
|
2796
|
+
}
|
|
2797
|
+
/**
|
|
2798
|
+
* 渲染节点为树形结构
|
|
2799
|
+
*/
|
|
2800
|
+
render(node) {
|
|
2801
|
+
const lines = [];
|
|
2802
|
+
lines.push(this.buildLine(node));
|
|
2803
|
+
if (node.children && node.children.length > 0) {
|
|
2804
|
+
this.renderChildren(node, "", lines);
|
|
2805
|
+
}
|
|
2806
|
+
return lines;
|
|
2807
|
+
}
|
|
2808
|
+
renderChildren(parent, prefix, lines) {
|
|
2809
|
+
if (!parent.children) return;
|
|
2810
|
+
const gapSymbol = parent.flexMode === "H" ? this.gapChars.horizontal : this.gapChars.vertical;
|
|
2811
|
+
parent.children.forEach((child, index) => {
|
|
2812
|
+
const isLastChild = index === parent.children.length - 1;
|
|
2813
|
+
const connector = isLastChild ? this.treeChars.lastBranch : this.treeChars.branch;
|
|
2814
|
+
lines.push(prefix + connector + this.buildLine(child));
|
|
2815
|
+
if (child.children && child.children.length > 0) {
|
|
2816
|
+
const childPrefix = prefix + (isLastChild ? this.treeChars.space : this.treeChars.vertical);
|
|
2817
|
+
this.renderChildren(child, childPrefix, lines);
|
|
2818
|
+
}
|
|
2819
|
+
if (this.options.showGap && parent.itemSpacing && parent.itemSpacing > 0 && index < parent.children.length - 1) {
|
|
2820
|
+
const gapLinePrefix = prefix + this.treeChars.vertical;
|
|
2821
|
+
lines.push(gapLinePrefix + ` ${gapSymbol} gap:${parent.itemSpacing}`);
|
|
2822
|
+
}
|
|
2823
|
+
});
|
|
2824
|
+
}
|
|
2825
|
+
buildLine(node) {
|
|
2826
|
+
const parts = [];
|
|
2827
|
+
let typeName = `${node.type} "${node.name}"`;
|
|
2828
|
+
if (this.options.showId) {
|
|
2829
|
+
typeName += ` [${node.id}]`;
|
|
2830
|
+
}
|
|
2831
|
+
parts.push(typeName);
|
|
2832
|
+
if (this.options.showSize) {
|
|
2833
|
+
parts.push(`${node.width}\xD7${node.height}`);
|
|
2834
|
+
}
|
|
2835
|
+
if (this.options.showRadius && node.cornerRadius) {
|
|
2836
|
+
parts.push(`r:${node.cornerRadius}`);
|
|
2837
|
+
}
|
|
2838
|
+
if (this.options.showPadding && node.padding) {
|
|
2839
|
+
const { top, right, bottom, left } = node.padding;
|
|
2840
|
+
if (top === right && right === bottom && bottom === left && top > 0) {
|
|
2841
|
+
parts.push(`p:${top}`);
|
|
2842
|
+
} else if (top > 0 || right > 0 || bottom > 0 || left > 0) {
|
|
2843
|
+
parts.push(`p:${top}/${right}/${bottom}/${left}`);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
if (this.options.showLayout && node.flexMode && node.flexMode !== "none") {
|
|
2847
|
+
parts.push(`flex:${node.flexMode}`);
|
|
2848
|
+
}
|
|
2849
|
+
if (this.options.showGap && node.itemSpacing && node.itemSpacing > 0) {
|
|
2850
|
+
parts.push(`gap:${node.itemSpacing}`);
|
|
2851
|
+
}
|
|
2852
|
+
if (node.font) {
|
|
2853
|
+
parts.push(`font:${node.font.family}/${node.font.size}px`);
|
|
2854
|
+
}
|
|
2855
|
+
parts.push(`@(${node.x},${node.y})`);
|
|
2856
|
+
return parts.join(" ");
|
|
2857
|
+
}
|
|
2858
|
+
};
|
|
2859
|
+
var BoxRenderer = class {
|
|
2860
|
+
options;
|
|
2861
|
+
boxChars = {
|
|
2862
|
+
topLeft: "\u250C",
|
|
2863
|
+
topRight: "\u2510",
|
|
2864
|
+
bottomLeft: "\u2514",
|
|
2865
|
+
bottomRight: "\u2518",
|
|
2866
|
+
horizontal: "\u2500",
|
|
2867
|
+
vertical: "\u2502",
|
|
2868
|
+
teeRight: "\u251C",
|
|
2869
|
+
teeLeft: "\u2524"
|
|
2870
|
+
};
|
|
2871
|
+
gapChars = {
|
|
2872
|
+
vertical: "\u2195",
|
|
2873
|
+
horizontal: "\u2194"
|
|
2874
|
+
};
|
|
2875
|
+
/** 固定总宽度,确保右边框对齐 */
|
|
2876
|
+
totalWidth = 80;
|
|
2877
|
+
constructor(options = {}) {
|
|
2878
|
+
this.options = { ...defaultRenderOptions, ...options, compact: false };
|
|
2879
|
+
}
|
|
2880
|
+
/**
|
|
2881
|
+
* 渲染节点为框图
|
|
2882
|
+
*/
|
|
2883
|
+
render(node) {
|
|
2884
|
+
this.totalWidth = Math.max(80, this.calculateMaxWidth(node, 0));
|
|
2885
|
+
return this.renderNode(node, 0);
|
|
2886
|
+
}
|
|
2887
|
+
/**
|
|
2888
|
+
* 计算整棵树需要的最大宽度
|
|
2889
|
+
*/
|
|
2890
|
+
calculateMaxWidth(node, indent) {
|
|
2891
|
+
const indentWidth = indent * 4;
|
|
2892
|
+
const title = this.buildTitle(node);
|
|
2893
|
+
const props = this.buildPropsLine(node);
|
|
2894
|
+
const nodeWidth = Math.max(title.length + 6, props.length + 6) + indentWidth;
|
|
2895
|
+
let maxWidth = nodeWidth;
|
|
2896
|
+
if (node.children) {
|
|
2897
|
+
for (const child of node.children) {
|
|
2898
|
+
const childWidth = this.calculateMaxWidth(child, indent + 1);
|
|
2899
|
+
maxWidth = Math.max(maxWidth, childWidth);
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
return maxWidth;
|
|
2903
|
+
}
|
|
2904
|
+
renderNode(node, indent) {
|
|
2905
|
+
const lines = [];
|
|
2906
|
+
const indentWidth = indent * 4;
|
|
2907
|
+
const contentWidth = this.totalWidth - indentWidth - 2;
|
|
2908
|
+
const indentStr = " ".repeat(indent);
|
|
2909
|
+
const title = this.buildTitle(node);
|
|
2910
|
+
const props = this.buildPropsLine(node);
|
|
2911
|
+
const titlePadding = contentWidth - title.length - 4;
|
|
2912
|
+
lines.push(
|
|
2913
|
+
indentStr + this.boxChars.topLeft + this.boxChars.horizontal + " " + title + " " + this.boxChars.horizontal.repeat(Math.max(0, titlePadding)) + this.boxChars.topRight
|
|
2914
|
+
);
|
|
2915
|
+
lines.push(
|
|
2916
|
+
indentStr + this.boxChars.vertical + " " + props.padEnd(contentWidth - 2) + this.boxChars.vertical
|
|
2917
|
+
);
|
|
2918
|
+
lines.push(
|
|
2919
|
+
indentStr + this.boxChars.teeRight + this.boxChars.horizontal.repeat(contentWidth) + this.boxChars.teeLeft
|
|
2920
|
+
);
|
|
2921
|
+
if (node.children && node.children.length > 0) {
|
|
2922
|
+
lines.push(
|
|
2923
|
+
indentStr + this.boxChars.vertical + " ".repeat(contentWidth) + this.boxChars.vertical
|
|
2924
|
+
);
|
|
2925
|
+
const gapSymbol = node.flexMode === "H" ? this.gapChars.horizontal : this.gapChars.vertical;
|
|
2926
|
+
node.children.forEach((child, index) => {
|
|
2927
|
+
const childLines = this.renderNode(child, indent + 1);
|
|
2928
|
+
for (const childLine of childLines) {
|
|
2929
|
+
const paddedLine = " " + childLine.padEnd(contentWidth - 2);
|
|
2930
|
+
lines.push(indentStr + this.boxChars.vertical + paddedLine + this.boxChars.vertical);
|
|
2931
|
+
}
|
|
2932
|
+
if (this.options.showGap && node.itemSpacing && node.itemSpacing > 0 && index < node.children.length - 1) {
|
|
2933
|
+
const gapText = `${gapSymbol} gap:${node.itemSpacing}`;
|
|
2934
|
+
const gapPadding = Math.floor((contentWidth - gapText.length) / 2);
|
|
2935
|
+
const gapLine = " ".repeat(gapPadding) + gapText;
|
|
2936
|
+
lines.push(
|
|
2937
|
+
indentStr + this.boxChars.vertical + gapLine.padEnd(contentWidth) + this.boxChars.vertical
|
|
2938
|
+
);
|
|
2939
|
+
} else {
|
|
2940
|
+
lines.push(
|
|
2941
|
+
indentStr + this.boxChars.vertical + " ".repeat(contentWidth) + this.boxChars.vertical
|
|
2942
|
+
);
|
|
2943
|
+
}
|
|
2944
|
+
});
|
|
2945
|
+
}
|
|
2946
|
+
lines.push(
|
|
2947
|
+
indentStr + this.boxChars.bottomLeft + this.boxChars.horizontal.repeat(contentWidth) + this.boxChars.bottomRight
|
|
2948
|
+
);
|
|
2949
|
+
return lines;
|
|
2950
|
+
}
|
|
2951
|
+
buildTitle(node) {
|
|
2952
|
+
let title = `${node.type} "${node.name}"`;
|
|
2953
|
+
if (this.options.showId) {
|
|
2954
|
+
title += ` [${node.id}]`;
|
|
2955
|
+
}
|
|
2956
|
+
return title;
|
|
2957
|
+
}
|
|
2958
|
+
buildPropsLine(node) {
|
|
2959
|
+
const parts = [];
|
|
2960
|
+
if (this.options.showSize) {
|
|
2961
|
+
parts.push(`${node.width}\xD7${node.height}`);
|
|
2962
|
+
}
|
|
2963
|
+
if (this.options.showRadius && node.cornerRadius) {
|
|
2964
|
+
parts.push(`r:${node.cornerRadius}`);
|
|
2965
|
+
}
|
|
2966
|
+
if (this.options.showPadding && node.padding) {
|
|
2967
|
+
const { top, right, bottom, left } = node.padding;
|
|
2968
|
+
if (top === right && right === bottom && bottom === left && top > 0) {
|
|
2969
|
+
parts.push(`p:${top}`);
|
|
2970
|
+
} else if (top > 0 || right > 0 || bottom > 0 || left > 0) {
|
|
2971
|
+
parts.push(`p:${top}/${right}/${bottom}/${left}`);
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
if (this.options.showLayout && node.flexMode && node.flexMode !== "none") {
|
|
2975
|
+
parts.push(`flex:${node.flexMode}`);
|
|
2976
|
+
}
|
|
2977
|
+
if (this.options.showGap && node.itemSpacing && node.itemSpacing > 0) {
|
|
2978
|
+
parts.push(`gap:${node.itemSpacing}`);
|
|
2979
|
+
}
|
|
2980
|
+
if (node.font) {
|
|
2981
|
+
parts.push(`font:${node.font.family}/${node.font.size}px`);
|
|
2982
|
+
}
|
|
2983
|
+
parts.push(`pos:(${node.x},${node.y})`);
|
|
2984
|
+
return parts.join(" ");
|
|
2985
|
+
}
|
|
2986
|
+
};
|
|
2987
|
+
function renderAscii(node, options = {}) {
|
|
2988
|
+
const renderNode = nodeToRenderNode(node);
|
|
2989
|
+
const mergedOptions = { ...defaultRenderOptions, ...options };
|
|
2990
|
+
let lines;
|
|
2991
|
+
if (mergedOptions.compact) {
|
|
2992
|
+
const renderer = new CompactRenderer(mergedOptions);
|
|
2993
|
+
lines = renderer.render(renderNode);
|
|
2994
|
+
} else {
|
|
2995
|
+
const renderer = new BoxRenderer(mergedOptions);
|
|
2996
|
+
lines = renderer.render(renderNode);
|
|
2997
|
+
}
|
|
2998
|
+
return lines.join("\n");
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
// src/cli/commands/visualize.ts
|
|
3002
|
+
function createVisualizeCommand() {
|
|
3003
|
+
return new Command12("visualize").description("\u5C06 MasterGo \u8BBE\u8BA1\u7A3F\u8282\u70B9\u6E32\u67D3\u4E3A ASCII \u793A\u610F\u56FE").requiredOption("--link <url>", "mgp:// \u534F\u8BAE\u94FE\u63A5").option("--output <path>", "\u8F93\u51FA\u6587\u4EF6\u8DEF\u5F84\uFF08\u4E0D\u6307\u5B9A\u5219\u8F93\u51FA\u5230\u7EC8\u7AEF\uFF09").option("--maxDepth <number>", "\u904D\u5386\u6DF1\u5EA6", "3").option("--no-show-id", "\u9690\u85CF\u8282\u70B9 ID").option("--no-show-size", "\u9690\u85CF\u5C3A\u5BF8").option("--no-show-padding", "\u9690\u85CF padding").option("--no-show-radius", "\u9690\u85CF\u5706\u89D2").option("--no-show-layout", "\u9690\u85CF\u5E03\u5C40\u65B9\u5411").option("--no-show-gap", "\u9690\u85CF gap \u53EF\u89C6\u5316").option("--no-compact", "\u4F7F\u7528\u6846\u56FE\u6A21\u5F0F\uFF08\u4EBA\u7C7B\u9605\u8BFB\u4F18\u5316\uFF09").option("--no-auto-start", "\u7981\u7528\u81EA\u52A8\u542F\u52A8 Server").option("--no-retry", "\u7981\u7528\u81EA\u52A8\u91CD\u8BD5").action(async (options) => {
|
|
3004
|
+
await handleVisualize(options);
|
|
3005
|
+
});
|
|
3006
|
+
}
|
|
3007
|
+
async function handleVisualize(options) {
|
|
3008
|
+
const parsed = parseMgpLink(options.link);
|
|
3009
|
+
if (!parsed) {
|
|
3010
|
+
console.error(`\u9519\u8BEF [${"E010" /* INVALID_LINK */}]: \u65E0\u6548\u7684 mgp:// \u94FE\u63A5\u683C\u5F0F`);
|
|
3011
|
+
console.error(`\u63D0\u4F9B\u7684\u94FE\u63A5: ${options.link}`);
|
|
3012
|
+
console.error(`\u671F\u671B\u683C\u5F0F:`);
|
|
3013
|
+
console.error(` \u8282\u70B9\u94FE\u63A5: mgp://[mastergo_page_url]?nodeId=[\u8282\u70B9ID]`);
|
|
3014
|
+
console.error(` \u9875\u9762\u94FE\u63A5: mgp://[mastergo_page_url]?pageId=[\u9875\u9762ID]`);
|
|
3015
|
+
process.exit(1);
|
|
3016
|
+
}
|
|
3017
|
+
const { pageUrl, nodeId, pageId } = parsed;
|
|
3018
|
+
const isPageLink = !!pageId;
|
|
3019
|
+
const client = new MGClient({
|
|
3020
|
+
noAutoStart: options.noAutoStart,
|
|
3021
|
+
noRetry: options.noRetry
|
|
3022
|
+
});
|
|
3023
|
+
try {
|
|
3024
|
+
await client.connect();
|
|
3025
|
+
let data;
|
|
3026
|
+
if (isPageLink) {
|
|
3027
|
+
const params = {
|
|
3028
|
+
pageId,
|
|
3029
|
+
maxDepth: parseInt(options.maxDepth || "3", 10),
|
|
3030
|
+
includeInvisible: false
|
|
3031
|
+
};
|
|
3032
|
+
data = await client.requestWithRetry("get_page_by_id" /* GET_PAGE_BY_ID */, params, pageUrl);
|
|
3033
|
+
} else {
|
|
3034
|
+
const params = {
|
|
3035
|
+
nodeId,
|
|
3036
|
+
maxDepth: parseInt(options.maxDepth || "3", 10),
|
|
3037
|
+
includeInvisible: false
|
|
3038
|
+
};
|
|
3039
|
+
data = await client.requestWithRetry("get_node_by_id" /* GET_NODE_BY_ID */, params, pageUrl);
|
|
3040
|
+
}
|
|
3041
|
+
const renderOptions = {
|
|
3042
|
+
showId: options.showId !== false,
|
|
3043
|
+
showSize: options.showSize !== false,
|
|
3044
|
+
showPadding: options.showPadding !== false,
|
|
3045
|
+
showRadius: options.showRadius !== false,
|
|
3046
|
+
showLayout: options.showLayout !== false,
|
|
3047
|
+
showGap: options.showGap !== false,
|
|
3048
|
+
compact: options.compact !== false
|
|
3049
|
+
};
|
|
3050
|
+
const asciiOutput = renderAscii(data, renderOptions);
|
|
3051
|
+
if (options.output) {
|
|
3052
|
+
const outputPath = resolve8(options.output);
|
|
3053
|
+
const outputDir = dirname11(outputPath);
|
|
3054
|
+
mkdirSync10(outputDir, { recursive: true });
|
|
3055
|
+
writeFileSync9(outputPath, asciiOutput, "utf-8");
|
|
3056
|
+
console.log(`ASCII \u793A\u610F\u56FE\u5DF2\u4FDD\u5B58\u5230: ${outputPath}`);
|
|
3057
|
+
console.log(`Link: ${options.link}`);
|
|
3058
|
+
console.log(`\u6A21\u5F0F: ${options.compact ? "\u7D27\u51D1" : "\u6807\u51C6"}`);
|
|
3059
|
+
console.log(`\u904D\u5386\u6DF1\u5EA6: ${options.maxDepth || "3"}`);
|
|
3060
|
+
} else {
|
|
3061
|
+
console.log(asciiOutput);
|
|
3062
|
+
}
|
|
3063
|
+
} catch (error) {
|
|
3064
|
+
if (error instanceof MGError) {
|
|
3065
|
+
console.error(`\u9519\u8BEF [${error.code}]: ${error.message}`);
|
|
3066
|
+
} else {
|
|
3067
|
+
console.error(`\u9519\u8BEF: ${error instanceof Error ? error.message : error}`);
|
|
3068
|
+
}
|
|
3069
|
+
process.exit(1);
|
|
3070
|
+
} finally {
|
|
3071
|
+
client.close();
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
|
|
2619
3075
|
// src/cli/index.ts
|
|
2620
|
-
var program = new
|
|
3076
|
+
var program = new Command13();
|
|
2621
3077
|
program.name("mg-cli").description("MasterGo CLI \u5DE5\u5177 - \u7528\u4E8E Claude Code \u4E0E MasterGo \u901A\u4FE1").version("1.0.0");
|
|
2622
3078
|
program.addCommand(createServerCommand());
|
|
2623
3079
|
program.addCommand(createGetNodeByIdCommand());
|
|
@@ -2630,5 +3086,7 @@ program.addCommand(createGetNodeForSpaceCommand());
|
|
|
2630
3086
|
program.addCommand(createListExtensionsCommand());
|
|
2631
3087
|
program.addCommand(createOpenPageCommand());
|
|
2632
3088
|
program.addCommand(createNavigateToNodeCommand());
|
|
3089
|
+
program.addCommand(createVisualizeCommand());
|
|
3090
|
+
checkForUpdates();
|
|
2633
3091
|
program.parse();
|
|
2634
3092
|
//# sourceMappingURL=cli.js.map
|