@uofx/cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/LICENSE +40 -0
  2. package/README.md +444 -0
  3. package/THIRD-PARTY-NOTICES.txt +894 -0
  4. package/dist/application/dtos/index.js +24 -0
  5. package/dist/application/dtos/request/delete-instance.request.dto.js +3 -0
  6. package/dist/application/dtos/request/get-config.request.dto.js +3 -0
  7. package/dist/application/dtos/request/get-credentials.request.dto.js +3 -0
  8. package/dist/application/dtos/request/index.js +27 -0
  9. package/dist/application/dtos/request/install-instance.request.dto.js +3 -0
  10. package/dist/application/dtos/request/list-charts.request.dto.js +3 -0
  11. package/dist/application/dtos/request/set-config.request.dto.js +16 -0
  12. package/dist/application/dtos/request/setup-environment.request.dto.js +16 -0
  13. package/dist/application/dtos/request/show-logs.request.dto.js +19 -0
  14. package/dist/application/dtos/request/start-instance.request.dto.js +3 -0
  15. package/dist/application/dtos/request/stop-instance.request.dto.js +3 -0
  16. package/dist/application/dtos/response/credentials.response.dto.js +3 -0
  17. package/dist/application/dtos/response/delete-instance.response.dto.js +3 -0
  18. package/dist/application/dtos/response/index.js +26 -0
  19. package/dist/application/dtos/response/install-instance.response.dto.js +3 -0
  20. package/dist/application/dtos/response/instance-list.response.dto.js +3 -0
  21. package/dist/application/dtos/response/instance-status.response.dto.js +3 -0
  22. package/dist/application/dtos/response/setup-result.response.dto.js +3 -0
  23. package/dist/application/dtos/response/show-logs.response.dto.js +3 -0
  24. package/dist/application/dtos/response/start-instance.response.dto.js +3 -0
  25. package/dist/application/dtos/response/stop-instance.response.dto.js +3 -0
  26. package/dist/application/index.js +25 -0
  27. package/dist/application/interfaces/index.js +24 -0
  28. package/dist/application/interfaces/use-case.interface.js +3 -0
  29. package/dist/application/use-cases/config/get-config.use-case.js +66 -0
  30. package/dist/application/use-cases/config/set-config.use-case.js +49 -0
  31. package/dist/application/use-cases/credentials/get-credentials.use-case.js +57 -0
  32. package/dist/application/use-cases/index.js +28 -0
  33. package/dist/application/use-cases/instance/delete-instance.use-case.js +81 -0
  34. package/dist/application/use-cases/instance/index.js +23 -0
  35. package/dist/application/use-cases/instance/install-instance.use-case.js +424 -0
  36. package/dist/application/use-cases/instance/list-charts.use-case.js +43 -0
  37. package/dist/application/use-cases/instance/list-instances.use-case.js +62 -0
  38. package/dist/application/use-cases/instance/start-instance.use-case.js +154 -0
  39. package/dist/application/use-cases/instance/stop-instance.use-case.js +55 -0
  40. package/dist/application/use-cases/logs/show-logs.use-case.js +66 -0
  41. package/dist/application/use-cases/setup/setup-environment.use-case.js +53 -0
  42. package/dist/cli.js +286 -0
  43. package/dist/constants/config-defaults.js +23 -0
  44. package/dist/constants/defaults.js +89 -0
  45. package/dist/constants/deployment.js +39 -0
  46. package/dist/constants/environments.js +93 -0
  47. package/dist/constants/index.js +53 -0
  48. package/dist/constants/oci-artifacts.js +25 -0
  49. package/dist/constants/paths.js +92 -0
  50. package/dist/constants/timeouts.js +60 -0
  51. package/dist/di/container.js +34 -0
  52. package/dist/di/index.js +22 -0
  53. package/dist/di/modules/application.module.js +54 -0
  54. package/dist/di/modules/infrastructure.module.js +206 -0
  55. package/dist/di/modules/interceptor.module.js +68 -0
  56. package/dist/di/modules/presentation.module.js +31 -0
  57. package/dist/di/tokens.js +149 -0
  58. package/dist/domain/decorators/sensitive.decorator.js +39 -0
  59. package/dist/domain/entities/credentials-resolver.entity.js +127 -0
  60. package/dist/domain/entities/credentials.entity.js +65 -0
  61. package/dist/domain/entities/delete-instance-validation.entity.js +100 -0
  62. package/dist/domain/entities/deployment-parameters.entity.js +120 -0
  63. package/dist/domain/entities/environment-validation.entity.js +125 -0
  64. package/dist/domain/entities/index.js +29 -0
  65. package/dist/domain/entities/instance-lifecycle-state.entity.js +100 -0
  66. package/dist/domain/entities/instance-list-aggregator.entity.js +104 -0
  67. package/dist/domain/entities/instance-metadata.entity.js +86 -0
  68. package/dist/domain/entities/instance-status.entity.js +79 -0
  69. package/dist/domain/entities/instance.entity.js +128 -0
  70. package/dist/domain/entities/log-filter.entity.js +141 -0
  71. package/dist/domain/index.js +29 -0
  72. package/dist/domain/interfaces/safe-loggable.interface.js +3 -0
  73. package/dist/domain/ports/app-config.port.js +3 -0
  74. package/dist/domain/ports/base-image.port.js +3 -0
  75. package/dist/domain/ports/chart-version.port.js +3 -0
  76. package/dist/domain/ports/correlation-id.port.js +3 -0
  77. package/dist/domain/ports/credentials.port.js +3 -0
  78. package/dist/domain/ports/deployment.port.js +3 -0
  79. package/dist/domain/ports/error-handler.port.js +3 -0
  80. package/dist/domain/ports/index.js +46 -0
  81. package/dist/domain/ports/instance-manager.port.js +3 -0
  82. package/dist/domain/ports/instance-metadata.port.js +8 -0
  83. package/dist/domain/ports/instance-storage.port.js +3 -0
  84. package/dist/domain/ports/k8s-deployer.port.js +3 -0
  85. package/dist/domain/ports/logger.port.js +14 -0
  86. package/dist/domain/ports/output.port.js +3 -0
  87. package/dist/domain/ports/runtime-environment.port.js +6 -0
  88. package/dist/domain/ports/user-interaction.port.js +9 -0
  89. package/dist/domain/ports/user-settings.port.js +3 -0
  90. package/dist/domain/types/index.js +22 -0
  91. package/dist/domain/types/logger.types.js +29 -0
  92. package/dist/domain/types/validation.types.js +9 -0
  93. package/dist/domain/value-objects/acr-credentials.value-object.js +92 -0
  94. package/dist/domain/value-objects/chart-version.value-object.js +124 -0
  95. package/dist/domain/value-objects/config-log-level.value-object.js +84 -0
  96. package/dist/domain/value-objects/connection-info.value-object.js +65 -0
  97. package/dist/domain/value-objects/index.js +25 -0
  98. package/dist/domain/value-objects/instance-name.value-object.js +91 -0
  99. package/dist/domain/value-objects/jwt-key.value-object.js +97 -0
  100. package/dist/domain/value-objects/mssql-password.value-object.js +140 -0
  101. package/dist/domain/value-objects/rsa-key-pair.value-object.js +181 -0
  102. package/dist/index.js +6 -0
  103. package/dist/infrastructure/config/app-config.interface.js +3 -0
  104. package/dist/infrastructure/config/app-config.service.js +280 -0
  105. package/dist/infrastructure/config/config-validator.js +31 -0
  106. package/dist/infrastructure/config/crypto.service.js +125 -0
  107. package/dist/infrastructure/deployment/deployment.adapter.js +118 -0
  108. package/dist/infrastructure/deployment/interfaces/acr-credential-manager.interface.js +3 -0
  109. package/dist/infrastructure/deployment/interfaces/app-manager.interface.js +3 -0
  110. package/dist/infrastructure/deployment/interfaces/helm-registry.interface.js +3 -0
  111. package/dist/infrastructure/deployment/interfaces/infra-manager.interface.js +3 -0
  112. package/dist/infrastructure/deployment/interfaces/k8s-job-runner.interface.js +3 -0
  113. package/dist/infrastructure/deployment/interfaces/mssql-database-init.interface.js +3 -0
  114. package/dist/infrastructure/deployment/interfaces/mssql-helm-deployment.interface.js +3 -0
  115. package/dist/infrastructure/deployment/interfaces/mssql-storage.interface.js +3 -0
  116. package/dist/infrastructure/deployment/interfaces/mssql-user-manager.interface.js +3 -0
  117. package/dist/infrastructure/deployment/interfaces/oci-artifact.interface.js +3 -0
  118. package/dist/infrastructure/deployment/interfaces/secret-manager.interface.js +3 -0
  119. package/dist/infrastructure/deployment/interfaces/service-manager.interface.js +3 -0
  120. package/dist/infrastructure/deployment/interfaces/version-compatibility.interface.js +3 -0
  121. package/dist/infrastructure/deployment/services/acr-credential-manager.service.js +144 -0
  122. package/dist/infrastructure/deployment/services/app-manager.service.js +193 -0
  123. package/dist/infrastructure/deployment/services/base-helm-deployment.service.js +163 -0
  124. package/dist/infrastructure/deployment/services/helm-registry.service.js +126 -0
  125. package/dist/infrastructure/deployment/services/infra-manager.service.js +130 -0
  126. package/dist/infrastructure/deployment/services/k8s-job-runner.service.js +194 -0
  127. package/dist/infrastructure/deployment/services/mssql-database-init.service.js +139 -0
  128. package/dist/infrastructure/deployment/services/mssql-helm-deployment.service.js +100 -0
  129. package/dist/infrastructure/deployment/services/mssql-storage.service.js +54 -0
  130. package/dist/infrastructure/deployment/services/mssql-user-manager.service.js +66 -0
  131. package/dist/infrastructure/deployment/services/oci-artifact.service.js +289 -0
  132. package/dist/infrastructure/deployment/services/secret-manager.service.js +179 -0
  133. package/dist/infrastructure/deployment/services/service-manager.service.js +82 -0
  134. package/dist/infrastructure/deployment/services/version-compatibility.service.js +291 -0
  135. package/dist/infrastructure/environment/interfaces/hardware-info.interface.js +3 -0
  136. package/dist/infrastructure/environment/interfaces/network-checker.interface.js +3 -0
  137. package/dist/infrastructure/environment/services/hardware-info.service.js +135 -0
  138. package/dist/infrastructure/environment/services/network-checker.service.js +142 -0
  139. package/dist/infrastructure/environment/windows-environment.adapter.js +162 -0
  140. package/dist/infrastructure/errors/app-error.js +73 -0
  141. package/dist/infrastructure/errors/error-handler.interface.js +3 -0
  142. package/dist/infrastructure/errors/error-handler.js +218 -0
  143. package/dist/infrastructure/errors/exit-codes.js +27 -0
  144. package/dist/infrastructure/errors/index.js +25 -0
  145. package/dist/infrastructure/execution/builders/base-command.builder.js +122 -0
  146. package/dist/infrastructure/execution/builders/host-command.builder.js +58 -0
  147. package/dist/infrastructure/execution/builders/windows-host-command.builder.js +50 -0
  148. package/dist/infrastructure/execution/builders/wsl-command.builder.js +29 -0
  149. package/dist/infrastructure/execution/command-builder.js +252 -0
  150. package/dist/infrastructure/execution/command-executor.service.js +230 -0
  151. package/dist/infrastructure/execution/environments/wsl-execution.environment.js +70 -0
  152. package/dist/infrastructure/execution/execution-environment.factory.js +53 -0
  153. package/dist/infrastructure/execution/index.js +25 -0
  154. package/dist/infrastructure/execution/interfaces/command-builder.interface.js +3 -0
  155. package/dist/infrastructure/execution/interfaces/command-executor.interface.js +3 -0
  156. package/dist/infrastructure/execution/interfaces/execution-environment-factory.interface.js +3 -0
  157. package/dist/infrastructure/execution/interfaces/execution-environment.interface.js +7 -0
  158. package/dist/infrastructure/execution/interfaces/host-command-builder.interface.js +3 -0
  159. package/dist/infrastructure/execution/interfaces/index.js +23 -0
  160. package/dist/infrastructure/execution/interfaces/script-executor.interface.js +3 -0
  161. package/dist/infrastructure/execution/script-executor.service.js +171 -0
  162. package/dist/infrastructure/http/http-client.service.js +176 -0
  163. package/dist/infrastructure/http/index.js +18 -0
  164. package/dist/infrastructure/http/interfaces/http-client.interface.js +3 -0
  165. package/dist/infrastructure/interceptors/index.js +8 -0
  166. package/dist/infrastructure/interceptors/interceptor.factory.js +44 -0
  167. package/dist/infrastructure/interceptors/interceptor.interface.js +3 -0
  168. package/dist/infrastructure/interceptors/logging.interceptor.js +171 -0
  169. package/dist/infrastructure/logger/correlation-id.adapter.js +68 -0
  170. package/dist/infrastructure/logger/index.js +23 -0
  171. package/dist/infrastructure/logger/interfaces/index.js +22 -0
  172. package/dist/infrastructure/logger/interfaces/log-reader.repository.interface.js +7 -0
  173. package/dist/infrastructure/logger/interfaces/log-writer.repository.interface.js +7 -0
  174. package/dist/infrastructure/logger/logger.adapter.js +274 -0
  175. package/dist/infrastructure/logger/services/file-log-reader.repository.js +148 -0
  176. package/dist/infrastructure/logger/services/file-log-writer.repository.js +307 -0
  177. package/dist/infrastructure/logger/services/index.js +22 -0
  178. package/dist/infrastructure/persistence/index.js +25 -0
  179. package/dist/infrastructure/persistence/instance-metadata.adapter.js +100 -0
  180. package/dist/infrastructure/persistence/instance-storage.adapter.js +64 -0
  181. package/dist/infrastructure/persistence/interfaces/config.repository.interface.js +3 -0
  182. package/dist/infrastructure/persistence/interfaces/index.js +22 -0
  183. package/dist/infrastructure/persistence/interfaces/instance.repository.interface.js +3 -0
  184. package/dist/infrastructure/persistence/services/file-system-config.repository.js +168 -0
  185. package/dist/infrastructure/persistence/services/file-system-instance.repository.js +170 -0
  186. package/dist/infrastructure/persistence/services/index.js +22 -0
  187. package/dist/infrastructure/persistence/user-settings.adapter.js +55 -0
  188. package/dist/infrastructure/platform-detector.js +71 -0
  189. package/dist/infrastructure/platforms/windows/interfaces/microk8s.interface.js +3 -0
  190. package/dist/infrastructure/platforms/windows/interfaces/rootfs-manager.interface.js +3 -0
  191. package/dist/infrastructure/platforms/windows/interfaces/windows-features.interface.js +3 -0
  192. package/dist/infrastructure/platforms/windows/interfaces/windows-info.interface.js +3 -0
  193. package/dist/infrastructure/platforms/windows/interfaces/wsl-config.interface.js +3 -0
  194. package/dist/infrastructure/platforms/windows/interfaces/wsl-info.interface.js +3 -0
  195. package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-inspection.interface.js +3 -0
  196. package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-lifecycle.interface.js +3 -0
  197. package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-naming.interface.js +3 -0
  198. package/dist/infrastructure/platforms/windows/interfaces/wsl-manager.interface.js +3 -0
  199. package/dist/infrastructure/platforms/windows/interfaces/wsl-resources.interface.js +8 -0
  200. package/dist/infrastructure/platforms/windows/interfaces/wsl-updater.interface.js +3 -0
  201. package/dist/infrastructure/platforms/windows/interfaces/wslconfig-parser.interface.js +3 -0
  202. package/dist/infrastructure/platforms/windows/parsers/wsl-version.parser.js +133 -0
  203. package/dist/infrastructure/platforms/windows/services/microk8s.service.js +168 -0
  204. package/dist/infrastructure/platforms/windows/services/rootfs-manager.service.js +336 -0
  205. package/dist/infrastructure/platforms/windows/services/windows-features.service.js +191 -0
  206. package/dist/infrastructure/platforms/windows/services/windows-info.service.js +138 -0
  207. package/dist/infrastructure/platforms/windows/services/wsl-config.service.js +171 -0
  208. package/dist/infrastructure/platforms/windows/services/wsl-info.service.js +226 -0
  209. package/dist/infrastructure/platforms/windows/services/wsl-instance-inspection.service.js +325 -0
  210. package/dist/infrastructure/platforms/windows/services/wsl-instance-lifecycle.service.js +442 -0
  211. package/dist/infrastructure/platforms/windows/services/wsl-instance-naming.service.js +93 -0
  212. package/dist/infrastructure/platforms/windows/services/wsl-updater.service.js +273 -0
  213. package/dist/infrastructure/platforms/windows/services/wslconfig-parser.service.js +222 -0
  214. package/dist/infrastructure/platforms/windows/wsl-base-image.adapter.js +41 -0
  215. package/dist/infrastructure/platforms/windows/wsl-instance-manager.adapter.js +150 -0
  216. package/dist/infrastructure/utils/error-formatter.util.js +29 -0
  217. package/dist/infrastructure/utils/file-operations.util.js +201 -0
  218. package/dist/infrastructure/utils/input-validator.util.js +152 -0
  219. package/dist/infrastructure/utils/retry.util.js +98 -0
  220. package/dist/presentation/controllers/config.controller.js +146 -0
  221. package/dist/presentation/controllers/credentials.controller.js +105 -0
  222. package/dist/presentation/controllers/index.js +25 -0
  223. package/dist/presentation/controllers/instance.controller.js +363 -0
  224. package/dist/presentation/controllers/logs.controller.js +103 -0
  225. package/dist/presentation/controllers/setup.controller.js +175 -0
  226. package/dist/presentation/interfaces/cli-options.interface.js +8 -0
  227. package/dist/presentation/prompts/acr-credentials.prompt.js +76 -0
  228. package/dist/presentation/prompts/index.js +21 -0
  229. package/dist/presentation/ui/cli-progress.service.js +193 -0
  230. package/dist/presentation/ui/constants/output-symbols.js +42 -0
  231. package/dist/presentation/ui/index.js +27 -0
  232. package/dist/presentation/ui/interaction.service.js +276 -0
  233. package/dist/presentation/ui/interfaces/cli-progress.interface.js +9 -0
  234. package/dist/presentation/ui/interfaces/output-formatter.interface.js +23 -0
  235. package/dist/presentation/ui/log-level.enum.js +66 -0
  236. package/dist/presentation/ui/output-builder.service.js +378 -0
  237. package/dist/presentation/ui/output-formatter.service.js +393 -0
  238. package/package.json +65 -0
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.WindowsFeaturesService = exports.VM_PLATFORM_FEATURE_NAME = exports.WSL_FEATURE_NAME = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const tokens_1 = require("../../../../di/tokens");
18
+ const errors_1 = require("../../../errors");
19
+ const command_builder_1 = require("../../../execution/command-builder");
20
+ /**
21
+ * Windows 功能管理服務
22
+ *
23
+ * 負責檢查與啟用 Windows 相關功能(如 WSL, 虛擬機器平台),包含:
24
+ * - 檢查功能狀態
25
+ * - 檢查管理員權限
26
+ * - 啟用功能
27
+ * - 格式化狀態報告
28
+ */
29
+ exports.WSL_FEATURE_NAME = 'Microsoft-Windows-Subsystem-Linux';
30
+ exports.VM_PLATFORM_FEATURE_NAME = 'VirtualMachinePlatform';
31
+ let WindowsFeaturesService = class WindowsFeaturesService {
32
+ constructor(commandExecutor) {
33
+ this.commandExecutor = commandExecutor;
34
+ }
35
+ /**
36
+ * 檢查單一 Windows 功能的狀態
37
+ * @param featureName - Windows 功能名稱
38
+ * @returns 功能狀態 ('Enabled', 'Disabled', 'Unknown')
39
+ * @throws AppSystemError 若查詢失敗
40
+ */
41
+ async checkFeatureState(featureName) {
42
+ try {
43
+ const builder = command_builder_1.CommandBuilder.create('powershell')
44
+ .powershell(`[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; $feature = Get-WindowsOptionalFeature -Online -FeatureName ${featureName}; $feature.State`);
45
+ const result = await builder.exec(this.commandExecutor);
46
+ const output = result.stdout.trim();
47
+ if (output.includes('Enable')) {
48
+ return 'Enabled';
49
+ }
50
+ else if (output.includes('Disable')) {
51
+ return 'Disabled';
52
+ }
53
+ else {
54
+ return 'Unknown';
55
+ }
56
+ }
57
+ catch (error) {
58
+ throw new errors_1.AppError(`Failed to check Windows feature: ${featureName}`, {
59
+ exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
60
+ solution: 'Ensure PowerShell is available and you have permission to query Windows features',
61
+ cause: error,
62
+ context: { operation: 'checkFeatureState', resource: 'PowerShell Get-WindowsOptionalFeature' }
63
+ });
64
+ }
65
+ }
66
+ /**
67
+ * 檢查 WSL 相關功能的狀態
68
+ * 包含 'Microsoft-Windows-Subsystem-Linux' 和 'VirtualMachinePlatform'
69
+ * @returns WSL 功能狀態報告
70
+ */
71
+ async checkWSLFeatures() {
72
+ const wslState = await this.checkFeatureState(exports.WSL_FEATURE_NAME);
73
+ const wsl = {
74
+ name: exports.WSL_FEATURE_NAME,
75
+ displayName: 'Windows Subsystem for Linux',
76
+ state: wslState
77
+ };
78
+ const vmState = await this.checkFeatureState(exports.VM_PLATFORM_FEATURE_NAME);
79
+ const virtualMachine = {
80
+ name: exports.VM_PLATFORM_FEATURE_NAME,
81
+ displayName: 'Virtual Machine Platform',
82
+ state: vmState
83
+ };
84
+ const allEnabled = wslState === 'Enabled' && vmState === 'Enabled';
85
+ const missingFeatures = [];
86
+ if (wslState !== 'Enabled') {
87
+ missingFeatures.push(wsl);
88
+ }
89
+ if (vmState !== 'Enabled') {
90
+ missingFeatures.push(virtualMachine);
91
+ }
92
+ return {
93
+ wsl,
94
+ virtualMachine,
95
+ allEnabled,
96
+ missingFeatures
97
+ };
98
+ }
99
+ /**
100
+ * 檢查當前處理程序是否具有管理員權限
101
+ * @returns 若具有管理員權限則回傳 true
102
+ * @throws AppSystemError 若檢查失敗
103
+ */
104
+ async checkAdminPrivileges() {
105
+ try {
106
+ const builder = command_builder_1.CommandBuilder.create('powershell')
107
+ .powershell("([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')");
108
+ const result = await builder.exec(this.commandExecutor);
109
+ const output = result.stdout.trim();
110
+ return output === 'True';
111
+ }
112
+ catch (error) {
113
+ throw new errors_1.AppError('Failed to check administrator privileges', {
114
+ exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
115
+ solution: 'Ensure PowerShell is available and you have permission to check privileges',
116
+ cause: error,
117
+ context: { operation: 'checkAdminPrivileges', resource: 'PowerShell Security.Principal' }
118
+ });
119
+ }
120
+ }
121
+ /**
122
+ * 啟用指定的 Windows 功能
123
+ * @param features - 要啟用的功能列表
124
+ * @returns 成功啟用的功能數量
125
+ * @throws AppSystemError 若啟用失敗
126
+ */
127
+ async enableWSLFeatures(features) {
128
+ let enabledCount = 0;
129
+ for (const feature of features) {
130
+ try {
131
+ const builder = command_builder_1.CommandBuilder.create('dism.exe')
132
+ .arg('/online')
133
+ .arg('/enable-feature')
134
+ .arg(`/featurename:${feature.name}`)
135
+ .arg('/all')
136
+ .arg('/norestart');
137
+ await builder.exec(this.commandExecutor);
138
+ enabledCount++;
139
+ }
140
+ catch (error) {
141
+ throw new errors_1.AppError(`Failed to enable Windows feature: ${feature.displayName}`, {
142
+ exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
143
+ solution: 'Ensure you have administrator privileges and try again',
144
+ cause: error,
145
+ context: { operation: 'enableWSLFeatures', resource: 'dism.exe' }
146
+ });
147
+ }
148
+ }
149
+ return enabledCount;
150
+ }
151
+ /**
152
+ * 檢查 WSL 功能需求(整合檢查)
153
+ * @returns 檢查結果(包含錯誤與警告)
154
+ */
155
+ async checkWSLFeaturesRequirement() {
156
+ const blockingErrors = [];
157
+ try {
158
+ const status = await this.checkWSLFeatures();
159
+ if (!status.allEnabled) {
160
+ const missingFeatureNames = status.missingFeatures
161
+ .map(f => f.displayName)
162
+ .join(', ');
163
+ blockingErrors.push({
164
+ code: 'WSL_FEATURES_MISSING',
165
+ message: `Required Windows features are not enabled: ${missingFeatureNames}`,
166
+ solution: 'Run this command as administrator and agree to enable the features, or manually run: wsl --install'
167
+ });
168
+ }
169
+ }
170
+ catch (error) {
171
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
172
+ blockingErrors.push({
173
+ code: 'WSL_FEATURES_CHECK_FAILED',
174
+ message: `Failed to check WSL features: ${errorMessage}`,
175
+ solution: 'Ensure you have administrator privileges and PowerShell is available. Try running as administrator.'
176
+ });
177
+ }
178
+ return {
179
+ passed: blockingErrors.length === 0,
180
+ blockingErrors,
181
+ warnings: []
182
+ };
183
+ }
184
+ };
185
+ exports.WindowsFeaturesService = WindowsFeaturesService;
186
+ exports.WindowsFeaturesService = WindowsFeaturesService = __decorate([
187
+ (0, tsyringe_1.injectable)(),
188
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.ICommandExecutor)),
189
+ __metadata("design:paramtypes", [Object])
190
+ ], WindowsFeaturesService);
191
+ //# sourceMappingURL=windows-features.service.js.map
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.WindowsInfoService = exports.MIN_WIN11_BUILD = exports.MIN_WIN10_BUILD = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const tokens_1 = require("../../../../di/tokens");
18
+ const command_builder_1 = require("../../../execution/command-builder");
19
+ const errors_1 = require("../../../errors");
20
+ /**
21
+ * Windows 支援的最低 Build 號碼
22
+ */
23
+ exports.MIN_WIN10_BUILD = 19041; // Windows 10 Version 2004
24
+ exports.MIN_WIN11_BUILD = 22000; // Windows 11
25
+ /**
26
+ * PowerShell 查詢命令
27
+ */
28
+ const PS_QUERY_COMMAND = '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, BuildNumber | ConvertTo-Json';
29
+ let WindowsInfoService = class WindowsInfoService {
30
+ constructor(commandExecutor) {
31
+ this.commandExecutor = commandExecutor;
32
+ }
33
+ async getWindowsVersion() {
34
+ // 檢查是否在 Windows 平台上執行
35
+ if (process.platform !== 'win32') {
36
+ throw new errors_1.AppError(`Unsupported platform: ${process.platform}. This tool requires Windows.`, {
37
+ exitCode: errors_1.EXIT_CODES.ENVIRONMENT_ERROR,
38
+ solution: 'This tool requires Windows 10 (Build 19041+) or Windows 11. Please run on a Windows system.',
39
+ context: { operation: 'getWindowsVersion', resource: 'Windows OS', platform: process.platform }
40
+ });
41
+ }
42
+ try {
43
+ const builder = command_builder_1.CommandBuilder.create('powershell')
44
+ .arg('-NoProfile')
45
+ .arg('-NoLogo')
46
+ .arg('-Command')
47
+ .arg(`"${PS_QUERY_COMMAND}"`);
48
+ const result = await builder.exec(this.commandExecutor);
49
+ const info = JSON.parse(result.stdout.trim());
50
+ if (!info.Caption || !info.Version || !info.BuildNumber) {
51
+ throw new Error('Invalid PowerShell output format');
52
+ }
53
+ const buildNumber = parseInt(info.BuildNumber, 10);
54
+ if (isNaN(buildNumber)) {
55
+ throw new Error(`Invalid build number: ${info.BuildNumber}`);
56
+ }
57
+ const isWindows11 = buildNumber >= exports.MIN_WIN11_BUILD;
58
+ const isSupported = buildNumber >= exports.MIN_WIN10_BUILD;
59
+ return {
60
+ productName: info.Caption,
61
+ version: info.Version,
62
+ buildNumber,
63
+ isWindows11,
64
+ isSupported
65
+ };
66
+ }
67
+ catch (error) {
68
+ if (error instanceof errors_1.AppError) {
69
+ throw error;
70
+ }
71
+ throw new errors_1.AppError('Failed to query Windows version information', {
72
+ exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
73
+ solution: 'Ensure PowerShell is available and you have permission to query system information',
74
+ cause: error,
75
+ context: { operation: 'getWindowsVersion', resource: 'PowerShell' }
76
+ });
77
+ }
78
+ }
79
+ isWindowsSupported(version) {
80
+ if (version.isWindows11) {
81
+ return true;
82
+ }
83
+ return version.buildNumber >= exports.MIN_WIN10_BUILD;
84
+ }
85
+ async checkWindowsVersionRequirement() {
86
+ const blockingErrors = [];
87
+ if (process.platform !== 'win32') {
88
+ const platformNames = {
89
+ darwin: 'macOS',
90
+ linux: 'Linux',
91
+ freebsd: 'FreeBSD',
92
+ openbsd: 'OpenBSD'
93
+ };
94
+ const platformName = platformNames[process.platform] || process.platform;
95
+ blockingErrors.push({
96
+ code: 'WIN_PLATFORM',
97
+ message: `Unsupported platform: ${process.platform} (${platformName})`,
98
+ solution: 'This tool requires Windows 10 (Build 19041+) or Windows 11. Please run on a Windows system.'
99
+ });
100
+ return {
101
+ passed: false,
102
+ blockingErrors,
103
+ warnings: []
104
+ };
105
+ }
106
+ try {
107
+ const version = await this.getWindowsVersion();
108
+ if (!version.isSupported) {
109
+ const name = version.productName.replace('Microsoft ', '');
110
+ blockingErrors.push({
111
+ code: 'WIN_VERSION',
112
+ message: `Windows version not supported: ${name} (Build ${version.buildNumber})`,
113
+ solution: `Please upgrade to Windows 10 (Build ${exports.MIN_WIN10_BUILD}) or higher. Visit https://aka.ms/wslinstall for more information.`
114
+ });
115
+ }
116
+ }
117
+ catch (error) {
118
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
119
+ blockingErrors.push({
120
+ code: 'WIN_VERSION_CHECK_FAILED',
121
+ message: `Failed to check Windows version: ${errorMessage}`,
122
+ solution: 'Ensure PowerShell is available and you have permission to query system information.'
123
+ });
124
+ }
125
+ return {
126
+ passed: blockingErrors.length === 0,
127
+ blockingErrors,
128
+ warnings: []
129
+ };
130
+ }
131
+ };
132
+ exports.WindowsInfoService = WindowsInfoService;
133
+ exports.WindowsInfoService = WindowsInfoService = __decorate([
134
+ (0, tsyringe_1.injectable)(),
135
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.ICommandExecutor)),
136
+ __metadata("design:paramtypes", [Object])
137
+ ], WindowsInfoService);
138
+ //# sourceMappingURL=windows-info.service.js.map
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.WslConfigService = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const tokens_1 = require("../../../../di/tokens");
18
+ const index_1 = require("../../../../constants/index");
19
+ const input_validator_util_1 = require("../../../utils/input-validator.util");
20
+ /**
21
+ * 延遲執行輔助函式
22
+ */
23
+ function sleep(ms) {
24
+ return new Promise((resolve) => setTimeout(resolve, ms));
25
+ }
26
+ /**
27
+ * WSL 配置服務
28
+ *
29
+ * 負責 WSL 實例的配置管理,包括建立 wsl.conf 檔案、
30
+ * 啟用 systemd、設定預設使用者等。
31
+ *
32
+ * 安全性:
33
+ * - 所有使用者輸入都經過驗證
34
+ * - 使用 CommandBuilder 避免命令注入
35
+ * - 敏感資料透過 stdin 傳遞
36
+ */
37
+ let WslConfigService = class WslConfigService {
38
+ constructor(envFactory, appLogger) {
39
+ this.envFactory = envFactory;
40
+ this.appLogger = appLogger;
41
+ }
42
+ get hostEnv() {
43
+ return this.envFactory.getHostEnvironment();
44
+ }
45
+ /**
46
+ * 生成 WSL 配置檔案內容
47
+ *
48
+ * 安全性設計:
49
+ * - [automount] enabled=false:禁用 Windows 檔案系統掛載(/mnt/c 等),
50
+ * 避免在 WSL 中誤執行 rm 等命令刪除 Windows 檔案,
51
+ * 同時讓進入 WSL 時預設目錄為用戶 home 目錄而非 Windows 路徑
52
+ * - [interop] appendWindowsPath=false:禁用 Windows PATH 附加,
53
+ * 因為 automount=false 後 Windows 路徑無法轉換,會產生警告訊息
54
+ *
55
+ * @param defaultUser 預設使用者名稱
56
+ * @returns WSL 配置檔案內容
57
+ */
58
+ generateWslConfigContent(defaultUser = 'ubuntu') {
59
+ (0, input_validator_util_1.requireValidUsername)(defaultUser);
60
+ return `[boot]
61
+ systemd=true
62
+
63
+ [user]
64
+ default=${defaultUser}
65
+
66
+ [automount]
67
+ enabled=false
68
+
69
+ [interop]
70
+ appendWindowsPath=false`;
71
+ }
72
+ async createWslConfig(instanceName, defaultUser = 'ubuntu') {
73
+ // 驗證輸入
74
+ (0, input_validator_util_1.requireValidInstanceName)(instanceName);
75
+ (0, input_validator_util_1.requireValidUsername)(defaultUser);
76
+ this.appLogger?.debug('[WSL] Creating wsl.conf', {
77
+ instanceName,
78
+ defaultUser,
79
+ component: 'WslConfigService'
80
+ });
81
+ // 生成完整的配置內容
82
+ const configContent = this.generateWslConfigContent(defaultUser);
83
+ // 使用 stdin 傳遞配置內容,避免命令注入
84
+ const env = this.envFactory.getForInstance(instanceName);
85
+ const builder = env.shellScript('cat > /etc/wsl.conf')
86
+ .stdin(configContent);
87
+ const result = await builder.exec();
88
+ if (result.exitCode !== 0) {
89
+ throw new Error(`Failed to create wsl.conf in instance '${instanceName}': ${result.stderr}`);
90
+ }
91
+ return true;
92
+ }
93
+ async restartWslInstance(instanceName) {
94
+ (0, input_validator_util_1.requireValidInstanceName)(instanceName);
95
+ // 使用 wslCmd 終止實例
96
+ const terminateBuilder = this.hostEnv.wslCmd('--terminate')
97
+ .arg(instanceName);
98
+ const terminateResult = await terminateBuilder.exec();
99
+ if (terminateResult.exitCode !== 0) {
100
+ throw new Error(`Failed to terminate instance '${instanceName}': ${terminateResult.stderr}`);
101
+ }
102
+ await sleep(index_1.TIMEOUTS.WSL_CONFIG_APPLY);
103
+ // 重啟實例
104
+ const env = this.envFactory.getForInstance(instanceName);
105
+ const restartBuilder = env.shell('exit');
106
+ const restartResult = await restartBuilder.exec();
107
+ if (restartResult.exitCode !== 0) {
108
+ throw new Error(`Failed to restart instance '${instanceName}': ${restartResult.stderr}`);
109
+ }
110
+ await sleep(index_1.TIMEOUTS.WSL_SHUTDOWN_DELAY);
111
+ }
112
+ async checkUserExists(instanceName, username) {
113
+ (0, input_validator_util_1.requireValidInstanceName)(instanceName);
114
+ (0, input_validator_util_1.requireValidUsername)(username);
115
+ try {
116
+ const env = this.envFactory.getForInstance(instanceName);
117
+ const builder = env.shell('id')
118
+ .arg(username);
119
+ const result = await builder.exec();
120
+ return result.exitCode === 0;
121
+ }
122
+ catch {
123
+ return false;
124
+ }
125
+ }
126
+ async createUser(instanceName, username = 'ubuntu') {
127
+ // 驗證輸入
128
+ (0, input_validator_util_1.requireValidInstanceName)(instanceName);
129
+ (0, input_validator_util_1.requireValidUsername)(username);
130
+ if (await this.checkUserExists(instanceName, username)) {
131
+ return true;
132
+ }
133
+ const env = this.envFactory.getForInstance(instanceName);
134
+ // 建立使用者
135
+ const createBuilder = env.shell('useradd')
136
+ .arg('-m')
137
+ .arg('-s')
138
+ .arg('/bin/bash')
139
+ .arg(username);
140
+ const createResult = await createBuilder.exec();
141
+ if (createResult.exitCode !== 0) {
142
+ throw new Error(`Failed to create user '${username}' in instance '${instanceName}': ${createResult.stderr}`);
143
+ }
144
+ // 加入 sudo 群組
145
+ const sudoGroupBuilder = env.shell('usermod')
146
+ .arg('-aG')
147
+ .arg('sudo')
148
+ .arg(username);
149
+ const sudoGroupResult = await sudoGroupBuilder.exec();
150
+ if (sudoGroupResult.exitCode !== 0) {
151
+ throw new Error(`Failed to add user '${username}' to sudo group: ${sudoGroupResult.stderr}`);
152
+ }
153
+ // 設定 sudoers 權限 - 使用 stdin 傳遞內容,避免命令注入
154
+ const sudoersContent = `${username} ALL=(ALL) NOPASSWD:ALL\n`;
155
+ const sudoersBuilder = env.shellScript(`cat > /etc/sudoers.d/${username}`)
156
+ .stdin(sudoersContent);
157
+ const sudoersResult = await sudoersBuilder.exec();
158
+ if (sudoersResult.exitCode !== 0) {
159
+ throw new Error(`Failed to configure passwordless sudo for '${username}': ${sudoersResult.stderr}`);
160
+ }
161
+ return true;
162
+ }
163
+ };
164
+ exports.WslConfigService = WslConfigService;
165
+ exports.WslConfigService = WslConfigService = __decorate([
166
+ (0, tsyringe_1.injectable)(),
167
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
168
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
169
+ __metadata("design:paramtypes", [Object, Object])
170
+ ], WslConfigService);
171
+ //# sourceMappingURL=wsl-config.service.js.map