@meet-im/lxcli 0.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.
- package/LICENSE +15 -0
- package/README.md +3 -0
- package/bin/lxcli.js +2 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +45 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +28 -0
- package/dist/commands/generate-skills.d.ts +2 -0
- package/dist/commands/generate-skills.js +283 -0
- package/dist/commands/index.d.ts +9 -0
- package/dist/commands/index.js +43 -0
- package/dist/commands/schema.d.ts +2 -0
- package/dist/commands/schema.js +37 -0
- package/dist/commands/services/kb/config.d.ts +2 -0
- package/dist/commands/services/kb/config.js +32 -0
- package/dist/commands/services/kb/descriptions.d.ts +4 -0
- package/dist/commands/services/kb/descriptions.js +24 -0
- package/dist/commands/services/kb/handler.d.ts +12 -0
- package/dist/commands/services/kb/handler.js +179 -0
- package/dist/commands/services/kb/index.d.ts +3 -0
- package/dist/commands/services/kb/index.js +119 -0
- package/dist/commands/services/kb/params.d.ts +8 -0
- package/dist/commands/services/kb/params.js +73 -0
- package/dist/commands/services/kb/rpc.d.ts +1 -0
- package/dist/commands/services/kb/rpc.js +35 -0
- package/dist/commands/services/kb/types.d.ts +97 -0
- package/dist/commands/services/kb/types.js +2 -0
- package/dist/commands/services/kb/utils.d.ts +1 -0
- package/dist/commands/services/kb/utils.js +4 -0
- package/dist/commands/services/meet/api.d.ts +13 -0
- package/dist/commands/services/meet/api.js +38 -0
- package/dist/commands/services/meet/config.d.ts +4 -0
- package/dist/commands/services/meet/config.js +16 -0
- package/dist/commands/services/meet/descriptions.d.ts +3 -0
- package/dist/commands/services/meet/descriptions.js +7 -0
- package/dist/commands/services/meet/handler.d.ts +25 -0
- package/dist/commands/services/meet/handler.js +50 -0
- package/dist/commands/services/meet/index.d.ts +3 -0
- package/dist/commands/services/meet/index.js +43 -0
- package/dist/commands/services/meet/types.d.ts +65 -0
- package/dist/commands/services/meet/types.js +2 -0
- package/dist/commands/services/meetbot/api.d.ts +37 -0
- package/dist/commands/services/meetbot/api.js +130 -0
- package/dist/commands/services/meetbot/config.d.ts +4 -0
- package/dist/commands/services/meetbot/config.js +21 -0
- package/dist/commands/services/meetbot/descriptions.d.ts +3 -0
- package/dist/commands/services/meetbot/descriptions.js +10 -0
- package/dist/commands/services/meetbot/handler.d.ts +42 -0
- package/dist/commands/services/meetbot/handler.js +83 -0
- package/dist/commands/services/meetbot/index.d.ts +3 -0
- package/dist/commands/services/meetbot/index.js +74 -0
- package/dist/commands/services/meetbot/types.d.ts +101 -0
- package/dist/commands/services/meetbot/types.js +2 -0
- package/dist/commands/services/meetbot/utils.d.ts +28 -0
- package/dist/commands/services/meetbot/utils.js +78 -0
- package/dist/commands/services.d.ts +2 -0
- package/dist/commands/services.js +50 -0
- package/dist/commands/tenants.d.ts +2 -0
- package/dist/commands/tenants.js +46 -0
- package/dist/commands/upgrade.d.ts +2 -0
- package/dist/commands/upgrade.js +38 -0
- package/dist/commands/users.d.ts +2 -0
- package/dist/commands/users.js +182 -0
- package/dist/core/auth.d.ts +26 -0
- package/dist/core/auth.js +75 -0
- package/dist/core/config.d.ts +76 -0
- package/dist/core/config.js +255 -0
- package/dist/core/error.d.ts +128 -0
- package/dist/core/error.js +85 -0
- package/dist/core/help.d.ts +6 -0
- package/dist/core/help.js +15 -0
- package/dist/core/http.d.ts +28 -0
- package/dist/core/http.js +140 -0
- package/dist/core/logger.d.ts +24 -0
- package/dist/core/logger.js +53 -0
- package/dist/core/reserved.d.ts +13 -0
- package/dist/core/reserved.js +28 -0
- package/dist/core/tenants.d.ts +36 -0
- package/dist/core/tenants.js +50 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +152 -0
- package/dist/types/index.d.ts +59 -0
- package/dist/types/index.js +5 -0
- package/dist/utils/index.d.ts +20 -0
- package/dist/utils/index.js +133 -0
- package/dist/utils/loose-params.d.ts +9 -0
- package/dist/utils/loose-params.js +274 -0
- package/dist/utils/table.d.ts +4 -0
- package/dist/utils/table.js +25 -0
- package/package.json +46 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { AppConfig, UserConfig } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* 生成用户 ID (name@tenant)
|
|
4
|
+
*/
|
|
5
|
+
export declare function getUserId(name: string, tenant: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* 解析用户 ID
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseUserId(id: string): {
|
|
10
|
+
name: string;
|
|
11
|
+
tenant: string;
|
|
12
|
+
} | null;
|
|
13
|
+
/**
|
|
14
|
+
* 获取配置文件路径
|
|
15
|
+
*/
|
|
16
|
+
export declare function getConfigPath(): string;
|
|
17
|
+
/**
|
|
18
|
+
* 获取配置目录路径
|
|
19
|
+
*/
|
|
20
|
+
export declare function getConfigDir(): string;
|
|
21
|
+
/**
|
|
22
|
+
* 加载配置
|
|
23
|
+
*/
|
|
24
|
+
export declare function loadConfig(): AppConfig;
|
|
25
|
+
/**
|
|
26
|
+
* 保存配置
|
|
27
|
+
*/
|
|
28
|
+
export declare function saveConfig(config: AppConfig): void;
|
|
29
|
+
/**
|
|
30
|
+
* 添加用户
|
|
31
|
+
*/
|
|
32
|
+
export declare function addUser(user: UserConfig): void;
|
|
33
|
+
/**
|
|
34
|
+
* 删除用户
|
|
35
|
+
*/
|
|
36
|
+
export declare function removeUser(id: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* 获取用户(支持省略 @tenant)
|
|
39
|
+
*/
|
|
40
|
+
export declare function getUser(idOrName: string): UserConfig | undefined;
|
|
41
|
+
export declare function findUsersByName(name: string): UserConfig[];
|
|
42
|
+
/**
|
|
43
|
+
* 获取默认用户
|
|
44
|
+
*/
|
|
45
|
+
export declare function getDefaultUser(): UserConfig | null;
|
|
46
|
+
/**
|
|
47
|
+
* 设置默认用户
|
|
48
|
+
*/
|
|
49
|
+
export declare function setDefaultUser(id: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* 设置当前用户
|
|
52
|
+
*/
|
|
53
|
+
export declare function setCurrentUser(id: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* 禁用用户
|
|
56
|
+
*/
|
|
57
|
+
export declare function disableUser(id: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* 启用用户
|
|
60
|
+
*/
|
|
61
|
+
export declare function enableUser(id: string): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* 更新用户配置
|
|
64
|
+
*/
|
|
65
|
+
export declare function updateUser(id: string, updates: {
|
|
66
|
+
token?: string;
|
|
67
|
+
env?: string;
|
|
68
|
+
}): UserConfig | null;
|
|
69
|
+
/**
|
|
70
|
+
* 列出所有用户
|
|
71
|
+
*/
|
|
72
|
+
export declare function listUsers(): UserConfig[];
|
|
73
|
+
/**
|
|
74
|
+
* 重置配置
|
|
75
|
+
*/
|
|
76
|
+
export declare function resetConfig(): void;
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// src/core/config.ts
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
import { outputCliError } from './error.js';
|
|
6
|
+
const CONFIG_DIR = '.lxcli';
|
|
7
|
+
const CONFIG_FILE = 'config.json';
|
|
8
|
+
const CONFIG_VERSION = '1.0';
|
|
9
|
+
/**
|
|
10
|
+
* 生成用户 ID (name@tenant)
|
|
11
|
+
*/
|
|
12
|
+
export function getUserId(name, tenant) {
|
|
13
|
+
return `${name}@${tenant}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 解析用户 ID
|
|
17
|
+
*/
|
|
18
|
+
export function parseUserId(id) {
|
|
19
|
+
const parts = id.split('@');
|
|
20
|
+
if (parts.length !== 2)
|
|
21
|
+
return null;
|
|
22
|
+
return { name: parts[0], tenant: parts[1] };
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 获取配置文件路径
|
|
26
|
+
*/
|
|
27
|
+
export function getConfigPath() {
|
|
28
|
+
const configDir = process.env.LXCLI_CONFIG_DIR || path.join(os.homedir(), CONFIG_DIR);
|
|
29
|
+
return path.join(configDir, CONFIG_FILE);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 获取配置目录路径
|
|
33
|
+
*/
|
|
34
|
+
export function getConfigDir() {
|
|
35
|
+
return process.env.LXCLI_CONFIG_DIR || path.join(os.homedir(), CONFIG_DIR);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 确保用户有 id 字段(兼容旧数据)
|
|
39
|
+
*/
|
|
40
|
+
function ensureUserId(user) {
|
|
41
|
+
if (!user.id) {
|
|
42
|
+
user.id = getUserId(user.name, user.tenant);
|
|
43
|
+
}
|
|
44
|
+
return user;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 确保配置目录存在
|
|
48
|
+
*/
|
|
49
|
+
function ensureConfigDir() {
|
|
50
|
+
const configDir = getConfigDir();
|
|
51
|
+
if (!fs.existsSync(configDir)) {
|
|
52
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 加载配置
|
|
57
|
+
*/
|
|
58
|
+
export function loadConfig() {
|
|
59
|
+
const configPath = getConfigPath();
|
|
60
|
+
if (!fs.existsSync(configPath)) {
|
|
61
|
+
return {
|
|
62
|
+
version: CONFIG_VERSION,
|
|
63
|
+
users: [],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
68
|
+
const config = JSON.parse(content);
|
|
69
|
+
// 兼容旧数据:确保每个用户有 id
|
|
70
|
+
config.users.forEach(ensureUserId);
|
|
71
|
+
return config;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
outputCliError('CONFIG_READ_ERROR', 'Failed to load config file', {
|
|
75
|
+
path: configPath,
|
|
76
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 保存配置
|
|
82
|
+
*/
|
|
83
|
+
export function saveConfig(config) {
|
|
84
|
+
ensureConfigDir();
|
|
85
|
+
const configPath = getConfigPath();
|
|
86
|
+
try {
|
|
87
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
outputCliError('CONFIG_WRITE_ERROR', 'Failed to save config file', {
|
|
91
|
+
path: configPath,
|
|
92
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 添加用户
|
|
98
|
+
*/
|
|
99
|
+
export function addUser(user) {
|
|
100
|
+
const config = loadConfig();
|
|
101
|
+
// 确保 id
|
|
102
|
+
ensureUserId(user);
|
|
103
|
+
// 检查用户是否已存在 (name + tenant)
|
|
104
|
+
const existingIndex = config.users.findIndex(u => u.id === user.id);
|
|
105
|
+
if (existingIndex >= 0) {
|
|
106
|
+
config.users[existingIndex] = user;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// 第一个用户自动设为默认
|
|
110
|
+
if (config.users.length === 0) {
|
|
111
|
+
user.isDefault = true;
|
|
112
|
+
}
|
|
113
|
+
config.users.push(user);
|
|
114
|
+
}
|
|
115
|
+
saveConfig(config);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 删除用户
|
|
119
|
+
*/
|
|
120
|
+
export function removeUser(id) {
|
|
121
|
+
const config = loadConfig();
|
|
122
|
+
const index = config.users.findIndex(u => u.id === id);
|
|
123
|
+
if (index < 0)
|
|
124
|
+
return false;
|
|
125
|
+
const removedUser = config.users[index];
|
|
126
|
+
config.users.splice(index, 1);
|
|
127
|
+
// 如果删除的是默认用户,将第一个用户设为默认
|
|
128
|
+
if (removedUser.isDefault && config.users.length > 0) {
|
|
129
|
+
config.users[0].isDefault = true;
|
|
130
|
+
}
|
|
131
|
+
// 如果删除的是当前用户,清除 currentUser
|
|
132
|
+
if (config.currentUser === id) {
|
|
133
|
+
delete config.currentUser;
|
|
134
|
+
}
|
|
135
|
+
saveConfig(config);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* 获取用户(支持省略 @tenant)
|
|
140
|
+
*/
|
|
141
|
+
export function getUser(idOrName) {
|
|
142
|
+
const config = loadConfig();
|
|
143
|
+
// 精确匹配 (name@tenant)
|
|
144
|
+
const exact = config.users.find(u => u.id === idOrName);
|
|
145
|
+
if (exact)
|
|
146
|
+
return exact;
|
|
147
|
+
// 模糊匹配 (只有 name)
|
|
148
|
+
const matches = config.users.filter(u => u.name === idOrName);
|
|
149
|
+
if (matches.length === 0)
|
|
150
|
+
return undefined;
|
|
151
|
+
// 只有一个同名用户,直接返回
|
|
152
|
+
if (matches.length === 1)
|
|
153
|
+
return matches[0];
|
|
154
|
+
// 多个同名用户,优先返回默认用户
|
|
155
|
+
const defaultMatch = matches.find(u => u.isDefault);
|
|
156
|
+
if (defaultMatch)
|
|
157
|
+
return defaultMatch;
|
|
158
|
+
// 返回第一个
|
|
159
|
+
return matches[0];
|
|
160
|
+
}
|
|
161
|
+
export function findUsersByName(name) {
|
|
162
|
+
const config = loadConfig();
|
|
163
|
+
return config.users.filter(user => user.name === name);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 获取默认用户
|
|
167
|
+
*/
|
|
168
|
+
export function getDefaultUser() {
|
|
169
|
+
const config = loadConfig();
|
|
170
|
+
return config.users.find(u => u.isDefault) || config.users[0] || null;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 设置默认用户
|
|
174
|
+
*/
|
|
175
|
+
export function setDefaultUser(id) {
|
|
176
|
+
const config = loadConfig();
|
|
177
|
+
const user = config.users.find(u => u.id === id);
|
|
178
|
+
if (!user)
|
|
179
|
+
return false;
|
|
180
|
+
// 清除其他用户的默认标记
|
|
181
|
+
config.users.forEach(u => {
|
|
182
|
+
u.isDefault = u.id === id;
|
|
183
|
+
});
|
|
184
|
+
saveConfig(config);
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* 设置当前用户
|
|
189
|
+
*/
|
|
190
|
+
export function setCurrentUser(id) {
|
|
191
|
+
const config = loadConfig();
|
|
192
|
+
const user = config.users.find(u => u.id === id);
|
|
193
|
+
if (!user)
|
|
194
|
+
return false;
|
|
195
|
+
config.currentUser = id;
|
|
196
|
+
saveConfig(config);
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* 禁用用户
|
|
201
|
+
*/
|
|
202
|
+
export function disableUser(id) {
|
|
203
|
+
const config = loadConfig();
|
|
204
|
+
const user = config.users.find(u => u.id === id);
|
|
205
|
+
if (!user)
|
|
206
|
+
return false;
|
|
207
|
+
user.disabled = true;
|
|
208
|
+
saveConfig(config);
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* 启用用户
|
|
213
|
+
*/
|
|
214
|
+
export function enableUser(id) {
|
|
215
|
+
const config = loadConfig();
|
|
216
|
+
const user = config.users.find(u => u.id === id);
|
|
217
|
+
if (!user)
|
|
218
|
+
return false;
|
|
219
|
+
user.disabled = false;
|
|
220
|
+
saveConfig(config);
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* 更新用户配置
|
|
225
|
+
*/
|
|
226
|
+
export function updateUser(id, updates) {
|
|
227
|
+
const config = loadConfig();
|
|
228
|
+
const user = config.users.find(u => u.id === id);
|
|
229
|
+
if (!user)
|
|
230
|
+
return null;
|
|
231
|
+
if (updates.token !== undefined) {
|
|
232
|
+
user.token = updates.token;
|
|
233
|
+
}
|
|
234
|
+
if (updates.env !== undefined) {
|
|
235
|
+
user.env = updates.env;
|
|
236
|
+
}
|
|
237
|
+
saveConfig(config);
|
|
238
|
+
return user;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* 列出所有用户
|
|
242
|
+
*/
|
|
243
|
+
export function listUsers() {
|
|
244
|
+
const config = loadConfig();
|
|
245
|
+
return config.users;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* 重置配置
|
|
249
|
+
*/
|
|
250
|
+
export function resetConfig() {
|
|
251
|
+
const configPath = getConfigPath();
|
|
252
|
+
if (fs.existsSync(configPath)) {
|
|
253
|
+
fs.unlinkSync(configPath);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI 退出码(供 shell / CI 使用)
|
|
3
|
+
*/
|
|
4
|
+
export declare const CLI_EXIT_CODES: {
|
|
5
|
+
readonly GENERAL: 1;
|
|
6
|
+
readonly PARAM: 2;
|
|
7
|
+
readonly AUTH: 3;
|
|
8
|
+
readonly NOT_FOUND: 4;
|
|
9
|
+
readonly INTERNAL: 5;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* CLI 业务错误码(供 JSON 输出使用)
|
|
13
|
+
*/
|
|
14
|
+
export declare const CLI_ERROR_CODES: {
|
|
15
|
+
readonly UNKNOWN: {
|
|
16
|
+
readonly code: 10000;
|
|
17
|
+
readonly reason: "unknownError";
|
|
18
|
+
readonly exitCode: 1;
|
|
19
|
+
};
|
|
20
|
+
readonly PARAM_MISSING: {
|
|
21
|
+
readonly code: 10001;
|
|
22
|
+
readonly reason: "paramMissing";
|
|
23
|
+
readonly exitCode: 2;
|
|
24
|
+
};
|
|
25
|
+
readonly PARAM_INVALID: {
|
|
26
|
+
readonly code: 10002;
|
|
27
|
+
readonly reason: "paramInvalid";
|
|
28
|
+
readonly exitCode: 2;
|
|
29
|
+
};
|
|
30
|
+
readonly USER_NOT_FOUND: {
|
|
31
|
+
readonly code: 20001;
|
|
32
|
+
readonly reason: "userNotFound";
|
|
33
|
+
readonly exitCode: 4;
|
|
34
|
+
};
|
|
35
|
+
readonly USER_DISABLED: {
|
|
36
|
+
readonly code: 20002;
|
|
37
|
+
readonly reason: "userDisabled";
|
|
38
|
+
readonly exitCode: 3;
|
|
39
|
+
};
|
|
40
|
+
readonly TENANT_NOT_FOUND: {
|
|
41
|
+
readonly code: 30001;
|
|
42
|
+
readonly reason: "tenantNotFound";
|
|
43
|
+
readonly exitCode: 4;
|
|
44
|
+
};
|
|
45
|
+
readonly SERVICE_NOT_FOUND: {
|
|
46
|
+
readonly code: 30002;
|
|
47
|
+
readonly reason: "serviceNotFound";
|
|
48
|
+
readonly exitCode: 4;
|
|
49
|
+
};
|
|
50
|
+
readonly CONFIG_READ_ERROR: {
|
|
51
|
+
readonly code: 40001;
|
|
52
|
+
readonly reason: "configReadError";
|
|
53
|
+
readonly exitCode: 5;
|
|
54
|
+
};
|
|
55
|
+
readonly CONFIG_WRITE_ERROR: {
|
|
56
|
+
readonly code: 40002;
|
|
57
|
+
readonly reason: "configWriteError";
|
|
58
|
+
readonly exitCode: 5;
|
|
59
|
+
};
|
|
60
|
+
readonly NETWORK_ERROR: {
|
|
61
|
+
readonly code: 50001;
|
|
62
|
+
readonly reason: "networkError";
|
|
63
|
+
readonly exitCode: 5;
|
|
64
|
+
};
|
|
65
|
+
readonly UPGRADE_CHECK_FAILED: {
|
|
66
|
+
readonly code: 50002;
|
|
67
|
+
readonly reason: "upgradeCheckFailed";
|
|
68
|
+
readonly exitCode: 5;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export type CliErrorKey = keyof typeof CLI_ERROR_CODES;
|
|
72
|
+
export declare function getErrorMeta(key: CliErrorKey): {
|
|
73
|
+
readonly code: 10000;
|
|
74
|
+
readonly reason: "unknownError";
|
|
75
|
+
readonly exitCode: 1;
|
|
76
|
+
} | {
|
|
77
|
+
readonly code: 10001;
|
|
78
|
+
readonly reason: "paramMissing";
|
|
79
|
+
readonly exitCode: 2;
|
|
80
|
+
} | {
|
|
81
|
+
readonly code: 10002;
|
|
82
|
+
readonly reason: "paramInvalid";
|
|
83
|
+
readonly exitCode: 2;
|
|
84
|
+
} | {
|
|
85
|
+
readonly code: 20001;
|
|
86
|
+
readonly reason: "userNotFound";
|
|
87
|
+
readonly exitCode: 4;
|
|
88
|
+
} | {
|
|
89
|
+
readonly code: 20002;
|
|
90
|
+
readonly reason: "userDisabled";
|
|
91
|
+
readonly exitCode: 3;
|
|
92
|
+
} | {
|
|
93
|
+
readonly code: 30001;
|
|
94
|
+
readonly reason: "tenantNotFound";
|
|
95
|
+
readonly exitCode: 4;
|
|
96
|
+
} | {
|
|
97
|
+
readonly code: 30002;
|
|
98
|
+
readonly reason: "serviceNotFound";
|
|
99
|
+
readonly exitCode: 4;
|
|
100
|
+
} | {
|
|
101
|
+
readonly code: 40001;
|
|
102
|
+
readonly reason: "configReadError";
|
|
103
|
+
readonly exitCode: 5;
|
|
104
|
+
} | {
|
|
105
|
+
readonly code: 40002;
|
|
106
|
+
readonly reason: "configWriteError";
|
|
107
|
+
readonly exitCode: 5;
|
|
108
|
+
} | {
|
|
109
|
+
readonly code: 50001;
|
|
110
|
+
readonly reason: "networkError";
|
|
111
|
+
readonly exitCode: 5;
|
|
112
|
+
} | {
|
|
113
|
+
readonly code: 50002;
|
|
114
|
+
readonly reason: "upgradeCheckFailed";
|
|
115
|
+
readonly exitCode: 5;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* 输出错误响应(JSON 格式到 stdout,人类提示到 stderr)
|
|
119
|
+
*/
|
|
120
|
+
export declare function outputError(exitCode: number, code: number, message: string, reason?: string, details?: Record<string, unknown>): never;
|
|
121
|
+
/**
|
|
122
|
+
* 输出 API 错误响应
|
|
123
|
+
*/
|
|
124
|
+
export declare function outputCliError(errorCode: CliErrorKey, message: string, details?: Record<string, unknown>): never;
|
|
125
|
+
/**
|
|
126
|
+
* 输出 API 错误响应
|
|
127
|
+
*/
|
|
128
|
+
export declare function outputApiError(code: number, message: string, details?: Record<string, unknown>, httpStatus?: number): never;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// src/core/error.ts
|
|
2
|
+
/**
|
|
3
|
+
* CLI 退出码(供 shell / CI 使用)
|
|
4
|
+
*/
|
|
5
|
+
export const CLI_EXIT_CODES = {
|
|
6
|
+
GENERAL: 1,
|
|
7
|
+
PARAM: 2,
|
|
8
|
+
AUTH: 3,
|
|
9
|
+
NOT_FOUND: 4,
|
|
10
|
+
INTERNAL: 5,
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* CLI 业务错误码(供 JSON 输出使用)
|
|
14
|
+
*/
|
|
15
|
+
export const CLI_ERROR_CODES = {
|
|
16
|
+
UNKNOWN: { code: 10000, reason: 'unknownError', exitCode: CLI_EXIT_CODES.GENERAL },
|
|
17
|
+
PARAM_MISSING: { code: 10001, reason: 'paramMissing', exitCode: CLI_EXIT_CODES.PARAM },
|
|
18
|
+
PARAM_INVALID: { code: 10002, reason: 'paramInvalid', exitCode: CLI_EXIT_CODES.PARAM },
|
|
19
|
+
USER_NOT_FOUND: { code: 20001, reason: 'userNotFound', exitCode: CLI_EXIT_CODES.NOT_FOUND },
|
|
20
|
+
USER_DISABLED: { code: 20002, reason: 'userDisabled', exitCode: CLI_EXIT_CODES.AUTH },
|
|
21
|
+
TENANT_NOT_FOUND: { code: 30001, reason: 'tenantNotFound', exitCode: CLI_EXIT_CODES.NOT_FOUND },
|
|
22
|
+
SERVICE_NOT_FOUND: { code: 30002, reason: 'serviceNotFound', exitCode: CLI_EXIT_CODES.NOT_FOUND },
|
|
23
|
+
CONFIG_READ_ERROR: { code: 40001, reason: 'configReadError', exitCode: CLI_EXIT_CODES.INTERNAL },
|
|
24
|
+
CONFIG_WRITE_ERROR: { code: 40002, reason: 'configWriteError', exitCode: CLI_EXIT_CODES.INTERNAL },
|
|
25
|
+
NETWORK_ERROR: { code: 50001, reason: 'networkError', exitCode: CLI_EXIT_CODES.INTERNAL },
|
|
26
|
+
UPGRADE_CHECK_FAILED: { code: 50002, reason: 'upgradeCheckFailed', exitCode: CLI_EXIT_CODES.INTERNAL },
|
|
27
|
+
};
|
|
28
|
+
export function getErrorMeta(key) {
|
|
29
|
+
return CLI_ERROR_CODES[key];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 输出人类可读错误提示到 stderr
|
|
33
|
+
*/
|
|
34
|
+
function supportsColor() {
|
|
35
|
+
return Boolean(process.stderr.isTTY) && !process.env.CI && !process.env.NO_COLOR;
|
|
36
|
+
}
|
|
37
|
+
function printErrorHint(reason, message) {
|
|
38
|
+
const text = `error[${reason || 'unknown'}]:`;
|
|
39
|
+
const label = supportsColor() ? `\x1b[1;31m${text}\x1b[0m` : text;
|
|
40
|
+
console.error(`${label} ${message}`);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 输出错误响应(JSON 格式到 stdout,人类提示到 stderr)
|
|
44
|
+
*/
|
|
45
|
+
export function outputError(exitCode, code, message, reason, details) {
|
|
46
|
+
const response = {
|
|
47
|
+
error: {
|
|
48
|
+
code,
|
|
49
|
+
reason,
|
|
50
|
+
message,
|
|
51
|
+
details: details || {},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
// JSON 到 stdout(供 AI agent / 管道)
|
|
55
|
+
console.log(JSON.stringify(response, null, 2));
|
|
56
|
+
// 人类提示到 stderr
|
|
57
|
+
printErrorHint(reason, message);
|
|
58
|
+
process.exit(exitCode);
|
|
59
|
+
throw new Error('Never reached');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 输出 API 错误响应
|
|
63
|
+
*/
|
|
64
|
+
export function outputCliError(errorCode, message, details) {
|
|
65
|
+
const meta = getErrorMeta(errorCode);
|
|
66
|
+
return outputError(meta.exitCode, meta.code, message, meta.reason, details);
|
|
67
|
+
}
|
|
68
|
+
function getApiExitCode(httpStatus) {
|
|
69
|
+
if (httpStatus === 400) {
|
|
70
|
+
return CLI_EXIT_CODES.PARAM;
|
|
71
|
+
}
|
|
72
|
+
if (httpStatus === 401 || httpStatus === 403) {
|
|
73
|
+
return CLI_EXIT_CODES.AUTH;
|
|
74
|
+
}
|
|
75
|
+
if (httpStatus === 404) {
|
|
76
|
+
return CLI_EXIT_CODES.NOT_FOUND;
|
|
77
|
+
}
|
|
78
|
+
return CLI_EXIT_CODES.INTERNAL;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 输出 API 错误响应
|
|
82
|
+
*/
|
|
83
|
+
export function outputApiError(code, message, details, httpStatus) {
|
|
84
|
+
return outputError(getApiExitCode(httpStatus ?? code), code, message, 'apiError', details);
|
|
85
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/core/help.ts
|
|
2
|
+
/**
|
|
3
|
+
* 自定义帮助显示,分组展示内置命令和服务命令
|
|
4
|
+
*/
|
|
5
|
+
export function configureHelp(program, services) {
|
|
6
|
+
// 在帮助后添加服务分组
|
|
7
|
+
program.addHelpText('after', () => {
|
|
8
|
+
if (services.length === 0)
|
|
9
|
+
return '';
|
|
10
|
+
const serviceList = services
|
|
11
|
+
.map((s) => ` ${s.name.padEnd(15)} ${s.description}`)
|
|
12
|
+
.join('\n');
|
|
13
|
+
return `\nServices:\n${serviceList}\n`;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface RequestOptions {
|
|
2
|
+
/** gateway 地址(必填) */
|
|
3
|
+
gateway: string;
|
|
4
|
+
/** 请求路径(不含域名) */
|
|
5
|
+
path: string;
|
|
6
|
+
/** HTTP 方法,默认 GET */
|
|
7
|
+
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
8
|
+
/** URL query 参数 */
|
|
9
|
+
query?: Record<string, string | number | boolean>;
|
|
10
|
+
/** 请求体 */
|
|
11
|
+
body?: Record<string, unknown>;
|
|
12
|
+
/** 自定义 headers(会覆盖默认 headers) */
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
/** User-Agent,默认 lxcli/版本号 */
|
|
15
|
+
userAgent?: string;
|
|
16
|
+
/** 最大重试次数,默认 3 */
|
|
17
|
+
maxRetries?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 通用请求函数
|
|
21
|
+
*
|
|
22
|
+
* 支持灵活传递 gateway、路径、方法、参数、UA 等。
|
|
23
|
+
*
|
|
24
|
+
* 支持自动重试:
|
|
25
|
+
* - 429 (rate limit) 响应时重试,尊重 Retry-After header
|
|
26
|
+
* - 网络错误时重试,使用指数退避
|
|
27
|
+
*/
|
|
28
|
+
export declare function request<T>(options: RequestOptions): Promise<T>;
|