@cloudbase/cloudbase-mcp 1.7.0 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -169
- package/dist/interactive-server.js +1261 -435
- package/dist/tools/env.js +2 -0
- package/dist/tools/functions.js +28 -4
- package/dist/tools/hosting.js +70 -110
- package/dist/tools/interactive.js +4 -4
- package/dist/tools/setup.js +48 -8
- package/dist/utils/logger.js +2 -2
- package/package.json +1 -1
package/dist/tools/env.js
CHANGED
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { getCloudBaseManager } from '../cloudbase-manager.js';
|
|
3
3
|
import { logout } from '../auth.js';
|
|
4
4
|
import { clearUserEnvId, _promptAndSetEnvironmentId } from './interactive.js';
|
|
5
|
+
import { debug } from '../utils/logger.js';
|
|
5
6
|
export function registerEnvTools(server) {
|
|
6
7
|
// login - 登录云开发环境
|
|
7
8
|
server.tool("login", "登录云开发环境并选择要使用的环境", {
|
|
@@ -9,6 +10,7 @@ export function registerEnvTools(server) {
|
|
|
9
10
|
}, async ({ forceUpdate = false }) => {
|
|
10
11
|
try {
|
|
11
12
|
const { selectedEnvId, cancelled, error, noEnvs } = await _promptAndSetEnvironmentId(false);
|
|
13
|
+
debug("login", { selectedEnvId, cancelled, error, noEnvs });
|
|
12
14
|
if (error) {
|
|
13
15
|
return { content: [{ type: "text", text: error }] };
|
|
14
16
|
}
|
package/dist/tools/functions.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { getCloudBaseManager } from '../cloudbase-manager.js';
|
|
3
|
+
import path from 'path';
|
|
3
4
|
// 支持的 Node.js 运行时列表
|
|
4
5
|
export const SUPPORTED_NODEJS_RUNTIMES = [
|
|
5
6
|
'Nodejs 18.15',
|
|
@@ -10,6 +11,25 @@ export const SUPPORTED_NODEJS_RUNTIMES = [
|
|
|
10
11
|
'Nodejs 8.9(即将下线)',
|
|
11
12
|
];
|
|
12
13
|
export const DEFAULT_NODEJS_RUNTIME = 'Nodejs 18.15';
|
|
14
|
+
/**
|
|
15
|
+
* 处理函数根目录路径,确保不包含函数名
|
|
16
|
+
* @param functionRootPath 用户输入的路径
|
|
17
|
+
* @param functionName 函数名称
|
|
18
|
+
* @returns 处理后的根目录路径
|
|
19
|
+
*/
|
|
20
|
+
function processFunctionRootPath(functionRootPath, functionName) {
|
|
21
|
+
if (!functionRootPath)
|
|
22
|
+
return functionRootPath;
|
|
23
|
+
const normalizedPath = path.normalize(functionRootPath);
|
|
24
|
+
const lastDir = path.basename(normalizedPath);
|
|
25
|
+
// 如果路径的最后一级目录名与函数名相同,说明用户可能传入了包含函数名的路径
|
|
26
|
+
if (lastDir === functionName) {
|
|
27
|
+
const parentPath = path.dirname(normalizedPath);
|
|
28
|
+
console.warn(`检测到 functionRootPath 包含函数名 "${functionName}",已自动调整为父目录: ${parentPath}`);
|
|
29
|
+
return parentPath;
|
|
30
|
+
}
|
|
31
|
+
return functionRootPath;
|
|
32
|
+
}
|
|
13
33
|
export function registerFunctionTools(server) {
|
|
14
34
|
// getFunctionList - 获取云函数列表(推荐)
|
|
15
35
|
server.tool("getFunctionList", "获取云函数列表", {
|
|
@@ -52,17 +72,19 @@ export function registerFunctionTools(server) {
|
|
|
52
72
|
version: z.number()
|
|
53
73
|
})).optional().describe("Layer配置")
|
|
54
74
|
}).describe("函数配置"),
|
|
55
|
-
functionRootPath: z.string().optional().describe("
|
|
75
|
+
functionRootPath: z.string().optional().describe("函数根目录(云函数目录的父目录),这里需要传操作系统上文件的绝对路径,注意:不要包含函数名本身,例如函数名为 'hello',应传入 '/path/to/cloudfunctions',而不是 '/path/to/cloudfunctions/hello'"),
|
|
56
76
|
force: z.boolean().describe("是否覆盖")
|
|
57
77
|
}, async ({ func, functionRootPath, force }) => {
|
|
58
78
|
// 自动填充默认 runtime
|
|
59
79
|
if (!func.runtime) {
|
|
60
80
|
func.runtime = DEFAULT_NODEJS_RUNTIME;
|
|
61
81
|
}
|
|
82
|
+
// 处理函数根目录路径,确保不包含函数名
|
|
83
|
+
const processedRootPath = processFunctionRootPath(functionRootPath, func.name);
|
|
62
84
|
const cloudbase = await getCloudBaseManager();
|
|
63
85
|
const result = await cloudbase.functions.createFunction({
|
|
64
86
|
func,
|
|
65
|
-
functionRootPath,
|
|
87
|
+
functionRootPath: processedRootPath,
|
|
66
88
|
force
|
|
67
89
|
});
|
|
68
90
|
return {
|
|
@@ -79,15 +101,17 @@ export function registerFunctionTools(server) {
|
|
|
79
101
|
func: z.object({
|
|
80
102
|
name: z.string().describe("函数名称")
|
|
81
103
|
}).describe("函数配置"),
|
|
82
|
-
functionRootPath: z.string().optional().describe("
|
|
104
|
+
functionRootPath: z.string().optional().describe("函数根目录(云函数目录的父目录),这里需要传操作系统上文件的绝对路径,注意:不要包含函数名本身,例如函数名为 'hello',应传入 '/path/to/cloudfunctions',而不是 '/path/to/cloudfunctions/hello'")
|
|
83
105
|
}, async ({ func, functionRootPath }) => {
|
|
106
|
+
// 处理函数根目录路径,确保不包含函数名
|
|
107
|
+
const processedRootPath = processFunctionRootPath(functionRootPath, func.name);
|
|
84
108
|
const cloudbase = await getCloudBaseManager();
|
|
85
109
|
const result = await cloudbase.functions.updateFunctionCode({
|
|
86
110
|
func: {
|
|
87
111
|
...func,
|
|
88
112
|
installDependency: true // 默认安装依赖
|
|
89
113
|
},
|
|
90
|
-
functionRootPath,
|
|
114
|
+
functionRootPath: processedRootPath,
|
|
91
115
|
});
|
|
92
116
|
return {
|
|
93
117
|
content: [
|
package/dist/tools/hosting.js
CHANGED
|
@@ -96,109 +96,16 @@ export function registerHostingTools(server) {
|
|
|
96
96
|
]
|
|
97
97
|
};
|
|
98
98
|
});
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// replaceKeyWith: z.string().optional(),
|
|
110
|
-
// replaceKeyPrefixWith: z.string().optional()
|
|
111
|
-
// })).optional().describe("重定向规则")
|
|
112
|
-
// },
|
|
113
|
-
// async ({ indexDocument, errorDocument, routingRules }) => {
|
|
114
|
-
// const cloudbase = await getCloudBaseManager()
|
|
115
|
-
// const result = await cloudbase.hosting.setWebsiteDocument({
|
|
116
|
-
// indexDocument,
|
|
117
|
-
// errorDocument,
|
|
118
|
-
// routingRules
|
|
119
|
-
// });
|
|
120
|
-
// return {
|
|
121
|
-
// content: [
|
|
122
|
-
// {
|
|
123
|
-
// type: "text",
|
|
124
|
-
// text: JSON.stringify(result, null, 2)
|
|
125
|
-
// }
|
|
126
|
-
// ]
|
|
127
|
-
// };
|
|
128
|
-
// }
|
|
129
|
-
// );
|
|
130
|
-
// createHostingDomain - 绑定自定义域名
|
|
131
|
-
server.tool("createHostingDomain", "绑定自定义域名", {
|
|
132
|
-
domain: z.string().describe("自定义域名"),
|
|
133
|
-
certId: z.string().describe("证书ID")
|
|
134
|
-
}, async ({ domain, certId }) => {
|
|
135
|
-
const cloudbase = await getCloudBaseManager();
|
|
136
|
-
const result = await cloudbase.hosting.CreateHostingDomain({
|
|
137
|
-
domain,
|
|
138
|
-
certId
|
|
139
|
-
});
|
|
140
|
-
return {
|
|
141
|
-
content: [
|
|
142
|
-
{
|
|
143
|
-
type: "text",
|
|
144
|
-
text: JSON.stringify(result, null, 2)
|
|
145
|
-
}
|
|
146
|
-
]
|
|
147
|
-
};
|
|
148
|
-
});
|
|
149
|
-
// deleteHostingDomain - 解绑自定义域名
|
|
150
|
-
server.tool("deleteHostingDomain", "解绑自定义域名", {
|
|
151
|
-
domain: z.string().describe("自定义域名")
|
|
152
|
-
}, async ({ domain }) => {
|
|
153
|
-
const cloudbase = await getCloudBaseManager();
|
|
154
|
-
const result = await cloudbase.hosting.deleteHostingDomain({
|
|
155
|
-
domain
|
|
156
|
-
});
|
|
157
|
-
return {
|
|
158
|
-
content: [
|
|
159
|
-
{
|
|
160
|
-
type: "text",
|
|
161
|
-
text: JSON.stringify(result, null, 2)
|
|
162
|
-
}
|
|
163
|
-
]
|
|
164
|
-
};
|
|
165
|
-
});
|
|
166
|
-
// getWebsiteConfig - 获取静态网站配置
|
|
167
|
-
server.tool("getWebsiteConfig", "获取静态网站配置", {
|
|
168
|
-
confirm: z.literal("yes").describe("确认操作,默认传 yes")
|
|
169
|
-
}, async () => {
|
|
170
|
-
const cloudbase = await getCloudBaseManager();
|
|
171
|
-
const result = await cloudbase.hosting.getWebsiteConfig();
|
|
172
|
-
return {
|
|
173
|
-
content: [
|
|
174
|
-
{
|
|
175
|
-
type: "text",
|
|
176
|
-
text: JSON.stringify(result, null, 2)
|
|
177
|
-
}
|
|
178
|
-
]
|
|
179
|
-
};
|
|
180
|
-
});
|
|
181
|
-
// tcbCheckResource - 获取域名配置
|
|
182
|
-
server.tool("tcbCheckResource", "获取域名配置", {
|
|
183
|
-
domains: z.array(z.string()).describe("域名列表")
|
|
184
|
-
}, async ({ domains }) => {
|
|
185
|
-
const cloudbase = await getCloudBaseManager();
|
|
186
|
-
const result = await cloudbase.hosting.tcbCheckResource({
|
|
187
|
-
domains
|
|
188
|
-
});
|
|
189
|
-
return {
|
|
190
|
-
content: [
|
|
191
|
-
{
|
|
192
|
-
type: "text",
|
|
193
|
-
text: JSON.stringify(result, null, 2)
|
|
194
|
-
}
|
|
195
|
-
]
|
|
196
|
-
};
|
|
197
|
-
});
|
|
198
|
-
// tcbModifyAttribute - 修改域名配置
|
|
199
|
-
server.tool("tcbModifyAttribute", "修改域名配置", {
|
|
200
|
-
domain: z.string().describe("域名"),
|
|
201
|
-
domainId: z.number().describe("域名ID"),
|
|
99
|
+
// domainManagement - 统一的域名管理工具
|
|
100
|
+
server.tool("domainManagement", "统一的域名管理工具,支持绑定、解绑、查询和修改域名配置", {
|
|
101
|
+
action: z.enum(["create", "delete", "check", "modify"]).describe("操作类型: create=绑定域名, delete=解绑域名, check=查询域名配置, modify=修改域名配置"),
|
|
102
|
+
// 绑定域名参数
|
|
103
|
+
domain: z.string().optional().describe("域名"),
|
|
104
|
+
certId: z.string().optional().describe("证书ID(绑定域名时必需)"),
|
|
105
|
+
// 查询域名参数
|
|
106
|
+
domains: z.array(z.string()).optional().describe("域名列表(查询配置时使用)"),
|
|
107
|
+
// 修改域名参数
|
|
108
|
+
domainId: z.number().optional().describe("域名ID(修改配置时必需)"),
|
|
202
109
|
domainConfig: z.object({
|
|
203
110
|
Refer: z.object({
|
|
204
111
|
Switch: z.string(),
|
|
@@ -222,14 +129,67 @@ export function registerHostingTools(server) {
|
|
|
222
129
|
Switch: z.string(),
|
|
223
130
|
Qps: z.number().optional()
|
|
224
131
|
}).optional()
|
|
225
|
-
}).describe("
|
|
226
|
-
}, async ({ domain, domainId, domainConfig }) => {
|
|
132
|
+
}).optional().describe("域名配置(修改配置时使用)")
|
|
133
|
+
}, async ({ action, domain, certId, domains, domainId, domainConfig }) => {
|
|
227
134
|
const cloudbase = await getCloudBaseManager();
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
135
|
+
let result;
|
|
136
|
+
switch (action) {
|
|
137
|
+
case "create":
|
|
138
|
+
if (!domain || !certId) {
|
|
139
|
+
throw new Error("绑定域名需要提供域名和证书ID");
|
|
140
|
+
}
|
|
141
|
+
result = await cloudbase.hosting.CreateHostingDomain({
|
|
142
|
+
domain,
|
|
143
|
+
certId
|
|
144
|
+
});
|
|
145
|
+
break;
|
|
146
|
+
case "delete":
|
|
147
|
+
if (!domain) {
|
|
148
|
+
throw new Error("解绑域名需要提供域名");
|
|
149
|
+
}
|
|
150
|
+
result = await cloudbase.hosting.deleteHostingDomain({
|
|
151
|
+
domain
|
|
152
|
+
});
|
|
153
|
+
break;
|
|
154
|
+
case "check":
|
|
155
|
+
if (!domains || domains.length === 0) {
|
|
156
|
+
throw new Error("查询域名配置需要提供域名列表");
|
|
157
|
+
}
|
|
158
|
+
result = await cloudbase.hosting.tcbCheckResource({
|
|
159
|
+
domains
|
|
160
|
+
});
|
|
161
|
+
break;
|
|
162
|
+
case "modify":
|
|
163
|
+
if (!domain || domainId === undefined || !domainConfig) {
|
|
164
|
+
throw new Error("修改域名配置需要提供域名、域名ID和配置信息");
|
|
165
|
+
}
|
|
166
|
+
result = await cloudbase.hosting.tcbModifyAttribute({
|
|
167
|
+
domain,
|
|
168
|
+
domainId,
|
|
169
|
+
domainConfig
|
|
170
|
+
});
|
|
171
|
+
break;
|
|
172
|
+
default:
|
|
173
|
+
throw new Error(`不支持的操作类型: ${action}`);
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
content: [
|
|
177
|
+
{
|
|
178
|
+
type: "text",
|
|
179
|
+
text: JSON.stringify({
|
|
180
|
+
action,
|
|
181
|
+
result
|
|
182
|
+
}, null, 2)
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
// getWebsiteConfig - 获取静态网站配置
|
|
188
|
+
server.tool("getWebsiteConfig", "获取静态网站配置", {
|
|
189
|
+
confirm: z.literal("yes").describe("确认操作,默认传 yes")
|
|
190
|
+
}, async () => {
|
|
191
|
+
const cloudbase = await getCloudBaseManager();
|
|
192
|
+
const result = await cloudbase.hosting.getWebsiteConfig();
|
|
233
193
|
return {
|
|
234
194
|
content: [
|
|
235
195
|
{
|
|
@@ -29,7 +29,7 @@ export function registerInteractiveTools(server) {
|
|
|
29
29
|
return {
|
|
30
30
|
content: [{
|
|
31
31
|
type: "text",
|
|
32
|
-
text: `📝 用户澄清反馈:\n${result.data
|
|
32
|
+
text: `📝 用户澄清反馈:\n${result.data}`
|
|
33
33
|
}]
|
|
34
34
|
};
|
|
35
35
|
}
|
|
@@ -45,13 +45,13 @@ export function registerInteractiveTools(server) {
|
|
|
45
45
|
const dialogOptions = options || ["确认执行", "取消操作", "需要修改任务"];
|
|
46
46
|
const interactiveServer = getInteractiveServer();
|
|
47
47
|
const result = await interactiveServer.clarifyRequest(dialogMessage, dialogOptions);
|
|
48
|
-
if (result.cancelled || result.data.
|
|
48
|
+
if (result.cancelled || (result.data && result.data.includes && result.data.includes('取消'))) {
|
|
49
49
|
return { content: [{ type: "text", text: "❌ 用户取消了任务执行" }] };
|
|
50
50
|
}
|
|
51
51
|
return {
|
|
52
52
|
content: [{
|
|
53
53
|
type: "text",
|
|
54
|
-
text: `✅ 用户确认: ${result.data
|
|
54
|
+
text: `✅ 用户确认: ${result.data}`
|
|
55
55
|
}]
|
|
56
56
|
};
|
|
57
57
|
}
|
|
@@ -95,7 +95,7 @@ export async function _promptAndSetEnvironmentId(autoSelectSingle) {
|
|
|
95
95
|
if (result.cancelled) {
|
|
96
96
|
return { selectedEnvId: null, cancelled: true };
|
|
97
97
|
}
|
|
98
|
-
selectedEnvId = result.data
|
|
98
|
+
selectedEnvId = result.data;
|
|
99
99
|
}
|
|
100
100
|
// 4. 保存并设置环境ID
|
|
101
101
|
if (selectedEnvId) {
|
package/dist/tools/setup.js
CHANGED
|
@@ -97,6 +97,27 @@ async function copyFileIfNotExists(src, dest) {
|
|
|
97
97
|
return { copied: false, reason: `复制失败: ${error instanceof Error ? error.message : '未知错误'}` };
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
+
// 复制文件,支持覆盖模式
|
|
101
|
+
async function copyFile(src, dest, overwrite = false) {
|
|
102
|
+
try {
|
|
103
|
+
const destExists = fs.existsSync(dest);
|
|
104
|
+
// 如果目标文件存在且不允许覆盖
|
|
105
|
+
if (destExists && !overwrite) {
|
|
106
|
+
return { copied: false, reason: '文件已存在', action: 'skipped' };
|
|
107
|
+
}
|
|
108
|
+
// 创建目标目录
|
|
109
|
+
await fsPromises.mkdir(path.dirname(dest), { recursive: true });
|
|
110
|
+
// 复制文件
|
|
111
|
+
await fsPromises.copyFile(src, dest);
|
|
112
|
+
return {
|
|
113
|
+
copied: true,
|
|
114
|
+
action: destExists ? 'overwritten' : 'created'
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
return { copied: false, reason: `复制失败: ${error instanceof Error ? error.message : '未知错误'}` };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
100
121
|
export function registerSetupTools(server) {
|
|
101
122
|
server.tool("downloadTemplate", `自动下载并部署CloudBase项目模板。
|
|
102
123
|
|
|
@@ -105,9 +126,10 @@ export function registerSetupTools(server) {
|
|
|
105
126
|
- miniprogram: 微信小程序 + 云开发模板
|
|
106
127
|
- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置
|
|
107
128
|
|
|
108
|
-
工具会自动下载模板到临时目录,解压后如果检测到WORKSPACE_FOLDER_PATHS
|
|
109
|
-
template: z.enum(["react", "miniprogram", "rules"]).describe("要下载的模板类型")
|
|
110
|
-
|
|
129
|
+
工具会自动下载模板到临时目录,解压后如果检测到WORKSPACE_FOLDER_PATHS环境变量,则复制到项目目录。`, {
|
|
130
|
+
template: z.enum(["react", "miniprogram", "rules"]).describe("要下载的模板类型"),
|
|
131
|
+
overwrite: z.boolean().optional().describe("是否覆盖已存在的文件,默认为false(不覆盖)")
|
|
132
|
+
}, async ({ template, overwrite = false }) => {
|
|
111
133
|
try {
|
|
112
134
|
const templateConfig = TEMPLATES[template];
|
|
113
135
|
if (!templateConfig) {
|
|
@@ -131,16 +153,22 @@ export function registerSetupTools(server) {
|
|
|
131
153
|
// 检查是否需要复制到项目目录
|
|
132
154
|
const workspaceFolder = process.env.WORKSPACE_FOLDER_PATHS;
|
|
133
155
|
let finalFiles = [];
|
|
134
|
-
let
|
|
156
|
+
let createdCount = 0;
|
|
157
|
+
let overwrittenCount = 0;
|
|
135
158
|
let skippedCount = 0;
|
|
136
159
|
const results = [];
|
|
137
160
|
if (workspaceFolder) {
|
|
138
161
|
for (const relativePath of extractedFiles) {
|
|
139
162
|
const srcPath = path.join(extractDir, relativePath);
|
|
140
163
|
const destPath = path.join(workspaceFolder, relativePath);
|
|
141
|
-
const copyResult = await
|
|
164
|
+
const copyResult = await copyFile(srcPath, destPath, overwrite);
|
|
142
165
|
if (copyResult.copied) {
|
|
143
|
-
|
|
166
|
+
if (copyResult.action === 'overwritten') {
|
|
167
|
+
overwrittenCount++;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
createdCount++;
|
|
171
|
+
}
|
|
144
172
|
finalFiles.push(destPath);
|
|
145
173
|
}
|
|
146
174
|
else {
|
|
@@ -149,8 +177,20 @@ export function registerSetupTools(server) {
|
|
|
149
177
|
}
|
|
150
178
|
}
|
|
151
179
|
results.push(`✅ ${templateConfig.description} 同步完成`);
|
|
152
|
-
results.push(`📁
|
|
153
|
-
|
|
180
|
+
results.push(`📁 临时目录: ${extractDir}`);
|
|
181
|
+
const stats = [];
|
|
182
|
+
if (createdCount > 0)
|
|
183
|
+
stats.push(`新建 ${createdCount} 个文件`);
|
|
184
|
+
if (overwrittenCount > 0)
|
|
185
|
+
stats.push(`覆盖 ${overwrittenCount} 个文件`);
|
|
186
|
+
if (skippedCount > 0)
|
|
187
|
+
stats.push(`跳过 ${skippedCount} 个已存在文件`);
|
|
188
|
+
if (stats.length > 0) {
|
|
189
|
+
results.push(`📊 ${stats.join(',')}`);
|
|
190
|
+
}
|
|
191
|
+
if (overwrite || overwrittenCount > 0 || skippedCount > 0) {
|
|
192
|
+
results.push(`🔄 覆盖模式: ${overwrite ? '启用' : '禁用'}`);
|
|
193
|
+
}
|
|
154
194
|
}
|
|
155
195
|
else {
|
|
156
196
|
finalFiles = extractedFiles.map(relativePath => path.join(extractDir, relativePath));
|
package/dist/utils/logger.js
CHANGED
|
@@ -14,8 +14,8 @@ class Logger {
|
|
|
14
14
|
logFile;
|
|
15
15
|
useConsole;
|
|
16
16
|
constructor(options = {}) {
|
|
17
|
-
//
|
|
18
|
-
this.enabled = options.enabled ??
|
|
17
|
+
// 默认开启
|
|
18
|
+
this.enabled = options.enabled ?? true;
|
|
19
19
|
this.level = options.level ?? LogLevel.INFO;
|
|
20
20
|
this.useConsole = options.console ?? false;
|
|
21
21
|
// 默认日志文件路径
|