xray-manager 1.0.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.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +798 -0
  3. package/dist/cli.d.ts +11 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +113 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/config.d.ts +49 -0
  8. package/dist/commands/config.d.ts.map +1 -0
  9. package/dist/commands/config.js +295 -0
  10. package/dist/commands/config.js.map +1 -0
  11. package/dist/commands/interactive.d.ts +83 -0
  12. package/dist/commands/interactive.d.ts.map +1 -0
  13. package/dist/commands/interactive.js +362 -0
  14. package/dist/commands/interactive.js.map +1 -0
  15. package/dist/commands/logs.d.ts +43 -0
  16. package/dist/commands/logs.d.ts.map +1 -0
  17. package/dist/commands/logs.js +257 -0
  18. package/dist/commands/logs.js.map +1 -0
  19. package/dist/commands/service.d.ts +43 -0
  20. package/dist/commands/service.d.ts.map +1 -0
  21. package/dist/commands/service.js +177 -0
  22. package/dist/commands/service.js.map +1 -0
  23. package/dist/commands/user.d.ts +43 -0
  24. package/dist/commands/user.d.ts.map +1 -0
  25. package/dist/commands/user.js +212 -0
  26. package/dist/commands/user.js.map +1 -0
  27. package/dist/constants/exit-codes.d.ts +49 -0
  28. package/dist/constants/exit-codes.d.ts.map +1 -0
  29. package/dist/constants/exit-codes.js +100 -0
  30. package/dist/constants/exit-codes.js.map +1 -0
  31. package/dist/constants/paths.d.ts +57 -0
  32. package/dist/constants/paths.d.ts.map +1 -0
  33. package/dist/constants/paths.js +72 -0
  34. package/dist/constants/paths.js.map +1 -0
  35. package/dist/constants/timeouts.d.ts +84 -0
  36. package/dist/constants/timeouts.d.ts.map +1 -0
  37. package/dist/constants/timeouts.js +111 -0
  38. package/dist/constants/timeouts.js.map +1 -0
  39. package/dist/services/config-manager.d.ts +66 -0
  40. package/dist/services/config-manager.d.ts.map +1 -0
  41. package/dist/services/config-manager.js +206 -0
  42. package/dist/services/config-manager.js.map +1 -0
  43. package/dist/services/log-manager.d.ts +113 -0
  44. package/dist/services/log-manager.d.ts.map +1 -0
  45. package/dist/services/log-manager.js +288 -0
  46. package/dist/services/log-manager.js.map +1 -0
  47. package/dist/services/systemd-manager.d.ts +197 -0
  48. package/dist/services/systemd-manager.d.ts.map +1 -0
  49. package/dist/services/systemd-manager.js +458 -0
  50. package/dist/services/systemd-manager.js.map +1 -0
  51. package/dist/services/user-manager.d.ts +63 -0
  52. package/dist/services/user-manager.d.ts.map +1 -0
  53. package/dist/services/user-manager.js +219 -0
  54. package/dist/services/user-manager.js.map +1 -0
  55. package/dist/types/config.d.ts +256 -0
  56. package/dist/types/config.d.ts.map +1 -0
  57. package/dist/types/config.js +7 -0
  58. package/dist/types/config.js.map +1 -0
  59. package/dist/types/service.d.ts +96 -0
  60. package/dist/types/service.d.ts.map +1 -0
  61. package/dist/types/service.js +7 -0
  62. package/dist/types/service.js.map +1 -0
  63. package/dist/types/user.d.ts +114 -0
  64. package/dist/types/user.d.ts.map +1 -0
  65. package/dist/types/user.js +7 -0
  66. package/dist/types/user.js.map +1 -0
  67. package/dist/utils/clipboard.d.ts +21 -0
  68. package/dist/utils/clipboard.d.ts.map +1 -0
  69. package/dist/utils/clipboard.js +45 -0
  70. package/dist/utils/clipboard.js.map +1 -0
  71. package/dist/utils/format.d.ts +93 -0
  72. package/dist/utils/format.d.ts.map +1 -0
  73. package/dist/utils/format.js +242 -0
  74. package/dist/utils/format.js.map +1 -0
  75. package/dist/utils/logger.d.ts +113 -0
  76. package/dist/utils/logger.d.ts.map +1 -0
  77. package/dist/utils/logger.js +260 -0
  78. package/dist/utils/logger.js.map +1 -0
  79. package/dist/utils/preflight.d.ts +57 -0
  80. package/dist/utils/preflight.d.ts.map +1 -0
  81. package/dist/utils/preflight.js +215 -0
  82. package/dist/utils/preflight.js.map +1 -0
  83. package/dist/utils/validator.d.ts +102 -0
  84. package/dist/utils/validator.d.ts.map +1 -0
  85. package/dist/utils/validator.js +238 -0
  86. package/dist/utils/validator.js.map +1 -0
  87. package/dist/utils/which.d.ts +13 -0
  88. package/dist/utils/which.d.ts.map +1 -0
  89. package/dist/utils/which.js +28 -0
  90. package/dist/utils/which.js.map +1 -0
  91. package/package.json +69 -0
