@uofx/cli 1.0.2 → 1.1.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 (240) hide show
  1. package/README.md +159 -3
  2. package/THIRD-PARTY-NOTICES.txt +84 -2
  3. package/dist/application/dtos/config/index.js +22 -0
  4. package/dist/application/dtos/config/request/index.js +19 -0
  5. package/dist/application/dtos/config/request/set-config.request.dto.js +3 -0
  6. package/dist/application/dtos/config/response/get-config.response.dto.js +8 -0
  7. package/dist/application/dtos/config/response/index.js +21 -0
  8. package/dist/application/dtos/dev/index.js +24 -0
  9. package/dist/application/dtos/dev/request/generate-component.request.dto.js +3 -0
  10. package/dist/application/dtos/dev/request/index.js +25 -0
  11. package/dist/application/dtos/dev/request/install-template.request.dto.js +3 -0
  12. package/dist/application/dtos/dev/request/new-project.request.dto.js +3 -0
  13. package/dist/application/dtos/dev/request/publish-plugin.request.dto.js +3 -0
  14. package/dist/application/dtos/dev/request/uninstall-template.request.dto.js +3 -0
  15. package/dist/application/dtos/dev/response/generate-component.response.dto.js +3 -0
  16. package/dist/application/dtos/dev/response/index.js +24 -0
  17. package/dist/application/dtos/dev/response/new-project.response.dto.js +3 -0
  18. package/dist/application/dtos/dev/response/publish-plugin.response.dto.js +3 -0
  19. package/dist/application/dtos/dev/response/template-info.response.dto.js +3 -0
  20. package/dist/application/dtos/env/index.js +24 -0
  21. package/dist/application/dtos/{request → env/request}/index.js +1 -3
  22. package/dist/application/dtos/env/request/list-running-instances.request.dto.js +3 -0
  23. package/dist/application/dtos/{response → env/response}/index.js +1 -1
  24. package/dist/application/dtos/env/response/list-running-instances.response.dto.js +3 -0
  25. package/dist/application/dtos/index.js +9 -2
  26. package/dist/application/dtos/logs/index.js +22 -0
  27. package/dist/application/dtos/logs/request/index.js +18 -0
  28. package/dist/application/dtos/logs/response/index.js +18 -0
  29. package/dist/application/index.js +1 -0
  30. package/dist/application/services/env/environment-validator.service.js +120 -0
  31. package/dist/application/services/env/index.js +11 -0
  32. package/dist/application/services/env/instance-cleanup.service.js +79 -0
  33. package/dist/application/services/index.js +21 -0
  34. package/dist/application/use-cases/config/get-all-config.use-case.js +54 -0
  35. package/dist/application/use-cases/config/get-config.use-case.js +7 -17
  36. package/dist/application/use-cases/config/index.js +23 -0
  37. package/dist/application/use-cases/config/set-config.use-case.js +49 -3
  38. package/dist/application/use-cases/dev/generate-component.use-case.js +138 -0
  39. package/dist/application/use-cases/dev/index.js +28 -0
  40. package/dist/application/use-cases/dev/install-template.use-case.js +60 -0
  41. package/dist/application/use-cases/dev/list-templates.use-case.js +45 -0
  42. package/dist/application/use-cases/dev/new-project.use-case.js +130 -0
  43. package/dist/application/use-cases/dev/publish-plugin.use-case.js +243 -0
  44. package/dist/application/use-cases/dev/uninstall-template.use-case.js +50 -0
  45. package/dist/application/use-cases/{instance → env}/delete-instance.use-case.js +2 -2
  46. package/dist/application/use-cases/{credentials → env}/get-credentials.use-case.js +1 -1
  47. package/dist/application/use-cases/{instance → env}/index.js +11 -0
  48. package/dist/application/use-cases/{instance → env}/install-instance.use-case.js +25 -136
  49. package/dist/application/use-cases/env/list-running-instances.use-case.js +47 -0
  50. package/dist/application/use-cases/{setup → env}/setup-environment.use-case.js +35 -4
  51. package/dist/application/use-cases/{instance → env}/start-instance.use-case.js +53 -41
  52. package/dist/application/use-cases/index.js +9 -6
  53. package/dist/application/use-cases/logs/index.js +21 -0
  54. package/dist/cli.js +175 -26
  55. package/dist/constants/defaults.js +8 -1
  56. package/dist/constants/oci-artifacts.js +4 -0
  57. package/dist/constants/paths.js +0 -4
  58. package/dist/constants/timeouts.js +5 -0
  59. package/dist/di/modules/application.module.js +13 -44
  60. package/dist/di/modules/config.module.js +19 -0
  61. package/dist/di/modules/dev.module.js +45 -0
  62. package/dist/di/modules/env.module.js +42 -0
  63. package/dist/di/modules/index.js +30 -0
  64. package/dist/di/modules/infrastructure.module.js +65 -82
  65. package/dist/di/modules/logs.module.js +15 -0
  66. package/dist/di/modules/presentation.module.js +18 -7
  67. package/dist/di/tokens.js +42 -30
  68. package/dist/domain/entities/credentials-resolver.entity.js +4 -1
  69. package/dist/domain/entities/credentials.entity.js +2 -5
  70. package/dist/domain/entities/delete-instance-validation.entity.js +4 -1
  71. package/dist/domain/entities/deployment-parameters.entity.js +11 -8
  72. package/dist/domain/entities/index.js +5 -1
  73. package/dist/domain/entities/instance-list-aggregator.entity.js +2 -2
  74. package/dist/domain/entities/instance-metadata.entity.js +2 -3
  75. package/dist/domain/entities/instance.entity.js +2 -1
  76. package/dist/domain/entities/log-filter.entity.js +6 -6
  77. package/dist/domain/entities/template-info.entity.js +63 -0
  78. package/dist/{infrastructure/utils/error-formatter.util.js → domain/errors/error-utils.js} +1 -1
  79. package/dist/domain/errors/index.js +19 -0
  80. package/dist/domain/index.js +6 -0
  81. package/dist/domain/interfaces/index.js +21 -0
  82. package/dist/domain/ports/dotnet-publisher.port.js +9 -0
  83. package/dist/{infrastructure/http/interfaces/http-client.interface.js → domain/ports/file-system.port.js} +1 -1
  84. package/dist/domain/ports/http-client.port.js +3 -0
  85. package/dist/domain/ports/index.js +10 -0
  86. package/dist/domain/ports/logger.port.js +3 -3
  87. package/dist/domain/ports/progress.port.js +10 -0
  88. package/dist/domain/ports/project-scaffolder.port.js +9 -0
  89. package/dist/domain/ports/schematics-runner.port.js +9 -0
  90. package/dist/domain/ports/template-manager.port.js +9 -0
  91. package/dist/domain/ports/wsl-setup.port.js +3 -0
  92. package/dist/domain/types/index.js +1 -0
  93. package/dist/domain/value-objects/acr-credentials.value-object.js +13 -1
  94. package/dist/domain/value-objects/chart-version.value-object.js +20 -3
  95. package/dist/domain/value-objects/config-log-level.value-object.js +2 -1
  96. package/dist/domain/value-objects/index.js +3 -1
  97. package/dist/domain/value-objects/instance-name.value-object.js +6 -3
  98. package/dist/domain/value-objects/jwt-key.value-object.js +27 -5
  99. package/dist/domain/value-objects/mssql-password.value-object.js +27 -5
  100. package/dist/domain/value-objects/output-path.value-object.js +85 -0
  101. package/dist/domain/value-objects/rsa-key-pair.value-object.js +29 -3
  102. package/dist/index.js +6 -1
  103. package/dist/infrastructure/config/{app-config.service.js → app-config.adapter.js} +29 -17
  104. package/dist/infrastructure/config/{config-validator.js → config-validator.util.js} +1 -1
  105. package/dist/infrastructure/config/index.js +14 -0
  106. package/dist/infrastructure/config/interfaces/index.js +3 -0
  107. package/dist/infrastructure/config/{crypto.service.js → services/crypto.service.js} +4 -1
  108. package/dist/infrastructure/config/services/index.js +9 -0
  109. package/dist/infrastructure/deployment/deployment.adapter.js +5 -5
  110. package/dist/infrastructure/deployment/index.js +9 -0
  111. package/dist/infrastructure/deployment/interfaces/index.js +3 -0
  112. package/dist/infrastructure/deployment/services/acr-credential-manager.service.js +18 -7
  113. package/dist/infrastructure/deployment/services/app-manager.service.js +3 -3
  114. package/dist/infrastructure/deployment/services/base-helm-deployment.service.js +13 -5
  115. package/dist/infrastructure/deployment/services/helm-registry.service.js +10 -3
  116. package/dist/infrastructure/deployment/services/index.js +35 -0
  117. package/dist/infrastructure/deployment/services/infra-manager.service.js +19 -15
  118. package/dist/infrastructure/deployment/services/k8s-job-runner.service.js +24 -6
  119. package/dist/infrastructure/deployment/services/mssql-database-init.service.js +75 -11
  120. package/dist/infrastructure/deployment/services/mssql-helm-deployment.service.js +17 -5
  121. package/dist/infrastructure/deployment/services/mssql-storage.service.js +5 -1
  122. package/dist/infrastructure/deployment/services/mssql-user-manager.service.js +7 -3
  123. package/dist/infrastructure/deployment/services/oci-artifact.service.js +8 -3
  124. package/dist/infrastructure/deployment/services/secret-manager.service.js +14 -5
  125. package/dist/infrastructure/deployment/services/service-manager.service.js +1 -1
  126. package/dist/infrastructure/deployment/services/version-compatibility.service.js +9 -5
  127. package/dist/infrastructure/dotnet/dotnet-publisher.adapter.js +143 -0
  128. package/dist/infrastructure/dotnet/index.js +9 -0
  129. package/dist/infrastructure/environment/index.js +11 -0
  130. package/dist/infrastructure/environment/interfaces/index.js +3 -0
  131. package/dist/infrastructure/{platform-detector.js → environment/platform-detector.util.js} +1 -1
  132. package/dist/infrastructure/environment/services/hardware-info.service.js +8 -8
  133. package/dist/infrastructure/environment/services/index.js +11 -0
  134. package/dist/infrastructure/errors/{error-handler.js → error-handler.adapter.js} +17 -17
  135. package/dist/infrastructure/errors/index.js +5 -21
  136. package/dist/infrastructure/execution/builders/base-command.builder.js +32 -11
  137. package/dist/infrastructure/execution/builders/index.js +26 -0
  138. package/dist/infrastructure/execution/builders/wsl-command.builder.js +39 -1
  139. package/dist/infrastructure/execution/command-builder.util.js +94 -0
  140. package/dist/infrastructure/execution/environments/index.js +23 -0
  141. package/dist/infrastructure/execution/environments/wsl-execution.environment.js +22 -7
  142. package/dist/infrastructure/execution/index.js +1 -2
  143. package/dist/infrastructure/execution/services/command-executor.service.js +389 -0
  144. package/dist/infrastructure/execution/services/index.js +8 -0
  145. package/dist/infrastructure/execution/{script-executor.service.js → services/script-executor.service.js} +12 -15
  146. package/dist/infrastructure/filesystem/filesystem.adapter.js +86 -0
  147. package/dist/infrastructure/filesystem/index.js +23 -0
  148. package/dist/infrastructure/http/{http-client.service.js → http-client.adapter.js} +20 -13
  149. package/dist/infrastructure/http/index.js +1 -1
  150. package/dist/infrastructure/interceptors/decorators/index.js +23 -0
  151. package/dist/infrastructure/interceptors/index.js +2 -2
  152. package/dist/infrastructure/interceptors/interceptor.factory.js +3 -3
  153. package/dist/infrastructure/interceptors/interfaces/index.js +3 -0
  154. package/dist/infrastructure/interceptors/services/index.js +6 -0
  155. package/dist/infrastructure/interceptors/{logging.interceptor.js → services/logging-interceptor.service.js} +4 -4
  156. package/dist/infrastructure/logger/services/file-log-reader.repository.js +1 -1
  157. package/dist/infrastructure/logger/services/file-log-writer.repository.js +1 -1
  158. package/dist/infrastructure/persistence/instance-metadata.adapter.js +2 -1
  159. package/dist/infrastructure/persistence/services/file-system-config.repository.js +10 -4
  160. package/dist/infrastructure/persistence/services/file-system-instance.repository.js +2 -2
  161. package/dist/infrastructure/platforms/index.js +18 -0
  162. package/dist/infrastructure/platforms/windows/index.js +13 -0
  163. package/dist/infrastructure/platforms/windows/interfaces/index.js +3 -0
  164. package/dist/infrastructure/platforms/windows/parsers/index.js +9 -0
  165. package/dist/infrastructure/platforms/windows/services/index.js +33 -0
  166. package/dist/infrastructure/platforms/windows/services/microk8s.service.js +28 -10
  167. package/dist/infrastructure/platforms/windows/services/rootfs-manager.service.js +7 -3
  168. package/dist/infrastructure/platforms/windows/services/windows-features.service.js +22 -8
  169. package/dist/infrastructure/platforms/windows/services/windows-info.service.js +10 -6
  170. package/dist/infrastructure/platforms/windows/services/wsl-config.service.js +15 -6
  171. package/dist/infrastructure/platforms/windows/services/wsl-info.service.js +12 -12
  172. package/dist/infrastructure/platforms/windows/services/wsl-instance-inspection.service.js +3 -3
  173. package/dist/infrastructure/platforms/windows/services/wsl-instance-lifecycle.service.js +76 -22
  174. package/dist/infrastructure/platforms/windows/services/wsl-updater.service.js +20 -15
  175. package/dist/infrastructure/platforms/windows/services/wslconfig-parser.service.js +3 -3
  176. package/dist/infrastructure/platforms/windows/wsl-instance-manager.adapter.js +8 -3
  177. package/dist/infrastructure/platforms/windows/wsl-setup.adapter.js +100 -0
  178. package/dist/infrastructure/schematics/index.js +11 -0
  179. package/dist/infrastructure/schematics/project-scaffolder.adapter.js +314 -0
  180. package/dist/infrastructure/schematics/schematics-runner.adapter.js +175 -0
  181. package/dist/infrastructure/template/index.js +25 -0
  182. package/dist/infrastructure/template/interfaces/index.js +22 -0
  183. package/dist/infrastructure/template/interfaces/template-downloader.interface.js +6 -0
  184. package/dist/infrastructure/template/interfaces/template-registry.interface.js +6 -0
  185. package/dist/infrastructure/template/services/index.js +24 -0
  186. package/dist/infrastructure/template/services/template-downloader.service.js +319 -0
  187. package/dist/infrastructure/template/services/template-registry.service.js +175 -0
  188. package/dist/infrastructure/template/template-manager.adapter.js +196 -0
  189. package/dist/infrastructure/utils/index.js +23 -0
  190. package/dist/infrastructure/utils/input-validator.util.js +7 -6
  191. package/dist/presentation/controllers/base.controller.js +36 -0
  192. package/dist/presentation/controllers/{config.controller.js → config/config.controller.js} +17 -62
  193. package/dist/presentation/controllers/config/index.js +21 -0
  194. package/dist/presentation/controllers/dev/dev.controller.js +202 -0
  195. package/dist/presentation/controllers/dev/index.js +23 -0
  196. package/dist/presentation/controllers/dev/template.controller.js +158 -0
  197. package/dist/presentation/controllers/{credentials.controller.js → env/credentials.controller.js} +8 -14
  198. package/dist/presentation/controllers/env/index.js +23 -0
  199. package/dist/presentation/controllers/{instance.controller.js → env/instance.controller.js} +35 -92
  200. package/dist/presentation/controllers/{setup.controller.js → env/setup.controller.js} +33 -66
  201. package/dist/presentation/controllers/index.js +9 -5
  202. package/dist/presentation/controllers/logs/index.js +21 -0
  203. package/dist/presentation/controllers/{logs.controller.js → logs/logs.controller.js} +8 -14
  204. package/dist/presentation/interfaces/index.js +21 -0
  205. package/dist/presentation/prompts/acr-credentials.prompt.js +37 -9
  206. package/dist/presentation/ui/constants/index.js +23 -0
  207. package/dist/presentation/ui/interaction.service.js +4 -4
  208. package/dist/presentation/ui/interfaces/cli-progress.interface.js +0 -6
  209. package/dist/presentation/ui/interfaces/index.js +6 -0
  210. package/package.json +6 -1
  211. package/dist/application/dtos/request/set-config.request.dto.js +0 -16
  212. package/dist/infrastructure/errors/error-handler.interface.js +0 -3
  213. package/dist/infrastructure/execution/command-builder.js +0 -252
  214. package/dist/infrastructure/execution/command-executor.service.js +0 -230
  215. /package/dist/application/dtos/{request → config/request}/get-config.request.dto.js +0 -0
  216. /package/dist/application/dtos/{request → env/request}/delete-instance.request.dto.js +0 -0
  217. /package/dist/application/dtos/{request → env/request}/get-credentials.request.dto.js +0 -0
  218. /package/dist/application/dtos/{request → env/request}/install-instance.request.dto.js +0 -0
  219. /package/dist/application/dtos/{request → env/request}/list-charts.request.dto.js +0 -0
  220. /package/dist/application/dtos/{request → env/request}/setup-environment.request.dto.js +0 -0
  221. /package/dist/application/dtos/{request → env/request}/start-instance.request.dto.js +0 -0
  222. /package/dist/application/dtos/{request → env/request}/stop-instance.request.dto.js +0 -0
  223. /package/dist/application/dtos/{response → env/response}/credentials.response.dto.js +0 -0
  224. /package/dist/application/dtos/{response → env/response}/delete-instance.response.dto.js +0 -0
  225. /package/dist/application/dtos/{response → env/response}/install-instance.response.dto.js +0 -0
  226. /package/dist/application/dtos/{response → env/response}/instance-list.response.dto.js +0 -0
  227. /package/dist/application/dtos/{response → env/response}/instance-status.response.dto.js +0 -0
  228. /package/dist/application/dtos/{response → env/response}/setup-result.response.dto.js +0 -0
  229. /package/dist/application/dtos/{response → env/response}/start-instance.response.dto.js +0 -0
  230. /package/dist/application/dtos/{response → env/response}/stop-instance.response.dto.js +0 -0
  231. /package/dist/application/dtos/{request → logs/request}/show-logs.request.dto.js +0 -0
  232. /package/dist/application/dtos/{response → logs/response}/show-logs.response.dto.js +0 -0
  233. /package/dist/application/use-cases/{instance → env}/list-charts.use-case.js +0 -0
  234. /package/dist/application/use-cases/{instance → env}/list-instances.use-case.js +0 -0
  235. /package/dist/application/use-cases/{instance → env}/stop-instance.use-case.js +0 -0
  236. /package/dist/{infrastructure → domain}/errors/app-error.js +0 -0
  237. /package/dist/{infrastructure → domain}/errors/exit-codes.js +0 -0
  238. /package/dist/infrastructure/config/{app-config.interface.js → interfaces/app-config.interface.js} +0 -0
  239. /package/dist/{domain → infrastructure/interceptors}/decorators/sensitive.decorator.js +0 -0
  240. /package/dist/infrastructure/interceptors/{interceptor.interface.js → interfaces/interceptor.interface.js} +0 -0
