rl-rockcli 0.0.8 → 0.0.9
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/commands/log/core/constants.js +237 -0
- package/commands/log/core/display.js +370 -0
- package/commands/log/core/search.js +330 -0
- package/commands/log/core/tail.js +216 -0
- package/commands/log/core/utils.js +424 -0
- package/commands/log.js +298 -0
- package/commands/sandbox/core/log-bridge.js +119 -0
- package/commands/sandbox/core/replay/analyzer.js +311 -0
- package/commands/sandbox/core/replay/batch-orchestrator.js +536 -0
- package/commands/sandbox/core/replay/batch-task.js +369 -0
- package/commands/sandbox/core/replay/concurrent-display.js +70 -0
- package/commands/sandbox/core/replay/concurrent-orchestrator.js +170 -0
- package/commands/sandbox/core/replay/data-source.js +86 -0
- package/commands/sandbox/core/replay/display.js +231 -0
- package/commands/sandbox/core/replay/executor.js +634 -0
- package/commands/sandbox/core/replay/history-fetcher.js +124 -0
- package/commands/sandbox/core/replay/index.js +338 -0
- package/commands/sandbox/core/replay/loghouse-data-source.js +177 -0
- package/commands/sandbox/core/replay/pid-mapping.js +26 -0
- package/commands/sandbox/core/replay/request.js +109 -0
- package/commands/sandbox/core/replay/worker.js +166 -0
- package/commands/sandbox/core/session.js +346 -0
- package/commands/sandbox/log-bridge.js +2 -0
- package/commands/sandbox/ray.js +2 -0
- package/commands/sandbox/replay/analyzer.js +311 -0
- package/commands/sandbox/replay/batch-orchestrator.js +536 -0
- package/commands/sandbox/replay/batch-task.js +369 -0
- package/commands/sandbox/replay/concurrent-display.js +70 -0
- package/commands/sandbox/replay/concurrent-orchestrator.js +170 -0
- package/commands/sandbox/replay/display.js +231 -0
- package/commands/sandbox/replay/executor.js +634 -0
- package/commands/sandbox/replay/history-fetcher.js +118 -0
- package/commands/sandbox/replay/index.js +338 -0
- package/commands/sandbox/replay/pid-mapping.js +26 -0
- package/commands/sandbox/replay/request.js +109 -0
- package/commands/sandbox/replay/worker.js +166 -0
- package/commands/sandbox/replay.js +2 -0
- package/commands/sandbox/session.js +2 -0
- package/commands/sandbox-original.js +1393 -0
- package/commands/sandbox.js +499 -0
- package/help/help.json +1071 -0
- package/help/middleware.js +71 -0
- package/help/renderer.js +800 -0
- package/index.js +5 -15
- package/lib/plugin-context.js +40 -0
- package/package.json +2 -2
- package/sdks/sandbox/core/client.js +845 -0
- package/sdks/sandbox/core/config.js +70 -0
- package/sdks/sandbox/core/types.js +74 -0
- package/sdks/sandbox/httpLogger.js +251 -0
- package/sdks/sandbox/index.js +9 -0
- package/utils/asciiArt.js +138 -0
- package/utils/bun-compat.js +59 -0
- package/utils/ciPipelines.js +138 -0
- package/utils/cli.js +17 -0
- package/utils/command-router.js +79 -0
- package/utils/configManager.js +503 -0
- package/utils/dependency-resolver.js +135 -0
- package/utils/eagleeye_traceid.js +151 -0
- package/utils/envDetector.js +78 -0
- package/utils/execution_logger.js +415 -0
- package/utils/featureManager.js +68 -0
- package/utils/firstTimeTip.js +44 -0
- package/utils/hook-manager.js +125 -0
- package/utils/http-logger.js +264 -0
- package/utils/i18n.js +139 -0
- package/utils/image-progress.js +159 -0
- package/utils/logger.js +154 -0
- package/utils/plugin-loader.js +124 -0
- package/utils/plugin-manager.js +348 -0
- package/utils/ray_cli_wrapper.js +746 -0
- package/utils/sandbox-client.js +419 -0
- package/utils/terminal.js +32 -0
- package/utils/tips.js +106 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const logger = require('./logger');
|
|
4
|
+
const { gracefulExit } = require('./execution_logger');
|
|
5
|
+
const DependencyResolver = require('./dependency-resolver');
|
|
6
|
+
const PluginLoader = require('./plugin-loader');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 插件管理器
|
|
10
|
+
* 负责插件系统的初始化、加载和命令注册
|
|
11
|
+
*/
|
|
12
|
+
class PluginManager {
|
|
13
|
+
constructor(configManager, hookManager) {
|
|
14
|
+
this._configManager = configManager;
|
|
15
|
+
this._hookManager = hookManager;
|
|
16
|
+
this._loader = new PluginLoader();
|
|
17
|
+
this._resolver = new DependencyResolver();
|
|
18
|
+
this._loadedPlugins = [];
|
|
19
|
+
this._registeredCommands = [];
|
|
20
|
+
this._currentPluginMetadata = null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 初始化插件系统
|
|
25
|
+
* @returns {Promise<void>}
|
|
26
|
+
*/
|
|
27
|
+
async initialize() {
|
|
28
|
+
// 检查是否禁用插件
|
|
29
|
+
if (process.env.ROCK_DISABLE_PLUGINS === 'true') {
|
|
30
|
+
logger.info('Plugin system disabled via ROCK_DISABLE_PLUGINS');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 读取插件配置
|
|
35
|
+
const pluginsConfig = this._configManager.getPlugins();
|
|
36
|
+
|
|
37
|
+
// 转换插件配置为路径数组(包括用户配置的插件)
|
|
38
|
+
const pluginPaths = this._convertPluginsConfigToPaths(pluginsConfig);
|
|
39
|
+
|
|
40
|
+
// 扫描并添加内置插件(plugins/ 目录)
|
|
41
|
+
const builtInPlugins = await this._scanBuiltInPlugins(pluginsConfig);
|
|
42
|
+
pluginPaths.push(...builtInPlugins);
|
|
43
|
+
|
|
44
|
+
if (!pluginPaths || pluginPaths.length === 0) {
|
|
45
|
+
logger.debug('No plugins configured');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
logger.debug(`Initializing plugin system with ${pluginPaths.length} plugins`);
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
// 解析插件元数据
|
|
53
|
+
const pluginsMetadata = await this._parseAllPluginsMetadata(pluginPaths);
|
|
54
|
+
|
|
55
|
+
// 检测依赖环并确定加载顺序
|
|
56
|
+
const loadOrder = this._resolver.resolveLoadOrder(pluginsMetadata);
|
|
57
|
+
logger.debug(`Plugin load order: ${loadOrder.join(' -> ')}`);
|
|
58
|
+
|
|
59
|
+
// 按顺序加载插件
|
|
60
|
+
for (const pluginName of loadOrder) {
|
|
61
|
+
const pluginInfo = pluginsMetadata.find(p => p.name === pluginName);
|
|
62
|
+
if (pluginInfo) {
|
|
63
|
+
await this._loadSinglePlugin(pluginInfo);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 触发 plugin-load 钩子
|
|
68
|
+
await this._hookManager.executeHooks('plugin-load', {
|
|
69
|
+
plugins: this._loadedPlugins.map(p => ({
|
|
70
|
+
name: p.name,
|
|
71
|
+
path: p.path,
|
|
72
|
+
priority: p.priority
|
|
73
|
+
}))
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
logger.debug(`Plugin system initialized: ${this._loadedPlugins.length} plugins loaded`);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
logger.error('Failed to initialize plugin system');
|
|
79
|
+
logger.error(error);
|
|
80
|
+
// 不抛出异常,允许 CLI 继续运行
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 将插件配置转换为路径数组
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
_convertPluginsConfigToPaths(pluginsConfig) {
|
|
89
|
+
const paths = [];
|
|
90
|
+
|
|
91
|
+
// 如果配置为空或不为对象,返回空数组
|
|
92
|
+
if (!pluginsConfig) {
|
|
93
|
+
return paths;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 如果配置是数组(旧格式),直接返回
|
|
97
|
+
if (Array.isArray(pluginsConfig)) {
|
|
98
|
+
return pluginsConfig;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 如果配置是对象(新格式),提取路径并过滤禁用的插件
|
|
102
|
+
for (const [pluginName, pluginDef] of Object.entries(pluginsConfig)) {
|
|
103
|
+
// 检查是否禁用
|
|
104
|
+
if (pluginDef.enabled === false) {
|
|
105
|
+
logger.debug(`Plugin disabled: ${pluginName}`);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 获取路径
|
|
110
|
+
if (pluginDef.path) {
|
|
111
|
+
paths.push(pluginDef.path);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return paths;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 扫描并加载内置插件(plugins/ 目录)
|
|
120
|
+
* 内置插件默认启用,除非在配置中明确禁用
|
|
121
|
+
* @private
|
|
122
|
+
*/
|
|
123
|
+
async _scanBuiltInPlugins(pluginsConfig) {
|
|
124
|
+
const builtInPaths = [];
|
|
125
|
+
const pluginsDir = path.join(__dirname, '..', 'plugins');
|
|
126
|
+
|
|
127
|
+
// 检查 plugins 目录是否存在
|
|
128
|
+
if (!fs.existsSync(pluginsDir)) {
|
|
129
|
+
return builtInPaths;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 读取 plugins 目录下的所有子目录
|
|
133
|
+
const entries = fs.readdirSync(pluginsDir, { withFileTypes: true });
|
|
134
|
+
|
|
135
|
+
for (const entry of entries) {
|
|
136
|
+
if (!entry.isDirectory()) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const pluginName = entry.name;
|
|
141
|
+
const pluginPath = path.join(pluginsDir, pluginName);
|
|
142
|
+
|
|
143
|
+
// 检查插件是否在配置中明确禁用
|
|
144
|
+
const isDisabled = pluginsConfig &&
|
|
145
|
+
pluginsConfig[pluginName] &&
|
|
146
|
+
pluginsConfig[pluginName].enabled === false;
|
|
147
|
+
|
|
148
|
+
if (isDisabled) {
|
|
149
|
+
logger.debug(`Built-in plugin disabled: ${pluginName}`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 添加到内置插件列表
|
|
154
|
+
builtInPaths.push(pluginPath);
|
|
155
|
+
logger.debug(`Built-in plugin auto-loaded: ${pluginName}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return builtInPaths;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 解析所有插件的元数据
|
|
163
|
+
* @private
|
|
164
|
+
*/ /**
|
|
165
|
+
* 解析所有插件的元数据
|
|
166
|
+
* @private
|
|
167
|
+
*/
|
|
168
|
+
async _parseAllPluginsMetadata(pluginPaths) {
|
|
169
|
+
const metadata = [];
|
|
170
|
+
|
|
171
|
+
for (const pluginPath of pluginPaths) {
|
|
172
|
+
try {
|
|
173
|
+
const meta = await this._loader.parsePluginMetadata(pluginPath);
|
|
174
|
+
meta.path = pluginPath;
|
|
175
|
+
metadata.push(meta);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
logger.warn(`Failed to parse plugin metadata: ${pluginPath}`);
|
|
178
|
+
logger.warn(error.message);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return metadata;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* 加载单个插件
|
|
187
|
+
* @private
|
|
188
|
+
*/
|
|
189
|
+
async _loadSinglePlugin(pluginInfo) {
|
|
190
|
+
const { name, path: pluginPath, priority = 0 } = pluginInfo;
|
|
191
|
+
|
|
192
|
+
// 触发 pre-plugin-load 钩子
|
|
193
|
+
const preContext = await this._hookManager.executeHooks('pre-plugin-load', {
|
|
194
|
+
pluginName: name,
|
|
195
|
+
pluginPath,
|
|
196
|
+
modifyPath: (newPath) => {
|
|
197
|
+
pluginInfo.path = newPath;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
if (preContext.prevented) {
|
|
202
|
+
logger.warn(`Plugin loading prevented: ${name} (${preContext.message})`);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
// 设置当前插件元数据
|
|
208
|
+
this._currentPluginMetadata = pluginInfo;
|
|
209
|
+
|
|
210
|
+
// 创建注册 API
|
|
211
|
+
const registerAPI = this._createRegisterAPI(name, priority);
|
|
212
|
+
|
|
213
|
+
// 加载插件
|
|
214
|
+
const loadedPlugin = await this._loader.loadPlugin(pluginInfo.path, name, registerAPI);
|
|
215
|
+
|
|
216
|
+
// 添加到已加载插件列表
|
|
217
|
+
this._loadedPlugins.push({
|
|
218
|
+
...loadedPlugin,
|
|
219
|
+
priority
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// 触发 post-plugin-load 钩子
|
|
223
|
+
await this._hookManager.executeHooks('post-plugin-load', {
|
|
224
|
+
pluginName: name
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
logger.debug(`Plugin loaded: ${name} (priority: ${priority})`);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
logger.warn(`Failed to load plugin: ${name}`);
|
|
230
|
+
logger.warn(error.message);
|
|
231
|
+
// 继续加载其他插件
|
|
232
|
+
} finally {
|
|
233
|
+
this._currentPluginMetadata = null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* 创建注册 API (ROCKCLI)
|
|
239
|
+
* @private
|
|
240
|
+
*/
|
|
241
|
+
_createRegisterAPI(pluginName, defaultPriority) {
|
|
242
|
+
return {
|
|
243
|
+
/**
|
|
244
|
+
* 注册命令
|
|
245
|
+
* @param {Object} commandDef - 命令定义
|
|
246
|
+
* @param {string} commandDef.command - 命令名称
|
|
247
|
+
* @param {string} commandDef.describe - 命令描述
|
|
248
|
+
* @param {Object} [commandDef.helpConfig] - 帮助配置(可选,用于本地化描述)
|
|
249
|
+
*/
|
|
250
|
+
registerCommand: (commandDef) => {
|
|
251
|
+
// 检查命令冲突
|
|
252
|
+
if (this._isCommandRegistered(commandDef.command)) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
`Command "${commandDef.command}" is already registered by another plugin or built-in command`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
this._registeredCommands.push({
|
|
259
|
+
...commandDef,
|
|
260
|
+
pluginName
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
logger.debug(`Command registered by plugin ${pluginName}: ${commandDef.command}`);
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* 注册钩子
|
|
268
|
+
*/
|
|
269
|
+
registerHook: (hookName, hookDef) => {
|
|
270
|
+
const priority = hookDef.priority !== undefined ? hookDef.priority : defaultPriority;
|
|
271
|
+
this._hookManager.registerHook(hookName, hookDef, priority, pluginName);
|
|
272
|
+
logger.debug(`Hook registered by plugin ${pluginName}: ${hookName} (priority: ${priority})`);
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* 获取插件配置
|
|
277
|
+
* @param {string} [key] - 配置键,不提供则返回完整配置
|
|
278
|
+
* @returns {*} 配置值或完整配置对象
|
|
279
|
+
*/
|
|
280
|
+
getConfig: (key) => {
|
|
281
|
+
const config = this._configManager.getPluginConfig(pluginName);
|
|
282
|
+
if (key !== undefined) {
|
|
283
|
+
return config[key];
|
|
284
|
+
}
|
|
285
|
+
return config;
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* 获取全局配置(带优先级合并)
|
|
290
|
+
* @param {Object} argv - 命令行参数对象
|
|
291
|
+
* @returns {Object} - 合并后的全局配置
|
|
292
|
+
*/
|
|
293
|
+
getGlobalConfig: (argv) => {
|
|
294
|
+
return this._configManager.getGlobalConfigWithPriority(argv);
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* 日志工具
|
|
299
|
+
*/
|
|
300
|
+
logger: {
|
|
301
|
+
error: (...args) => logger.error(...args),
|
|
302
|
+
warn: (...args) => logger.warn(...args),
|
|
303
|
+
info: (...args) => logger.info(...args),
|
|
304
|
+
debug: (...args) => logger.debug(...args),
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* 优雅退出函数
|
|
309
|
+
* @param {number} code - 退出码
|
|
310
|
+
*/
|
|
311
|
+
gracefulExit,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* 检查命令是否已注册
|
|
317
|
+
* @private
|
|
318
|
+
*/
|
|
319
|
+
_isCommandRegistered(command) {
|
|
320
|
+
return this._registeredCommands.some(cmd => cmd.command === command);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* 获取所有插件注册的命令
|
|
325
|
+
* @returns {Array<Object>}
|
|
326
|
+
*/
|
|
327
|
+
getRegisteredCommands() {
|
|
328
|
+
return [...this._registeredCommands];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* 获取所有已加载的插件信息
|
|
333
|
+
* @returns {Array<Object>}
|
|
334
|
+
*/
|
|
335
|
+
getLoadedPlugins() {
|
|
336
|
+
return [...this._loadedPlugins];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* 获取 HookManager 实例
|
|
341
|
+
* @returns {HookManager}
|
|
342
|
+
*/
|
|
343
|
+
getHookManager() {
|
|
344
|
+
return this._hookManager;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
module.exports = PluginManager;
|