@hangox/mg-cli 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/cli.js +1574 -0
  2. package/dist/cli.js.map +1 -0
  3. package/dist/daemon-runner.js +794 -0
  4. package/dist/daemon-runner.js.map +1 -0
  5. package/dist/index-DNrszrq9.d.ts +568 -0
  6. package/dist/index.d.ts +129 -0
  7. package/dist/index.js +950 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/server.d.ts +2 -0
  10. package/dist/server.js +689 -0
  11. package/dist/server.js.map +1 -0
  12. package/package.json +5 -1
  13. package/.eslintrc.cjs +0 -26
  14. package/CLAUDE.md +0 -43
  15. package/src/cli/client.ts +0 -266
  16. package/src/cli/commands/execute-code.ts +0 -59
  17. package/src/cli/commands/export-image.ts +0 -193
  18. package/src/cli/commands/get-all-nodes.ts +0 -81
  19. package/src/cli/commands/get-all-pages.ts +0 -118
  20. package/src/cli/commands/get-node-by-id.ts +0 -83
  21. package/src/cli/commands/get-node-by-link.ts +0 -105
  22. package/src/cli/commands/server.ts +0 -130
  23. package/src/cli/index.ts +0 -33
  24. package/src/index.ts +0 -9
  25. package/src/server/connection-manager.ts +0 -211
  26. package/src/server/daemon-runner.ts +0 -22
  27. package/src/server/daemon.ts +0 -211
  28. package/src/server/index.ts +0 -8
  29. package/src/server/logger.ts +0 -117
  30. package/src/server/request-handler.ts +0 -192
  31. package/src/server/websocket-server.ts +0 -297
  32. package/src/shared/constants.ts +0 -90
  33. package/src/shared/errors.ts +0 -131
  34. package/src/shared/index.ts +0 -8
  35. package/src/shared/types.ts +0 -227
  36. package/src/shared/utils.ts +0 -352
  37. package/tests/unit/shared/constants.test.ts +0 -66
  38. package/tests/unit/shared/errors.test.ts +0 -82
  39. package/tests/unit/shared/utils.test.ts +0 -208
  40. package/tsconfig.json +0 -22
  41. package/tsup.config.ts +0 -33
  42. package/vitest.config.ts +0 -22
