@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,226 @@
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.WslInfoService = void 0;
16
+ const errors_1 = require("../../../errors");
17
+ const tsyringe_1 = require("tsyringe");
18
+ const tokens_1 = require("../../../../di/tokens");
19
+ const command_builder_1 = require("../../../execution/command-builder");
20
+ const wsl_version_parser_1 = require("../parsers/wsl-version.parser");
21
+ /**
22
+ * 最低建議 WSL 版本
23
+ */
24
+ const MIN_RECOMMENDED_WSL_VERSION = '2.0.0.0';
25
+ let WslInfoService = class WslInfoService {
26
+ constructor(commandExecutor) {
27
+ this.commandExecutor = commandExecutor;
28
+ }
29
+ /**
30
+ * 檢查 WSL 是否已安裝
31
+ * 使用 where.exe 檢查 wsl.exe 是否存在,避免觸發 WSL 的安裝/更新提示視窗
32
+ */
33
+ async isWslInstalled() {
34
+ try {
35
+ // 使用 where.exe 檢查 wsl.exe 是否存在,這不會觸發 WSL 的彈窗
36
+ const builder = command_builder_1.CommandBuilder.create('where.exe')
37
+ .arg('wsl.exe');
38
+ const result = await builder.exec(this.commandExecutor);
39
+ return result.exitCode === 0 && result.stdout.trim().length > 0;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ /**
46
+ * 檢查 WSL 是否需要安裝/更新
47
+ * 透過檢查 LxssManager 服務來判斷 WSL 是否已完全安裝
48
+ * 這樣可以避免觸發 WSL 的安裝/更新彈窗
49
+ */
50
+ async isWslFullyInstalled() {
51
+ // 優先檢查 Store 版本,如果已安裝 Store 版本則視為已安裝
52
+ if (await this.isStoreVersionInstalled()) {
53
+ return true;
54
+ }
55
+ try {
56
+ // 檢查 LxssManager 服務是否存在並正在執行
57
+ // 這個服務只有在 WSL 完全安裝後才會存在
58
+ const builder = command_builder_1.CommandBuilder.create('powershell')
59
+ .arg('-NoProfile')
60
+ .arg('-Command')
61
+ .arg('Get-Service LxssManager -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Status');
62
+ const result = await builder.exec(this.commandExecutor);
63
+ const status = result.stdout.trim();
64
+ // 服務狀態應該是 Running 或 Stopped
65
+ return status === 'Running' || status === 'Stopped';
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ }
71
+ /**
72
+ * 檢查是否安裝了 WSL Store 版本 (Microsoft.WSL)
73
+ * 只有 Store 版本支援 --version 命令
74
+ */
75
+ async isStoreVersionInstalled() {
76
+ try {
77
+ const builder = command_builder_1.CommandBuilder.create('powershell')
78
+ .arg('-NoProfile')
79
+ .arg('-Command')
80
+ .arg('Get-AppxPackage -Name MicrosoftCorporationII.WindowsSubsystemForLinux');
81
+ const result = await builder.exec(this.commandExecutor);
82
+ return result.stdout.trim().length > 0;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ }
88
+ /**
89
+ * 取得 WSL 版本資訊
90
+ */
91
+ async getWslVersionInfo() {
92
+ // 檢查 WSL 是否已安裝
93
+ if (!await this.isWslInstalled()) {
94
+ return {
95
+ installed: false
96
+ };
97
+ }
98
+ // 檢查 WSL 是否完全安裝(避免觸發安裝彈窗)
99
+ if (!await this.isWslFullyInstalled()) {
100
+ return {
101
+ installed: false,
102
+ needsInstall: true
103
+ };
104
+ }
105
+ try {
106
+ let wslVersion;
107
+ let kernelVersion;
108
+ // 只有 Store 版本才支援 --version 命令
109
+ // 如果是 Inbox 版本,執行 --version 可能會失敗或觸發安裝提示
110
+ if (await this.isStoreVersionInstalled()) {
111
+ try {
112
+ // 使用 --version 檢查版本
113
+ const versionBuilder = command_builder_1.CommandBuilder.create('wsl')
114
+ .arg('--version');
115
+ const versionResult = await versionBuilder.exec(this.commandExecutor);
116
+ const versionOutput = versionResult.stdout;
117
+ // 使用 Parser 解析版本資訊(支援多語系)
118
+ wslVersion = wsl_version_parser_1.WslVersionParser.parseWslVersion(versionOutput) ?? undefined;
119
+ kernelVersion = wsl_version_parser_1.WslVersionParser.parseKernelVersion(versionOutput) ?? undefined;
120
+ }
121
+ catch {
122
+ // 忽略錯誤,保持 undefined
123
+ }
124
+ }
125
+ // 執行 wsl --status 取得預設版本
126
+ let defaultVersion;
127
+ try {
128
+ const statusBuilder = command_builder_1.CommandBuilder.create('wsl')
129
+ .arg('--status');
130
+ const statusResult = await statusBuilder.exec(this.commandExecutor);
131
+ const statusOutput = statusResult.stdout;
132
+ // 使用 Parser 解析預設版本(支援多語系)
133
+ defaultVersion = wsl_version_parser_1.WslVersionParser.parseDefaultVersion(statusOutput) ?? undefined;
134
+ }
135
+ catch {
136
+ // wsl --status 可能在某些舊版本中不可用,不影響主要流程
137
+ defaultVersion = undefined;
138
+ }
139
+ return {
140
+ installed: true,
141
+ wslVersion,
142
+ kernelVersion,
143
+ defaultVersion
144
+ };
145
+ }
146
+ catch (err) {
147
+ throw new errors_1.AppError('Failed to get WSL version information', {
148
+ exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
149
+ solution: 'Ensure WSL is properly installed and accessible. Try running: wsl --version',
150
+ cause: err instanceof Error ? err : undefined,
151
+ context: { operation: 'getWslVersionInfo', resource: 'WSL' }
152
+ });
153
+ }
154
+ }
155
+ /**
156
+ * 比較兩個版本號碼
157
+ */
158
+ compareVersions(version1, version2) {
159
+ const parts1 = version1.split('.').map(Number);
160
+ const parts2 = version2.split('.').map(Number);
161
+ const maxLength = Math.max(parts1.length, parts2.length);
162
+ for (let i = 0; i < maxLength; i++) {
163
+ const part1 = parts1[i] || 0;
164
+ const part2 = parts2[i] || 0;
165
+ if (part1 < part2)
166
+ return -1;
167
+ if (part1 > part2)
168
+ return 1;
169
+ }
170
+ return 0;
171
+ }
172
+ /**
173
+ * 檢查 WSL 更新需求
174
+ */
175
+ checkWslUpdateRequirement(versionInfo) {
176
+ const steps = [];
177
+ let needsUpdate = false;
178
+ let needsDefaultVersion = false;
179
+ // 檢查是否已安裝
180
+ if (!versionInfo.installed) {
181
+ throw new errors_1.AppError('WSL is not installed', {
182
+ exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
183
+ solution: 'Install WSL by running: wsl --install (requires administrator privileges)',
184
+ context: { operation: 'checkWslUpdateRequirement', resource: 'WSL' }
185
+ });
186
+ }
187
+ // 檢查是否需要更新 WSL 版本
188
+ if (versionInfo.wslVersion) {
189
+ if (this.compareVersions(versionInfo.wslVersion, MIN_RECOMMENDED_WSL_VERSION) < 0) {
190
+ needsUpdate = true;
191
+ steps.push('Update WSL to the latest version');
192
+ }
193
+ }
194
+ else {
195
+ // 如果無法取得版本資訊,建議更新
196
+ needsUpdate = true;
197
+ steps.push('Update WSL to the latest version');
198
+ }
199
+ // 檢查預設版本是否為 WSL 2
200
+ if (versionInfo.defaultVersion !== undefined) {
201
+ if (versionInfo.defaultVersion !== 2) {
202
+ needsDefaultVersion = true;
203
+ steps.push('Set WSL 2 as default version');
204
+ }
205
+ }
206
+ else {
207
+ // 如果無法取得預設版本,建議設定
208
+ needsDefaultVersion = true;
209
+ steps.push('Set WSL 2 as default version');
210
+ }
211
+ return {
212
+ needsUpdate,
213
+ needsDefaultVersion,
214
+ currentVersion: versionInfo.wslVersion,
215
+ currentDefaultVersion: versionInfo.defaultVersion,
216
+ steps
217
+ };
218
+ }
219
+ };
220
+ exports.WslInfoService = WslInfoService;
221
+ exports.WslInfoService = WslInfoService = __decorate([
222
+ (0, tsyringe_1.injectable)(),
223
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.ICommandExecutor)),
224
+ __metadata("design:paramtypes", [Object])
225
+ ], WslInfoService);
226
+ //# sourceMappingURL=wsl-info.service.js.map
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ 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;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
45
+ return function (target, key) { decorator(target, key, paramIndex); }
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.WslInstanceInspectionService = void 0;
49
+ const tsyringe_1 = require("tsyringe");
50
+ const fs = __importStar(require("fs"));
51
+ const path = __importStar(require("path"));
52
+ const tokens_1 = require("../../../../di/tokens");
53
+ const command_builder_1 = require("../../../execution/command-builder");
54
+ const paths_1 = require("../../../../constants/paths");
55
+ const input_validator_util_1 = require("../../../utils/input-validator.util");
56
+ /**
57
+ * WSL 實例檢視服務
58
+ *
59
+ * 合併了原 WslInstanceScannerService 和 WslInstanceQueryService 的功能
60
+ * 負責掃描、查詢 WSL 實例的狀態和存在性
61
+ */
62
+ let WslInstanceInspectionService = class WslInstanceInspectionService {
63
+ constructor(commandExecutor, envFactory, appLogger) {
64
+ this.commandExecutor = commandExecutor;
65
+ this.envFactory = envFactory;
66
+ this.appLogger = appLogger;
67
+ }
68
+ get hostEnv() {
69
+ return this.envFactory.getHostEnvironment();
70
+ }
71
+ // ===========================================================================
72
+ // Scan Methods (原 WslInstanceScannerService)
73
+ // ===========================================================================
74
+ /**
75
+ * 掃描所有 WSL 實例
76
+ * @returns 所有實例的列表
77
+ */
78
+ async scanAllInstances() {
79
+ this.appLogger?.debug('[WSL] Scanning all instances', {
80
+ component: 'WslInstanceInspectionService'
81
+ });
82
+ try {
83
+ const builder = command_builder_1.CommandBuilder.create('wsl')
84
+ .arg('--list')
85
+ .arg('--verbose');
86
+ const result = await builder.exec(this.commandExecutor);
87
+ const output = result.stdout;
88
+ const lines = output.split('\n');
89
+ const instances = [];
90
+ // 跳過標題行 (NAME STATE VERSION)
91
+ for (let i = 1; i < lines.length; i++) {
92
+ const line = lines[i].trim();
93
+ if (!line)
94
+ continue;
95
+ // 解析實例資訊
96
+ // 格式: [*] NAME STATE VERSION
97
+ // 某些版本的 WSL 輸出 "Running" 或 "Stopped" (英文)
98
+ const match = line.match(/^(\*?)\s*(\S+)\s+(Running|Stopped)\s+(\d+)/);
99
+ if (match) {
100
+ const [, defaultMarker, name, state, version] = match;
101
+ instances.push({
102
+ name,
103
+ state: state,
104
+ version: parseInt(version, 10),
105
+ isDefault: !!defaultMarker
106
+ });
107
+ }
108
+ }
109
+ return instances;
110
+ }
111
+ catch {
112
+ return [];
113
+ }
114
+ }
115
+ /**
116
+ * 掃描 uofx 相關的實例
117
+ * @returns uofx 實例掃描結果
118
+ */
119
+ async scanUofxInstances() {
120
+ const allInstances = await this.scanAllInstances();
121
+ const instances = allInstances.filter(instance => instance.name.startsWith('uofx-'));
122
+ const runningInstances = instances.filter(instance => instance.state === 'Running');
123
+ return {
124
+ instances,
125
+ runningInstances,
126
+ totalCount: instances.length,
127
+ runningCount: runningInstances.length
128
+ };
129
+ }
130
+ /**
131
+ * 掃描其他 WSL 實例(排除 uofx- 開頭的實例)
132
+ * @returns 其他實例名稱列表
133
+ */
134
+ async scanOtherInstances() {
135
+ const allInstances = await this.scanAllInstances();
136
+ return allInstances
137
+ .filter(instance => !instance.name.startsWith('uofx-'))
138
+ .map(instance => instance.name);
139
+ }
140
+ /**
141
+ * 取得共享資源上下文
142
+ * 包含容器執行環境和其他 WSL 實例資訊
143
+ * @returns 共享資源上下文
144
+ */
145
+ async getSharedResourceContext() {
146
+ const containerRuntime = this.detectContainerRuntime();
147
+ const otherInstances = await this.scanOtherInstances();
148
+ const hasSharedResources = containerRuntime !== null || otherInstances.length > 0;
149
+ return {
150
+ containerRuntime,
151
+ otherInstances,
152
+ hasSharedResources
153
+ };
154
+ }
155
+ /**
156
+ * 格式化掃描結果為可讀字串
157
+ * @param scanResult - 掃描結果
158
+ * @returns 格式化後的字串
159
+ */
160
+ formatScanResult(scanResult) {
161
+ const { instances, runningInstances, totalCount, runningCount } = scanResult;
162
+ if (totalCount === 0) {
163
+ return ' No existing uofx instances found';
164
+ }
165
+ const lines = [];
166
+ lines.push(`Found ${totalCount} uofx instance${totalCount > 1 ? 's' : ''}:`);
167
+ instances.forEach(instance => {
168
+ const status = instance.state === 'Running' ? '✓' : '✗';
169
+ lines.push(` ${status} ${instance.name} (${instance.state})`);
170
+ });
171
+ if (runningCount > 0) {
172
+ lines.push('');
173
+ lines.push(`Warning: ${runningCount} instance${runningCount > 1 ? 's are' : ' is'} currently running`);
174
+ runningInstances.forEach(instance => {
175
+ lines.push(` • ${instance.name}`);
176
+ });
177
+ lines.push('Only one instance can run at a time.');
178
+ if (runningCount === 1) {
179
+ lines.push(`Use 'uofx env stop --name ${runningInstances[0].name.replace('uofx-', '')}' to stop it.`);
180
+ }
181
+ }
182
+ return lines.join('\n');
183
+ }
184
+ /**
185
+ * 偵測容器執行環境
186
+ * @returns 偵測到的執行環境 ('docker-desktop' | 'podman-desktop' | null)
187
+ */
188
+ detectContainerRuntime() {
189
+ const programFiles = process.env.PROGRAMFILES || 'C:\\Program Files';
190
+ const dockerPaths = [
191
+ path.join('C:\\Program Files', paths_1.WINDOWS_PATHS.DOCKER_DESKTOP),
192
+ path.join(programFiles, paths_1.WINDOWS_PATHS.DOCKER_DESKTOP)
193
+ ];
194
+ for (const dockerPath of dockerPaths) {
195
+ if (fs.existsSync(dockerPath)) {
196
+ return 'docker-desktop';
197
+ }
198
+ }
199
+ const podmanPaths = [
200
+ path.join('C:\\Program Files', paths_1.WINDOWS_PATHS.PODMAN_DESKTOP),
201
+ path.join(programFiles, paths_1.WINDOWS_PATHS.PODMAN_DESKTOP)
202
+ ];
203
+ for (const podmanPath of podmanPaths) {
204
+ if (fs.existsSync(podmanPath)) {
205
+ return 'podman-desktop';
206
+ }
207
+ }
208
+ return null;
209
+ }
210
+ // ===========================================================================
211
+ // Query Methods (原 WslInstanceQueryService)
212
+ // ===========================================================================
213
+ /**
214
+ * 檢查 WSL 實例是否存在
215
+ * @param instanceName 實例名稱
216
+ * @returns 是否存在
217
+ */
218
+ async checkInstanceExists(instanceName) {
219
+ try {
220
+ const instances = await this.scanAllInstances();
221
+ return instances.some(inst => inst.name === instanceName);
222
+ }
223
+ catch (error) {
224
+ this.appLogger?.debug('[WSL] Instance existence check failed (assuming false)', {
225
+ instanceName,
226
+ error,
227
+ component: 'WslInstanceInspectionService'
228
+ });
229
+ return false;
230
+ }
231
+ }
232
+ /**
233
+ * 取得實例狀態
234
+ * @param instanceName 實例名稱
235
+ * @returns 實例狀態
236
+ */
237
+ async getInstanceStatus(instanceName) {
238
+ try {
239
+ const instances = await this.scanAllInstances();
240
+ const instance = instances.find(inst => inst.name === instanceName);
241
+ if (!instance) {
242
+ return { name: instanceName, running: false };
243
+ }
244
+ const isRunning = instance.state === 'Running';
245
+ let uptime;
246
+ if (isRunning) {
247
+ try {
248
+ const env = this.envFactory.getForInstance(instanceName);
249
+ const uptimeBuilder = env.shell('cat')
250
+ .arg('/proc/uptime');
251
+ const uptimeResult = await uptimeBuilder.exec();
252
+ if (uptimeResult.exitCode === 0) {
253
+ uptime = parseFloat(uptimeResult.stdout.split(' ')[0]);
254
+ }
255
+ }
256
+ catch {
257
+ // Ignore
258
+ }
259
+ }
260
+ const status = { name: instanceName, running: isRunning, uptime };
261
+ return status;
262
+ }
263
+ catch (error) {
264
+ this.appLogger?.error(error instanceof Error ? error : new Error(String(error)), {
265
+ operation: 'getInstanceStatus',
266
+ instanceName,
267
+ });
268
+ return { name: instanceName, running: false };
269
+ }
270
+ }
271
+ /**
272
+ * 列出所有正在運行的 uofx 實例
273
+ * @returns 實例名稱陣列
274
+ */
275
+ async listRunningInstances() {
276
+ try {
277
+ const builder = this.hostEnv.wslCmd('--list')
278
+ .arg('--verbose');
279
+ const result = await builder.exec();
280
+ const lines = result.stdout.split('\n').slice(1);
281
+ return lines
282
+ .filter((line) => line.trim())
283
+ .filter((line) => line.includes('Running') || line.includes('執行'))
284
+ .map((line) => {
285
+ const match = line.replace('*', '').trim().match(/^([^\s]+)/);
286
+ return match ? match[1] : '';
287
+ })
288
+ .filter((name) => name.startsWith('uofx-') && name !== '');
289
+ }
290
+ catch {
291
+ return [];
292
+ }
293
+ }
294
+ /**
295
+ * 驗證實例建立成功 (執行 echo 測試)
296
+ * @param instanceName 實例名稱
297
+ * @returns 是否驗證成功
298
+ */
299
+ async verifyInstance(instanceName) {
300
+ (0, input_validator_util_1.requireValidInstanceName)(instanceName);
301
+ const exists = await this.checkInstanceExists(instanceName);
302
+ if (!exists) {
303
+ return false;
304
+ }
305
+ try {
306
+ const env = this.envFactory.getForInstance(instanceName);
307
+ const builder = env.shell('echo')
308
+ .arg('test');
309
+ const result = await builder.exec();
310
+ return result.exitCode === 0 && result.stdout.includes('test');
311
+ }
312
+ catch {
313
+ return false;
314
+ }
315
+ }
316
+ };
317
+ exports.WslInstanceInspectionService = WslInstanceInspectionService;
318
+ exports.WslInstanceInspectionService = WslInstanceInspectionService = __decorate([
319
+ (0, tsyringe_1.injectable)(),
320
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.ICommandExecutor)),
321
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IExecutionEnvironmentFactory)),
322
+ __param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
323
+ __metadata("design:paramtypes", [Object, Object, Object])
324
+ ], WslInstanceInspectionService);
325
+ //# sourceMappingURL=wsl-instance-inspection.service.js.map