@@ -0,0 +1,314 @@
1
+ "use strict";
2
+ /**
3
+ * Project Scaffolder Adapter
4
+ *
5
+ * 實作 IProjectScaffolderPort 介面
6
+ * 從已安裝的樣板複製並初始化新專案
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
25
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
26
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
27
+ 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;
28
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
29
+ };
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ var __metadata = (this && this.__metadata) || function (k, v) {
48
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
49
+ };
50
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
51
+ return function (target, key) { decorator(target, key, paramIndex); }
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.ProjectScaffolderAdapter = void 0;
55
+ const tsyringe_1 = require("tsyringe");
56
+ const fs = __importStar(require("fs"));
57
+ const path = __importStar(require("path"));
58
+ const tokens_1 = require("../../di/tokens");
59
+ const timeouts_1 = require("../../constants/timeouts");
60
+ const defaults_1 = require("../../constants/defaults");
61
+ const platform_detector_util_1 = require("../environment/platform-detector.util");
62
+ let ProjectScaffolderAdapter = class ProjectScaffolderAdapter {
63
+ constructor(logger, commandExecutor) {
64
+ this.logger = logger;
65
+ this.commandExecutor = commandExecutor;
66
+ }
67
+ /**
68
+ * 從樣板建立新專案
69
+ * @param options - 專案建立選項
70
+ * @param output - 輸出端口,用於回報進度
71
+ * @returns 專案建立結果
72
+ */
73
+ async scaffold(options, output) {
74
+ try {
75
+ // 檢查樣板路徑是否存在
76
+ if (!fs.existsSync(options.templatePath)) {
77
+ const msg = `Template path not found: ${options.templatePath}`;
78
+ output?.error(msg).flush();
79
+ return { success: false, message: msg };
80
+ }
81
+ // 確認輸出目錄若存在則必須為空(除非使用 --force)
82
+ if (fs.existsSync(options.outputDir) && !options.force) {
83
+ const entries = fs.readdirSync(options.outputDir);
84
+ if (entries.length > 0) {
85
+ const msg = `Output directory is not empty: ${options.outputDir}. Use --force to skip this check.`;
86
+ output?.error(msg).flush();
87
+ return { success: false, message: msg };
88
+ }
89
+ }
90
+ // 尋找樣板中的 project 目錄
91
+ const projectSourceDir = this.findProjectDir(options.templatePath);
92
+ if (!projectSourceDir) {
93
+ const msg = `No project directory found in template: ${options.templatePath}`;
94
+ output?.error(msg).flush();
95
+ return { success: false, message: msg };
96
+ }
97
+ // 複製樣板
98
+ output?.item('arrow', `Copying template to: ${options.outputDir}`).flush();
99
+ this.copyDirectory(projectSourceDir, options.outputDir);
100
+ output?.success('Template copied').flush();
101
+ // 搜尋 ClientApp 目錄
102
+ const clientAppDirs = this.findClientAppDirs(options.outputDir);
103
+ // 執行 npm install
104
+ let npmInstallFailed = false;
105
+ if (!options.skipInstall) {
106
+ if (clientAppDirs.length === 0) {
107
+ output?.info('No ClientApp directory found, skipping npm install').flush();
108
+ }
109
+ for (const clientAppDir of clientAppDirs) {
110
+ output?.newline().item('arrow', `Installing dependencies in ${clientAppDir}...`).flush();
111
+ output?.item('bullet', 'This may take a few minutes').flush();
112
+ const installSuccess = await this.runNpmInstall(clientAppDir, output);
113
+ if (!installSuccess) {
114
+ npmInstallFailed = true;
115
+ output?.warning(`npm install failed in ${clientAppDir}. You can manually run "cd ${clientAppDir} && npm install" later.`).flush();
116
+ }
117
+ else {
118
+ output?.success(`Dependencies installed in ${clientAppDir}`).flush();
119
+ }
120
+ }
121
+ }
122
+ else {
123
+ output?.info('Skipping npm install (--skip-install)').flush();
124
+ }
125
+ return {
126
+ success: true,
127
+ projectPath: options.outputDir,
128
+ message: `Project created at ${options.outputDir}`,
129
+ npmInstallFailed,
130
+ clientAppDirs,
131
+ };
132
+ }
133
+ catch (error) {
134
+ const errorMessage = error instanceof Error ? error.message : String(error);
135
+ this.logger.error(new Error(`Failed to scaffold project: ${errorMessage}`));
136
+ return {
137
+ success: false,
138
+ message: `Failed to scaffold project: ${errorMessage}`,
139
+ };
140
+ }
141
+ }
142
+ /**
143
+ * 尋找樣板中的 project 目錄
144
+ * 優先尋找 template.json 中定義的 project.path
145
+ */
146
+ findProjectDir(templatePath) {
147
+ // 嘗試讀取 template.json
148
+ const templateJsonPath = path.join(templatePath, 'template.json');
149
+ if (fs.existsSync(templateJsonPath)) {
150
+ try {
151
+ const templateJson = JSON.parse(fs.readFileSync(templateJsonPath, 'utf-8'));
152
+ if (templateJson.project?.path) {
153
+ const projectDir = path.join(templatePath, templateJson.project.path);
154
+ // 路徑遍歷防護:確保解析後的路徑仍在樣板目錄內
155
+ const resolvedProjectDir = path.resolve(projectDir);
156
+ const resolvedTemplatePath = path.resolve(templatePath);
157
+ if (!resolvedProjectDir.startsWith(resolvedTemplatePath + path.sep) && resolvedProjectDir !== resolvedTemplatePath) {
158
+ this.logger.warn(`Template project.path "${templateJson.project.path}" attempts to escape template directory, ignoring`);
159
+ return templatePath;
160
+ }
161
+ if (fs.existsSync(projectDir)) {
162
+ return projectDir;
163
+ }
164
+ }
165
+ }
166
+ catch {
167
+ this.logger.debug('Failed to parse template.json, using fallback');
168
+ }
169
+ }
170
+ // 回退:直接使用樣板根目錄
171
+ return templatePath;
172
+ }
173
+ /**
174
+ * 遞迴複製目錄
175
+ */
176
+ copyDirectory(src, dest) {
177
+ fs.mkdirSync(dest, { recursive: true });
178
+ const entries = fs.readdirSync(src, { withFileTypes: true });
179
+ for (const entry of entries) {
180
+ const srcPath = path.join(src, entry.name);
181
+ const destPath = path.join(dest, entry.name);
182
+ // 跳過 node_modules 和 .git
183
+ if (entry.name === 'node_modules' || entry.name === '.git') {
184
+ continue;
185
+ }
186
+ if (entry.isDirectory()) {
187
+ this.copyDirectory(srcPath, destPath);
188
+ }
189
+ else {
190
+ fs.copyFileSync(srcPath, destPath);
191
+ }
192
+ }
193
+ }
194
+ /**
195
+ * 遞迴搜尋所有包含 package.json 的 ClientApp 目錄
196
+ * @param baseDir - 起始搜尋目錄
197
+ * @returns 所有找到的 ClientApp 目錄路徑
198
+ */
199
+ findClientAppDirs(baseDir) {
200
+ const results = [];
201
+ const search = (dir) => {
202
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
203
+ for (const entry of entries) {
204
+ if (!entry.isDirectory() || entry.name === 'node_modules' || entry.name === '.git')
205
+ continue;
206
+ const fullPath = path.join(dir, entry.name);
207
+ if (entry.name === defaults_1.PROJECT_DEFAULTS.CLIENT_APP_DIR && fs.existsSync(path.join(fullPath, 'package.json'))) {
208
+ results.push(fullPath);
209
+ }
210
+ else {
211
+ search(fullPath);
212
+ }
213
+ }
214
+ };
215
+ search(baseDir);
216
+ return results;
217
+ }
218
+ /**
219
+ * 執行 npm install
220
+ * Windows 上採用兩階段安裝策略,避免 Windows Defender 即時掃描導致 EPERM 錯誤
221
+ * @param cwd - 執行目錄
222
+ * @param output - 輸出端口
223
+ * @returns 是否成功
224
+ */
225
+ async runNpmInstall(cwd, output) {
226
+ try {
227
+ if ((0, platform_detector_util_1.isWindows)()) {
228
+ return await this.runNpmInstallWindows(cwd, output);
229
+ }
230
+ const result = await this.runNpm(['install'], cwd);
231
+ this.logCommandOutput(result);
232
+ return result.exitCode === 0;
233
+ }
234
+ catch (err) {
235
+ this.logger.error(new Error(`Failed to run npm install: ${err instanceof Error ? err.message : String(err)}`));
236
+ return false;
237
+ }
238
+ }
239
+ /**
240
+ * Windows 兩階段 npm install
241
+ * Phase 1: npm install --ignore-scripts(安裝套件但跳過 postinstall scripts)
242
+ * Phase 2: npm install(執行 lifecycle scripts)
243
+ * 中間等待 5 秒讓 Windows Defender 完成檔案掃描
244
+ * @param cwd - 執行目錄
245
+ * @param output - 輸出端口
246
+ * @returns 是否成功
247
+ */
248
+ async runNpmInstallWindows(cwd, output) {
249
+ // Phase 1: 安裝套件但跳過 scripts
250
+ output?.item('arrow', 'Phase 1: Installing packages (--ignore-scripts)...').flush();
251
+ const phase1 = await this.runNpm(['install', '--ignore-scripts'], cwd);
252
+ this.logCommandOutput(phase1);
253
+ if (phase1.exitCode !== 0) {
254
+ this.logger.error(new Error('npm install --ignore-scripts failed'), {
255
+ cwd,
256
+ exitCode: phase1.exitCode,
257
+ stderr: phase1.stderr,
258
+ });
259
+ return false;
260
+ }
261
+ output?.success('Phase 1 completed').flush();
262
+ // 等待 Windows Defender 完成掃描
263
+ output?.item('arrow', 'Waiting for Windows Defender scan to complete...').flush();
264
+ await this.delay(timeouts_1.TIMEOUTS.WINDOWS_DEFENDER_SCAN_WAIT);
265
+ // Phase 2: 執行 lifecycle scripts
266
+ output?.item('arrow', 'Phase 2: Running lifecycle scripts...').flush();
267
+ const phase2 = await this.runNpm(['install'], cwd);
268
+ this.logCommandOutput(phase2);
269
+ if (phase2.exitCode !== 0) {
270
+ this.logger.error(new Error('npm install lifecycle scripts failed'), {
271
+ cwd,
272
+ exitCode: phase2.exitCode,
273
+ stderr: phase2.stderr,
274
+ });
275
+ return false;
276
+ }
277
+ output?.success('Phase 2 completed').flush();
278
+ return true;
279
+ }
280
+ /**
281
+ * 記錄命令執行的標準輸出和標準錯誤
282
+ * @param result - 命令執行結果
283
+ */
284
+ logCommandOutput(result) {
285
+ if (result.stdout)
286
+ this.logger.debug(result.stdout);
287
+ if (result.stderr)
288
+ this.logger.debug(result.stderr);
289
+ }
290
+ /**
291
+ * 執行 npm 命令
292
+ * @param args - npm 命令參數
293
+ * @param cwd - 執行目錄
294
+ * @returns 命令執行結果
295
+ */
296
+ async runNpm(args, cwd) {
297
+ return this.commandExecutor.spawnProcess('npm', args, undefined, { cwd });
298
+ }
299
+ /**
300
+ * 延遲指定毫秒數
301
+ * @param ms - 延遲毫秒數
302
+ */
303
+ delay(ms) {
304
+ return new Promise(resolve => setTimeout(resolve, ms));
305
+ }
306
+ };
307
+ exports.ProjectScaffolderAdapter = ProjectScaffolderAdapter;
308
+ exports.ProjectScaffolderAdapter = ProjectScaffolderAdapter = __decorate([
309
+ (0, tsyringe_1.injectable)(),
310
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
311
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.ICommandExecutor)),
312
+ __metadata("design:paramtypes", [Object, Object])
313
+ ], ProjectScaffolderAdapter);
314
+ //# sourceMappingURL=project-scaffolder.adapter.js.map
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ /**
3
+ * Schematics Runner Adapter
4
+ *
5
+ * 實作 ISchematicsRunnerPort 介面
6
+ * 透過 npx ng generate 呼叫 @uofx/plugin-schematics
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
25
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
26
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
27
+ 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;
28
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
29
+ };
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ var __metadata = (this && this.__metadata) || function (k, v) {
48
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
49
+ };
50
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
51
+ return function (target, key) { decorator(target, key, paramIndex); }
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.SchematicsRunnerAdapter = void 0;
55
+ const tsyringe_1 = require("tsyringe");
56
+ const fs = __importStar(require("fs"));
57
+ const path = __importStar(require("path"));
58
+ const tokens_1 = require("../../di/tokens");
59
+ let SchematicsRunnerAdapter = class SchematicsRunnerAdapter {
60
+ constructor(logger, commandExecutor) {
61
+ this.logger = logger;
62
+ this.commandExecutor = commandExecutor;
63
+ }
64
+ /**
65
+ * 執行 Angular Schematics 產生元件
66
+ * @param options - Schematics 執行選項
67
+ * @param output - 輸出端口,用於回報進度
68
+ * @returns Schematics 執行結果
69
+ */
70
+ async run(options, output) {
71
+ // 預檢:確認 angular.json 存在
72
+ const angularJsonPath = path.join(options.projectPath, 'angular.json');
73
+ if (!fs.existsSync(angularJsonPath)) {
74
+ const msg = 'Plugin project not found (angular.json not detected). Please run this command from the ClientApp directory.';
75
+ output?.error(msg).flush();
76
+ return { success: false, message: msg };
77
+ }
78
+ // 預檢:確認 @uofx/plugin-schematics 已安裝
79
+ const isInstalled = await this.isSchematicsInstalled(options.projectPath);
80
+ if (!isInstalled) {
81
+ const msg = 'Package @uofx/plugin-schematics is not installed. Run: cd ClientApp && npm install @uofx/plugin-schematics';
82
+ output?.error(msg).flush();
83
+ return { success: false, message: msg };
84
+ }
85
+ // 組裝指令參數
86
+ const args = this.buildArgs(options);
87
+ const command = 'npx';
88
+ this.logger.debug(`Executing: ${command} ${args.join(' ')}`, {
89
+ cwd: options.projectPath,
90
+ });
91
+ const displayMessage = options.componentName
92
+ ? `Generating ${options.schematicName} "${options.componentName}"...`
93
+ : `Running ${options.schematicName} schematic...`;
94
+ output?.item('arrow', displayMessage).flush();
95
+ // 執行 schematics(使用 inheritStdio 支援互動式提示)
96
+ try {
97
+ output?.divider().flush();
98
+ const result = await this.commandExecutor.spawnProcess(command, args, undefined, { cwd: options.projectPath, inheritStdio: true });
99
+ output?.divider().flush();
100
+ if (result.exitCode === 0) {
101
+ return {
102
+ success: true,
103
+ message: 'Schematics executed successfully.',
104
+ };
105
+ }
106
+ else {
107
+ const errorMsg = `Process exited with code ${result.exitCode}`;
108
+ output?.error(errorMsg).flush();
109
+ return {
110
+ success: false,
111
+ message: errorMsg,
112
+ };
113
+ }
114
+ }
115
+ catch (err) {
116
+ const errorMsg = `Failed to execute schematics: ${err instanceof Error ? err.message : String(err)}`;
117
+ this.logger.error(new Error(errorMsg));
118
+ output?.error(errorMsg).flush();
119
+ return {
120
+ success: false,
121
+ message: errorMsg,
122
+ };
123
+ }
124
+ }
125
+ /**
126
+ * 檢查 @uofx/plugin-schematics 是否已安裝
127
+ * @param projectPath - 專案路徑
128
+ * @returns 是否已安裝
129
+ */
130
+ async isSchematicsInstalled(projectPath) {
131
+ const schematicsPath = path.join(projectPath, 'node_modules', '@uofx', 'plugin-schematics');
132
+ return fs.existsSync(schematicsPath);
133
+ }
134
+ /**
135
+ * 組裝 npx ng generate 指令參數
136
+ */
137
+ buildArgs(options) {
138
+ const args = [
139
+ 'ng',
140
+ 'generate',
141
+ `@uofx/plugin-schematics:${options.schematicName}`,
142
+ ];
143
+ // componentName 有值才加入位置參數
144
+ if (options.componentName) {
145
+ args.push(options.componentName);
146
+ }
147
+ // 加入額外參數
148
+ for (const [key, value] of Object.entries(options.extraArgs)) {
149
+ if (typeof value === 'boolean') {
150
+ if (value) {
151
+ args.push(`--${key}`);
152
+ }
153
+ else {
154
+ args.push(`--no-${key}`);
155
+ }
156
+ }
157
+ else {
158
+ args.push(`--${key}=${value}`);
159
+ }
160
+ }
161
+ // dry-run
162
+ if (options.dryRun) {
163
+ args.push('--dry-run');
164
+ }
165
+ return args;
166
+ }
167
+ };
168
+ exports.SchematicsRunnerAdapter = SchematicsRunnerAdapter;
169
+ exports.SchematicsRunnerAdapter = SchematicsRunnerAdapter = __decorate([
170
+ (0, tsyringe_1.injectable)(),
171
+ __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.ILoggerPort)),
172
+ __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.ICommandExecutor)),
173
+ __metadata("design:paramtypes", [Object, Object])
174
+ ], SchematicsRunnerAdapter);
175
+ //# sourceMappingURL=schematics-runner.adapter.js.map
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * Template Infrastructure Module
4
+ *
5
+ * 匯出樣板管理相關的基礎設施服務
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ __exportStar(require("./interfaces"), exports);
23
+ __exportStar(require("./services"), exports);
24
+ __exportStar(require("./template-manager.adapter"), exports);
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,22 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * Template Infrastructure Interfaces
19
+ */
20
+ __exportStar(require("./template-downloader.interface"), exports);
21
+ __exportStar(require("./template-registry.interface"), exports);
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Template Downloader Interface
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=template-downloader.interface.js.map
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Template Registry Interface
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=template-registry.interface.js.map
@@ -0,0 +1,24 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * Template Services
19
+ *
20
+ * 樣板管理相關服務實作
21
+ */
22
+ __exportStar(require("./template-downloader.service"), exports);
23
+ __exportStar(require("./template-registry.service"), exports);
24
+ //# sourceMappingURL=index.js.map