@@ -1,193 +0,0 @@
1
- /**
2
- * export_image 命令
3
- * 导出 MasterGo 节点为图片文件
4
- */
5
-
6
- import { Command } from 'commander'
7
- import { writeFileSync } from 'node:fs'
8
- import { resolve, dirname, extname } from 'node:path'
9
- import { mkdirSync } from 'node:fs'
10
- import { tmpdir } from 'node:os'
11
- import { MessageType } from '../../shared/constants.js'
12
- import { MGClient, parseMgpLink } from '../client.js'
13
- import { MGError } from '../../shared/errors.js'
14
- import type { ExportImageParams } from '../../shared/types.js'
15
-
16
- type ImageFormat = 'PNG' | 'JPG' | 'SVG' | 'PDF' | 'WEBP'
17
-
18
- interface ExportImageOptions {
19
- output?: string
20
- link?: string
21
- format?: string
22
- scale?: string
23
- width?: string
24
- height?: string
25
- useAbsoluteBounds?: boolean
26
- useRenderBounds?: boolean
27
- noAutoStart?: boolean
28
- noRetry?: boolean
29
- }
30
-
31
- /** 导出响应 */
32
- interface ExportResponse {
33
- /** Base64 编码的图片数据 */
34
- data: string
35
- /** MIME 类型 */
36
- mimeType: string
37
- /** 文件名建议 */
38
- filename?: string
39
- }
40
-
41
- /**
42
- * 创建 export_image 命令
43
- */
44
- export function createExportImageCommand(): Command {
45
- return new Command('export_image')
46
- .description('导出 MasterGo 节点为图片文件。强烈建议指定 --output,否则保存到临时目录可能被系统清理')
47
- .option('--output <path>', '输出文件路径。强烈建议指定,否则保存到系统临时目录可能被清理')
48
- .option('--link <mgp-link>', 'mgp:// 协议链接。不指定则导出当前选中节点')
49
- .option('--format <type>', '导出格式:PNG(无损透明)、JPG(有损)、SVG(矢量)、PDF、WEBP', 'PNG')
50
- .option('--scale <number>', '缩放倍率(如 1、2、3)。与 width/height 互斥')
51
- .option('--width <number>', '固定宽度(像素)。与 scale/height 互斥')
52
- .option('--height <number>', '固定高度(像素)。与 scale/width 互斥')
53
- .option('--useAbsoluteBounds', '使用完整尺寸。true: 包含被裁剪部分,false: 只导出可见区域', false)
54
- .option('--no-use-render-bounds', '不包含特效和外描边。默认包含阴影、外描边等')
55
- .option('--no-auto-start', '禁用自动启动 Server')
56
- .option('--no-retry', '禁用自动重试')
57
- .action(async (options: ExportImageOptions) => {
58
- await handleExportImage(options)
59
- })
60
- }
61
-
62
- /**
63
- * 处理 export_image 命令
64
- */
65
- async function handleExportImage(options: ExportImageOptions): Promise<void> {
66
- // 验证格式
67
- const format = (options.format?.toUpperCase() || 'PNG') as ImageFormat
68
- const validFormats: ImageFormat[] = ['PNG', 'JPG', 'SVG', 'PDF', 'WEBP']
69
- if (!validFormats.includes(format)) {
70
- console.error(`错误: 不支持的格式 "${options.format}"`)
71
- console.error(`支持的格式: ${validFormats.join(', ')}`)
72
- process.exit(1)
73
- }
74
-
75
- // 验证参数互斥
76
- const sizeParams = [options.scale, options.width, options.height].filter(Boolean)
77
- if (sizeParams.length > 1) {
78
- console.error('错误: scale、width、height 三者互斥,只能指定其中一个')
79
- process.exit(1)
80
- }
81
-
82
- // 解析 link 参数
83
- let pageUrl: string | undefined
84
- let nodeId: string | undefined
85
-
86
- if (options.link) {
87
- const linkInfo = parseMgpLink(options.link)
88
- if (!linkInfo) {
89
- console.error(`错误: 无效的 mgp:// 链接格式: ${options.link}`)
90
- process.exit(1)
91
- }
92
- pageUrl = linkInfo.pageUrl
93
- nodeId = linkInfo.nodeId
94
- }
95
-
96
- const client = new MGClient({
97
- noAutoStart: options.noAutoStart,
98
- noRetry: options.noRetry,
99
- })
100
-
101
- try {
102
- // 连接 Server
103
- await client.connect()
104
-
105
- // 构建请求参数
106
- const params: ExportImageParams = {
107
- format,
108
- useAbsoluteBounds: options.useAbsoluteBounds || false,
109
- useRenderBounds: options.useRenderBounds !== false,
110
- }
111
-
112
- if (nodeId) {
113
- params.nodeId = nodeId
114
- }
115
- if (options.scale) {
116
- params.scale = parseFloat(options.scale)
117
- }
118
- if (options.width) {
119
- params.width = parseInt(options.width, 10)
120
- }
121
- if (options.height) {
122
- params.height = parseInt(options.height, 10)
123
- }
124
-
125
- // 发送请求(传入 pageUrl 以指定目标页面)
126
- const response = await client.requestWithRetry<ExportResponse>(
127
- MessageType.EXPORT_IMAGE,
128
- params as Record<string, unknown>,
129
- pageUrl
130
- )
131
-
132
- // 确定输出路径
133
- const ext = getExtension(format)
134
- let outputPath: string
135
- if (options.output) {
136
- outputPath = resolve(options.output)
137
- // 如果没有扩展名,添加扩展名
138
- if (!extname(outputPath)) {
139
- outputPath = `${outputPath}${ext}`
140
- }
141
- } else {
142
- // 使用临时目录
143
- const filename = response.filename || `export_${Date.now()}${ext}`
144
- outputPath = resolve(tmpdir(), filename)
145
- console.log('警告: 未指定 --output,文件将保存到临时目录,可能会被系统清理')
146
- }
147
-
148
- // 确保目录存在
149
- const outputDir = dirname(outputPath)
150
- mkdirSync(outputDir, { recursive: true })
151
-
152
- // 解码 Base64 并保存
153
- const buffer = Buffer.from(response.data, 'base64')
154
- writeFileSync(outputPath, buffer)
155
-
156
- // 输出结果
157
- const sizeKB = (buffer.length / 1024).toFixed(2)
158
- console.log(`文件路径: ${outputPath}`)
159
- if (options.link) {
160
- console.log(`Link: ${options.link}`)
161
- }
162
- if (nodeId) {
163
- console.log(`节点 ID: ${nodeId}`)
164
- } else {
165
- console.log('节点 ID: (选中的节点)')
166
- }
167
- console.log(`导出格式: ${format}`)
168
- console.log(`文件大小: ${buffer.length.toLocaleString()} 字节 (约 ${sizeKB} KB)`)
169
- } catch (error) {
170
- if (error instanceof MGError) {
171
- console.error(`错误 [${error.code}]: ${error.message}`)
172
- } else {
173
- console.error(`错误: ${error instanceof Error ? error.message : error}`)
174
- }
175
- process.exit(1)
176
- } finally {
177
- client.close()
178
- }
179
- }
180
-
181
- /**
182
- * 获取格式对应的文件扩展名
183
- */
184
- function getExtension(format: ImageFormat): string {
185
- const extensions: Record<ImageFormat, string> = {
186
- PNG: '.png',
187
- JPG: '.jpg',
188
- SVG: '.svg',
189
- PDF: '.pdf',
190
- WEBP: '.webp',
191
- }
192
- return extensions[format]
193
- }
@@ -1,81 +0,0 @@
1
- /**
2
- * get_all_nodes 命令
3
- * 获取当前页面的所有节点树
4
- */
5
-
6
- import { Command } from 'commander'
7
- import { writeFileSync } from 'node:fs'
8
- import { resolve, dirname } from 'node:path'
9
- import { mkdirSync } from 'node:fs'
10
- import { MessageType } from '../../shared/constants.js'
11
- import { MGClient } from '../client.js'
12
- import type { GetAllNodesParams, NodeInfo } from '../../shared/types.js'
13
-
14
- interface GetAllNodesOptions {
15
- output: string
16
- maxDepth?: string
17
- includeInvisible?: boolean
18
- noAutoStart?: boolean
19
- noRetry?: boolean
20
- }
21
-
22
- /**
23
- * 创建 get_all_nodes 命令
24
- */
25
- export function createGetAllNodesCommand(): Command {
26
- return new Command('get_all_nodes')
27
- .description('获取当前页面的所有节点树。警告:深度每增加 1,数据量可能呈指数级增长。建议从 maxDepth=1 开始')
28
- .requiredOption('--output <path>', '输出 JSON 文件路径。支持绝对路径或相对路径')
29
- .option('--maxDepth <number>', '最大深度,默认 1。深度 2 可能产生 100KB-500KB,深度 3 可能超过 1MB', '1')
30
- .option('--includeInvisible', '包含不可见节点(visible: false),默认不包含', false)
31
- .option('--no-auto-start', '禁用自动启动 Server')
32
- .option('--no-retry', '禁用自动重试')
33
- .action(async (options: GetAllNodesOptions) => {
34
- await handleGetAllNodes(options)
35
- })
36
- }
37
-
38
- /**
39
- * 处理 get_all_nodes 命令
40
- */
41
- async function handleGetAllNodes(options: GetAllNodesOptions): Promise<void> {
42
- const client = new MGClient({
43
- noAutoStart: options.noAutoStart,
44
- noRetry: options.noRetry,
45
- })
46
-
47
- try {
48
- // 连接 Server
49
- await client.connect()
50
-
51
- // 发送请求
52
- const params: GetAllNodesParams = {
53
- maxDepth: parseInt(options.maxDepth || '1', 10),
54
- includeInvisible: options.includeInvisible || false,
55
- }
56
-
57
- const data = await client.requestWithRetry<NodeInfo[]>(MessageType.GET_ALL_NODES, params)
58
-
59
- // 保存到文件
60
- const outputPath = resolve(options.output)
61
- const outputDir = dirname(outputPath)
62
- mkdirSync(outputDir, { recursive: true })
63
-
64
- const jsonContent = JSON.stringify(data, null, 2)
65
- writeFileSync(outputPath, jsonContent, 'utf-8')
66
-
67
- // 输出结果
68
- const size = jsonContent.length
69
- const sizeKB = (size / 1024).toFixed(2)
70
- const nodeCount = Array.isArray(data) ? data.length : 1
71
- console.log(`文件路径: ${outputPath}`)
72
- console.log(`节点数量: ${nodeCount}`)
73
- console.log(`数据大小: ${size.toLocaleString()} 字符 (约 ${sizeKB} KB)`)
74
- console.log(`节点深度: ${params.maxDepth}`)
75
- } catch (error) {
76
- console.error(`错误: ${error instanceof Error ? error.message : error}`)
77
- process.exit(1)
78
- } finally {
79
- client.close()
80
- }
81
- }
@@ -1,118 +0,0 @@
1
- /**
2
- * get_all_pages 命令
3
- * 获取 MasterGo 文档的所有页面信息
4
- */
5
-
6
- import { Command } from 'commander'
7
- import { writeFileSync } from 'node:fs'
8
- import { resolve, dirname } from 'node:path'
9
- import { mkdirSync } from 'node:fs'
10
- import { tmpdir } from 'node:os'
11
- import { MessageType } from '../../shared/constants.js'
12
- import { MGClient } from '../client.js'
13
- import { extractFileId } from '../../shared/utils.js'
14
- import type { AllPagesInfo } from '../../shared/types.js'
15
-
16
- interface GetAllPagesOptions {
17
- link?: string
18
- fileId?: string
19
- output?: string
20
- noAutoStart?: boolean
21
- noRetry?: boolean
22
- }
23
-
24
- /**
25
- * 创建 get_all_pages 命令
26
- */
27
- export function createGetAllPagesCommand(): Command {
28
- return new Command('get_all_pages')
29
- .description('获取 MasterGo 文档的所有页面信息。不指定 --output 时保存到系统临时目录')
30
- .option('--link <url>', '页面链接。支持完整 URL 或 mgp:// 协议')
31
- .option('--fileId <id>', '文件 ID(纯数字)。从 URL 中 /file/ 后面的数字')
32
- .option('--output <path>', '输出 JSON 文件路径。不指定则保存到系统临时目录')
33
- .option('--no-auto-start', '禁用自动启动 Server')
34
- .option('--no-retry', '禁用自动重试')
35
- .action(async (options: GetAllPagesOptions) => {
36
- await handleGetAllPages(options)
37
- })
38
- }
39
-
40
- /**
41
- * 处理 get_all_pages 命令
42
- */
43
- async function handleGetAllPages(options: GetAllPagesOptions): Promise<void> {
44
- // 提取 fileId
45
- let fileId: string | null = null
46
-
47
- if (options.fileId) {
48
- fileId = options.fileId
49
- } else if (options.link) {
50
- fileId = extractFileId(options.link)
51
- if (!fileId) {
52
- console.error('错误: 无法从链接中提取 fileId')
53
- console.error('支持的格式:')
54
- console.error(' - 完整 URL: https://mastergo.netease.com/file/174875497054651')
55
- console.error(' - mgp 协议: mgp://mastergo.netease.com/file/174875497054651')
56
- console.error(' - 纯 fileId: 174875497054651')
57
- process.exit(1)
58
- }
59
- } else {
60
- // 没有提供参数,获取当前连接页面的所有页面
61
- console.log('未提供 --link 或 --fileId,将获取当前连接页面的所有页面信息')
62
- }
63
-
64
- const client = new MGClient({
65
- noAutoStart: options.noAutoStart,
66
- noRetry: options.noRetry,
67
- })
68
-
69
- try {
70
- // 连接 Server
71
- await client.connect()
72
-
73
- // 构建 pageUrl(如果有 fileId)
74
- let pageUrl: string | undefined
75
- if (fileId) {
76
- // 构建标准化的 pageUrl
77
- pageUrl = `mastergo.netease.com/file/${fileId}`
78
- }
79
-
80
- // 发送请求
81
- const data = await client.requestWithRetry<AllPagesInfo>(
82
- MessageType.GET_ALL_PAGES,
83
- {},
84
- pageUrl
85
- )
86
-
87
- // 确定输出路径
88
- let outputPath: string
89
- if (options.output) {
90
- outputPath = resolve(options.output)
91
- } else {
92
- // 使用系统临时目录
93
- const filename = `pages_${fileId || 'current'}_${Date.now()}.json`
94
- outputPath = resolve(tmpdir(), filename)
95
- }
96
-
97
- // 确保目录存在
98
- const outputDir = dirname(outputPath)
99
- mkdirSync(outputDir, { recursive: true })
100
-
101
- // 保存到文件
102
- const jsonContent = JSON.stringify(data, null, 2)
103
- writeFileSync(outputPath, jsonContent, 'utf-8')
104
-
105
- // 输出结果
106
- const size = jsonContent.length
107
- const sizeKB = (size / 1024).toFixed(2)
108
- console.log(`文件路径: ${outputPath}`)
109
- console.log(`文档名称: ${data.documentName}`)
110
- console.log(`页面数量: ${data.totalCount}`)
111
- console.log(`数据大小: ${size.toLocaleString()} 字符 (约 ${sizeKB} KB)`)
112
- } catch (error) {
113
- console.error(`错误: ${error instanceof Error ? error.message : error}`)
114
- process.exit(1)
115
- } finally {
116
- client.close()
117
- }
118
- }
@@ -1,83 +0,0 @@
1
- /**
2
- * get_node_by_id 命令
3
- * 根据节点 ID 获取节点详细信息
4
- */
5
-
6
- import { Command } from 'commander'
7
- import { writeFileSync } from 'node:fs'
8
- import { resolve, dirname } from 'node:path'
9
- import { mkdirSync } from 'node:fs'
10
- import { MessageType } from '../../shared/constants.js'
11
- import { MGClient } from '../client.js'
12
- import type { GetNodeParams, NodeInfo } from '../../shared/types.js'
13
-
14
- interface GetNodeByIdOptions {
15
- nodeId: string
16
- output: string
17
- maxDepth?: string
18
- includeInvisible?: boolean
19
- noAutoStart?: boolean
20
- noRetry?: boolean
21
- }
22
-
23
- /**
24
- * 创建 get_node_by_id 命令
25
- */
26
- export function createGetNodeByIdCommand(): Command {
27
- return new Command('get_node_by_id')
28
- .description('根据节点 ID 获取节点详细信息。数据保存到指定 JSON 文件,返回文件路径和大小信息')
29
- .requiredOption('--nodeId <id>', '节点 ID,格式如 123:456。可从 MasterGo 浮窗链接中获取')
30
- .requiredOption('--output <path>', '输出 JSON 文件路径。支持绝对路径或相对路径')
31
- .option('--maxDepth <number>', '遍历深度,默认 1。增加深度会显著增加数据量', '1')
32
- .option('--includeInvisible', '包含不可见节点(visible: false),默认不包含', false)
33
- .option('--no-auto-start', '禁用自动启动 Server')
34
- .option('--no-retry', '禁用自动重试')
35
- .action(async (options: GetNodeByIdOptions) => {
36
- await handleGetNodeById(options)
37
- })
38
- }
39
-
40
- /**
41
- * 处理 get_node_by_id 命令
42
- */
43
- async function handleGetNodeById(options: GetNodeByIdOptions): Promise<void> {
44
- const client = new MGClient({
45
- noAutoStart: options.noAutoStart,
46
- noRetry: options.noRetry,
47
- })
48
-
49
- try {
50
- // 连接 Server
51
- await client.connect()
52
-
53
- // 发送请求
54
- const params: GetNodeParams = {
55
- nodeId: options.nodeId,
56
- maxDepth: parseInt(options.maxDepth || '1', 10),
57
- includeInvisible: options.includeInvisible || false,
58
- }
59
-
60
- const data = await client.requestWithRetry<NodeInfo>(MessageType.GET_NODE_BY_ID, params)
61
-
62
- // 保存到文件
63
- const outputPath = resolve(options.output)
64
- const outputDir = dirname(outputPath)
65
- mkdirSync(outputDir, { recursive: true })
66
-
67
- const jsonContent = JSON.stringify(data, null, 2)
68
- writeFileSync(outputPath, jsonContent, 'utf-8')
69
-
70
- // 输出结果
71
- const size = jsonContent.length
72
- const sizeKB = (size / 1024).toFixed(2)
73
- console.log(`文件路径: ${outputPath}`)
74
- console.log(`节点 ID: ${options.nodeId}`)
75
- console.log(`数据大小: ${size.toLocaleString()} 字符 (约 ${sizeKB} KB)`)
76
- console.log(`节点深度: ${params.maxDepth}`)
77
- } catch (error) {
78
- console.error(`错误: ${error instanceof Error ? error.message : error}`)
79
- process.exit(1)
80
- } finally {
81
- client.close()
82
- }
83
- }
@@ -1,105 +0,0 @@
1
- /**
2
- * get_node_by_link 命令
3
- * 解析 mgp:// 协议链接并获取节点信息
4
- */
5
-
6
- import { Command } from 'commander'
7
- import { writeFileSync } from 'node:fs'
8
- import { resolve, dirname } from 'node:path'
9
- import { mkdirSync } from 'node:fs'
10
- import { MessageType } from '../../shared/constants.js'
11
- import { MGClient, parseMgpLink } from '../client.js'
12
- import { ErrorCode, MGError } from '../../shared/errors.js'
13
- import type { GetNodeParams, NodeInfo } from '../../shared/types.js'
14
-
15
- interface GetNodeByLinkOptions {
16
- link: string
17
- output: string
18
- maxDepth?: string
19
- includeInvisible?: boolean
20
- noAutoStart?: boolean
21
- noRetry?: boolean
22
- }
23
-
24
- /**
25
- * 创建 get_node_by_link 命令
26
- */
27
- export function createGetNodeByLinkCommand(): Command {
28
- return new Command('get_node_by_link')
29
- .description('解析 mgp:// 协议链接并获取节点信息')
30
- .requiredOption('--link <url>', 'mgp:// 协议链接')
31
- .requiredOption('--output <path>', '输出 JSON 文件路径')
32
- .option('--maxDepth <number>', '遍历深度', '1')
33
- .option('--includeInvisible', '包含不可见节点', false)
34
- .option('--no-auto-start', '禁用自动启动 Server')
35
- .option('--no-retry', '禁用自动重试')
36
- .action(async (options: GetNodeByLinkOptions) => {
37
- await handleGetNodeByLink(options)
38
- })
39
- }
40
-
41
- /**
42
- * 处理 get_node_by_link 命令
43
- */
44
- async function handleGetNodeByLink(options: GetNodeByLinkOptions): Promise<void> {
45
- // 解析 mgp:// 链接
46
- const parsed = parseMgpLink(options.link)
47
- if (!parsed) {
48
- console.error(`错误 [${ErrorCode.INVALID_LINK}]: 无效的 mgp:// 链接格式`)
49
- console.error(`提供的链接: ${options.link}`)
50
- console.error(`期望格式: mgp://[mastergo_page_url]/nodeId`)
51
- process.exit(1)
52
- }
53
-
54
- const { pageUrl, nodeId } = parsed
55
-
56
- const client = new MGClient({
57
- noAutoStart: options.noAutoStart,
58
- noRetry: options.noRetry,
59
- })
60
-
61
- try {
62
- // 连接 Server
63
- await client.connect()
64
-
65
- // 发送请求
66
- const params: GetNodeParams = {
67
- nodeId,
68
- maxDepth: parseInt(options.maxDepth || '1', 10),
69
- includeInvisible: options.includeInvisible || false,
70
- }
71
-
72
- const data = await client.requestWithRetry<NodeInfo>(
73
- MessageType.GET_NODE_BY_ID,
74
- params,
75
- pageUrl
76
- )
77
-
78
- // 保存到文件
79
- const outputPath = resolve(options.output)
80
- const outputDir = dirname(outputPath)
81
- mkdirSync(outputDir, { recursive: true })
82
-
83
- const jsonContent = JSON.stringify(data, null, 2)
84
- writeFileSync(outputPath, jsonContent, 'utf-8')
85
-
86
- // 输出结果
87
- const size = jsonContent.length
88
- const sizeKB = (size / 1024).toFixed(2)
89
- console.log(`文件路径: ${outputPath}`)
90
- console.log(`Link: ${options.link}`)
91
- console.log(`页面 URL: ${pageUrl}`)
92
- console.log(`节点 ID: ${nodeId}`)
93
- console.log(`数据大小: ${size.toLocaleString()} 字符 (约 ${sizeKB} KB)`)
94
- console.log(`节点深度: ${params.maxDepth}`)
95
- } catch (error) {
96
- if (error instanceof MGError) {
97
- console.error(`错误 [${error.code}]: ${error.message}`)
98
- } else {
99
- console.error(`错误: ${error instanceof Error ? error.message : error}`)
100
- }
101
- process.exit(1)
102
- } finally {
103
- client.close()
104
- }
105
- }