@@ -0,0 +1,362 @@
1
+ "use strict";
2
+ /**
3
+ * Interactive Menu Implementation
4
+ *
5
+ * Provides the main interactive menu system for the CLI tool
6
+ *
7
+ * @module commands/interactive
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.MenuStack = void 0;
14
+ exports.getMenuContext = getMenuContext;
15
+ exports.formatMenuHeader = formatMenuHeader;
16
+ exports.getMainMenuOptions = getMainMenuOptions;
17
+ exports.getMenuDepth = getMenuDepth;
18
+ exports.formatMenuOption = formatMenuOption;
19
+ exports.showMenu = showMenu;
20
+ exports.handleMenuSelection = handleMenuSelection;
21
+ exports.handleSigInt = handleSigInt;
22
+ exports.startInteractiveMenu = startInteractiveMenu;
23
+ const prompts_1 = require("@inquirer/prompts");
24
+ const chalk_1 = __importDefault(require("chalk"));
25
+ const logger_1 = __importDefault(require("../utils/logger"));
26
+ const exit_codes_1 = require("../constants/exit-codes");
27
+ const systemd_manager_1 = require("../services/systemd-manager");
28
+ const user_manager_1 = require("../services/user-manager");
29
+ const service_1 = require("./service");
30
+ const user_1 = require("./user");
31
+ /**
32
+ * Menu stack for navigation
33
+ */
34
+ class MenuStack {
35
+ constructor() {
36
+ this.stack = [];
37
+ }
38
+ push(menu) {
39
+ this.stack.push(menu);
40
+ }
41
+ pop() {
42
+ if (this.stack.length === 0) {
43
+ throw new Error('Cannot pop from empty menu stack');
44
+ }
45
+ return this.stack.pop();
46
+ }
47
+ current() {
48
+ return this.stack[this.stack.length - 1];
49
+ }
50
+ depth() {
51
+ return this.stack.length;
52
+ }
53
+ canGoBack() {
54
+ return this.stack.length > 0;
55
+ }
56
+ clear() {
57
+ this.stack = [];
58
+ }
59
+ }
60
+ exports.MenuStack = MenuStack;
61
+ // Global menu stack instance
62
+ const menuStack = new MenuStack();
63
+ /**
64
+ * Get menu context (service status, user count)
65
+ */
66
+ async function getMenuContext(options = {}) {
67
+ const serviceName = options.serviceName || 'xray';
68
+ try {
69
+ const systemdManager = new systemd_manager_1.SystemdManager(serviceName);
70
+ const userManager = new user_manager_1.UserManager(options.configPath, serviceName);
71
+ const [status, users] = await Promise.all([
72
+ systemdManager.getStatus(),
73
+ userManager.listUsers(),
74
+ ]);
75
+ return {
76
+ serviceStatus: status.healthy ? 'active' : status.active ? status.subState : 'inactive',
77
+ userCount: users.length,
78
+ lastUpdated: new Date(),
79
+ };
80
+ }
81
+ catch (error) {
82
+ // If service status fails, return unknown
83
+ return {
84
+ serviceStatus: 'unknown',
85
+ userCount: 0,
86
+ lastUpdated: new Date(),
87
+ };
88
+ }
89
+ }
90
+ /**
91
+ * Format menu header with context
92
+ */
93
+ function formatMenuHeader(context) {
94
+ const status = context.serviceStatus || 'unknown';
95
+ const userCount = context.userCount || 0;
96
+ const statusColor = status === 'active' ? chalk_1.default.green : status === 'inactive' ? chalk_1.default.red : chalk_1.default.yellow;
97
+ return `${chalk_1.default.gray('服务状态:')} ${statusColor(status)} ${chalk_1.default.gray('用户数:')} ${chalk_1.default.cyan(String(userCount))}`;
98
+ }
99
+ /**
100
+ * Get main menu options
101
+ */
102
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
103
+ function getMainMenuOptions() {
104
+ return [
105
+ {
106
+ name: chalk_1.default.cyan('📊 查看服务状态'),
107
+ value: 'service-status',
108
+ },
109
+ {
110
+ name: chalk_1.default.green('🚀 启动服务'),
111
+ value: 'service-start',
112
+ },
113
+ {
114
+ name: chalk_1.default.red('🛑 停止服务'),
115
+ value: 'service-stop',
116
+ },
117
+ {
118
+ name: chalk_1.default.yellow('🔄 重启服务'),
119
+ value: 'service-restart',
120
+ },
121
+ { type: 'separator' },
122
+ {
123
+ name: chalk_1.default.blue('👥 用户管理'),
124
+ value: 'user',
125
+ },
126
+ {
127
+ name: chalk_1.default.magenta('⚙️ 配置管理'),
128
+ value: 'config',
129
+ },
130
+ {
131
+ name: chalk_1.default.gray('📝 查看日志'),
132
+ value: 'logs',
133
+ },
134
+ { type: 'separator' },
135
+ {
136
+ name: chalk_1.default.red('❌ 退出'),
137
+ value: 'exit',
138
+ },
139
+ ];
140
+ }
141
+ /**
142
+ * Get menu depth (for Constitution compliance - max 3 levels)
143
+ */
144
+ function getMenuDepth() {
145
+ // Main menu (1) -> Submenu (2) -> Action (3)
146
+ return 3;
147
+ }
148
+ /**
149
+ * Format a menu option
150
+ */
151
+ function formatMenuOption(name, value) {
152
+ // Add icon based on value type
153
+ let icon = '•';
154
+ if (value.includes('service'))
155
+ icon = '⚙️';
156
+ else if (value.includes('user'))
157
+ icon = '👤';
158
+ else if (value.includes('config'))
159
+ icon = '🔧';
160
+ else if (value.includes('log'))
161
+ icon = '📄';
162
+ return {
163
+ name: `${icon} ${name}`,
164
+ value,
165
+ };
166
+ }
167
+ /**
168
+ * Show a menu and get user selection
169
+ */
170
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
171
+ async function showMenu(options, message = '请选择操作:') {
172
+ const answer = await (0, prompts_1.select)({
173
+ message,
174
+ choices: options,
175
+ });
176
+ return answer;
177
+ }
178
+ /**
179
+ * Handle menu selection
180
+ */
181
+ async function handleMenuSelection(selection, options) {
182
+ switch (selection) {
183
+ case 'exit':
184
+ return true; // Signal to exit
185
+ case 'service-status':
186
+ logger_1.default.newline();
187
+ await (0, service_1.displayServiceStatus)(options);
188
+ await promptContinue();
189
+ return false;
190
+ case 'service-start':
191
+ logger_1.default.newline();
192
+ await (0, service_1.startService)(options);
193
+ await promptContinue();
194
+ return false;
195
+ case 'service-stop':
196
+ logger_1.default.newline();
197
+ const confirmStop = await (0, prompts_1.confirm)({
198
+ message: chalk_1.default.yellow('⚠️ 确定要停止服务吗?这将中断所有连接。'),
199
+ default: false,
200
+ });
201
+ if (confirmStop) {
202
+ await (0, service_1.stopService)(options);
203
+ }
204
+ else {
205
+ logger_1.default.info('已取消停止操作');
206
+ }
207
+ await promptContinue();
208
+ return false;
209
+ case 'service-restart':
210
+ logger_1.default.newline();
211
+ const confirmRestart = await (0, prompts_1.confirm)({
212
+ message: chalk_1.default.yellow('⚠️ 确定要重启服务吗?'),
213
+ default: true,
214
+ });
215
+ if (confirmRestart) {
216
+ await (0, service_1.restartService)(options);
217
+ }
218
+ else {
219
+ logger_1.default.info('已取消重启操作');
220
+ }
221
+ await promptContinue();
222
+ return false;
223
+ case 'user':
224
+ // Show user management submenu
225
+ return await handleUserManagementMenu(options);
226
+ case 'config':
227
+ logger_1.default.info('配置管理功能即将推出...');
228
+ await promptContinue();
229
+ return false;
230
+ case 'logs':
231
+ logger_1.default.info('日志查看功能即将推出...');
232
+ await promptContinue();
233
+ return false;
234
+ default:
235
+ logger_1.default.warn(`未知选项: ${selection}`);
236
+ return false;
237
+ }
238
+ }
239
+ /**
240
+ * Handle user management submenu
241
+ */
242
+ async function handleUserManagementMenu(options) {
243
+ while (true) {
244
+ logger_1.default.newline();
245
+ logger_1.default.separator();
246
+ console.log(chalk_1.default.bold.cyan('👥 用户管理'));
247
+ logger_1.default.separator();
248
+ logger_1.default.newline();
249
+ const userMenuOptions = [
250
+ { name: chalk_1.default.cyan('📋 查看用户列表'), value: 'user-list' },
251
+ { name: chalk_1.default.green('➕ 添加用户'), value: 'user-add' },
252
+ { name: chalk_1.default.red('➖ 删除用户'), value: 'user-delete' },
253
+ { name: chalk_1.default.blue('📤 显示分享链接'), value: 'user-share' },
254
+ { type: 'separator' },
255
+ { name: chalk_1.default.gray('⬅️ 返回主菜单'), value: 'back' },
256
+ ];
257
+ const selection = await showMenu(userMenuOptions, chalk_1.default.bold('请选择操作:'));
258
+ switch (selection) {
259
+ case 'back':
260
+ return false; // Return to main menu
261
+ case 'user-list':
262
+ logger_1.default.newline();
263
+ await (0, user_1.listUsers)(options);
264
+ await promptContinue();
265
+ break;
266
+ case 'user-add':
267
+ logger_1.default.newline();
268
+ await (0, user_1.addUser)(options);
269
+ await promptContinue();
270
+ break;
271
+ case 'user-delete':
272
+ logger_1.default.newline();
273
+ await (0, user_1.deleteUser)(options);
274
+ await promptContinue();
275
+ break;
276
+ case 'user-share':
277
+ logger_1.default.newline();
278
+ await (0, user_1.showUserShare)(options);
279
+ await promptContinue();
280
+ break;
281
+ default:
282
+ logger_1.default.warn(`未知选项: ${selection}`);
283
+ break;
284
+ }
285
+ }
286
+ }
287
+ /**
288
+ * Prompt user to continue
289
+ */
290
+ async function promptContinue() {
291
+ await (0, prompts_1.confirm)({
292
+ message: '按 Enter 继续...',
293
+ default: true,
294
+ });
295
+ }
296
+ /**
297
+ * Handle SIGINT (Ctrl+C)
298
+ */
299
+ async function handleSigInt() {
300
+ logger_1.default.newline();
301
+ const shouldExit = await (0, prompts_1.confirm)({
302
+ message: chalk_1.default.yellow('⚠️ 确定要退出吗?'),
303
+ default: false,
304
+ });
305
+ return shouldExit;
306
+ }
307
+ /**
308
+ * Main interactive menu loop
309
+ */
310
+ async function startInteractiveMenu(options) {
311
+ logger_1.default.title('Xray Manager - 交互式管理工具');
312
+ // Setup SIGINT handler
313
+ let sigintHandled = false;
314
+ const sigintHandler = async () => {
315
+ if (sigintHandled)
316
+ return;
317
+ sigintHandled = true;
318
+ const shouldExit = await handleSigInt();
319
+ if (shouldExit) {
320
+ logger_1.default.info('👋 再见!');
321
+ process.exit(exit_codes_1.ExitCode.SUCCESS);
322
+ }
323
+ else {
324
+ sigintHandled = false;
325
+ // Continue with menu
326
+ }
327
+ };
328
+ process.on('SIGINT', sigintHandler);
329
+ try {
330
+ // Get menu context
331
+ const context = await getMenuContext(options);
332
+ // Main menu loop
333
+ let shouldExit = false;
334
+ while (!shouldExit) {
335
+ logger_1.default.newline();
336
+ logger_1.default.separator();
337
+ // Display context
338
+ const header = formatMenuHeader(context);
339
+ console.log(header);
340
+ logger_1.default.separator();
341
+ logger_1.default.newline();
342
+ // Get menu options
343
+ const menuOptions = getMainMenuOptions();
344
+ // Show menu and get selection
345
+ const selection = await showMenu(menuOptions, chalk_1.default.bold('请选择操作:'));
346
+ // Handle selection
347
+ shouldExit = await handleMenuSelection(selection, options);
348
+ // Update context after each action
349
+ if (!shouldExit) {
350
+ const updatedContext = await getMenuContext(options);
351
+ Object.assign(context, updatedContext);
352
+ }
353
+ }
354
+ logger_1.default.success('感谢使用 Xray Manager!');
355
+ }
356
+ finally {
357
+ // Cleanup
358
+ process.removeListener('SIGINT', sigintHandler);
359
+ menuStack.clear();
360
+ }
361
+ }
362
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/commands/interactive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Logs Command Handler
3
+ *
4
+ * Handles log viewing commands (view, follow, filter)
5
+ *
6
+ * @module commands/logs
7
+ */
8
+ /**
9
+ * Logs command options
10
+ */
11
+ export interface LogsCommandOptions {
12
+ /** Service name */
13
+ serviceName?: string;
14
+ /** JSON output mode */
15
+ json?: boolean;
16
+ /** Log level filter */
17
+ level?: string;
18
+ /** Time range start */
19
+ since?: string;
20
+ /** Number of lines */
21
+ lines?: number;
22
+ /** Follow mode */
23
+ follow?: boolean;
24
+ }
25
+ /**
26
+ * View recent logs
27
+ *
28
+ * @param options - Command options
29
+ */
30
+ export declare function viewLogs(options?: LogsCommandOptions): Promise<void>;
31
+ /**
32
+ * Follow logs in real-time
33
+ *
34
+ * @param options - Command options
35
+ */
36
+ export declare function followLogs(options?: LogsCommandOptions): Promise<void>;
37
+ /**
38
+ * Interactive log filtering
39
+ *
40
+ * @param options - Command options
41
+ */
42
+ export declare function filterLogs(options?: LogsCommandOptions): Promise<void>;
43
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,uBAAuB;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,uBAAuB;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,uBAAuB;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,kBAAkB;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA+ED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD9E;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDhF;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiEhF"}
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ /**
3
+ * Logs Command Handler
4
+ *
5
+ * Handles log viewing commands (view, follow, filter)
6
+ *
7
+ * @module commands/logs
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.viewLogs = viewLogs;
14
+ exports.followLogs = followLogs;
15
+ exports.filterLogs = filterLogs;
16
+ const log_manager_1 = require("../services/log-manager");
17
+ const logger_1 = __importDefault(require("../utils/logger"));
18
+ const chalk_1 = __importDefault(require("chalk"));
19
+ const prompts_1 = require("@inquirer/prompts");
20
+ /**
21
+ * Get color for log level
22
+ *
23
+ * @param level - Log level
24
+ * @returns Chalk color function
25
+ */
26
+ function getColorForLevel(level) {
27
+ switch (level.toLowerCase()) {
28
+ case 'emergency':
29
+ case 'alert':
30
+ case 'critical':
31
+ case 'error':
32
+ return chalk_1.default.red;
33
+ case 'warning':
34
+ return chalk_1.default.yellow;
35
+ case 'notice':
36
+ return chalk_1.default.cyan;
37
+ case 'info':
38
+ return chalk_1.default.white;
39
+ case 'debug':
40
+ return chalk_1.default.gray;
41
+ default:
42
+ return chalk_1.default.white;
43
+ }
44
+ }
45
+ /**
46
+ * Get emoji for log level
47
+ *
48
+ * @param level - Log level
49
+ * @returns Emoji string
50
+ */
51
+ function getEmojiForLevel(level) {
52
+ switch (level.toLowerCase()) {
53
+ case 'emergency':
54
+ case 'alert':
55
+ return '🚨';
56
+ case 'critical':
57
+ case 'error':
58
+ return '❌';
59
+ case 'warning':
60
+ return '⚠️';
61
+ case 'notice':
62
+ return '📢';
63
+ case 'info':
64
+ return 'ℹ️';
65
+ case 'debug':
66
+ return '🐛';
67
+ default:
68
+ return '📄';
69
+ }
70
+ }
71
+ /**
72
+ * Format log entry for display
73
+ *
74
+ * @param entry - Log entry
75
+ * @returns Formatted string
76
+ */
77
+ function formatLogEntry(entry) {
78
+ const colorFn = getColorForLevel(entry.level);
79
+ const emoji = getEmojiForLevel(entry.level);
80
+ const timestamp = entry.timestamp.toLocaleString('zh-CN', {
81
+ year: 'numeric',
82
+ month: '2-digit',
83
+ day: '2-digit',
84
+ hour: '2-digit',
85
+ minute: '2-digit',
86
+ second: '2-digit',
87
+ });
88
+ const level = entry.level.toUpperCase().padEnd(9);
89
+ return `${chalk_1.default.gray(timestamp)} ${emoji} ${colorFn(level)} ${entry.message}`;
90
+ }
91
+ /**
92
+ * View recent logs
93
+ *
94
+ * @param options - Command options
95
+ */
96
+ async function viewLogs(options = {}) {
97
+ try {
98
+ const serviceName = options.serviceName || 'xray';
99
+ const manager = new log_manager_1.LogManager(serviceName);
100
+ // Check journalctl availability
101
+ if (!manager.isJournalctlAvailable()) {
102
+ logger_1.default.error('journalctl 不可用。请确保系统使用 systemd。');
103
+ process.exit(1);
104
+ }
105
+ // Query logs
106
+ const logs = await manager.queryLogs({
107
+ level: options.level,
108
+ since: options.since,
109
+ lines: options.lines || 50,
110
+ });
111
+ if (options.json) {
112
+ console.log(JSON.stringify(logs, null, 2));
113
+ return;
114
+ }
115
+ logger_1.default.newline();
116
+ logger_1.default.separator();
117
+ console.log(chalk_1.default.bold.cyan(`📝 服务日志 (${serviceName})`));
118
+ if (options.level) {
119
+ console.log(chalk_1.default.gray(` 过滤器: 级别 ≥ ${options.level}`));
120
+ }
121
+ if (options.since) {
122
+ console.log(chalk_1.default.gray(` 时间范围: ${options.since} 至今`));
123
+ }
124
+ console.log(chalk_1.default.gray(` 显示: 最近 ${logs.length} 条`));
125
+ logger_1.default.separator();
126
+ logger_1.default.newline();
127
+ if (logs.length === 0) {
128
+ console.log(chalk_1.default.gray(' 没有找到日志'));
129
+ logger_1.default.newline();
130
+ return;
131
+ }
132
+ // Display logs
133
+ for (const log of logs) {
134
+ console.log(formatLogEntry(log));
135
+ }
136
+ logger_1.default.newline();
137
+ }
138
+ catch (error) {
139
+ logger_1.default.error(error.message);
140
+ process.exit(1);
141
+ }
142
+ }
143
+ /**
144
+ * Follow logs in real-time
145
+ *
146
+ * @param options - Command options
147
+ */
148
+ async function followLogs(options = {}) {
149
+ try {
150
+ const serviceName = options.serviceName || 'xray';
151
+ const manager = new log_manager_1.LogManager(serviceName);
152
+ // Check journalctl availability
153
+ if (!manager.isJournalctlAvailable()) {
154
+ logger_1.default.error('journalctl 不可用。请确保系统使用 systemd。');
155
+ process.exit(1);
156
+ }
157
+ logger_1.default.newline();
158
+ logger_1.default.separator();
159
+ console.log(chalk_1.default.bold.cyan(`📝 实时日志 (${serviceName})`));
160
+ if (options.level) {
161
+ console.log(chalk_1.default.gray(` 过滤器: 级别 ≥ ${options.level}`));
162
+ }
163
+ console.log(chalk_1.default.gray(' 按 Ctrl+C 停止'));
164
+ logger_1.default.separator();
165
+ logger_1.default.newline();
166
+ // Follow logs
167
+ const followProcess = await manager.followLogs({
168
+ level: options.level,
169
+ lines: options.lines || 10,
170
+ }, (entry) => {
171
+ console.log(formatLogEntry(entry));
172
+ });
173
+ // Handle Ctrl+C
174
+ const sigintHandler = () => {
175
+ logger_1.default.newline();
176
+ logger_1.default.info('停止日志跟踪...');
177
+ followProcess.kill();
178
+ process.exit(0);
179
+ };
180
+ process.on('SIGINT', sigintHandler);
181
+ // Wait for process to exit
182
+ await new Promise((resolve) => {
183
+ followProcess.process.on('close', resolve);
184
+ });
185
+ process.removeListener('SIGINT', sigintHandler);
186
+ }
187
+ catch (error) {
188
+ logger_1.default.error(error.message);
189
+ process.exit(1);
190
+ }
191
+ }
192
+ /**
193
+ * Interactive log filtering
194
+ *
195
+ * @param options - Command options
196
+ */
197
+ async function filterLogs(options = {}) {
198
+ try {
199
+ logger_1.default.newline();
200
+ console.log(chalk_1.default.bold('🔍 日志过滤'));
201
+ logger_1.default.newline();
202
+ // Select log level
203
+ const levelChoice = await (0, prompts_1.select)({
204
+ message: '选择日志级别:',
205
+ choices: [
206
+ { name: '🚨 Emergency (紧急)', value: 'emergency' },
207
+ { name: '🔴 Alert (警报)', value: 'alert' },
208
+ { name: '❗ Critical (严重)', value: 'critical' },
209
+ { name: '❌ Error (错误)', value: 'error' },
210
+ { name: '⚠️ Warning (警告)', value: 'warning' },
211
+ { name: '📢 Notice (通知)', value: 'notice' },
212
+ { name: 'ℹ️ Info (信息)', value: 'info' },
213
+ { name: '🐛 Debug (调试)', value: 'debug' },
214
+ { name: chalk_1.default.gray('不过滤'), value: 'none' },
215
+ ],
216
+ });
217
+ // Select time range
218
+ const timeChoice = await (0, prompts_1.select)({
219
+ message: '选择时间范围:',
220
+ choices: [
221
+ { name: '最近 1 小时', value: '1 hour ago' },
222
+ { name: '最近 3 小时', value: '3 hours ago' },
223
+ { name: '最近 6 小时', value: '6 hours ago' },
224
+ { name: '最近 12 小时', value: '12 hours ago' },
225
+ { name: '今天', value: 'today' },
226
+ { name: '昨天', value: 'yesterday' },
227
+ { name: '最近 7 天', value: '7 days ago' },
228
+ { name: chalk_1.default.gray('自定义'), value: 'custom' },
229
+ { name: chalk_1.default.gray('不限制'), value: 'none' },
230
+ ],
231
+ });
232
+ let since = timeChoice === 'none' ? undefined : timeChoice;
233
+ if (timeChoice === 'custom') {
234
+ since = await (0, prompts_1.input)({
235
+ message: '请输入时间范围 (例如: "2024-01-01", "1 week ago"):',
236
+ });
237
+ }
238
+ // Select number of lines
239
+ const linesStr = await (0, prompts_1.input)({
240
+ message: '显示多少条日志? (默认 50):',
241
+ default: '50',
242
+ });
243
+ const lines = parseInt(linesStr, 10);
244
+ // Query logs
245
+ await viewLogs({
246
+ ...options,
247
+ level: levelChoice === 'none' ? undefined : levelChoice,
248
+ since,
249
+ lines,
250
+ });
251
+ }
252
+ catch (error) {
253
+ logger_1.default.error(error.message);
254
+ process.exit(1);
255
+ }
256
+ }
257
+ //# sourceMappingURL=logs.js.map