xray-manager 1.8.5 → 2.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/README.md +129 -42
- package/dist/cli.mjs +8598 -0
- package/dist/cli.mjs.map +7 -0
- package/package.json +13 -5
- package/dist/cli.d.ts +0 -11
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -134
- package/dist/cli.js.map +0 -1
- package/dist/commands/clash.d.ts +0 -20
- package/dist/commands/clash.d.ts.map +0 -1
- package/dist/commands/clash.js +0 -156
- package/dist/commands/clash.js.map +0 -1
- package/dist/commands/config.d.ts +0 -56
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js +0 -461
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/interactive.d.ts +0 -55
- package/dist/commands/interactive.d.ts.map +0 -1
- package/dist/commands/interactive.js +0 -418
- package/dist/commands/interactive.js.map +0 -1
- package/dist/commands/logs.d.ts +0 -62
- package/dist/commands/logs.d.ts.map +0 -1
- package/dist/commands/logs.js +0 -389
- package/dist/commands/logs.js.map +0 -1
- package/dist/commands/quota.d.ts +0 -54
- package/dist/commands/quota.d.ts.map +0 -1
- package/dist/commands/quota.js +0 -661
- package/dist/commands/quota.js.map +0 -1
- package/dist/commands/review.d.ts +0 -8
- package/dist/commands/review.d.ts.map +0 -1
- package/dist/commands/review.js +0 -79
- package/dist/commands/review.js.map +0 -1
- package/dist/commands/service.d.ts +0 -43
- package/dist/commands/service.d.ts.map +0 -1
- package/dist/commands/service.js +0 -202
- package/dist/commands/service.js.map +0 -1
- package/dist/commands/user.d.ts +0 -49
- package/dist/commands/user.d.ts.map +0 -1
- package/dist/commands/user.js +0 -371
- package/dist/commands/user.js.map +0 -1
- package/dist/components/dashboard-widget.d.ts +0 -21
- package/dist/components/dashboard-widget.d.ts.map +0 -1
- package/dist/components/dashboard-widget.js +0 -234
- package/dist/components/dashboard-widget.js.map +0 -1
- package/dist/components/progress-bar.d.ts +0 -67
- package/dist/components/progress-bar.d.ts.map +0 -1
- package/dist/components/progress-bar.js +0 -138
- package/dist/components/progress-bar.js.map +0 -1
- package/dist/components/user-table.d.ts +0 -8
- package/dist/components/user-table.d.ts.map +0 -1
- package/dist/components/user-table.js +0 -91
- package/dist/components/user-table.js.map +0 -1
- package/dist/config/i18n.d.ts +0 -136
- package/dist/config/i18n.d.ts.map +0 -1
- package/dist/config/i18n.js +0 -323
- package/dist/config/i18n.js.map +0 -1
- package/dist/constants/error-codes.d.ts +0 -344
- package/dist/constants/error-codes.d.ts.map +0 -1
- package/dist/constants/error-codes.js +0 -462
- package/dist/constants/error-codes.js.map +0 -1
- package/dist/constants/exit-codes.d.ts +0 -49
- package/dist/constants/exit-codes.d.ts.map +0 -1
- package/dist/constants/exit-codes.js +0 -100
- package/dist/constants/exit-codes.js.map +0 -1
- package/dist/constants/paths.d.ts +0 -63
- package/dist/constants/paths.d.ts.map +0 -1
- package/dist/constants/paths.js +0 -78
- package/dist/constants/paths.js.map +0 -1
- package/dist/constants/quota.d.ts +0 -126
- package/dist/constants/quota.d.ts.map +0 -1
- package/dist/constants/quota.js +0 -135
- package/dist/constants/quota.js.map +0 -1
- package/dist/constants/review.d.ts +0 -14
- package/dist/constants/review.d.ts.map +0 -1
- package/dist/constants/review.js +0 -33
- package/dist/constants/review.js.map +0 -1
- package/dist/constants/supported-distros.d.ts +0 -17
- package/dist/constants/supported-distros.d.ts.map +0 -1
- package/dist/constants/supported-distros.js +0 -68
- package/dist/constants/supported-distros.js.map +0 -1
- package/dist/constants/theme.d.ts +0 -34
- package/dist/constants/theme.d.ts.map +0 -1
- package/dist/constants/theme.js +0 -52
- package/dist/constants/theme.js.map +0 -1
- package/dist/constants/timeouts.d.ts +0 -84
- package/dist/constants/timeouts.d.ts.map +0 -1
- package/dist/constants/timeouts.js +0 -111
- package/dist/constants/timeouts.js.map +0 -1
- package/dist/constants/ui-symbols.d.ts +0 -47
- package/dist/constants/ui-symbols.d.ts.map +0 -1
- package/dist/constants/ui-symbols.js +0 -48
- package/dist/constants/ui-symbols.js.map +0 -1
- package/dist/services/clash-config.d.ts +0 -16
- package/dist/services/clash-config.d.ts.map +0 -1
- package/dist/services/clash-config.js +0 -107
- package/dist/services/clash-config.js.map +0 -1
- package/dist/services/config-manager.d.ts +0 -90
- package/dist/services/config-manager.d.ts.map +0 -1
- package/dist/services/config-manager.js +0 -307
- package/dist/services/config-manager.js.map +0 -1
- package/dist/services/layout-manager.d.ts +0 -94
- package/dist/services/layout-manager.d.ts.map +0 -1
- package/dist/services/layout-manager.js +0 -192
- package/dist/services/layout-manager.js.map +0 -1
- package/dist/services/log-manager.d.ts +0 -157
- package/dist/services/log-manager.d.ts.map +0 -1
- package/dist/services/log-manager.js +0 -397
- package/dist/services/log-manager.js.map +0 -1
- package/dist/services/navigation-manager.d.ts +0 -23
- package/dist/services/navigation-manager.d.ts.map +0 -1
- package/dist/services/navigation-manager.js +0 -39
- package/dist/services/navigation-manager.js.map +0 -1
- package/dist/services/platform-detector.d.ts +0 -10
- package/dist/services/platform-detector.d.ts.map +0 -1
- package/dist/services/platform-detector.js +0 -106
- package/dist/services/platform-detector.js.map +0 -1
- package/dist/services/public-ip-manager.d.ts +0 -78
- package/dist/services/public-ip-manager.d.ts.map +0 -1
- package/dist/services/public-ip-manager.js +0 -296
- package/dist/services/public-ip-manager.js.map +0 -1
- package/dist/services/quota-enforcer.d.ts +0 -86
- package/dist/services/quota-enforcer.d.ts.map +0 -1
- package/dist/services/quota-enforcer.js +0 -151
- package/dist/services/quota-enforcer.js.map +0 -1
- package/dist/services/quota-manager.d.ts +0 -101
- package/dist/services/quota-manager.d.ts.map +0 -1
- package/dist/services/quota-manager.js +0 -257
- package/dist/services/quota-manager.js.map +0 -1
- package/dist/services/review/areas/community.d.ts +0 -9
- package/dist/services/review/areas/community.d.ts.map +0 -1
- package/dist/services/review/areas/community.js +0 -59
- package/dist/services/review/areas/community.js.map +0 -1
- package/dist/services/review/areas/contribution.d.ts +0 -9
- package/dist/services/review/areas/contribution.d.ts.map +0 -1
- package/dist/services/review/areas/contribution.js +0 -107
- package/dist/services/review/areas/contribution.js.map +0 -1
- package/dist/services/review/areas/documentation.d.ts +0 -9
- package/dist/services/review/areas/documentation.d.ts.map +0 -1
- package/dist/services/review/areas/documentation.js +0 -110
- package/dist/services/review/areas/documentation.js.map +0 -1
- package/dist/services/review/areas/license.d.ts +0 -9
- package/dist/services/review/areas/license.d.ts.map +0 -1
- package/dist/services/review/areas/license.js +0 -86
- package/dist/services/review/areas/license.js.map +0 -1
- package/dist/services/review/areas/quality.d.ts +0 -9
- package/dist/services/review/areas/quality.d.ts.map +0 -1
- package/dist/services/review/areas/quality.js +0 -84
- package/dist/services/review/areas/quality.js.map +0 -1
- package/dist/services/review/areas/security.d.ts +0 -9
- package/dist/services/review/areas/security.d.ts.map +0 -1
- package/dist/services/review/areas/security.js +0 -64
- package/dist/services/review/areas/security.js.map +0 -1
- package/dist/services/review/evidence.d.ts +0 -10
- package/dist/services/review/evidence.d.ts.map +0 -1
- package/dist/services/review/evidence.js +0 -40
- package/dist/services/review/evidence.js.map +0 -1
- package/dist/services/review/recommendations-filter.d.ts +0 -12
- package/dist/services/review/recommendations-filter.d.ts.map +0 -1
- package/dist/services/review/recommendations-filter.js +0 -20
- package/dist/services/review/recommendations-filter.js.map +0 -1
- package/dist/services/review/repo-scanner.d.ts +0 -8
- package/dist/services/review/repo-scanner.d.ts.map +0 -1
- package/dist/services/review/repo-scanner.js +0 -15
- package/dist/services/review/repo-scanner.js.map +0 -1
- package/dist/services/review/report-renderer.d.ts +0 -15
- package/dist/services/review/report-renderer.d.ts.map +0 -1
- package/dist/services/review/report-renderer.js +0 -120
- package/dist/services/review/report-renderer.js.map +0 -1
- package/dist/services/review/review-engine.d.ts +0 -15
- package/dist/services/review/review-engine.d.ts.map +0 -1
- package/dist/services/review/review-engine.js +0 -61
- package/dist/services/review/review-engine.js.map +0 -1
- package/dist/services/review/summary-builder.d.ts +0 -8
- package/dist/services/review/summary-builder.d.ts.map +0 -1
- package/dist/services/review/summary-builder.js +0 -26
- package/dist/services/review/summary-builder.js.map +0 -1
- package/dist/services/screen-manager.d.ts +0 -13
- package/dist/services/screen-manager.d.ts.map +0 -1
- package/dist/services/screen-manager.js +0 -42
- package/dist/services/screen-manager.js.map +0 -1
- package/dist/services/stats-config-manager.d.ts +0 -110
- package/dist/services/stats-config-manager.d.ts.map +0 -1
- package/dist/services/stats-config-manager.js +0 -443
- package/dist/services/stats-config-manager.js.map +0 -1
- package/dist/services/systemd-manager.d.ts +0 -197
- package/dist/services/systemd-manager.d.ts.map +0 -1
- package/dist/services/systemd-manager.js +0 -458
- package/dist/services/systemd-manager.js.map +0 -1
- package/dist/services/traffic-manager.d.ts +0 -106
- package/dist/services/traffic-manager.d.ts.map +0 -1
- package/dist/services/traffic-manager.js +0 -368
- package/dist/services/traffic-manager.js.map +0 -1
- package/dist/services/user-manager.d.ts +0 -90
- package/dist/services/user-manager.d.ts.map +0 -1
- package/dist/services/user-manager.js +0 -347
- package/dist/services/user-manager.js.map +0 -1
- package/dist/services/user-metadata-manager.d.ts +0 -85
- package/dist/services/user-metadata-manager.d.ts.map +0 -1
- package/dist/services/user-metadata-manager.js +0 -181
- package/dist/services/user-metadata-manager.js.map +0 -1
- package/dist/types/config.d.ts +0 -340
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/config.js +0 -7
- package/dist/types/config.js.map +0 -1
- package/dist/types/layout.d.ts +0 -119
- package/dist/types/layout.d.ts.map +0 -1
- package/dist/types/layout.js +0 -142
- package/dist/types/layout.js.map +0 -1
- package/dist/types/platform.d.ts +0 -72
- package/dist/types/platform.d.ts.map +0 -1
- package/dist/types/platform.js +0 -38
- package/dist/types/platform.js.map +0 -1
- package/dist/types/quota.d.ts +0 -158
- package/dist/types/quota.d.ts.map +0 -1
- package/dist/types/quota.js +0 -26
- package/dist/types/quota.js.map +0 -1
- package/dist/types/review.d.ts +0 -62
- package/dist/types/review.d.ts.map +0 -1
- package/dist/types/review.js +0 -8
- package/dist/types/review.js.map +0 -1
- package/dist/types/server-config.d.ts +0 -53
- package/dist/types/server-config.d.ts.map +0 -1
- package/dist/types/server-config.js +0 -19
- package/dist/types/server-config.js.map +0 -1
- package/dist/types/service.d.ts +0 -96
- package/dist/types/service.d.ts.map +0 -1
- package/dist/types/service.js +0 -7
- package/dist/types/service.js.map +0 -1
- package/dist/types/terminal.d.ts +0 -35
- package/dist/types/terminal.d.ts.map +0 -1
- package/dist/types/terminal.js +0 -20
- package/dist/types/terminal.js.map +0 -1
- package/dist/types/ui-components.d.ts +0 -53
- package/dist/types/ui-components.d.ts.map +0 -1
- package/dist/types/ui-components.js +0 -3
- package/dist/types/ui-components.js.map +0 -1
- package/dist/types/user-metadata.d.ts +0 -43
- package/dist/types/user-metadata.d.ts.map +0 -1
- package/dist/types/user-metadata.js +0 -17
- package/dist/types/user-metadata.js.map +0 -1
- package/dist/types/user.d.ts +0 -134
- package/dist/types/user.d.ts.map +0 -1
- package/dist/types/user.js +0 -7
- package/dist/types/user.js.map +0 -1
- package/dist/utils/clipboard.d.ts +0 -21
- package/dist/utils/clipboard.d.ts.map +0 -1
- package/dist/utils/clipboard.js +0 -45
- package/dist/utils/clipboard.js.map +0 -1
- package/dist/utils/error-formatter.d.ts +0 -60
- package/dist/utils/error-formatter.d.ts.map +0 -1
- package/dist/utils/error-formatter.js +0 -244
- package/dist/utils/error-formatter.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -92
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js +0 -143
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/firewall.d.ts +0 -14
- package/dist/utils/firewall.d.ts.map +0 -1
- package/dist/utils/firewall.js +0 -78
- package/dist/utils/firewall.js.map +0 -1
- package/dist/utils/format.d.ts +0 -93
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/format.js +0 -240
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/icons.d.ts +0 -53
- package/dist/utils/icons.d.ts.map +0 -1
- package/dist/utils/icons.js +0 -143
- package/dist/utils/icons.js.map +0 -1
- package/dist/utils/layout.d.ts +0 -142
- package/dist/utils/layout.d.ts.map +0 -1
- package/dist/utils/layout.js +0 -381
- package/dist/utils/layout.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -160
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -351
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/network.d.ts +0 -39
- package/dist/utils/network.d.ts.map +0 -1
- package/dist/utils/network.js +0 -227
- package/dist/utils/network.js.map +0 -1
- package/dist/utils/os-detection.d.ts +0 -10
- package/dist/utils/os-detection.d.ts.map +0 -1
- package/dist/utils/os-detection.js +0 -86
- package/dist/utils/os-detection.js.map +0 -1
- package/dist/utils/preflight.d.ts +0 -57
- package/dist/utils/preflight.d.ts.map +0 -1
- package/dist/utils/preflight.js +0 -215
- package/dist/utils/preflight.js.map +0 -1
- package/dist/utils/repo-scan.d.ts +0 -54
- package/dist/utils/repo-scan.d.ts.map +0 -1
- package/dist/utils/repo-scan.js +0 -165
- package/dist/utils/repo-scan.js.map +0 -1
- package/dist/utils/report-output.d.ts +0 -13
- package/dist/utils/report-output.d.ts.map +0 -1
- package/dist/utils/report-output.js +0 -33
- package/dist/utils/report-output.js.map +0 -1
- package/dist/utils/review-id.d.ts +0 -8
- package/dist/utils/review-id.d.ts.map +0 -1
- package/dist/utils/review-id.js +0 -17
- package/dist/utils/review-id.js.map +0 -1
- package/dist/utils/splash.d.ts +0 -21
- package/dist/utils/splash.d.ts.map +0 -1
- package/dist/utils/splash.js +0 -179
- package/dist/utils/splash.js.map +0 -1
- package/dist/utils/terminal.d.ts +0 -32
- package/dist/utils/terminal.d.ts.map +0 -1
- package/dist/utils/terminal.js +0 -93
- package/dist/utils/terminal.js.map +0 -1
- package/dist/utils/traffic-formatter.d.ts +0 -45
- package/dist/utils/traffic-formatter.d.ts.map +0 -1
- package/dist/utils/traffic-formatter.js +0 -131
- package/dist/utils/traffic-formatter.js.map +0 -1
- package/dist/utils/validator.d.ts +0 -102
- package/dist/utils/validator.d.ts.map +0 -1
- package/dist/utils/validator.js +0 -238
- package/dist/utils/validator.js.map +0 -1
- package/dist/utils/vless-link.d.ts +0 -27
- package/dist/utils/vless-link.d.ts.map +0 -1
- package/dist/utils/vless-link.js +0 -69
- package/dist/utils/vless-link.js.map +0 -1
- package/dist/utils/which.d.ts +0 -13
- package/dist/utils/which.d.ts.map +0 -1
- package/dist/utils/which.js +0 -28
- package/dist/utils/which.js.map +0 -1
package/dist/cli.mjs.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/constants/timeouts.ts", "../src/services/systemd-manager.ts", "../src/cli.ts", "../src/utils/logger.ts", "../src/utils/terminal.ts", "../src/constants/ui-symbols.ts", "../src/utils/icons.ts", "../src/utils/error-formatter.ts", "../src/utils/errors.ts", "../src/constants/error-codes.ts", "../src/constants/exit-codes.ts", "../src/utils/preflight.ts", "../src/constants/paths.ts", "../src/constants/review.ts", "../src/utils/review-id.ts", "../src/services/review/repo-scanner.ts", "../src/utils/repo-scan.ts", "../src/services/review/summary-builder.ts", "../src/services/review/evidence.ts", "../src/services/review/areas/community.ts", "../src/services/review/areas/contribution.ts", "../src/services/review/areas/documentation.ts", "../src/services/review/areas/license.ts", "../src/services/review/areas/quality.ts", "../src/services/review/areas/security.ts", "../src/services/review/review-engine.ts", "../src/services/review/report-renderer.ts", "../src/utils/report-output.ts", "../src/commands/review.ts", "../src/commands/clash.ts", "../src/utils/validator.ts", "../src/utils/vless-link.ts", "../src/services/clash-config.ts", "../src/components/design-system/ThemeProvider.tsx", "../src/components/design-system/theme.ts", "../src/contexts/I18nContext.tsx", "../src/config/i18n.ts", "../src/contexts/ServiceContext.tsx", "../src/services/config-manager.ts", "../src/services/user-manager.ts", "../src/services/public-ip-manager.ts", "../src/constants/supported-distros.ts", "../src/utils/network.ts", "../src/services/user-metadata-manager.ts", "../src/services/quota-manager.ts", "../src/types/quota.ts", "../src/constants/quota.ts", "../src/services/traffic-manager.ts", "../src/services/log-manager.ts", "../src/utils/which.ts", "../src/services/stats-config-manager.ts", "../src/contexts/NavigationContext.tsx", "../src/app/routes.ts", "../src/contexts/NotificationContext.tsx", "../src/app/AppShell.tsx", "../src/components/design-system/Header.tsx", "../src/components/design-system/StatusBar.tsx", "../src/components/design-system/Divider.tsx", "../src/components/Breadcrumb.tsx", "../src/components/Dashboard.tsx", "../src/utils/format.ts", "../src/components/Toast.tsx", "../src/components/CommandPalette.tsx", "../src/screens/MainMenu.tsx", "../src/components/Select.tsx", "../src/components/Spinner.tsx", "../src/components/Confirm.tsx", "../src/screens/ServiceStatus.tsx", "../src/hooks/useServiceStatus.ts", "../src/components/StatusBadge.tsx", "../src/components/KeyValue.tsx", "../src/screens/UserManagement.tsx", "../src/hooks/useUsers.ts", "../src/components/Table.tsx", "../src/screens/UserAdd.tsx", "../src/components/TextInput.tsx", "../src/screens/UserDelete.tsx", "../src/screens/UserShare.tsx", "../src/screens/QuotaManagement.tsx", "../src/hooks/useQuotas.ts", "../src/components/ProgressBar.tsx", "../src/screens/QuotaSet.tsx", "../src/screens/QuotaDetails.tsx", "../src/screens/ConfigManagement.tsx", "../src/screens/LogViewer.tsx", "../src/screens/OnlineUsers.tsx", "../src/hooks/useOnlineUsers.ts", "../src/services/online-manager.ts", "../src/screens/SubscriptionManagement.tsx", "../src/services/subscription-server.ts", "../src/app/Router.tsx", "../src/hooks/useDashboardData.ts", "../src/services/system-monitor.ts", "../src/app/App.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * \u8D85\u65F6\u65F6\u95F4\u5E38\u91CF\u5B9A\u4E49\n * @module constants/timeouts\n */\n\n/**\n * \u8D85\u65F6\u914D\u7F6E\uFF08\u5355\u4F4D\uFF1A\u6BEB\u79D2\uFF09\n */\nexport const TIMEOUTS = {\n /** systemctl \u547D\u4EE4\u9ED8\u8BA4\u8D85\u65F6 */\n SYSTEMCTL_DEFAULT: 30000, // 30 \u79D2\n\n /** \u670D\u52A1\u542F\u52A8\u8D85\u65F6 */\n SERVICE_START: 15000, // 15 \u79D2\n\n /** \u670D\u52A1\u505C\u6B62\u8D85\u65F6\uFF08\u4F18\u96C5\u5173\u95ED\uFF09 */\n SERVICE_STOP: 10000, // 10 \u79D2\n\n /** \u670D\u52A1\u91CD\u542F\u8D85\u65F6 */\n SERVICE_RESTART: 25000, // 25 \u79D2\n\n /** \u670D\u52A1\u72B6\u6001\u67E5\u8BE2\u8D85\u65F6 */\n SERVICE_STATUS: 5000, // 5 \u79D2\n\n /** \u914D\u7F6E\u6587\u4EF6\u8BFB\u5199\u8D85\u65F6 */\n CONFIG_IO: 5000, // 5 \u79D2\n\n /** \u914D\u7F6E\u5907\u4EFD\u64CD\u4F5C\u8D85\u65F6 */\n CONFIG_BACKUP: 10000, // 10 \u79D2\n\n /** \u65E5\u5FD7\u67E5\u8BE2\u8D85\u65F6 */\n LOG_QUERY: 10000, // 10 \u79D2\n\n /** \u7F51\u7EDC\u64CD\u4F5C\u8D85\u65F6\uFF08\u4E0B\u8F7D\u3001\u68C0\u67E5\u66F4\u65B0\uFF09 */\n NETWORK: 30000, // 30 \u79D2\n\n /** \u7528\u6237\u8F93\u5165\u8D85\u65F6\uFF08\u4EA4\u4E92\u5F0F\u83DC\u5355\uFF09 */\n USER_INPUT: 60000, // 60 \u79D2\n\n /** \u6587\u4EF6\u7CFB\u7EDF\u64CD\u4F5C\u8D85\u65F6 */\n FILESYSTEM: 10000, // 10 \u79D2\n\n /** \u4F18\u96C5\u5173\u95ED\u7B49\u5F85\u65F6\u95F4 */\n GRACEFUL_SHUTDOWN: 10000, // 10 \u79D2\n\n /** \u8FDB\u7A0B\u6740\u6B7B\u524D\u7B49\u5F85\u65F6\u95F4 */\n KILL_WAIT: 2000, // 2 \u79D2\n\n /** \u83DC\u5355\u5237\u65B0\u95F4\u9694 */\n MENU_REFRESH: 1000, // 1 \u79D2\n\n /** \u72B6\u6001\u8F6E\u8BE2\u95F4\u9694 */\n STATUS_POLL: 500, // 500 \u6BEB\u79D2\n} as const;\n\n/**\n * \u6027\u80FD\u8981\u6C42\uFF08\u7528\u4E8E\u76D1\u63A7\u548C\u6D4B\u8BD5\uFF09\n */\nexport const PERFORMANCE_TARGETS = {\n /** \u83DC\u5355\u542F\u52A8\u65F6\u95F4\u76EE\u6807 */\n MENU_STARTUP: 500, // 500ms (SC-003)\n\n /** \u83DC\u5355\u5BFC\u822A\u54CD\u5E94\u65F6\u95F4\u76EE\u6807 */\n MENU_NAVIGATION: 100, // 100ms (SC-002)\n\n /** \u6309\u952E\u54CD\u5E94\u65F6\u95F4\u76EE\u6807 */\n KEY_RESPONSE: 50, // 50ms (SC-002)\n\n /** \u670D\u52A1\u91CD\u542F\u4E2D\u65AD\u65F6\u95F4\u76EE\u6807 */\n SERVICE_DOWNTIME: 10000, // 10s (FR-016)\n} as const;\n\n/**\n * \u91CD\u8BD5\u914D\u7F6E\n */\nexport const RETRY_CONFIG = {\n /** \u9ED8\u8BA4\u91CD\u8BD5\u6B21\u6570 */\n DEFAULT_ATTEMPTS: 3,\n\n /** \u91CD\u8BD5\u95F4\u9694\uFF08\u6BEB\u79D2\uFF09 */\n RETRY_DELAY: 1000, // 1 \u79D2\n\n /** \u6307\u6570\u9000\u907F\u57FA\u6570 */\n BACKOFF_MULTIPLIER: 2,\n\n /** \u6700\u5927\u91CD\u8BD5\u95F4\u9694 */\n MAX_RETRY_DELAY: 10000, // 10 \u79D2\n} as const;\n\n/**\n * \u8BA1\u7B97\u6307\u6570\u9000\u907F\u5EF6\u8FDF\n * @param attempt \u5F53\u524D\u5C1D\u8BD5\u6B21\u6570\uFF08\u4ECE 0 \u5F00\u59CB\uFF09\n * @returns \u5EF6\u8FDF\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\n */\nexport function getBackoffDelay(attempt: number): number {\n const delay = RETRY_CONFIG.RETRY_DELAY * Math.pow(RETRY_CONFIG.BACKOFF_MULTIPLIER, attempt);\n return Math.min(delay, RETRY_CONFIG.MAX_RETRY_DELAY);\n}\n\n/**\n * \u7761\u7720\u51FD\u6570\uFF08\u7528\u4E8E\u5EF6\u8FDF\uFF09\n * @param ms \u6BEB\u79D2\u6570\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * \u5E26\u8D85\u65F6\u7684 Promise\n * @param promise \u539F\u59CB Promise\n * @param timeoutMs \u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\n * @param errorMessage \u8D85\u65F6\u9519\u8BEF\u6D88\u606F\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage = '\u64CD\u4F5C\u8D85\u65F6'\n): Promise<T> {\n let timeoutId: NodeJS.Timeout;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(`${errorMessage} (${timeoutMs}ms)`));\n }, timeoutMs);\n });\n\n try {\n const result = await Promise.race([promise, timeoutPromise]);\n clearTimeout(timeoutId!);\n return result;\n } catch (error) {\n clearTimeout(timeoutId!);\n throw error;\n }\n}\n", "/**\n * SystemdManager - Service Management via systemctl\n *\n * Provides safe interface to systemd service management with:\n * - Command injection prevention\n * - Action and service name validation\n * - Graceful shutdown with configurable timeout\n * - Detailed status parsing\n *\n * @module services/systemd-manager\n */\n\nimport { spawn } from 'child_process';\nimport { TIMEOUTS } from '../constants/timeouts';\n\n/**\n * Service status information\n */\nexport interface ServiceStatus {\n /** Service name */\n serviceName: string;\n\n /** Whether service is active */\n active: boolean;\n\n /** Active state (active, inactive, failed, etc.) */\n activeState: string;\n\n /** Sub state (running, dead, failed, etc.) */\n subState: string;\n\n /** Whether service is loaded */\n loaded: boolean;\n\n /** Whether service is healthy */\n healthy: boolean;\n\n /** Main process PID (null if not running) */\n pid: number | null;\n\n /** Memory usage (formatted string) */\n memory?: string;\n\n /** Number of restarts */\n restarts?: number;\n\n /** Uptime (formatted string) */\n uptime?: string;\n\n /** Start timestamp */\n startTime?: Date;\n}\n\n/**\n * Service operation result\n */\nexport interface ServiceOperationResult {\n /** Whether operation succeeded */\n success: boolean;\n\n /** Operation type */\n operation: string;\n\n /** Service name */\n serviceName: string;\n\n /** Exit code */\n exitCode: number;\n\n /** Duration in milliseconds */\n duration: number;\n\n /** Downtime in milliseconds (for restart) */\n downtime?: number;\n\n /** Standard output */\n stdout?: string;\n\n /** Standard error */\n stderr?: string;\n}\n\n/**\n * Systemctl execution options\n */\nexport interface SystemctlOptions {\n /** Timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * Restart options\n */\nexport interface RestartOptions {\n /** Graceful shutdown timeout in milliseconds */\n gracefulTimeout?: number;\n\n /** Whether to wait for active connections to complete */\n waitForConnections?: boolean;\n}\n\n/**\n * SystemdManager - Safe systemctl wrapper\n */\nexport class SystemdManager {\n private serviceName: string;\n\n /** Valid systemctl actions (whitelist) */\n private static readonly VALID_ACTIONS = [\n 'start',\n 'stop',\n 'restart',\n 'status',\n 'enable',\n 'disable',\n 'is-active',\n 'is-enabled',\n 'show',\n ];\n\n /**\n * Create a new SystemdManager\n *\n * @param serviceName - Service name to manage\n * @throws Error if service name is invalid\n */\n constructor(serviceName: string) {\n this.validateServiceName(serviceName);\n this.serviceName = serviceName;\n }\n\n /**\n * Validate service name\n *\n * @param name - Service name to validate\n * @throws Error if service name is invalid\n */\n private validateServiceName(name: string): void {\n // Prevent empty names\n if (!name || name.trim().length === 0) {\n throw new Error('Service name cannot be empty');\n }\n\n // Prevent path traversal attempts\n if (name.includes('/') || name.includes('\\\\') || name.includes('..')) {\n throw new Error(`Invalid service name: ${name} (path traversal detected)`);\n }\n\n // Prevent command injection attempts\n const dangerousChars = /[;&|`$()]/;\n if (dangerousChars.test(name)) {\n throw new Error(`Invalid service name: ${name} (potentially dangerous characters detected)`);\n }\n\n // Only allow alphanumeric, dash, underscore\n const validPattern = /^[a-zA-Z0-9_-]+$/;\n if (!validPattern.test(name)) {\n throw new Error(\n `Invalid service name: ${name} (only alphanumeric, dash, and underscore allowed)`\n );\n }\n }\n\n /**\n * Validate systemctl action\n *\n * @param action - Action to validate\n * @throws Error if action is invalid\n */\n validateAction(action: string): void {\n if (!SystemdManager.VALID_ACTIONS.includes(action)) {\n throw new Error(\n `Invalid systemctl action: ${action} (must be one of: ${SystemdManager.VALID_ACTIONS.join(', ')})`\n );\n }\n\n // Extra paranoia: check for command injection attempts\n const dangerousChars = /[;&|`$()]/;\n if (dangerousChars.test(action)) {\n throw new Error(\n `Invalid systemctl action: ${action} (potentially dangerous characters detected)`\n );\n }\n }\n\n /**\n * Execute systemctl command\n *\n * @param action - Systemctl action to execute\n * @param options - Execution options\n * @returns Command output\n */\n async executeSystemctl(action: string, options?: SystemctlOptions): Promise<string> {\n // Validate action to prevent command injection\n this.validateAction(action);\n\n const timeout = options?.timeout || TIMEOUTS.SYSTEMCTL_DEFAULT;\n\n return new Promise((resolve, reject) => {\n // Use spawn (not exec) to prevent shell injection\n const child = spawn('systemctl', [action, this.serviceName], {\n timeout,\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data) => {\n stderr += data.toString();\n });\n\n child.on('close', (code) => {\n if (code === 0) {\n resolve(stdout);\n } else {\n const errorMessage = this.parseSystemdError(stderr || stdout, action);\n reject(new Error(errorMessage));\n }\n });\n\n child.on('error', (error) => {\n reject(new Error(`Failed to execute systemctl: ${error.message}`));\n });\n });\n }\n\n /**\n * Parse systemd error messages and provide suggestions\n *\n * @param errorOutput - Error output from systemctl\n * @param action - Action that was attempted\n * @returns User-friendly error message with suggestions\n */\n private parseSystemdError(errorOutput: string, action: string): string {\n const lowerError = errorOutput.toLowerCase();\n\n // Service not found\n if (\n lowerError.includes('not found') ||\n lowerError.includes('does not exist') ||\n lowerError.includes('could not be found')\n ) {\n return `\u670D\u52A1 '${this.serviceName}' \u4E0D\u5B58\u5728\u3002\u8BF7\u786E\u8BA4\u670D\u52A1\u540D\u79F0\u662F\u5426\u6B63\u786E\u3002`;\n }\n\n // Permission denied\n if (\n lowerError.includes('permission denied') ||\n lowerError.includes('access denied') ||\n lowerError.includes('authentication required')\n ) {\n return `\u6743\u9650\u4E0D\u8DB3: \u65E0\u6CD5\u6267\u884C ${action} \u64CD\u4F5C\u3002\u8BF7\u4F7F\u7528 sudo \u6216\u4EE5 root \u7528\u6237\u8FD0\u884C\u3002`;\n }\n\n // Timeout\n if (lowerError.includes('timeout') || lowerError.includes('timed out')) {\n return `\u64CD\u4F5C\u8D85\u65F6: ${action} \u64CD\u4F5C\u672A\u80FD\u5728\u89C4\u5B9A\u65F6\u95F4\u5185\u5B8C\u6210\u3002`;\n }\n\n // Already running/stopped\n if (\n action === 'start' &&\n (lowerError.includes('already running') || lowerError.includes('already active'))\n ) {\n return `\u670D\u52A1 '${this.serviceName}' \u5DF2\u7ECF\u5728\u8FD0\u884C\u4E2D\u3002`;\n }\n\n if (\n action === 'stop' &&\n (lowerError.includes('already stopped') || lowerError.includes('inactive'))\n ) {\n return `\u670D\u52A1 '${this.serviceName}' \u5DF2\u7ECF\u505C\u6B62\u3002`;\n }\n\n // Generic error with original output\n return `\u6267\u884C systemctl ${action} \u5931\u8D25: ${errorOutput}`;\n }\n\n /**\n * Parse systemctl show output\n *\n * @param output - Raw output from systemctl show\n * @returns Parsed service status\n */\n parseSystemdShow(output: string): ServiceStatus {\n const lines = output.split('\\n');\n const props: Record<string, string> = {};\n\n // Parse key=value pairs\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || !trimmed.includes('=')) {\n continue;\n }\n\n const [key, ...valueParts] = trimmed.split('=');\n const value = valueParts.join('='); // Handle values with '=' in them\n props[key] = value;\n }\n\n // Validate we have at least basic properties\n if (!props.ActiveState && !props.SubState) {\n throw new Error('Invalid systemctl show output: missing required fields (parse error)');\n }\n\n // Parse active state\n const activeState = props.ActiveState || 'unknown';\n const subState = props.SubState || 'unknown';\n const active = activeState === 'active';\n\n // Parse loaded state\n const loaded = props.LoadState === 'loaded';\n\n // Parse PID\n const pidStr = props.MainPID || '0';\n const pid = parseInt(pidStr, 10);\n const pidValue = pid > 0 ? pid : null;\n\n // Parse memory usage\n const memoryBytes = parseInt(props.MemoryCurrent || '0', 10);\n const memory = this.formatBytes(memoryBytes);\n\n // Parse restart count\n const restarts = parseInt(props.NRestarts || '0', 10);\n\n // Parse start time and calculate uptime\n const startTimestamp = props.ExecMainStartTimestamp;\n let uptime: string | undefined;\n let startTime: Date | undefined;\n\n if (startTimestamp && startTimestamp.trim() !== '') {\n try {\n startTime = new Date(startTimestamp);\n const now = Date.now();\n const startMs = startTime.getTime();\n const uptimeMs = now - startMs;\n uptime = this.formatUptime(uptimeMs);\n } catch {\n // Ignore parse errors\n }\n }\n\n // Determine health\n const healthy = active && subState === 'running';\n\n return {\n serviceName: this.serviceName,\n active,\n activeState,\n subState,\n loaded,\n healthy,\n pid: pidValue,\n memory,\n restarts,\n uptime,\n startTime,\n };\n }\n\n /**\n * Format bytes to human-readable string\n *\n * @param bytes - Number of bytes\n * @returns Formatted string (e.g., \"45.2 MB\")\n */\n private formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n\n const units = ['B', 'KB', 'MB', 'GB'];\n const k = 1024;\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n const value = bytes / Math.pow(k, i);\n\n return `${value.toFixed(1)} ${units[i]}`;\n }\n\n /**\n * Format uptime in milliseconds to human-readable string\n *\n * @param ms - Uptime in milliseconds\n * @returns Formatted string (e.g., \"2\u5C0F\u65F615\u5206\u949F\")\n */\n private formatUptime(ms: number): string {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days}\u5929${hours % 24}\u5C0F\u65F6`;\n } else if (hours > 0) {\n return `${hours}\u5C0F\u65F6${minutes % 60}\u5206\u949F`;\n } else if (minutes > 0) {\n return `${minutes}\u5206\u949F`;\n } else {\n return `${seconds}\u79D2`;\n }\n }\n\n /**\n * Get service status\n *\n * @returns Service status information\n */\n async getStatus(): Promise<ServiceStatus> {\n const output = await this.executeSystemctl('show');\n return this.parseSystemdShow(output);\n }\n\n /**\n * Start service\n *\n * @returns Operation result\n */\n async start(): Promise<ServiceOperationResult> {\n const startTime = Date.now();\n\n try {\n const stdout = await this.executeSystemctl('start', {\n timeout: TIMEOUTS.SERVICE_START,\n });\n\n const duration = Date.now() - startTime;\n\n return {\n success: true,\n operation: 'start',\n serviceName: this.serviceName,\n exitCode: 0,\n duration,\n stdout,\n };\n } catch (error) {\n const duration = Date.now() - startTime;\n\n return {\n success: false,\n operation: 'start',\n serviceName: this.serviceName,\n exitCode: 1,\n duration,\n stderr: (error as Error).message,\n };\n }\n }\n\n /**\n * Stop service\n *\n * @returns Operation result\n */\n async stop(): Promise<ServiceOperationResult> {\n const startTime = Date.now();\n\n try {\n const stdout = await this.executeSystemctl('stop', {\n timeout: TIMEOUTS.SERVICE_STOP,\n });\n\n const duration = Date.now() - startTime;\n\n return {\n success: true,\n operation: 'stop',\n serviceName: this.serviceName,\n exitCode: 0,\n duration,\n stdout,\n };\n } catch (error) {\n const duration = Date.now() - startTime;\n\n return {\n success: false,\n operation: 'stop',\n serviceName: this.serviceName,\n exitCode: 1,\n duration,\n stderr: (error as Error).message,\n };\n }\n }\n\n /**\n * Restart service with graceful shutdown\n *\n * @param options - Restart options\n * @returns Operation result\n */\n async restart(options?: RestartOptions): Promise<ServiceOperationResult> {\n const gracefulTimeout = options?.gracefulTimeout || 10000; // Default 10s (FR-016)\n const restartStartTime = Date.now();\n\n try {\n // Measure service downtime\n const downtimeStart = Date.now();\n\n // Use systemctl restart which handles graceful shutdown internally\n const stdout = await this.executeSystemctl('restart', {\n timeout: TIMEOUTS.SERVICE_RESTART,\n });\n\n // Wait a moment for service to fully start\n await this.waitForServiceReady(gracefulTimeout);\n\n const downtimeEnd = Date.now();\n const downtime = downtimeEnd - downtimeStart;\n const duration = Date.now() - restartStartTime;\n\n return {\n success: true,\n operation: 'restart',\n serviceName: this.serviceName,\n exitCode: 0,\n duration,\n downtime,\n stdout,\n };\n } catch (error) {\n const duration = Date.now() - restartStartTime;\n\n return {\n success: false,\n operation: 'restart',\n serviceName: this.serviceName,\n exitCode: 1,\n duration,\n stderr: (error as Error).message,\n };\n }\n }\n\n /**\n * Wait for service to be ready after start/restart\n *\n * @param maxWait - Maximum time to wait in milliseconds\n */\n private async waitForServiceReady(maxWait: number): Promise<void> {\n const startTime = Date.now();\n const pollInterval = 100; // Check every 100ms\n\n while (Date.now() - startTime < maxWait) {\n try {\n const status = await this.getStatus();\n if (status.active && status.subState === 'running') {\n return; // Service is ready\n }\n } catch {\n // Ignore errors during polling\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n // If we get here, service didn't become ready in time\n // But don't throw - let caller determine if this is critical\n }\n\n /**\n * Check if running as root\n *\n * @returns True if running as root\n */\n isRoot(): boolean {\n return !!(process.getuid && process.getuid() === 0);\n }\n\n /**\n * Check if sudo is available\n *\n * @returns True if sudo is available\n */\n async canUseSudo(): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn('which', ['sudo']);\n\n child.on('close', (code) => {\n resolve(code === 0);\n });\n\n child.on('error', () => {\n resolve(false);\n });\n });\n }\n\n /**\n * Get permission warning message\n *\n * @returns Warning message if not running with sufficient permissions\n */\n getPermissionWarning(): string | undefined {\n if (this.isRoot()) {\n return undefined;\n }\n\n return 'Not running as root - some operations may require sudo';\n }\n\n /**\n * Estimate downtime for restart operation\n *\n * @returns Estimated downtime in milliseconds\n */\n estimateDowntime(): number {\n // Estimate based on typical graceful shutdown time\n // Conservative estimate: 5 seconds\n return 5000;\n }\n}\n", "/**\n * Xray Manager CLI Entry Point\n *\n * Renders the React+Ink based terminal UI.\n *\n * @module cli\n */\n\nimport { Command } from 'commander';\nimport updateNotifier from 'update-notifier';\nimport React from 'react';\nimport { render } from 'ink';\nimport logger from './utils/logger.js';\nimport { ExitCode, gracefulExit } from './constants/exit-codes.js';\nimport { preflightChecks } from './utils/preflight.js';\nimport { registerReviewCommand } from './commands/review.js';\nimport { registerClashCommand } from './commands/clash.js';\nimport { App } from './app/App.js';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\n// Read package.json for version\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));\n\n/**\n * Main CLI function\n */\nasync function main(): Promise<void> {\n // Check for updates\n const notifier = updateNotifier({\n pkg: packageJson,\n updateCheckInterval: 1000 * 60 * 60 * 24, // Daily\n });\n\n if (notifier.update) {\n notifier.notify({ isGlobal: true, defer: false });\n }\n\n // Create Commander program\n const program = new Command();\n\n program\n .name('xray-manager')\n .description('Xray VPN Service Manager')\n .version(packageJson.version, '-v, --version', 'Show version')\n .helpOption('-h, --help', 'Show help');\n\n // Global options\n program\n .option('--config <path>', 'Specify config file path')\n .option('--service <name>', 'Specify service name', 'xray')\n .option('--json', 'JSON output mode')\n .option('--no-color', 'Disable colored output')\n .option('--verbose', 'Verbose output mode');\n\n registerReviewCommand(program);\n registerClashCommand(program);\n\n // Default action: start interactive Ink UI\n program.action(async () => {\n const options = program.opts();\n\n if (options.noColor) {\n logger.configure({ color: false });\n }\n\n try {\n // Perform preflight checks\n const preflightResult = await preflightChecks({\n checkSystemd: true,\n checkXray: false,\n checkConfig: false,\n });\n\n if (!preflightResult.passed && preflightResult.critical) {\n logger.error('Preflight check failed');\n preflightResult.errors.forEach((error) => logger.error(` \\u2022 ${error}`));\n\n if (preflightResult.suggestions.length > 0) {\n logger.hint('Suggestions:');\n preflightResult.suggestions.forEach((s) => logger.info(` \\u2022 ${s}`));\n }\n\n await gracefulExit(ExitCode.SERVICE_ERROR);\n }\n\n if (preflightResult.warnings.length > 0) {\n preflightResult.warnings.forEach((w) => logger.warn(w));\n }\n\n // Render the Ink app\n const { waitUntilExit } = render(\n React.createElement(App, {\n options: {\n configPath: options.config,\n serviceName: options.service,\n },\n version: packageJson.version,\n })\n );\n\n await waitUntilExit();\n await gracefulExit(ExitCode.SUCCESS);\n } catch (error) {\n logger.error('Error starting application:');\n logger.error((error as Error).message);\n\n if (options.verbose && error instanceof Error) {\n logger.error(error.stack || 'No stack trace');\n }\n\n await gracefulExit(ExitCode.GENERAL_ERROR);\n }\n });\n\n // Parse and execute\n await program.parseAsync(process.argv);\n}\n\n// Handle uncaught errors\nprocess.on('uncaughtException', async (error) => {\n logger.error(`Uncaught exception: ${error.message}`);\n await gracefulExit(ExitCode.GENERAL_ERROR);\n});\n\nprocess.on('unhandledRejection', async (reason) => {\n logger.error(`Unhandled rejection: ${String(reason)}`);\n await gracefulExit(ExitCode.GENERAL_ERROR);\n});\n\n// Run\nmain().catch(async (error) => {\n logger.error(`Fatal: ${error.message}`);\n await gracefulExit(ExitCode.GENERAL_ERROR);\n});\n", "/**\n * \u65E5\u5FD7\u5DE5\u5177\u51FD\u6570\uFF08\u4F7F\u7528 chalk \u989C\u8272\u548C\u901A\u7528\u6587\u672C\u6307\u793A\u7B26\uFF09\n * @module utils/logger\n */\n\nimport chalk from 'chalk';\nimport { detectTerminalCapabilities } from './terminal';\nimport { resolveIcon, resolveSpecialIcon, getStatusIndicator } from './icons';\nimport { AppError } from './errors';\nimport { ErrorInfo } from '../constants/error-codes';\nimport {\n formatAppError,\n formatErrorInfo,\n formatError as formatErrorUtil,\n type FormatOptions,\n} from './error-formatter';\n\n/**\n * \u65E5\u5FD7\u7EA7\u522B\n */\n/* eslint-disable no-unused-vars */\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n SUCCESS = 'success',\n WARN = 'warn',\n ERROR = 'error',\n}\n/* eslint-enable no-unused-vars */\n\n/**\n * \u8F93\u51FA\u6A21\u5F0F\n */\n/* eslint-disable no-unused-vars */\nexport enum OutputMode {\n /** \u5B8C\u6574\u6A21\u5F0F\uFF1A\u989C\u8272 + \u683C\u5F0F\u5316 */\n RICH = 'rich',\n /** \u6734\u7D20\u6A21\u5F0F\uFF1A\u65E0\u989C\u8272 + \u683C\u5F0F\u5316 */\n PLAIN_TTY = 'plain_tty',\n /** \u7BA1\u9053\u6A21\u5F0F\uFF1A\u7EAF\u6587\u672C + \u65F6\u95F4\u6233 */\n PIPE = 'pipe',\n}\n/* eslint-enable no-unused-vars */\n\n/**\n * \u65E5\u5FD7\u9009\u9879\n */\nexport interface LogOptions {\n /** \u662F\u5426\u542F\u7528\u989C\u8272\uFF08\u9ED8\u8BA4 true\uFF09 */\n color?: boolean;\n\n /** \u662F\u5426\u663E\u793A\u65F6\u95F4\u6233\uFF08\u9ED8\u8BA4 false\uFF09 */\n timestamp?: boolean;\n\n /** \u65E5\u5FD7\u7EA7\u522B\uFF08\u7528\u4E8E\u8FC7\u6EE4\uFF09 */\n level?: LogLevel;\n}\n\n/**\n * \u5168\u5C40\u65E5\u5FD7\u914D\u7F6E\n */\nlet globalOptions: LogOptions = {\n color: true,\n timestamp: false,\n level: LogLevel.INFO,\n};\n\n/**\n * \u7F13\u5B58\u7684\u7EC8\u7AEF\u80FD\u529B\n */\nlet cachedCapabilities = detectTerminalCapabilities();\n\n/**\n * \u914D\u7F6E\u5168\u5C40\u65E5\u5FD7\u9009\u9879\n */\nexport function configureLogger(options: LogOptions): void {\n globalOptions = { ...globalOptions, ...options };\n}\n\n/**\n * \u83B7\u53D6\u5F53\u524D\u8F93\u51FA\u6A21\u5F0F\n * @returns \u8F93\u51FA\u6A21\u5F0F\uFF08RICH, PLAIN_TTY, \u6216 PIPE\uFF09\n */\nexport function getOutputMode(): OutputMode {\n const isTTY = cachedCapabilities.isTTY;\n const colorEnabled = globalOptions.color !== false;\n\n if (!isTTY) {\n return OutputMode.PIPE;\n }\n\n if (!colorEnabled) {\n return OutputMode.PLAIN_TTY;\n }\n\n return OutputMode.RICH;\n}\n\n/**\n * \u83B7\u53D6\u65F6\u95F4\u6233\u5B57\u7B26\u4E32\n */\nfunction getTimestamp(): string {\n const now = new Date();\n const hours = String(now.getHours()).padStart(2, '0');\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const seconds = String(now.getSeconds()).padStart(2, '0');\n return `[${hours}:${minutes}:${seconds}]`;\n}\n\n/**\n * \u683C\u5F0F\u5316\u65E5\u5FD7\u6D88\u606F\uFF08\u4F7F\u7528\u65B0\u7684\u8F93\u51FA\u6A21\u5F0F\u68C0\u6D4B\uFF09\n * @param level - \u65E5\u5FD7\u7EA7\u522B\n * @param message - \u6D88\u606F\u5185\u5BB9\n * @param includeIndicator - \u662F\u5426\u5305\u542B\u72B6\u6001\u6307\u793A\u7B26\uFF08\u9ED8\u8BA4 true\uFF09\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u6D88\u606F\n */\nfunction formatMessage(level: LogLevel, message: string, includeIndicator: boolean = true): string {\n const mode = getOutputMode();\n const indicator = includeIndicator ? resolveIcon(level, cachedCapabilities) : '';\n\n switch (mode) {\n case OutputMode.PIPE:\n // \u7BA1\u9053\u6A21\u5F0F\uFF1A[timestamp] [LEVEL] message\n const levelLabel = getStatusIndicator(level).ascii;\n return `${getTimestamp()} ${levelLabel} ${message}`;\n\n case OutputMode.PLAIN_TTY:\n // \u6734\u7D20 TTY \u6A21\u5F0F\uFF1Aindicator message\uFF08\u65E0\u989C\u8272\uFF09\n return includeIndicator ? `${indicator} ${message}` : message;\n\n case OutputMode.RICH:\n default:\n // \u5B8C\u6574\u6A21\u5F0F\uFF1A\u989C\u8272 + indicator + message\n const formattedMessage = includeIndicator ? `${indicator} ${message}` : message;\n\n if (globalOptions.timestamp) {\n return `${chalk.gray(getTimestamp())} ${formattedMessage}`;\n }\n\n return formattedMessage;\n }\n}\n\n/**\n * \u5E94\u7528\u989C\u8272\uFF08\u4EC5\u5728 RICH \u6A21\u5F0F\u4E0B\uFF09\n * @param message - \u6D88\u606F\n * @param colorFn - Chalk \u989C\u8272\u51FD\u6570\n * @returns \u7740\u8272\u540E\u7684\u6D88\u606F\n */\nfunction applyColor(message: string, colorFn: (_text: string) => string): string {\n const mode = getOutputMode();\n\n if (mode === OutputMode.RICH) {\n return colorFn(message);\n }\n\n return message;\n}\n\n/**\n * \u8C03\u8BD5\u65E5\u5FD7\uFF08\u7070\u8272\uFF0C[DEBUG] \u6307\u793A\u7B26\uFF09\n */\nexport function debug(...args: unknown[]): void {\n const message = args.join(' ');\n const formatted = formatMessage(LogLevel.DEBUG, message);\n console.debug(applyColor(formatted, chalk.gray));\n}\n\n/**\n * \u4FE1\u606F\u65E5\u5FD7\uFF08\u9ED8\u8BA4\u989C\u8272\uFF0C[INFO] \u6307\u793A\u7B26\uFF09\n */\nexport function info(...args: unknown[]): void {\n const message = args.join(' ');\n const formatted = formatMessage(LogLevel.INFO, message);\n console.info(applyColor(formatted, chalk.cyan));\n}\n\n/**\n * \u6210\u529F\u65E5\u5FD7\uFF08\u7EFF\u8272\uFF0C\u2713 \u6216 [OK] \u6307\u793A\u7B26\uFF09\n */\nexport function success(...args: unknown[]): void {\n const message = args.join(' ');\n const formatted = formatMessage(LogLevel.SUCCESS, message);\n console.log(applyColor(formatted, chalk.green));\n}\n\n/**\n * \u8B66\u544A\u65E5\u5FD7\uFF08\u9EC4\u8272\uFF0C! \u6216 [WARN] \u6307\u793A\u7B26\uFF09\n */\nexport function warn(...args: unknown[]): void {\n const message = args.join(' ');\n const formatted = formatMessage(LogLevel.WARN, message);\n console.warn(applyColor(formatted, chalk.yellow));\n}\n\n/**\n * \u9519\u8BEF\u65E5\u5FD7\uFF08\u7EA2\u8272\uFF0C\u2717 \u6216 [ERROR] \u6307\u793A\u7B26\uFF09\n */\nexport function error(...args: unknown[]): void {\n const message = args.join(' ');\n const formatted = formatMessage(LogLevel.ERROR, message);\n console.error(applyColor(formatted, chalk.red));\n}\n\n/**\n * \u6807\u9898\u65E5\u5FD7\uFF08\u9752\u8272\uFF0C\u52A0\u7C97\uFF09\n */\nexport function title(message: string): void {\n const mode = getOutputMode();\n\n if (mode === OutputMode.RICH) {\n console.log(chalk.cyan.bold(`\\n${message}\\n`));\n } else {\n console.log(`\\n=== ${message} ===\\n`);\n }\n}\n\n/**\n * \u5206\u9694\u7EBF\uFF08\u81EA\u52A8\u9002\u5E94\u7EC8\u7AEF\u5BBD\u5EA6\uFF0C\u6700\u5927 80 \u5217\uFF09\n * @param char - \u5206\u9694\u7B26\u5B57\u7B26\n * @param length - \u5206\u9694\u7EBF\u957F\u5EA6\uFF08\u9ED8\u8BA4 50\uFF09\n */\nexport function separator(char: string = '\u2500', length: number = 50): void {\n // Ensure separator doesn't exceed 80 columns\n const maxWidth = 80;\n const actualLength = Math.min(length, maxWidth);\n const line = char.repeat(actualLength);\n console.log(applyColor(line, chalk.gray));\n}\n\n/**\n * \u8868\u683C\u8868\u5934\uFF08\u5E26\u8FB9\u6846\uFF0C\u786E\u4FDD\u5728 80 \u5217\u5185\uFF09\n * @param titleText - \u6807\u9898\u6587\u672C\n */\nexport function tableHeader(titleText: string): void {\n // Use 59 character width to ensure box drawing chars stay within 80 columns\n // 59 (content) + 2 (borders) = 61 chars total\n const width = 59;\n const border = '\u2550'.repeat(width);\n const mode = getOutputMode();\n\n if (mode === OutputMode.RICH) {\n console.log(chalk.cyan(`\u2554${border}\u2557`));\n console.log(\n chalk.cyan(`\u2551${titleText.padStart((width + titleText.length) / 2).padEnd(width)}\u2551`)\n );\n console.log(chalk.cyan(`\u255A${border}\u255D`));\n } else {\n console.log(border);\n console.log(titleText);\n console.log(border);\n }\n}\n\n/**\n * \u52A0\u8F7D\u52A8\u753B\u6D88\u606F\uFF08... \u6216 [...] \u6307\u793A\u7B26\uFF09\n */\nexport function loading(message: string): void {\n const icon = resolveSpecialIcon('LOADING', cachedCapabilities);\n const formatted = `${icon} ${message}...`;\n console.log(applyColor(formatted, chalk.cyan));\n}\n\n/**\n * \u8FDB\u5EA6\u6D88\u606F\uFF08> \u6216 [>>] \u6307\u793A\u7B26\uFF09\n */\nexport function progress(message: string): void {\n const icon = resolveSpecialIcon('PROGRESS', cachedCapabilities);\n const formatted = `${icon} ${message}...`;\n console.log(applyColor(formatted, chalk.blue));\n}\n\n/**\n * \u63D0\u793A\u6D88\u606F\uFF08* \u6216 [TIP] \u6307\u793A\u7B26\uFF09\n */\nexport function hint(message: string): void {\n const icon = resolveSpecialIcon('HINT', cachedCapabilities);\n const formatted = `${icon} \u63D0\u793A: ${message}`;\n console.log(applyColor(formatted, chalk.cyan));\n}\n\n/**\n * \u5E26\u989C\u8272\u7684\u952E\u503C\u5BF9\u8F93\u51FA\n */\nexport function keyValue(key: string, value: string, keyColor = chalk.gray): void {\n const mode = getOutputMode();\n\n if (mode === OutputMode.RICH) {\n console.log(` ${keyColor(key + ':')} ${value}`);\n } else {\n console.log(` ${key}: ${value}`);\n }\n}\n\n/**\n * \u6253\u5370\u7A7A\u884C\uFF08\u7528\u4E8E\u64CD\u4F5C\u4E4B\u95F4\u7684\u89C6\u89C9\u5206\u9694\uFF0C\u4FDD\u6301\u4E00\u81F4\u95F4\u8DDD\uFF09\n * @param count - \u7A7A\u884C\u6570\u91CF\uFF08\u9ED8\u8BA4 1\uFF09\n */\nexport function newline(count: number = 1): void {\n console.log('\\n'.repeat(count - 1));\n}\n\n/**\n * \u5E26\u989C\u8272\u7684\u5217\u8868\u9879\n */\nexport function listItem(message: string, symbol: string = '\u2022'): void {\n const mode = getOutputMode();\n\n if (mode === OutputMode.RICH) {\n console.log(chalk.gray(` ${symbol} `) + message);\n } else {\n console.log(` ${symbol} ${message}`);\n }\n}\n\n/**\n * \u4EE3\u7801\u5757\uFF08\u5E26\u7070\u8272\u80CC\u666F\uFF09\n */\nexport function code(codeText: string): void {\n const mode = getOutputMode();\n\n if (mode === OutputMode.RICH) {\n console.log(chalk.bgGray.white(` ${codeText} `));\n } else {\n console.log(`\\`${codeText}\\``);\n }\n}\n\n/**\n * \u8F93\u51FA\u683C\u5F0F\u5316\u7684 AppError\uFF08\u5E26\u539F\u56E0\u548C\u89E3\u51B3\u65B9\u6848\uFF09\n * @param err - AppError \u5B9E\u4F8B\n * @param options - \u683C\u5F0F\u5316\u9009\u9879\n */\nexport function formattedError(err: AppError, options?: FormatOptions): void {\n const formatted = formatAppError(err, options);\n console.error(formatted);\n}\n\n/**\n * \u8F93\u51FA\u683C\u5F0F\u5316\u7684\u9519\u8BEF\u4FE1\u606F\uFF08\u4ECE ErrorInfo \u5BF9\u8C61\uFF09\n * @param errorInfo - \u9519\u8BEF\u4FE1\u606F\u5B9A\u4E49\n * @param details - \u9644\u52A0\u8BE6\u60C5\n * @param options - \u683C\u5F0F\u5316\u9009\u9879\n */\nexport function formattedErrorInfo(\n errorInfo: ErrorInfo,\n details?: string,\n options?: FormatOptions\n): void {\n const formatted = formatErrorInfo(errorInfo, details, options);\n console.error(formatted);\n}\n\n/**\n * \u8F93\u51FA\u683C\u5F0F\u5316\u7684\u901A\u7528\u9519\u8BEF\n * @param err - \u4EFB\u610F Error \u5BF9\u8C61\n * @param fallbackInfo - \u5982\u679C\u4E0D\u662F AppError\uFF0C\u4F7F\u7528\u7684\u56DE\u9000\u9519\u8BEF\u4FE1\u606F\n * @param options - \u683C\u5F0F\u5316\u9009\u9879\n */\nexport function formattedGenericError(\n err: Error,\n fallbackInfo?: ErrorInfo,\n options?: FormatOptions\n): void {\n const formatted = formatErrorUtil(err, fallbackInfo, options);\n console.error(formatted);\n}\n\n/**\n * \u9ED8\u8BA4\u5BFC\u51FA\u5BF9\u8C61\n */\nexport default {\n debug,\n info,\n success,\n warn,\n error,\n title,\n separator,\n tableHeader,\n loading,\n progress,\n hint,\n keyValue,\n newline,\n listItem,\n code,\n configure: configureLogger,\n getOutputMode,\n formattedError,\n formattedErrorInfo,\n formattedGenericError,\n};\n", "/**\n * Terminal Capability Detection\n * @module utils/terminal\n *\n * Provides functions to detect terminal capabilities for adaptive output formatting.\n */\n\nimport chalk from 'chalk';\nimport { Platform, TerminalCapabilities } from '../types/terminal';\n\n/**\n * Detect current terminal capabilities\n * @returns Terminal capabilities object with detected features\n */\nexport function detectTerminalCapabilities(): TerminalCapabilities {\n const platform = mapPlatform(process.platform);\n const isTTY = process.stdout.isTTY || false;\n const term = process.env.TERM;\n\n return {\n isTTY,\n supportsColor: chalk.level > 0,\n supportsUnicode: supportsUnicode(term, platform),\n width: process.stdout.columns || 80,\n height: process.stdout.rows,\n platform,\n term,\n };\n}\n\n/**\n * Check if given platform is Windows\n * @param platform - Platform to check\n * @returns True if platform is Windows\n */\nexport function isWindows(platform: Platform): boolean {\n return platform === Platform.WIN32;\n}\n\n/**\n * Determine if terminal supports Unicode characters\n * @param term - TERM environment variable value\n * @param platform - Operating system platform\n * @returns True if Unicode is supported\n */\nexport function supportsUnicode(term: string | undefined, platform: Platform): boolean {\n // Windows CMD typically doesn't support Unicode well\n if (platform === Platform.WIN32) {\n return false;\n }\n\n // No TERM variable means no Unicode support\n if (!term) {\n return false;\n }\n\n // Dumb terminals don't support Unicode\n if (term === 'dumb') {\n return false;\n }\n\n // Legacy terminals don't support Unicode\n if (term === 'vt100') {\n return false;\n }\n\n // Modern terminals (xterm, screen, tmux variants) support Unicode\n if (term.startsWith('xterm') || term.startsWith('screen') || term.startsWith('tmux')) {\n return true;\n }\n\n // Default to false for unknown terminals to be safe\n return false;\n}\n\n/**\n * Map Node.js platform string to Platform enum\n * @param nodePlatform - process.platform value\n * @returns Platform enum value\n */\nexport function mapPlatform(nodePlatform: string): Platform {\n switch (nodePlatform) {\n case 'win32':\n return Platform.WIN32;\n case 'linux':\n return Platform.LINUX;\n case 'darwin':\n return Platform.DARWIN;\n case 'freebsd':\n return Platform.FREEBSD;\n default:\n return Platform.OTHER;\n }\n}\n", "/**\n * UI Symbols Constants\n * @module constants/ui-symbols\n *\n * This file defines all text-based icons and status indicators\n * used throughout the CLI for universal terminal compatibility.\n */\n\n/**\n * Status icons for different message types\n * These replace emoji indicators with text-based alternatives\n */\nexport const statusIcons = {\n SUCCESS: '[OK]',\n ERROR: '[ERROR]',\n WARN: '[WARN]',\n INFO: '[INFO]',\n DEBUG: '[DEBUG]',\n LOADING: '[...]',\n PROGRESS: '[>>]',\n HINT: '[TIP]',\n} as const;\n\n/**\n * Menu icons for different CLI operations\n * These replace emoji in menu options with text labels\n */\nexport const menuIcons = {\n STATUS: '[\u67E5\u770B]',\n START: '[\u542F\u52A8]',\n STOP: '[\u505C\u6B62]',\n RESTART: '[\u91CD\u542F]',\n USER: '[\u7528\u6237]',\n CONFIG: '[\u914D\u7F6E]',\n LOGS: '[\u65E5\u5FD7]',\n LANGUAGE: '[\u8BED\u8A00]',\n EXIT: '[\u9000\u51FA]',\n STATS: '[\u6D41\u91CF]',\n QUOTA: '[\u914D\u989D]',\n VIEW: '[\u67E5\u770B]',\n BACK: '[\u8FD4\u56DE]',\n ERROR: '[\u9519\u8BEF]',\n WARNING: '[\u8B66\u544A]',\n BACKUP: '[\u5907\u4EFD]',\n RESTORE: '[\u6062\u590D]',\n} as const;\n\n// Type exports for TypeScript support\nexport type StatusIcon = (typeof statusIcons)[keyof typeof statusIcons];\nexport type MenuIcon = (typeof menuIcons)[keyof typeof menuIcons];\n", "/**\n * Icon Resolver\n * @module utils/icons\n *\n * Resolves appropriate icons based on terminal capabilities and context.\n */\n\nimport { TerminalCapabilities } from '../types/terminal';\nimport { statusIcons, menuIcons } from '../constants/ui-symbols';\n\n// Import LogLevel type only to avoid circular dependency\nimport type { LogLevel } from './logger';\n\n/**\n * Status indicator with both Unicode and ASCII representations\n */\nexport interface StatusIndicator {\n level: string; // Using string instead of LogLevel enum to avoid circular dependency\n unicode: string;\n ascii: string;\n color: 'green' | 'red' | 'yellow' | 'cyan' | 'blue' | 'gray';\n}\n\n/**\n * Menu icon with emoji (deprecated) and text representations\n */\nexport interface MenuIcon {\n emoji?: string;\n text: string;\n}\n\n/**\n * Status indicator mappings for all log levels\n */\nconst STATUS_INDICATOR_MAP: Record<string, StatusIndicator> = {\n success: {\n level: 'success',\n unicode: '\u2713',\n ascii: statusIcons.SUCCESS,\n color: 'green',\n },\n error: {\n level: 'error',\n unicode: '\u2717',\n ascii: statusIcons.ERROR,\n color: 'red',\n },\n warn: {\n level: 'warn',\n unicode: '!',\n ascii: statusIcons.WARN,\n color: 'yellow',\n },\n info: {\n level: 'info',\n unicode: 'i',\n ascii: statusIcons.INFO,\n color: 'cyan',\n },\n debug: {\n level: 'debug',\n unicode: '\u00B7',\n ascii: statusIcons.DEBUG,\n color: 'gray',\n },\n};\n\n/**\n * Additional status indicators for special states\n */\nconst EXTRA_INDICATORS: Record<string, StatusIndicator> = {\n LOADING: {\n level: 'info',\n unicode: '...',\n ascii: statusIcons.LOADING,\n color: 'cyan',\n },\n PROGRESS: {\n level: 'info',\n unicode: '>',\n ascii: statusIcons.PROGRESS,\n color: 'blue',\n },\n HINT: {\n level: 'info',\n unicode: '*',\n ascii: statusIcons.HINT,\n color: 'cyan',\n },\n};\n\n/**\n * Menu icon mappings\n */\nconst MENU_ICON_MAP: Record<string, MenuIcon> = {\n STATUS: { emoji: '\uD83D\uDCCA', text: menuIcons.STATUS },\n START: { emoji: '\uD83D\uDE80', text: menuIcons.START },\n STOP: { emoji: '\uD83D\uDED1', text: menuIcons.STOP },\n RESTART: { emoji: '\uD83D\uDD04', text: menuIcons.RESTART },\n USER: { emoji: '\uD83D\uDC65', text: menuIcons.USER },\n CONFIG: { emoji: '\u2699\uFE0F', text: menuIcons.CONFIG },\n LOGS: { emoji: '\uD83D\uDCDD', text: menuIcons.LOGS },\n EXIT: { emoji: '\u274C', text: menuIcons.EXIT },\n};\n\n/**\n * Resolve appropriate icon based on log level and terminal capabilities\n * @param level - Log level\n * @param capabilities - Terminal capabilities\n * @returns Icon string (Unicode or ASCII)\n */\nexport function resolveIcon(level: LogLevel, capabilities: TerminalCapabilities): string {\n const indicator = STATUS_INDICATOR_MAP[level as string];\n\n if (!indicator) {\n // Fallback for unknown levels\n return capabilities.supportsUnicode ? '\u2022' : statusIcons.INFO;\n }\n\n // Use ASCII for terminals that don't support Unicode\n if (!capabilities.supportsUnicode) {\n return indicator.ascii;\n }\n\n // Use Unicode for modern terminals\n return indicator.unicode;\n}\n\n/**\n * Resolve icon for special states (loading, progress, hint)\n * @param state - State name (LOADING, PROGRESS, HINT)\n * @param capabilities - Terminal capabilities\n * @returns Icon string\n */\nexport function resolveSpecialIcon(\n state: 'LOADING' | 'PROGRESS' | 'HINT',\n capabilities: TerminalCapabilities\n): string {\n const indicator = EXTRA_INDICATORS[state];\n\n if (!indicator) {\n return capabilities.supportsUnicode ? '\u2022' : statusIcons.INFO;\n }\n\n return capabilities.supportsUnicode ? indicator.unicode : indicator.ascii;\n}\n\n/**\n * Get status indicator details for a log level\n * @param level - Log level\n * @returns Status indicator object\n * @throws Error if log level is invalid\n */\nexport function getStatusIndicator(level: LogLevel): StatusIndicator {\n const indicator = STATUS_INDICATOR_MAP[level as string];\n\n if (!indicator) {\n throw new Error(`Invalid log level: ${level}`);\n }\n\n return indicator;\n}\n\n/**\n * Get menu icon for a specific key\n * @param key - Menu icon key (STATUS, START, STOP, etc.)\n * @returns Menu icon object\n * @throws Error if key is not found\n */\nexport function getMenuIcon(key: string): MenuIcon {\n const icon = MENU_ICON_MAP[key.toUpperCase()];\n\n if (!icon) {\n throw new Error(`Unknown menu icon key: ${key}`);\n }\n\n return icon;\n}\n", "/**\n * Error Formatter Utility\n * @module utils/error-formatter\n *\n * Formats errors into user-friendly output with causes and solutions.\n */\n\nimport chalk from 'chalk';\nimport { AppError } from './errors';\nimport { ErrorInfo, findErrorByCode } from '../constants/error-codes';\nimport { detectTerminalCapabilities } from './terminal';\nimport { getOutputMode, OutputMode } from './logger';\n\n/**\n * Format options\n */\nexport interface FormatOptions {\n /** Show causes section */\n showCauses?: boolean;\n /** Show solutions section */\n showSolutions?: boolean;\n /** Show stack trace (for debugging) */\n showStack?: boolean;\n /** Indentation string */\n indent?: string;\n}\n\nconst DEFAULT_OPTIONS: FormatOptions = {\n showCauses: true,\n showSolutions: true,\n showStack: false,\n indent: ' ',\n};\n\n/**\n * Get error icon based on terminal capabilities\n */\nfunction getErrorIcon(): string {\n const capabilities = detectTerminalCapabilities();\n return capabilities.supportsUnicode ? '\u2717' : '[ERROR]';\n}\n\n/**\n * Format an AppError into user-friendly output\n * @param error - The AppError to format\n * @param options - Formatting options\n * @returns Formatted error string\n */\nexport function formatAppError(error: AppError, options?: FormatOptions): string {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const mode = getOutputMode();\n const lines: string[] = [];\n const indent = opts.indent || ' ';\n\n // Header line: \u2717 \u9519\u8BEF [E101]: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\n const icon = getErrorIcon();\n const headerText = `${icon} \u9519\u8BEF [${error.code}]: ${error.title}`;\n\n if (mode === OutputMode.RICH) {\n lines.push(chalk.red.bold(headerText));\n } else {\n lines.push(headerText);\n }\n\n // Details if present\n if (error.details) {\n lines.push('');\n if (mode === OutputMode.RICH) {\n lines.push(chalk.gray(`${indent}${error.details}`));\n } else {\n lines.push(`${indent}${error.details}`);\n }\n }\n\n // Causes section\n if (opts.showCauses && error.causes.length > 0) {\n lines.push('');\n if (mode === OutputMode.RICH) {\n lines.push(chalk.yellow('\u53EF\u80FD\u7684\u539F\u56E0:'));\n } else {\n lines.push('\u53EF\u80FD\u7684\u539F\u56E0:');\n }\n error.causes.forEach((cause, index) => {\n const bullet = `${indent}${index + 1}. ${cause}`;\n if (mode === OutputMode.RICH) {\n lines.push(chalk.gray(bullet));\n } else {\n lines.push(bullet);\n }\n });\n }\n\n // Solutions section\n if (opts.showSolutions && error.solutions.length > 0) {\n lines.push('');\n if (mode === OutputMode.RICH) {\n lines.push(chalk.green('\u89E3\u51B3\u65B9\u6848:'));\n } else {\n lines.push('\u89E3\u51B3\u65B9\u6848:');\n }\n error.solutions.forEach((solution) => {\n const bullet = `${indent}- ${solution}`;\n if (mode === OutputMode.RICH) {\n lines.push(chalk.cyan(bullet));\n } else {\n lines.push(bullet);\n }\n });\n }\n\n // Stack trace (for debugging)\n if (opts.showStack && error.stack) {\n lines.push('');\n if (mode === OutputMode.RICH) {\n lines.push(chalk.gray('Stack trace:'));\n lines.push(chalk.gray(error.stack));\n } else {\n lines.push('Stack trace:');\n lines.push(error.stack);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Format an ErrorInfo object (without creating an AppError)\n * @param errorInfo - The error info to format\n * @param details - Additional details\n * @param options - Formatting options\n * @returns Formatted error string\n */\nexport function formatErrorInfo(\n errorInfo: ErrorInfo,\n details?: string,\n options?: FormatOptions\n): string {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const mode = getOutputMode();\n const lines: string[] = [];\n const indent = opts.indent || ' ';\n\n // Header line\n const icon = getErrorIcon();\n const headerText = `${icon} \u9519\u8BEF [${errorInfo.code}]: ${errorInfo.title}`;\n\n if (mode === OutputMode.RICH) {\n lines.push(chalk.red.bold(headerText));\n } else {\n lines.push(headerText);\n }\n\n // Details if present\n if (details) {\n lines.push('');\n if (mode === OutputMode.RICH) {\n lines.push(chalk.gray(`${indent}${details}`));\n } else {\n lines.push(`${indent}${details}`);\n }\n }\n\n // Causes section\n if (opts.showCauses && errorInfo.causes.length > 0) {\n lines.push('');\n if (mode === OutputMode.RICH) {\n lines.push(chalk.yellow('\u53EF\u80FD\u7684\u539F\u56E0:'));\n } else {\n lines.push('\u53EF\u80FD\u7684\u539F\u56E0:');\n }\n errorInfo.causes.forEach((cause, index) => {\n const bullet = `${indent}${index + 1}. ${cause}`;\n if (mode === OutputMode.RICH) {\n lines.push(chalk.gray(bullet));\n } else {\n lines.push(bullet);\n }\n });\n }\n\n // Solutions section\n if (opts.showSolutions && errorInfo.solutions.length > 0) {\n lines.push('');\n if (mode === OutputMode.RICH) {\n lines.push(chalk.green('\u89E3\u51B3\u65B9\u6848:'));\n } else {\n lines.push('\u89E3\u51B3\u65B9\u6848:');\n }\n errorInfo.solutions.forEach((solution) => {\n const bullet = `${indent}- ${solution}`;\n if (mode === OutputMode.RICH) {\n lines.push(chalk.cyan(bullet));\n } else {\n lines.push(bullet);\n }\n });\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Format a generic Error with fallback error info\n * @param error - The error to format\n * @param fallbackInfo - Fallback error info if not an AppError\n * @param options - Formatting options\n * @returns Formatted error string\n */\nexport function formatError(\n error: Error,\n fallbackInfo?: ErrorInfo,\n options?: FormatOptions\n): string {\n // If it's an AppError, format it directly\n if (AppError.isAppError(error)) {\n return formatAppError(error, options);\n }\n\n // If we have fallback info, use it\n if (fallbackInfo) {\n return formatErrorInfo(fallbackInfo, error.message, options);\n }\n\n // Simple fallback for generic errors\n const mode = getOutputMode();\n const icon = getErrorIcon();\n const headerText = `${icon} \u9519\u8BEF: ${error.message}`;\n\n if (mode === OutputMode.RICH) {\n return chalk.red(headerText);\n }\n return headerText;\n}\n\n/**\n * Format error by looking up error code\n * @param code - Error code (e.g., \"E101\")\n * @param details - Additional details\n * @param options - Formatting options\n * @returns Formatted error string or undefined if code not found\n */\nexport function formatByCode(\n code: string,\n details?: string,\n options?: FormatOptions\n): string | undefined {\n const errorInfo = findErrorByCode(code);\n if (!errorInfo) {\n return undefined;\n }\n return formatErrorInfo(errorInfo, details, options);\n}\n\n/**\n * Create a simple error message (just the header line)\n * @param errorInfo - The error info\n * @param details - Additional details\n * @returns Simple error message\n */\nexport function simpleErrorMessage(errorInfo: ErrorInfo, details?: string): string {\n const icon = getErrorIcon();\n const message = details\n ? `${icon} \u9519\u8BEF [${errorInfo.code}]: ${errorInfo.title} - ${details}`\n : `${icon} \u9519\u8BEF [${errorInfo.code}]: ${errorInfo.title}`;\n\n const mode = getOutputMode();\n if (mode === OutputMode.RICH) {\n return chalk.red(message);\n }\n return message;\n}\n", "/**\n * Custom Error Classes for CLI\n * @module utils/errors\n *\n * Provides structured error handling with error codes,\n * causes, and solutions for user-friendly error messages.\n */\n\nimport { ErrorInfo } from '../constants/error-codes';\n\n/**\n * Base application error with structured error information\n */\nexport class AppError extends Error {\n /** Error code (e.g., E101) */\n public readonly code: string;\n\n /** Error title */\n public readonly title: string;\n\n /** Possible causes */\n public readonly causes: readonly string[];\n\n /** Suggested solutions */\n public readonly solutions: readonly string[];\n\n /** Additional context/details */\n public readonly details?: string;\n\n /**\n * Create an AppError from ErrorInfo\n * @param errorInfo - Error definition from error-codes.ts\n * @param details - Additional context (e.g., file path, specific value)\n */\n constructor(errorInfo: ErrorInfo, details?: string) {\n // Build the message from title and details\n const message = details ? `${errorInfo.title}: ${details}` : errorInfo.title;\n super(message);\n\n this.name = 'AppError';\n this.code = errorInfo.code;\n this.title = errorInfo.title;\n this.causes = errorInfo.causes;\n this.solutions = errorInfo.solutions;\n this.details = details;\n\n // Maintains proper stack trace for where error was thrown (V8 engines)\n const ErrorWithCaptureStackTrace = Error as typeof Error & {\n captureStackTrace?: (_target: object, _constructor: Function) => void;\n };\n if (ErrorWithCaptureStackTrace.captureStackTrace) {\n ErrorWithCaptureStackTrace.captureStackTrace(this, AppError);\n }\n }\n\n /**\n * Check if an error is an AppError\n */\n static isAppError(error: unknown): error is AppError {\n return error instanceof AppError;\n }\n\n /**\n * Convert a generic Error to AppError with a fallback error info\n */\n static fromError(error: Error, fallbackInfo: ErrorInfo): AppError {\n if (AppError.isAppError(error)) {\n return error;\n }\n return new AppError(fallbackInfo, error.message);\n }\n}\n\n/**\n * Configuration-related error\n */\nexport class ConfigError extends AppError {\n constructor(errorInfo: ErrorInfo, details?: string) {\n super(errorInfo, details);\n this.name = 'ConfigError';\n }\n}\n\n/**\n * User management error\n */\nexport class UserError extends AppError {\n constructor(errorInfo: ErrorInfo, details?: string) {\n super(errorInfo, details);\n this.name = 'UserError';\n }\n}\n\n/**\n * Quota management error\n */\nexport class QuotaError extends AppError {\n constructor(errorInfo: ErrorInfo, details?: string) {\n super(errorInfo, details);\n this.name = 'QuotaError';\n }\n}\n\n/**\n * Service management error\n */\nexport class ServiceError extends AppError {\n constructor(errorInfo: ErrorInfo, details?: string) {\n super(errorInfo, details);\n this.name = 'ServiceError';\n }\n}\n\n/**\n * Network-related error\n */\nexport class NetworkError extends AppError {\n constructor(errorInfo: ErrorInfo, details?: string) {\n super(errorInfo, details);\n this.name = 'NetworkError';\n }\n}\n\n/**\n * File operation error\n */\nexport class FileError extends AppError {\n constructor(errorInfo: ErrorInfo, details?: string) {\n super(errorInfo, details);\n this.name = 'FileError';\n }\n}\n\n/**\n * Input validation error\n */\nexport class ValidationError extends AppError {\n constructor(errorInfo: ErrorInfo, details?: string) {\n super(errorInfo, details);\n this.name = 'ValidationError';\n }\n}\n\n/**\n * Protocol parsing error (VLESS, etc.)\n */\nexport class ProtocolError extends AppError {\n constructor(errorInfo: ErrorInfo, details?: string) {\n super(errorInfo, details);\n this.name = 'ProtocolError';\n }\n}\n\n/**\n * System/permission error\n */\nexport class SystemError extends AppError {\n constructor(errorInfo: ErrorInfo, details?: string) {\n super(errorInfo, details);\n this.name = 'SystemError';\n }\n}\n", "/**\n * Unified Error Code Definitions\n * @module constants/error-codes\n *\n * Error code format: E + Category + Number\n * - E1xx: Configuration errors\n * - E2xx: User management errors\n * - E3xx: Quota management errors\n * - E4xx: Service management errors\n * - E5xx: Network errors\n * - E6xx: File operation errors\n * - E7xx: Validation errors\n * - E8xx: VLESS/Protocol parsing errors\n * - E9xx: System/Permission errors\n */\n\n/**\n * Error information details\n */\nexport interface ErrorInfo {\n /** Error code (e.g., E101) */\n readonly code: string;\n /** Error title (short description) */\n readonly title: string;\n /** Possible causes */\n readonly causes: readonly string[];\n /** Solutions */\n readonly solutions: readonly string[];\n}\n\n/**\n * Configuration Errors (E1xx)\n */\nexport const ConfigErrors = {\n CONFIG_NOT_FOUND: {\n code: 'E101',\n title: '\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728',\n causes: ['Xray \u5C1A\u672A\u5B89\u88C5', '\u914D\u7F6E\u6587\u4EF6\u88AB\u5220\u9664\u6216\u79FB\u52A8', '\u8DEF\u5F84\u914D\u7F6E\u9519\u8BEF'],\n solutions: [\n '\u8FD0\u884C\u5B89\u88C5\u811A\u672C\u91CD\u65B0\u5B89\u88C5 Xray',\n '\u68C0\u67E5\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: /usr/local/etc/xray/config.json',\n \"\u4F7F\u7528 'xray-manager config --restore' \u4ECE\u5907\u4EFD\u6062\u590D\",\n ],\n },\n CONFIG_NO_READ_PERMISSION: {\n code: 'E102',\n title: '\u914D\u7F6E\u6587\u4EF6\u65E0\u8BFB\u53D6\u6743\u9650',\n causes: ['\u5F53\u524D\u7528\u6237\u6743\u9650\u4E0D\u8DB3', '\u6587\u4EF6\u6743\u9650\u8BBE\u7F6E\u9519\u8BEF', '\u672A\u4F7F\u7528 sudo \u8FD0\u884C'],\n solutions: [\n \"\u4F7F\u7528 sudo \u8FD0\u884C: 'sudo xray-manager' \u6216 'sudo xm'\",\n \"\u68C0\u67E5\u6587\u4EF6\u6743\u9650: 'ls -la /usr/local/etc/xray/config.json'\",\n \"\u4FEE\u6539\u6743\u9650: 'sudo chmod 644 /usr/local/etc/xray/config.json'\",\n ],\n },\n CONFIG_NO_WRITE_PERMISSION: {\n code: 'E103',\n title: '\u914D\u7F6E\u6587\u4EF6\u65E0\u5199\u5165\u6743\u9650',\n causes: ['\u5F53\u524D\u7528\u6237\u6743\u9650\u4E0D\u8DB3', '\u6587\u4EF6\u7CFB\u7EDF\u53EA\u8BFB', '\u78C1\u76D8\u7A7A\u95F4\u4E0D\u8DB3'],\n solutions: [\n \"\u4F7F\u7528 sudo \u8FD0\u884C: 'sudo xray-manager' \u6216 'sudo xm'\",\n \"\u68C0\u67E5\u78C1\u76D8\u7A7A\u95F4: 'df -h'\",\n '\u68C0\u67E5\u6587\u4EF6\u7CFB\u7EDF\u72B6\u6001',\n ],\n },\n CONFIG_INVALID_JSON: {\n code: 'E104',\n title: '\u914D\u7F6E\u6587\u4EF6 JSON \u683C\u5F0F\u9519\u8BEF',\n causes: ['JSON \u8BED\u6CD5\u9519\u8BEF', '\u6587\u4EF6\u88AB\u635F\u574F', '\u7F16\u8F91\u65F6\u5F15\u5165\u9519\u8BEF'],\n solutions: [\n \"\u4F7F\u7528 JSON \u9A8C\u8BC1\u5DE5\u5177\u68C0\u67E5: 'cat config.json | jq .'\",\n \"\u4ECE\u5907\u4EFD\u6062\u590D: 'xray-manager config --restore'\",\n '\u624B\u52A8\u68C0\u67E5 JSON \u8BED\u6CD5\uFF08\u5F15\u53F7\u3001\u9017\u53F7\u3001\u62EC\u53F7\u5339\u914D\uFF09',\n ],\n },\n CONFIG_INVALID_STRUCTURE: {\n code: 'E105',\n title: '\u914D\u7F6E\u6587\u4EF6\u7ED3\u6784\u65E0\u6548',\n causes: ['\u7F3A\u5C11\u5FC5\u8981\u5B57\u6BB5 (inbounds/outbounds)', 'Xray \u7248\u672C\u4E0D\u517C\u5BB9', '\u914D\u7F6E\u683C\u5F0F\u8FC7\u65F6'],\n solutions: [\n '\u786E\u4FDD\u914D\u7F6E\u5305\u542B inbounds \u548C outbounds \u6570\u7EC4',\n '\u53C2\u8003 Xray \u5B98\u65B9\u6587\u6863\u68C0\u67E5\u914D\u7F6E\u683C\u5F0F',\n '\u4F7F\u7528\u6A21\u677F\u91CD\u65B0\u751F\u6210\u914D\u7F6E\u6587\u4EF6',\n ],\n },\n CONFIG_BACKUP_FAILED: {\n code: 'E106',\n title: '\u914D\u7F6E\u5907\u4EFD\u5931\u8D25',\n causes: ['\u76EE\u6807\u76EE\u5F55\u4E0D\u5B58\u5728', '\u78C1\u76D8\u7A7A\u95F4\u4E0D\u8DB3', '\u6743\u9650\u4E0D\u8DB3'],\n solutions: ['\u786E\u4FDD\u5907\u4EFD\u76EE\u5F55\u5B58\u5728', \"\u68C0\u67E5\u78C1\u76D8\u7A7A\u95F4: 'df -h'\", '\u4F7F\u7528 sudo \u8FD0\u884C\u7A0B\u5E8F'],\n },\n CONFIG_RESTORE_FAILED: {\n code: 'E107',\n title: '\u914D\u7F6E\u6062\u590D\u5931\u8D25',\n causes: ['\u5907\u4EFD\u6587\u4EF6\u4E0D\u5B58\u5728', '\u5907\u4EFD\u6587\u4EF6\u5DF2\u635F\u574F', '\u6743\u9650\u4E0D\u8DB3'],\n solutions: [\n \"\u5217\u51FA\u53EF\u7528\u5907\u4EFD: 'xray-manager config --list-backups'\",\n '\u9009\u62E9\u4E00\u4E2A\u6709\u6548\u7684\u5907\u4EFD\u6587\u4EF6',\n '\u786E\u4FDD\u6709\u8DB3\u591F\u6743\u9650\u5199\u5165\u914D\u7F6E\u6587\u4EF6',\n ],\n },\n} as const;\n\n/**\n * User Management Errors (E2xx)\n */\nexport const UserErrors = {\n INVALID_EMAIL: {\n code: 'E201',\n title: '\u90AE\u7BB1\u5730\u5740\u683C\u5F0F\u65E0\u6548',\n causes: ['\u90AE\u7BB1\u683C\u5F0F\u4E0D\u6B63\u786E', '\u5305\u542B\u975E\u6CD5\u5B57\u7B26', '\u7F3A\u5C11\u5FC5\u8981\u90E8\u5206 (@, \u57DF\u540D)'],\n solutions: [\n '\u4F7F\u7528\u6807\u51C6\u90AE\u7BB1\u683C\u5F0F: user@example.com',\n '\u786E\u4FDD\u90AE\u7BB1\u53EA\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u5141\u8BB8\u7684\u7279\u6B8A\u5B57\u7B26',\n '\u68C0\u67E5\u662F\u5426\u6709\u591A\u4F59\u7684\u7A7A\u683C',\n ],\n },\n EMAIL_EXISTS: {\n code: 'E202',\n title: '\u90AE\u7BB1\u5730\u5740\u5DF2\u5B58\u5728',\n causes: ['\u8BE5\u90AE\u7BB1\u5DF2\u88AB\u5176\u4ED6\u7528\u6237\u4F7F\u7528', '\u5C1D\u8BD5\u521B\u5EFA\u91CD\u590D\u7528\u6237'],\n solutions: [\n \"\u4F7F\u7528 'xray-manager user list' \u67E5\u770B\u73B0\u6709\u7528\u6237\",\n '\u9009\u62E9\u4E00\u4E2A\u4E0D\u540C\u7684\u90AE\u7BB1\u5730\u5740',\n \"\u5982\u9700\u66F4\u65B0\u7528\u6237\uFF0C\u4F7F\u7528 'xray-manager user update' \u547D\u4EE4\",\n ],\n },\n USER_NOT_FOUND: {\n code: 'E203',\n title: '\u7528\u6237\u4E0D\u5B58\u5728',\n causes: ['\u7528\u6237\u5DF2\u88AB\u5220\u9664', '\u90AE\u7BB1\u5730\u5740\u8F93\u5165\u9519\u8BEF', '\u7528\u6237\u4ECE\u672A\u521B\u5EFA'],\n solutions: [\n \"\u4F7F\u7528 'xray-manager user list' \u67E5\u770B\u6240\u6709\u7528\u6237\",\n '\u68C0\u67E5\u90AE\u7BB1\u5730\u5740\u662F\u5426\u6B63\u786E\uFF08\u533A\u5206\u5927\u5C0F\u5199\uFF09',\n \"\u4F7F\u7528 'xray-manager user add' \u521B\u5EFA\u65B0\u7528\u6237\",\n ],\n },\n INVALID_UUID: {\n code: 'E204',\n title: 'UUID \u683C\u5F0F\u65E0\u6548',\n causes: ['UUID \u683C\u5F0F\u4E0D\u6B63\u786E', '\u4E0D\u662F\u6709\u6548\u7684 UUID v4', '\u590D\u5236\u65F6\u4E22\u5931\u90E8\u5206\u5B57\u7B26'],\n solutions: [\n 'UUID \u5E94\u4E3A 36 \u5B57\u7B26\u683C\u5F0F: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',\n '\u4F7F\u7528\u7CFB\u7EDF\u751F\u6210\u7684 UUID\uFF0C\u4E0D\u8981\u624B\u52A8\u7F16\u8F91',\n \"\u53EF\u4F7F\u7528 'uuidgen' \u547D\u4EE4\u751F\u6210\u65B0 UUID\",\n ],\n },\n KEY_GENERATION_FAILED: {\n code: 'E205',\n title: '\u5BC6\u94A5\u751F\u6210\u5931\u8D25',\n causes: ['xray \u547D\u4EE4\u4E0D\u53EF\u7528', 'x25519 \u7B97\u6CD5\u4E0D\u652F\u6301', '\u7CFB\u7EDF\u968F\u673A\u6570\u751F\u6210\u5668\u95EE\u9898'],\n solutions: [\n \"\u786E\u4FDD Xray \u5DF2\u6B63\u786E\u5B89\u88C5: 'xray version'\",\n '\u68C0\u67E5 Xray \u7248\u672C\u662F\u5426\u652F\u6301 x25519',\n '\u91CD\u65B0\u5B89\u88C5 Xray',\n ],\n },\n} as const;\n\n/**\n * Quota Management Errors (E3xx)\n */\nexport const QuotaErrors = {\n QUOTA_CONFIG_NOT_FOUND: {\n code: 'E301',\n title: '\u914D\u989D\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728',\n causes: ['\u914D\u989D\u529F\u80FD\u672A\u521D\u59CB\u5316', '\u6587\u4EF6\u88AB\u5220\u9664', '\u8DEF\u5F84\u914D\u7F6E\u9519\u8BEF'],\n solutions: [\n \"\u8FD0\u884C 'xray-manager quota init' \u521D\u59CB\u5316\u914D\u989D\u7CFB\u7EDF\",\n '\u68C0\u67E5\u6587\u4EF6\u8DEF\u5F84: /usr/local/etc/xray/quota.json',\n '\u786E\u4FDD Xray \u914D\u7F6E\u76EE\u5F55\u5B58\u5728',\n ],\n },\n INVALID_QUOTA_VALUE: {\n code: 'E302',\n title: '\u914D\u989D\u503C\u65E0\u6548',\n causes: ['\u6570\u503C\u4E0D\u662F\u6709\u6548\u6570\u5B57', '\u6570\u503C\u4E3A\u8D1F\u6570\uFF08\u975E -1\uFF09', '\u8D85\u51FA\u5141\u8BB8\u8303\u56F4'],\n solutions: [\n '\u914D\u989D\u503C\u5FC5\u987B\u4E3A -1\uFF08\u65E0\u9650\u5236\uFF09\u6216 >= 0 \u7684\u6574\u6570',\n '\u4F7F\u7528\u5B57\u8282\u4E3A\u5355\u4F4D\u6216\u5E26\u5355\u4F4D\u7684\u683C\u5F0F\uFF08\u5982 10GB\uFF09',\n \"\u8BBE\u7F6E\u65E0\u9650\u5236\u914D\u989D\u4F7F\u7528 '-1'\",\n ],\n },\n USER_QUOTA_NOT_FOUND: {\n code: 'E303',\n title: '\u7528\u6237\u914D\u989D\u4E0D\u5B58\u5728',\n causes: ['\u7528\u6237\u672A\u8BBE\u7F6E\u914D\u989D', '\u7528\u6237\u90AE\u7BB1\u9519\u8BEF', '\u7528\u6237\u5DF2\u88AB\u5220\u9664'],\n solutions: [\n \"\u4F7F\u7528 'xray-manager quota list' \u67E5\u770B\u6240\u6709\u914D\u989D\",\n \"\u4F7F\u7528 'xray-manager quota set <email> <limit>' \u8BBE\u7F6E\u914D\u989D\",\n '\u786E\u8BA4\u7528\u6237\u90AE\u7BB1\u5730\u5740\u6B63\u786E',\n ],\n },\n TRAFFIC_UPDATE_FAILED: {\n code: 'E304',\n title: '\u6D41\u91CF\u7EDF\u8BA1\u66F4\u65B0\u5931\u8D25',\n causes: ['\u914D\u989D\u6587\u4EF6\u5199\u5165\u5931\u8D25', '\u5E76\u53D1\u8BBF\u95EE\u51B2\u7A81', '\u6570\u636E\u683C\u5F0F\u9519\u8BEF'],\n solutions: ['\u68C0\u67E5\u914D\u989D\u6587\u4EF6\u5199\u5165\u6743\u9650', '\u786E\u4FDD\u6CA1\u6709\u5176\u4ED6\u8FDB\u7A0B\u6B63\u5728\u4FEE\u6539\u914D\u989D\u6587\u4EF6', '\u91CD\u65B0\u521D\u59CB\u5316\u914D\u989D\u7CFB\u7EDF'],\n },\n QUOTA_EXCEEDED: {\n code: 'E305',\n title: '\u7528\u6237\u6D41\u91CF\u914D\u989D\u5DF2\u8D85\u9650',\n causes: ['\u7528\u6237\u6D41\u91CF\u4F7F\u7528\u8D85\u8FC7\u9650\u5236', '\u914D\u989D\u8BBE\u7F6E\u8FC7\u4F4E'],\n solutions: [\n \"\u4F7F\u7528 'xray-manager quota set <email> <new_limit>' \u589E\u52A0\u914D\u989D\",\n \"\u4F7F\u7528 'xray-manager quota reset <email>' \u91CD\u7F6E\u6D41\u91CF\u7EDF\u8BA1\",\n '\u8003\u8651\u8BBE\u7F6E\u65E0\u9650\u5236\u914D\u989D (-1)',\n ],\n },\n} as const;\n\n/**\n * Service Management Errors (E4xx)\n */\nexport const ServiceErrors = {\n SERVICE_NOT_RUNNING: {\n code: 'E401',\n title: 'Xray \u670D\u52A1\u672A\u8FD0\u884C',\n causes: ['\u670D\u52A1\u672A\u542F\u52A8', '\u670D\u52A1\u542F\u52A8\u540E\u5D29\u6E83', '\u914D\u7F6E\u9519\u8BEF\u5BFC\u81F4\u542F\u52A8\u5931\u8D25'],\n solutions: [\n \"\u542F\u52A8\u670D\u52A1: 'sudo systemctl start xray'\",\n \"\u67E5\u770B\u670D\u52A1\u72B6\u6001: 'sudo systemctl status xray'\",\n \"\u68C0\u67E5\u65E5\u5FD7: 'sudo journalctl -u xray -n 50'\",\n ],\n },\n SERVICE_START_FAILED: {\n code: 'E402',\n title: '\u670D\u52A1\u542F\u52A8\u5931\u8D25',\n causes: ['\u914D\u7F6E\u6587\u4EF6\u9519\u8BEF', '\u7AEF\u53E3\u88AB\u5360\u7528', '\u6743\u9650\u4E0D\u8DB3'],\n solutions: [\n \"\u9A8C\u8BC1\u914D\u7F6E: 'xray run -test -c /usr/local/etc/xray/config.json'\",\n \"\u68C0\u67E5\u7AEF\u53E3\u5360\u7528: 'ss -tlnp | grep <port>'\",\n \"\u67E5\u770B\u8BE6\u7EC6\u65E5\u5FD7: 'sudo journalctl -u xray -n 100'\",\n ],\n },\n SERVICE_STOP_FAILED: {\n code: 'E403',\n title: '\u670D\u52A1\u505C\u6B62\u5931\u8D25',\n causes: ['\u670D\u52A1\u8FDB\u7A0B\u50F5\u6B7B', '\u6743\u9650\u4E0D\u8DB3', 'systemd \u95EE\u9898'],\n solutions: [\n \"\u5F3A\u5236\u505C\u6B62: 'sudo systemctl kill xray'\",\n \"\u68C0\u67E5\u8FDB\u7A0B: 'ps aux | grep xray'\",\n \"\u624B\u52A8\u7EC8\u6B62: 'sudo kill -9 <pid>'\",\n ],\n },\n INVALID_SERVICE_NAME: {\n code: 'E404',\n title: '\u670D\u52A1\u540D\u79F0\u65E0\u6548',\n causes: ['\u5305\u542B\u975E\u6CD5\u5B57\u7B26', '\u8DEF\u5F84\u904D\u5386\u5C1D\u8BD5', '\u540D\u79F0\u4E3A\u7A7A'],\n solutions: [\n '\u670D\u52A1\u540D\u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u548C @._- \u5B57\u7B26',\n '\u9ED8\u8BA4\u670D\u52A1\u540D\u4E3A \"xray\"',\n '\u4E0D\u8981\u5728\u670D\u52A1\u540D\u4E2D\u4F7F\u7528\u8DEF\u5F84\u5206\u9694\u7B26',\n ],\n },\n SYSTEMD_NOT_AVAILABLE: {\n code: 'E405',\n title: 'systemd \u4E0D\u53EF\u7528',\n causes: ['\u7CFB\u7EDF\u672A\u4F7F\u7528 systemd', '\u5728\u5BB9\u5668\u4E2D\u8FD0\u884C', 'systemd \u670D\u52A1\u672A\u542F\u52A8'],\n solutions: [\n '\u786E\u4FDD\u7CFB\u7EDF\u4F7F\u7528 systemd \u4F5C\u4E3A init \u7CFB\u7EDF',\n \"\u68C0\u67E5 systemd \u72B6\u6001: 'systemctl --version'\",\n '\u5982\u5728\u5BB9\u5668\u4E2D\uFF0C\u9700\u624B\u52A8\u7BA1\u7406\u8FDB\u7A0B',\n ],\n },\n} as const;\n\n/**\n * Network Errors (E5xx)\n */\nexport const NetworkErrors = {\n CONNECTION_REFUSED: {\n code: 'E501',\n title: '\u8FDE\u63A5\u88AB\u62D2\u7EDD',\n causes: ['\u76EE\u6807\u670D\u52A1\u672A\u8FD0\u884C', '\u7AEF\u53E3\u672A\u5F00\u653E', '\u9632\u706B\u5899\u963B\u6B62'],\n solutions: [\n '\u68C0\u67E5\u76EE\u6807\u670D\u52A1\u662F\u5426\u8FD0\u884C',\n \"\u68C0\u67E5\u9632\u706B\u5899\u89C4\u5219: 'sudo ufw status'\",\n \"\u5F00\u653E\u7AEF\u53E3: 'sudo ufw allow <port>'\",\n ],\n },\n CONNECTION_TIMEOUT: {\n code: 'E502',\n title: '\u8FDE\u63A5\u8D85\u65F6',\n causes: ['\u7F51\u7EDC\u4E0D\u7A33\u5B9A', '\u670D\u52A1\u5668\u65E0\u54CD\u5E94', '\u9632\u706B\u5899\u4E22\u5F03\u6570\u636E\u5305'],\n solutions: ['\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5', \"\u6D4B\u8BD5\u7F51\u7EDC: 'ping <server_ip>'\", '\u68C0\u67E5\u670D\u52A1\u5668\u7AEF\u9632\u706B\u5899\u8BBE\u7F6E'],\n },\n PUBLIC_IP_FAILED: {\n code: 'E503',\n title: '\u65E0\u6CD5\u83B7\u53D6\u516C\u7F51 IP',\n causes: ['\u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898', 'IP \u68C0\u6D4B\u670D\u52A1\u4E0D\u53EF\u7528', 'DNS \u89E3\u6790\u5931\u8D25'],\n solutions: [\n \"\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5: 'curl -s https://api.ipify.org'\",\n '\u624B\u52A8\u6307\u5B9A\u670D\u52A1\u5668 IP \u5730\u5740',\n '\u68C0\u67E5 DNS \u8BBE\u7F6E',\n ],\n },\n INVALID_PORT: {\n code: 'E504',\n title: '\u7AEF\u53E3\u53F7\u65E0\u6548',\n causes: ['\u7AEF\u53E3\u53F7\u8D85\u51FA\u8303\u56F4', '\u7AEF\u53E3\u53F7\u4E0D\u662F\u6570\u5B57', '\u4F7F\u7528\u4E86\u4FDD\u7559\u7AEF\u53E3'],\n solutions: [\n '\u7AEF\u53E3\u53F7\u5FC5\u987B\u5728 1-65535 \u4E4B\u95F4',\n '\u5EFA\u8BAE\u4F7F\u7528 1024 \u4EE5\u4E0A\u7684\u7AEF\u53E3',\n '\u786E\u4FDD\u7AEF\u53E3\u672A\u88AB\u5176\u4ED6\u670D\u52A1\u5360\u7528',\n ],\n },\n PORT_IN_USE: {\n code: 'E505',\n title: '\u7AEF\u53E3\u5DF2\u88AB\u5360\u7528',\n causes: ['\u5176\u4ED6\u7A0B\u5E8F\u6B63\u5728\u4F7F\u7528\u8BE5\u7AEF\u53E3', 'Xray \u5DF2\u5728\u8FD0\u884C', '\u7CFB\u7EDF\u670D\u52A1\u5360\u7528'],\n solutions: [\n \"\u67E5\u770B\u7AEF\u53E3\u5360\u7528: 'ss -tlnp | grep <port>'\",\n '\u9009\u62E9\u5176\u4ED6\u672A\u4F7F\u7528\u7684\u7AEF\u53E3',\n '\u505C\u6B62\u5360\u7528\u7AEF\u53E3\u7684\u670D\u52A1\u540E\u91CD\u8BD5',\n ],\n },\n} as const;\n\n/**\n * File Operation Errors (E6xx)\n */\nexport const FileErrors = {\n FILE_NOT_FOUND: {\n code: 'E601',\n title: '\u6587\u4EF6\u4E0D\u5B58\u5728',\n causes: ['\u6587\u4EF6\u5DF2\u88AB\u5220\u9664', '\u8DEF\u5F84\u9519\u8BEF', '\u4ECE\u672A\u521B\u5EFA'],\n solutions: ['\u68C0\u67E5\u6587\u4EF6\u8DEF\u5F84\u662F\u5426\u6B63\u786E', '\u786E\u8BA4\u6587\u4EF6\u662F\u5426\u5DF2\u521B\u5EFA', '\u68C0\u67E5\u7236\u76EE\u5F55\u662F\u5426\u5B58\u5728'],\n },\n DIRECTORY_NOT_FOUND: {\n code: 'E602',\n title: '\u76EE\u5F55\u4E0D\u5B58\u5728',\n causes: ['\u76EE\u5F55\u5DF2\u88AB\u5220\u9664', '\u8DEF\u5F84\u9519\u8BEF', '\u7236\u76EE\u5F55\u4E0D\u5B58\u5728'],\n solutions: [\"\u521B\u5EFA\u76EE\u5F55: 'mkdir -p <path>'\", '\u68C0\u67E5\u8DEF\u5F84\u62FC\u5199', '\u786E\u4FDD\u6709\u521B\u5EFA\u76EE\u5F55\u7684\u6743\u9650'],\n },\n FILE_READ_FAILED: {\n code: 'E603',\n title: '\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25',\n causes: ['\u6743\u9650\u4E0D\u8DB3', '\u6587\u4EF6\u88AB\u9501\u5B9A', '\u6587\u4EF6\u5DF2\u635F\u574F'],\n solutions: ['\u4F7F\u7528 sudo \u8FD0\u884C', '\u68C0\u67E5\u6587\u4EF6\u662F\u5426\u88AB\u5176\u4ED6\u8FDB\u7A0B\u5360\u7528', '\u68C0\u67E5\u6587\u4EF6\u6743\u9650\u8BBE\u7F6E'],\n },\n FILE_WRITE_FAILED: {\n code: 'E604',\n title: '\u6587\u4EF6\u5199\u5165\u5931\u8D25',\n causes: ['\u6743\u9650\u4E0D\u8DB3', '\u78C1\u76D8\u7A7A\u95F4\u4E0D\u8DB3', '\u6587\u4EF6\u7CFB\u7EDF\u53EA\u8BFB'],\n solutions: ['\u4F7F\u7528 sudo \u8FD0\u884C', \"\u68C0\u67E5\u78C1\u76D8\u7A7A\u95F4: 'df -h'\", '\u68C0\u67E5\u6587\u4EF6\u7CFB\u7EDF\u6302\u8F7D\u72B6\u6001'],\n },\n} as const;\n\n/**\n * Validation Errors (E7xx)\n */\nexport const ValidationErrors = {\n REQUIRED_FIELD_EMPTY: {\n code: 'E701',\n title: '\u5FC5\u586B\u5B57\u6BB5\u4E0D\u80FD\u4E3A\u7A7A',\n causes: ['\u672A\u63D0\u4F9B\u5FC5\u8981\u7684\u8F93\u5165', '\u8F93\u5165\u53EA\u5305\u542B\u7A7A\u767D\u5B57\u7B26'],\n solutions: ['\u8BF7\u63D0\u4F9B\u6240\u6709\u5FC5\u586B\u5B57\u6BB5\u7684\u503C', '\u68C0\u67E5\u8F93\u5165\u662F\u5426\u5305\u542B\u6709\u6548\u5185\u5BB9'],\n },\n INVALID_FORMAT: {\n code: 'E702',\n title: '\u8F93\u5165\u683C\u5F0F\u4E0D\u6B63\u786E',\n causes: ['\u8F93\u5165\u4E0D\u7B26\u5408\u9884\u671F\u683C\u5F0F', '\u5305\u542B\u975E\u6CD5\u5B57\u7B26'],\n solutions: ['\u68C0\u67E5\u8F93\u5165\u683C\u5F0F\u8981\u6C42', '\u53C2\u8003\u793A\u4F8B\u8F93\u5165'],\n },\n VALUE_OUT_OF_RANGE: {\n code: 'E703',\n title: '\u503C\u8D85\u51FA\u6709\u6548\u8303\u56F4',\n causes: ['\u6570\u503C\u8FC7\u5927\u6216\u8FC7\u5C0F', '\u8D85\u51FA\u5141\u8BB8\u7684\u9650\u5236'],\n solutions: ['\u68C0\u67E5\u5141\u8BB8\u7684\u503C\u8303\u56F4', '\u4F7F\u7528\u8303\u56F4\u5185\u7684\u503C\u91CD\u8BD5'],\n },\n} as const;\n\n/**\n * VLESS/Protocol Parsing Errors (E8xx)\n */\nexport const ProtocolErrors = {\n INVALID_VLESS_LINK: {\n code: 'E801',\n title: 'VLESS \u94FE\u63A5\u683C\u5F0F\u65E0\u6548',\n causes: ['\u94FE\u63A5\u683C\u5F0F\u4E0D\u6B63\u786E', '\u4E0D\u662F vless:// \u534F\u8BAE', '\u94FE\u63A5\u4E0D\u5B8C\u6574'],\n solutions: ['\u786E\u4FDD\u94FE\u63A5\u4EE5 vless:// \u5F00\u5934', '\u68C0\u67E5\u94FE\u63A5\u662F\u5426\u5B8C\u6574\u590D\u5236', '\u9A8C\u8BC1\u94FE\u63A5\u6765\u6E90\u662F\u5426\u53EF\u9760'],\n },\n VLESS_MISSING_UUID: {\n code: 'E802',\n title: 'VLESS \u94FE\u63A5\u7F3A\u5C11 UUID',\n causes: ['\u94FE\u63A5\u683C\u5F0F\u9519\u8BEF', 'UUID \u90E8\u5206\u88AB\u622A\u65AD'],\n solutions: ['\u68C0\u67E5\u94FE\u63A5\u662F\u5426\u5B8C\u6574', '\u91CD\u65B0\u83B7\u53D6\u6B63\u786E\u7684\u5206\u4EAB\u94FE\u63A5'],\n },\n VLESS_MISSING_HOST: {\n code: 'E803',\n title: 'VLESS \u94FE\u63A5\u7F3A\u5C11\u670D\u52A1\u5668\u5730\u5740',\n causes: ['\u94FE\u63A5\u683C\u5F0F\u9519\u8BEF', '\u670D\u52A1\u5668\u5730\u5740\u90E8\u5206\u7F3A\u5931'],\n solutions: ['\u68C0\u67E5\u94FE\u63A5\u683C\u5F0F', '\u786E\u4FDD\u5305\u542B\u670D\u52A1\u5668\u5730\u5740\u548C\u7AEF\u53E3'],\n },\n VLESS_INVALID_PORT: {\n code: 'E804',\n title: 'VLESS \u94FE\u63A5\u7AEF\u53E3\u65E0\u6548',\n causes: ['\u7AEF\u53E3\u4E0D\u662F\u6570\u5B57', '\u7AEF\u53E3\u8D85\u51FA\u8303\u56F4'],\n solutions: ['\u7AEF\u53E3\u5FC5\u987B\u662F 1-65535 \u4E4B\u95F4\u7684\u6570\u5B57', '\u68C0\u67E5\u94FE\u63A5\u683C\u5F0F\u662F\u5426\u6B63\u786E'],\n },\n VLESS_MISSING_REALITY_PBK: {\n code: 'E805',\n title: 'Reality \u94FE\u63A5\u7F3A\u5C11\u516C\u94A5\u53C2\u6570',\n causes: ['\u94FE\u63A5\u7F3A\u5C11 pbk \u53C2\u6570', 'Reality \u914D\u7F6E\u4E0D\u5B8C\u6574'],\n solutions: ['Reality \u94FE\u63A5\u5FC5\u987B\u5305\u542B pbk (\u516C\u94A5) \u53C2\u6570', '\u91CD\u65B0\u751F\u6210\u5305\u542B\u5B8C\u6574\u53C2\u6570\u7684\u94FE\u63A5'],\n },\n} as const;\n\n/**\n * System/Permission Errors (E9xx)\n */\nexport const SystemErrors = {\n ROOT_REQUIRED: {\n code: 'E901',\n title: '\u9700\u8981\u7BA1\u7406\u5458\u6743\u9650',\n causes: ['\u5F53\u524D\u7528\u6237\u4E0D\u662F root', '\u672A\u4F7F\u7528 sudo \u8FD0\u884C'],\n solutions: [\"\u4F7F\u7528 sudo \u8FD0\u884C: 'sudo xray-vpn'\", \"\u5207\u6362\u5230 root \u7528\u6237: 'su -'\"],\n },\n UNSUPPORTED_OS: {\n code: 'E902',\n title: '\u4E0D\u652F\u6301\u7684\u64CD\u4F5C\u7CFB\u7EDF',\n causes: ['\u64CD\u4F5C\u7CFB\u7EDF\u4E0D\u517C\u5BB9', '\u7CFB\u7EDF\u7248\u672C\u8FC7\u4F4E'],\n solutions: [\n '\u652F\u6301\u7684\u7CFB\u7EDF: Ubuntu 18+, Debian 10+, CentOS 7+, Fedora 30+',\n '\u8003\u8651\u4F7F\u7528 Docker \u5BB9\u5668\u8FD0\u884C',\n ],\n },\n DEPENDENCY_MISSING: {\n code: 'E903',\n title: '\u7F3A\u5C11\u5FC5\u8981\u7684\u4F9D\u8D56',\n causes: ['\u7CFB\u7EDF\u5DE5\u5177\u672A\u5B89\u88C5', 'Node.js \u7248\u672C\u4E0D\u517C\u5BB9'],\n solutions: [\n '\u8FD0\u884C\u5B89\u88C5\u811A\u672C\u81EA\u52A8\u5B89\u88C5\u4F9D\u8D56',\n '\u786E\u4FDD Node.js >= 18.0.0',\n \"\u68C0\u67E5 xray \u662F\u5426\u5B89\u88C5: 'xray version'\",\n ],\n },\n PREFLIGHT_FAILED: {\n code: 'E904',\n title: '\u542F\u52A8\u9884\u68C0\u67E5\u5931\u8D25',\n causes: ['\u7CFB\u7EDF\u73AF\u5883\u4E0D\u6EE1\u8DB3\u8981\u6C42', '\u5FC5\u8981\u670D\u52A1\u672A\u8FD0\u884C', '\u914D\u7F6E\u5B58\u5728\u95EE\u9898'],\n solutions: ['\u8FD0\u884C\u8BCA\u65AD\u547D\u4EE4\u68C0\u67E5\u95EE\u9898', '\u68C0\u67E5\u4E0A\u8FF0\u9519\u8BEF\u4FE1\u606F\u5E76\u9010\u4E00\u89E3\u51B3', '\u786E\u4FDD\u6240\u6709\u5FC5\u8981\u670D\u52A1\u5DF2\u542F\u52A8'],\n },\n} as const;\n\n/**\n * Union type of all error codes\n */\nexport type ErrorCode =\n | (typeof ConfigErrors)[keyof typeof ConfigErrors]\n | (typeof UserErrors)[keyof typeof UserErrors]\n | (typeof QuotaErrors)[keyof typeof QuotaErrors]\n | (typeof ServiceErrors)[keyof typeof ServiceErrors]\n | (typeof NetworkErrors)[keyof typeof NetworkErrors]\n | (typeof FileErrors)[keyof typeof FileErrors]\n | (typeof ValidationErrors)[keyof typeof ValidationErrors]\n | (typeof ProtocolErrors)[keyof typeof ProtocolErrors]\n | (typeof SystemErrors)[keyof typeof SystemErrors];\n\n/**\n * Find error info by error code string\n */\nexport function findErrorByCode(code: string): ErrorInfo | undefined {\n const allErrors = {\n ...ConfigErrors,\n ...UserErrors,\n ...QuotaErrors,\n ...ServiceErrors,\n ...NetworkErrors,\n ...FileErrors,\n ...ValidationErrors,\n ...ProtocolErrors,\n ...SystemErrors,\n };\n\n for (const error of Object.values(allErrors)) {\n if (error.code === code) {\n return error;\n }\n }\n\n return undefined;\n}\n\n/**\n * Get all error codes list\n */\nexport function getAllErrorCodes(): string[] {\n const allErrors = {\n ...ConfigErrors,\n ...UserErrors,\n ...QuotaErrors,\n ...ServiceErrors,\n ...NetworkErrors,\n ...FileErrors,\n ...ValidationErrors,\n ...ProtocolErrors,\n ...SystemErrors,\n };\n\n return Object.values(allErrors).map((e) => e.code);\n}\n", "/**\n * \u6807\u51C6\u5316\u9000\u51FA\u4EE3\u7801\n * @module constants/exit-codes\n */\n\n/**\n * CLI \u5DE5\u5177\u9000\u51FA\u4EE3\u7801\u5E38\u91CF\n * \u9075\u5FAA Unix/Linux \u9000\u51FA\u4EE3\u7801\u89C4\u8303\n */\nexport const ExitCode = {\n /** \u6210\u529F */\n SUCCESS: 0,\n\n /** \u901A\u7528\u9519\u8BEF */\n GENERAL_ERROR: 1,\n\n /** \u53C2\u6570\u9519\u8BEF - \u65E0\u6548\u7684\u547D\u4EE4\u884C\u53C2\u6570\u6216\u9009\u9879 */\n INVALID_ARGUMENT: 2,\n\n /** \u914D\u7F6E\u9519\u8BEF - \u914D\u7F6E\u6587\u4EF6\u9519\u8BEF\u3001\u7F3A\u5931\u6216\u65E0\u6CD5\u89E3\u6790 */\n CONFIG_ERROR: 3,\n\n /** \u6743\u9650\u9519\u8BEF - \u9700\u8981 root/sudo \u6743\u9650\u4F46\u672A\u63D0\u4F9B */\n PERMISSION_ERROR: 4,\n\n /** \u670D\u52A1\u9519\u8BEF - systemd \u670D\u52A1\u64CD\u4F5C\u5931\u8D25 */\n SERVICE_ERROR: 5,\n\n /** \u7F51\u7EDC\u9519\u8BEF - \u7F51\u7EDC\u8FDE\u63A5\u5931\u8D25\u6216\u8D85\u65F6 */\n NETWORK_ERROR: 6,\n\n /** \u6587\u4EF6\u9519\u8BEF - \u6587\u4EF6\u8BFB\u5199\u64CD\u4F5C\u5931\u8D25 */\n FILE_ERROR: 7,\n\n /** \u9A8C\u8BC1\u9519\u8BEF - \u8F93\u5165\u9A8C\u8BC1\u5931\u8D25\uFF08\u90AE\u7BB1\u3001UUID \u7B49\uFF09 */\n VALIDATION_ERROR: 8,\n\n /** \u672A\u627E\u5230 - \u8D44\u6E90\u4E0D\u5B58\u5728\uFF08\u7528\u6237\u3001\u670D\u52A1\u7B49\uFF09 */\n NOT_FOUND: 9,\n\n /** \u7528\u6237\u4E2D\u65AD - Ctrl+C \u4E2D\u65AD\u7A0B\u5E8F\u6267\u884C */\n SIGINT: 130,\n} as const;\n\n/**\n * \u9000\u51FA\u4EE3\u7801\u7C7B\u578B\n */\nexport type ExitCodeType = (typeof ExitCode)[keyof typeof ExitCode];\n\n/**\n * \u9000\u51FA\u4EE3\u7801\u5230\u63CF\u8FF0\u7684\u6620\u5C04\n */\nexport const ExitCodeDescription: Record<number, string> = {\n [ExitCode.SUCCESS]: '\u6210\u529F',\n [ExitCode.GENERAL_ERROR]: '\u901A\u7528\u9519\u8BEF',\n [ExitCode.INVALID_ARGUMENT]: '\u53C2\u6570\u9519\u8BEF',\n [ExitCode.CONFIG_ERROR]: '\u914D\u7F6E\u9519\u8BEF',\n [ExitCode.PERMISSION_ERROR]: '\u6743\u9650\u4E0D\u8DB3',\n [ExitCode.SERVICE_ERROR]: '\u670D\u52A1\u64CD\u4F5C\u5931\u8D25',\n [ExitCode.NETWORK_ERROR]: '\u7F51\u7EDC\u9519\u8BEF',\n [ExitCode.FILE_ERROR]: '\u6587\u4EF6\u9519\u8BEF',\n [ExitCode.VALIDATION_ERROR]: '\u8F93\u5165\u9A8C\u8BC1\u5931\u8D25',\n [ExitCode.NOT_FOUND]: '\u8D44\u6E90\u672A\u627E\u5230',\n [ExitCode.SIGINT]: '\u7528\u6237\u4E2D\u65AD',\n};\n\n/**\n * \u6839\u636E\u9519\u8BEF\u7C7B\u578B\u83B7\u53D6\u9000\u51FA\u4EE3\u7801\n */\nexport function getExitCodeForError(error: Error): ExitCodeType {\n const errorName = error.name.toLowerCase();\n const errorMessage = error.message.toLowerCase();\n\n // \u6839\u636E\u9519\u8BEF\u540D\u79F0\u6216\u6D88\u606F\u5224\u65AD\u9000\u51FA\u4EE3\u7801\n if (errorName.includes('permission') || errorMessage.includes('eacces')) {\n return ExitCode.PERMISSION_ERROR;\n }\n if (errorName.includes('validation') || errorMessage.includes('invalid')) {\n return ExitCode.VALIDATION_ERROR;\n }\n if (errorName.includes('notfound') || errorMessage.includes('not found')) {\n return ExitCode.NOT_FOUND;\n }\n if (errorName.includes('config') || errorMessage.includes('config')) {\n return ExitCode.CONFIG_ERROR;\n }\n if (errorName.includes('service') || errorMessage.includes('systemctl')) {\n return ExitCode.SERVICE_ERROR;\n }\n if (errorName.includes('file') || errorMessage.includes('enoent')) {\n return ExitCode.FILE_ERROR;\n }\n if (errorName.includes('network') || errorMessage.includes('timeout')) {\n return ExitCode.NETWORK_ERROR;\n }\n\n return ExitCode.GENERAL_ERROR;\n}\n\n/**\n * \u4F18\u96C5\u9000\u51FA\uFF08\u6E05\u7406\u8D44\u6E90\u540E\u9000\u51FA\uFF09\n */\nexport async function gracefulExit(\n code: ExitCodeType,\n cleanup?: () => Promise<void>\n): Promise<never> {\n try {\n if (cleanup) {\n await cleanup();\n }\n } catch (error) {\n console.error('\u6E05\u7406\u8D44\u6E90\u65F6\u51FA\u9519:', error);\n } finally {\n process.exit(code);\n }\n}\n", "/**\n * Preflight Checks Utility\n *\n * Performs system checks before starting the CLI tool\n *\n * @module utils/preflight\n */\n\nimport { spawn } from 'child_process';\nimport { access, constants as fsConstants } from 'fs/promises';\nimport { DEFAULT_PATHS } from '../constants/paths';\nimport { TIMEOUTS } from '../constants/timeouts';\n\n/**\n * Preflight check options\n */\nexport interface PreflightOptions {\n /** Check if systemd is available */\n checkSystemd?: boolean;\n\n /** Check if Xray binary exists */\n checkXray?: boolean;\n\n /** Check if config file exists and is readable */\n checkConfig?: boolean;\n\n /** Config file path (if checking) */\n configPath?: string;\n\n /** Service name (if checking) */\n serviceName?: string;\n}\n\n/**\n * Preflight check result\n */\nexport interface PreflightResult {\n /** Overall passed status */\n passed: boolean;\n\n /** Whether failures are critical (should prevent startup) */\n critical: boolean;\n\n /** List of errors */\n errors: string[];\n\n /** List of warnings */\n warnings: string[];\n\n /** Suggestions for fixing issues */\n suggestions: string[];\n\n /** Individual check results */\n checks: {\n systemd?: boolean;\n xray?: boolean;\n config?: boolean;\n permissions?: boolean;\n };\n}\n\n/**\n * Check if systemd is available\n */\nasync function checkSystemd(): Promise<{ passed: boolean; error?: string }> {\n return new Promise((resolve) => {\n const child = spawn('systemctl', ['--version'], {\n timeout: TIMEOUTS.SYSTEMCTL_DEFAULT,\n });\n\n let stdout = '';\n\n child.stdout?.on('data', (data) => {\n stdout += data.toString();\n });\n\n child.on('close', (code) => {\n if (code === 0 && stdout.includes('systemd')) {\n resolve({ passed: true });\n } else {\n resolve({\n passed: false,\n error: 'systemd \u4E0D\u53EF\u7528 - \u6B64\u5DE5\u5177\u9700\u8981\u5728 systemd \u7CFB\u7EDF\u4E0A\u8FD0\u884C',\n });\n }\n });\n\n child.on('error', (error) => {\n resolve({\n passed: false,\n error: `systemd \u68C0\u67E5\u5931\u8D25: ${error.message}`,\n });\n });\n });\n}\n\n/**\n * Check if Xray binary exists and is executable\n */\nasync function checkXray(\n path: string = DEFAULT_PATHS.XRAY_BINARY\n): Promise<{ passed: boolean; error?: string; warning?: string }> {\n try {\n // Check if file exists and is executable\n await access(path, fsConstants.F_OK | fsConstants.X_OK);\n return { passed: true };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n passed: false,\n warning: `Xray \u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u5B58\u5728: ${path}`,\n };\n } else if ((error as NodeJS.ErrnoException).code === 'EACCES') {\n return {\n passed: false,\n error: `Xray \u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u53EF\u6267\u884C: ${path}`,\n };\n } else {\n return {\n passed: false,\n warning: `Xray \u4E8C\u8FDB\u5236\u6587\u4EF6\u68C0\u67E5\u5931\u8D25: ${(error as Error).message}`,\n };\n }\n }\n}\n\n/**\n * Check if config file exists and is readable\n */\nasync function checkConfig(\n path: string = DEFAULT_PATHS.CONFIG_FILE\n): Promise<{ passed: boolean; error?: string; warning?: string }> {\n try {\n // Check if file exists and is readable\n await access(path, fsConstants.F_OK | fsConstants.R_OK);\n\n // Verify it's a JSON file\n if (!path.endsWith('.json')) {\n return {\n passed: false,\n warning: `\u914D\u7F6E\u6587\u4EF6\u5E94\u4E3A JSON \u683C\u5F0F: ${path}`,\n };\n }\n\n return { passed: true };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n passed: false,\n warning: `\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728: ${path}`,\n };\n } else if ((error as NodeJS.ErrnoException).code === 'EACCES') {\n return {\n passed: false,\n error: `\u914D\u7F6E\u6587\u4EF6\u4E0D\u53EF\u8BFB: ${path}`,\n };\n } else {\n return {\n passed: false,\n warning: `\u914D\u7F6E\u6587\u4EF6\u68C0\u67E5\u5931\u8D25: ${(error as Error).message}`,\n };\n }\n }\n}\n\n/**\n * Check if current user has necessary permissions\n */\nfunction checkPermissions(): { passed: boolean; warning?: string } {\n const isRoot = process.getuid && process.getuid() === 0;\n\n if (isRoot) {\n return { passed: true };\n }\n\n // Check if sudo is available\n return {\n passed: true,\n warning: 'Not running as root - some operations may require sudo',\n };\n}\n\n/**\n * Perform all preflight checks\n */\nexport async function preflightChecks(options: PreflightOptions = {}): Promise<PreflightResult> {\n const result: PreflightResult = {\n passed: true,\n critical: false,\n errors: [],\n warnings: [],\n suggestions: [],\n checks: {},\n };\n\n // Check systemd\n if (options.checkSystemd !== false) {\n const systemdResult = await checkSystemd();\n result.checks.systemd = systemdResult.passed;\n\n if (!systemdResult.passed) {\n result.passed = false;\n result.critical = true;\n if (systemdResult.error) {\n result.errors.push(systemdResult.error);\n result.suggestions.push(\n '\u786E\u4FDD\u5728\u652F\u6301 systemd \u7684 Linux \u53D1\u884C\u7248\u4E0A\u8FD0\u884C (Debian 10+, Ubuntu 20.04+, CentOS 8+)'\n );\n }\n }\n }\n\n // Check Xray binary\n if (options.checkXray) {\n const xrayResult = await checkXray();\n result.checks.xray = xrayResult.passed;\n\n if (!xrayResult.passed) {\n result.passed = false;\n\n if (xrayResult.error) {\n result.errors.push(xrayResult.error);\n result.suggestions.push(\n `\u4FEE\u590D Xray \u4E8C\u8FDB\u5236\u6587\u4EF6\u6743\u9650: sudo chmod +x ${DEFAULT_PATHS.XRAY_BINARY}`\n );\n } else if (xrayResult.warning) {\n result.warnings.push(xrayResult.warning);\n result.suggestions.push(`\u5B89\u88C5 Xray: https://github.com/XTLS/Xray-install`);\n }\n }\n }\n\n // Check config file\n if (options.checkConfig) {\n const configPath = options.configPath || DEFAULT_PATHS.CONFIG_FILE;\n const configResult = await checkConfig(configPath);\n result.checks.config = configResult.passed;\n\n if (!configResult.passed) {\n result.passed = false;\n\n if (configResult.error) {\n result.errors.push(configResult.error);\n result.suggestions.push(`\u4FEE\u590D\u914D\u7F6E\u6587\u4EF6\u6743\u9650: sudo chmod 600 ${configPath}`);\n } else if (configResult.warning) {\n result.warnings.push(configResult.warning);\n result.suggestions.push(`\u521B\u5EFA\u914D\u7F6E\u6587\u4EF6: sudo touch ${configPath}`);\n }\n }\n }\n\n // Check permissions\n const permResult = checkPermissions();\n result.checks.permissions = permResult.passed;\n\n if (permResult.warning) {\n result.warnings.push(permResult.warning);\n }\n\n return result;\n}\n\n/**\n * Check if running as root\n */\nexport function isRoot(): boolean {\n return !!(process.getuid && process.getuid() === 0);\n}\n\n/**\n * Check if sudo is available\n */\nexport async function canUseSudo(): Promise<boolean> {\n return new Promise((resolve) => {\n const child = spawn('which', ['sudo']);\n\n child.on('close', (code) => {\n resolve(code === 0);\n });\n\n child.on('error', () => {\n resolve(false);\n });\n });\n}\n", "/**\n * \u8DEF\u5F84\u5E38\u91CF\u5B9A\u4E49\n * @module constants/paths\n */\n\nimport { homedir } from 'os';\nimport { join } from 'path';\n\n/**\n * \u9ED8\u8BA4\u8DEF\u5F84\u914D\u7F6E\n */\nexport const DEFAULT_PATHS = {\n /** Xray \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84 */\n CONFIG_FILE: '/usr/local/etc/xray/config.json',\n\n /** Xray \u914D\u7F6E\u76EE\u5F55 */\n CONFIG_DIR: '/usr/local/etc/xray',\n\n /** \u914D\u7F6E\u5907\u4EFD\u76EE\u5F55 */\n BACKUP_DIR: '/var/backups/xray',\n\n /** systemd \u670D\u52A1\u540D\u79F0 */\n SERVICE_NAME: 'xray',\n\n /** systemd \u670D\u52A1\u6587\u4EF6\u8DEF\u5F84 */\n SERVICE_FILE: '/etc/systemd/system/xray.service',\n\n /** Xray \u53EF\u6267\u884C\u6587\u4EF6\u8DEF\u5F84 */\n XRAY_BINARY: '/usr/local/bin/xray',\n\n /** \u65E5\u5FD7\u76EE\u5F55\uFF08\u5982\u679C\u4F7F\u7528\u6587\u4EF6\u65E5\u5FD7\uFF09 */\n LOG_DIR: '/var/log/xray',\n\n /** \u8BBF\u95EE\u65E5\u5FD7\u6587\u4EF6 */\n ACCESS_LOG: '/var/log/xray/access.log',\n\n /** \u9519\u8BEF\u65E5\u5FD7\u6587\u4EF6 */\n ERROR_LOG: '/var/log/xray/error.log',\n\n /** \u4E34\u65F6\u6587\u4EF6\u76EE\u5F55 */\n TEMP_DIR: '/tmp/xray-manager',\n\n /** \u7528\u6237\u914D\u7F6E\u76EE\u5F55\uFF08~/.xray-manager\uFF09 */\n USER_CONFIG_DIR: join(homedir(), '.xray-manager'),\n\n /** \u7528\u6237\u914D\u7F6E\u6587\u4EF6 */\n USER_CONFIG_FILE: join(homedir(), '.xray-manager', 'config.json'),\n\n /** Clash \u914D\u7F6E\u6587\u4EF6\uFF08\u9ED8\u8BA4\u8F93\u51FA\uFF09 */\n CLASH_CONFIG_FILE: join(homedir(), 'clash-config-v3.yaml'),\n\n /** \u670D\u52A1\u5668\u914D\u7F6E\u6587\u4EF6\uFF08\u516C\u7F51 IP \u7B49\uFF09 */\n SERVER_CONFIG_FILE: '/usr/local/etc/xray/server-config.json',\n\n /** \u7528\u6237\u5143\u6570\u636E\u6587\u4EF6\uFF08\u521B\u5EFA\u65F6\u95F4\u3001\u72B6\u6001\u7B49\uFF09 */\n USER_METADATA_FILE: '/usr/local/etc/xray/user-metadata.json',\n} as const;\n\n/**\n * \u8DEF\u5F84\u9A8C\u8BC1\u89C4\u5219\n */\nexport const PATH_VALIDATION = {\n /** \u914D\u7F6E\u6587\u4EF6\u5FC5\u987B\u4EE5 .json \u7ED3\u5C3E */\n CONFIG_FILE_EXTENSION: '.json',\n\n /** \u5907\u4EFD\u6587\u4EF6\u547D\u540D\u683C\u5F0F */\n BACKUP_FILE_PATTERN: /^config\\.\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}\\.\\d{3}Z\\.json$/,\n\n /** \u6700\u5927\u8DEF\u5F84\u957F\u5EA6 */\n MAX_PATH_LENGTH: 4096,\n} as const;\n\n/**\n * \u5907\u4EFD\u6587\u4EF6\u540D\u751F\u6210\n */\nexport function getBackupFileName(timestamp: Date = new Date()): string {\n const isoString = timestamp.toISOString().replace(/:/g, '-');\n return `config.${isoString}.json`;\n}\n\n/**\n * \u83B7\u53D6\u5B8C\u6574\u5907\u4EFD\u8DEF\u5F84\n */\nexport function getBackupFilePath(timestamp?: Date): string {\n return join(DEFAULT_PATHS.BACKUP_DIR, getBackupFileName(timestamp));\n}\n\n/**\n * \u68C0\u67E5\u8DEF\u5F84\u662F\u5426\u4E3A\u5907\u4EFD\u6587\u4EF6\n */\nexport function isBackupFile(filename: string): boolean {\n return PATH_VALIDATION.BACKUP_FILE_PATTERN.test(filename);\n}\n", "/**\n * Review constants and enums\n *\n * @module constants/review\n */\n\nimport type {\n AssessmentStatus,\n OutputFormat,\n ReviewPriority,\n ReviewTimeHorizon,\n} from '../types/review';\n\nexport const REVIEW_PRIORITIES: readonly ReviewPriority[] = ['high', 'medium', 'low'];\nexport const REVIEW_TIME_HORIZONS: readonly ReviewTimeHorizon[] = ['quick', 'long-term'];\nexport const REVIEW_STATUSES: readonly AssessmentStatus[] = [\n 'good',\n 'needs-improvement',\n 'missing',\n];\nexport const REVIEW_FORMATS: readonly OutputFormat[] = ['markdown', 'json'];\n\nexport const REVIEW_AREA_IDS = [\n 'documentation',\n 'license',\n 'contribution',\n 'quality',\n 'community',\n 'security',\n] as const;\nexport type ReviewAreaId = (typeof REVIEW_AREA_IDS)[number];\n\nexport const REVIEW_AREA_LABELS: Record<ReviewAreaId, string> = {\n documentation: 'Documentation',\n license: 'License',\n contribution: 'Contribution',\n quality: 'Quality',\n community: 'Community',\n security: 'Security',\n};\n", "/**\n * Review identifiers and timestamps\n *\n * @module utils/review-id\n */\n\nimport { randomUUID } from 'crypto';\n\nexport function createReviewId(): string {\n return `review_${randomUUID()}`;\n}\n\nexport function getIsoTimestamp(date: Date = new Date()): string {\n return date.toISOString();\n}\n", "/**\n * Repository scanning service\n *\n * @module services/review/repo-scanner\n */\n\nimport { access, constants as fsConstants } from 'fs/promises';\nimport { scanRepository, type RepoScanResult } from '../../utils/repo-scan';\n\nexport async function runRepoScan(repoPath: string): Promise<RepoScanResult> {\n await access(repoPath, fsConstants.R_OK);\n return scanRepository(repoPath);\n}\n", "/**\n * Repository scanning helpers (read-only)\n *\n * @module utils/repo-scan\n */\n\nimport { readdir, readFile, stat } from 'fs/promises';\nimport path from 'path';\n\nexport interface RepoScanResult {\n repoPath: string;\n files: {\n readme?: string;\n license?: string;\n contributing?: string;\n codeOfConduct?: string;\n security?: string;\n changelog?: string;\n packageJson?: string;\n pullRequestTemplate?: string;\n maintainers?: string;\n roadmap?: string;\n };\n content: {\n readme?: string;\n license?: string;\n contributing?: string;\n codeOfConduct?: string;\n security?: string;\n changelog?: string;\n };\n directories: {\n docs?: string;\n tests?: string;\n examples?: string;\n github?: string;\n workflows?: string;\n issueTemplates?: string;\n };\n signals: {\n hasReadme: boolean;\n hasLicense: boolean;\n hasContributing: boolean;\n hasCodeOfConduct: boolean;\n hasSecurityPolicy: boolean;\n hasChangelog: boolean;\n hasTests: boolean;\n hasDocs: boolean;\n hasExamples: boolean;\n hasGithubActions: boolean;\n hasIssueTemplates: boolean;\n hasPullRequestTemplate: boolean;\n hasMaintainers: boolean;\n hasRoadmap: boolean;\n };\n}\n\nconst SEARCH_DIRS = ['.', '.github', 'docs'];\n\nfunction normalizeName(name: string): string {\n return name.toLowerCase();\n}\n\nasync function safeReadDir(dirPath: string): Promise<string[]> {\n try {\n const entries = await readdir(dirPath, { withFileTypes: true });\n return entries.map((entry) => entry.name);\n } catch {\n return [];\n }\n}\n\nasync function safeStat(targetPath: string): Promise<ReturnType<typeof stat> | null> {\n try {\n return await stat(targetPath);\n } catch {\n return null;\n }\n}\n\nasync function safeReadFile(targetPath: string): Promise<string | undefined> {\n try {\n return await readFile(targetPath, 'utf-8');\n } catch {\n return undefined;\n }\n}\n\nasync function findFileInDirs(repoPath: string, names: string[]): Promise<string | undefined> {\n const normalized = names.map(normalizeName);\n\n for (const dir of SEARCH_DIRS) {\n const searchDir = path.join(repoPath, dir);\n const entries = await safeReadDir(searchDir);\n\n for (const entry of entries) {\n if (normalized.includes(normalizeName(entry))) {\n return path.join(searchDir, entry);\n }\n }\n }\n\n return undefined;\n}\n\nasync function directoryExists(repoPath: string, dirName: string): Promise<string | undefined> {\n const target = path.join(repoPath, dirName);\n const info = await safeStat(target);\n if (info && info.isDirectory()) {\n return target;\n }\n return undefined;\n}\n\nasync function hasAnyFiles(dirPath: string, extensions: string[]): Promise<boolean> {\n const entries = await safeReadDir(dirPath);\n const normalized = extensions.map(normalizeName);\n return entries.some((entry) => normalized.some((ext) => normalizeName(entry).endsWith(ext)));\n}\n\nasync function findPullRequestTemplate(repoPath: string): Promise<string | undefined> {\n const candidates = ['PULL_REQUEST_TEMPLATE.md', 'pull_request_template.md'];\n\n for (const dir of ['.', '.github', 'docs']) {\n const searchDir = path.join(repoPath, dir);\n const entries = await safeReadDir(searchDir);\n for (const entry of entries) {\n if (candidates.includes(entry)) {\n return path.join(searchDir, entry);\n }\n }\n }\n\n return undefined;\n}\n\nexport async function scanRepository(repoPath: string): Promise<RepoScanResult> {\n const resolvedRepoPath = path.resolve(repoPath);\n const repoInfo = await safeStat(resolvedRepoPath);\n if (!repoInfo || !repoInfo.isDirectory()) {\n throw new Error(`Repository path is not a directory: ${resolvedRepoPath}`);\n }\n\n const readmePath = await findFileInDirs(resolvedRepoPath, ['README.md', 'README']);\n const licensePath = await findFileInDirs(resolvedRepoPath, ['LICENSE', 'LICENSE.md', 'COPYING']);\n const contributingPath = await findFileInDirs(resolvedRepoPath, [\n 'CONTRIBUTING.md',\n 'CONTRIBUTING',\n ]);\n const codeOfConductPath = await findFileInDirs(resolvedRepoPath, [\n 'CODE_OF_CONDUCT.md',\n 'CODE_OF_CONDUCT',\n ]);\n const securityPath = await findFileInDirs(resolvedRepoPath, ['SECURITY.md']);\n const changelogPath = await findFileInDirs(resolvedRepoPath, ['CHANGELOG.md', 'CHANGELOG']);\n const packageJsonPath = await findFileInDirs(resolvedRepoPath, ['package.json']);\n const maintainersPath = await findFileInDirs(resolvedRepoPath, ['MAINTAINERS.md', 'MAINTAINERS']);\n const roadmapPath = await findFileInDirs(resolvedRepoPath, ['ROADMAP.md', 'ROADMAP']);\n\n const docsDir = await directoryExists(resolvedRepoPath, 'docs');\n const testsDir =\n (await directoryExists(resolvedRepoPath, 'tests')) ||\n (await directoryExists(resolvedRepoPath, '__tests__'));\n const examplesDir = await directoryExists(resolvedRepoPath, 'examples');\n const githubDir = await directoryExists(resolvedRepoPath, '.github');\n const workflowsDir = githubDir ? await directoryExists(githubDir, 'workflows') : undefined;\n const issueTemplatesDir = githubDir\n ? await directoryExists(githubDir, 'ISSUE_TEMPLATE')\n : undefined;\n const pullRequestTemplate = await findPullRequestTemplate(resolvedRepoPath);\n\n const hasGithubActions = workflowsDir\n ? await hasAnyFiles(workflowsDir, ['.yml', '.yaml'])\n : false;\n\n const content = {\n readme: readmePath ? await safeReadFile(readmePath) : undefined,\n license: licensePath ? await safeReadFile(licensePath) : undefined,\n contributing: contributingPath ? await safeReadFile(contributingPath) : undefined,\n codeOfConduct: codeOfConductPath ? await safeReadFile(codeOfConductPath) : undefined,\n security: securityPath ? await safeReadFile(securityPath) : undefined,\n changelog: changelogPath ? await safeReadFile(changelogPath) : undefined,\n };\n\n return {\n repoPath: resolvedRepoPath,\n files: {\n readme: readmePath,\n license: licensePath,\n contributing: contributingPath,\n codeOfConduct: codeOfConductPath,\n security: securityPath,\n changelog: changelogPath,\n packageJson: packageJsonPath,\n pullRequestTemplate,\n maintainers: maintainersPath,\n roadmap: roadmapPath,\n },\n content,\n directories: {\n docs: docsDir,\n tests: testsDir,\n examples: examplesDir,\n github: githubDir,\n workflows: workflowsDir,\n issueTemplates: issueTemplatesDir,\n },\n signals: {\n hasReadme: Boolean(readmePath),\n hasLicense: Boolean(licensePath),\n hasContributing: Boolean(contributingPath),\n hasCodeOfConduct: Boolean(codeOfConductPath),\n hasSecurityPolicy: Boolean(securityPath),\n hasChangelog: Boolean(changelogPath),\n hasTests: Boolean(testsDir),\n hasDocs: Boolean(docsDir),\n hasExamples: Boolean(examplesDir),\n hasGithubActions: Boolean(hasGithubActions),\n hasIssueTemplates: Boolean(issueTemplatesDir),\n hasPullRequestTemplate: Boolean(pullRequestTemplate),\n hasMaintainers: Boolean(maintainersPath),\n hasRoadmap: Boolean(roadmapPath),\n },\n };\n}\n", "/**\n * Summary builder for review reports\n *\n * @module services/review/summary-builder\n */\n\nimport type { AssessmentArea, Recommendation, Summary } from '../../types/review';\n\nexport function buildSummary(areas: AssessmentArea[], recommendations: Recommendation[]): Summary {\n const highPriority = recommendations.filter((rec) => rec.priority === 'high');\n const quickWins = recommendations.filter((rec) => rec.timeHorizon === 'quick');\n\n const headline =\n highPriority.length > 0\n ? 'High priority improvements are needed.'\n : 'No high priority risks detected.';\n\n const riskNotes = highPriority.slice(0, 3).map((rec) => rec.riskIfIgnored);\n if (riskNotes.length === 0 && recommendations.length > 0) {\n riskNotes.push(recommendations[0].riskIfIgnored);\n }\n\n return {\n headline,\n highPriorityCount: highPriority.length,\n quickWinsCount: quickWins.length,\n riskNotes,\n };\n}\n", "/**\n * Evidence helpers for review reports\n *\n * @module services/review/evidence\n */\n\nimport path from 'path';\nimport type { EvidenceReference } from '../../types/review';\n\nfunction toRelativePath(repoPath: string, targetPath: string): string {\n const relative = path.relative(repoPath, targetPath);\n return relative.length > 0 ? relative : '.';\n}\n\nexport function fileEvidence(\n repoPath: string,\n targetPath: string,\n notes?: string\n): EvidenceReference {\n return {\n type: 'file',\n target: toRelativePath(repoPath, targetPath),\n notes,\n };\n}\n\nexport function pathEvidence(\n repoPath: string,\n targetPath: string,\n notes?: string\n): EvidenceReference {\n return {\n type: 'path',\n target: toRelativePath(repoPath, targetPath),\n notes,\n };\n}\n\nexport function missingEvidence(label: string, notes?: string): EvidenceReference {\n return {\n type: 'missing',\n target: label,\n notes,\n };\n}\n", "/**\n * Community area evaluation\n *\n * @module services/review/areas/community\n */\n\nimport { type AreaEvaluation } from '../review-engine';\nimport type { RepoScanResult } from '../../../utils/repo-scan';\nimport { fileEvidence, missingEvidence } from '../evidence';\n\nexport function evaluateCommunity(scan: RepoScanResult): AreaEvaluation {\n const findings: AreaEvaluation['findings'] = [];\n const recommendations: AreaEvaluation['recommendations'] = [];\n\n if (!scan.signals.hasMaintainers) {\n recommendations.push({\n areaId: 'community',\n title: 'Document maintainers and support cadence',\n details: 'Provide a MAINTAINERS file or similar guidance on support expectations.',\n priority: 'medium',\n timeHorizon: 'long-term',\n riskIfIgnored: 'Users may not know where to seek support or how active maintenance is.',\n evidence: [missingEvidence('MAINTAINERS.md missing')],\n });\n } else if (scan.files.maintainers) {\n findings.push({\n areaId: 'community',\n title: 'Maintainers guidance present',\n details: 'Maintainers or support expectations are documented.',\n evidence: [fileEvidence(scan.repoPath, scan.files.maintainers)],\n });\n }\n\n if (!scan.signals.hasRoadmap) {\n recommendations.push({\n areaId: 'community',\n title: 'Publish a lightweight roadmap',\n details: 'Add a ROADMAP file to communicate future direction and release cadence.',\n priority: 'low',\n timeHorizon: 'long-term',\n riskIfIgnored: 'Community members may not know what is planned or prioritized.',\n evidence: [missingEvidence('ROADMAP.md missing')],\n });\n } else if (scan.files.roadmap) {\n findings.push({\n areaId: 'community',\n title: 'Roadmap present',\n details: 'A roadmap exists to communicate future plans.',\n evidence: [fileEvidence(scan.repoPath, scan.files.roadmap)],\n });\n }\n\n const status = recommendations.length > 0 ? 'needs-improvement' : 'good';\n\n return {\n areaId: 'community',\n status,\n findings,\n recommendations,\n };\n}\n", "/**\n * Contribution area evaluation\n *\n * @module services/review/areas/contribution\n */\n\nimport { type AreaEvaluation } from '../review-engine';\nimport type { RepoScanResult } from '../../../utils/repo-scan';\nimport { fileEvidence, missingEvidence, pathEvidence } from '../evidence';\n\nexport function evaluateContribution(scan: RepoScanResult): AreaEvaluation {\n const findings: AreaEvaluation['findings'] = [];\n const recommendations: AreaEvaluation['recommendations'] = [];\n\n if (!scan.files.contributing) {\n findings.push({\n areaId: 'contribution',\n title: 'CONTRIBUTING guide missing',\n details: 'No contribution guide found for new contributors.',\n evidence: [missingEvidence('CONTRIBUTING.md missing')],\n });\n recommendations.push({\n areaId: 'contribution',\n title: 'Add a contribution guide',\n details: 'Document contribution workflow, coding standards, and review expectations.',\n priority: 'high',\n timeHorizon: 'quick',\n riskIfIgnored: 'Contributors may abandon PRs due to unclear expectations.',\n evidence: [missingEvidence('CONTRIBUTING.md missing')],\n });\n } else {\n findings.push({\n areaId: 'contribution',\n title: 'Contribution guide present',\n details: 'A CONTRIBUTING file exists for contributors.',\n evidence: [fileEvidence(scan.repoPath, scan.files.contributing)],\n });\n }\n\n if (!scan.files.codeOfConduct) {\n recommendations.push({\n areaId: 'contribution',\n title: 'Add a code of conduct',\n details: 'Include a CODE_OF_CONDUCT file to set community expectations.',\n priority: 'medium',\n timeHorizon: 'quick',\n riskIfIgnored: 'Lack of conduct guidance can hinder community trust.',\n evidence: [missingEvidence('CODE_OF_CONDUCT.md missing')],\n });\n } else {\n findings.push({\n areaId: 'contribution',\n title: 'Code of conduct present',\n details: 'A code of conduct is available for community guidelines.',\n evidence: [fileEvidence(scan.repoPath, scan.files.codeOfConduct)],\n });\n }\n\n if (!scan.directories.issueTemplates) {\n recommendations.push({\n areaId: 'contribution',\n title: 'Provide issue templates',\n details: 'Add GitHub issue templates to standardize bug reports and feature requests.',\n priority: 'low',\n timeHorizon: 'long-term',\n riskIfIgnored: 'Issues may lack critical details and slow triage.',\n evidence: [missingEvidence('.github/ISSUE_TEMPLATE missing')],\n });\n } else {\n findings.push({\n areaId: 'contribution',\n title: 'Issue templates available',\n details: 'Issue templates are configured in the repository.',\n evidence: [pathEvidence(scan.repoPath, scan.directories.issueTemplates)],\n });\n }\n\n if (!scan.files.pullRequestTemplate) {\n recommendations.push({\n areaId: 'contribution',\n title: 'Add a pull request template',\n details: 'Provide a PR template to guide contributors through required context and testing.',\n priority: 'low',\n timeHorizon: 'long-term',\n riskIfIgnored: 'Pull requests may omit critical context or validation steps.',\n evidence: [missingEvidence('Pull request template missing')],\n });\n } else {\n findings.push({\n areaId: 'contribution',\n title: 'Pull request template present',\n details: 'A pull request template is available for contributors.',\n evidence: [fileEvidence(scan.repoPath, scan.files.pullRequestTemplate)],\n });\n }\n\n const status =\n !scan.files.contributing && !scan.files.codeOfConduct\n ? 'missing'\n : recommendations.length > 0\n ? 'needs-improvement'\n : 'good';\n\n return {\n areaId: 'contribution',\n status,\n findings,\n recommendations,\n };\n}\n", "/**\n * Documentation area evaluation\n *\n * @module services/review/areas/documentation\n */\n\nimport { type AreaEvaluation } from '../review-engine';\nimport type { RepoScanResult } from '../../../utils/repo-scan';\nimport { fileEvidence, missingEvidence, pathEvidence } from '../evidence';\n\nfunction hasKeyword(content: string | undefined, keyword: string): boolean {\n if (!content) {\n return false;\n }\n return content.toLowerCase().includes(keyword.toLowerCase());\n}\n\nexport function evaluateDocumentation(scan: RepoScanResult): AreaEvaluation {\n const findings: AreaEvaluation['findings'] = [];\n const recommendations: AreaEvaluation['recommendations'] = [];\n\n if (!scan.files.readme) {\n findings.push({\n areaId: 'documentation',\n title: 'README not found',\n details: 'The repository does not include a README file at the root or docs directories.',\n evidence: [missingEvidence('README.md missing')],\n });\n recommendations.push({\n areaId: 'documentation',\n title: 'Add a README with install and usage guidance',\n details: 'Provide a primary README with installation steps, usage examples, and scope.',\n priority: 'high',\n timeHorizon: 'quick',\n riskIfIgnored: 'Users and contributors will struggle to understand how to use the project.',\n evidence: [missingEvidence('README.md missing')],\n });\n } else {\n findings.push({\n areaId: 'documentation',\n title: 'README present',\n details: 'A README file is present and can be used as the primary entry point.',\n evidence: [fileEvidence(scan.repoPath, scan.files.readme)],\n });\n\n const hasInstall = hasKeyword(scan.content.readme, 'install');\n const hasUsage = hasKeyword(scan.content.readme, 'usage');\n const hasContributing =\n hasKeyword(scan.content.readme, 'contributing') ||\n hasKeyword(scan.content.readme, 'contribute');\n\n if (!hasInstall || !hasUsage) {\n const missingParts = [!hasInstall ? 'installation' : null, !hasUsage ? 'usage' : null]\n .filter((part): part is string => Boolean(part))\n .join(' and ');\n findings.push({\n areaId: 'documentation',\n title: 'README missing key sections',\n details: `README lacks clear ${missingParts} guidance.`,\n evidence: [fileEvidence(scan.repoPath, scan.files.readme)],\n });\n recommendations.push({\n areaId: 'documentation',\n title: 'Expand README with installation and usage sections',\n details:\n 'Add concise installation steps and usage examples so new users can start quickly.',\n priority: 'medium',\n timeHorizon: 'quick',\n riskIfIgnored: 'Adoption and onboarding will remain slow and support load will increase.',\n evidence: [fileEvidence(scan.repoPath, scan.files.readme)],\n });\n }\n\n if (!hasContributing) {\n recommendations.push({\n areaId: 'documentation',\n title: 'Link to contribution guidance from README',\n details:\n 'Add a brief contribution section or link to CONTRIBUTING.md for new contributors.',\n priority: 'low',\n timeHorizon: 'quick',\n riskIfIgnored: 'Potential contributors may not find the right onboarding materials.',\n evidence: [fileEvidence(scan.repoPath, scan.files.readme)],\n });\n }\n }\n\n if (!scan.directories.docs) {\n recommendations.push({\n areaId: 'documentation',\n title: 'Add a dedicated docs directory',\n details: 'Move detailed guides into a docs/ directory for discoverability and maintenance.',\n priority: 'low',\n timeHorizon: 'long-term',\n riskIfIgnored: 'Long-form documentation will be harder to maintain as the project grows.',\n evidence: [missingEvidence('docs/ directory missing')],\n });\n } else {\n findings.push({\n areaId: 'documentation',\n title: 'Docs directory present',\n details: 'Supporting documentation exists in docs/.',\n evidence: [pathEvidence(scan.repoPath, scan.directories.docs)],\n });\n }\n\n const status = !scan.files.readme\n ? 'missing'\n : recommendations.length > 0\n ? 'needs-improvement'\n : 'good';\n\n return {\n areaId: 'documentation',\n status,\n findings,\n recommendations,\n };\n}\n", "/**\n * License area evaluation\n *\n * @module services/review/areas/license\n */\n\nimport { type AreaEvaluation } from '../review-engine';\nimport type { RepoScanResult } from '../../../utils/repo-scan';\nimport { fileEvidence, missingEvidence } from '../evidence';\n\nfunction detectLicenseType(content: string | undefined): string | undefined {\n if (!content) {\n return undefined;\n }\n\n const text = content.toLowerCase();\n\n if (text.includes('mit license')) {\n return 'MIT';\n }\n if (text.includes('apache license') && text.includes('version 2')) {\n return 'Apache-2.0';\n }\n if (text.includes('gnu general public license') && text.includes('version 3')) {\n return 'GPL-3.0';\n }\n if (text.includes('gnu general public license') && text.includes('version 2')) {\n return 'GPL-2.0';\n }\n if (text.includes('mozilla public license')) {\n return 'MPL-2.0';\n }\n\n return undefined;\n}\n\nexport function evaluateLicense(scan: RepoScanResult): AreaEvaluation {\n const findings: AreaEvaluation['findings'] = [];\n const recommendations: AreaEvaluation['recommendations'] = [];\n\n if (!scan.files.license) {\n findings.push({\n areaId: 'license',\n title: 'License file missing',\n details: 'A license file is required to clarify usage rights for the project.',\n evidence: [missingEvidence('LICENSE missing')],\n });\n recommendations.push({\n areaId: 'license',\n title: 'Add an explicit license file',\n details: 'Include a LICENSE file that matches the intended distribution terms.',\n priority: 'high',\n timeHorizon: 'quick',\n riskIfIgnored: 'Users and contributors may avoid the project due to legal uncertainty.',\n evidence: [missingEvidence('LICENSE missing')],\n });\n } else {\n const licenseType = detectLicenseType(scan.content.license);\n findings.push({\n areaId: 'license',\n title: 'License file present',\n details: licenseType\n ? `Detected license type: ${licenseType}.`\n : 'License file present but type not detected.',\n evidence: [fileEvidence(scan.repoPath, scan.files.license)],\n });\n\n if (!licenseType) {\n recommendations.push({\n areaId: 'license',\n title: 'Clarify license type',\n details: 'Ensure the license text is complete and matches a well-known SPDX identifier.',\n priority: 'medium',\n timeHorizon: 'quick',\n riskIfIgnored: 'Ambiguous licensing can slow adoption and contributions.',\n evidence: [fileEvidence(scan.repoPath, scan.files.license)],\n });\n }\n }\n\n const status = !scan.files.license\n ? 'missing'\n : recommendations.length > 0\n ? 'needs-improvement'\n : 'good';\n\n return {\n areaId: 'license',\n status,\n findings,\n recommendations,\n };\n}\n", "/**\n * Quality area evaluation\n *\n * @module services/review/areas/quality\n */\n\nimport { type AreaEvaluation } from '../review-engine';\nimport type { RepoScanResult } from '../../../utils/repo-scan';\nimport { fileEvidence, missingEvidence, pathEvidence } from '../evidence';\n\nexport function evaluateQuality(scan: RepoScanResult): AreaEvaluation {\n const findings: AreaEvaluation['findings'] = [];\n const recommendations: AreaEvaluation['recommendations'] = [];\n\n if (!scan.signals.hasTests) {\n findings.push({\n areaId: 'quality',\n title: 'Tests not detected',\n details: 'No tests directory found in the repository.',\n evidence: [missingEvidence('tests/ directory missing')],\n });\n recommendations.push({\n areaId: 'quality',\n title: 'Add automated tests',\n details: 'Introduce unit or integration tests to validate key workflows.',\n priority: 'high',\n timeHorizon: 'long-term',\n riskIfIgnored: 'Regression risk increases and changes become harder to validate.',\n evidence: [missingEvidence('tests/ directory missing')],\n });\n } else if (scan.directories.tests) {\n findings.push({\n areaId: 'quality',\n title: 'Tests directory present',\n details: 'Automated tests are present in the repository.',\n evidence: [pathEvidence(scan.repoPath, scan.directories.tests)],\n });\n }\n\n if (!scan.signals.hasGithubActions) {\n recommendations.push({\n areaId: 'quality',\n title: 'Add CI workflows',\n details: 'Set up continuous integration to run tests and lint checks.',\n priority: 'medium',\n timeHorizon: 'long-term',\n riskIfIgnored: 'Quality checks will be inconsistent across contributions.',\n evidence: [missingEvidence('.github/workflows missing')],\n });\n } else if (scan.directories.workflows) {\n findings.push({\n areaId: 'quality',\n title: 'CI workflows detected',\n details: 'GitHub Actions workflows are configured.',\n evidence: [pathEvidence(scan.repoPath, scan.directories.workflows)],\n });\n }\n\n if (!scan.files.changelog) {\n recommendations.push({\n areaId: 'quality',\n title: 'Maintain a changelog',\n details: 'Add a CHANGELOG file to track releases and major changes.',\n priority: 'low',\n timeHorizon: 'long-term',\n riskIfIgnored: 'Users will struggle to track changes between releases.',\n evidence: [missingEvidence('CHANGELOG.md missing')],\n });\n } else {\n findings.push({\n areaId: 'quality',\n title: 'Changelog present',\n details: 'Changelog exists for release tracking.',\n evidence: [fileEvidence(scan.repoPath, scan.files.changelog)],\n });\n }\n\n const status = recommendations.length > 0 ? 'needs-improvement' : 'good';\n\n return {\n areaId: 'quality',\n status,\n findings,\n recommendations,\n };\n}\n", "/**\n * Security area evaluation\n *\n * @module services/review/areas/security\n */\n\nimport { type AreaEvaluation } from '../review-engine';\nimport type { RepoScanResult } from '../../../utils/repo-scan';\nimport { fileEvidence, missingEvidence } from '../evidence';\n\nexport function evaluateSecurity(scan: RepoScanResult): AreaEvaluation {\n const findings: AreaEvaluation['findings'] = [];\n const recommendations: AreaEvaluation['recommendations'] = [];\n\n if (!scan.files.security) {\n findings.push({\n areaId: 'security',\n title: 'Security policy missing',\n details: 'No SECURITY.md file was found for reporting vulnerabilities.',\n evidence: [missingEvidence('SECURITY.md missing')],\n });\n recommendations.push({\n areaId: 'security',\n title: 'Add a security policy',\n details: 'Document how to report vulnerabilities and response expectations.',\n priority: 'high',\n timeHorizon: 'quick',\n riskIfIgnored: 'Security issues may be reported publicly without guidance.',\n evidence: [missingEvidence('SECURITY.md missing')],\n });\n } else {\n findings.push({\n areaId: 'security',\n title: 'Security policy present',\n details: 'A SECURITY.md file exists for vulnerability reporting.',\n evidence: [fileEvidence(scan.repoPath, scan.files.security)],\n });\n\n const securityText = scan.content.security?.toLowerCase() ?? '';\n const hasContact = securityText.includes('email') || securityText.includes('contact');\n const hasReport = securityText.includes('report') || securityText.includes('vulnerability');\n\n if (!hasContact || !hasReport) {\n recommendations.push({\n areaId: 'security',\n title: 'Clarify disclosure instructions',\n details: 'Add contact details and reporting steps to the security policy.',\n priority: 'medium',\n timeHorizon: 'quick',\n riskIfIgnored: 'Reporters may not know how to disclose issues safely.',\n evidence: [fileEvidence(scan.repoPath, scan.files.security)],\n });\n }\n }\n\n const status = !scan.files.security\n ? 'missing'\n : recommendations.length > 0\n ? 'needs-improvement'\n : 'good';\n\n return {\n areaId: 'security',\n status,\n findings,\n recommendations,\n };\n}\n", "/**\n * Review engine orchestration\n *\n * @module services/review/review-engine\n */\n\nimport { REVIEW_AREA_LABELS, type ReviewAreaId } from '../../constants/review';\nimport type {\n AssessmentArea,\n Finding,\n Recommendation,\n ReviewReport,\n Summary,\n} from '../../types/review';\nimport { createReviewId, getIsoTimestamp } from '../../utils/review-id';\nimport type { RepoScanResult } from '../../utils/repo-scan';\nimport { runRepoScan } from './repo-scanner';\nimport { buildSummary } from './summary-builder';\nimport { evaluateCommunity } from './areas/community';\nimport { evaluateContribution } from './areas/contribution';\nimport { evaluateDocumentation } from './areas/documentation';\nimport { evaluateLicense } from './areas/license';\nimport { evaluateQuality } from './areas/quality';\nimport { evaluateSecurity } from './areas/security';\n\nexport interface AreaEvaluation {\n areaId: ReviewAreaId;\n status: AssessmentArea['status'];\n findings: Array<Omit<Finding, 'id'>>;\n recommendations: Array<Omit<Recommendation, 'id'>>;\n}\n\nfunction attachIds(areas: AreaEvaluation[]): AssessmentArea[] {\n let findingIndex = 0;\n let recommendationIndex = 0;\n\n return areas.map((area) => ({\n id: area.areaId,\n name: REVIEW_AREA_LABELS[area.areaId],\n status: area.status,\n findings: area.findings.map((finding) => ({\n ...finding,\n id: `finding_${++findingIndex}`,\n })),\n recommendations: area.recommendations.map((rec) => ({\n ...rec,\n id: `rec_${++recommendationIndex}`,\n })),\n }));\n}\n\nfunction evaluateAreas(scan: RepoScanResult): AreaEvaluation[] {\n return [\n evaluateDocumentation(scan),\n evaluateLicense(scan),\n evaluateContribution(scan),\n evaluateQuality(scan),\n evaluateCommunity(scan),\n evaluateSecurity(scan),\n ];\n}\n\nexport async function generateReviewReport(repoPath: string): Promise<ReviewReport> {\n const scan = await runRepoScan(repoPath);\n const evaluated = evaluateAreas(scan);\n const areas = attachIds(evaluated);\n const recommendations = areas.flatMap((area) => area.recommendations);\n const summary: Summary = buildSummary(areas, recommendations);\n\n return {\n id: createReviewId(),\n repoPath: scan.repoPath,\n generatedAt: getIsoTimestamp(),\n summary,\n areas,\n recommendations,\n };\n}\n", "/**\n * Report renderer for review outputs\n *\n * @module services/review/report-renderer\n */\n\nimport type { AssessmentArea, Recommendation, ReviewReport } from '../../types/review';\n\nexport interface RenderOptions {\n summaryOnly?: boolean;\n recommendationsOnly?: boolean;\n}\n\nfunction renderEvidence(evidence: { type: string; target: string; notes?: string }[]): string {\n if (!evidence.length) {\n return '';\n }\n const items = evidence\n .map((item) => `- ${item.type}: ${item.target}${item.notes ? ` (${item.notes})` : ''}`)\n .join('\\n');\n return `\\n\\nEvidence:\\n${items}`;\n}\n\nfunction renderRecommendationsList(recommendations: Recommendation[]): string {\n if (recommendations.length === 0) {\n return 'No recommendations found.';\n }\n\n const priorityOrder: Record<string, number> = { high: 0, medium: 1, low: 2 };\n const sorted = [...recommendations].sort((a, b) => {\n const left = priorityOrder[a.priority] ?? 99;\n const right = priorityOrder[b.priority] ?? 99;\n return left - right;\n });\n\n return sorted\n .map((rec) => {\n const header = `- [${rec.priority.toUpperCase()} | ${rec.timeHorizon}] ${rec.title}`;\n const details = ` ${rec.details}`;\n const risk = ` Risk if ignored: ${rec.riskIfIgnored}`;\n const evidence = renderEvidence(rec.evidence)\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n return [header, details, risk, evidence].filter(Boolean).join('\\n');\n })\n .join('\\n');\n}\n\nfunction renderArea(area: AssessmentArea): string {\n const findings = area.findings.length\n ? area.findings\n .map((finding) => {\n const header = `- ${finding.title}`;\n const details = ` ${finding.details}`;\n const evidence = renderEvidence(finding.evidence)\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n return [header, details, evidence].filter(Boolean).join('\\n');\n })\n .join('\\n')\n : 'No findings.';\n\n const recommendations = renderRecommendationsList(area.recommendations);\n\n return [\n `### ${area.name}`,\n `Status: ${area.status}`,\n '',\n 'Findings:',\n findings,\n '',\n 'Recommendations:',\n recommendations,\n ].join('\\n');\n}\n\nexport function renderReportMarkdown(report: ReviewReport, options: RenderOptions = {}): string {\n if (options.summaryOnly) {\n return renderSummaryMarkdown(report);\n }\n\n if (options.recommendationsOnly) {\n return renderRecommendationsMarkdown(report.recommendations);\n }\n\n const header = [\n '# Open Source Review Report',\n '',\n `Repository: ${report.repoPath}`,\n `Generated: ${report.generatedAt}`,\n '',\n ].join('\\n');\n\n const summary = renderSummaryMarkdown(report);\n const contributorRecommendations = report.recommendations.filter(\n (rec) => rec.areaId === 'contribution'\n );\n const contributorSection = contributorRecommendations.length\n ? ['## Contributor Guidance', renderRecommendationsList(contributorRecommendations)].join('\\n')\n : '';\n const recommendations = renderRecommendationsMarkdown(report.recommendations);\n const areas = report.areas.map(renderArea).join('\\n\\n');\n\n return [header, summary, '', contributorSection, '', recommendations, '', '## Areas', areas]\n .filter((section) => section.trim().length > 0)\n .join('\\n');\n}\n\nexport function renderSummaryMarkdown(report: ReviewReport): string {\n const risks = report.summary.riskNotes.length\n ? report.summary.riskNotes.map((note) => `- ${note}`).join('\\n')\n : 'No critical risks noted.';\n\n return [\n '## Summary',\n `Headline: ${report.summary.headline}`,\n `High priority recommendations: ${report.summary.highPriorityCount}`,\n `Quick wins: ${report.summary.quickWinsCount}`,\n 'Risk notes:',\n risks,\n ].join('\\n');\n}\n\nexport function renderRecommendationsMarkdown(recommendations: Recommendation[]): string {\n return ['## Recommendations', renderRecommendationsList(recommendations)].join('\\n');\n}\n\nexport function renderReportJson(report: ReviewReport, options: RenderOptions = {}): string {\n if (options.summaryOnly) {\n return JSON.stringify(report.summary, null, 2);\n }\n\n if (options.recommendationsOnly) {\n return JSON.stringify(report.recommendations, null, 2);\n }\n\n return JSON.stringify(report, null, 2);\n}\n", "/**\n * Report output writer\n *\n * @module utils/report-output\n */\n\nimport { writeFile } from 'fs/promises';\n\nexport interface ReportOutputPayload {\n markdown?: string;\n json?: string;\n markdownPath?: string;\n jsonPath?: string;\n}\n\nexport async function writeReportOutputs(payload: ReportOutputPayload): Promise<void> {\n const stdoutChunks: string[] = [];\n\n if (payload.markdown) {\n if (payload.markdownPath) {\n await writeFile(payload.markdownPath, payload.markdown, 'utf-8');\n } else {\n stdoutChunks.push(payload.markdown);\n }\n }\n\n if (payload.json) {\n if (payload.jsonPath) {\n await writeFile(payload.jsonPath, payload.json, 'utf-8');\n } else {\n stdoutChunks.push(payload.json);\n }\n }\n\n if (stdoutChunks.length > 0) {\n process.stdout.write(stdoutChunks.join('\\n\\n'));\n process.stdout.write('\\n');\n }\n}\n", "/**\n * Repository review command\n *\n * @module commands/review\n */\n\nimport type { Command } from 'commander';\nimport logger from '../utils/logger';\nimport { ExitCode, getExitCodeForError, gracefulExit } from '../constants/exit-codes';\nimport { REVIEW_FORMATS } from '../constants/review';\nimport type { OutputFormat } from '../types/review';\nimport { generateReviewReport } from '../services/review/review-engine';\nimport { renderReportJson, renderReportMarkdown } from '../services/review/report-renderer';\nimport { writeReportOutputs } from '../utils/report-output';\n\ninterface ReviewCommandOptions {\n repo: string;\n format?: string;\n out?: string;\n jsonOut?: string;\n summary?: boolean;\n recommendations?: boolean;\n}\n\nfunction parseFormats(value?: string): OutputFormat[] {\n if (!value) {\n return [...REVIEW_FORMATS];\n }\n\n const normalized = value\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean) as OutputFormat[];\n\n const unique = Array.from(new Set(normalized));\n const invalid = unique.filter((format) => !REVIEW_FORMATS.includes(format));\n\n if (invalid.length > 0) {\n throw new Error(`Invalid format(s): ${invalid.join(', ')}`);\n }\n\n return unique;\n}\n\nexport function registerReviewCommand(program: Command): void {\n program\n .command('review')\n .description('Generate an open-source review report for a local repository')\n .requiredOption('--repo <path>', 'Repository path to review')\n .option('--format <formats>', 'Output formats (markdown,json)', 'markdown,json')\n .option('--out <path>', 'Markdown output path')\n .option('--json-out <path>', 'JSON output path')\n .option('--summary', 'Render summary only')\n .option('--recommendations', 'Render recommendations only')\n .action(async (options: ReviewCommandOptions) => {\n try {\n if (options.summary && options.recommendations) {\n throw new Error('Only one of --summary or --recommendations can be used.');\n }\n\n let formats = parseFormats(options.format);\n\n if (options.out && !formats.includes('markdown')) {\n formats = [...formats, 'markdown'];\n }\n if (options.jsonOut && !formats.includes('json')) {\n formats = [...formats, 'json'];\n }\n\n const report = await generateReviewReport(options.repo);\n const renderOptions = {\n summaryOnly: Boolean(options.summary),\n recommendationsOnly: Boolean(options.recommendations),\n };\n\n const markdown = formats.includes('markdown')\n ? renderReportMarkdown(report, renderOptions)\n : undefined;\n const json = formats.includes('json') ? renderReportJson(report, renderOptions) : undefined;\n\n await writeReportOutputs({\n markdown,\n json,\n markdownPath: options.out,\n jsonPath: options.jsonOut,\n });\n\n logger.success('Review report generated successfully.');\n } catch (error) {\n const err = error as Error;\n logger.error(`Review failed: ${err.message}`);\n await gracefulExit(getExitCodeForError(err) || ExitCode.GENERAL_ERROR);\n }\n });\n}\n", "/**\n * Clash config export command\n *\n * @module commands/clash\n */\n\nimport type { Command } from 'commander';\nimport { input, confirm } from '@inquirer/prompts';\nimport { promises as fs } from 'fs';\nimport { dirname, join } from 'path';\nimport { homedir } from 'os';\nimport chalk from 'chalk';\nimport logger from '../utils/logger';\nimport { DEFAULT_PATHS } from '../constants/paths';\nimport { parseVlessLink } from '../utils/vless-link';\nimport { buildClashConfigYaml } from '../services/clash-config';\n\ninterface ClashExportResult {\n outputPath: string;\n proxyName: string;\n proxyGroupName: string;\n}\n\ninterface ClashExportOptions {\n link?: string;\n outputPath?: string;\n proxyName?: string;\n json?: boolean;\n force?: boolean;\n promptLink?: boolean;\n promptOutputPath?: boolean;\n promptOverwrite?: boolean;\n}\n\ninterface ClashCommandOptions {\n link?: string;\n out?: string;\n name?: string;\n json?: boolean;\n force?: boolean;\n}\n\nfunction normalizeOutputPath(value: string): string {\n const trimmed = value.trim();\n let path = trimmed;\n\n // \u5904\u7406 ~ \u5F00\u5934\u7684\u8DEF\u5F84\n if (path.startsWith('~/')) {\n path = join(homedir(), path.slice(2));\n }\n\n // \u5982\u679C\u4E3A\u7A7A\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u8DEF\u5F84\n if (!path) {\n return DEFAULT_PATHS.CLASH_CONFIG_FILE;\n }\n\n return path;\n}\n\nasync function isDirectory(path: string): Promise<boolean> {\n try {\n const stat = await fs.stat(path);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await fs.access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function writeClashConfigFile(\n options: ClashExportOptions\n): Promise<ClashExportResult | null> {\n const rawLink = options.link || '';\n const link = rawLink.trim();\n if (!link) {\n throw new Error('\u672A\u63D0\u4F9B VLESS \u94FE\u63A5');\n }\n\n let outputPath = normalizeOutputPath(options.outputPath || DEFAULT_PATHS.CLASH_CONFIG_FILE);\n\n // \u5982\u679C\u662F\u76EE\u5F55\uFF0C\u5219\u8FFD\u52A0\u9ED8\u8BA4\u6587\u4EF6\u540D\n if (await isDirectory(outputPath)) {\n outputPath = join(outputPath, 'clash-config.yaml');\n }\n\n const info = parseVlessLink(link);\n const { yaml, proxyName, proxyGroupName } = buildClashConfigYaml(info, {\n proxyName: options.proxyName,\n });\n\n const exists = await fileExists(outputPath);\n if (exists && !options.force) {\n if (options.promptOverwrite) {\n const overwrite = await confirm({\n message: chalk.yellow(`\u8F93\u51FA\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6\uFF1F\\n${outputPath}`),\n default: false,\n });\n if (!overwrite) {\n logger.info('\u5DF2\u53D6\u6D88\u751F\u6210 Clash \u914D\u7F6E');\n return null;\n }\n } else {\n throw new Error(`\u8F93\u51FA\u6587\u4EF6\u5DF2\u5B58\u5728: ${outputPath}`);\n }\n }\n\n await fs.mkdir(dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, yaml, 'utf8');\n\n return {\n outputPath,\n proxyName,\n proxyGroupName,\n };\n}\n\nexport async function exportClashConfigFromLink(options: ClashExportOptions = {}): Promise<void> {\n try {\n let link = options.link;\n if (!link && options.promptLink) {\n link = await input({\n message: '\u8BF7\u8F93\u5165 VLESS \u94FE\u63A5:',\n });\n }\n\n let outputPath = options.outputPath;\n if (options.promptOutputPath) {\n const outputInput = await input({\n message: '\u8BF7\u8F93\u5165 Clash \u914D\u7F6E\u8F93\u51FA\u8DEF\u5F84:',\n default: options.outputPath || DEFAULT_PATHS.CLASH_CONFIG_FILE,\n });\n outputPath = outputInput;\n }\n\n const result = await writeClashConfigFile({\n ...options,\n link,\n outputPath,\n });\n\n if (!result) {\n return;\n }\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n logger.newline();\n logger.separator();\n console.log(chalk.bold.cyan('\uD83D\uDCC4 Clash \u914D\u7F6E\u5DF2\u751F\u6210'));\n logger.separator();\n logger.newline();\n console.log(chalk.cyan(' \u8F93\u51FA\u8DEF\u5F84: ') + chalk.white(result.outputPath));\n console.log(chalk.cyan(' \u8282\u70B9\u540D\u79F0: ') + chalk.white(result.proxyName));\n logger.newline();\n } catch (error) {\n logger.error((error as Error).message);\n process.exit(1);\n }\n}\n\nexport function registerClashCommand(program: Command): void {\n program\n .command('clash')\n .description('\u4ECE VLESS \u5206\u4EAB\u94FE\u63A5\u751F\u6210 Clash \u914D\u7F6E\u6587\u4EF6')\n .option('--link <vless>', 'VLESS \u5206\u4EAB\u94FE\u63A5')\n .option('--out <path>', 'Clash \u914D\u7F6E\u8F93\u51FA\u8DEF\u5F84', DEFAULT_PATHS.CLASH_CONFIG_FILE)\n .option('--name <name>', '\u8282\u70B9\u540D\u79F0\uFF08\u8986\u76D6\u94FE\u63A5\u5185\u540D\u79F0\uFF09')\n .option('--json', '\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u7ED3\u679C')\n .option('-f, --force', '\u8986\u76D6\u5DF2\u5B58\u5728\u7684\u8F93\u51FA\u6587\u4EF6')\n .action(async (options: ClashCommandOptions) => {\n await exportClashConfigFromLink({\n link: options.link,\n outputPath: options.out,\n proxyName: options.name,\n json: options.json,\n force: options.force,\n promptLink: !options.link,\n promptOutputPath: false,\n promptOverwrite: true,\n });\n });\n}\n", "/**\n * \u8F93\u5165\u9A8C\u8BC1\u5DE5\u5177\u51FD\u6570\n * @module utils/validator\n */\n\n/**\n * \u90AE\u7BB1\u9A8C\u8BC1\u6B63\u5219\u8868\u8FBE\u5F0F\n */\nconst EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/;\n\n/**\n * UUID v4 \u9A8C\u8BC1\u6B63\u5219\u8868\u8FBE\u5F0F\n */\nconst UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/**\n * \u7AEF\u53E3\u53F7\u9A8C\u8BC1\u6B63\u5219\u8868\u8FBE\u5F0F\uFF081-65535\uFF09\n */\nconst _PORT_REGEX =\n /^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/;\n\n/**\n * \u57DF\u540D\u9A8C\u8BC1\u6B63\u5219\u8868\u8FBE\u5F0F\n */\nconst DOMAIN_REGEX = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$/;\n\n/**\n * \u670D\u52A1\u540D\u9A8C\u8BC1\u6B63\u5219\u8868\u8FBE\u5F0F\uFF08\u4EC5\u5B57\u6BCD\u6570\u5B57\u3001@\u3001._-\uFF09\n */\nconst SERVICE_NAME_REGEX = /^[a-zA-Z0-9@._-]+$/;\n\n/**\n * IPv4 \u5730\u5740\u9A8C\u8BC1\u6B63\u5219\u8868\u8FBE\u5F0F\n */\nconst IPV4_REGEX =\n /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;\n\n/**\n * \u8DEF\u5F84\u9A8C\u8BC1\u6B63\u5219\u8868\u8FBE\u5F0F\uFF08Unix \u8DEF\u5F84\uFF09\n */\nconst PATH_REGEX = /^\\/(?:[^/\\0]+\\/)*[^/\\0]*$/;\n\n/**\n * \u9A8C\u8BC1\u90AE\u7BB1\u5730\u5740\n * @param email \u90AE\u7BB1\u5730\u5740\n * @returns \u662F\u5426\u6709\u6548\n */\nexport function isValidEmail(email: string): boolean {\n if (!email || typeof email !== 'string') {\n return false;\n }\n return EMAIL_REGEX.test(email);\n}\n\n/**\n * \u9A8C\u8BC1 UUID v4 \u683C\u5F0F\n * @param uuid UUID \u5B57\u7B26\u4E32\n * @returns \u662F\u5426\u6709\u6548\n */\nexport function isValidUuid(uuid: string): boolean {\n if (!uuid || typeof uuid !== 'string') {\n return false;\n }\n return UUID_V4_REGEX.test(uuid);\n}\n\n/**\n * \u9A8C\u8BC1\u7AEF\u53E3\u53F7\uFF081-65535\uFF09\n * @param port \u7AEF\u53E3\u53F7\uFF08\u6570\u5B57\u6216\u5B57\u7B26\u4E32\uFF09\n * @returns \u662F\u5426\u6709\u6548\n */\nexport function isValidPort(port: number | string): boolean {\n const num = typeof port === 'string' ? parseInt(port, 10) : port;\n\n if (isNaN(num) || !Number.isInteger(num)) {\n return false;\n }\n\n return num >= 1 && num <= 65535;\n}\n\n/**\n * \u9A8C\u8BC1\u57DF\u540D\n * @param domain \u57DF\u540D\n * @returns \u662F\u5426\u6709\u6548\n */\nexport function isValidDomain(domain: string): boolean {\n if (!domain || typeof domain !== 'string') {\n return false;\n }\n return DOMAIN_REGEX.test(domain);\n}\n\n/**\n * \u9A8C\u8BC1\u670D\u52A1\u540D\u79F0\n * @param serviceName \u670D\u52A1\u540D\u79F0\n * @returns \u662F\u5426\u6709\u6548\n */\nexport function isValidServiceName(serviceName: string): boolean {\n if (!serviceName || typeof serviceName !== 'string') {\n return false;\n }\n return SERVICE_NAME_REGEX.test(serviceName);\n}\n\n/**\n * \u9A8C\u8BC1 IPv4 \u5730\u5740\n * @param ip IP \u5730\u5740\n * @returns \u662F\u5426\u6709\u6548\n */\nexport function isValidIPv4(ip: string): boolean {\n if (!ip || typeof ip !== 'string') {\n return false;\n }\n return IPV4_REGEX.test(ip);\n}\n\n/**\n * \u9A8C\u8BC1 Unix \u8DEF\u5F84\n * @param path \u8DEF\u5F84\u5B57\u7B26\u4E32\n * @returns \u662F\u5426\u6709\u6548\n */\nexport function isValidPath(path: string): boolean {\n if (!path || typeof path !== 'string') {\n return false;\n }\n return PATH_REGEX.test(path);\n}\n\n/**\n * \u9A8C\u8BC1 URL\n * @param url URL \u5B57\u7B26\u4E32\n * @returns \u662F\u5426\u6709\u6548\n */\nexport function isValidUrl(url: string): boolean {\n try {\n new URL(url);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * \u9A8C\u8BC1\u5668\u63A5\u53E3\n */\nexport interface Validator {\n validate(_value: string): boolean;\n errorMessage: string;\n}\n\n/**\n * \u9A8C\u8BC1\u5668\u6620\u5C04\n */\nexport const validators: Record<string, Validator> = {\n email: {\n validate: isValidEmail,\n errorMessage: '\u8BF7\u8F93\u5165\u6709\u6548\u7684\u90AE\u7BB1\u5730\u5740\uFF08\u5982 user@example.com\uFF09',\n },\n\n uuid: {\n validate: isValidUuid,\n errorMessage: '\u8BF7\u8F93\u5165\u6709\u6548\u7684 UUID v4 \u683C\u5F0F',\n },\n\n port: {\n validate: (value) => {\n const num = parseInt(value, 10);\n return !isNaN(num) && isValidPort(num);\n },\n errorMessage: '\u7AEF\u53E3\u53F7\u5FC5\u987B\u5728 1-65535 \u4E4B\u95F4',\n },\n\n domain: {\n validate: isValidDomain,\n errorMessage: '\u8BF7\u8F93\u5165\u6709\u6548\u7684\u57DF\u540D\uFF08\u5982 example.com\uFF09',\n },\n\n serviceName: {\n validate: isValidServiceName,\n errorMessage: '\u670D\u52A1\u540D\u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u548C @._- \u5B57\u7B26',\n },\n\n ipv4: {\n validate: isValidIPv4,\n errorMessage: '\u8BF7\u8F93\u5165\u6709\u6548\u7684 IPv4 \u5730\u5740',\n },\n\n path: {\n validate: isValidPath,\n errorMessage: '\u8BF7\u8F93\u5165\u6709\u6548\u7684 Unix \u8DEF\u5F84\uFF08\u4EE5 / \u5F00\u5934\uFF09',\n },\n\n url: {\n validate: isValidUrl,\n errorMessage: '\u8BF7\u8F93\u5165\u6709\u6548\u7684 URL',\n },\n};\n\n/**\n * \u9A8C\u8BC1\u7ED3\u679C\n */\nexport interface ValidationResult {\n /** \u662F\u5426\u6709\u6548 */\n valid: boolean;\n\n /** \u9519\u8BEF\u6D88\u606F */\n error?: string;\n\n /** \u5B57\u6BB5\u540D\u79F0 */\n field?: string;\n}\n\n/**\n * \u901A\u7528\u9A8C\u8BC1\u51FD\u6570\n * @param value \u5F85\u9A8C\u8BC1\u7684\u503C\n * @param validatorName \u9A8C\u8BC1\u5668\u540D\u79F0\n * @param fieldName \u5B57\u6BB5\u540D\u79F0\uFF08\u7528\u4E8E\u9519\u8BEF\u6D88\u606F\uFF09\n * @returns \u9A8C\u8BC1\u7ED3\u679C\n */\nexport function validate(\n value: string,\n validatorName: keyof typeof validators,\n fieldName?: string\n): ValidationResult {\n const validator = validators[validatorName];\n\n if (!validator) {\n return {\n valid: false,\n error: `\u672A\u77E5\u7684\u9A8C\u8BC1\u5668: ${validatorName}`,\n field: fieldName,\n };\n }\n\n const valid = validator.validate(value);\n\n if (!valid) {\n return {\n valid: false,\n error: validator.errorMessage,\n field: fieldName,\n };\n }\n\n return { valid: true };\n}\n\n/**\n * \u6279\u91CF\u9A8C\u8BC1\n * @param values \u5B57\u6BB5\u548C\u503C\u7684\u6620\u5C04\n * @param validatorMap \u5B57\u6BB5\u548C\u9A8C\u8BC1\u5668\u7684\u6620\u5C04\n * @returns \u9A8C\u8BC1\u7ED3\u679C\u5217\u8868\n */\nexport function validateMultiple(\n values: Record<string, string>,\n validatorMap: Record<string, keyof typeof validators>\n): ValidationResult[] {\n const results: ValidationResult[] = [];\n\n for (const [field, value] of Object.entries(values)) {\n const validatorName = validatorMap[field];\n if (validatorName) {\n results.push(validate(value, validatorName, field));\n }\n }\n\n return results;\n}\n\n/**\n * \u68C0\u67E5\u6240\u6709\u9A8C\u8BC1\u662F\u5426\u901A\u8FC7\n * @param results \u9A8C\u8BC1\u7ED3\u679C\u5217\u8868\n * @returns \u662F\u5426\u5168\u90E8\u901A\u8FC7\n */\nexport function allValid(results: ValidationResult[]): boolean {\n return results.every((result) => result.valid);\n}\n\n/**\n * \u83B7\u53D6\u6240\u6709\u9519\u8BEF\u6D88\u606F\n * @param results \u9A8C\u8BC1\u7ED3\u679C\u5217\u8868\n * @returns \u9519\u8BEF\u6D88\u606F\u5217\u8868\n */\nexport function getErrors(results: ValidationResult[]): string[] {\n return results.filter((result) => !result.valid).map((result) => result.error || '\u672A\u77E5\u9519\u8BEF');\n}\n", "/**\n * VLESS link parser and generator utilities\n * @module utils/vless-link\n */\n\nimport { isValidPort, isValidUuid } from './validator';\nimport { ProtocolError } from './errors';\nimport { ProtocolErrors } from '../constants/error-codes';\n\n/**\n * Parameters for generating VLESS REALITY link\n */\nexport interface VlessRealityParams {\n uuid: string;\n server: string;\n port: number;\n publicKey: string;\n shortId: string;\n sni?: string;\n flow?: string;\n fingerprint?: string;\n remark?: string;\n}\n\n/**\n * Parameters for generating VLESS WebSocket (CDN) link\n */\nexport interface VlessWebSocketParams {\n uuid: string;\n server: string;\n port: number;\n path: string;\n host?: string;\n sni?: string;\n tls?: boolean;\n remark?: string;\n}\n\n/**\n * Generate VLESS REALITY share link\n *\n * @param params - REALITY link parameters\n * @returns VLESS share link string\n */\nexport function generateVlessRealityLink(params: VlessRealityParams): string {\n const {\n uuid,\n server,\n port,\n publicKey,\n shortId,\n sni = 'www.microsoft.com',\n flow = 'xtls-rprx-vision',\n fingerprint = 'chrome',\n remark = 'Xray-Reality',\n } = params;\n\n const searchParams = new URLSearchParams({\n encryption: 'none',\n flow,\n security: 'reality',\n sni,\n fp: fingerprint,\n pbk: publicKey,\n sid: shortId,\n type: 'tcp',\n headerType: 'none',\n });\n\n return `vless://${uuid}@${server}:${port}?${searchParams.toString()}#${encodeURIComponent(remark)}`;\n}\n\n/**\n * Generate VLESS WebSocket (CDN) share link\n *\n * @param params - WebSocket link parameters\n * @returns VLESS share link string\n */\nexport function generateVlessWebSocketLink(params: VlessWebSocketParams): string {\n const { uuid, server, port, path, host, sni, tls = true, remark = 'Xray-CDN' } = params;\n\n const searchParams = new URLSearchParams({\n encryption: 'none',\n security: tls ? 'tls' : 'none',\n type: 'ws',\n host: host || server,\n path,\n });\n\n if (tls && sni) {\n searchParams.set('sni', sni);\n }\n\n return `vless://${uuid}@${server}:${port}?${searchParams.toString()}#${encodeURIComponent(remark)}`;\n}\n\nexport interface VlessLinkInfo {\n uuid: string;\n server: string;\n port: number;\n name: string;\n encryption?: string;\n security?: string;\n type?: string;\n flow?: string;\n sni?: string;\n fp?: string;\n pbk?: string;\n sid?: string;\n spx?: string;\n host?: string;\n path?: string;\n serviceName?: string;\n alpn?: string;\n headerType?: string;\n}\n\nexport function normalizeVlessLink(raw: string): string {\n return raw.trim().replace(/\\s+/g, '');\n}\n\nexport function parseVlessLink(raw: string): VlessLinkInfo {\n const normalized = normalizeVlessLink(raw);\n let url: URL;\n\n try {\n url = new URL(normalized);\n } catch {\n throw new ProtocolError(ProtocolErrors.INVALID_VLESS_LINK);\n }\n\n if (url.protocol !== 'vless:') {\n throw new ProtocolError(ProtocolErrors.INVALID_VLESS_LINK, url.protocol);\n }\n\n const uuid = url.username;\n if (!uuid) {\n throw new ProtocolError(ProtocolErrors.VLESS_MISSING_UUID);\n }\n if (!isValidUuid(uuid)) {\n throw new ProtocolError(ProtocolErrors.VLESS_MISSING_UUID, uuid);\n }\n\n const server = url.hostname;\n if (!server) {\n throw new ProtocolError(ProtocolErrors.VLESS_MISSING_HOST);\n }\n\n const port = url.port ? parseInt(url.port, 10) : 443;\n if (!isValidPort(port)) {\n throw new ProtocolError(ProtocolErrors.VLESS_INVALID_PORT, String(port));\n }\n\n const name = url.hash ? decodeURIComponent(url.hash.slice(1)) : '';\n const params = url.searchParams;\n const getParam = (key: string): string | undefined => {\n const value = params.get(key);\n return value === null ? undefined : value;\n };\n\n return {\n uuid,\n server,\n port,\n name: name || `${server}:${port}`,\n encryption: getParam('encryption'),\n security: getParam('security'),\n type: getParam('type'),\n flow: getParam('flow'),\n sni: getParam('sni'),\n fp: getParam('fp'),\n pbk: getParam('pbk'),\n sid: getParam('sid'),\n spx: getParam('spx'),\n host: getParam('host'),\n path: getParam('path'),\n serviceName: getParam('serviceName'),\n alpn: getParam('alpn'),\n headerType: getParam('headerType'),\n };\n}\n", "/**\n * Clash config generator for VLESS links\n * @module services/clash-config\n */\n\nimport { VlessLinkInfo } from '../utils/vless-link';\n\nexport interface ClashConfigOptions {\n proxyName?: string;\n proxyGroupName?: string;\n}\n\nexport interface ClashConfigResult {\n yaml: string;\n proxyName: string;\n proxyGroupName: string;\n}\n\nfunction yamlQuote(value: string): string {\n const escaped = value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n return `\"${escaped}\"`;\n}\n\nfunction renderStringList(lines: string[], indent: number, values: string[]): void {\n const prefix = ' '.repeat(indent);\n values.forEach((value) => {\n lines.push(`${prefix}- ${yamlQuote(value)}`);\n });\n}\n\nexport function buildClashConfigYaml(\n info: VlessLinkInfo,\n options: ClashConfigOptions = {}\n): ClashConfigResult {\n const proxyName = options.proxyName || info.name || `${info.server}:${info.port}`;\n const proxyGroupName = options.proxyGroupName || 'PROXY';\n\n const network = (info.type || 'tcp').toLowerCase();\n const security = (info.security || '').toLowerCase();\n\n const lines: string[] = [];\n\n lines.push('port: 7890');\n lines.push('socks-port: 7891');\n lines.push('allow-lan: true');\n lines.push('mode: rule');\n lines.push('log-level: info');\n lines.push('');\n lines.push('proxies:');\n lines.push(` - name: ${yamlQuote(proxyName)}`);\n lines.push(' type: vless');\n lines.push(` server: ${yamlQuote(info.server)}`);\n lines.push(` port: ${info.port}`);\n lines.push(` uuid: ${yamlQuote(info.uuid)}`);\n lines.push(' udp: true');\n lines.push(` network: ${yamlQuote(network)}`);\n\n if (info.flow) {\n lines.push(` flow: ${yamlQuote(info.flow)}`);\n }\n\n if (security === 'reality' || security === 'tls') {\n lines.push(' tls: true');\n if (info.sni) {\n lines.push(` servername: ${yamlQuote(info.sni)}`);\n }\n }\n\n if (security === 'reality') {\n if (!info.pbk) {\n throw new Error('Reality \u94FE\u63A5\u7F3A\u5C11 pbk \u53C2\u6570');\n }\n lines.push(' reality-opts:');\n lines.push(` public-key: ${yamlQuote(info.pbk)}`);\n if (info.sid) {\n lines.push(` short-id: ${yamlQuote(info.sid)}`);\n }\n if (info.spx) {\n lines.push(` spider-x: ${yamlQuote(info.spx)}`);\n }\n }\n\n if (info.fp) {\n lines.push(` client-fingerprint: ${yamlQuote(info.fp)}`);\n }\n\n if (info.alpn) {\n const list = info.alpn\n .split(',')\n .map((value) => value.trim())\n .filter(Boolean);\n if (list.length > 0) {\n lines.push(' alpn:');\n renderStringList(lines, 6, list);\n }\n }\n\n if (network === 'ws') {\n lines.push(' ws-opts:');\n if (info.path) {\n lines.push(` path: ${yamlQuote(info.path)}`);\n }\n if (info.host) {\n lines.push(' headers:');\n lines.push(` Host: ${yamlQuote(info.host)}`);\n }\n }\n\n if (network === 'grpc') {\n lines.push(' grpc-opts:');\n const serviceName = info.serviceName || info.path;\n if (serviceName) {\n lines.push(` grpc-service-name: ${yamlQuote(serviceName)}`);\n }\n }\n\n lines.push('');\n lines.push('proxy-groups:');\n lines.push(` - name: ${yamlQuote(proxyGroupName)}`);\n lines.push(' type: select');\n lines.push(' proxies:');\n lines.push(` - ${yamlQuote(proxyName)}`);\n lines.push(' - DIRECT');\n lines.push('');\n lines.push('rules:');\n lines.push(` - MATCH,${proxyGroupName}`);\n lines.push('');\n\n return {\n yaml: `${lines.join('\\n')}\\n`,\n proxyName,\n proxyGroupName,\n };\n}\n", "import React, { createContext, useContext, useState, useCallback } from 'react';\nimport { type ThemeName, type Theme, getTheme } from './theme.js';\n\ninterface ThemeContextValue {\n themeName: ThemeName;\n theme: Theme;\n setTheme: (name: ThemeName) => void;\n}\n\nconst ThemeContext = createContext<ThemeContextValue>({\n themeName: 'dark',\n theme: getTheme('dark'),\n setTheme: () => {},\n});\n\nexport function ThemeProvider({\n children,\n defaultTheme = 'dark',\n}: {\n children: React.ReactNode;\n defaultTheme?: ThemeName;\n}) {\n const [themeName, setThemeName] = useState<ThemeName>(defaultTheme);\n\n const setTheme = useCallback((name: ThemeName) => {\n setThemeName(name);\n }, []);\n\n const value: ThemeContextValue = {\n themeName,\n theme: getTheme(themeName),\n setTheme,\n };\n\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n}\n\nexport function useTheme(): ThemeContextValue {\n return useContext(ThemeContext);\n}\n", "export interface Theme {\n // Brand\n primary: string;\n primaryShimmer: string;\n\n // Semantic\n success: string;\n error: string;\n warning: string;\n info: string;\n\n // Text\n text: string;\n inverseText: string;\n inactive: string;\n subtle: string;\n\n // UI Chrome\n border: string;\n borderAccent: string;\n highlight: string;\n\n // Service status\n serviceRunning: string;\n serviceStopped: string;\n\n // Quota\n quotaNormal: string;\n quotaWarning: string;\n quotaExceeded: string;\n quotaUnlimited: string;\n\n // Progress\n progressFill: string;\n progressEmpty: string;\n}\n\nexport type ThemeName = 'dark' | 'light';\n\nexport const darkTheme: Theme = {\n primary: '#00c8c8',\n primaryShimmer: '#32e6e6',\n\n success: '#48c757',\n error: '#f04747',\n warning: '#fac83c',\n info: '#5789f7',\n\n text: '#e6e6e6',\n inverseText: '#141414',\n inactive: '#808080',\n subtle: '#5a5a5a',\n\n border: '#3c3c3c',\n borderAccent: '#00c8c8',\n highlight: '#283c3c',\n\n serviceRunning: '#48c757',\n serviceStopped: '#f04747',\n\n quotaNormal: '#48c757',\n quotaWarning: '#fac83c',\n quotaExceeded: '#f04747',\n quotaUnlimited: '#5789f7',\n\n progressFill: '#00c8c8',\n progressEmpty: '#323232',\n};\n\nexport const lightTheme: Theme = {\n primary: '#009999',\n primaryShimmer: '#00b7b7',\n\n success: '#2c7a39',\n error: '#ab2b3f',\n warning: '#966c1e',\n info: '#5769f7',\n\n text: '#141414',\n inverseText: '#f5f5f5',\n inactive: '#787878',\n subtle: '#afafaf',\n\n border: '#c8c8c8',\n borderAccent: '#009999',\n highlight: '#dcf0f0',\n\n serviceRunning: '#2c7a39',\n serviceStopped: '#ab2b3f',\n\n quotaNormal: '#2c7a39',\n quotaWarning: '#966c1e',\n quotaExceeded: '#ab2b3f',\n quotaUnlimited: '#5769f7',\n\n progressFill: '#009999',\n progressEmpty: '#dcdcdc',\n};\n\nconst themes: Record<ThemeName, Theme> = { dark: darkTheme, light: lightTheme };\n\nexport function getTheme(name: ThemeName): Theme {\n return themes[name];\n}\n\nexport function resolveColor(color: string | undefined, theme: Theme): string | undefined {\n if (!color) return undefined;\n if (color.startsWith('#') || color.startsWith('rgb(') || color.startsWith('ansi')) {\n return color;\n }\n return (theme as unknown as Record<string, string>)[color] ?? color;\n}\n", "import React, { createContext, useContext, useState, useCallback } from 'react';\nimport {\n type Language,\n type Translations,\n t as getTranslations,\n setLanguage as setLangPersist,\n getCurrentLanguage,\n loadLanguagePreference,\n} from '../config/i18n.js';\n\ninterface I18nContextValue {\n language: Language;\n t: Translations;\n setLanguage: (lang: Language) => void;\n toggleLanguage: () => void;\n}\n\nconst I18nContext = createContext<I18nContextValue>({\n language: 'en',\n t: getTranslations(),\n setLanguage: () => {},\n toggleLanguage: () => {},\n});\n\nexport function I18nProvider({\n children,\n defaultLanguage = 'en',\n}: {\n children: React.ReactNode;\n defaultLanguage?: Language;\n}) {\n // Load from preference file, fallback to default\n const initial = loadLanguagePreference() || defaultLanguage;\n const [language, setLanguageState] = useState<Language>(initial);\n\n const setLanguage = useCallback((lang: Language) => {\n setLangPersist(lang);\n setLanguageState(lang);\n }, []);\n\n const toggleLanguage = useCallback(() => {\n const newLang = language === 'zh' ? 'en' : 'zh';\n setLanguage(newLang);\n }, [language, setLanguage]);\n\n // Update module-level language so t() returns correct translations\n if (getCurrentLanguage() !== language) {\n setLangPersist(language);\n }\n\n return (\n <I18nContext.Provider value={{ language, t: getTranslations(), setLanguage, toggleLanguage }}>\n {children}\n </I18nContext.Provider>\n );\n}\n\nexport function useI18n(): I18nContextValue {\n return useContext(I18nContext);\n}\n", "/**\n * Internationalization (i18n) Configuration\n *\n * Provides language support for Chinese and English\n *\n * @module config/i18n\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\n/** Supported languages */\nexport type Language = 'zh' | 'en';\n\n/** Language preference storage path */\nconst LANG_FILE = path.join(os.homedir(), '.xray-manager-lang');\n\n/** Translation interface */\nexport interface Translations {\n // Menu items\n menu: {\n viewStatus: string;\n startService: string;\n stopService: string;\n restartService: string;\n userManagement: string;\n quotaManagement: string;\n configManagement: string;\n viewLogs: string;\n switchLanguage: string;\n exit: string;\n onlineUsers: string;\n subscriptions: string;\n };\n\n // Menu hints (shown next to menu items)\n hints: {\n viewDetails: string;\n liveConnections: string;\n addDeleteShare: string;\n limitsUsage: string;\n subLinkServer: string;\n backupRestore: string;\n accessError: string;\n };\n\n // Status labels\n status: {\n serviceStatus: string;\n userCount: string;\n active: string;\n inactive: string;\n unknown: string;\n running: string;\n stopped: string;\n loading: string;\n error: string;\n };\n\n // UI common\n ui: {\n navigate: string;\n select: string;\n search: string;\n quit: string;\n back: string;\n add: string;\n delete_: string;\n share: string;\n details: string;\n refresh: string;\n follow: string;\n scroll: string;\n switchLog: string;\n setQuota: string;\n resetUsage: string;\n reenable: string;\n start: string;\n stop: string;\n entries: string;\n users: string;\n noData: string;\n processing: string;\n autoRefresh: string;\n never: string;\n expired: string;\n daysLeft: string;\n unlimited: string;\n createBackup: string;\n existing: string;\n custom: string;\n confirmStop: string;\n confirmRestart: string;\n userCreated: string;\n email: string;\n uuid: string;\n expiry: string;\n expiryDaysPrompt: string;\n emailPrompt: string;\n selectUser: string;\n selectQuota: string;\n noUsers: string;\n noConnections: string;\n noEntries: string;\n noQuotas: string;\n pressEscBack: string;\n };\n\n // Quota labels\n quota: {\n title: string;\n list: string;\n set: string;\n show: string;\n reset: string;\n reenable: string;\n unlimited: string;\n used: string;\n remaining: string;\n exceeded: string;\n warning: string;\n normal: string;\n noQuota: string;\n selectUser: string;\n selectPreset: string;\n enterCustom: string;\n confirmReset: string;\n confirmReenable: string;\n executeCheck: string;\n checkComplete: string;\n normalUsers: string;\n warningUsers: string;\n exceededUsers: string;\n disabledUsers: string;\n };\n\n // Logs labels\n logs: {\n title: string;\n accessLog: string;\n errorLog: string;\n noLogs: string;\n logFileNotFound: string;\n logFileEmpty: string;\n showingLines: string;\n };\n\n // Config labels\n config: {\n title: string;\n viewConfig: string;\n backupConfig: string;\n restoreConfig: string;\n backupSuccess: string;\n restoreSuccess: string;\n noBackups: string;\n selectBackup: string;\n confirmRestore: string;\n restoreWarning: string;\n };\n\n // Public IP labels\n publicIp: {\n detecting: string;\n detected: string;\n detectionFailed: string;\n enterManually: string;\n invalidIp: string;\n saved: string;\n natDetected: string;\n };\n\n // Common actions\n actions: {\n selectAction: string;\n confirm: string;\n cancel: string;\n back: string;\n };\n\n // Messages\n messages: {\n languageSwitched: string;\n operationSuccess: string;\n operationFailed: string;\n thankYou: string;\n terminalTooNarrow: string;\n terminalTooShort: string;\n terminalResizeSuggestion: string;\n quotaSet: string;\n quotaReset: string;\n userReenabled: string;\n noUsersWithQuota: string;\n noDisabledUsers: string;\n };\n}\n\n/** Chinese translations */\nconst zhTranslations: Translations = {\n menu: {\n viewStatus: '\u670D\u52A1\u72B6\u6001',\n startService: '\u542F\u52A8\u670D\u52A1',\n stopService: '\u505C\u6B62\u670D\u52A1',\n restartService: '\u91CD\u542F\u670D\u52A1',\n userManagement: '\u7528\u6237\u7BA1\u7406',\n quotaManagement: '\u6D41\u91CF\u914D\u989D',\n configManagement: '\u914D\u7F6E\u7BA1\u7406',\n viewLogs: '\u67E5\u770B\u65E5\u5FD7',\n switchLanguage: '\u5207\u6362\u8BED\u8A00',\n exit: '\u9000\u51FA',\n onlineUsers: '\u5728\u7EBF\u7528\u6237',\n subscriptions: '\u8BA2\u9605\u94FE\u63A5',\n },\n hints: {\n viewDetails: '\u67E5\u770B\u8BE6\u60C5',\n liveConnections: '\u5B9E\u65F6\u8FDE\u63A5',\n addDeleteShare: '\u589E / \u5220 / \u5206\u4EAB',\n limitsUsage: '\u9650\u989D\u4E0E\u7528\u91CF',\n subLinkServer: '\u8BA2\u9605\u670D\u52A1',\n backupRestore: '\u5907\u4EFD / \u6062\u590D',\n accessError: '\u8BBF\u95EE\u4E0E\u9519\u8BEF',\n },\n status: {\n serviceStatus: '\u670D\u52A1\u72B6\u6001',\n userCount: '\u7528\u6237\u6570',\n active: '\u8FD0\u884C\u4E2D',\n inactive: '\u5DF2\u505C\u6B62',\n unknown: '\u672A\u77E5',\n running: '\u8FD0\u884C\u4E2D',\n stopped: '\u5DF2\u505C\u6B62',\n loading: '\u52A0\u8F7D\u4E2D',\n error: '\u9519\u8BEF',\n },\n ui: {\n navigate: '\u5BFC\u822A',\n select: '\u9009\u62E9',\n search: '\u641C\u7D22',\n quit: '\u9000\u51FA',\n back: '\u8FD4\u56DE',\n add: '\u6DFB\u52A0',\n delete_: '\u5220\u9664',\n share: '\u5206\u4EAB',\n details: '\u8BE6\u60C5',\n refresh: '\u5237\u65B0',\n follow: '\u8DDF\u968F',\n scroll: '\u6EDA\u52A8',\n switchLog: '\u5207\u6362\u65E5\u5FD7',\n setQuota: '\u8BBE\u7F6E\u914D\u989D',\n resetUsage: '\u91CD\u7F6E\u7528\u91CF',\n reenable: '\u91CD\u65B0\u542F\u7528',\n start: '\u542F\u52A8',\n stop: '\u505C\u6B62',\n entries: '\u6761\u8BB0\u5F55',\n users: '\u7528\u6237',\n noData: '\u6682\u65E0\u6570\u636E',\n processing: '\u5904\u7406\u4E2D...',\n autoRefresh: '\u81EA\u52A8\u5237\u65B0',\n never: '\u6C38\u4E0D',\n expired: '\u5DF2\u8FC7\u671F',\n daysLeft: '\u5929\u540E\u5230\u671F',\n unlimited: '\u65E0\u9650\u5236',\n createBackup: '\u521B\u5EFA\u5907\u4EFD',\n existing: '\u4E2A\u5DF2\u6709',\n custom: '\u81EA\u5B9A\u4E49...',\n confirmStop: '\u505C\u6B62\u670D\u52A1\uFF1F\u6D3B\u8DC3\u8FDE\u63A5\u5C06\u65AD\u5F00\u3002',\n confirmRestart: '\u91CD\u542F\u670D\u52A1\uFF1F\u6D3B\u8DC3\u8FDE\u63A5\u5C06\u65AD\u5F00\u3002',\n userCreated: '\u7528\u6237\u5DF2\u521B\u5EFA',\n email: '\u90AE\u7BB1',\n uuid: 'UUID',\n expiry: '\u5230\u671F',\n expiryDaysPrompt: '\u5230\u671F\u5929\u6570 (\u7559\u7A7A=\u6C38\u4E0D):',\n emailPrompt: '\u90AE\u7BB1:',\n selectUser: '\u9009\u62E9\u7528\u6237:',\n selectQuota: '\u9009\u62E9\u914D\u989D:',\n noUsers: '\u6682\u65E0\u7528\u6237',\n noConnections: '\u65E0\u6D3B\u8DC3\u8FDE\u63A5',\n noEntries: '\u6682\u65E0\u8BB0\u5F55',\n noQuotas: '\u6682\u65E0\u914D\u989D\u914D\u7F6E',\n pressEscBack: '\u6309 esc \u8FD4\u56DE',\n },\n quota: {\n title: '\u6D41\u91CF\u914D\u989D\u7BA1\u7406',\n list: '\u67E5\u770B\u914D\u989D\u5217\u8868',\n set: '\u8BBE\u7F6E\u7528\u6237\u914D\u989D',\n show: '\u67E5\u770B\u914D\u989D\u8BE6\u60C5',\n reset: '\u91CD\u7F6E\u5DF2\u7528\u6D41\u91CF',\n reenable: '\u91CD\u65B0\u542F\u7528\u7528\u6237',\n unlimited: '\u65E0\u9650\u5236',\n used: '\u5DF2\u4F7F\u7528',\n remaining: '\u5269\u4F59',\n exceeded: '\u5DF2\u8D85\u989D',\n warning: '\u63A5\u8FD1\u9650\u989D',\n normal: '\u6B63\u5E38',\n noQuota: '\u672A\u8BBE\u7F6E\u914D\u989D',\n selectUser: '\u8BF7\u9009\u62E9\u7528\u6237',\n selectPreset: '\u8BF7\u9009\u62E9\u9884\u8BBE\u914D\u989D',\n enterCustom: '\u8BF7\u8F93\u5165\u81EA\u5B9A\u4E49\u914D\u989D',\n confirmReset: '\u786E\u5B9A\u8981\u91CD\u7F6E\u8BE5\u7528\u6237\u7684\u5DF2\u7528\u6D41\u91CF\u5417\uFF1F',\n confirmReenable: '\u786E\u5B9A\u8981\u91CD\u65B0\u542F\u7528\u8BE5\u7528\u6237\u5417\uFF1F',\n executeCheck: '\u6267\u884C\u914D\u989D\u68C0\u67E5',\n checkComplete: '\u914D\u989D\u68C0\u67E5\u5B8C\u6210',\n normalUsers: '\u6B63\u5E38\u7528\u6237',\n warningUsers: '\u8B66\u544A\u7528\u6237',\n exceededUsers: '\u8D85\u9650\u7528\u6237',\n disabledUsers: '\u5DF2\u7981\u7528',\n },\n logs: {\n title: '\u65E5\u5FD7\u67E5\u770B',\n accessLog: '\u8BBF\u95EE\u65E5\u5FD7',\n errorLog: '\u9519\u8BEF\u65E5\u5FD7',\n noLogs: '\u6682\u65E0\u65E5\u5FD7',\n logFileNotFound: '\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728',\n logFileEmpty: '\u65E5\u5FD7\u6587\u4EF6\u4E3A\u7A7A',\n showingLines: '\u663E\u793A\u6700\u8FD1 {lines} \u884C',\n },\n config: {\n title: '\u914D\u7F6E\u7BA1\u7406',\n viewConfig: '\u67E5\u770B\u5F53\u524D\u914D\u7F6E',\n backupConfig: '\u5907\u4EFD\u914D\u7F6E',\n restoreConfig: '\u6062\u590D\u914D\u7F6E',\n backupSuccess: '\u914D\u7F6E\u5DF2\u5907\u4EFD\u5230: {path}',\n restoreSuccess: '\u914D\u7F6E\u5DF2\u6062\u590D',\n noBackups: '\u6682\u65E0\u5907\u4EFD\u6587\u4EF6',\n selectBackup: '\u8BF7\u9009\u62E9\u8981\u6062\u590D\u7684\u5907\u4EFD',\n confirmRestore: '\u786E\u5B9A\u8981\u6062\u590D\u6B64\u5907\u4EFD\u5417\uFF1F',\n restoreWarning: '\u6062\u590D\u914D\u7F6E\u5C06\u8986\u76D6\u5F53\u524D\u914D\u7F6E\u5E76\u91CD\u542F\u670D\u52A1',\n },\n publicIp: {\n detecting: '\u6B63\u5728\u68C0\u6D4B\u516C\u7F51 IP...',\n detected: '\u68C0\u6D4B\u5230\u516C\u7F51 IP: {ip}',\n detectionFailed: '\u65E0\u6CD5\u81EA\u52A8\u68C0\u6D4B\u516C\u7F51 IP',\n enterManually: '\u8BF7\u624B\u52A8\u8F93\u5165\u516C\u7F51 IP \u5730\u5740',\n invalidIp: '\u65E0\u6548\u7684 IP \u5730\u5740\u683C\u5F0F',\n saved: '\u516C\u7F51 IP \u5DF2\u4FDD\u5B58',\n natDetected: '\u68C0\u6D4B\u5230 NAT \u73AF\u5883 (\u79C1\u6709 IP: {ip})',\n },\n actions: {\n selectAction: '\u8BF7\u9009\u62E9\u64CD\u4F5C',\n confirm: '\u786E\u8BA4',\n cancel: '\u53D6\u6D88',\n back: '\u8FD4\u56DE',\n },\n messages: {\n languageSwitched: '\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A\u4E2D\u6587',\n operationSuccess: '\u64CD\u4F5C\u6210\u529F',\n operationFailed: '\u64CD\u4F5C\u5931\u8D25',\n thankYou: '\u611F\u8C22\u4F7F\u7528 Xray Manager!',\n terminalTooNarrow: '\u7EC8\u7AEF\u5BBD\u5EA6\u8FC7\u7A84',\n terminalTooShort: '\u7EC8\u7AEF\u9AD8\u5EA6\u8FC7\u4F4E',\n terminalResizeSuggestion: '\u8BF7\u8C03\u6574\u7EC8\u7AEF\u5927\u5C0F\u4EE5\u83B7\u5F97\u6700\u4F73\u663E\u793A\u6548\u679C',\n quotaSet: '\u914D\u989D\u8BBE\u7F6E\u6210\u529F',\n quotaReset: '\u5DF2\u7528\u6D41\u91CF\u5DF2\u91CD\u7F6E',\n userReenabled: '\u7528\u6237\u5DF2\u91CD\u65B0\u542F\u7528',\n noUsersWithQuota: '\u6682\u65E0\u8BBE\u7F6E\u914D\u989D\u7684\u7528\u6237',\n noDisabledUsers: '\u6682\u65E0\u88AB\u7981\u7528\u7684\u7528\u6237',\n },\n};\n\n/** English translations */\nconst enTranslations: Translations = {\n menu: {\n viewStatus: 'Service Status',\n startService: 'Start Service',\n stopService: 'Stop Service',\n restartService: 'Restart Service',\n userManagement: 'User Management',\n quotaManagement: 'Traffic & Quotas',\n configManagement: 'Configuration',\n viewLogs: 'View Logs',\n switchLanguage: 'Switch Language',\n exit: 'Exit',\n onlineUsers: 'Online Users',\n subscriptions: 'Subscriptions',\n },\n hints: {\n viewDetails: 'view details',\n liveConnections: 'live connections',\n addDeleteShare: 'add / delete / share',\n limitsUsage: 'limits & usage',\n subLinkServer: 'sub link server',\n backupRestore: 'backup / restore',\n accessError: 'access & error',\n },\n status: {\n serviceStatus: 'Service Status',\n userCount: 'User Count',\n active: 'Active',\n inactive: 'Inactive',\n unknown: 'Unknown',\n running: 'Running',\n stopped: 'Stopped',\n loading: 'Loading',\n error: 'Error',\n },\n ui: {\n navigate: 'navigate',\n select: 'select',\n search: 'search',\n quit: 'quit',\n back: 'back',\n add: 'add',\n delete_: 'delete',\n share: 'share',\n details: 'details',\n refresh: 'refresh',\n follow: 'follow',\n scroll: 'scroll',\n switchLog: 'switch log',\n setQuota: 'set quota',\n resetUsage: 'reset usage',\n reenable: 're-enable',\n start: 'start',\n stop: 'stop',\n entries: 'entries',\n users: 'users',\n noData: 'No data',\n processing: 'Processing...',\n autoRefresh: 'Auto-refresh',\n never: 'Never',\n expired: 'Expired',\n daysLeft: 'd left',\n unlimited: 'Unlimited',\n createBackup: 'Create Backup',\n existing: 'existing',\n custom: 'Custom...',\n confirmStop: 'Stop service? Active connections will be dropped.',\n confirmRestart: 'Restart service? Active connections will be dropped.',\n userCreated: 'User created',\n email: 'Email',\n uuid: 'UUID',\n expiry: 'Expiry',\n expiryDaysPrompt: 'Expiry (days, empty=never):',\n emailPrompt: 'Email:',\n selectUser: 'Select user:',\n selectQuota: 'Select quota:',\n noUsers: 'No users configured',\n noConnections: 'No active connections',\n noEntries: 'No entries',\n noQuotas: 'No quotas configured',\n pressEscBack: 'press esc to go back',\n },\n quota: {\n title: 'Traffic Quota Management',\n list: 'View Quota List',\n set: 'Set User Quota',\n show: 'View Quota Details',\n reset: 'Reset Used Traffic',\n reenable: 'Re-enable User',\n unlimited: 'Unlimited',\n used: 'Used',\n remaining: 'Remaining',\n exceeded: 'Exceeded',\n warning: 'Warning',\n normal: 'Normal',\n noQuota: 'No quota set',\n selectUser: 'Select a user',\n selectPreset: 'Select a preset quota',\n enterCustom: 'Enter custom quota',\n confirmReset: \"Are you sure you want to reset this user's traffic?\",\n confirmReenable: 'Are you sure you want to re-enable this user?',\n executeCheck: 'Execute Quota Check',\n checkComplete: 'Quota check complete',\n normalUsers: 'Normal users',\n warningUsers: 'Warning users',\n exceededUsers: 'Exceeded users',\n disabledUsers: 'Disabled',\n },\n logs: {\n title: 'Log Viewer',\n accessLog: 'Access Log',\n errorLog: 'Error Log',\n noLogs: 'No logs available',\n logFileNotFound: 'Log file not found',\n logFileEmpty: 'Log file is empty',\n showingLines: 'Showing last {lines} lines',\n },\n config: {\n title: 'Config Management',\n viewConfig: 'View Current Config',\n backupConfig: 'Backup Config',\n restoreConfig: 'Restore Config',\n backupSuccess: 'Config backed up to: {path}',\n restoreSuccess: 'Config restored successfully',\n noBackups: 'No backup files available',\n selectBackup: 'Select a backup to restore',\n confirmRestore: 'Are you sure you want to restore this backup?',\n restoreWarning: 'Restoring will overwrite current config and restart service',\n },\n publicIp: {\n detecting: 'Detecting public IP...',\n detected: 'Detected public IP: {ip}',\n detectionFailed: 'Failed to detect public IP automatically',\n enterManually: 'Please enter public IP address manually',\n invalidIp: 'Invalid IP address format',\n saved: 'Public IP saved',\n natDetected: 'NAT environment detected (private IP: {ip})',\n },\n actions: {\n selectAction: 'Please select an action',\n confirm: 'Confirm',\n cancel: 'Cancel',\n back: 'Back',\n },\n messages: {\n languageSwitched: 'Language switched to English',\n operationSuccess: 'Operation successful',\n operationFailed: 'Operation failed',\n thankYou: 'Thank you for using Xray Manager!',\n terminalTooNarrow: 'Terminal width is too narrow',\n terminalTooShort: 'Terminal height is too short',\n terminalResizeSuggestion: 'Please resize your terminal for optimal display',\n quotaSet: 'Quota set successfully',\n quotaReset: 'Used traffic has been reset',\n userReenabled: 'User has been re-enabled',\n noUsersWithQuota: 'No users with quota configured',\n noDisabledUsers: 'No disabled users',\n },\n};\n\n/** All translations */\nconst translations: Record<Language, Translations> = {\n zh: zhTranslations,\n en: enTranslations,\n};\n\n/** Current language (default: English) */\nlet currentLanguage: Language = 'en';\n\n/**\n * Load language preference from file\n */\nexport function loadLanguagePreference(): Language {\n try {\n if (fs.existsSync(LANG_FILE)) {\n const lang = fs.readFileSync(LANG_FILE, 'utf-8').trim();\n if (lang === 'zh' || lang === 'en') {\n currentLanguage = lang;\n return lang;\n }\n }\n } catch {\n // Ignore errors, use default\n }\n return 'en'; // Default to English\n}\n\n/**\n * Save language preference to file\n */\nexport function saveLanguagePreference(lang: Language): void {\n try {\n fs.writeFileSync(LANG_FILE, lang, 'utf-8');\n currentLanguage = lang;\n } catch {\n // Ignore errors\n }\n}\n\n/**\n * Get current language\n */\nexport function getCurrentLanguage(): Language {\n return currentLanguage;\n}\n\n/**\n * Set current language\n */\nexport function setLanguage(lang: Language): void {\n currentLanguage = lang;\n saveLanguagePreference(lang);\n}\n\n/**\n * Toggle language (switch between zh and en)\n */\nexport function toggleLanguage(): Language {\n const newLang = currentLanguage === 'zh' ? 'en' : 'zh';\n setLanguage(newLang);\n return newLang;\n}\n\n/**\n * Get translations for current language\n */\nexport function t(): Translations {\n return translations[currentLanguage];\n}\n\n/**\n * Get translation for specific language\n */\nexport function getTranslations(lang: Language): Translations {\n return translations[lang];\n}\n\n// Load language preference on module initialization\nloadLanguagePreference();\n", "import React, { createContext, useContext, useMemo } from 'react';\nimport { ConfigManager } from '../services/config-manager.js';\nimport { UserManager } from '../services/user-manager.js';\nimport { SystemdManager } from '../services/systemd-manager.js';\nimport { QuotaManager } from '../services/quota-manager.js';\nimport { TrafficManager } from '../services/traffic-manager.js';\nimport { LogManager } from '../services/log-manager.js';\nimport { StatsConfigManager } from '../services/stats-config-manager.js';\n\nexport interface ServiceInstances {\n configManager: ConfigManager;\n userManager: UserManager;\n systemdManager: SystemdManager;\n quotaManager: QuotaManager;\n trafficManager: TrafficManager;\n logManager: LogManager;\n statsConfigManager: StatsConfigManager;\n}\n\nexport interface ServiceOptions {\n configPath?: string;\n serviceName?: string;\n}\n\nconst ServiceContext = createContext<ServiceInstances | null>(null);\n\nexport function ServiceProvider({\n children,\n options,\n}: {\n children: React.ReactNode;\n options: ServiceOptions;\n}) {\n const services = useMemo(() => {\n const serviceName = options.serviceName ?? 'xray';\n return {\n configManager: new ConfigManager(options.configPath),\n userManager: new UserManager(options.configPath, serviceName),\n systemdManager: new SystemdManager(serviceName),\n quotaManager: new QuotaManager(),\n trafficManager: new TrafficManager(),\n logManager: new LogManager(serviceName),\n statsConfigManager: new StatsConfigManager(options.configPath, serviceName),\n };\n }, [options.configPath, options.serviceName]);\n\n return <ServiceContext.Provider value={services}>{children}</ServiceContext.Provider>;\n}\n\nexport function useServices(): ServiceInstances {\n const ctx = useContext(ServiceContext);\n if (!ctx) throw new Error('useServices must be used within ServiceProvider');\n return ctx;\n}\n", "/**\n * ConfigManager - Xray Configuration File Management\n *\n * Provides safe interface to read, write, validate, and backup Xray config\n *\n * @module services/config-manager\n */\n\nimport { readFile, writeFile, mkdir, chmod, access, readdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { DEFAULT_PATHS } from '../constants/paths';\nimport type { XrayConfig } from '../types/config';\nimport { ConfigError } from '../utils/errors';\nimport { ConfigErrors } from '../constants/error-codes';\n\n/**\n * ConfigManager - Safe configuration file operations\n */\nexport class ConfigManager {\n private configPath: string;\n private backupDir: string;\n\n /**\n * Create a new ConfigManager\n *\n * @param configPath - Path to config file (default: /usr/local/etc/xray/config.json)\n */\n constructor(configPath?: string) {\n this.configPath = configPath || DEFAULT_PATHS.CONFIG_FILE;\n this.backupDir = DEFAULT_PATHS.BACKUP_DIR || '/var/backups/xray';\n }\n\n /**\n * Read and parse config file\n *\n * @returns Parsed configuration object\n */\n async readConfig(): Promise<XrayConfig> {\n try {\n const content = await readFile(this.configPath, 'utf-8');\n const config = JSON.parse(content) as XrayConfig;\n return config;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new ConfigError(ConfigErrors.CONFIG_NOT_FOUND, this.configPath);\n } else if ((error as NodeJS.ErrnoException).code === 'EACCES') {\n throw new ConfigError(ConfigErrors.CONFIG_NO_READ_PERMISSION, this.configPath);\n } else if (error instanceof SyntaxError) {\n throw new ConfigError(ConfigErrors.CONFIG_INVALID_JSON, (error as Error).message);\n }\n throw error;\n }\n }\n\n /**\n * Write config to file with secure permissions\n *\n * @param config - Configuration object to write\n */\n async writeConfig(config: XrayConfig): Promise<void> {\n try {\n // Validate config before writing\n this.validateConfig(config);\n\n // Ensure directory exists\n const dir = dirname(this.configPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n\n // Write with pretty formatting\n const content = JSON.stringify(config, null, 2);\n await writeFile(this.configPath, content, 'utf-8');\n\n // Set secure permissions (600 = rw-------)\n await chmod(this.configPath, 0o600);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'EACCES') {\n throw new ConfigError(ConfigErrors.CONFIG_NO_WRITE_PERMISSION, this.configPath);\n }\n throw error;\n }\n }\n\n /**\n * Validate configuration structure\n *\n * @param config - Configuration to validate\n * @throws Error if validation fails\n */\n validateConfig(config: XrayConfig): void {\n if (!config || typeof config !== 'object') {\n throw new ConfigError(ConfigErrors.CONFIG_INVALID_STRUCTURE, '\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61');\n }\n\n // Check for required top-level fields\n if (!config.inbounds || !Array.isArray(config.inbounds)) {\n throw new ConfigError(ConfigErrors.CONFIG_INVALID_STRUCTURE, '\u7F3A\u5C11 inbounds \u6570\u7EC4');\n }\n\n if (!config.outbounds || !Array.isArray(config.outbounds)) {\n throw new ConfigError(ConfigErrors.CONFIG_INVALID_STRUCTURE, '\u7F3A\u5C11 outbounds \u6570\u7EC4');\n }\n\n // Validate inbounds\n for (const inbound of config.inbounds) {\n if (!inbound.protocol) {\n throw new ConfigError(ConfigErrors.CONFIG_INVALID_STRUCTURE, 'inbound \u7F3A\u5C11 protocol');\n }\n if (typeof inbound.port !== 'number') {\n throw new ConfigError(ConfigErrors.CONFIG_INVALID_STRUCTURE, 'inbound \u7F3A\u5C11\u6709\u6548 port');\n }\n }\n\n // Validate outbounds\n for (const outbound of config.outbounds) {\n if (!outbound.protocol) {\n throw new ConfigError(ConfigErrors.CONFIG_INVALID_STRUCTURE, 'outbound \u7F3A\u5C11 protocol');\n }\n }\n }\n\n /**\n * Backup configuration file\n *\n * @returns Path to backup file\n */\n async backupConfig(): Promise<string> {\n try {\n // Ensure backup directory exists\n if (!existsSync(this.backupDir)) {\n await mkdir(this.backupDir, { recursive: true, mode: 0o700 });\n }\n\n // Generate timestamp-based backup filename\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\n const backupPath = join(this.backupDir, `config.${timestamp}.json`);\n\n // Read current config\n const config = await this.readConfig();\n\n // Write backup\n const content = JSON.stringify(config, null, 2);\n await writeFile(backupPath, content, 'utf-8');\n await chmod(backupPath, 0o600);\n\n return backupPath;\n } catch (error) {\n throw new ConfigError(ConfigErrors.CONFIG_BACKUP_FAILED, (error as Error).message);\n }\n }\n\n /**\n * List available backups\n *\n * @returns Array of backup file paths\n */\n async listBackups(): Promise<string[]> {\n try {\n if (!existsSync(this.backupDir)) {\n return [];\n }\n\n const files = await readdir(this.backupDir);\n const backups = files\n .filter((file) => file.startsWith('config.') && file.endsWith('.json'))\n .map((file) => join(this.backupDir, file))\n .sort()\n .reverse(); // Most recent first\n\n return backups;\n } catch (error) {\n throw new ConfigError(ConfigErrors.CONFIG_BACKUP_FAILED, (error as Error).message);\n }\n }\n\n /**\n * Restore configuration from backup\n *\n * @param backupPath - Path to backup file\n */\n async restoreConfig(backupPath: string): Promise<void> {\n try {\n // Verify backup file exists\n await access(backupPath);\n\n // Backup current config first (pre-restore backup)\n await this.backupConfig();\n\n // Read backup content\n const content = await readFile(backupPath, 'utf-8');\n const config = JSON.parse(content) as XrayConfig;\n\n // Validate and write\n await this.writeConfig(config);\n } catch (error) {\n throw new ConfigError(ConfigErrors.CONFIG_RESTORE_FAILED, (error as Error).message);\n }\n }\n\n /**\n * Modify a configuration item\n *\n * @param path - Dot-separated path to config item (e.g., \"log.loglevel\")\n * @param value - New value\n */\n async modifyConfigItem(path: string, value: unknown): Promise<void> {\n const config = await this.readConfig();\n\n // Split path and navigate to parent object\n const parts = path.split('.');\n let current: Record<string, unknown> = config as unknown as Record<string, unknown>;\n\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) {\n current[parts[i]] = {};\n }\n current = current[parts[i]] as Record<string, unknown>;\n }\n\n // Set value\n const lastPart = parts[parts.length - 1];\n current[lastPart] = value;\n\n // Validate and write\n await this.writeConfig(config);\n }\n\n /**\n * Get formatted configuration for display\n *\n * @returns Pretty-printed JSON string\n */\n async getFormattedConfig(): Promise<string> {\n const config = await this.readConfig();\n return JSON.stringify(config, null, 2);\n }\n\n /**\n * List available backups with metadata\n *\n * @returns Array of backup info objects\n */\n async listBackupsWithInfo(): Promise<\n Array<{ path: string; filename: string; createdAt: Date; size: number }>\n > {\n const backupPaths = await this.listBackups();\n const backupsWithInfo = [];\n\n for (const backupPath of backupPaths) {\n try {\n const stats = await import('fs/promises').then((fs) => fs.stat(backupPath));\n const filename = backupPath.split('/').pop() || '';\n\n // Extract timestamp from filename: config.2024-01-15T10-30-00-000Z.json\n let createdAt = stats.mtime;\n const timestampMatch = filename.match(/config\\.(\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2})/);\n if (timestampMatch) {\n const isoString = timestampMatch[1].replace(/-/g, (match, offset) => {\n // Replace dashes in time portion with colons\n return offset > 10 ? ':' : '-';\n });\n try {\n createdAt = new Date(isoString);\n } catch {\n // Use file mtime as fallback\n }\n }\n\n backupsWithInfo.push({\n path: backupPath,\n filename,\n createdAt,\n size: stats.size,\n });\n } catch {\n // Skip files we can't stat\n continue;\n }\n }\n\n return backupsWithInfo;\n }\n\n /**\n * Restore configuration from backup with optional service restart\n *\n * @param backupPath - Path to backup file\n * @param restartService - Whether to restart service after restore (default: true)\n */\n async restoreFromBackup(backupPath: string, restartService: boolean = true): Promise<void> {\n // First restore the config\n await this.restoreConfig(backupPath);\n\n // Optionally restart service\n if (restartService) {\n const { SystemdManager } = await import('./systemd-manager');\n const systemd = new SystemdManager(DEFAULT_PATHS.SERVICE_NAME);\n await systemd.restart();\n }\n }\n}\n", "/**\n * UserManager - User Management with Auto UUID Generation\n *\n * Provides safe user management with automatic service restart\n *\n * @module services/user-manager\n */\n\nimport { randomUUID, createPrivateKey, createPublicKey } from 'crypto';\nimport { URLSearchParams } from 'url';\nimport { ConfigManager } from './config-manager';\nimport { SystemdManager } from './systemd-manager';\nimport { PublicIpManager } from './public-ip-manager';\nimport { UserMetadataManager } from './user-metadata-manager';\nimport type { User, CreateUserParams, UserShareInfo } from '../types/user';\nimport { isValidEmail } from '../utils/validator';\nimport { UserError, NetworkError } from '../utils/errors';\nimport { UserErrors, NetworkErrors, ConfigErrors } from '../constants/error-codes';\nimport { ConfigError } from '../utils/errors';\n\n/**\n * Generate X25519 public key from private key\n *\n * @param privateKeyBase64 - Base64URL encoded private key (32 bytes)\n * @returns Base64URL encoded public key\n */\nfunction generatePublicKeyFromPrivate(privateKeyBase64: string): string {\n try {\n // Decode the raw private key (32 bytes)\n const privateKeyBuffer = Buffer.from(privateKeyBase64, 'base64url');\n\n // X25519 PKCS#8 DER header (for 32-byte raw key)\n const pkcs8Header = Buffer.from([\n 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04,\n 0x20,\n ]);\n\n const privateKeyDer = Buffer.concat([pkcs8Header, privateKeyBuffer]);\n\n const privateKey = createPrivateKey({\n key: privateKeyDer,\n format: 'der',\n type: 'pkcs8',\n });\n\n const publicKey = createPublicKey(privateKey);\n const publicKeySpki = publicKey.export({ type: 'spki', format: 'der' });\n\n // Extract the raw public key (last 32 bytes of SPKI)\n const publicKeyRaw = publicKeySpki.slice(-32);\n return publicKeyRaw.toString('base64url');\n } catch {\n throw new UserError(UserErrors.KEY_GENERATION_FAILED);\n }\n}\n\n/**\n * UserManager - Manage Xray users\n */\nexport class UserManager {\n private configManager: ConfigManager;\n private systemdManager: SystemdManager;\n private publicIpManager: PublicIpManager;\n private metadataManager: UserMetadataManager;\n private serviceName: string;\n\n /**\n * Create a new UserManager\n *\n * @param configPath - Optional config file path\n * @param serviceName - Service name (default: xray)\n */\n constructor(configPath?: string, serviceName: string = 'xray') {\n this.configManager = new ConfigManager(configPath);\n this.systemdManager = new SystemdManager(serviceName);\n this.publicIpManager = new PublicIpManager();\n this.metadataManager = new UserMetadataManager();\n this.serviceName = serviceName;\n }\n\n /**\n * Generate a new UUID v4 using crypto.randomUUID()\n *\n * @returns UUID string\n */\n generateUuid(): string {\n return randomUUID();\n }\n\n /**\n * Validate email address\n *\n * @param email - Email to validate\n * @throws Error if email is invalid\n */\n validateEmail(email: string): void {\n if (!isValidEmail(email)) {\n throw new UserError(UserErrors.INVALID_EMAIL, email);\n }\n }\n\n /**\n * List all users from config\n *\n * @returns Array of users\n */\n async listUsers(): Promise<User[]> {\n const config = await this.configManager.readConfig();\n const allMetadata = await this.metadataManager.getAllMetadata();\n const users: User[] = [];\n\n // Extract users from all inbounds\n for (const inbound of config.inbounds || []) {\n if (inbound.settings?.clients) {\n for (const client of inbound.settings.clients) {\n const metadata = allMetadata[client.id];\n users.push({\n id: client.id,\n email: client.email || '',\n level: client.level || 0,\n flow: client.flow,\n createdAt: metadata?.createdAt || new Date().toISOString(),\n status: metadata?.status || 'active',\n expiryDate: metadata?.expiryDate,\n dataLimit: metadata?.dataLimit,\n maxConnections: metadata?.maxConnections,\n subscriptionToken: metadata?.subscriptionToken,\n });\n }\n }\n }\n\n return users;\n }\n\n /**\n * Add a new user with auto-generated UUID\n *\n * @param params - User creation parameters\n * @returns Created user\n */\n async addUser(params: CreateUserParams): Promise<User> {\n // Validate email\n this.validateEmail(params.email);\n\n // Check for duplicate email\n const existingUsers = await this.listUsers();\n const duplicate = existingUsers.find((u) => u.email === params.email);\n if (duplicate) {\n throw new UserError(UserErrors.EMAIL_EXISTS, params.email);\n }\n\n // Backup config before modification\n await this.configManager.backupConfig();\n\n // Generate UUID\n const id = this.generateUuid();\n const now = new Date().toISOString();\n\n // Calculate expiry date\n let expiryDate: string | undefined;\n if (params.expiryDate) {\n expiryDate = params.expiryDate;\n } else if (params.expiryDays && params.expiryDays > 0) {\n const expiry = new Date();\n expiry.setDate(expiry.getDate() + params.expiryDays);\n expiryDate = expiry.toISOString();\n }\n\n // Create user object\n const newUser: User = {\n id,\n email: params.email,\n level: params.level ?? 0,\n flow: params.flow,\n createdAt: now,\n status: 'active',\n expiryDate,\n dataLimit: params.dataLimit,\n maxConnections: params.maxConnections,\n };\n\n // Read config\n const config = await this.configManager.readConfig();\n\n // Find first VLESS or VMess inbound and add user\n let added = false;\n for (const inbound of config.inbounds || []) {\n if (inbound.protocol === 'vless' || inbound.protocol === 'vmess') {\n if (!inbound.settings) {\n inbound.settings = { clients: [] };\n }\n if (!inbound.settings.clients) {\n inbound.settings.clients = [];\n }\n\n // Determine flow value: use provided, or default for VLESS + REALITY\n let flowValue = params.flow;\n if (!flowValue && inbound.protocol === 'vless') {\n // For VLESS with REALITY or TLS, default to xtls-rprx-vision\n const security = inbound.streamSettings?.security;\n if (security === 'reality' || security === 'tls') {\n flowValue = 'xtls-rprx-vision';\n }\n }\n\n inbound.settings.clients.push({\n id,\n email: params.email,\n level: params.level,\n flow: flowValue,\n });\n\n added = true;\n break;\n }\n }\n\n if (!added) {\n throw new ConfigError(ConfigErrors.CONFIG_INVALID_STRUCTURE, '\u672A\u627E\u5230 VLESS/VMess inbound');\n }\n\n // Write config\n await this.configManager.writeConfig(config);\n\n // Create user metadata with expiry and limits\n await this.metadataManager.createUser(id);\n if (expiryDate || params.dataLimit || params.maxConnections) {\n await this.metadataManager.setMetadata(id, {\n ...(expiryDate ? { expiryDate } : {}),\n ...(params.dataLimit ? { dataLimit: params.dataLimit } : {}),\n ...(params.maxConnections ? { maxConnections: params.maxConnections } : {}),\n });\n }\n\n // Restart service\n await this.systemdManager.restart();\n\n return newUser;\n }\n\n /**\n * Delete user by ID\n *\n * @param userId - User ID (UUID) to delete\n */\n async deleteUser(userId: string): Promise<void> {\n // Backup config before modification\n await this.configManager.backupConfig();\n\n // Read config\n const config = await this.configManager.readConfig();\n\n // Find and remove user\n let found = false;\n for (const inbound of config.inbounds || []) {\n if (inbound.settings?.clients) {\n const index = inbound.settings.clients.findIndex((c) => c.id === userId);\n if (index !== -1) {\n inbound.settings.clients.splice(index, 1);\n found = true;\n break;\n }\n }\n }\n\n if (!found) {\n throw new UserError(UserErrors.USER_NOT_FOUND, userId);\n }\n\n // Write config\n await this.configManager.writeConfig(config);\n\n // Delete user metadata\n await this.metadataManager.deleteMetadata(userId);\n\n // Restart service\n await this.systemdManager.restart();\n }\n\n /**\n * Get share information for a user\n *\n * @param userId - User ID (UUID)\n * @returns Share information including VLESS link\n */\n async getShareInfo(userId: string): Promise<UserShareInfo> {\n const config = await this.configManager.readConfig();\n const metadata = await this.metadataManager.getMetadata(userId);\n\n // Find user in all inbounds and collect inbound info\n let user: User | undefined;\n let primaryInbound:\n | {\n port: number;\n protocol: string;\n streamSettings?: {\n network?: string;\n security?: string;\n realitySettings?: {\n privateKey: string;\n serverNames: string[];\n shortIds: string[];\n };\n wsSettings?: {\n path: string;\n headers?: Record<string, string>;\n };\n };\n }\n | undefined;\n let wsInbound:\n | {\n port: number;\n protocol: string;\n streamSettings?: {\n network?: string;\n security?: string;\n wsSettings?: {\n path: string;\n headers?: Record<string, string>;\n };\n };\n }\n | undefined;\n\n // Search through all inbounds\n for (const inbound of config.inbounds || []) {\n if (inbound.settings?.clients) {\n const client = inbound.settings.clients.find((c) => c.id === userId);\n if (client) {\n if (!user) {\n user = {\n id: client.id,\n email: client.email || '',\n level: client.level || 0,\n flow: client.flow,\n createdAt: metadata?.createdAt || new Date().toISOString(),\n status: metadata?.status || 'active',\n };\n }\n\n const network = inbound.streamSettings?.network || 'tcp';\n const security = inbound.streamSettings?.security || 'none';\n\n // Categorize inbound: WebSocket vs Primary (REALITY/TLS)\n if (network === 'ws') {\n wsInbound = {\n port: inbound.port,\n protocol: inbound.protocol,\n streamSettings: inbound.streamSettings,\n };\n } else if (security === 'reality' || security === 'tls') {\n primaryInbound = {\n port: inbound.port,\n protocol: inbound.protocol,\n streamSettings: inbound.streamSettings,\n };\n } else if (!primaryInbound) {\n // Fallback to first found inbound\n primaryInbound = {\n port: inbound.port,\n protocol: inbound.protocol,\n streamSettings: inbound.streamSettings,\n };\n }\n }\n }\n }\n\n if (!user) {\n throw new UserError(UserErrors.USER_NOT_FOUND, userId);\n }\n\n // Get public IP (from cache or detect)\n let serverAddress: string;\n try {\n serverAddress = await this.publicIpManager.getPublicIp();\n } catch {\n throw new NetworkError(NetworkErrors.PUBLIC_IP_FAILED);\n }\n\n // Use primary inbound for main link, fallback to ws if no primary\n const mainInbound = primaryInbound || wsInbound;\n if (!mainInbound) {\n throw new UserError(UserErrors.USER_NOT_FOUND, userId);\n }\n\n const port = mainInbound.port || 443;\n const security = mainInbound.streamSettings?.security || 'tls';\n const network = mainInbound.streamSettings?.network || 'tcp';\n const flow = user.flow || 'xtls-rprx-vision';\n const name = encodeURIComponent(user.email);\n\n let vlessLink: string;\n let publicKey: string | undefined;\n let shortId: string | undefined;\n let serverName: string | undefined;\n\n if (security === 'reality' && primaryInbound?.streamSettings?.realitySettings) {\n const reality = primaryInbound.streamSettings.realitySettings;\n\n // Generate public key from private key\n publicKey = generatePublicKeyFromPrivate(reality.privateKey);\n serverName = reality.serverNames[0] || 'www.microsoft.com';\n shortId = reality.shortIds[0] || '';\n\n const params = new URLSearchParams();\n params.set('encryption', 'none');\n params.set('security', 'reality');\n params.set('type', network);\n params.set('flow', flow);\n params.set('pbk', publicKey);\n params.set('fp', 'chrome');\n params.set('sni', serverName);\n params.set('sid', shortId);\n params.set('spx', '/');\n\n vlessLink = `vless://${user.id}@${serverAddress}:${port}?${params.toString()}#${name}`;\n } else {\n vlessLink = `vless://${user.id}@${serverAddress}:${port}?encryption=none&security=${security}&type=${network}&flow=${flow}#${name}`;\n }\n\n // Build CDN (WebSocket) link if ws inbound exists\n let cdnShareLink: string | undefined;\n let wsPath: string | undefined;\n\n if (wsInbound?.streamSettings?.wsSettings) {\n wsPath = wsInbound.streamSettings.wsSettings.path;\n const wsHost = wsInbound.streamSettings.wsSettings.headers?.Host || serverAddress;\n const wsSecurity = wsInbound.streamSettings.security || 'none';\n const wsPort = wsInbound.port || 443;\n\n const wsParams = new URLSearchParams({\n encryption: 'none',\n security: wsSecurity === 'tls' ? 'tls' : 'tls', // CDN always uses TLS on client side\n type: 'ws',\n host: wsHost,\n path: wsPath,\n sni: wsHost,\n });\n\n // CDN link uses domain as server address (user should replace with their CDN domain)\n cdnShareLink = `vless://${user.id}@${wsHost}:${wsPort}?${wsParams.toString()}#${encodeURIComponent(user.email + '-CDN')}`;\n }\n\n return {\n user,\n shareLink: vlessLink,\n cdnShareLink,\n serverAddress,\n serverPort: port,\n protocol: mainInbound.protocol || 'vless',\n security,\n network,\n serverName,\n publicKey,\n shortId,\n wsPath,\n qrCode: vlessLink,\n };\n }\n\n /**\n * Get CDN share link for a user with custom domain\n *\n * @param userId - User ID (UUID)\n * @param cdnDomain - CDN domain (e.g., \"example.com\")\n * @param cdnPort - CDN port (default: 443)\n * @returns CDN share link string or null if no WebSocket inbound\n */\n async getCdnShareLink(\n userId: string,\n cdnDomain: string,\n cdnPort: number = 443\n ): Promise<string | null> {\n const config = await this.configManager.readConfig();\n\n // Find WebSocket inbound with this user\n for (const inbound of config.inbounds || []) {\n if (inbound.settings?.clients) {\n const client = inbound.settings.clients.find((c) => c.id === userId);\n if (client && inbound.streamSettings?.network === 'ws') {\n const wsPath = inbound.streamSettings.wsSettings?.path || '/ws';\n\n const params = new URLSearchParams({\n encryption: 'none',\n security: 'tls',\n type: 'ws',\n host: cdnDomain,\n path: wsPath,\n sni: cdnDomain,\n });\n\n const name = encodeURIComponent((client.email || 'user') + '-CDN');\n return `vless://${client.id}@${cdnDomain}:${cdnPort}?${params.toString()}#${name}`;\n }\n }\n }\n\n return null;\n }\n\n /**\n * Check if public IP needs manual input\n *\n * @returns true if manual input is needed\n */\n async needsPublicIpInput(): Promise<boolean> {\n return this.publicIpManager.needsManualInput();\n }\n\n /**\n * Set public IP manually\n *\n * @param ip - Public IP address\n */\n async setPublicIp(ip: string): Promise<void> {\n await this.publicIpManager.setPublicIp(ip);\n }\n\n /**\n * Get current public IP (from cache)\n *\n * @returns Public IP or null if not set\n */\n async getPublicIp(): Promise<string | null> {\n const config = await this.publicIpManager.getConfig();\n return config?.publicIp || null;\n }\n\n /**\n * Get metadata manager for external access\n *\n * @returns UserMetadataManager instance\n */\n getMetadataManager(): UserMetadataManager {\n return this.metadataManager;\n }\n}\n", "/**\n * PublicIpManager - Public IP Detection and Caching Service\n *\n * Provides automatic public IP detection with fallback to manual input\n *\n * @module services/public-ip-manager\n */\n\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { dirname } from 'path';\nimport * as https from 'https';\nimport { DEFAULT_PATHS } from '../constants/paths';\nimport { isPrivateIp } from '../utils/network';\nimport type {\n ServerConfig,\n IpSource,\n IpDetectionResult,\n IpDetectionService,\n} from '../types/server-config';\n\n/**\n * Default IP detection services (in priority order)\n */\nconst IP_SERVICES: IpDetectionService[] = [\n { name: 'ipify', url: 'https://api.ipify.org', timeout: 3000 },\n { name: 'ifconfig.me', url: 'https://ifconfig.me/ip', timeout: 3000 },\n { name: 'ip.sb', url: 'https://api.ip.sb/ip', timeout: 3000 },\n];\n\n/**\n * Validate IPv4 address format\n */\nfunction isValidIpv4(ip: string): boolean {\n const ipv4Regex = /^(\\d{1,3}\\.){3}\\d{1,3}$/;\n if (!ipv4Regex.test(ip)) return false;\n\n const parts = ip.split('.');\n return parts.every((part) => {\n const num = parseInt(part, 10);\n return num >= 0 && num <= 255;\n });\n}\n\n/**\n * Validate IPv6 address format (simplified)\n */\nfunction isValidIpv6(ip: string): boolean {\n const ipv6Regex =\n /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::$|^([0-9a-fA-F]{1,4}:)*:([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4}$/;\n return ipv6Regex.test(ip);\n}\n\n/**\n * Validate IP address (IPv4 or IPv6)\n */\nexport function isValidIp(ip: string): boolean {\n return isValidIpv4(ip) || isValidIpv6(ip);\n}\n\n/**\n * Fetch IP from a single service with timeout\n */\nfunction fetchIpFromService(service: IpDetectionService): Promise<IpDetectionResult> {\n return new Promise((resolve) => {\n const timeoutId = setTimeout(() => {\n resolve({\n ip: '',\n success: false,\n error: `Timeout after ${service.timeout}ms`,\n provider: service.name,\n });\n }, service.timeout);\n\n const req = https.get(service.url, (res) => {\n let data = '';\n\n res.on('data', (chunk) => {\n data += chunk;\n });\n\n res.on('end', () => {\n clearTimeout(timeoutId);\n const ip = data.trim();\n\n if (isValidIp(ip)) {\n resolve({\n ip,\n success: true,\n provider: service.name,\n });\n } else {\n resolve({\n ip: '',\n success: false,\n error: `Invalid IP response: ${ip.substring(0, 50)}`,\n provider: service.name,\n });\n }\n });\n });\n\n req.on('error', (error) => {\n clearTimeout(timeoutId);\n resolve({\n ip: '',\n success: false,\n error: error.message,\n provider: service.name,\n });\n });\n });\n}\n\n/**\n * PublicIpManager - Manage public IP detection and caching\n */\nexport class PublicIpManager {\n private configPath: string;\n private maxRetries: number;\n\n /**\n * Create a new PublicIpManager\n *\n * @param configPath - Path to server config file\n * @param maxRetries - Maximum retry attempts (default: 1)\n */\n constructor(configPath?: string, maxRetries: number = 1) {\n this.configPath = configPath || DEFAULT_PATHS.SERVER_CONFIG_FILE;\n this.maxRetries = maxRetries;\n }\n\n /**\n * Read server config from file\n *\n * @returns ServerConfig or null if not found\n */\n async getConfig(): Promise<ServerConfig | null> {\n try {\n if (!existsSync(this.configPath)) {\n return null;\n }\n const content = await readFile(this.configPath, 'utf-8');\n return JSON.parse(content) as ServerConfig;\n } catch {\n return null;\n }\n }\n\n /**\n * Save server config to file\n *\n * @param config - ServerConfig to save\n */\n private async saveConfig(config: ServerConfig): Promise<void> {\n const dir = dirname(this.configPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(this.configPath, JSON.stringify(config, null, 2), 'utf-8');\n }\n\n /**\n * Detect public IP from external services\n *\n * @returns Detection result\n */\n private async detectPublicIp(): Promise<IpDetectionResult> {\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n for (const service of IP_SERVICES) {\n const result = await fetchIpFromService(service);\n if (result.success) {\n return result;\n }\n }\n }\n\n return {\n ip: '',\n success: false,\n error: 'All IP detection services failed after retries',\n };\n }\n\n /**\n * Get public IP (from cache or detect)\n *\n * @returns Public IP address\n * @throws Error if unable to get IP and no cache exists\n */\n async getPublicIp(): Promise<string> {\n // Try to get from cache first\n const config = await this.getConfig();\n if (config?.publicIp) {\n return config.publicIp;\n }\n\n // Try to detect\n const result = await this.detectPublicIp();\n if (result.success) {\n // Cache the result\n await this.saveConfig({\n publicIp: result.ip,\n lastUpdated: new Date().toISOString(),\n source: 'auto',\n });\n return result.ip;\n }\n\n throw new Error(result.error || 'Failed to detect public IP');\n }\n\n /**\n * Force refresh public IP (ignore cache)\n *\n * @returns New public IP address\n * @throws Error if detection fails\n */\n async refreshPublicIp(): Promise<string> {\n const result = await this.detectPublicIp();\n if (result.success) {\n await this.saveConfig({\n publicIp: result.ip,\n lastUpdated: new Date().toISOString(),\n source: 'auto',\n });\n return result.ip;\n }\n\n throw new Error(result.error || 'Failed to detect public IP');\n }\n\n /**\n * Manually set public IP\n *\n * @param ip - IP address to set\n * @throws Error if IP format is invalid\n */\n async setPublicIp(ip: string): Promise<void> {\n const trimmedIp = ip.trim();\n if (!isValidIp(trimmedIp)) {\n throw new Error(`Invalid IP address format: ${ip}`);\n }\n\n await this.saveConfig({\n publicIp: trimmedIp,\n lastUpdated: new Date().toISOString(),\n source: 'manual',\n });\n }\n\n /**\n * Check if manual IP input is needed\n *\n * @returns true if NAT environment detected or detection fails\n */\n async needsManualInput(): Promise<boolean> {\n // Check if we already have a cached IP\n const config = await this.getConfig();\n if (config?.publicIp) {\n return false;\n }\n\n // Try to detect\n const result = await this.detectPublicIp();\n if (!result.success) {\n return true;\n }\n\n // Check if detected IP is private (NAT)\n if (isPrivateIp(result.ip)) {\n return true;\n }\n\n // Cache the detected IP\n await this.saveConfig({\n publicIp: result.ip,\n lastUpdated: new Date().toISOString(),\n source: 'auto',\n });\n\n return false;\n }\n\n /**\n * Get IP source (auto or manual)\n *\n * @returns IP source or null if no config\n */\n async getIpSource(): Promise<IpSource | null> {\n const config = await this.getConfig();\n return config?.source || null;\n }\n}\n", "/**\n * Supported Linux distributions configuration\n * Feature: 009-cross-platform-support\n */\n\nimport { OsFamily, PackageManager } from '../types/platform.js';\n\nexport interface DistroConfig {\n family: OsFamily;\n minVersion: string;\n packageManager: PackageManager;\n displayName: string;\n}\n\nexport const SUPPORTED_DISTROS: Record<string, DistroConfig> = {\n ubuntu: {\n family: OsFamily.DEBIAN,\n minVersion: '22.04',\n packageManager: PackageManager.APT,\n displayName: 'Ubuntu',\n },\n debian: {\n family: OsFamily.DEBIAN,\n minVersion: '11',\n packageManager: PackageManager.APT,\n displayName: 'Debian',\n },\n kali: {\n family: OsFamily.DEBIAN,\n minVersion: '2023',\n packageManager: PackageManager.APT,\n displayName: 'Kali Linux',\n },\n centos: {\n family: OsFamily.RHEL,\n minVersion: '9',\n packageManager: PackageManager.DNF,\n displayName: 'CentOS Stream',\n },\n almalinux: {\n family: OsFamily.RHEL,\n minVersion: '9',\n packageManager: PackageManager.DNF,\n displayName: 'AlmaLinux',\n },\n rocky: {\n family: OsFamily.RHEL,\n minVersion: '9',\n packageManager: PackageManager.DNF,\n displayName: 'Rocky Linux',\n },\n fedora: {\n family: OsFamily.RHEL,\n minVersion: '39',\n packageManager: PackageManager.DNF,\n displayName: 'Fedora',\n },\n};\n\nexport const PRIVATE_IP_RANGES = [\n /^10\\./,\n /^172\\.(1[6-9]|2[0-9]|3[01])\\./,\n /^192\\.168\\./,\n /^127\\./, // Loopback\n];\n\nexport const SUPPORTED_DISTRO_IDS = Object.keys(SUPPORTED_DISTROS);\n\nexport function isDistroSupported(distroId: string): boolean {\n return distroId.toLowerCase() in SUPPORTED_DISTROS;\n}\n\nexport function getDistroConfig(distroId: string): DistroConfig | undefined {\n return SUPPORTED_DISTROS[distroId.toLowerCase()];\n}\n", "/**\n * Network detection utilities\n * Feature: 009-cross-platform-support\n */\n\nimport { execSync } from 'child_process';\nimport * as https from 'https';\nimport { NetworkConfig, NetworkInterface } from '../types/platform.js';\nimport { PRIVATE_IP_RANGES } from '../constants/supported-distros.js';\n\n/**\n * Public IP detection result\n */\nexport interface PublicIpResult {\n ip: string;\n success: boolean;\n error?: string;\n provider?: string;\n}\n\n/**\n * Default timeout for IP detection (3 seconds)\n */\nconst DEFAULT_TIMEOUT = 3000;\n\n/**\n * IP detection services in priority order\n */\nconst IP_DETECTION_SERVICES = [\n { name: 'ipify', url: 'https://api.ipify.org' },\n { name: 'ifconfig.me', url: 'https://ifconfig.me/ip' },\n { name: 'ip.sb', url: 'https://api.ip.sb/ip' },\n];\n\n/**\n * Validate IPv4 address format\n */\nfunction isValidIpv4(ip: string): boolean {\n const ipv4Regex = /^(\\d{1,3}\\.){3}\\d{1,3}$/;\n if (!ipv4Regex.test(ip)) return false;\n\n const parts = ip.split('.');\n return parts.every((part) => {\n const num = parseInt(part, 10);\n return num >= 0 && num <= 255;\n });\n}\n\n/**\n * Validate IPv6 address format (simplified)\n */\nfunction isValidIpv6(ip: string): boolean {\n // Handle special cases\n if (ip === '::') return true;\n if (ip === '::1') return true;\n\n // Full IPv6 address: 8 groups of 4 hex digits\n const fullIpv6 = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;\n if (fullIpv6.test(ip)) return true;\n\n // IPv6 with :: compression (can appear anywhere)\n // Must have :: and valid hex groups before/after\n if (ip.includes('::')) {\n const parts = ip.split('::');\n if (parts.length !== 2) return false;\n\n const validatePart = (part: string): boolean => {\n if (part === '') return true;\n const groups = part.split(':');\n return groups.every((g) => /^[0-9a-fA-F]{1,4}$/.test(g));\n };\n\n return validatePart(parts[0]) && validatePart(parts[1]);\n }\n\n return false;\n}\n\n/**\n * Validate IP address (IPv4 or IPv6)\n */\nexport function isValidIp(ip: string): boolean {\n return isValidIpv4(ip) || isValidIpv6(ip);\n}\n\n/**\n * Fetch public IP from a single service with timeout\n *\n * @param url - Service URL\n * @param timeout - Timeout in milliseconds\n * @returns Promise resolving to IP string or rejecting on error\n */\nfunction fetchFromService(url: string, timeout: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(new Error(`Timeout after ${timeout}ms`));\n }, timeout);\n\n const req = https.get(url, (res) => {\n let data = '';\n\n res.on('data', (chunk) => {\n data += chunk;\n });\n\n res.on('end', () => {\n clearTimeout(timeoutId);\n const ip = data.trim();\n\n if (isValidIp(ip)) {\n resolve(ip);\n } else {\n reject(new Error(`Invalid IP response: ${ip.substring(0, 50)}`));\n }\n });\n });\n\n req.on('error', (error) => {\n clearTimeout(timeoutId);\n reject(error);\n });\n });\n}\n\n/**\n * Fetch public IP address with timeout and retry\n *\n * @param timeout - Timeout per request in milliseconds (default: 3000)\n * @param maxRetries - Maximum retry attempts (default: 1)\n * @returns Public IP detection result\n */\nexport async function fetchPublicIp(\n timeout: number = DEFAULT_TIMEOUT,\n maxRetries: number = 1\n): Promise<PublicIpResult> {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n for (const service of IP_DETECTION_SERVICES) {\n try {\n const ip = await fetchFromService(service.url, timeout);\n return {\n ip,\n success: true,\n provider: service.name,\n };\n } catch {\n // Try next service\n continue;\n }\n }\n }\n\n return {\n ip: '',\n success: false,\n error: 'All IP detection services failed after retries',\n };\n}\n\n/**\n * Check if an IP address is private (NAT)\n */\nexport function isPrivateIp(ip: string): boolean {\n return PRIVATE_IP_RANGES.some((regex) => regex.test(ip));\n}\n\n/**\n * Get all network interfaces with IPv4 addresses\n */\nexport function getNetworkInterfaces(): NetworkInterface[] {\n const interfaces: NetworkInterface[] = [];\n\n try {\n const output = execSync('ip -4 addr show', { encoding: 'utf-8' });\n const lines = output.split('\\n');\n\n let currentInterface: Partial<NetworkInterface> = {};\n\n for (const line of lines) {\n // Match interface line: \"2: eth0: <BROADCAST...\"\n const ifaceMatch = line.match(/^\\d+:\\s+(\\S+):/);\n if (ifaceMatch) {\n if (currentInterface.name) {\n interfaces.push(currentInterface as NetworkInterface);\n }\n currentInterface = {\n name: ifaceMatch[1],\n isLoopback: ifaceMatch[1] === 'lo',\n };\n }\n\n // Match inet line: \" inet 192.168.1.100/24...\"\n const inetMatch = line.match(/^\\s+inet\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+)/);\n if (inetMatch && currentInterface.name) {\n currentInterface.ipv4 = inetMatch[1];\n }\n }\n\n // Add last interface\n if (currentInterface.name) {\n interfaces.push(currentInterface as NetworkInterface);\n }\n } catch {\n // Failed to get interfaces\n }\n\n return interfaces.filter((iface) => !iface.isLoopback && iface.ipv4);\n}\n\n/**\n * Detect network configuration\n */\nexport function detectNetwork(): NetworkConfig {\n const interfaces = getNetworkInterfaces();\n const firstIp = interfaces[0]?.ipv4 || '';\n\n return {\n interfaces,\n selectedIp: firstIp,\n isNat: isPrivateIp(firstIp),\n };\n}\n", "/**\n * UserMetadataManager - User Metadata Persistence Service\n *\n * Manages user creation time, status, and other metadata\n *\n * @module services/user-metadata-manager\n */\n\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { dirname } from 'path';\nimport { DEFAULT_PATHS } from '../constants/paths';\nimport type { UserMeta, UserMetadataStore, UserStatus } from '../types/user-metadata';\n\n/**\n * Validate UUID v4 format\n */\nfunction isValidUuid(uuid: string): boolean {\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return uuidRegex.test(uuid);\n}\n\n/**\n * UserMetadataManager - Manage user metadata persistence\n */\nexport class UserMetadataManager {\n private metadataPath: string;\n private cache: UserMetadataStore | null = null;\n\n /**\n * Create a new UserMetadataManager\n *\n * @param metadataPath - Path to metadata file\n */\n constructor(metadataPath?: string) {\n this.metadataPath = metadataPath || DEFAULT_PATHS.USER_METADATA_FILE;\n }\n\n /**\n * Load metadata from file\n *\n * @returns UserMetadataStore\n */\n private async loadMetadata(): Promise<UserMetadataStore> {\n if (this.cache) {\n return this.cache;\n }\n\n try {\n if (!existsSync(this.metadataPath)) {\n this.cache = { users: {} };\n return this.cache;\n }\n const content = await readFile(this.metadataPath, 'utf-8');\n this.cache = JSON.parse(content) as UserMetadataStore;\n return this.cache;\n } catch {\n this.cache = { users: {} };\n return this.cache;\n }\n }\n\n /**\n * Save metadata to file\n *\n * @param store - UserMetadataStore to save\n */\n private async saveMetadata(store: UserMetadataStore): Promise<void> {\n const dir = dirname(this.metadataPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(this.metadataPath, JSON.stringify(store, null, 2), 'utf-8');\n this.cache = store;\n }\n\n /**\n * Get metadata for a specific user\n *\n * @param userId - User UUID\n * @returns UserMeta or null if not found\n */\n async getMetadata(userId: string): Promise<UserMeta | null> {\n const store = await this.loadMetadata();\n return store.users[userId] || null;\n }\n\n /**\n * Set metadata for a user (create or update)\n *\n * @param userId - User UUID\n * @param metadata - Partial metadata to set/update\n */\n async setMetadata(userId: string, metadata: Partial<UserMeta>): Promise<void> {\n if (!isValidUuid(userId)) {\n throw new Error(`Invalid UUID format: ${userId}`);\n }\n\n const store = await this.loadMetadata();\n const existing = store.users[userId] || {\n createdAt: new Date().toISOString(),\n status: 'active' as UserStatus,\n };\n\n store.users[userId] = {\n ...existing,\n ...metadata,\n };\n\n await this.saveMetadata(store);\n }\n\n /**\n * Create metadata for a new user\n *\n * @param userId - User UUID\n * @returns Created UserMeta\n */\n async createUser(userId: string): Promise<UserMeta> {\n if (!isValidUuid(userId)) {\n throw new Error(`Invalid UUID format: ${userId}`);\n }\n\n const store = await this.loadMetadata();\n\n // Don't overwrite existing metadata\n if (store.users[userId]) {\n return store.users[userId];\n }\n\n const now = new Date().toISOString();\n const metadata: UserMeta = {\n createdAt: now,\n status: 'active',\n statusChangedAt: now,\n };\n\n store.users[userId] = metadata;\n await this.saveMetadata(store);\n\n return metadata;\n }\n\n /**\n * Update user status\n *\n * @param userId - User UUID\n * @param status - New status\n */\n async updateStatus(userId: string, status: UserStatus): Promise<void> {\n const store = await this.loadMetadata();\n\n if (!store.users[userId]) {\n throw new Error(`User metadata not found: ${userId}`);\n }\n\n store.users[userId].status = status;\n store.users[userId].statusChangedAt = new Date().toISOString();\n\n await this.saveMetadata(store);\n }\n\n /**\n * Delete user metadata\n *\n * @param userId - User UUID\n */\n async deleteMetadata(userId: string): Promise<void> {\n const store = await this.loadMetadata();\n\n if (store.users[userId]) {\n delete store.users[userId];\n await this.saveMetadata(store);\n }\n }\n\n /**\n * Get all user metadata\n *\n * @returns Record of userId to UserMeta\n */\n async getAllMetadata(): Promise<Record<string, UserMeta>> {\n const store = await this.loadMetadata();\n return { ...store.users };\n }\n\n /**\n * Get users by status\n *\n * @param status - Status to filter by\n * @returns Array of [userId, metadata] pairs\n */\n async getUsersByStatus(status: UserStatus): Promise<Array<[string, UserMeta]>> {\n const store = await this.loadMetadata();\n return Object.entries(store.users).filter(([_, meta]) => meta.status === status);\n }\n\n /**\n * Clear cache (force reload from file on next access)\n */\n clearCache(): void {\n this.cache = null;\n }\n}\n", "/**\n * QuotaManager - \u914D\u989D\u914D\u7F6E\u7BA1\u7406\u670D\u52A1\n *\n * \u7BA1\u7406\u7528\u6237\u6D41\u91CF\u914D\u989D\u7684\u914D\u7F6E\u548C\u6301\u4E45\u5316\n *\n * @module services/quota-manager\n */\n\nimport { readFile, writeFile, mkdir, chmod } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { dirname } from 'path';\nimport type { TrafficQuota, QuotaConfig, SetQuotaParams, AlertLevel } from '../types/quota';\nimport { DEFAULT_QUOTA, DEFAULT_QUOTA_CONFIG } from '../types/quota';\nimport { QUOTA_CONFIG_PATH, WARNING_THRESHOLD, EXCEEDED_THRESHOLD } from '../constants/quota';\nimport { QuotaError, ValidationError, NetworkError } from '../utils/errors';\nimport { QuotaErrors, ValidationErrors, NetworkErrors } from '../constants/error-codes';\n\n/**\n * \u9A8C\u8BC1\u90AE\u7BB1\u683C\u5F0F\n */\nfunction isValidEmail(email: string): boolean {\n return email.length > 0 && email.includes('@') && email.length <= 254;\n}\n\n/**\n * \u9A8C\u8BC1\u914D\u989D\u503C\n * @param bytes - \u914D\u989D\u5B57\u8282\u6570\n * @returns true \u5982\u679C\u6709\u6548\uFF08-1 \u8868\u793A\u65E0\u9650\u5236\uFF0C\u6216\u8005 >= 0\uFF09\n */\nfunction isValidQuotaBytes(bytes: number): boolean {\n return bytes === -1 || (Number.isFinite(bytes) && bytes >= 0);\n}\n\n/**\n * \u9A8C\u8BC1\u7AEF\u53E3\u53F7\n */\nfunction isValidPort(port: number): boolean {\n return Number.isInteger(port) && port >= 1 && port <= 65535;\n}\n\n/**\n * QuotaManager - \u7BA1\u7406\u7528\u6237\u6D41\u91CF\u914D\u989D\n */\nexport class QuotaManager {\n private configPath: string;\n\n /**\n * \u521B\u5EFA QuotaManager \u5B9E\u4F8B\n *\n * @param configPath - \u914D\u989D\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 /usr/local/etc/xray/quota.json\uFF09\n */\n constructor(configPath: string = QUOTA_CONFIG_PATH) {\n this.configPath = configPath;\n }\n\n /**\n * \u8BFB\u53D6\u914D\u989D\u914D\u7F6E\u6587\u4EF6\n *\n * @returns \u914D\u989D\u914D\u7F6E\n */\n async readConfig(): Promise<QuotaConfig> {\n try {\n if (!existsSync(this.configPath)) {\n return { ...DEFAULT_QUOTA_CONFIG };\n }\n\n const content = await readFile(this.configPath, 'utf-8');\n const config = JSON.parse(content) as QuotaConfig;\n\n // \u786E\u4FDD\u914D\u7F6E\u7ED3\u6784\u5B8C\u6574\n return {\n ...DEFAULT_QUOTA_CONFIG,\n ...config,\n users: config.users || {},\n };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'EACCES') {\n throw new QuotaError(QuotaErrors.QUOTA_CONFIG_NOT_FOUND, this.configPath);\n } else if (error instanceof SyntaxError) {\n throw new QuotaError(QuotaErrors.QUOTA_CONFIG_NOT_FOUND, (error as Error).message);\n }\n throw error;\n }\n }\n\n /**\n * \u5199\u5165\u914D\u989D\u914D\u7F6E\u6587\u4EF6\n *\n * @param config - \u914D\u989D\u914D\u7F6E\n */\n async writeConfig(config: QuotaConfig): Promise<void> {\n try {\n // \u786E\u4FDD\u76EE\u5F55\u5B58\u5728\n const dir = dirname(this.configPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n\n // \u5199\u5165\u914D\u7F6E\n const content = JSON.stringify(config, null, 2);\n await writeFile(this.configPath, content, 'utf-8');\n\n // \u8BBE\u7F6E\u5B89\u5168\u6743\u9650\n await chmod(this.configPath, 0o600);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'EACCES') {\n throw new QuotaError(QuotaErrors.TRAFFIC_UPDATE_FAILED, this.configPath);\n }\n throw error;\n }\n }\n\n /**\n * \u83B7\u53D6\u7528\u6237\u914D\u989D\n *\n * @param email - \u7528\u6237\u90AE\u7BB1\n * @returns \u914D\u989D\u914D\u7F6E\uFF0C\u4E0D\u5B58\u5728\u65F6\u8FD4\u56DE\u9ED8\u8BA4\u503C\n */\n async getQuota(email: string): Promise<TrafficQuota> {\n const config = await this.readConfig();\n return config.users[email] || { ...DEFAULT_QUOTA };\n }\n\n /**\n * \u8BBE\u7F6E\u7528\u6237\u914D\u989D\n *\n * @param params - \u914D\u989D\u8BBE\u7F6E\u53C2\u6570\n * @throws Error \u5982\u679C\u53C2\u6570\u65E0\u6548\n */\n async setQuota(params: SetQuotaParams): Promise<void> {\n // \u9A8C\u8BC1\u90AE\u7BB1\n if (!isValidEmail(params.email)) {\n throw new ValidationError(ValidationErrors.INVALID_FORMAT, params.email);\n }\n\n // \u9A8C\u8BC1\u914D\u989D\u503C\n if (!isValidQuotaBytes(params.quotaBytes)) {\n throw new QuotaError(QuotaErrors.INVALID_QUOTA_VALUE, String(params.quotaBytes));\n }\n\n const config = await this.readConfig();\n\n const existingQuota = config.users[params.email];\n const now = new Date().toISOString();\n\n config.users[params.email] = {\n quotaBytes: params.quotaBytes,\n quotaType: params.quotaType,\n usedBytes: existingQuota?.usedBytes || 0,\n lastReset: existingQuota?.lastReset || now,\n status: existingQuota?.status || 'active',\n };\n\n await this.writeConfig(config);\n }\n\n /**\n * \u91CD\u7F6E\u7528\u6237\u5DF2\u7528\u6D41\u91CF\n *\n * @param email - \u7528\u6237\u90AE\u7BB1\n */\n async resetUsage(email: string): Promise<void> {\n const config = await this.readConfig();\n\n if (!config.users[email]) {\n throw new QuotaError(QuotaErrors.USER_QUOTA_NOT_FOUND, email);\n }\n\n config.users[email].usedBytes = 0;\n config.users[email].lastReset = new Date().toISOString();\n config.users[email].status = 'active';\n\n await this.writeConfig(config);\n }\n\n /**\n * \u66F4\u65B0\u7528\u6237\u5DF2\u7528\u6D41\u91CF\n *\n * @param email - \u7528\u6237\u90AE\u7BB1\n * @param usedBytes - \u5DF2\u7528\u5B57\u8282\u6570\n * @throws Error \u5982\u679C\u53C2\u6570\u65E0\u6548\n */\n async updateUsage(email: string, usedBytes: number): Promise<void> {\n // \u9A8C\u8BC1\u5DF2\u7528\u5B57\u8282\u6570\n if (!Number.isFinite(usedBytes) || usedBytes < 0) {\n throw new ValidationError(ValidationErrors.VALUE_OUT_OF_RANGE, String(usedBytes));\n }\n\n const config = await this.readConfig();\n\n if (!config.users[email]) {\n // \u5982\u679C\u7528\u6237\u6CA1\u6709\u914D\u989D\u8BB0\u5F55\uFF0C\u521B\u5EFA\u9ED8\u8BA4\u8BB0\u5F55\n config.users[email] = { ...DEFAULT_QUOTA };\n }\n\n config.users[email].usedBytes = usedBytes;\n\n await this.writeConfig(config);\n }\n\n /**\n * \u83B7\u53D6\u6240\u6709\u7528\u6237\u914D\u989D\n *\n * @returns \u7528\u6237\u914D\u989D\u6620\u5C04\n */\n async getAllQuotas(): Promise<Record<string, TrafficQuota>> {\n const config = await this.readConfig();\n return config.users;\n }\n\n /**\n * \u5220\u9664\u7528\u6237\u914D\u989D\u8BB0\u5F55\n *\n * @param email - \u7528\u6237\u90AE\u7BB1\n */\n async deleteQuota(email: string): Promise<void> {\n const config = await this.readConfig();\n\n if (!config.users[email]) {\n return; // \u4E0D\u5B58\u5728\u5219\u9759\u9ED8\u8FD4\u56DE\n }\n\n delete config.users[email];\n await this.writeConfig(config);\n }\n\n /**\n * \u8BBE\u7F6E\u7528\u6237\u72B6\u6001\n *\n * @param email - \u7528\u6237\u90AE\u7BB1\n * @param status - \u65B0\u72B6\u6001\n */\n async setStatus(email: string, status: TrafficQuota['status']): Promise<void> {\n const config = await this.readConfig();\n\n if (!config.users[email]) {\n throw new QuotaError(QuotaErrors.USER_QUOTA_NOT_FOUND, email);\n }\n\n config.users[email].status = status;\n await this.writeConfig(config);\n }\n\n /**\n * \u8BA1\u7B97\u8B66\u544A\u7EA7\u522B\n *\n * @param usedBytes - \u5DF2\u7528\u5B57\u8282\u6570\n * @param quotaBytes - \u914D\u989D\u5B57\u8282\u6570\uFF08-1 \u8868\u793A\u65E0\u9650\u5236\uFF09\n * @returns \u8B66\u544A\u7EA7\u522B\n */\n calculateAlertLevel(usedBytes: number, quotaBytes: number): AlertLevel {\n if (quotaBytes < 0) {\n return 'normal'; // \u65E0\u9650\u5236\n }\n\n const percent = (usedBytes / quotaBytes) * 100;\n\n if (percent >= EXCEEDED_THRESHOLD) {\n return 'exceeded';\n }\n if (percent >= WARNING_THRESHOLD) {\n return 'warning';\n }\n return 'normal';\n }\n\n /**\n * \u83B7\u53D6 API \u7AEF\u53E3\n *\n * @returns API \u7AEF\u53E3\u53F7\n */\n async getApiPort(): Promise<number> {\n const config = await this.readConfig();\n return config.apiPort;\n }\n\n /**\n * \u8BBE\u7F6E API \u7AEF\u53E3\n *\n * @param port - API \u7AEF\u53E3\u53F7\n * @throws Error \u5982\u679C\u7AEF\u53E3\u53F7\u65E0\u6548\n */\n async setApiPort(port: number): Promise<void> {\n if (!isValidPort(port)) {\n throw new NetworkError(NetworkErrors.INVALID_PORT, String(port));\n }\n\n const config = await this.readConfig();\n config.apiPort = port;\n await this.writeConfig(config);\n }\n}\n", "/**\n * \u6D41\u91CF\u914D\u989D\u76F8\u5173\u7C7B\u578B\u5B9A\u4E49\n * @module types/quota\n */\n\n/**\n * \u6D41\u91CF\u914D\u989D\u7C7B\u578B\n */\nexport type QuotaType = 'limited' | 'unlimited';\n\n/**\n * \u914D\u989D\u72B6\u6001\n */\nexport type QuotaStatus = 'active' | 'disabled' | 'exceeded';\n\n/**\n * \u8B66\u544A\u7EA7\u522B\n */\nexport type AlertLevel = 'normal' | 'warning' | 'exceeded';\n\n/**\n * \u6D41\u91CF\u5355\u4F4D\n */\nexport type TrafficUnit = 'B' | 'KB' | 'MB' | 'GB' | 'TB';\n\n/**\n * \u6D41\u91CF\u914D\u989D\n */\nexport interface TrafficQuota {\n /** \u914D\u989D\u603B\u91CF\uFF08\u5B57\u8282\uFF09\uFF0C-1 \u8868\u793A\u65E0\u9650\u5236 */\n quotaBytes: number;\n /** \u914D\u989D\u7C7B\u578B */\n quotaType: QuotaType;\n /** \u5DF2\u4F7F\u7528\u6D41\u91CF\uFF08\u5B57\u8282\uFF09 */\n usedBytes: number;\n /** \u4E0A\u6B21\u91CD\u7F6E\u65F6\u95F4\uFF08ISO 8601\uFF09 */\n lastReset: string;\n /** \u72B6\u6001 */\n status: QuotaStatus;\n}\n\n/**\n * \u6D41\u91CF\u4F7F\u7528\u60C5\u51B5\n */\nexport interface TrafficUsage {\n /** \u7528\u6237\u90AE\u7BB1\u6807\u8BC6 */\n email: string;\n /** \u4E0A\u884C\u6D41\u91CF\uFF08\u5B57\u8282\uFF09 */\n uplink: number;\n /** \u4E0B\u884C\u6D41\u91CF\uFF08\u5B57\u8282\uFF09 */\n downlink: number;\n /** \u603B\u6D41\u91CF\uFF08\u5B57\u8282\uFF09 */\n total: number;\n /** \u67E5\u8BE2\u65F6\u95F4\uFF08ISO 8601\uFF09 */\n queriedAt: string;\n}\n\n/**\n * \u5E26\u914D\u989D\u7684\u7528\u6237\n */\nexport interface UserWithQuota {\n /** \u7528\u6237 UUID */\n id: string;\n /** \u7528\u6237\u90AE\u7BB1\u6807\u8BC6 */\n email: string;\n /** \u6D41\u91CF\u914D\u989D\u914D\u7F6E */\n quota: TrafficQuota;\n /** \u5F53\u524D\u6D41\u91CF\u4F7F\u7528\uFF08\u53EF\u80FD\u4E0D\u53EF\u7528\uFF09 */\n usage?: TrafficUsage;\n /** \u4F7F\u7528\u767E\u5206\u6BD4\uFF080-100\uFF0C\u65E0\u9650\u5236\u65F6\u4E3A 0\uFF09 */\n usagePercent?: number;\n /** \u8B66\u544A\u7EA7\u522B */\n alertLevel?: AlertLevel;\n}\n\n/**\n * \u914D\u989D\u914D\u7F6E\u6587\u4EF6\n */\nexport interface QuotaConfig {\n /** \u914D\u7F6E\u7248\u672C\u53F7 */\n version: string;\n /** Xray Stats API \u7AEF\u53E3 */\n apiPort: number;\n /** \u7528\u6237\u914D\u989D\u6620\u5C04\uFF08key \u4E3A email\uFF09 */\n users: Record<string, TrafficQuota>;\n}\n\n/**\n * \u914D\u989D\u8BBE\u7F6E\u53C2\u6570\n */\nexport interface SetQuotaParams {\n /** \u7528\u6237\u90AE\u7BB1 */\n email: string;\n /** \u914D\u989D\u5B57\u8282\u6570\uFF08-1 \u8868\u793A\u65E0\u9650\u5236\uFF09 */\n quotaBytes: number;\n /** \u914D\u989D\u7C7B\u578B */\n quotaType: QuotaType;\n}\n\n/**\n * \u683C\u5F0F\u5316\u7684\u6D41\u91CF\u503C\n */\nexport interface FormattedTraffic {\n /** \u6570\u503C */\n value: number;\n /** \u5355\u4F4D */\n unit: TrafficUnit;\n /** \u663E\u793A\u5B57\u7B26\u4E32 */\n display: string;\n}\n\n/**\n * Xray Stats API \u54CD\u5E94\n */\nexport interface XrayStatsResponse {\n stat: Array<{\n name: string;\n value: number;\n }>;\n}\n\n/**\n * \u9ED8\u8BA4\u914D\u989D\u503C\n */\nexport const DEFAULT_QUOTA: TrafficQuota = {\n quotaBytes: -1,\n quotaType: 'unlimited',\n usedBytes: 0,\n lastReset: new Date().toISOString(),\n status: 'active',\n};\n\n/**\n * \u9ED8\u8BA4\u914D\u989D\u914D\u7F6E\n */\nexport const DEFAULT_QUOTA_CONFIG: QuotaConfig = {\n version: '1.0',\n apiPort: 10085,\n users: {},\n};\n\n/**\n * Stats API \u7F3A\u5931\u7EC4\u4EF6\u7C7B\u578B\n */\nexport type MissingComponent =\n | 'stats'\n | 'policy'\n | 'api'\n | 'api-inbound'\n | 'api-routing'\n | 'api-outbound';\n\n/**\n * Stats API \u68C0\u6D4B\u7ED3\u679C\n */\nexport interface StatsDetectionResult {\n /** API \u662F\u5426\u53EF\u7528\uFF08\u53EF\u8FDE\u63A5\uFF09 */\n available: boolean;\n /** \u914D\u7F6E\u6587\u4EF6\u4E2D\u662F\u5426\u68C0\u6D4B\u5230 stats \u914D\u7F6E */\n configDetected: boolean;\n /** \u68C0\u6D4B\u5230\u7684 API \u7AEF\u53E3 */\n detectedPort?: number;\n /** Xray \u670D\u52A1\u662F\u5426\u8FD0\u884C */\n serviceRunning: boolean;\n /** \u72B6\u6001\u63CF\u8FF0\u6D88\u606F */\n message: string;\n /** \u5EFA\u8BAE\u64CD\u4F5C */\n suggestion?: string;\n /** \u7F3A\u5931\u7684\u914D\u7F6E\u7EC4\u4EF6\u5217\u8868 */\n missingComponents: MissingComponent[];\n}\n\n/**\n * Stats API \u914D\u7F6E\u7ED3\u679C\n */\nexport interface StatsConfigResult {\n /** \u914D\u7F6E\u662F\u5426\u6210\u529F */\n success: boolean;\n /** \u5907\u4EFD\u6587\u4EF6\u8DEF\u5F84 */\n backupPath?: string;\n /** \u914D\u7F6E\u7684 API \u7AEF\u53E3 */\n apiPort: number;\n /** \u7ED3\u679C\u6D88\u606F */\n message: string;\n /** \u9519\u8BEF\u4FE1\u606F\uFF08\u5982\u679C\u5931\u8D25\uFF09 */\n error?: string;\n /** \u662F\u5426\u5DF2\u56DE\u6EDA */\n rolledBack: boolean;\n}\n", "/**\n * \u6D41\u91CF\u914D\u989D\u76F8\u5173\u5E38\u91CF\n * @module constants/quota\n */\n\n/**\n * \u914D\u989D\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\n */\nexport const QUOTA_CONFIG_PATH = '/usr/local/etc/xray/quota.json';\n\n/**\n * \u9ED8\u8BA4 Xray Stats API \u7AEF\u53E3\n */\nexport const DEFAULT_API_PORT = 10085;\n\n/**\n * \u9ED8\u8BA4 API \u670D\u52A1\u5668\u5730\u5740\n */\nexport const DEFAULT_API_SERVER = '127.0.0.1';\n\n/**\n * \u8B66\u544A\u9608\u503C\uFF08\u767E\u5206\u6BD4\uFF09\n */\nexport const WARNING_THRESHOLD = 80;\n\n/**\n * \u8D85\u989D\u9608\u503C\uFF08\u767E\u5206\u6BD4\uFF09\n */\nexport const EXCEEDED_THRESHOLD = 100;\n\n/**\n * Xray Stats \u547D\u4EE4\n */\nexport const XRAY_STATS_COMMAND = 'xray';\n\n/**\n * Stats API \u5B50\u547D\u4EE4\n */\nexport const STATS_SUBCOMMAND = 'api';\n\n/**\n * \u6D41\u91CF\u7EDF\u8BA1\u540D\u79F0\u6A21\u5F0F\n */\nexport const STATS_PATTERNS = {\n /** \u7528\u6237\u4E0A\u884C\u6D41\u91CF */\n USER_UPLINK: (email: string) => `user>>>${email}>>>traffic>>>uplink`,\n /** \u7528\u6237\u4E0B\u884C\u6D41\u91CF */\n USER_DOWNLINK: (email: string) => `user>>>${email}>>>traffic>>>downlink`,\n};\n\n/**\n * \u914D\u989D\u914D\u7F6E\u7248\u672C\n */\nexport const QUOTA_CONFIG_VERSION = '1.0';\n\n/**\n * \u5355\u4F4D\u5B57\u8282\u6570\u6620\u5C04\n */\nexport const UNIT_BYTES = {\n B: 1,\n KB: 1024,\n MB: 1024 ** 2,\n GB: 1024 ** 3,\n TB: 1024 ** 4,\n} as const;\n\n/**\n * \u9884\u8BBE\u914D\u989D\u9009\u9879\uFF08\u7528\u4E8E UI\uFF09\n */\nexport const PRESET_QUOTAS = [\n { label: '1 GB', bytes: 1 * UNIT_BYTES.GB },\n { label: '5 GB', bytes: 5 * UNIT_BYTES.GB },\n { label: '10 GB', bytes: 10 * UNIT_BYTES.GB },\n { label: '50 GB', bytes: 50 * UNIT_BYTES.GB },\n { label: '100 GB', bytes: 100 * UNIT_BYTES.GB },\n { label: '500 GB', bytes: 500 * UNIT_BYTES.GB },\n { label: '1 TB', bytes: 1 * UNIT_BYTES.TB },\n { label: '\u65E0\u9650\u5236', bytes: -1 },\n];\n\n/**\n * \u9ED8\u8BA4 Stats API \u914D\u7F6E\n */\nexport const DEFAULT_STATS_CONFIG = {\n /** Stats \u914D\u7F6E\u5757\uFF08\u7A7A\u5BF9\u8C61\u542F\u7528\u7EDF\u8BA1\uFF09 */\n stats: {},\n\n /** Policy \u914D\u7F6E\uFF08\u542F\u7528\u7528\u6237\u548C\u5165\u7AD9\u6D41\u91CF\u7EDF\u8BA1\uFF09 */\n policy: {\n levels: {\n '0': {\n statsUserUplink: true,\n statsUserDownlink: true,\n },\n },\n system: {\n statsInboundUplink: true,\n statsInboundDownlink: true,\n },\n },\n\n /** API \u914D\u7F6E */\n api: {\n tag: 'api',\n services: ['StatsService'] as const,\n },\n\n /** API \u5165\u7AD9\u914D\u7F6E */\n apiInbound: {\n tag: 'api',\n port: DEFAULT_API_PORT,\n listen: DEFAULT_API_SERVER,\n protocol: 'dokodemo-door' as const,\n settings: {\n address: DEFAULT_API_SERVER,\n },\n },\n\n /** API \u8DEF\u7531\u89C4\u5219 */\n apiRoutingRule: {\n type: 'field' as const,\n inboundTag: ['api'],\n outboundTag: 'api',\n },\n\n /** API \u51FA\u7AD9\u914D\u7F6E */\n apiOutbound: {\n protocol: 'freedom' as const,\n tag: 'api',\n },\n} as const;\n\n/**\n * Stats API \u7AEF\u53E3\u8303\u56F4\n */\nexport const STATS_PORT_RANGE = {\n /** \u8D77\u59CB\u7AEF\u53E3 */\n START: 10085,\n /** \u7ED3\u675F\u7AEF\u53E3 */\n END: 10099,\n} as const;\n\n/**\n * Stats API \u8FDE\u63A5\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09\n */\nexport const STATS_API_TIMEOUT = 5000;\n\n/**\n * \u670D\u52A1\u91CD\u542F\u7B49\u5F85\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\n */\nexport const SERVICE_RESTART_WAIT = 2000;\n", "/**\n * TrafficManager - \u6D41\u91CF\u7EDF\u8BA1\u670D\u52A1\n *\n * \u901A\u8FC7 Xray Stats API \u83B7\u53D6\u7528\u6237\u6D41\u91CF\u4F7F\u7528\u60C5\u51B5\n *\n * @module services/traffic-manager\n */\n\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { existsSync } from 'fs';\nimport { readFile } from 'fs/promises';\nimport type { TrafficUsage, XrayStatsResponse } from '../types/quota';\nimport { QuotaManager } from './quota-manager';\nimport {\n DEFAULT_API_PORT,\n DEFAULT_API_SERVER,\n STATS_PATTERNS,\n XRAY_STATS_COMMAND,\n} from '../constants/quota';\n\nconst execAsync = promisify(exec);\n\n/**\n * Stats API \u68C0\u6D4B\u7ED3\u679C\n */\nexport interface StatsDetectionResult {\n /** API \u662F\u5426\u53EF\u7528 */\n available: boolean;\n\n /** \u662F\u5426\u68C0\u6D4B\u5230 stats \u914D\u7F6E */\n configDetected: boolean;\n\n /** \u68C0\u6D4B\u5230\u7684 API \u7AEF\u53E3 */\n detectedPort?: number;\n\n /** \u670D\u52A1\u662F\u5426\u8FD0\u884C */\n serviceRunning: boolean;\n\n /** \u63D0\u793A\u6D88\u606F */\n message: string;\n\n /** \u5EFA\u8BAE\u64CD\u4F5C */\n suggestion?: string;\n}\n\n/**\n * \u9ED8\u8BA4 Xray \u914D\u7F6E\u8DEF\u5F84\n */\nconst DEFAULT_XRAY_CONFIG_PATH = '/usr/local/etc/xray/config.json';\n\n/**\n * TrafficManager - \u7BA1\u7406 Xray \u6D41\u91CF\u7EDF\u8BA1\n */\nexport class TrafficManager {\n private apiServer: string;\n private apiPort: number;\n\n /**\n * \u521B\u5EFA TrafficManager \u5B9E\u4F8B\n *\n * @param apiServer - API \u670D\u52A1\u5668\u5730\u5740\uFF08\u9ED8\u8BA4 127.0.0.1\uFF09\n * @param apiPort - API \u7AEF\u53E3\uFF08\u9ED8\u8BA4 10085\uFF09\n */\n constructor(apiServer: string = DEFAULT_API_SERVER, apiPort: number = DEFAULT_API_PORT) {\n this.apiServer = apiServer;\n this.apiPort = apiPort;\n }\n\n /**\n * \u4ECE Xray \u914D\u7F6E\u4E2D\u8BFB\u53D6 API \u7AEF\u53E3\n */\n private async detectApiPortFromConfig(\n configPath: string = DEFAULT_XRAY_CONFIG_PATH\n ): Promise<number | null> {\n try {\n const content = await readFile(configPath, 'utf-8');\n const config = JSON.parse(content);\n const apiTag = config.api?.tag || 'api';\n const apiInbound = config.inbounds?.find(\n (inbound: { tag?: string }) => inbound.tag === apiTag\n );\n const port = Number(apiInbound?.port);\n if (Number.isInteger(port) && port >= 1 && port <= 65535) {\n return port;\n }\n return null;\n } catch {\n return null;\n }\n }\n\n /**\n * \u4ECE\u914D\u989D\u914D\u7F6E\u4E2D\u540C\u6B65 API \u7AEF\u53E3\n */\n private async syncApiPort(): Promise<void> {\n let quotaPort: number | null = null;\n try {\n const quotaManager = new QuotaManager();\n quotaPort = await quotaManager.getApiPort();\n } catch {\n quotaPort = null;\n }\n\n const configPort = await this.detectApiPortFromConfig();\n const resolvedPort = configPort ?? quotaPort;\n\n if (\n typeof resolvedPort === 'number' &&\n Number.isInteger(resolvedPort) &&\n resolvedPort >= 1 &&\n resolvedPort <= 65535\n ) {\n this.apiPort = resolvedPort;\n }\n }\n\n /**\n * \u83B7\u53D6 API \u670D\u52A1\u5668\u5730\u5740\n */\n getServerAddress(): string {\n return `${this.apiServer}:${this.apiPort}`;\n }\n\n /**\n * \u68C0\u67E5 Xray Stats API \u662F\u5426\u53EF\u7528\n *\n * @returns \u662F\u5426\u53EF\u7528\n */\n async isStatsAvailable(): Promise<boolean> {\n try {\n await this.syncApiPort();\n const { stdout } = await execAsync(\n `${XRAY_STATS_COMMAND} api statsquery --server=${this.getServerAddress()} 2>/dev/null`\n );\n // \u5982\u679C\u547D\u4EE4\u6210\u529F\u6267\u884C\u5E76\u8FD4\u56DE JSON\uFF0C\u5219 API \u53EF\u7528\n JSON.parse(stdout || '{}');\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * \u5224\u65AD\u6D41\u91CF\u7EDF\u8BA1\u662F\u5426\u53EF\u7528\uFF08\u542B policy \u68C0\u67E5\uFF09\n */\n async isUsageAvailable(): Promise<boolean> {\n const [available, policyEnabled] = await Promise.all([\n this.isStatsAvailable(),\n this.hasUserStatsPolicy(),\n ]);\n\n return available && policyEnabled;\n }\n\n /**\n * \u6267\u884C Xray stats \u547D\u4EE4\n *\n * @param name - \u7EDF\u8BA1\u540D\u79F0\n * @returns \u7EDF\u8BA1\u503C\uFF08\u5B57\u8282\u6570\uFF09\n */\n private async queryStats(name: string): Promise<number> {\n try {\n const { stdout } = await execAsync(\n `${XRAY_STATS_COMMAND} api stats --server=${this.getServerAddress()} -name \"${name}\" 2>/dev/null`\n );\n const result = JSON.parse(stdout || '{}');\n return Number(result.stat?.value) || 0;\n } catch {\n return 0;\n }\n }\n\n /**\n * \u68C0\u67E5\u7528\u6237\u6D41\u91CF\u7EDF\u8BA1\u7B56\u7565\u662F\u5426\u542F\u7528\n */\n private async hasUserStatsPolicy(\n configPath: string = DEFAULT_XRAY_CONFIG_PATH\n ): Promise<boolean> {\n try {\n const content = await readFile(configPath, 'utf-8');\n const config = JSON.parse(content);\n const levels = config.policy?.levels;\n if (!levels) {\n return false;\n }\n const levelValues = Object.values(\n levels as Record<string, { statsUserUplink?: boolean; statsUserDownlink?: boolean }>\n );\n return levelValues.some(\n (level) => level?.statsUserUplink === true && level?.statsUserDownlink === true\n );\n } catch {\n return false;\n }\n }\n\n /**\n * \u83B7\u53D6\u7528\u6237\u6D41\u91CF\u4F7F\u7528\u60C5\u51B5\n *\n * @param email - \u7528\u6237\u90AE\u7BB1\n * @returns \u6D41\u91CF\u4F7F\u7528\u6570\u636E\uFF0C\u670D\u52A1\u672A\u8FD0\u884C\u65F6\u8FD4\u56DE null\n */\n async getUsage(email: string): Promise<TrafficUsage | null> {\n const available = await this.isStatsAvailable();\n if (!available) {\n return null;\n }\n\n const policyEnabled = await this.hasUserStatsPolicy();\n if (!policyEnabled) {\n return null;\n }\n\n const uplinkName = STATS_PATTERNS.USER_UPLINK(email);\n const downlinkName = STATS_PATTERNS.USER_DOWNLINK(email);\n\n const [uplink, downlink] = await Promise.all([\n this.queryStats(uplinkName),\n this.queryStats(downlinkName),\n ]);\n\n return {\n email,\n uplink,\n downlink,\n total: uplink + downlink,\n queriedAt: new Date().toISOString(),\n };\n }\n\n /**\n * \u83B7\u53D6\u6240\u6709\u7528\u6237\u6D41\u91CF\u4F7F\u7528\u60C5\u51B5\n *\n * @returns \u6240\u6709\u7528\u6237\u7684\u6D41\u91CF\u6570\u636E\n */\n async getAllUsage(): Promise<TrafficUsage[]> {\n const available = await this.isStatsAvailable();\n if (!available) {\n return [];\n }\n\n const policyEnabled = await this.hasUserStatsPolicy();\n if (!policyEnabled) {\n return [];\n }\n\n try {\n const { stdout } = await execAsync(\n `${XRAY_STATS_COMMAND} api statsquery --server=${this.getServerAddress()} 2>/dev/null`\n );\n const response: XrayStatsResponse = JSON.parse(stdout || '{\"stat\":[]}');\n\n // \u89E3\u6790\u6240\u6709\u7528\u6237\u6D41\u91CF\n const userStats = new Map<string, { uplink: number; downlink: number }>();\n\n for (const stat of response.stat || []) {\n const match = stat.name.match(/^user>>>(.+?)>>>traffic>>>(uplink|downlink)$/);\n if (match) {\n const email = match[1];\n const direction = match[2] as 'uplink' | 'downlink';\n\n if (!userStats.has(email)) {\n userStats.set(email, { uplink: 0, downlink: 0 });\n }\n\n const stats = userStats.get(email)!;\n stats[direction] = Number(stat.value) || 0;\n }\n }\n\n // \u8F6C\u6362\u4E3A TrafficUsage \u6570\u7EC4\n const now = new Date().toISOString();\n const usages: TrafficUsage[] = [];\n\n for (const [email, stats] of userStats) {\n usages.push({\n email,\n uplink: stats.uplink,\n downlink: stats.downlink,\n total: stats.uplink + stats.downlink,\n queriedAt: now,\n });\n }\n\n return usages;\n } catch {\n return [];\n }\n }\n\n /**\n * \u91CD\u7F6E\u7528\u6237\u6D41\u91CF\u7EDF\u8BA1\uFF08\u67E5\u8BE2\u5E76\u91CD\u7F6E\uFF09\n *\n * @param email - \u7528\u6237\u90AE\u7BB1\n * @returns \u91CD\u7F6E\u524D\u7684\u6D41\u91CF\u6570\u636E\n */\n async resetUserStats(email: string): Promise<TrafficUsage | null> {\n const available = await this.isStatsAvailable();\n if (!available) {\n return null;\n }\n\n const uplinkName = STATS_PATTERNS.USER_UPLINK(email);\n const downlinkName = STATS_PATTERNS.USER_DOWNLINK(email);\n\n // \u4F7F\u7528 -reset \u53C2\u6570\u67E5\u8BE2\u5E76\u91CD\u7F6E\n const queryAndReset = async (name: string): Promise<number> => {\n try {\n const { stdout } = await execAsync(\n `${XRAY_STATS_COMMAND} api stats --server=${this.getServerAddress()} -name \"${name}\" -reset 2>/dev/null`\n );\n const result = JSON.parse(stdout || '{}');\n return Number(result.stat?.value) || 0;\n } catch {\n return 0;\n }\n };\n\n const [uplink, downlink] = await Promise.all([\n queryAndReset(uplinkName),\n queryAndReset(downlinkName),\n ]);\n\n return {\n email,\n uplink,\n downlink,\n total: uplink + downlink,\n queriedAt: new Date().toISOString(),\n };\n }\n\n /**\n * \u68C0\u6D4B Xray Stats API \u914D\u7F6E\u72B6\u6001\n *\n * @param configPath - Xray \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\n * @returns \u68C0\u6D4B\u7ED3\u679C\n */\n async detectStatsConfig(\n configPath: string = DEFAULT_XRAY_CONFIG_PATH\n ): Promise<StatsDetectionResult> {\n const result: StatsDetectionResult = {\n available: false,\n configDetected: false,\n serviceRunning: false,\n message: '',\n };\n\n // 1. \u68C0\u67E5\u670D\u52A1\u662F\u5426\u8FD0\u884C\n try {\n await execAsync('systemctl is-active xray');\n result.serviceRunning = true;\n } catch {\n result.serviceRunning = false;\n result.message = 'Xray \u670D\u52A1\u672A\u8FD0\u884C';\n result.suggestion = '\u8BF7\u5148\u542F\u52A8 Xray \u670D\u52A1: systemctl start xray';\n return result;\n }\n\n // 2. \u68C0\u67E5\u914D\u7F6E\u6587\u4EF6\u662F\u5426\u5B58\u5728\n if (!existsSync(configPath)) {\n result.message = `\u672A\u627E\u5230 Xray \u914D\u7F6E\u6587\u4EF6: ${configPath}`;\n result.suggestion = '\u8BF7\u786E\u8BA4 Xray \u5DF2\u6B63\u786E\u5B89\u88C5';\n return result;\n }\n\n // 3. \u89E3\u6790\u914D\u7F6E\u6587\u4EF6\u67E5\u627E stats \u548C api \u914D\u7F6E\n try {\n const content = await readFile(configPath, 'utf-8');\n const config = JSON.parse(content);\n\n // \u68C0\u67E5 stats \u914D\u7F6E\n if (!config.stats) {\n result.message = 'Xray \u914D\u7F6E\u4E2D\u672A\u542F\u7528 stats \u7EDF\u8BA1\u529F\u80FD';\n result.suggestion = '\u8BF7\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u6DFB\u52A0 \"stats\": {} \u6765\u542F\u7528\u6D41\u91CF\u7EDF\u8BA1';\n return result;\n }\n\n // \u68C0\u67E5 policy \u914D\u7F6E\n const levels = config.policy?.levels;\n const hasUserStatsPolicy = levels\n ? Object.values(\n levels as Record<string, { statsUserUplink?: boolean; statsUserDownlink?: boolean }>\n ).some((level) => level?.statsUserUplink === true && level?.statsUserDownlink === true)\n : false;\n if (!hasUserStatsPolicy) {\n result.message = 'Xray \u914D\u7F6E\u4E2D\u672A\u542F\u7528 policy \u6D41\u91CF\u7EDF\u8BA1';\n result.suggestion = '\u8BF7\u5728 policy.levels \u4E2D\u542F\u7528 statsUserUplink/statsUserDownlink';\n return result;\n }\n\n result.configDetected = true;\n\n // \u68C0\u67E5 api \u914D\u7F6E\n if (!config.api) {\n result.message = 'Xray \u914D\u7F6E\u4E2D\u672A\u542F\u7528 API \u63A5\u53E3';\n result.suggestion = '\u8BF7\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u6DFB\u52A0 api \u914D\u7F6E\u6765\u542F\u7528 Stats API';\n return result;\n }\n\n // \u67E5\u627E api inbound \u7AEF\u53E3\n const apiTag = config.api.tag || 'api';\n const apiInbound = config.inbounds?.find(\n (inbound: { tag?: string }) => inbound.tag === apiTag\n );\n\n if (apiInbound?.port) {\n result.detectedPort = apiInbound.port;\n }\n\n // 4. \u6D4B\u8BD5 API \u8FDE\u63A5\n result.available = await this.isStatsAvailable();\n\n if (result.available) {\n result.message = 'Stats API \u5DF2\u5C31\u7EEA';\n } else {\n result.message = 'Stats API \u914D\u7F6E\u5DF2\u68C0\u6D4B\u5230\uFF0C\u4F46\u65E0\u6CD5\u8FDE\u63A5';\n result.suggestion = `\u8BF7\u68C0\u67E5 API \u7AEF\u53E3 ${this.apiPort} \u662F\u5426\u6B63\u786E\uFF0C\u6216\u91CD\u542F Xray \u670D\u52A1`;\n }\n } catch (error) {\n if (error instanceof SyntaxError) {\n result.message = 'Xray \u914D\u7F6E\u6587\u4EF6 JSON \u683C\u5F0F\u9519\u8BEF';\n result.suggestion = '\u8BF7\u68C0\u67E5\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F';\n } else {\n result.message = `\u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6\u5931\u8D25: ${(error as Error).message}`;\n }\n }\n\n return result;\n }\n\n /**\n * \u83B7\u53D6 Stats API \u72B6\u6001\u7684\u53CB\u597D\u63D0\u793A\u4FE1\u606F\n *\n * @returns \u72B6\u6001\u63D0\u793A\n */\n async getStatusMessage(): Promise<string> {\n const [available, policyEnabled] = await Promise.all([\n this.isStatsAvailable(),\n this.hasUserStatsPolicy(),\n ]);\n\n if (available && policyEnabled) {\n return '\u6D41\u91CF\u7EDF\u8BA1\u529F\u80FD\u6B63\u5E38';\n }\n\n if (available && !policyEnabled) {\n return '\u6D41\u91CF\u7EDF\u8BA1\u4E0D\u53EF\u7528 (\u9700\u8981\u5728 Xray \u914D\u7F6E\u4E2D\u542F\u7528 policy \u7EDF\u8BA1)';\n }\n\n const detection = await this.detectStatsConfig();\n\n if (!detection.serviceRunning) {\n return '\u6D41\u91CF\u7EDF\u8BA1\u4E0D\u53EF\u7528 (Xray \u670D\u52A1\u672A\u8FD0\u884C)';\n }\n\n if (!detection.configDetected) {\n return '\u6D41\u91CF\u7EDF\u8BA1\u4E0D\u53EF\u7528 (\u9700\u8981\u5728 Xray \u914D\u7F6E\u4E2D\u542F\u7528 stats)';\n }\n\n return '\u6D41\u91CF\u7EDF\u8BA1\u4E0D\u53EF\u7528 (Stats API \u8FDE\u63A5\u5931\u8D25)';\n }\n}\n", "/**\n * LogManager - System Log Management via journalctl\n *\n * Provides safe interface to query and follow systemd journal logs\n *\n * @module services/log-manager\n */\n\nimport { spawn, ChildProcess } from 'child_process';\nimport { existsSync } from 'fs';\nimport { readFile, stat } from 'fs/promises';\nimport { which } from '../utils/which';\nimport { DEFAULT_PATHS } from '../constants/paths';\n\nconst DEFAULT_LOG_LINES = 200;\nconst DEFAULT_FILE_LOG_LINES = 50;\n\n/**\n * Log entry structure\n */\nexport interface LogEntry {\n /** Log timestamp */\n timestamp: Date;\n\n /** Log message */\n message: string;\n\n /** Log level */\n level: string;\n\n /** Process ID */\n pid?: string;\n\n /** Hostname */\n hostname?: string;\n\n /** Systemd unit */\n unit?: string;\n\n /** Raw log data */\n raw?: string;\n}\n\n/**\n * Log query options\n */\nexport interface LogQueryOptions {\n /** Filter by log level (error, warning, info, debug) */\n level?: string;\n\n /** Time range start (e.g., \"1 hour ago\", \"today\", \"2024-01-01\") */\n since?: string;\n\n /** Time range end */\n until?: string;\n\n /** Number of lines to retrieve */\n lines?: number;\n\n /** Follow mode (real-time) */\n follow?: boolean;\n}\n\n/**\n * Log follow process\n */\nexport interface LogFollowProcess {\n /** Kill the follow process */\n kill: () => void;\n\n /** Child process */\n process: ChildProcess;\n}\n\n/**\n * LogManager - Query and follow systemd journal logs\n */\nexport class LogManager {\n private serviceName: string;\n\n /**\n * Create a new LogManager\n *\n * @param serviceName - Service name to query logs for\n */\n constructor(serviceName: string) {\n this.validateServiceName(serviceName);\n this.serviceName = serviceName;\n }\n\n /**\n * Validate service name to prevent command injection\n *\n * @param name - Service name to validate\n * @throws Error if invalid\n */\n private validateServiceName(name: string): void {\n if (!name || name.trim().length === 0) {\n throw new Error('Service name cannot be empty');\n }\n\n // Prevent path traversal\n if (name.includes('/') || name.includes('\\\\') || name.includes('..')) {\n throw new Error(`Invalid service name: ${name} (path traversal detected)`);\n }\n\n // Prevent command injection\n const dangerousChars = /[;&|`$()]/;\n if (dangerousChars.test(name)) {\n throw new Error(`Invalid service name: ${name} (potentially dangerous characters detected)`);\n }\n\n // Only allow alphanumeric, dash, underscore, and dot\n const validPattern = /^[a-zA-Z0-9_.-]+$/;\n if (!validPattern.test(name)) {\n throw new Error(`Invalid service name: ${name}`);\n }\n }\n\n /**\n * Check if journalctl is available\n *\n * @returns True if journalctl is available\n */\n isJournalctlAvailable(): boolean {\n try {\n const journalctlPath = which('journalctl');\n return journalctlPath !== null && existsSync(journalctlPath);\n } catch {\n return false;\n }\n }\n\n /**\n * Map log level to journalctl priority\n *\n * @param level - Log level (error, warning, info, debug)\n * @returns journalctl priority string\n */\n private mapLevelToPriority(level: string): string {\n const mapping: Record<string, string> = {\n emergency: 'emerg',\n alert: 'alert',\n critical: 'crit',\n error: 'err',\n warning: 'warning',\n notice: 'notice',\n info: 'info',\n debug: 'debug',\n };\n\n return mapping[level.toLowerCase()] || level;\n }\n\n /**\n * Map journalctl priority to readable level\n *\n * @param priority - Journalctl priority (0-7)\n * @returns Readable log level\n */\n private mapPriorityToLevel(priority: string): string {\n const mapping: Record<string, string> = {\n '0': 'emergency',\n '1': 'alert',\n '2': 'critical',\n '3': 'error',\n '4': 'warning',\n '5': 'notice',\n '6': 'info',\n '7': 'debug',\n };\n\n return mapping[priority] || 'unknown';\n }\n\n /**\n * Parse a JSON log entry from journalctl\n *\n * @param jsonLine - JSON string from journalctl -o json\n * @returns Parsed log entry\n */\n parseLogEntry(jsonLine: string): LogEntry {\n try {\n const data = JSON.parse(jsonLine);\n\n // Extract timestamp (microseconds since epoch)\n const timestampMicros = parseInt(data.__REALTIME_TIMESTAMP || '0', 10);\n const timestamp = new Date(timestampMicros / 1000);\n\n // Extract message\n const message = data.MESSAGE || '';\n\n // Extract and map priority\n const priority = data.PRIORITY || '6';\n const level = this.mapPriorityToLevel(priority);\n\n // Extract metadata\n const pid = data._PID;\n const hostname = data._HOSTNAME;\n const unit = data._SYSTEMD_UNIT;\n\n return {\n timestamp,\n message,\n level,\n pid,\n hostname,\n unit,\n raw: jsonLine,\n };\n } catch (error) {\n throw new Error(`Failed to parse log entry: ${(error as Error).message}`);\n }\n }\n\n /**\n * Query logs with filters\n *\n * @param options - Query options\n * @returns Array of log entries\n */\n async queryLogs(options: LogQueryOptions = {}): Promise<LogEntry[]> {\n if (!this.isJournalctlAvailable()) {\n throw new Error(\n 'journalctl is not available on this system. Please ensure systemd is installed.'\n );\n }\n\n const lineLimit = options.lines ?? DEFAULT_LOG_LINES;\n\n // Build journalctl arguments\n const args: string[] = [\n '-u',\n this.serviceName, // Unit filter\n '-o',\n 'json', // JSON output\n '--no-pager', // Disable pager\n ];\n\n // Add level filter\n if (options.level) {\n const priority = this.mapLevelToPriority(options.level);\n args.push('-p', priority);\n }\n\n // Add time range filters\n if (options.since) {\n args.push('--since', options.since);\n }\n\n if (options.until) {\n args.push('--until', options.until);\n }\n\n // Add line limit\n if (Number.isFinite(lineLimit) && lineLimit > 0) {\n args.push('-n', String(lineLimit));\n }\n\n return new Promise((resolve, reject) => {\n const child = spawn('journalctl', args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('close', (code: number) => {\n if (code !== 0) {\n const errorMsg = stderr.trim() || `journalctl exited with code ${code}`;\n\n // Provide helpful error messages\n if (errorMsg.includes('permission') || errorMsg.includes('access')) {\n reject(\n new Error(`\u65E0\u6743\u8BBF\u95EE\u65E5\u5FD7\u3002\u8BF7\u4F7F\u7528 sudo \u6216\u4EE5 root \u7528\u6237\u8FD0\u884C\u3002\\n\u8BE6\u7EC6\u9519\u8BEF: ${errorMsg}`)\n );\n } else {\n reject(new Error(`\u67E5\u8BE2\u65E5\u5FD7\u5931\u8D25: ${errorMsg}`));\n }\n return;\n }\n\n // Parse log entries\n const logs: LogEntry[] = [];\n const lines = stdout.trim().split('\\n');\n\n for (const line of lines) {\n if (!line.trim()) continue;\n\n try {\n const entry = this.parseLogEntry(line);\n logs.push(entry);\n } catch (error) {\n // Skip malformed entries\n console.warn(`Skipped malformed log entry: ${(error as Error).message}`);\n }\n }\n\n resolve(logs);\n });\n\n child.on('error', (error: Error) => {\n reject(new Error(`Failed to execute journalctl: ${error.message}`));\n });\n });\n }\n\n /**\n * Follow logs in real-time\n *\n * @param options - Query options\n * @param onLog - Callback for each log entry\n * @returns Follow process controller\n */\n async followLogs(\n options: LogQueryOptions = {},\n onLog?: (_entry: LogEntry) => void\n ): Promise<LogFollowProcess> {\n if (!this.isJournalctlAvailable()) {\n throw new Error(\n 'journalctl is not available on this system. Please ensure systemd is installed.'\n );\n }\n\n // Build journalctl arguments\n const args: string[] = [\n '-u',\n this.serviceName,\n '-o',\n 'json',\n '--no-pager',\n '-f', // Follow mode\n ];\n\n // Add level filter\n if (options.level) {\n const priority = this.mapLevelToPriority(options.level);\n args.push('-p', priority);\n }\n\n // Add line limit for initial output\n if (options.lines) {\n args.push('-n', String(options.lines));\n }\n\n const child = spawn('journalctl', args, {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n // Handle stdout\n if (onLog) {\n let buffer = '';\n\n child.stdout.on('data', (data: Buffer) => {\n buffer += data.toString();\n const lines = buffer.split('\\n');\n\n // Process complete lines\n for (let i = 0; i < lines.length - 1; i++) {\n const line = lines[i].trim();\n if (!line) continue;\n\n try {\n const entry = this.parseLogEntry(line);\n onLog(entry);\n } catch (error) {\n console.warn(`Skipped malformed log entry: ${(error as Error).message}`);\n }\n }\n\n // Keep incomplete line in buffer\n buffer = lines[lines.length - 1];\n });\n }\n\n // Handle stderr\n child.stderr.on('data', (data: Buffer) => {\n const errorMsg = data.toString();\n console.error(`journalctl error: ${errorMsg}`);\n });\n\n return {\n process: child,\n kill: () => {\n child.kill('SIGINT');\n },\n };\n }\n\n /**\n * Read last N lines from access log file\n *\n * @param lines - Number of lines to read (default: 50)\n * @returns Array of log entry objects\n */\n async readAccessLog(lines: number = DEFAULT_FILE_LOG_LINES): Promise<LogEntry[]> {\n return this.readLogFile(DEFAULT_PATHS.ACCESS_LOG, lines);\n }\n\n /**\n * Read last N lines from error log file\n *\n * @param lines - Number of lines to read (default: 50)\n * @returns Array of log entry objects\n */\n async readErrorLog(lines: number = DEFAULT_FILE_LOG_LINES): Promise<LogEntry[]> {\n return this.readLogFile(DEFAULT_PATHS.ERROR_LOG, lines);\n }\n\n /**\n * Check if a log file exists\n *\n * @param type - Log type ('access' or 'error')\n * @returns true if file exists\n */\n async logExists(type: 'access' | 'error'): Promise<boolean> {\n const logPath = type === 'access' ? DEFAULT_PATHS.ACCESS_LOG : DEFAULT_PATHS.ERROR_LOG;\n return existsSync(logPath);\n }\n\n /**\n * Get log file size\n *\n * @param type - Log type ('access' or 'error')\n * @returns File size in bytes, or 0 if file doesn't exist\n */\n async getLogSize(type: 'access' | 'error'): Promise<number> {\n const logPath = type === 'access' ? DEFAULT_PATHS.ACCESS_LOG : DEFAULT_PATHS.ERROR_LOG;\n try {\n const stats = await stat(logPath);\n return stats.size;\n } catch {\n return 0;\n }\n }\n\n /**\n * Read last N lines from a log file\n *\n * @param logPath - Path to log file\n * @param lines - Number of lines to read\n * @returns Array of log entry objects\n */\n private async readLogFile(logPath: string, lines: number): Promise<LogEntry[]> {\n if (!existsSync(logPath)) {\n return [];\n }\n\n try {\n const content = await readFile(logPath, 'utf-8');\n const allLines = content.split('\\n').filter((line) => line.trim());\n\n // Get last N lines\n const lastLines = allLines.slice(-lines);\n\n return lastLines.map((line, index) =>\n this.parseFileLogEntry(line, allLines.length - lines + index + 1)\n );\n } catch (error) {\n throw new Error(`\u8BFB\u53D6\u65E5\u5FD7\u6587\u4EF6\u5931\u8D25: ${(error as Error).message}`);\n }\n }\n\n /**\n * Parse a log line from file into LogEntry\n *\n * @param line - Raw log line\n * @param lineNumber - Line number in file\n * @returns LogEntry object\n */\n private parseFileLogEntry(line: string, _lineNumber: number): LogEntry {\n // Try to parse timestamp from common log formats\n // Format 1: 2024/01/15 10:30:00 [Info] message\n // Format 2: 2024-01-15T10:30:00.000Z message\n let timestamp = new Date();\n let level = 'info';\n let message = line;\n\n // Try to extract timestamp\n const timestampMatch = line.match(/^(\\d{4}[/-]\\d{2}[/-]\\d{2}[T\\s]\\d{2}:\\d{2}:\\d{2})/);\n if (timestampMatch) {\n try {\n timestamp = new Date(timestampMatch[1].replace(' ', 'T'));\n message = line.substring(timestampMatch[0].length).trim();\n } catch {\n // Keep default timestamp\n }\n }\n\n // Try to extract log level\n const levelMatch = message.match(/^\\[?(Info|Warning|Error|Debug)\\]?:?\\s*/i);\n if (levelMatch) {\n level = levelMatch[1].toLowerCase();\n message = message.substring(levelMatch[0].length);\n }\n\n return {\n timestamp,\n message,\n level,\n raw: line,\n };\n }\n}\n", "/**\n * Which utility - Find executable in PATH\n *\n * @module utils/which\n */\n\nimport { execSync } from 'child_process';\n\n/**\n * Find executable in PATH\n *\n * @param command - Command name to find\n * @returns Path to executable or null if not found\n */\nexport function which(command: string): string | null {\n try {\n const result = execSync(`which ${command}`, {\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n });\n\n return result.trim() || null;\n } catch {\n return null;\n }\n}\n", "/**\n * StatsConfigManager - Xray Stats API \u914D\u7F6E\u7BA1\u7406\n *\n * \u63D0\u4F9B\u81EA\u52A8\u68C0\u6D4B\u3001\u914D\u7F6E\u3001\u5907\u4EFD\u548C\u56DE\u6EDA Stats API \u7684\u529F\u80FD\n *\n * @module services/stats-config-manager\n */\n\nimport { createServer } from 'net';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { ConfigManager } from './config-manager';\nimport { SystemdManager } from './systemd-manager';\nimport { DEFAULT_PATHS } from '../constants/paths';\nimport {\n DEFAULT_API_PORT,\n DEFAULT_API_SERVER,\n DEFAULT_STATS_CONFIG,\n STATS_PORT_RANGE,\n STATS_API_TIMEOUT,\n SERVICE_RESTART_WAIT,\n XRAY_STATS_COMMAND,\n} from '../constants/quota';\nimport type {\n XrayConfigWithStats,\n ApiInbound,\n RoutingRule,\n ApiServiceType,\n PolicyLevelConfig,\n PolicySystemConfig,\n Outbound,\n} from '../types/config';\nimport type { StatsDetectionResult, StatsConfigResult, MissingComponent } from '../types/quota';\n\nconst execAsync = promisify(exec);\n\n/**\n * StatsConfigManager - Stats API \u914D\u7F6E\u7BA1\u7406\u670D\u52A1\n */\nexport class StatsConfigManager {\n private configManager: ConfigManager;\n private systemdManager: SystemdManager;\n private configPath: string;\n\n /**\n * \u521B\u5EFA StatsConfigManager \u5B9E\u4F8B\n *\n * @param configPath - Xray \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\n * @param serviceName - systemd \u670D\u52A1\u540D\u79F0\n */\n constructor(configPath?: string, serviceName?: string) {\n this.configPath = configPath || DEFAULT_PATHS.CONFIG_FILE;\n this.configManager = new ConfigManager(this.configPath);\n this.systemdManager = new SystemdManager(serviceName || DEFAULT_PATHS.SERVICE_NAME);\n }\n\n /**\n * \u68C0\u6D4B\u7F3A\u5931\u7684 Stats API \u914D\u7F6E\u7EC4\u4EF6\n *\n * @returns \u7F3A\u5931\u7EC4\u4EF6\u5217\u8868\n */\n async detectMissingComponents(): Promise<MissingComponent[]> {\n const missing: MissingComponent[] = [];\n\n try {\n const config = (await this.configManager.readConfig()) as XrayConfigWithStats;\n\n // \u68C0\u67E5 stats \u914D\u7F6E\n if (!config.stats) {\n missing.push('stats');\n }\n\n // \u68C0\u67E5 policy \u914D\u7F6E\uFF08\u7528\u6237\u6D41\u91CF\u7EDF\u8BA1\uFF09\n const levels = config.policy?.levels;\n const hasUserStatsPolicy = levels\n ? Object.values(levels).some(\n (level) => level?.statsUserUplink === true && level?.statsUserDownlink === true\n )\n : false;\n if (!hasUserStatsPolicy) {\n missing.push('policy');\n }\n\n // \u68C0\u67E5 api \u914D\u7F6E\n if (!config.api || !config.api.services?.includes('StatsService')) {\n missing.push('api');\n }\n\n // \u68C0\u67E5 api inbound\n const hasApiInbound = config.inbounds?.some(\n (inbound) => inbound.tag === 'api' && inbound.protocol === 'dokodemo-door'\n );\n if (!hasApiInbound) {\n missing.push('api-inbound');\n }\n\n // \u68C0\u67E5 api outbound\n const hasApiOutbound = config.outbounds?.some((outbound) => outbound.tag === 'api');\n if (!hasApiOutbound) {\n missing.push('api-outbound');\n }\n\n // \u68C0\u67E5 api \u8DEF\u7531\u89C4\u5219\n const hasApiRouting = config.routing?.rules?.some(\n (rule) => rule.inboundTag?.includes('api') && rule.outboundTag === 'api'\n );\n if (!hasApiRouting) {\n missing.push('api-routing');\n }\n } catch {\n // \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u6240\u6709\u7EC4\u4EF6\u90FD\u7F3A\u5931\n return ['stats', 'policy', 'api', 'api-inbound', 'api-outbound', 'api-routing'];\n }\n\n return missing;\n }\n\n /**\n * \u68C0\u6D4B\u7AEF\u53E3\u662F\u5426\u53EF\u7528\n *\n * @param port - \u8981\u68C0\u6D4B\u7684\u7AEF\u53E3\n * @returns \u7AEF\u53E3\u662F\u5426\u53EF\u7528\n */\n async isPortAvailable(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = createServer();\n\n server.once('error', () => {\n resolve(false);\n });\n\n server.once('listening', () => {\n server.close();\n resolve(true);\n });\n\n server.listen(port, DEFAULT_API_SERVER);\n });\n }\n\n /**\n * \u67E5\u627E\u53EF\u7528\u7AEF\u53E3\n *\n * @param startPort - \u8D77\u59CB\u7AEF\u53E3\n * @returns \u53EF\u7528\u7AEF\u53E3\uFF0C\u5982\u679C\u6CA1\u6709\u53EF\u7528\u7AEF\u53E3\u5219\u8FD4\u56DE null\n */\n async findAvailablePort(startPort: number = DEFAULT_API_PORT): Promise<number | null> {\n for (let port = startPort; port <= STATS_PORT_RANGE.END; port++) {\n // \u68C0\u67E5\u7AEF\u53E3\u662F\u5426\u88AB\u7CFB\u7EDF\u5360\u7528\n const available = await this.isPortAvailable(port);\n if (!available) {\n continue;\n }\n\n // \u68C0\u67E5\u7AEF\u53E3\u662F\u5426\u5DF2\u88AB Xray \u914D\u7F6E\u4F7F\u7528\n try {\n const config = (await this.configManager.readConfig()) as XrayConfigWithStats;\n const portInUse = config.inbounds?.some((inbound) => inbound.port === port);\n if (portInUse) {\n continue;\n }\n } catch {\n // \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u7AEF\u53E3\u53EF\u7528\n }\n\n return port;\n }\n\n return null;\n }\n\n /**\n * \u751F\u6210 Stats API \u914D\u7F6E\u5BF9\u8C61\n *\n * @param port - API \u7AEF\u53E3\n * @returns Stats API \u914D\u7F6E\u5BF9\u8C61\n */\n generateStatsConfig(port: number = DEFAULT_API_PORT): {\n stats: Record<string, never>;\n policy: {\n levels: Record<string, PolicyLevelConfig>;\n system: PolicySystemConfig;\n };\n api: { tag: string; services: ApiServiceType[] };\n apiInbound: ApiInbound;\n apiOutbound: Outbound;\n apiRoutingRule: RoutingRule;\n } {\n return {\n stats: {},\n policy: {\n levels: {\n ...DEFAULT_STATS_CONFIG.policy.levels,\n },\n system: {\n ...DEFAULT_STATS_CONFIG.policy.system,\n },\n },\n api: {\n tag: DEFAULT_STATS_CONFIG.api.tag,\n services: [...DEFAULT_STATS_CONFIG.api.services] as ApiServiceType[],\n },\n apiInbound: {\n tag: DEFAULT_STATS_CONFIG.apiInbound.tag,\n port,\n listen: DEFAULT_STATS_CONFIG.apiInbound.listen,\n protocol: DEFAULT_STATS_CONFIG.apiInbound.protocol,\n settings: {\n address: DEFAULT_STATS_CONFIG.apiInbound.settings.address,\n },\n },\n apiOutbound: {\n protocol: DEFAULT_STATS_CONFIG.apiOutbound.protocol,\n tag: DEFAULT_STATS_CONFIG.apiOutbound.tag,\n },\n apiRoutingRule: {\n type: DEFAULT_STATS_CONFIG.apiRoutingRule.type,\n inboundTag: [...DEFAULT_STATS_CONFIG.apiRoutingRule.inboundTag],\n outboundTag: DEFAULT_STATS_CONFIG.apiRoutingRule.outboundTag,\n },\n };\n }\n\n /**\n * \u667A\u80FD\u5408\u5E76 Stats \u914D\u7F6E\u5230\u73B0\u6709\u914D\u7F6E\n *\n * @param config - \u73B0\u6709\u914D\u7F6E\n * @param statsConfig - Stats \u914D\u7F6E\n * @returns \u5408\u5E76\u540E\u7684\u914D\u7F6E\n */\n mergeStatsConfig(\n config: XrayConfigWithStats,\n statsConfig: ReturnType<typeof this.generateStatsConfig>\n ): XrayConfigWithStats {\n const merged = { ...config };\n\n // \u6DFB\u52A0 stats \u914D\u7F6E\uFF08\u5982\u679C\u4E0D\u5B58\u5728\uFF09\n if (!merged.stats) {\n merged.stats = statsConfig.stats;\n }\n\n // \u6DFB\u52A0\u6216\u66F4\u65B0 policy \u914D\u7F6E\uFF08\u7528\u6237\u6D41\u91CF\u7EDF\u8BA1\uFF09\n if (!merged.policy) {\n merged.policy = statsConfig.policy;\n } else {\n const hasLevels = !!merged.policy.levels && Object.keys(merged.policy.levels).length > 0;\n const levels = hasLevels ? { ...merged.policy.levels } : { ...statsConfig.policy.levels };\n\n for (const levelKey of Object.keys(levels)) {\n levels[levelKey] = {\n ...levels[levelKey],\n statsUserUplink: true,\n statsUserDownlink: true,\n };\n }\n\n merged.policy.levels = levels;\n merged.policy.system = {\n ...(merged.policy.system || {}),\n statsInboundUplink: true,\n statsInboundDownlink: true,\n };\n }\n\n // \u6DFB\u52A0\u6216\u66F4\u65B0 api \u914D\u7F6E\n if (!merged.api) {\n merged.api = statsConfig.api;\n } else if (!merged.api.services.includes('StatsService')) {\n merged.api.services = [...merged.api.services, 'StatsService'];\n }\n\n // \u6DFB\u52A0 api inbound\uFF08\u5982\u679C\u4E0D\u5B58\u5728\uFF09\n const hasApiInbound = merged.inbounds?.some(\n (inbound) => inbound.tag === 'api' && inbound.protocol === 'dokodemo-door'\n );\n if (!hasApiInbound) {\n merged.inbounds = [...(merged.inbounds || []), statsConfig.apiInbound];\n }\n\n // \u6DFB\u52A0 api outbound\uFF08\u5982\u679C\u4E0D\u5B58\u5728\uFF09\n const hasApiOutbound = merged.outbounds?.some((outbound) => outbound.tag === 'api');\n if (!hasApiOutbound) {\n merged.outbounds = [...(merged.outbounds || []), statsConfig.apiOutbound];\n }\n\n // \u6DFB\u52A0 api \u8DEF\u7531\u89C4\u5219\uFF08\u5982\u679C\u4E0D\u5B58\u5728\uFF09\n if (!merged.routing) {\n merged.routing = { rules: [] };\n }\n if (!merged.routing.rules) {\n merged.routing.rules = [];\n }\n\n const hasApiRouting = merged.routing.rules.some(\n (rule) => rule.inboundTag?.includes('api') && rule.outboundTag === 'api'\n );\n if (!hasApiRouting) {\n merged.routing.rules = [statsConfig.apiRoutingRule, ...merged.routing.rules];\n }\n\n return merged;\n }\n\n /**\n * \u9A8C\u8BC1 Stats API \u8FDE\u63A5\n *\n * @param port - API \u7AEF\u53E3\n * @returns \u662F\u5426\u53EF\u8FDE\u63A5\n */\n async verifyStatsApiConnection(port: number = DEFAULT_API_PORT): Promise<boolean> {\n try {\n const { stdout } = await execAsync(\n `${XRAY_STATS_COMMAND} api statsquery --server=${DEFAULT_API_SERVER}:${port} 2>/dev/null`,\n { timeout: STATS_API_TIMEOUT }\n );\n // \u5982\u679C\u547D\u4EE4\u6210\u529F\u6267\u884C\u5E76\u8FD4\u56DE JSON\uFF0C\u5219 API \u53EF\u7528\n JSON.parse(stdout || '{}');\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * \u5907\u4EFD\u914D\u7F6E\u6587\u4EF6\n *\n * @returns \u5907\u4EFD\u6587\u4EF6\u8DEF\u5F84\n */\n async backupBeforeModify(): Promise<string> {\n return await this.configManager.backupConfig();\n }\n\n /**\n * \u56DE\u6EDA\u914D\u7F6E\u5E76\u91CD\u542F\u670D\u52A1\n *\n * @param backupPath - \u5907\u4EFD\u6587\u4EF6\u8DEF\u5F84\n */\n async rollbackOnFailure(backupPath: string): Promise<void> {\n await this.configManager.restoreConfig(backupPath);\n await this.systemdManager.restart();\n }\n\n /**\n * \u91CD\u542F\u670D\u52A1\u5E76\u9A8C\u8BC1\u72B6\u6001\n *\n * @returns \u670D\u52A1\u662F\u5426\u6B63\u5E38\u8FD0\u884C\n */\n async restartAndVerify(): Promise<boolean> {\n try {\n await this.systemdManager.restart();\n\n // \u7B49\u5F85\u670D\u52A1\u542F\u52A8\n await new Promise((resolve) => setTimeout(resolve, SERVICE_RESTART_WAIT));\n\n // \u68C0\u67E5\u670D\u52A1\u72B6\u6001\n const status = await this.systemdManager.getStatus();\n return status.active;\n } catch {\n return false;\n }\n }\n\n /**\n * \u68C0\u6D4B Stats API \u72B6\u6001\n *\n * @returns \u68C0\u6D4B\u7ED3\u679C\n */\n async detectStatsConfig(): Promise<StatsDetectionResult> {\n const missingComponents = await this.detectMissingComponents();\n let serviceRunning = false;\n try {\n const status = await this.systemdManager.getStatus();\n serviceRunning = status.active;\n } catch {\n serviceRunning = false;\n }\n\n // \u5982\u679C\u6240\u6709\u7EC4\u4EF6\u90FD\u5B58\u5728\uFF0C\u5C1D\u8BD5\u8FDE\u63A5 API\n if (missingComponents.length === 0 && serviceRunning) {\n // \u83B7\u53D6\u914D\u7F6E\u7684\u7AEF\u53E3\n let detectedPort = DEFAULT_API_PORT;\n try {\n const config = (await this.configManager.readConfig()) as XrayConfigWithStats;\n const apiInbound = config.inbounds?.find(\n (inbound) => inbound.tag === 'api' && inbound.protocol === 'dokodemo-door'\n );\n if (apiInbound) {\n detectedPort = apiInbound.port;\n }\n } catch {\n // \u4F7F\u7528\u9ED8\u8BA4\u7AEF\u53E3\n }\n\n const available = await this.verifyStatsApiConnection(detectedPort);\n\n return {\n available,\n configDetected: true,\n detectedPort,\n serviceRunning,\n message: available ? 'Stats API \u5DF2\u914D\u7F6E\u4E14\u53EF\u7528' : 'Stats API \u5DF2\u914D\u7F6E\u4F46\u65E0\u6CD5\u8FDE\u63A5',\n suggestion: available ? undefined : '\u8BF7\u68C0\u67E5 Xray \u670D\u52A1\u72B6\u6001\u548C\u9632\u706B\u5899\u8BBE\u7F6E',\n missingComponents: [],\n };\n }\n\n // \u6709\u7F3A\u5931\u7EC4\u4EF6\n const componentNames: Record<MissingComponent, string> = {\n stats: 'stats \u914D\u7F6E\u5757',\n policy: 'policy \u914D\u7F6E',\n api: 'API \u914D\u7F6E',\n 'api-inbound': 'API \u5165\u7AD9\u914D\u7F6E',\n 'api-outbound': 'API \u51FA\u7AD9\u914D\u7F6E',\n 'api-routing': 'API \u8DEF\u7531\u89C4\u5219',\n };\n\n const missingNames = missingComponents.map((c) => componentNames[c]).join('\u3001');\n\n return {\n available: false,\n configDetected: missingComponents.length < 6,\n serviceRunning,\n message: `Stats API \u672A\u5B8C\u5168\u914D\u7F6E\uFF0C\u7F3A\u5C11: ${missingNames}`,\n suggestion: '\u662F\u5426\u81EA\u52A8\u914D\u7F6E Stats API\uFF1F',\n missingComponents,\n };\n }\n\n /**\n * \u542F\u7528 Stats API\uFF08\u4E3B\u65B9\u6CD5\uFF09\n *\n * @returns \u914D\u7F6E\u7ED3\u679C\n */\n async enableStatsApi(): Promise<StatsConfigResult> {\n let backupPath: string | undefined;\n\n try {\n // 1. \u67E5\u627E\u53EF\u7528\u7AEF\u53E3\n const port = await this.findAvailablePort();\n if (!port) {\n return {\n success: false,\n apiPort: DEFAULT_API_PORT,\n message: '\u65E0\u6CD5\u627E\u5230\u53EF\u7528\u7AEF\u53E3',\n error: `\u7AEF\u53E3\u8303\u56F4 ${STATS_PORT_RANGE.START}-${STATS_PORT_RANGE.END} \u5747\u88AB\u5360\u7528`,\n rolledBack: false,\n };\n }\n\n // 2. \u5907\u4EFD\u914D\u7F6E\n backupPath = await this.backupBeforeModify();\n\n // 3. \u8BFB\u53D6\u73B0\u6709\u914D\u7F6E\n const config = (await this.configManager.readConfig()) as XrayConfigWithStats;\n\n // 4. \u751F\u6210\u5E76\u5408\u5E76 Stats \u914D\u7F6E\n const statsConfig = this.generateStatsConfig(port);\n const mergedConfig = this.mergeStatsConfig(config, statsConfig);\n\n // 5. \u5199\u5165\u914D\u7F6E (cast to unknown first to bypass strict type checking)\n await this.configManager.writeConfig(\n mergedConfig as unknown as Parameters<typeof this.configManager.writeConfig>[0]\n );\n\n // 6. \u91CD\u542F\u670D\u52A1\n const serviceOk = await this.restartAndVerify();\n if (!serviceOk) {\n // \u670D\u52A1\u91CD\u542F\u5931\u8D25\uFF0C\u56DE\u6EDA\n await this.rollbackOnFailure(backupPath);\n return {\n success: false,\n backupPath,\n apiPort: port,\n message: '\u670D\u52A1\u91CD\u542F\u5931\u8D25\uFF0C\u5DF2\u6062\u590D\u539F\u914D\u7F6E',\n error: 'Xray \u670D\u52A1\u542F\u52A8\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E\u6587\u4EF6',\n rolledBack: true,\n };\n }\n\n // 7. \u9A8C\u8BC1 API \u8FDE\u63A5\n const apiOk = await this.verifyStatsApiConnection(port);\n if (!apiOk) {\n // API \u65E0\u6CD5\u8FDE\u63A5\uFF0C\u4F46\u670D\u52A1\u8FD0\u884C\u6B63\u5E38\uFF0C\u4E0D\u56DE\u6EDA\n return {\n success: true,\n backupPath,\n apiPort: port,\n message: 'Stats API \u914D\u7F6E\u6210\u529F\uFF0C\u4F46\u8FDE\u63A5\u9A8C\u8BC1\u5931\u8D25',\n error: 'API \u53EF\u80FD\u9700\u8981\u51E0\u79D2\u949F\u624D\u80FD\u5C31\u7EEA\uFF0C\u6216\u68C0\u67E5\u9632\u706B\u5899\u8BBE\u7F6E',\n rolledBack: false,\n };\n }\n\n return {\n success: true,\n backupPath,\n apiPort: port,\n message: 'Stats API \u914D\u7F6E\u6210\u529F\uFF01',\n rolledBack: false,\n };\n } catch (error) {\n // \u53D1\u751F\u9519\u8BEF\uFF0C\u5C1D\u8BD5\u56DE\u6EDA\n if (backupPath) {\n try {\n await this.rollbackOnFailure(backupPath);\n return {\n success: false,\n backupPath,\n apiPort: DEFAULT_API_PORT,\n message: '\u914D\u7F6E\u5931\u8D25\uFF0C\u5DF2\u6062\u590D\u539F\u914D\u7F6E',\n error: (error as Error).message,\n rolledBack: true,\n };\n } catch (rollbackError) {\n return {\n success: false,\n backupPath,\n apiPort: DEFAULT_API_PORT,\n message: '\u914D\u7F6E\u5931\u8D25\uFF0C\u56DE\u6EDA\u4E5F\u5931\u8D25',\n error: `\u539F\u9519\u8BEF: ${(error as Error).message}; \u56DE\u6EDA\u9519\u8BEF: ${(rollbackError as Error).message}`,\n rolledBack: false,\n };\n }\n }\n\n return {\n success: false,\n apiPort: DEFAULT_API_PORT,\n message: '\u914D\u7F6E\u5931\u8D25',\n error: (error as Error).message,\n rolledBack: false,\n };\n }\n }\n}\n", "import React, { createContext, useContext, useReducer, useCallback } from 'react';\nimport { type Route, SCREEN_TITLES } from '../app/routes.js';\n\ninterface NavigationState {\n stack: Route[];\n}\n\ntype NavigationAction =\n | { type: 'NAVIGATE'; route: Route }\n | { type: 'GO_BACK' }\n | { type: 'RESET' };\n\nfunction reducer(state: NavigationState, action: NavigationAction): NavigationState {\n switch (action.type) {\n case 'NAVIGATE':\n return { stack: [...state.stack, action.route] };\n case 'GO_BACK':\n if (state.stack.length <= 1) return state;\n return { stack: state.stack.slice(0, -1) };\n case 'RESET':\n return { stack: [{ screen: 'main-menu' }] };\n default:\n return state;\n }\n}\n\ninterface NavigationContextValue {\n currentRoute: Route;\n breadcrumb: string[];\n canGoBack: boolean;\n navigate: (route: Route) => void;\n goBack: () => void;\n reset: () => void;\n}\n\nconst NavigationContext = createContext<NavigationContextValue>({\n currentRoute: { screen: 'main-menu' },\n breadcrumb: ['Home'],\n canGoBack: false,\n navigate: () => {},\n goBack: () => {},\n reset: () => {},\n});\n\nexport function NavigationProvider({ children }: { children: React.ReactNode }) {\n const [state, dispatch] = useReducer(reducer, {\n stack: [{ screen: 'main-menu' }],\n });\n\n const navigate = useCallback((route: Route) => {\n dispatch({ type: 'NAVIGATE', route });\n }, []);\n\n const goBack = useCallback(() => {\n dispatch({ type: 'GO_BACK' });\n }, []);\n\n const reset = useCallback(() => {\n dispatch({ type: 'RESET' });\n }, []);\n\n const currentRoute = state.stack[state.stack.length - 1] ?? { screen: 'main-menu' as const };\n const breadcrumb = state.stack.map((r) => SCREEN_TITLES[r.screen]);\n const canGoBack = state.stack.length > 1;\n\n return (\n <NavigationContext.Provider\n value={{ currentRoute, breadcrumb, canGoBack, navigate, goBack, reset }}\n >\n {children}\n </NavigationContext.Provider>\n );\n}\n\nexport function useNavigation(): NavigationContextValue {\n return useContext(NavigationContext);\n}\n", "export type Route =\n | { screen: 'main-menu' }\n | { screen: 'service-status' }\n | { screen: 'user-management' }\n | { screen: 'user-add' }\n | { screen: 'user-delete' }\n | { screen: 'user-share'; userId?: string }\n | { screen: 'quota-management' }\n | { screen: 'quota-set' }\n | { screen: 'quota-details'; email?: string }\n | { screen: 'config-management' }\n | { screen: 'log-viewer' }\n | { screen: 'online-users' }\n | { screen: 'subscriptions' }\n | { screen: 'command-palette' };\n\nexport const SCREEN_TITLES: Record<Route['screen'], string> = {\n 'main-menu': 'Home',\n 'service-status': 'Service Status',\n 'user-management': 'User Management',\n 'user-add': 'Add User',\n 'user-delete': 'Delete User',\n 'user-share': 'Share Link',\n 'quota-management': 'Quota Management',\n 'quota-set': 'Set Quota',\n 'quota-details': 'Quota Details',\n 'config-management': 'Configuration',\n 'log-viewer': 'Log Viewer',\n 'online-users': 'Online Users',\n subscriptions: 'Subscriptions',\n 'command-palette': 'Command Palette',\n};\n", "import React, { createContext, useContext, useState, useCallback } from 'react';\n\nexport interface Notification {\n id: number;\n type: 'success' | 'error' | 'warning' | 'info';\n message: string;\n}\n\ninterface NotificationContextValue {\n notifications: Notification[];\n notify: (type: Notification['type'], message: string) => void;\n dismiss: (id: number) => void;\n}\n\nlet nextId = 0;\n\nconst NotificationContext = createContext<NotificationContextValue>({\n notifications: [],\n notify: () => {},\n dismiss: () => {},\n});\n\nexport function NotificationProvider({ children }: { children: React.ReactNode }) {\n const [notifications, setNotifications] = useState<Notification[]>([]);\n\n const dismiss = useCallback((id: number) => {\n setNotifications((prev) => prev.filter((n) => n.id !== id));\n }, []);\n\n const notify = useCallback(\n (type: Notification['type'], message: string) => {\n const id = nextId++;\n setNotifications((prev) => [...prev, { id, type, message }]);\n // Auto-dismiss after 3 seconds\n setTimeout(() => dismiss(id), 3000);\n },\n [dismiss]\n );\n\n return (\n <NotificationContext.Provider value={{ notifications, notify, dismiss }}>\n {children}\n </NotificationContext.Provider>\n );\n}\n\nexport function useNotification(): NotificationContextValue {\n return useContext(NotificationContext);\n}\n", "import React, { useState } from 'react';\nimport { Box, useInput, useApp } from 'ink';\nimport { Header } from '../components/design-system/Header.js';\nimport { StatusBar } from '../components/design-system/StatusBar.js';\nimport { Divider } from '../components/design-system/Divider.js';\nimport { Breadcrumb } from '../components/Breadcrumb.js';\nimport { Dashboard } from '../components/Dashboard.js';\nimport { Toast } from '../components/Toast.js';\nimport { CommandPalette, type CommandItem } from '../components/CommandPalette.js';\nimport { Router } from './Router.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useNotification } from '../contexts/NotificationContext.js';\nimport { useDashboardData } from '../hooks/useDashboardData.js';\n\ninterface AppShellProps {\n version: string;\n}\n\nexport function AppShell({ version }: AppShellProps) {\n const { exit } = useApp();\n const { currentRoute, goBack, canGoBack, navigate, reset } = useNavigation();\n const { notifications, dismiss } = useNotification();\n const { data: dashboardData, loading: dashboardLoading } = useDashboardData();\n const [showPalette, setShowPalette] = useState(false);\n\n const commandItems: CommandItem[] = [\n { label: 'Service Status', value: 'service-status', category: 'Service' },\n { label: 'Online Users', value: 'online-users', category: 'Monitor' },\n { label: 'User Management', value: 'user-management', category: 'Users' },\n { label: 'Add User', value: 'user-add', category: 'Users' },\n { label: 'Traffic & Quotas', value: 'quota-management', category: 'Quotas' },\n { label: 'Set Quota', value: 'quota-set', category: 'Quotas' },\n { label: 'Subscriptions', value: 'subscriptions', category: 'Service' },\n { label: 'Configuration', value: 'config-management', category: 'System' },\n { label: 'View Logs', value: 'log-viewer', category: 'System' },\n ];\n\n useInput((input, key) => {\n if (showPalette) return;\n if (input === '/' && currentRoute.screen !== 'command-palette') {\n setShowPalette(true);\n } else if (key.escape) {\n if (canGoBack) goBack();\n } else if (input === 'q') {\n if (currentRoute.screen === 'main-menu') exit();\n else reset();\n }\n });\n\n const handlePaletteSelect = (value: string) => {\n setShowPalette(false);\n navigate({ screen: value } as { screen: 'service-status' });\n };\n\n const serviceStatus = dashboardData?.serviceActive\n ? ('running' as const)\n : dashboardData\n ? ('stopped' as const)\n : ('loading' as const);\n\n const isHome = currentRoute.screen === 'main-menu';\n\n return (\n <Box flexDirection=\"column\">\n {/* Header: title + service status */}\n <Header version={version} serviceStatus={serviceStatus} uptime={dashboardData?.uptime} />\n\n {/* Dashboard: only on home screen */}\n {isHome && (\n <>\n <Dashboard data={dashboardData} loading={dashboardLoading} />\n <Divider />\n </>\n )}\n\n {/* Breadcrumb: only when navigated away from home */}\n {!isHome && (\n <Box paddingX={2} paddingBottom={1}>\n <Breadcrumb />\n </Box>\n )}\n\n {/* Command Palette overlay */}\n {showPalette && (\n <Box paddingX={2}>\n <CommandPalette\n items={commandItems}\n onSelect={handlePaletteSelect}\n onCancel={() => setShowPalette(false)}\n />\n </Box>\n )}\n\n {/* Main content */}\n {!showPalette && <Router />}\n\n {/* Notifications */}\n {notifications.length > 0 && (\n <Box flexDirection=\"column\" paddingX={2} paddingTop={1}>\n {notifications.map((n) => (\n <Toast key={n.id} type={n.type} message={n.message} onDismiss={() => dismiss(n.id)} />\n ))}\n </Box>\n )}\n\n {/* Status bar */}\n <Divider />\n <StatusBar />\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box, Text } from 'ink';\nimport { useTheme } from './ThemeProvider.js';\nimport { useI18n } from '../../contexts/I18nContext.js';\n\ninterface HeaderProps {\n version: string;\n serviceStatus?: 'running' | 'stopped' | 'error' | 'loading';\n uptime?: string;\n}\n\nexport function Header({ version, serviceStatus = 'loading', uptime }: HeaderProps) {\n const { theme } = useTheme();\n const { t } = useI18n();\n\n const statusColor =\n serviceStatus === 'running'\n ? theme.serviceRunning\n : serviceStatus === 'stopped'\n ? theme.serviceStopped\n : serviceStatus === 'error'\n ? theme.error\n : theme.inactive;\n\n const statusLabel = t.status[serviceStatus] ?? serviceStatus;\n\n return (\n <Box paddingX={2} paddingY={1} justifyContent=\"space-between\">\n <Box gap={1}>\n <Text color={theme.primary} bold>\n Xray Manager\n </Text>\n <Text dimColor>v{version}</Text>\n </Box>\n <Box gap={1}>\n <Text color={statusColor} bold>\n {'\\u25cf'} {statusLabel}\n </Text>\n {uptime && <Text dimColor>{uptime}</Text>}\n </Box>\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box, Text } from 'ink';\nimport { useNavigation } from '../../contexts/NavigationContext.js';\nimport { useI18n } from '../../contexts/I18nContext.js';\n\nexport interface ShortcutHint {\n key: string;\n action: string;\n}\n\ninterface StatusBarProps {\n hints?: ShortcutHint[];\n}\n\nexport function StatusBar({ hints }: StatusBarProps) {\n const { canGoBack } = useNavigation();\n const { t } = useI18n();\n\n const effectiveHints = hints ?? [\n ...(canGoBack ? [{ key: 'esc', action: t.ui.back }] : []),\n { key: '\\u2191\\u2193', action: t.ui.navigate },\n { key: 'enter', action: t.ui.select },\n { key: '/', action: t.ui.search },\n { key: 'q', action: t.ui.quit },\n ];\n\n return (\n <Box paddingX={2}>\n {effectiveHints.map((hint, i) => (\n <Text key={i} dimColor>\n {i > 0 ? ' ' : ''}\n <Text bold>{hint.key}</Text> {hint.action}\n </Text>\n ))}\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box, Text } from 'ink';\nimport { useTheme } from './ThemeProvider.js';\nimport { resolveColor } from './theme.js';\n\ninterface DividerProps {\n color?: string;\n title?: string;\n padding?: number;\n}\n\nexport function Divider({ color, title, padding = 2 }: DividerProps) {\n const { theme } = useTheme();\n const w = Math.max(10, (process.stdout.columns || 80) - padding * 2);\n const dimmed = !color;\n const lineColor = resolveColor(color, theme) ?? theme.border;\n\n if (title) {\n const titleStr = ` ${title} `;\n const remaining = Math.max(0, w - titleStr.length);\n const left = Math.min(3, remaining);\n const right = remaining - left;\n return (\n <Box paddingX={padding}>\n <Text dimColor={dimmed} color={dimmed ? undefined : lineColor}>\n {'\\u2500'.repeat(left)}\n </Text>\n <Text dimColor>{titleStr}</Text>\n <Text dimColor={dimmed} color={dimmed ? undefined : lineColor}>\n {'\\u2500'.repeat(Math.max(0, right))}\n </Text>\n </Box>\n );\n }\n\n return (\n <Box paddingX={padding}>\n <Text dimColor={dimmed} color={dimmed ? undefined : lineColor}>\n {'\\u2500'.repeat(w)}\n </Text>\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box, Text } from 'ink';\nimport { useNavigation } from '../contexts/NavigationContext.js';\n\nexport function Breadcrumb() {\n const { breadcrumb } = useNavigation();\n\n if (breadcrumb.length <= 1) return null;\n\n return (\n <Box>\n {breadcrumb.map((segment, i) => {\n const isLast = i === breadcrumb.length - 1;\n return (\n <Text key={i}>\n {i > 0 && <Text dimColor> {'>'} </Text>}\n <Text dimColor={!isLast} bold={isLast}>\n {segment}\n </Text>\n </Text>\n );\n })}\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box, Text } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\nimport { formatBytes } from '../utils/format.js';\n\nexport interface DashboardData {\n serviceActive: boolean;\n uptime?: string;\n userCount: number;\n onlineCount?: number;\n totalTraffic: number;\n uploadTraffic: number;\n downloadTraffic: number;\n quotaSummary: { ok: number; warning: number; exceeded: number };\n cpuPercent?: number;\n memPercent?: number;\n diskPercent?: number;\n}\n\ninterface DashboardProps {\n data: DashboardData | null;\n loading?: boolean;\n}\n\nfunction MiniBar({\n value,\n max = 100,\n width = 8,\n theme,\n}: {\n value: number;\n max?: number;\n theme: Record<string, string>;\n width?: number;\n}) {\n const ratio = Math.min(value / max, 1);\n const filled = Math.round(ratio * width);\n const empty = width - filled;\n const color = value > 90 ? theme.error : value > 70 ? theme.warning : theme.success;\n return (\n <Text>\n <Text color={color}>{'\\u2588'.repeat(filled)}</Text>\n <Text dimColor>{'\\u2591'.repeat(empty)}</Text>\n </Text>\n );\n}\n\nexport function Dashboard({ data, loading }: DashboardProps) {\n const { theme } = useTheme();\n const t = theme as unknown as Record<string, string>;\n\n if (loading || !data) {\n return (\n <Box paddingX={2}>\n <Text dimColor italic>\n Loading...\n </Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n {/* Row 1: Traffic + Users */}\n <Box gap={2}>\n <Box gap={1}>\n <Text dimColor>Traffic</Text>\n <Text bold>{formatBytes(data.totalTraffic)}</Text>\n <Text dimColor>\n {'\\u2191'}\n {formatBytes(data.uploadTraffic)} {'\\u2193'}\n {formatBytes(data.downloadTraffic)}\n </Text>\n </Box>\n\n <Text dimColor>|</Text>\n\n <Box gap={1}>\n <Text dimColor>Users</Text>\n {data.onlineCount !== undefined && (\n <Text color={theme.success} bold>\n {data.onlineCount}\n </Text>\n )}\n {data.onlineCount !== undefined && <Text dimColor>/</Text>}\n <Text bold>{data.userCount}</Text>\n {data.quotaSummary.exceeded > 0 && (\n <Text color={theme.error}>({data.quotaSummary.exceeded} over)</Text>\n )}\n </Box>\n </Box>\n\n {/* Row 2: System resources \u2014 compact bar style */}\n {data.cpuPercent !== undefined && (\n <Box gap={2}>\n <Box gap={1}>\n <Text dimColor>cpu</Text>\n <MiniBar value={data.cpuPercent ?? 0} theme={t} />\n <Text dimColor>{data.cpuPercent}%</Text>\n </Box>\n <Box gap={1}>\n <Text dimColor>mem</Text>\n <MiniBar value={data.memPercent ?? 0} theme={t} />\n <Text dimColor>{data.memPercent}%</Text>\n </Box>\n {data.diskPercent !== undefined && (\n <Box gap={1}>\n <Text dimColor>disk</Text>\n <MiniBar value={data.diskPercent} theme={t} />\n <Text dimColor>{data.diskPercent}%</Text>\n </Box>\n )}\n </Box>\n )}\n </Box>\n );\n}\n", "/**\n * \u683C\u5F0F\u5316\u5DE5\u5177\u51FD\u6570\n * @module utils/format\n */\n\n/**\n * \u8131\u654F\u9009\u9879\n */\nexport interface MaskOptions {\n /** \u524D\u7F00\u957F\u5EA6\uFF08\u9ED8\u8BA4 4\uFF09 */\n prefixLength?: number;\n\n /** \u540E\u7F00\u957F\u5EA6\uFF08\u9ED8\u8BA4 4\uFF09 */\n suffixLength?: number;\n\n /** \u63A9\u7801\u5B57\u7B26\uFF08\u9ED8\u8BA4 *\uFF09 */\n maskChar?: string;\n}\n\n/**\n * \u8131\u654F\u663E\u793A\u654F\u611F\u4FE1\u606F\uFF08\u524D4\u540E4\uFF09\n * @param value \u539F\u59CB\u503C\n * @param options \u8131\u654F\u9009\u9879\n * @returns \u8131\u654F\u540E\u7684\u503C\n */\nexport function maskSensitiveValue(value: string, options: MaskOptions = {}): string {\n const { prefixLength = 4, suffixLength = 4, maskChar = '*' } = options;\n\n // Handle empty or very short strings\n if (!value) {\n return maskChar.repeat(3);\n }\n\n if (value.length <= prefixLength + suffixLength) {\n // For short strings, show first char only\n if (value.length <= 3) {\n return value[0] + maskChar.repeat(value.length - 1 || 2);\n }\n return maskChar.repeat(value.length);\n }\n\n // Special handling for email addresses\n if (value.includes('@')) {\n const [localPart, domain] = value.split('@');\n const maskedLocal =\n localPart.slice(0, Math.min(4, localPart.length)) +\n maskChar.repeat(Math.max(0, localPart.length - 4));\n return `${maskedLocal}@${domain}`;\n }\n\n // Default masking: show first 4 and last 4\n const prefix = value.slice(0, prefixLength);\n const suffix = value.slice(-suffixLength);\n const maskLength = value.length - prefixLength - suffixLength;\n\n return `${prefix}${maskChar.repeat(maskLength)}${suffix}`;\n}\n\n/**\n * \u683C\u5F0F\u5316\u8FD0\u884C\u65F6\u957F\uFF08\u6BEB\u79D2\u8F6C\u4E3A\u53EF\u8BFB\u683C\u5F0F\uFF09\n * @param milliseconds \u6BEB\u79D2\u6570\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u65F6\u957F\u5B57\u7B26\u4E32\n */\nexport function formatUptime(milliseconds: number): string {\n if (!milliseconds || milliseconds < 0) {\n return '0\u79D2';\n }\n\n const seconds = Math.floor(milliseconds / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days}\u5929 ${hours % 24}\u5C0F\u65F6 ${minutes % 60}\u5206\u949F`;\n } else if (hours > 0) {\n return `${hours}\u5C0F\u65F6 ${minutes % 60}\u5206\u949F`;\n } else if (minutes > 0) {\n return `${minutes}\u5206\u949F ${seconds % 60}\u79D2`;\n } else {\n return `${seconds}\u79D2`;\n }\n}\n\n/**\n * \u683C\u5F0F\u5316\u5B57\u8282\u5927\u5C0F\n * @param bytes \u5B57\u8282\u6570\n * @param decimals \u5C0F\u6570\u4F4D\u6570\uFF08\u9ED8\u8BA4 2\uFF09\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u5927\u5C0F\u5B57\u7B26\u4E32\n */\nexport function formatBytes(bytes: number, decimals: number = 2): string {\n if (bytes === 0) return '0 B';\n if (!bytes || bytes < 0) return 'N/A';\n\n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];\n\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;\n}\n\n/**\n * \u683C\u5F0F\u5316\u65F6\u95F4\u6233\u4E3A\u53EF\u8BFB\u65E5\u671F\n * @param timestamp ISO 8601 \u5B57\u7B26\u4E32\u6216 Unix \u65F6\u95F4\u6233\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u65E5\u671F\u5B57\u7B26\u4E32\n */\nexport function formatDate(timestamp: string | number): string {\n const date = typeof timestamp === 'string' ? new Date(timestamp) : new Date(timestamp);\n\n if (isNaN(date.getTime())) {\n return 'Invalid Date';\n }\n\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hours = String(date.getHours()).padStart(2, '0');\n const minutes = String(date.getMinutes()).padStart(2, '0');\n\n return `${year}-${month}-${day} ${hours}:${minutes}`;\n}\n\n/**\n * \u683C\u5F0F\u5316\u76F8\u5BF9\u65F6\u95F4\uFF08\u5982 \"2 \u5C0F\u65F6\u524D\"\uFF09\n * @param timestamp ISO 8601 \u5B57\u7B26\u4E32\u6216 Unix \u65F6\u95F4\u6233\n * @returns \u76F8\u5BF9\u65F6\u95F4\u5B57\u7B26\u4E32\n */\nexport function formatRelativeTime(timestamp: string | number): string {\n const date = typeof timestamp === 'string' ? new Date(timestamp) : new Date(timestamp);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n\n if (diffMs < 0) {\n return '\u672A\u6765';\n }\n\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n\n if (diffDays > 0) {\n return `${diffDays}\u5929\u524D`;\n } else if (diffHours > 0) {\n return `${diffHours}\u5C0F\u65F6\u524D`;\n } else if (diffMinutes > 0) {\n return `${diffMinutes}\u5206\u949F\u524D`;\n } else {\n return `${diffSeconds}\u79D2\u524D`;\n }\n}\n\n/**\n * \u683C\u5F0F\u5316\u6301\u7EED\u65F6\u95F4\uFF08\u6BEB\u79D2\u8F6C\u4E3A\u7B80\u6D01\u683C\u5F0F\uFF09\n * @param ms \u6BEB\u79D2\u6570\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u6301\u7EED\u65F6\u95F4\u5B57\u7B26\u4E32\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${ms}ms`;\n } else if (ms < 60000) {\n return `${(ms / 1000).toFixed(1)}s`;\n } else if (ms < 3600000) {\n return `${(ms / 60000).toFixed(1)}m`;\n } else {\n return `${(ms / 3600000).toFixed(1)}h`;\n }\n}\n\n/**\n * \u683C\u5F0F\u5316 JSON\uFF08\u7F8E\u5316\u8F93\u51FA\uFF09\n * @param obj \u5BF9\u8C61\n * @param spaces \u7F29\u8FDB\u7A7A\u683C\u6570\uFF08\u9ED8\u8BA4 2\uFF09\n * @returns \u683C\u5F0F\u5316\u540E\u7684 JSON \u5B57\u7B26\u4E32\n */\nexport function formatJSON(obj: unknown, spaces: number = 2): string {\n try {\n return JSON.stringify(obj, null, spaces);\n } catch {\n return String(obj);\n }\n}\n\n/**\n * \u622A\u65AD\u5B57\u7B26\u4E32\uFF08\u6DFB\u52A0\u7701\u7565\u53F7\uFF09\n * @param str \u539F\u59CB\u5B57\u7B26\u4E32\n * @param maxLength \u6700\u5927\u957F\u5EA6\n * @param ellipsis \u7701\u7565\u53F7\uFF08\u9ED8\u8BA4 ...\uFF09\n * @returns \u622A\u65AD\u540E\u7684\u5B57\u7B26\u4E32\n */\nexport function truncate(str: string, maxLength: number, ellipsis: string = '...'): string {\n if (!str || str.length <= maxLength) {\n return str;\n }\n\n return str.slice(0, maxLength - ellipsis.length) + ellipsis;\n}\n\n/**\n * \u586B\u5145\u5B57\u7B26\u4E32\uFF08\u5BF9\u9F50\uFF09\n * @param str \u539F\u59CB\u5B57\u7B26\u4E32\n * @param length \u76EE\u6807\u957F\u5EA6\n * @param padChar \u586B\u5145\u5B57\u7B26\uFF08\u9ED8\u8BA4\u7A7A\u683C\uFF09\n * @param align \u5BF9\u9F50\u65B9\u5F0F\uFF08\u9ED8\u8BA4 left\uFF09\n * @returns \u586B\u5145\u540E\u7684\u5B57\u7B26\u4E32\n */\nexport function pad(\n str: string,\n length: number,\n padChar: string = ' ',\n align: 'left' | 'right' | 'center' = 'left'\n): string {\n if (str.length >= length) {\n return str;\n }\n\n const padLength = length - str.length;\n\n switch (align) {\n case 'right':\n return padChar.repeat(padLength) + str;\n case 'center': {\n const leftPad = Math.floor(padLength / 2);\n const rightPad = padLength - leftPad;\n return padChar.repeat(leftPad) + str + padChar.repeat(rightPad);\n }\n case 'left':\n default:\n return str + padChar.repeat(padLength);\n }\n}\n\n/**\n * \u683C\u5F0F\u5316\u8868\u683C\u884C\uFF08\u7528\u4E8E\u63A7\u5236\u53F0\u8F93\u51FA\uFF09\n * @param columns \u5217\u6570\u636E\n * @param widths \u5217\u5BBD\u5EA6\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u884C\u5B57\u7B26\u4E32\n */\nexport function formatTableRow(columns: string[], widths: number[]): string {\n return columns.map((col, i) => pad(truncate(col, widths[i]), widths[i])).join(' \u2502 ');\n}\n\n/**\n * \u683C\u5F0F\u5316\u767E\u5206\u6BD4\n * @param value \u6570\u503C\uFF080-1 \u6216 0-100\uFF09\n * @param total \u603B\u6570\uFF08\u53EF\u9009\uFF09\n * @param decimals \u5C0F\u6570\u4F4D\u6570\uFF08\u9ED8\u8BA4 1\uFF09\n * @returns \u683C\u5F0F\u5316\u540E\u7684\u767E\u5206\u6BD4\u5B57\u7B26\u4E32\n */\nexport function formatPercentage(value: number, total?: number, decimals: number = 1): string {\n let percent: number;\n\n if (total !== undefined && total > 0) {\n percent = (value / total) * 100;\n } else if (value > 0 && value <= 1) {\n percent = value * 100;\n } else {\n percent = value;\n }\n\n return `${percent.toFixed(decimals)}%`;\n}\n", "import React, { useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\n\ntype ToastType = 'success' | 'error' | 'warning' | 'info';\n\nconst TOAST_ICONS: Record<ToastType, string> = {\n success: '\\u2713',\n error: '\\u2717',\n warning: '!',\n info: '\\u2139',\n};\n\nconst TOAST_COLORS: Record<ToastType, string> = {\n success: 'success',\n error: 'error',\n warning: 'warning',\n info: 'info',\n};\n\ninterface ToastProps {\n type: ToastType;\n message: string;\n duration?: number;\n onDismiss?: () => void;\n}\n\nexport function Toast({ type, message, duration = 3000, onDismiss }: ToastProps) {\n const { theme } = useTheme();\n\n useEffect(() => {\n if (onDismiss && duration > 0) {\n const timer = setTimeout(onDismiss, duration);\n return () => clearTimeout(timer);\n }\n }, [duration, onDismiss]);\n\n const color = (theme as unknown as Record<string, string>)[TOAST_COLORS[type]] ?? theme.text;\n\n return (\n <Box>\n <Text color={color} bold>\n {TOAST_ICONS[type]}\n </Text>\n <Text color={color}> {message}</Text>\n </Box>\n );\n}\n", "import React, { useState, useMemo } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport Fuse from 'fuse.js';\nimport { useTheme } from './design-system/ThemeProvider.js';\n\nexport interface CommandItem {\n label: string;\n value: string;\n icon?: string;\n category?: string;\n}\n\ninterface CommandPaletteProps {\n items: CommandItem[];\n onSelect: (value: string) => void;\n onCancel: () => void;\n}\n\nexport function CommandPalette({ items, onSelect, onCancel }: CommandPaletteProps) {\n const { theme } = useTheme();\n const [query, setQuery] = useState('');\n const [selectedIdx, setSelectedIdx] = useState(0);\n\n const fuse = useMemo(\n () => new Fuse(items, { keys: ['label', 'category'], threshold: 0.4 }),\n [items]\n );\n\n const results = useMemo(() => {\n if (!query) return items;\n return fuse.search(query).map((r) => r.item);\n }, [query, fuse, items]);\n\n const visibleCount = Math.min(8, results.length);\n\n useInput((input, key) => {\n if (key.escape) {\n onCancel();\n } else if (key.return) {\n const item = results[selectedIdx];\n if (item) onSelect(item.value);\n } else if (key.upArrow || (key.ctrl && input === 'p')) {\n setSelectedIdx((prev) => (prev > 0 ? prev - 1 : results.length - 1));\n } else if (key.downArrow || (key.ctrl && input === 'n')) {\n setSelectedIdx((prev) => (prev < results.length - 1 ? prev + 1 : 0));\n } else if (key.backspace || key.delete) {\n setQuery((prev) => prev.slice(0, -1));\n setSelectedIdx(0);\n } else if (input && !key.ctrl && !key.meta) {\n setQuery((prev) => prev + input);\n setSelectedIdx(0);\n }\n });\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.primary}\n paddingX={1}\n paddingY={0}\n >\n {/* Search input */}\n <Box>\n <Text color={theme.primary} bold>\n {'/ '}\n </Text>\n <Text color={theme.text}>{query}</Text>\n <Text color={theme.primary}>{'\\u2588'}</Text>\n </Box>\n\n {/* Results */}\n {results.slice(0, visibleCount).map((item, i) => {\n const isSelected = i === selectedIdx;\n return (\n <Box key={item.value}>\n <Text color={isSelected ? theme.primary : theme.subtle}>\n {isSelected ? '\\u276f ' : ' '}\n </Text>\n {item.icon && <Text>{item.icon} </Text>}\n <Text color={isSelected ? theme.primary : theme.text} bold={isSelected}>\n {item.label}\n </Text>\n {item.category && <Text color={theme.subtle}> [{item.category}]</Text>}\n </Box>\n );\n })}\n\n {results.length === 0 && <Text color={theme.inactive}>No matches</Text>}\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box } from 'ink';\nimport { Select, type SelectOption } from '../components/Select.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useI18n } from '../contexts/I18nContext.js';\nimport { useNotification } from '../contexts/NotificationContext.js';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { Spinner } from '../components/Spinner.js';\nimport { Confirm } from '../components/Confirm.js';\n\ntype MenuAction = string;\n\nexport function MainMenu() {\n const { navigate } = useNavigation();\n const { t, toggleLanguage, language } = useI18n();\n const { notify } = useNotification();\n const { systemdManager } = useServices();\n const [operating, setOperating] = React.useState(false);\n const [confirmAction, setConfirmAction] = React.useState<'stop' | 'restart' | null>(null);\n\n const langHint = language === 'en' ? 'EN / \\u4e2d\\u6587' : '\\u4e2d\\u6587 / EN';\n\n const items: SelectOption<MenuAction>[] = [\n { label: t.menu.viewStatus, value: 'service-status', hint: t.hints.viewDetails },\n { label: t.menu.startService, value: 'service-start' },\n { label: t.menu.stopService, value: 'service-stop' },\n { label: t.menu.restartService, value: 'service-restart' },\n { separator: true },\n { label: t.menu.onlineUsers, value: 'online-users', hint: t.hints.liveConnections },\n { label: t.menu.userManagement, value: 'user-management', hint: t.hints.addDeleteShare },\n { label: t.menu.quotaManagement, value: 'quota-management', hint: t.hints.limitsUsage },\n { label: t.menu.subscriptions, value: 'subscriptions', hint: t.hints.subLinkServer },\n { separator: true },\n { label: t.menu.configManagement, value: 'config-management', hint: t.hints.backupRestore },\n { label: t.menu.viewLogs, value: 'log-viewer', hint: t.hints.accessError },\n { separator: true },\n { label: t.menu.switchLanguage, value: 'switch-language', hint: langHint },\n { label: t.menu.exit, value: 'exit', hint: 'q' },\n ];\n\n const executeAction = async (action: 'start' | 'stop' | 'restart') => {\n setConfirmAction(null);\n setOperating(true);\n try {\n if (action === 'start') await systemdManager.start();\n else if (action === 'stop') await systemdManager.stop();\n else await systemdManager.restart();\n notify('success', `Service ${action}ed`);\n } catch (e) {\n notify('error', `${(e as Error).message}`);\n }\n setOperating(false);\n };\n\n const handleSelect = async (value: MenuAction) => {\n switch (value) {\n case 'service-status':\n navigate({ screen: 'service-status' });\n break;\n case 'service-start':\n executeAction('start');\n break;\n case 'service-stop':\n setConfirmAction('stop');\n break;\n case 'service-restart':\n setConfirmAction('restart');\n break;\n case 'online-users':\n navigate({ screen: 'online-users' });\n break;\n case 'user-management':\n navigate({ screen: 'user-management' });\n break;\n case 'quota-management':\n navigate({ screen: 'quota-management' });\n break;\n case 'subscriptions':\n navigate({ screen: 'subscriptions' });\n break;\n case 'config-management':\n navigate({ screen: 'config-management' });\n break;\n case 'log-viewer':\n navigate({ screen: 'log-viewer' });\n break;\n case 'switch-language':\n toggleLanguage();\n break;\n case 'exit':\n process.exit(0);\n }\n };\n\n if (confirmAction) {\n return (\n <Box paddingX={2}>\n <Confirm\n message={confirmAction === 'stop' ? t.ui.confirmStop : t.ui.confirmRestart}\n onConfirm={() => executeAction(confirmAction)}\n onCancel={() => setConfirmAction(null)}\n destructive\n />\n </Box>\n );\n }\n\n if (operating) {\n return (\n <Box paddingX={2}>\n <Spinner message={t.ui.processing} />\n </Box>\n );\n }\n\n return <Select items={items} onSelect={handleSelect} visibleCount={20} />;\n}\n", "import React, { useState, useCallback } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\n\nexport interface SelectItem<T = string> {\n label: string;\n value: T;\n description?: string;\n hint?: string;\n disabled?: boolean;\n}\n\nexport interface SelectSeparator {\n separator: true;\n label?: string;\n}\n\nexport type SelectOption<T = string> = SelectItem<T> | SelectSeparator;\n\nfunction isSeparator<T>(opt: SelectOption<T>): opt is SelectSeparator {\n return 'separator' in opt && opt.separator === true;\n}\n\ninterface SelectProps<T = string> {\n items: SelectOption<T>[];\n onSelect: (value: T) => void;\n onCancel?: () => void;\n title?: string;\n visibleCount?: number;\n isFocused?: boolean;\n}\n\nexport function Select<T = string>({\n items,\n onSelect,\n onCancel,\n title,\n visibleCount = 14,\n isFocused = true,\n}: SelectProps<T>) {\n const { theme } = useTheme();\n const selectableIndices = items\n .map((item, i) => ({ item, i }))\n .filter(({ item }) => !isSeparator(item) && !(item as SelectItem<T>).disabled)\n .map(({ i }) => i);\n\n const [focusedIdx, setFocusedIdx] = useState(0);\n const [scrollOffset, setScrollOffset] = useState(0);\n\n const currentIndex = selectableIndices[focusedIdx] ?? 0;\n\n const navigate = useCallback(\n (direction: 1 | -1) => {\n setFocusedIdx((prev) => {\n const next = prev + direction;\n if (next < 0) return selectableIndices.length - 1;\n if (next >= selectableIndices.length) return 0;\n return next;\n });\n },\n [selectableIndices.length]\n );\n\n useInput(\n (input, key) => {\n if (key.upArrow || input === 'k') navigate(-1);\n else if (key.downArrow || input === 'j') navigate(1);\n else if (key.return) {\n const item = items[currentIndex];\n if (item && !isSeparator(item) && !item.disabled) onSelect(item.value);\n } else if (key.escape && onCancel) onCancel();\n },\n { isActive: isFocused }\n );\n\n // Scroll tracking\n const effectiveOffset = (() => {\n let off = scrollOffset;\n if (currentIndex < off) off = currentIndex;\n if (currentIndex >= off + visibleCount) off = currentIndex - visibleCount + 1;\n if (off !== scrollOffset) setScrollOffset(off);\n return off;\n })();\n\n const visibleItems = items.slice(effectiveOffset, effectiveOffset + visibleCount);\n const hasMore = effectiveOffset + visibleCount < items.length;\n const hasLess = effectiveOffset > 0;\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n {title && (\n <Box marginBottom={1}>\n <Text dimColor>{title}</Text>\n </Box>\n )}\n\n {hasLess && <Text dimColor> {'...'}</Text>}\n\n {visibleItems.map((item, vi) => {\n const realIdx = vi + effectiveOffset;\n\n if (isSeparator(item)) {\n return (\n <Box key={`sep-${realIdx}`} marginY={0}>\n <Text dimColor> {'\u2500'.repeat(30)}</Text>\n </Box>\n );\n }\n\n const isActive = realIdx === currentIndex;\n const si = item as SelectItem<T>;\n\n return (\n <Box key={`i-${realIdx}`}>\n <Text color={isActive ? theme.primary : undefined}>\n {isActive ? ' \\u276f ' : ' '}\n </Text>\n <Text\n color={si.disabled ? theme.inactive : isActive ? theme.primary : undefined}\n bold={isActive}\n dimColor={si.disabled}\n >\n {si.label}\n </Text>\n {si.hint && <Text dimColor> {si.hint}</Text>}\n </Box>\n );\n })}\n\n {hasMore && <Text dimColor> {'...'}</Text>}\n </Box>\n );\n}\n", "import React, { useState, useEffect } from 'react';\nimport { Text } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\nimport { resolveColor } from './design-system/theme.js';\n\nconst FRAMES = [\n '\\u280b',\n '\\u2819',\n '\\u2839',\n '\\u2838',\n '\\u283c',\n '\\u2834',\n '\\u2826',\n '\\u2827',\n '\\u2807',\n '\\u280f',\n];\n\ninterface SpinnerProps {\n message?: string;\n color?: string;\n}\n\nexport function Spinner({ message, color = 'primary' }: SpinnerProps) {\n const { theme } = useTheme();\n const [frame, setFrame] = useState(0);\n\n useEffect(() => {\n const timer = setInterval(() => {\n setFrame((prev) => (prev + 1) % FRAMES.length);\n }, 80);\n return () => clearInterval(timer);\n }, []);\n\n const resolvedColor = resolveColor(color, theme)!;\n\n return (\n <Text>\n <Text color={resolvedColor}>{FRAMES[frame]}</Text>\n {message && <Text color={theme.text}> {message}</Text>}\n </Text>\n );\n}\n", "import React from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\n\ninterface ConfirmProps {\n message: string;\n onConfirm: () => void;\n onCancel: () => void;\n defaultValue?: boolean;\n destructive?: boolean;\n isFocused?: boolean;\n}\n\nexport function Confirm({\n message,\n onConfirm,\n onCancel,\n defaultValue = false,\n destructive = false,\n isFocused = true,\n}: ConfirmProps) {\n const { theme } = useTheme();\n const color = destructive ? theme.error : theme.warning;\n const hint = defaultValue ? '[Y/n]' : '[y/N]';\n\n useInput(\n (input, key) => {\n if (input === 'y' || input === 'Y') {\n onConfirm();\n } else if (input === 'n' || input === 'N' || key.escape) {\n onCancel();\n } else if (key.return) {\n if (defaultValue) onConfirm();\n else onCancel();\n }\n },\n { isActive: isFocused }\n );\n\n return (\n <Box>\n <Text color={color} bold>\n {'? '}\n </Text>\n <Text color={theme.text}>{message} </Text>\n <Text color={theme.inactive}>{hint}</Text>\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box, Text } from 'ink';\nimport { useServiceStatus } from '../hooks/useServiceStatus.js';\nimport { StatusBadge } from '../components/StatusBadge.js';\nimport { KeyValue } from '../components/KeyValue.js';\nimport { Spinner } from '../components/Spinner.js';\n\nexport function ServiceStatus() {\n const { status, loading } = useServiceStatus(2000);\n\n if (loading) {\n return (\n <Box paddingX={2}>\n <Spinner message=\"Fetching service status...\" />\n </Box>\n );\n }\n\n if (!status) {\n return (\n <Box paddingX={2}>\n <Text color=\"red\">Failed to retrieve service status</Text>\n </Box>\n );\n }\n\n const labelW = 14;\n\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n <Box flexDirection=\"column\">\n <KeyValue\n label=\"Status\"\n labelWidth={labelW}\n value={\n <StatusBadge\n status={status.healthy ? 'running' : status.active ? 'warning' : 'stopped'}\n label={status.healthy ? 'Running' : status.active ? status.subState : 'Stopped'}\n />\n }\n />\n <KeyValue label=\"Active State\" labelWidth={labelW} value={status.activeState} />\n <KeyValue label=\"Sub State\" labelWidth={labelW} value={status.subState} />\n <KeyValue label=\"Loaded\" labelWidth={labelW} value={status.loaded ? 'Yes' : 'No'} />\n {status.pid && <KeyValue label=\"PID\" labelWidth={labelW} value={String(status.pid)} />}\n {status.uptime && <KeyValue label=\"Uptime\" labelWidth={labelW} value={status.uptime} />}\n {status.memory && <KeyValue label=\"Memory\" labelWidth={labelW} value={status.memory} />}\n </Box>\n\n <Text dimColor italic>\n Auto-refreshing every 2s\n </Text>\n </Box>\n );\n}\n", "import { useState, useEffect, useCallback } from 'react';\nimport { useServices } from '../contexts/ServiceContext.js';\n\ninterface ServiceStatusData {\n active: boolean;\n activeState: string;\n subState: string;\n loaded: boolean;\n healthy: boolean;\n pid?: number;\n uptime?: string;\n memory?: string;\n}\n\nexport function useServiceStatus(pollInterval = 5000) {\n const { systemdManager } = useServices();\n const [status, setStatus] = useState<ServiceStatusData | null>(null);\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n try {\n const s = await systemdManager.getStatus();\n setStatus({\n active: s.active,\n activeState: s.activeState,\n subState: s.subState,\n loaded: s.loaded,\n healthy: s.healthy,\n pid: s.pid ?? undefined,\n uptime: s.uptime,\n memory: s.memory,\n });\n } catch {\n setStatus(null);\n } finally {\n setLoading(false);\n }\n }, [systemdManager]);\n\n useEffect(() => {\n refresh();\n const timer = setInterval(refresh, pollInterval);\n return () => clearInterval(timer);\n }, [refresh, pollInterval]);\n\n return { status, loading, refresh };\n}\n", "import React from 'react';\nimport { Text } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\nimport { resolveColor } from './design-system/theme.js';\n\ntype BadgeStatus =\n | 'running'\n | 'stopped'\n | 'error'\n | 'warning'\n | 'loading'\n | 'disabled'\n | 'ok'\n | 'exceeded';\n\nconst STATUS_CONFIG: Record<BadgeStatus, { icon: string; themeKey: string; label: string }> = {\n running: { icon: '\\u25cf', themeKey: 'serviceRunning', label: 'Running' },\n stopped: { icon: '\\u25cf', themeKey: 'serviceStopped', label: 'Stopped' },\n error: { icon: '\\u25cf', themeKey: 'error', label: 'Error' },\n warning: { icon: '\\u25cf', themeKey: 'warning', label: 'Warning' },\n loading: { icon: '\\u25cb', themeKey: 'inactive', label: 'Loading' },\n disabled: { icon: '\\u25cf', themeKey: 'inactive', label: 'Disabled' },\n ok: { icon: '\\u25cf', themeKey: 'success', label: 'OK' },\n exceeded: { icon: '\\u25cf', themeKey: 'quotaExceeded', label: 'Exceeded' },\n};\n\ninterface StatusBadgeProps {\n status: BadgeStatus;\n label?: string;\n}\n\nexport function StatusBadge({ status, label }: StatusBadgeProps) {\n const { theme } = useTheme();\n const config = STATUS_CONFIG[status];\n const color = resolveColor(config.themeKey, theme);\n\n return (\n <Text>\n <Text color={color}>{config.icon}</Text>\n <Text> </Text>\n <Text color={color}>{label ?? config.label}</Text>\n </Text>\n );\n}\n", "import React from 'react';\nimport { Box, Text } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\n\ninterface KeyValueProps {\n label: string;\n value: React.ReactNode;\n labelWidth?: number;\n}\n\nexport function KeyValue({ label, value, labelWidth }: KeyValueProps) {\n const { theme } = useTheme();\n\n return (\n <Box>\n <Box width={labelWidth}>\n <Text color={theme.inactive}>{label}:</Text>\n </Box>\n <Text> </Text>\n {typeof value === 'string' ? <Text color={theme.text}>{value}</Text> : value}\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from '../components/design-system/ThemeProvider.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useI18n } from '../contexts/I18nContext.js';\nimport { useUsers } from '../hooks/useUsers.js';\nimport { Table, type Column } from '../components/Table.js';\nimport { StatusBadge } from '../components/StatusBadge.js';\nimport { Spinner } from '../components/Spinner.js';\n\nexport function UserManagement() {\n const { theme } = useTheme();\n const { navigate } = useNavigation();\n const { t } = useI18n();\n const { users, loading } = useUsers();\n\n useInput((input) => {\n if (input === 'a') navigate({ screen: 'user-add' });\n else if (input === 'd') navigate({ screen: 'user-delete' });\n else if (input === 's') navigate({ screen: 'user-share' });\n });\n\n const columns: Column<Record<string, unknown>>[] = [\n { key: 'email', header: t.ui.email, width: 20 },\n {\n key: 'id',\n header: t.ui.uuid,\n width: 14,\n render: (row) => <Text dimColor>{String(row.id ?? '').slice(0, 8)}...</Text>,\n },\n {\n key: 'expiry',\n header: t.ui.expiry,\n width: 12,\n render: (row) => {\n const expiry = row.expiryDate as string | undefined;\n if (!expiry) return <Text dimColor>-</Text>;\n const days = Math.ceil((new Date(expiry).getTime() - Date.now()) / 86400000);\n if (days <= 0)\n return (\n <Text color={theme.error} bold>\n {t.ui.expired}\n </Text>\n );\n if (days <= 3)\n return (\n <Text color={theme.warning}>\n {days}\n {t.ui.daysLeft}\n </Text>\n );\n return (\n <Text>\n {days}\n {t.ui.daysLeft}\n </Text>\n );\n },\n },\n {\n key: 'status',\n header: t.status.serviceStatus.split(' ')[0] ?? 'Status',\n width: 10,\n render: (row) => {\n const s = (row.status as string) ?? 'active';\n return (\n <StatusBadge\n status={s === 'exceeded' ? 'exceeded' : s === 'disabled' ? 'disabled' : 'ok'}\n />\n );\n },\n },\n ];\n\n const tableData = users.map((u) => ({\n email: u.email ?? u.id?.slice(0, 8) ?? '?',\n id: u.id ?? '',\n status: u.status ?? 'active',\n expiryDate: u.expiryDate,\n }));\n\n if (loading) {\n return (\n <Box paddingX={2}>\n <Spinner message={t.ui.processing} />\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n <Table\n columns={columns}\n data={tableData}\n onSelect={(row) => navigate({ screen: 'user-share', userId: row.id as string })}\n emptyMessage={t.ui.noUsers}\n />\n\n <Text dimColor>\n {users.length} {t.ui.users} <Text bold>a</Text> {t.ui.add} <Text bold>d</Text>{' '}\n {t.ui.delete_} <Text bold>s</Text> {t.ui.share} <Text bold>enter</Text> {t.ui.details}\n </Text>\n </Box>\n );\n}\n", "import { useState, useEffect, useCallback } from 'react';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { type User } from '../types/user.js';\n\nexport function useUsers() {\n const { userManager } = useServices();\n const [users, setUsers] = useState<User[]>([]);\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n try {\n setLoading(true);\n const list = await userManager.listUsers();\n setUsers(list);\n } catch {\n setUsers([]);\n } finally {\n setLoading(false);\n }\n }, [userManager]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n return { users, loading, refresh };\n}\n", "import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\n\nexport interface Column<T> {\n key: string;\n header: string;\n width?: number;\n align?: 'left' | 'right' | 'center';\n render?: (row: T) => React.ReactNode;\n}\n\ninterface TableProps<T> {\n columns: Column<T>[];\n data: T[];\n maxRows?: number;\n onSelect?: (row: T, index: number) => void;\n emptyMessage?: string;\n isFocused?: boolean;\n}\n\nfunction padStr(str: string, width: number, align: 'left' | 'right' | 'center' = 'left'): string {\n const len = str.length;\n if (len >= width) return str.slice(0, width);\n const diff = width - len;\n if (align === 'right') return ' '.repeat(diff) + str;\n if (align === 'center') {\n const left = Math.floor(diff / 2);\n return ' '.repeat(left) + str + ' '.repeat(diff - left);\n }\n return str + ' '.repeat(diff);\n}\n\nexport function Table<T extends Record<string, unknown>>({\n columns,\n data,\n maxRows = 15,\n onSelect,\n emptyMessage = 'No data',\n isFocused = true,\n}: TableProps<T>) {\n const { theme } = useTheme();\n const [selectedIdx, setSelectedIdx] = useState(0);\n const [scrollOffset, setScrollOffset] = useState(0);\n\n const termWidth = process.stdout.columns || 80;\n const defaultColWidth = Math.max(\n 8,\n Math.floor((termWidth - columns.length * 3) / columns.length)\n );\n\n useInput(\n (input, key) => {\n if (key.upArrow || input === 'k') {\n setSelectedIdx((prev) => {\n const next = Math.max(0, prev - 1);\n if (next < scrollOffset) setScrollOffset(next);\n return next;\n });\n } else if (key.downArrow || input === 'j') {\n setSelectedIdx((prev) => {\n const next = Math.min(data.length - 1, prev + 1);\n if (next >= scrollOffset + maxRows) setScrollOffset(next - maxRows + 1);\n return next;\n });\n } else if (key.return && onSelect && data[selectedIdx]) {\n onSelect(data[selectedIdx]!, selectedIdx);\n }\n },\n { isActive: isFocused && data.length > 0 }\n );\n\n if (data.length === 0) {\n return (\n <Box>\n <Text color={theme.inactive}>{emptyMessage}</Text>\n </Box>\n );\n }\n\n const visibleData = data.slice(scrollOffset, scrollOffset + maxRows);\n\n return (\n <Box flexDirection=\"column\">\n {/* Header */}\n <Box>\n <Text color={theme.subtle}>{' '}</Text>\n {columns.map((col, ci) => (\n <Box key={col.key} width={col.width ?? defaultColWidth}>\n <Text color={theme.inactive} bold>\n {padStr(col.header, (col.width ?? defaultColWidth) - 2, col.align)}\n </Text>\n {ci < columns.length - 1 && <Text color={theme.border}>{' \\u2502 '}</Text>}\n </Box>\n ))}\n </Box>\n\n {/* Separator */}\n <Box>\n <Text color={theme.border}>\n {' '}\n {columns\n .map((col) => '\\u2500'.repeat((col.width ?? defaultColWidth) - 1))\n .join('\\u2500\\u253c\\u2500')}\n </Text>\n </Box>\n\n {/* Rows */}\n {visibleData.map((row, vi) => {\n const realIdx = vi + scrollOffset;\n const isSelected = realIdx === selectedIdx;\n\n return (\n <Box key={vi}>\n <Text color={isSelected ? theme.primary : theme.subtle}>\n {isSelected ? '\\u276f ' : ' '}\n </Text>\n {columns.map((col, ci) => {\n const cellContent = col.render ? col.render(row) : String(row[col.key] ?? '');\n const w = col.width ?? defaultColWidth;\n\n return (\n <Box key={col.key} width={w}>\n {typeof cellContent === 'string' ? (\n <Text color={isSelected ? theme.text : theme.text}>\n {padStr(cellContent, w - 2, col.align)}\n </Text>\n ) : (\n cellContent\n )}\n {ci < columns.length - 1 && <Text color={theme.border}>{' \\u2502 '}</Text>}\n </Box>\n );\n })}\n </Box>\n );\n })}\n\n {/* Footer info */}\n {data.length > maxRows && (\n <Box marginTop={1}>\n <Text color={theme.subtle}>\n Showing {scrollOffset + 1}-{Math.min(scrollOffset + maxRows, data.length)} of{' '}\n {data.length}\n </Text>\n </Box>\n )}\n </Box>\n );\n}\n", "import React, { useState } from 'react';\nimport { Box, Text } from 'ink';\nimport { useTheme } from '../components/design-system/ThemeProvider.js';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useNotification } from '../contexts/NotificationContext.js';\nimport { useI18n } from '../contexts/I18nContext.js';\nimport { TextInput } from '../components/TextInput.js';\nimport { Spinner } from '../components/Spinner.js';\n\nexport function UserAdd() {\n const { theme } = useTheme();\n const { userManager } = useServices();\n const { goBack } = useNavigation();\n const { notify } = useNotification();\n const { t } = useI18n();\n const [phase, setPhase] = useState<'email' | 'expiry' | 'adding'>('email');\n const [email, setEmail] = useState('');\n const [result, setResult] = useState<{ email: string; id: string; expiryDate?: string } | null>(\n null\n );\n\n const handleEmailSubmit = (value: string) => {\n if (!value.trim()) return;\n setEmail(value.trim());\n setPhase('expiry');\n };\n\n const handleExpirySubmit = async (daysStr: string) => {\n setPhase('adding');\n const days = daysStr.trim() ? parseInt(daysStr.trim(), 10) : undefined;\n try {\n const user = await userManager.addUser({\n email,\n expiryDays: days && days > 0 ? days : undefined,\n });\n setResult({ email: user.email ?? email, id: user.id, expiryDate: user.expiryDate });\n notify('success', t.ui.userCreated);\n } catch (e) {\n notify('error', (e as Error).message);\n setPhase('email');\n }\n };\n\n if (result) {\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n <Text color={theme.success} bold>\n {'\\u2713'} {t.ui.userCreated}\n </Text>\n <Box flexDirection=\"column\">\n <Text dimColor>\n {t.ui.email}: <Text color={theme.text}>{result.email}</Text>\n </Text>\n <Text dimColor>\n {t.ui.uuid}: <Text color={theme.text}>{result.id}</Text>\n </Text>\n <Text dimColor>\n {t.ui.expiry}:{' '}\n <Text color={theme.text}>\n {result.expiryDate ? new Date(result.expiryDate).toLocaleDateString() : t.ui.never}\n </Text>\n </Text>\n </Box>\n <Text dimColor italic>\n {t.ui.pressEscBack}\n </Text>\n </Box>\n );\n }\n\n if (phase === 'adding') {\n return (\n <Box paddingX={2}>\n <Spinner message={t.ui.processing} />\n </Box>\n );\n }\n\n if (phase === 'expiry') {\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n <Text dimColor>\n {t.ui.email}: {email}\n </Text>\n <TextInput\n label={t.ui.expiryDaysPrompt}\n placeholder=\"30\"\n onSubmit={handleExpirySubmit}\n onCancel={() => setPhase('email')}\n validator={(v) => {\n if (v.trim() && (isNaN(Number(v)) || Number(v) < 0)) return 'Invalid number';\n return null;\n }}\n />\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <TextInput\n label={t.ui.emailPrompt}\n placeholder=\"user@example.com\"\n onSubmit={handleEmailSubmit}\n onCancel={goBack}\n validator={(v) => {\n if (!v.includes('@')) return 'Invalid email';\n return null;\n }}\n />\n </Box>\n );\n}\n", "import React, { useState } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\n\ninterface TextInputProps {\n label?: string;\n placeholder?: string;\n value?: string;\n onChange?: (value: string) => void;\n onSubmit: (value: string) => void;\n onCancel?: () => void;\n mask?: string;\n validator?: (value: string) => string | null;\n isFocused?: boolean;\n}\n\nexport function TextInput({\n label,\n placeholder,\n value: controlledValue,\n onChange,\n onSubmit,\n onCancel,\n mask,\n validator,\n isFocused = true,\n}: TextInputProps) {\n const { theme } = useTheme();\n const [internalValue, setInternalValue] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [cursorVisible, setCursorVisible] = useState(true);\n\n const value = controlledValue ?? internalValue;\n const setValue = (v: string) => {\n if (onChange) onChange(v);\n else setInternalValue(v);\n if (error) setError(null);\n };\n\n // Cursor blink\n React.useEffect(() => {\n const timer = setInterval(() => setCursorVisible((v) => !v), 530);\n return () => clearInterval(timer);\n }, []);\n\n useInput(\n (input, key) => {\n if (key.return) {\n if (validator) {\n const err = validator(value);\n if (err) {\n setError(err);\n return;\n }\n }\n onSubmit(value);\n } else if (key.escape && onCancel) {\n onCancel();\n } else if (key.backspace || key.delete) {\n setValue(value.slice(0, -1));\n } else if (input && !key.ctrl && !key.meta) {\n setValue(value + input);\n }\n },\n { isActive: isFocused }\n );\n\n const displayValue = mask ? mask.repeat(value.length) : value;\n const cursor = cursorVisible ? '\\u2588' : ' ';\n\n return (\n <Box flexDirection=\"column\">\n <Box>\n {label && (\n <Text color={theme.primary} bold>\n {label}{' '}\n </Text>\n )}\n <Text color={theme.text}>\n {displayValue}\n <Text color={theme.primary}>{cursor}</Text>\n </Text>\n {!value && placeholder && <Text color={theme.subtle}>{placeholder}</Text>}\n </Box>\n {error && <Text color={theme.error}> {error}</Text>}\n </Box>\n );\n}\n", "import React, { useState } from 'react';\nimport { Box, Text } from 'ink';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useNotification } from '../contexts/NotificationContext.js';\nimport { useI18n } from '../contexts/I18nContext.js';\nimport { useUsers } from '../hooks/useUsers.js';\nimport { Select, type SelectItem } from '../components/Select.js';\nimport { Confirm } from '../components/Confirm.js';\nimport { Spinner } from '../components/Spinner.js';\n\ntype Phase = 'select' | 'confirm' | 'deleting';\n\nexport function UserDelete() {\n const { userManager } = useServices();\n const { goBack } = useNavigation();\n const { notify } = useNotification();\n const { t } = useI18n();\n const { users, loading } = useUsers();\n const [phase, setPhase] = useState<Phase>('select');\n const [selectedUser, setSelectedUser] = useState<{ id: string; email: string } | null>(null);\n\n const handleUserSelect = (userId: string) => {\n const user = users.find((u) => u.id === userId);\n if (user) {\n setSelectedUser({ id: user.id, email: user.email ?? user.id.slice(0, 8) });\n setPhase('confirm');\n }\n };\n\n const handleConfirm = async () => {\n if (!selectedUser) return;\n setPhase('deleting');\n try {\n await userManager.deleteUser(selectedUser.id);\n notify('success', `${selectedUser.email} deleted`);\n goBack();\n } catch (e) {\n notify('error', (e as Error).message);\n setPhase('select');\n }\n };\n\n if (loading)\n return (\n <Box paddingX={2}>\n <Spinner message={t.ui.processing} />\n </Box>\n );\n if (users.length === 0)\n return (\n <Box paddingX={2}>\n <Text dimColor>{t.ui.noUsers}</Text>\n </Box>\n );\n if (phase === 'deleting')\n return (\n <Box paddingX={2}>\n <Spinner message={t.ui.processing} />\n </Box>\n );\n\n if (phase === 'confirm' && selectedUser) {\n return (\n <Box paddingX={2}>\n <Confirm\n message={`${t.ui.delete_} ${selectedUser.email}?`}\n onConfirm={handleConfirm}\n onCancel={() => setPhase('select')}\n destructive\n />\n </Box>\n );\n }\n\n const items: SelectItem<string>[] = users.map((u) => ({\n label: u.email ?? u.id.slice(0, 8),\n value: u.id,\n hint: u.id.slice(0, 8),\n }));\n\n return (\n <Select items={items} onSelect={handleUserSelect} onCancel={goBack} title={t.ui.selectUser} />\n );\n}\n", "import React, { useState, useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport { useTheme } from '../components/design-system/ThemeProvider.js';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useNotification } from '../contexts/NotificationContext.js';\nimport { useUsers } from '../hooks/useUsers.js';\nimport { Select, type SelectItem } from '../components/Select.js';\nimport { Spinner } from '../components/Spinner.js';\nimport { type Route } from '../app/routes.js';\n\nexport function UserShare() {\n const { theme } = useTheme();\n const { userManager } = useServices();\n const { goBack, currentRoute } = useNavigation();\n const { notify } = useNotification();\n const { users, loading: usersLoading } = useUsers();\n const [selectedUserId, setSelectedUserId] = useState<string | null>(\n (currentRoute as Extract<Route, { screen: 'user-share' }>).userId ?? null\n );\n const [shareInfo, setShareInfo] = useState<{ link: string; email: string } | null>(null);\n const [loadingShare, setLoadingShare] = useState(false);\n\n useEffect(() => {\n if (selectedUserId) {\n setLoadingShare(true);\n userManager\n .getShareInfo(selectedUserId)\n .then((info) => {\n setShareInfo({\n link: info.shareLink ?? 'No share link available',\n email: info.user?.email ?? selectedUserId.slice(0, 8),\n });\n })\n .catch((e) => {\n notify('error', `Failed: ${(e as Error).message}`);\n setShareInfo(null);\n })\n .finally(() => setLoadingShare(false));\n }\n }, [selectedUserId, userManager, notify]);\n\n if (usersLoading)\n return (\n <Box paddingX={2}>\n <Spinner message=\"Loading users...\" />\n </Box>\n );\n\n if (!selectedUserId) {\n const items: SelectItem<string>[] = users.map((u) => ({\n label: u.email ?? u.id.slice(0, 8),\n value: u.id,\n }));\n return (\n <Select items={items} onSelect={setSelectedUserId} onCancel={goBack} title=\"Select user:\" />\n );\n }\n\n if (loadingShare)\n return (\n <Box paddingX={2}>\n <Spinner message=\"Generating link...\" />\n </Box>\n );\n\n if (!shareInfo) {\n return (\n <Box paddingX={2}>\n <Text color={theme.error}>Failed to generate share link</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n <Text dimColor>\n User: <Text bold>{shareInfo.email}</Text>\n </Text>\n <Box borderStyle=\"single\" borderColor={theme.border} paddingX={1}>\n <Text wrap=\"wrap\">{shareInfo.link}</Text>\n </Box>\n <Text dimColor italic>\n Press esc to go back\n </Text>\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from '../components/design-system/ThemeProvider.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useI18n } from '../contexts/I18nContext.js';\nimport { useQuotas } from '../hooks/useQuotas.js';\nimport { Table, type Column } from '../components/Table.js';\nimport { ProgressBar } from '../components/ProgressBar.js';\nimport { StatusBadge } from '../components/StatusBadge.js';\nimport { Spinner } from '../components/Spinner.js';\nimport { formatBytes } from '../utils/format.js';\n\nexport function QuotaManagement() {\n const { theme } = useTheme();\n const { navigate } = useNavigation();\n const { t } = useI18n();\n const { quotas, loading } = useQuotas();\n\n useInput((input) => {\n if (input === 's') navigate({ screen: 'quota-set' });\n });\n\n const quotaEntries = Object.entries(quotas).map(([email, q]) => ({\n email,\n quota: q.quotaBytes > 0 ? formatBytes(q.quotaBytes) : t.ui.unlimited,\n used: formatBytes(q.usedBytes),\n ratio: q.quotaBytes > 0 ? q.usedBytes / q.quotaBytes : 0,\n status: q.status ?? 'active',\n quotaBytes: q.quotaBytes,\n }));\n\n const columns: Column<Record<string, unknown>>[] = [\n { key: 'email', header: t.ui.email, width: 18 },\n { key: 'quota', header: t.quota.title.split(' ')[0] ?? 'Quota', width: 12 },\n { key: 'used', header: t.quota.used, width: 12 },\n {\n key: 'progress',\n header: '',\n width: 20,\n render: (row) => {\n if ((row.quotaBytes as number) <= 0) return <Text dimColor>{'\\u2500'}</Text>;\n return <ProgressBar ratio={row.ratio as number} width={12} />;\n },\n },\n {\n key: 'status',\n header: '',\n width: 10,\n render: (row) => {\n const s = row.status as string;\n if (s === 'exceeded') return <StatusBadge status=\"exceeded\" />;\n if (s === 'disabled') return <StatusBadge status=\"disabled\" />;\n return <StatusBadge status=\"ok\" />;\n },\n },\n ];\n\n if (loading)\n return (\n <Box paddingX={2}>\n <Spinner message={t.ui.processing} />\n </Box>\n );\n\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n <Table\n columns={columns}\n data={quotaEntries}\n onSelect={(row) => navigate({ screen: 'quota-details', email: row.email as string })}\n emptyMessage={t.ui.noQuotas}\n />\n <Text dimColor>\n {quotaEntries.length} {t.ui.entries} <Text bold>s</Text> {t.ui.setQuota}{' '}\n <Text bold>enter</Text> {t.ui.details}\n </Text>\n </Box>\n );\n}\n", "import { useState, useEffect, useCallback } from 'react';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { type TrafficQuota } from '../types/quota.js';\nimport { DEFAULT_QUOTA } from '../types/quota.js';\n\nexport function useQuotas() {\n const { quotaManager, trafficManager } = useServices();\n const [quotas, setQuotas] = useState<Record<string, TrafficQuota>>({});\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n try {\n setLoading(true);\n const [stored, usages] = await Promise.all([\n quotaManager.getAllQuotas(),\n trafficManager.getAllUsage().catch(() => []),\n ]);\n\n const merged: Record<string, TrafficQuota> = { ...stored };\n for (const usage of usages) {\n const existing = merged[usage.email] ?? { ...DEFAULT_QUOTA };\n merged[usage.email] = {\n ...existing,\n usedBytes: usage.total,\n };\n }\n setQuotas(merged);\n } catch {\n setQuotas({});\n } finally {\n setLoading(false);\n }\n }, [quotaManager, trafficManager]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n return { quotas, loading, refresh };\n}\n", "import React from 'react';\nimport { Text } from 'ink';\nimport { useTheme } from './design-system/ThemeProvider.js';\nimport { resolveColor } from './design-system/theme.js';\n\ninterface ProgressBarProps {\n ratio: number;\n width?: number;\n showPercent?: boolean;\n thresholds?: { warning: number; error: number };\n}\n\nconst BLOCKS = [' ', '\\u2588'];\n\nexport function ProgressBar({\n ratio,\n width = 20,\n showPercent = true,\n thresholds = { warning: 0.8, error: 1.0 },\n}: ProgressBarProps) {\n const { theme } = useTheme();\n const clamped = Math.max(0, Math.min(ratio, 1.5));\n const filled = Math.round(Math.min(clamped, 1) * width);\n const empty = width - filled;\n const pct = Math.round(clamped * 100);\n\n let fillColorKey: string;\n if (clamped >= thresholds.error) {\n fillColorKey = 'quotaExceeded';\n } else if (clamped >= thresholds.warning) {\n fillColorKey = 'quotaWarning';\n } else {\n fillColorKey = 'quotaNormal';\n }\n\n const fillColor = resolveColor(fillColorKey, theme)!;\n const emptyColor = resolveColor('progressEmpty', theme)!;\n\n return (\n <Text>\n <Text color={fillColor}>{BLOCKS[1].repeat(filled)}</Text>\n <Text color={emptyColor}>{'\\u2591'.repeat(empty)}</Text>\n {showPercent && <Text color={fillColor}> {pct}%</Text>}\n </Text>\n );\n}\n", "import React, { useState } from 'react';\nimport { Box, Text } from 'ink';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useNotification } from '../contexts/NotificationContext.js';\nimport { useUsers } from '../hooks/useUsers.js';\nimport { Select, type SelectItem } from '../components/Select.js';\nimport { TextInput } from '../components/TextInput.js';\nimport { Spinner } from '../components/Spinner.js';\n\ntype Phase = 'select-user' | 'enter-quota' | 'setting';\n\nconst PRESETS: SelectItem<string>[] = [\n { label: '1 GB', value: '1073741824' },\n { label: '5 GB', value: '5368709120' },\n { label: '10 GB', value: '10737418240' },\n { label: '50 GB', value: '53687091200' },\n { label: '100 GB', value: '107374182400' },\n { label: 'Unlimited', value: '0' },\n { label: 'Custom...', value: 'custom' },\n];\n\nfunction parseQuota(input: string): number | null {\n const m = input.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(gb|mb|tb)?$/i);\n if (!m) return null;\n const n = parseFloat(m[1]!);\n const u = (m[2] ?? 'gb').toLowerCase();\n if (u === 'tb') return n * 1099511627776;\n if (u === 'gb') return n * 1073741824;\n if (u === 'mb') return n * 1048576;\n return n;\n}\n\nexport function QuotaSet() {\n const { quotaManager } = useServices();\n const { goBack } = useNavigation();\n const { notify } = useNotification();\n const { users, loading: usersLoading } = useUsers();\n const [phase, setPhase] = useState<Phase>('select-user');\n const [selectedEmail, setSelectedEmail] = useState('');\n const [customMode, setCustomMode] = useState(false);\n\n const applyQuota = async (bytes: number) => {\n setPhase('setting');\n try {\n await quotaManager.setQuota({\n email: selectedEmail,\n quotaBytes: bytes,\n quotaType: bytes > 0 ? 'limited' : 'unlimited',\n });\n notify('success', `Quota set for ${selectedEmail}`);\n goBack();\n } catch (e) {\n notify('error', `Failed: ${(e as Error).message}`);\n setPhase('enter-quota');\n }\n };\n\n if (usersLoading)\n return (\n <Box paddingX={2}>\n <Spinner message=\"Loading...\" />\n </Box>\n );\n if (phase === 'setting')\n return (\n <Box paddingX={2}>\n <Spinner message=\"Setting quota...\" />\n </Box>\n );\n\n if (phase === 'select-user') {\n const items: SelectItem<string>[] = users.map((u) => ({\n label: u.email ?? u.id.slice(0, 8),\n value: u.email ?? u.id,\n }));\n return (\n <Select\n items={items}\n onSelect={(e) => {\n setSelectedEmail(e);\n setPhase('enter-quota');\n }}\n onCancel={goBack}\n title=\"Select user:\"\n />\n );\n }\n\n if (customMode) {\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n <Text dimColor>\n User: <Text bold>{selectedEmail}</Text>\n </Text>\n <TextInput\n label=\"Quota (e.g. 10GB, 500MB):\"\n onSubmit={(val) => {\n const bytes = parseQuota(val);\n if (bytes !== null) applyQuota(bytes);\n }}\n onCancel={() => setCustomMode(false)}\n validator={(v) => (parseQuota(v) === null ? 'e.g. 10GB, 500MB, 1TB' : null)}\n />\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Box paddingX={2}>\n <Text dimColor>\n User: <Text bold>{selectedEmail}</Text>\n </Text>\n </Box>\n <Select\n items={PRESETS}\n onSelect={(v) => (v === 'custom' ? setCustomMode(true) : applyQuota(parseInt(v, 10)))}\n onCancel={goBack}\n title=\"Select quota:\"\n />\n </Box>\n );\n}\n", "import React, { useState, useEffect } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from '../components/design-system/ThemeProvider.js';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useNotification } from '../contexts/NotificationContext.js';\nimport { useI18n } from '../contexts/I18nContext.js';\nimport { KeyValue } from '../components/KeyValue.js';\nimport { ProgressBar } from '../components/ProgressBar.js';\nimport { StatusBadge } from '../components/StatusBadge.js';\nimport { Spinner } from '../components/Spinner.js';\nimport { Confirm } from '../components/Confirm.js';\nimport { formatBytes } from '../utils/format.js';\nimport { type Route } from '../app/routes.js';\nimport { type TrafficQuota } from '../types/quota.js';\n\nexport function QuotaDetails() {\n const { theme } = useTheme();\n const { quotaManager } = useServices();\n const { currentRoute } = useNavigation();\n const { notify } = useNotification();\n const { t } = useI18n();\n const email = (currentRoute as Extract<Route, { screen: 'quota-details' }>).email ?? '';\n const [quota, setQuota] = useState<TrafficQuota | null>(null);\n const [loading, setLoading] = useState(true);\n const [confirmAction, setConfirmAction] = useState<'reset' | 'reenable' | null>(null);\n\n const fetchQuota = async () => {\n try {\n setQuota(await quotaManager.getQuota(email));\n } catch {\n setQuota(null);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n fetchQuota();\n }, [email]);\n\n useInput((input) => {\n if (input === 'r') setConfirmAction('reset');\n else if (input === 'e') setConfirmAction('reenable');\n });\n\n const handleReset = async () => {\n try {\n await quotaManager.resetUsage(email);\n notify('success', t.messages.quotaReset);\n fetchQuota();\n } catch (e) {\n notify('error', (e as Error).message);\n }\n setConfirmAction(null);\n };\n\n const handleReenable = async () => {\n try {\n await quotaManager.setStatus(email, 'active');\n notify('success', t.messages.userReenabled);\n fetchQuota();\n } catch (e) {\n notify('error', (e as Error).message);\n }\n setConfirmAction(null);\n };\n\n if (loading)\n return (\n <Box paddingX={2}>\n <Spinner message={t.ui.processing} />\n </Box>\n );\n\n if (confirmAction === 'reset') {\n return (\n <Box paddingX={2}>\n <Confirm\n message={t.quota.confirmReset}\n onConfirm={handleReset}\n onCancel={() => setConfirmAction(null)}\n />\n </Box>\n );\n }\n if (confirmAction === 'reenable') {\n return (\n <Box paddingX={2}>\n <Confirm\n message={t.quota.confirmReenable}\n onConfirm={handleReenable}\n onCancel={() => setConfirmAction(null)}\n />\n </Box>\n );\n }\n\n if (!quota)\n return (\n <Box paddingX={2}>\n <Text dimColor>\n {t.quota.noQuota} ({email})\n </Text>\n </Box>\n );\n\n const ratio = quota.quotaBytes > 0 ? quota.usedBytes / quota.quotaBytes : 0;\n const remaining = quota.quotaBytes > 0 ? Math.max(0, quota.quotaBytes - quota.usedBytes) : -1;\n const labelW = 12;\n const badgeStatus =\n quota.status === 'exceeded'\n ? ('exceeded' as const)\n : quota.status === 'disabled'\n ? ('disabled' as const)\n : quota.quotaBytes > 0 && ratio >= 0.8\n ? ('warning' as const)\n : ('ok' as const);\n\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n <Text bold>{email}</Text>\n <Box flexDirection=\"column\">\n <KeyValue label=\"Status\" labelWidth={labelW} value={<StatusBadge status={badgeStatus} />} />\n <KeyValue\n label={t.quota.title.split(' ')[0] ?? 'Quota'}\n labelWidth={labelW}\n value={quota.quotaBytes > 0 ? formatBytes(quota.quotaBytes) : t.ui.unlimited}\n />\n <KeyValue label={t.quota.used} labelWidth={labelW} value={formatBytes(quota.usedBytes)} />\n {remaining >= 0 && (\n <KeyValue label={t.quota.remaining} labelWidth={labelW} value={formatBytes(remaining)} />\n )}\n </Box>\n {quota.quotaBytes > 0 && <ProgressBar ratio={ratio} width={30} />}\n <Text dimColor>\n <Text bold>r</Text> {t.ui.resetUsage} <Text bold>e</Text> {t.ui.reenable}{' '}\n <Text bold>esc</Text> {t.ui.back}\n </Text>\n </Box>\n );\n}\n", "import React, { useState, useEffect } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from '../components/design-system/ThemeProvider.js';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { useNotification } from '../contexts/NotificationContext.js';\nimport { Select, type SelectItem } from '../components/Select.js';\nimport { Confirm } from '../components/Confirm.js';\nimport { Spinner } from '../components/Spinner.js';\nimport { KeyValue } from '../components/KeyValue.js';\n\ntype Phase = 'menu' | 'confirm-restore' | 'operating';\n\nexport function ConfigManagement() {\n const { theme } = useTheme();\n const { configManager } = useServices();\n const { goBack } = useNavigation();\n const { notify } = useNotification();\n const [phase, setPhase] = useState<Phase>('menu');\n const [configSummary, setConfigSummary] = useState<Record<string, string> | null>(null);\n const [backups, setBackups] = useState<string[]>([]);\n const [loading, setLoading] = useState(true);\n const [restorePath, setRestorePath] = useState<string | null>(null);\n\n useEffect(() => {\n (async () => {\n try {\n const config = await configManager.readConfig();\n const inbound = config.inbounds?.[0];\n setConfigSummary({\n Protocol: inbound?.protocol ?? 'unknown',\n Port: String(inbound?.port ?? '-'),\n Network: (inbound?.streamSettings?.network as string) ?? '-',\n Security: (inbound?.streamSettings?.security as string) ?? '-',\n });\n setBackups(await configManager.listBackups());\n } catch {\n /* config may not exist */\n }\n setLoading(false);\n })();\n }, [configManager]);\n\n const handleBackup = async () => {\n setPhase('operating');\n try {\n const path = await configManager.backupConfig();\n notify('success', `Backed up to ${path}`);\n setBackups(await configManager.listBackups());\n } catch (e) {\n notify('error', `Backup failed: ${(e as Error).message}`);\n }\n setPhase('menu');\n };\n\n const handleRestore = async () => {\n if (!restorePath) return;\n setPhase('operating');\n try {\n await configManager.restoreConfig(restorePath);\n notify('success', 'Config restored');\n } catch (e) {\n notify('error', `Restore failed: ${(e as Error).message}`);\n }\n setRestorePath(null);\n setPhase('menu');\n };\n\n if (loading || phase === 'operating') {\n return (\n <Box paddingX={2}>\n <Spinner message={phase === 'operating' ? 'Processing...' : 'Loading config...'} />\n </Box>\n );\n }\n\n if (phase === 'confirm-restore' && restorePath) {\n return (\n <Box paddingX={2}>\n <Confirm\n message=\"Restore this backup? Current config will be overwritten.\"\n onConfirm={handleRestore}\n onCancel={() => {\n setRestorePath(null);\n setPhase('menu');\n }}\n destructive\n />\n </Box>\n );\n }\n\n const menuItems: SelectItem<string>[] = [\n { label: 'Create Backup', value: 'backup', hint: `${backups.length} existing` },\n ...(backups.length > 0\n ? backups.slice(0, 5).map((b) => ({\n label: `Restore: ${b.split('/').pop() ?? b}`,\n value: `restore:${b}`,\n }))\n : []),\n ];\n\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n {/* Current config summary */}\n {configSummary && (\n <Box flexDirection=\"column\">\n {Object.entries(configSummary).map(([k, v]) => (\n <KeyValue key={k} label={k} value={v} labelWidth={10} />\n ))}\n </Box>\n )}\n\n <Select\n items={menuItems}\n onSelect={(v) => {\n if (v === 'backup') handleBackup();\n else if (v.startsWith('restore:')) {\n setRestorePath(v.slice(8));\n setPhase('confirm-restore');\n }\n }}\n onCancel={goBack}\n />\n </Box>\n );\n}\n", "import React, { useState, useEffect } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from '../components/design-system/ThemeProvider.js';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { useI18n } from '../contexts/I18nContext.js';\nimport { Spinner } from '../components/Spinner.js';\n\ninterface LogLine {\n timestamp?: string;\n level?: string;\n message: string;\n}\n\nexport function LogViewer() {\n const { theme } = useTheme();\n const { logManager } = useServices();\n const { t } = useI18n();\n const [logType, setLogType] = useState<'access' | 'error'>('access');\n const [logs, setLogs] = useState<LogLine[]>([]);\n const [loading, setLoading] = useState(true);\n const [follow, setFollow] = useState(false);\n const [scrollOffset, setScrollOffset] = useState(0);\n\n const maxVisible = Math.max(5, (process.stdout.rows || 24) - 10);\n\n const fetchLogs = async () => {\n try {\n setLoading(true);\n const entries =\n logType === 'access'\n ? await logManager.readAccessLog(200)\n : await logManager.readErrorLog(200);\n setLogs(\n entries.map((e) => ({\n timestamp:\n e.timestamp instanceof Date\n ? e.timestamp.toISOString().slice(11, 19)\n : String(e.timestamp ?? ''),\n level: e.level,\n message: e.message,\n }))\n );\n if (follow) setScrollOffset(Math.max(0, entries.length - maxVisible));\n } catch {\n setLogs([]);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n fetchLogs();\n }, [logType]);\n useEffect(() => {\n if (!follow) return;\n const timer = setInterval(fetchLogs, 3000);\n return () => clearInterval(timer);\n }, [follow, logType]);\n\n useInput((input, key) => {\n if (input === 'f') setFollow((p) => !p);\n else if (input === 't') setLogType((p) => (p === 'access' ? 'error' : 'access'));\n else if (key.upArrow || input === 'k') {\n setScrollOffset((p) => Math.max(0, p - 1));\n setFollow(false);\n } else if (key.downArrow || input === 'j')\n setScrollOffset((p) => Math.min(Math.max(0, logs.length - maxVisible), p + 1));\n else if (key.pageUp) {\n setScrollOffset((p) => Math.max(0, p - maxVisible));\n setFollow(false);\n } else if (key.pageDown)\n setScrollOffset((p) => Math.min(Math.max(0, logs.length - maxVisible), p + maxVisible));\n });\n\n const visibleLogs = logs.slice(scrollOffset, scrollOffset + maxVisible);\n\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n <Box gap={2}>\n <Text\n bold={logType === 'access'}\n dimColor={logType !== 'access'}\n underline={logType === 'access'}\n >\n {t.logs.accessLog}\n </Text>\n <Text\n bold={logType === 'error'}\n dimColor={logType !== 'error'}\n underline={logType === 'error'}\n >\n {t.logs.errorLog}\n </Text>\n {follow && (\n <Text color={theme.success} bold>\n FOLLOW\n </Text>\n )}\n </Box>\n\n {loading ? (\n <Spinner message={t.ui.processing} />\n ) : logs.length === 0 ? (\n <Text dimColor>{t.ui.noEntries}</Text>\n ) : (\n <Box flexDirection=\"column\">\n {visibleLogs.map((line, i) => (\n <Box key={i + scrollOffset}>\n {line.timestamp && <Text dimColor>{line.timestamp} </Text>}\n {line.level && (\n <Text\n color={\n line.level.toLowerCase().includes('err')\n ? theme.error\n : line.level.toLowerCase().includes('warn')\n ? theme.warning\n : undefined\n }\n bold={line.level.toLowerCase().includes('err')}\n >\n {line.level.toUpperCase().padEnd(5)}{' '}\n </Text>\n )}\n <Text wrap=\"truncate-end\">{line.message}</Text>\n </Box>\n ))}\n </Box>\n )}\n\n <Text dimColor>\n {logs.length} {t.ui.entries} <Text bold>t</Text> {t.ui.switchLog} <Text bold>f</Text>{' '}\n {t.ui.follow}\n {follow ? ' (on)' : ''} <Text bold>{'\\u2191\\u2193'}</Text> {t.ui.scroll}\n </Text>\n </Box>\n );\n}\n", "import React from 'react';\nimport { Box, Text } from 'ink';\nimport { useTheme } from '../components/design-system/ThemeProvider.js';\nimport { useI18n } from '../contexts/I18nContext.js';\nimport { useOnlineUsers } from '../hooks/useOnlineUsers.js';\nimport { Spinner } from '../components/Spinner.js';\nimport { formatBytes } from '../utils/format.js';\n\nexport function OnlineUsers() {\n const { theme } = useTheme();\n const { t } = useI18n();\n const { summary, loading } = useOnlineUsers(5000);\n\n if (loading)\n return (\n <Box paddingX={2}>\n <Spinner message={t.ui.processing} />\n </Box>\n );\n\n if (!summary) {\n return (\n <Box paddingX={2}>\n <Text dimColor>{t.ui.noConnections}</Text>\n </Box>\n );\n }\n\n const activeList = summary.activeUsers.filter((u) => u.activeNow);\n const allUsers = summary.activeUsers;\n\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n {/* Summary line */}\n <Box gap={2}>\n <Text>\n <Text color={theme.success} bold>\n {summary.activeCount}\n </Text>\n <Text dimColor> active</Text>\n </Text>\n <Text dimColor>|</Text>\n <Text>\n <Text bold>{allUsers.length}</Text>\n <Text dimColor> {t.ui.users} total</Text>\n </Text>\n {summary.uniqueIps > 0 && (\n <>\n <Text dimColor>|</Text>\n <Text>\n <Text bold>{summary.uniqueIps}</Text>\n <Text dimColor> IPs</Text>\n </Text>\n </>\n )}\n {!summary.statsAvailable && <Text color={theme.warning}>Stats API unavailable</Text>}\n </Box>\n\n {/* User traffic table */}\n {allUsers.length > 0 ? (\n <Box flexDirection=\"column\">\n {/* Header */}\n <Box>\n <Box width={24}>\n <Text dimColor bold>\n User\n </Text>\n </Box>\n <Box width={14}>\n <Text dimColor bold>\n {'\\u2191'} Upload\n </Text>\n </Box>\n <Box width={14}>\n <Text dimColor bold>\n {'\\u2193'} Download\n </Text>\n </Box>\n <Box width={10}>\n <Text dimColor bold>\n Status\n </Text>\n </Box>\n </Box>\n\n {/* Rows */}\n {allUsers.map((user) => (\n <Box key={user.email}>\n <Box width={24}>\n <Text color={user.activeNow ? theme.text : theme.inactive}>{user.email}</Text>\n </Box>\n <Box width={14}>\n <Text dimColor={!user.activeNow}>{formatBytes(user.upload)}</Text>\n </Box>\n <Box width={14}>\n <Text dimColor={!user.activeNow}>{formatBytes(user.download)}</Text>\n </Box>\n <Box width={10}>\n {user.activeNow ? (\n <Text color={theme.success} bold>\n {'\\u25cf'} active\n </Text>\n ) : (\n <Text dimColor>{'\\u25cb'} idle</Text>\n )}\n </Box>\n </Box>\n ))}\n </Box>\n ) : (\n <Text dimColor>{t.ui.noConnections}</Text>\n )}\n\n {/* TCP connections section */}\n {summary.tcpConnections.length > 0 && (\n <Box flexDirection=\"column\">\n <Text dimColor>TCP connections:</Text>\n {summary.tcpConnections.slice(0, 10).map((c, i) => (\n <Text key={i} dimColor>\n {' '}\n {c.remoteIp}:{c.remotePort} {'\\u2192'} :{c.localPort}\n </Text>\n ))}\n {summary.tcpConnections.length > 10 && (\n <Text dimColor> ...and {summary.tcpConnections.length - 10} more</Text>\n )}\n </Box>\n )}\n\n <Text dimColor italic>\n {t.ui.autoRefresh}: 5s\n </Text>\n </Box>\n );\n}\n", "import { useState, useEffect, useCallback, useRef } from 'react';\nimport { OnlineManager, type OnlineUserSummary } from '../services/online-manager';\n\nexport function useOnlineUsers(pollInterval = 5000) {\n const [summary, setSummary] = useState<OnlineUserSummary | null>(null);\n const [loading, setLoading] = useState(true);\n const managerRef = useRef(new OnlineManager());\n\n const refresh = useCallback(async () => {\n try {\n const data = await managerRef.current.getOnlineConnections();\n setSummary(data);\n } catch {\n // Keep existing data\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n refresh();\n const timer = setInterval(refresh, pollInterval);\n return () => clearInterval(timer);\n }, [refresh, pollInterval]);\n\n return { summary, loading, refresh };\n}\n", "/**\n * Online User Manager\n *\n * Detects currently active users using two methods:\n * 1. Xray Stats API: compare traffic snapshots to detect active users\n * 2. TCP connections: parse `ss` output for connections to Xray ports\n *\n * @module services/online-manager\n */\n\nimport { execSync } from 'child_process';\nimport { ConfigManager } from './config-manager';\n\nexport interface OnlineUser {\n email: string;\n upload: number;\n download: number;\n activeNow: boolean;\n}\n\nexport interface TcpConnection {\n remoteIp: string;\n remotePort: number;\n localPort: number;\n}\n\nexport interface OnlineUserSummary {\n /** Users with traffic activity in the last interval */\n activeUsers: OnlineUser[];\n /** Number of active users */\n activeCount: number;\n /** TCP connections to Xray ports */\n tcpConnections: TcpConnection[];\n /** Unique remote IPs */\n uniqueIps: number;\n /** Xray listening ports */\n listeningPorts: number[];\n /** Xray stats API available */\n statsAvailable: boolean;\n}\n\ninterface TrafficSnapshot {\n email: string;\n uplink: number;\n downlink: number;\n}\n\n/**\n * Parse ss address like \"172.31.44.89:443\" or \"[::ffff:1.2.3.4]:443\"\n */\nfunction parseAddr(addr: string): { ip: string; port: number } | null {\n const v6 = addr.match(/^\\[(.+)\\]:(\\d+)$/);\n if (v6) {\n let ip = v6[1]!;\n const mapped = ip.match(/^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/i);\n if (mapped) ip = mapped[1]!;\n return { ip, port: parseInt(v6[2]!, 10) };\n }\n const v4 = addr.match(/^(.+):(\\d+)$/);\n if (v4) return { ip: v4[1]!, port: parseInt(v4[2]!, 10) };\n return null;\n}\n\nexport class OnlineManager {\n private configManager: ConfigManager;\n private previousSnapshot: Map<string, { up: number; down: number }> = new Map();\n private apiPort: number = 10085;\n\n constructor(configPath?: string) {\n this.configManager = new ConfigManager(configPath);\n }\n\n /**\n * Get Xray listening ports and API port from config\n */\n private async loadPorts(): Promise<{ listen: number[]; api: number }> {\n try {\n const config = await this.configManager.readConfig();\n const listen: number[] = [];\n let api = 10085;\n for (const inbound of config.inbounds ?? []) {\n if (inbound.tag === 'api' && inbound.port) {\n api = inbound.port;\n } else if (inbound.port) {\n listen.push(inbound.port);\n }\n }\n this.apiPort = api;\n return { listen, api };\n } catch {\n return { listen: [], api: 10085 };\n }\n }\n\n /**\n * Query Xray Stats API via the xray binary\n */\n private queryStats(): TrafficSnapshot[] {\n try {\n const output = execSync(\n `/usr/local/bin/xray api statsquery --server=127.0.0.1:${this.apiPort} 2>/dev/null`,\n { encoding: 'utf-8', timeout: 5000 }\n );\n const data = JSON.parse(output);\n const userMap = new Map<string, { uplink: number; downlink: number }>();\n\n for (const stat of data.stat ?? []) {\n const match = (stat.name as string).match(/^user>>>(.+?)>>>traffic>>>(uplink|downlink)$/);\n if (!match) continue;\n const email = match[1]!;\n const direction = match[2]!;\n if (!userMap.has(email)) userMap.set(email, { uplink: 0, downlink: 0 });\n const entry = userMap.get(email)!;\n if (direction === 'uplink') entry.uplink = Number(stat.value ?? 0);\n else entry.downlink = Number(stat.value ?? 0);\n }\n\n return Array.from(userMap.entries()).map(([email, v]) => ({\n email,\n uplink: v.uplink,\n downlink: v.downlink,\n }));\n } catch {\n return [];\n }\n }\n\n /**\n * Get TCP connections to Xray ports via ss\n */\n private getTcpConnections(ports: number[]): TcpConnection[] {\n if (ports.length === 0) return [];\n const connections: TcpConnection[] = [];\n\n try {\n const output = execSync('ss -tnH state established 2>/dev/null || true', {\n encoding: 'utf-8',\n timeout: 5000,\n });\n\n for (const line of output.split('\\n')) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 4) continue;\n\n const local = parseAddr(parts[2]!);\n const peer = parseAddr(parts[3]!);\n if (!local || !peer) continue;\n if (!ports.includes(local.port)) continue;\n if (peer.ip === '127.0.0.1' || peer.ip === '::1' || peer.ip === '0.0.0.0') continue;\n\n connections.push({\n remoteIp: peer.ip,\n remotePort: peer.port,\n localPort: local.port,\n });\n }\n } catch {\n // ss failed\n }\n\n return connections;\n }\n\n /**\n * Detect online users by comparing traffic snapshots\n */\n async getOnlineConnections(): Promise<OnlineUserSummary> {\n const { listen } = await this.loadPorts();\n\n // Method 1: Stats API \u2014 compare with previous snapshot\n const currentStats = this.queryStats();\n const statsAvailable = currentStats.length > 0;\n const activeUsers: OnlineUser[] = [];\n\n for (const user of currentStats) {\n const prev = this.previousSnapshot.get(user.email);\n const activeNow = prev ? user.uplink > prev.up || user.downlink > prev.down : false; // First run, can't determine\n\n activeUsers.push({\n email: user.email,\n upload: user.uplink,\n download: user.downlink,\n activeNow,\n });\n }\n\n // Save current snapshot for next comparison\n this.previousSnapshot.clear();\n for (const user of currentStats) {\n this.previousSnapshot.set(user.email, { up: user.uplink, down: user.downlink });\n }\n\n const activeCount = activeUsers.filter((u) => u.activeNow).length;\n\n // Method 2: TCP connections\n const tcpConnections = this.getTcpConnections(listen);\n const uniqueIps = new Set(tcpConnections.map((c) => c.remoteIp)).size;\n\n return {\n activeUsers,\n activeCount,\n tcpConnections,\n uniqueIps,\n listeningPorts: listen,\n statsAvailable,\n };\n }\n\n /**\n * Get connection count per IP\n */\n async getConnectionCounts(): Promise<Map<string, number>> {\n const summary = await this.getOnlineConnections();\n const counts = new Map<string, number>();\n for (const conn of summary.tcpConnections) {\n counts.set(conn.remoteIp, (counts.get(conn.remoteIp) ?? 0) + 1);\n }\n return counts;\n }\n}\n", "import React, { useState, useEffect } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport { useTheme } from '../components/design-system/ThemeProvider.js';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { useNotification } from '../contexts/NotificationContext.js';\nimport { useI18n } from '../contexts/I18nContext.js';\nimport { SubscriptionServer } from '../services/subscription-server.js';\nimport { PublicIpManager } from '../services/public-ip-manager.js';\nimport { StatusBadge } from '../components/StatusBadge.js';\nimport { Spinner } from '../components/Spinner.js';\n\ninterface SubInfo {\n email: string;\n token: string;\n fullUrl: string;\n}\n\nexport function SubscriptionManagement() {\n const { theme } = useTheme();\n const { userManager } = useServices();\n const { notify } = useNotification();\n const { t } = useI18n();\n const [subServer] = useState(() => new SubscriptionServer(userManager));\n const [running, setRunning] = useState(false);\n const [port, setPort] = useState(2096);\n const [subs, setSubs] = useState<SubInfo[]>([]);\n const [loading, setLoading] = useState(true);\n\n const refresh = async () => {\n try {\n const config = await subServer.loadConfig();\n setPort(config.port);\n setRunning(subServer.isRunning());\n\n let serverIp = 'localhost';\n try {\n serverIp = await new PublicIpManager().getPublicIp();\n } catch {\n /* fallback */\n }\n\n const allSubs = await subServer.getAllSubscriptions();\n setSubs(\n allSubs.map((s) => ({\n email: s.email,\n token: s.token,\n fullUrl: `http://${serverIp}:${config.port}${s.url}`,\n }))\n );\n } catch {\n /* ignore */\n }\n setLoading(false);\n };\n\n useEffect(() => {\n refresh();\n }, []);\n\n useInput((input) => {\n if (input === 's') {\n if (running) {\n subServer.stop().then(() => {\n setRunning(false);\n notify('info', 'Server stopped');\n });\n } else {\n subServer\n .start()\n .then((p) => {\n setRunning(true);\n setPort(p);\n notify('success', `Server started on :${p}`);\n })\n .catch((e) => notify('error', (e as Error).message));\n }\n } else if (input === 'r') {\n refresh();\n }\n });\n\n if (loading)\n return (\n <Box paddingX={2}>\n <Spinner message={t.ui.processing} />\n </Box>\n );\n\n return (\n <Box flexDirection=\"column\" paddingX={2} gap={1}>\n {/* Server status */}\n <Box gap={2}>\n <Text dimColor>Server:</Text>\n <StatusBadge status={running ? 'running' : 'stopped'} />\n <Text dimColor>\n Port: <Text bold>{port}</Text>\n </Text>\n </Box>\n\n {/* User subscription list \u2014 each user gets full-width URL display */}\n {subs.length > 0 ? (\n <Box flexDirection=\"column\">\n {subs.map((sub) => (\n <Box key={sub.email} flexDirection=\"column\" marginBottom={1}>\n <Text bold>{sub.email}</Text>\n <Text color={theme.primary} wrap=\"wrap\">\n {' '}\n {sub.fullUrl}\n </Text>\n </Box>\n ))}\n </Box>\n ) : (\n <Text dimColor>{t.ui.noUsers}</Text>\n )}\n\n {/* Hints */}\n <Text dimColor>\n <Text bold>s</Text> {running ? t.ui.stop : t.ui.start} <Text bold>r</Text> {t.ui.refresh}\n </Text>\n </Box>\n );\n}\n", "/**\n * Subscription Server\n *\n * Lightweight HTTP server that serves user subscription links.\n * Each user gets a unique token-based URL that returns their\n * current config in V2RayN-compatible format (base64 encoded VLESS links).\n *\n * @module services/subscription-server\n */\n\nimport http from 'http';\nimport { randomBytes } from 'crypto';\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { homedir } from 'os';\nimport { UserManager } from './user-manager';\nimport { UserMetadataManager } from './user-metadata-manager';\n\nconst SUB_CONFIG_PATH = join(homedir(), '.xray-manager', 'subscriptions.json');\n\ninterface SubConfig {\n port: number;\n enabled: boolean;\n tokens: Record<string, string>; // token -> userId\n}\n\nconst DEFAULT_CONFIG: SubConfig = {\n port: 2096,\n enabled: false,\n tokens: {},\n};\n\nexport class SubscriptionServer {\n private server: http.Server | null = null;\n private userManager: UserManager;\n private metadataManager: UserMetadataManager;\n private config: SubConfig = DEFAULT_CONFIG;\n\n constructor(userManager: UserManager) {\n this.userManager = userManager;\n this.metadataManager = new UserMetadataManager();\n }\n\n /**\n * Load subscription config\n */\n async loadConfig(): Promise<SubConfig> {\n try {\n if (existsSync(SUB_CONFIG_PATH)) {\n const content = await readFile(SUB_CONFIG_PATH, 'utf-8');\n this.config = { ...DEFAULT_CONFIG, ...JSON.parse(content) };\n }\n } catch {\n this.config = { ...DEFAULT_CONFIG };\n }\n return this.config;\n }\n\n /**\n * Save subscription config\n */\n async saveConfig(): Promise<void> {\n const dir = dirname(SUB_CONFIG_PATH);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(SUB_CONFIG_PATH, JSON.stringify(this.config, null, 2), 'utf-8');\n }\n\n /**\n * Generate a subscription token for a user\n */\n async generateToken(userId: string): Promise<string> {\n const token = randomBytes(16).toString('hex');\n await this.loadConfig();\n\n // Remove any existing token for this user\n for (const [existingToken, uid] of Object.entries(this.config.tokens)) {\n if (uid === userId) {\n delete this.config.tokens[existingToken];\n }\n }\n\n this.config.tokens[token] = userId;\n await this.saveConfig();\n\n // Also store in user metadata\n await this.metadataManager.setMetadata(userId, { subscriptionToken: token });\n\n return token;\n }\n\n /**\n * Get token for a user (generate if needed)\n */\n async getOrCreateToken(userId: string): Promise<string> {\n await this.loadConfig();\n\n // Check existing\n for (const [token, uid] of Object.entries(this.config.tokens)) {\n if (uid === userId) return token;\n }\n\n return this.generateToken(userId);\n }\n\n /**\n * Get all user subscription info\n */\n async getAllSubscriptions(): Promise<\n Array<{ userId: string; email: string; token: string; url: string }>\n > {\n await this.loadConfig();\n const users = await this.userManager.listUsers();\n const result: Array<{ userId: string; email: string; token: string; url: string }> = [];\n\n for (const user of users) {\n if (user.status !== 'active') continue;\n const token = await this.getOrCreateToken(user.id);\n result.push({\n userId: user.id,\n email: user.email,\n token,\n url: `/sub/${token}`,\n });\n }\n\n return result;\n }\n\n /**\n * Handle subscription request\n */\n private async handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {\n const url = req.url ?? '';\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n\n // Health check\n if (url === '/health') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ status: 'ok' }));\n return;\n }\n\n // Subscription endpoint: /sub/{token}\n const subMatch = url.match(/^\\/sub\\/([a-f0-9]{32})$/);\n if (!subMatch) {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n return;\n }\n\n const token = subMatch[1]!;\n await this.loadConfig();\n const userId = this.config.tokens[token];\n\n if (!userId) {\n res.writeHead(403, { 'Content-Type': 'text/plain' });\n res.end('Invalid subscription token');\n return;\n }\n\n try {\n const shareInfo = await this.userManager.getShareInfo(userId);\n\n // Build subscription content (base64-encoded links, one per line)\n const links: string[] = [];\n if (shareInfo.shareLink) {\n links.push(shareInfo.shareLink);\n }\n if (shareInfo.cdnShareLink) {\n links.push(shareInfo.cdnShareLink);\n }\n\n const content = Buffer.from(links.join('\\n')).toString('base64');\n\n // User-Agent detection for format (reserved for future Clash/Surge support)\n const _ua = (req.headers['user-agent'] ?? '').toLowerCase();\n\n res.writeHead(200, {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Content-Disposition': `attachment; filename=\"${shareInfo.user.email || 'sub'}\"`,\n 'Profile-Update-Interval': '24',\n 'Subscription-Userinfo': `upload=0; download=0; total=0; expire=0`,\n });\n res.end(content);\n } catch (e) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end(`Error: ${(e as Error).message}`);\n }\n }\n\n /**\n * Start the subscription server\n */\n async start(): Promise<number> {\n await this.loadConfig();\n const port = this.config.port;\n\n return new Promise((resolve, reject) => {\n this.server = http.createServer((req, res) => {\n this.handleRequest(req, res).catch(() => {\n res.writeHead(500);\n res.end('Internal Server Error');\n });\n });\n\n this.server.listen(port, '0.0.0.0', () => {\n this.config.enabled = true;\n this.saveConfig().catch(() => {});\n resolve(port);\n });\n\n this.server.on('error', (err) => {\n reject(err);\n });\n });\n }\n\n /**\n * Stop the subscription server\n */\n async stop(): Promise<void> {\n return new Promise((resolve) => {\n if (this.server) {\n this.server.close(() => {\n this.server = null;\n this.config.enabled = false;\n this.saveConfig().catch(() => {});\n resolve();\n });\n } else {\n resolve();\n }\n });\n }\n\n /**\n * Check if server is running\n */\n isRunning(): boolean {\n return this.server !== null && this.server.listening;\n }\n\n /**\n * Get configured port\n */\n getPort(): number {\n return this.config.port;\n }\n\n /**\n * Set port (requires restart)\n */\n async setPort(port: number): Promise<void> {\n await this.loadConfig();\n this.config.port = port;\n await this.saveConfig();\n }\n}\n", "import React from 'react';\nimport { useNavigation } from '../contexts/NavigationContext.js';\nimport { MainMenu } from '../screens/MainMenu.js';\nimport { ServiceStatus } from '../screens/ServiceStatus.js';\nimport { UserManagement } from '../screens/UserManagement.js';\nimport { UserAdd } from '../screens/UserAdd.js';\nimport { UserDelete } from '../screens/UserDelete.js';\nimport { UserShare } from '../screens/UserShare.js';\nimport { QuotaManagement } from '../screens/QuotaManagement.js';\nimport { QuotaSet } from '../screens/QuotaSet.js';\nimport { QuotaDetails } from '../screens/QuotaDetails.js';\nimport { ConfigManagement } from '../screens/ConfigManagement.js';\nimport { LogViewer } from '../screens/LogViewer.js';\nimport { OnlineUsers } from '../screens/OnlineUsers.js';\nimport { SubscriptionManagement } from '../screens/SubscriptionManagement.js';\n\nexport function Router() {\n const { currentRoute } = useNavigation();\n\n switch (currentRoute.screen) {\n case 'main-menu':\n return <MainMenu />;\n case 'service-status':\n return <ServiceStatus />;\n case 'user-management':\n return <UserManagement />;\n case 'user-add':\n return <UserAdd />;\n case 'user-delete':\n return <UserDelete />;\n case 'user-share':\n return <UserShare />;\n case 'quota-management':\n return <QuotaManagement />;\n case 'quota-set':\n return <QuotaSet />;\n case 'quota-details':\n return <QuotaDetails />;\n case 'config-management':\n return <ConfigManagement />;\n case 'log-viewer':\n return <LogViewer />;\n case 'online-users':\n return <OnlineUsers />;\n case 'subscriptions':\n return <SubscriptionManagement />;\n default:\n return <MainMenu />;\n }\n}\n", "import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useServices } from '../contexts/ServiceContext.js';\nimport { type DashboardData } from '../components/Dashboard.js';\nimport { OnlineManager } from '../services/online-manager.js';\nimport { SystemMonitor } from '../services/system-monitor.js';\n\nexport function useDashboardData(refreshInterval = 30000) {\n const { systemdManager, userManager, quotaManager, trafficManager } = useServices();\n const [data, setData] = useState<DashboardData | null>(null);\n const [loading, setLoading] = useState(true);\n const onlineManagerRef = useRef(new OnlineManager());\n const systemMonitorRef = useRef(new SystemMonitor());\n\n const refresh = useCallback(async () => {\n try {\n const [status, users, quotas] = await Promise.allSettled([\n systemdManager.getStatus(),\n userManager.listUsers(),\n quotaManager.getAllQuotas(),\n ]);\n\n const serviceStatus = status.status === 'fulfilled' ? status.value : null;\n const userList = users.status === 'fulfilled' ? users.value : [];\n const quotaMap = quotas.status === 'fulfilled' ? quotas.value : {};\n\n // Calculate quota summary\n let ok = 0;\n let warning = 0;\n let exceeded = 0;\n\n for (const q of Object.values(quotaMap)) {\n if (q.status === 'exceeded' || q.status === 'disabled') exceeded++;\n else if (q.quotaBytes > 0 && q.usedBytes / q.quotaBytes >= 0.8) warning++;\n else ok++;\n }\n\n // Users without quotas count as OK\n ok += Math.max(0, userList.length - Object.keys(quotaMap).length);\n\n // Traffic totals\n let totalTraffic = 0;\n let uploadTraffic = 0;\n let downloadTraffic = 0;\n\n try {\n const usages = await trafficManager.getAllUsage();\n for (const u of usages) {\n totalTraffic += (u.uplink ?? 0) + (u.downlink ?? 0);\n uploadTraffic += u.uplink ?? 0;\n downloadTraffic += u.downlink ?? 0;\n }\n } catch {\n // Stats API might not be available\n }\n\n // Format uptime\n let uptime: string | undefined;\n if (serviceStatus?.uptime) {\n uptime = serviceStatus.uptime;\n }\n\n // Online users (based on stats API traffic diff)\n let onlineCount: number | undefined;\n try {\n const online = await onlineManagerRef.current.getOnlineConnections();\n onlineCount = online.activeCount;\n } catch {\n // Ignore\n }\n\n // System metrics\n const sysMetrics = systemMonitorRef.current.getAll();\n\n setData({\n serviceActive: serviceStatus?.active ?? false,\n uptime,\n userCount: userList.length,\n onlineCount,\n totalTraffic,\n uploadTraffic,\n downloadTraffic,\n quotaSummary: { ok, warning, exceeded },\n cpuPercent: sysMetrics.cpuPercent,\n memPercent: sysMetrics.memPercent,\n diskPercent: sysMetrics.diskPercent,\n });\n } catch {\n // Keep existing data on error\n } finally {\n setLoading(false);\n }\n }, [systemdManager, userManager, quotaManager, trafficManager]);\n\n useEffect(() => {\n refresh();\n const timer = setInterval(refresh, refreshInterval);\n return () => clearInterval(timer);\n }, [refresh, refreshInterval]);\n\n return { data, loading, refresh };\n}\n", "/**\n * System Monitor Service\n *\n * Collects system resource metrics: CPU, memory, disk, network.\n *\n * @module services/system-monitor\n */\n\nimport os from 'os';\nimport { execSync } from 'child_process';\n\nexport interface SystemMetrics {\n cpuPercent: number;\n memTotal: number;\n memUsed: number;\n memPercent: number;\n diskTotal: number;\n diskUsed: number;\n diskPercent: number;\n networkRx: number;\n networkTx: number;\n uptime: number;\n loadAvg: number[];\n}\n\nexport class SystemMonitor {\n private lastCpuInfo: { idle: number; total: number } | null = null;\n private lastNetInfo: { rx: number; tx: number; time: number } | null = null;\n\n /**\n * Get CPU usage percentage (averaged over interval since last call)\n */\n getCpuPercent(): number {\n const cpus = os.cpus();\n let idle = 0;\n let total = 0;\n\n for (const cpu of cpus) {\n idle += cpu.times.idle;\n total += cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.irq + cpu.times.idle;\n }\n\n if (this.lastCpuInfo) {\n const idleDiff = idle - this.lastCpuInfo.idle;\n const totalDiff = total - this.lastCpuInfo.total;\n this.lastCpuInfo = { idle, total };\n if (totalDiff === 0) return 0;\n return Math.round((1 - idleDiff / totalDiff) * 100);\n }\n\n this.lastCpuInfo = { idle, total };\n return 0; // First call, no data yet\n }\n\n /**\n * Get memory usage\n */\n getMemory(): { total: number; used: number; percent: number } {\n const total = os.totalmem();\n const free = os.freemem();\n const used = total - free;\n return {\n total,\n used,\n percent: Math.round((used / total) * 100),\n };\n }\n\n /**\n * Get disk usage of root partition\n */\n getDisk(): { total: number; used: number; percent: number } {\n try {\n const output = execSync('df -B1 / 2>/dev/null | tail -1', {\n encoding: 'utf-8',\n timeout: 3000,\n });\n const parts = output.trim().split(/\\s+/);\n if (parts.length >= 5) {\n const total = parseInt(parts[1]!, 10) || 0;\n const used = parseInt(parts[2]!, 10) || 0;\n return {\n total,\n used,\n percent: total > 0 ? Math.round((used / total) * 100) : 0,\n };\n }\n } catch {\n // Fallback\n }\n return { total: 0, used: 0, percent: 0 };\n }\n\n /**\n * Get network throughput (bytes/sec since last call)\n */\n getNetworkThroughput(): { rx: number; tx: number } {\n try {\n const output = execSync('cat /proc/net/dev 2>/dev/null', {\n encoding: 'utf-8',\n timeout: 2000,\n });\n\n let totalRx = 0;\n let totalTx = 0;\n\n for (const line of output.split('\\n')) {\n const match = line.match(\n /^\\s*(\\w+):\\s*(\\d+)\\s+\\d+\\s+\\d+\\s+\\d+\\s+\\d+\\s+\\d+\\s+\\d+\\s+\\d+\\s+(\\d+)/\n );\n if (match && match[1] !== 'lo') {\n totalRx += parseInt(match[2]!, 10);\n totalTx += parseInt(match[3]!, 10);\n }\n }\n\n const now = Date.now();\n\n if (this.lastNetInfo) {\n const elapsed = (now - this.lastNetInfo.time) / 1000;\n const rx = elapsed > 0 ? (totalRx - this.lastNetInfo.rx) / elapsed : 0;\n const tx = elapsed > 0 ? (totalTx - this.lastNetInfo.tx) / elapsed : 0;\n this.lastNetInfo = { rx: totalRx, tx: totalTx, time: now };\n return { rx: Math.max(0, rx), tx: Math.max(0, tx) };\n }\n\n this.lastNetInfo = { rx: totalRx, tx: totalTx, time: now };\n } catch {\n // /proc not available\n }\n return { rx: 0, tx: 0 };\n }\n\n /**\n * Get all system metrics in one call\n */\n getAll(): SystemMetrics {\n const mem = this.getMemory();\n const disk = this.getDisk();\n const net = this.getNetworkThroughput();\n\n return {\n cpuPercent: this.getCpuPercent(),\n memTotal: mem.total,\n memUsed: mem.used,\n memPercent: mem.percent,\n diskTotal: disk.total,\n diskUsed: disk.used,\n diskPercent: disk.percent,\n networkRx: net.rx,\n networkTx: net.tx,\n uptime: os.uptime(),\n loadAvg: os.loadavg(),\n };\n }\n}\n", "import React from 'react';\nimport { ThemeProvider } from '../components/design-system/ThemeProvider.js';\nimport { I18nProvider } from '../contexts/I18nContext.js';\nimport { ServiceProvider, type ServiceOptions } from '../contexts/ServiceContext.js';\nimport { NavigationProvider } from '../contexts/NavigationContext.js';\nimport { NotificationProvider } from '../contexts/NotificationContext.js';\nimport { AppShell } from './AppShell.js';\n\ninterface AppProps {\n options: ServiceOptions;\n version: string;\n}\n\nexport function App({ options, version }: AppProps) {\n return (\n <ThemeProvider defaultTheme=\"dark\">\n <I18nProvider defaultLanguage=\"en\">\n <ServiceProvider options={options}>\n <NavigationProvider>\n <NotificationProvider>\n <AppShell version={version} />\n </NotificationProvider>\n </NavigationProvider>\n </ServiceProvider>\n </I18nProvider>\n </ThemeProvider>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["spawn", "code", "error", "React", "chalk", "chalk", "error", "error", "chalk", "chalk", "error", "code", "code", "error", "path", "access", "fsConstants", "info", "access", "fsConstants", "path", "error", "join", "homedir", "chalk", "info", "path", "join", "homedir", "stat", "info", "chalk", "error", "createContext", "useContext", "useState", "useCallback", "fs", "path", "jsx", "createContext", "useState", "setLanguage", "useCallback", "useContext", "createContext", "useContext", "readFile", "writeFile", "access", "readdir", "existsSync", "dirname", "join", "readFile", "error", "dirname", "existsSync", "writeFile", "join", "readdir", "access", "path", "fs", "SystemdManager", "randomUUID", "URLSearchParams", "readFile", "writeFile", "mkdir", "existsSync", "dirname", "error", "existsSync", "readFile", "dirname", "mkdir", "writeFile", "readFile", "writeFile", "mkdir", "existsSync", "dirname", "isValidUuid", "existsSync", "readFile", "dirname", "mkdir", "writeFile", "randomUUID", "network", "security", "URLSearchParams", "readFile", "writeFile", "mkdir", "chmod", "existsSync", "dirname", "isValidEmail", "isValidPort", "existsSync", "readFile", "error", "dirname", "mkdir", "writeFile", "chmod", "existsSync", "readFile", "readFile", "stat", "existsSync", "error", "spawn", "existsSync", "readFile", "stat", "existsSync", "error", "spawn", "code", "stat", "readFile", "exec", "promisify", "execAsync", "promisify", "exec", "error", "jsx", "createContext", "useContext", "createContext", "useContext", "useCallback", "jsx", "createContext", "useCallback", "useContext", "createContext", "useContext", "useState", "useCallback", "jsx", "useState", "Box", "useInput", "jsx", "t", "Box", "Text", "jsx", "jsxs", "t", "Box", "hint", "Text", "Box", "Text", "jsx", "jsxs", "title", "Box", "Text", "Box", "Text", "jsx", "jsxs", "Box", "Text", "Box", "Text", "jsx", "jsxs", "Text", "loading", "t", "Box", "Box", "Text", "jsx", "jsxs", "Box", "Text", "useState", "useMemo", "Box", "Text", "jsx", "jsxs", "useState", "useMemo", "input", "Box", "Text", "React", "Box", "useState", "useCallback", "Box", "Text", "useInput", "jsx", "jsxs", "title", "useState", "useCallback", "useInput", "input", "Box", "Text", "useState", "useEffect", "Text", "jsx", "jsxs", "useState", "useEffect", "Text", "Box", "Text", "useInput", "jsx", "jsxs", "hint", "useInput", "input", "Box", "Text", "jsx", "t", "React", "Box", "Box", "Text", "useState", "useEffect", "useCallback", "useState", "loading", "useCallback", "useEffect", "Text", "jsx", "jsxs", "Text", "Box", "Text", "jsx", "jsxs", "Box", "Text", "jsx", "jsxs", "loading", "Box", "Text", "Box", "Text", "useInput", "useState", "useEffect", "useCallback", "useState", "loading", "useCallback", "useEffect", "useState", "Box", "Text", "useInput", "jsx", "jsxs", "useState", "useInput", "input", "Box", "Text", "jsx", "jsxs", "t", "loading", "useInput", "input", "Text", "Box", "useState", "Box", "Text", "React", "useState", "Box", "Text", "useInput", "jsx", "jsxs", "useState", "error", "React", "useInput", "input", "Box", "Text", "jsx", "jsxs", "t", "useState", "Box", "Text", "useState", "Box", "Text", "jsx", "t", "loading", "useState", "Box", "Text", "useState", "useEffect", "Box", "Text", "jsx", "jsxs", "useState", "useEffect", "info", "Box", "Text", "Box", "Text", "useInput", "useState", "useEffect", "useCallback", "useState", "loading", "useCallback", "useEffect", "Text", "jsx", "jsxs", "Text", "jsx", "jsxs", "t", "loading", "useInput", "input", "Text", "Box", "useState", "Box", "Text", "jsx", "jsxs", "input", "useState", "Box", "Text", "useState", "useEffect", "Box", "Text", "useInput", "jsx", "jsxs", "t", "useState", "loading", "useEffect", "useInput", "input", "Box", "Text", "useState", "useEffect", "Box", "jsx", "jsxs", "useState", "loading", "useEffect", "path", "Box", "useState", "useEffect", "Box", "Text", "useInput", "jsx", "jsxs", "t", "useState", "loading", "useEffect", "useInput", "input", "Box", "Text", "Box", "Text", "useState", "useEffect", "useCallback", "execSync", "execSync", "stat", "useState", "loading", "useCallback", "useEffect", "jsx", "jsxs", "t", "loading", "Box", "Text", "useState", "useEffect", "Box", "Text", "useInput", "readFile", "writeFile", "mkdir", "existsSync", "join", "dirname", "homedir", "join", "homedir", "existsSync", "readFile", "dirname", "mkdir", "writeFile", "jsx", "jsxs", "t", "useState", "loading", "useEffect", "useInput", "input", "Box", "Text", "jsx", "useState", "useEffect", "useCallback", "useRef", "os", "execSync", "useState", "loading", "useRef", "useCallback", "useEffect", "Fragment", "jsx", "jsxs", "useState", "useInput", "input", "Box", "jsx", "readFileSync", "dirname", "join", "error", "React"]
|
|
7
|
+
}
|