@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.
- package/LICENSE +40 -0
- package/README.md +444 -0
- package/THIRD-PARTY-NOTICES.txt +894 -0
- package/dist/application/dtos/index.js +24 -0
- package/dist/application/dtos/request/delete-instance.request.dto.js +3 -0
- package/dist/application/dtos/request/get-config.request.dto.js +3 -0
- package/dist/application/dtos/request/get-credentials.request.dto.js +3 -0
- package/dist/application/dtos/request/index.js +27 -0
- package/dist/application/dtos/request/install-instance.request.dto.js +3 -0
- package/dist/application/dtos/request/list-charts.request.dto.js +3 -0
- package/dist/application/dtos/request/set-config.request.dto.js +16 -0
- package/dist/application/dtos/request/setup-environment.request.dto.js +16 -0
- package/dist/application/dtos/request/show-logs.request.dto.js +19 -0
- package/dist/application/dtos/request/start-instance.request.dto.js +3 -0
- package/dist/application/dtos/request/stop-instance.request.dto.js +3 -0
- package/dist/application/dtos/response/credentials.response.dto.js +3 -0
- package/dist/application/dtos/response/delete-instance.response.dto.js +3 -0
- package/dist/application/dtos/response/index.js +26 -0
- package/dist/application/dtos/response/install-instance.response.dto.js +3 -0
- package/dist/application/dtos/response/instance-list.response.dto.js +3 -0
- package/dist/application/dtos/response/instance-status.response.dto.js +3 -0
- package/dist/application/dtos/response/setup-result.response.dto.js +3 -0
- package/dist/application/dtos/response/show-logs.response.dto.js +3 -0
- package/dist/application/dtos/response/start-instance.response.dto.js +3 -0
- package/dist/application/dtos/response/stop-instance.response.dto.js +3 -0
- package/dist/application/index.js +25 -0
- package/dist/application/interfaces/index.js +24 -0
- package/dist/application/interfaces/use-case.interface.js +3 -0
- package/dist/application/use-cases/config/get-config.use-case.js +66 -0
- package/dist/application/use-cases/config/set-config.use-case.js +49 -0
- package/dist/application/use-cases/credentials/get-credentials.use-case.js +57 -0
- package/dist/application/use-cases/index.js +28 -0
- package/dist/application/use-cases/instance/delete-instance.use-case.js +81 -0
- package/dist/application/use-cases/instance/index.js +23 -0
- package/dist/application/use-cases/instance/install-instance.use-case.js +424 -0
- package/dist/application/use-cases/instance/list-charts.use-case.js +43 -0
- package/dist/application/use-cases/instance/list-instances.use-case.js +62 -0
- package/dist/application/use-cases/instance/start-instance.use-case.js +154 -0
- package/dist/application/use-cases/instance/stop-instance.use-case.js +55 -0
- package/dist/application/use-cases/logs/show-logs.use-case.js +66 -0
- package/dist/application/use-cases/setup/setup-environment.use-case.js +53 -0
- package/dist/cli.js +286 -0
- package/dist/constants/config-defaults.js +23 -0
- package/dist/constants/defaults.js +89 -0
- package/dist/constants/deployment.js +39 -0
- package/dist/constants/environments.js +93 -0
- package/dist/constants/index.js +53 -0
- package/dist/constants/oci-artifacts.js +25 -0
- package/dist/constants/paths.js +92 -0
- package/dist/constants/timeouts.js +60 -0
- package/dist/di/container.js +34 -0
- package/dist/di/index.js +22 -0
- package/dist/di/modules/application.module.js +54 -0
- package/dist/di/modules/infrastructure.module.js +206 -0
- package/dist/di/modules/interceptor.module.js +68 -0
- package/dist/di/modules/presentation.module.js +31 -0
- package/dist/di/tokens.js +149 -0
- package/dist/domain/decorators/sensitive.decorator.js +39 -0
- package/dist/domain/entities/credentials-resolver.entity.js +127 -0
- package/dist/domain/entities/credentials.entity.js +65 -0
- package/dist/domain/entities/delete-instance-validation.entity.js +100 -0
- package/dist/domain/entities/deployment-parameters.entity.js +120 -0
- package/dist/domain/entities/environment-validation.entity.js +125 -0
- package/dist/domain/entities/index.js +29 -0
- package/dist/domain/entities/instance-lifecycle-state.entity.js +100 -0
- package/dist/domain/entities/instance-list-aggregator.entity.js +104 -0
- package/dist/domain/entities/instance-metadata.entity.js +86 -0
- package/dist/domain/entities/instance-status.entity.js +79 -0
- package/dist/domain/entities/instance.entity.js +128 -0
- package/dist/domain/entities/log-filter.entity.js +141 -0
- package/dist/domain/index.js +29 -0
- package/dist/domain/interfaces/safe-loggable.interface.js +3 -0
- package/dist/domain/ports/app-config.port.js +3 -0
- package/dist/domain/ports/base-image.port.js +3 -0
- package/dist/domain/ports/chart-version.port.js +3 -0
- package/dist/domain/ports/correlation-id.port.js +3 -0
- package/dist/domain/ports/credentials.port.js +3 -0
- package/dist/domain/ports/deployment.port.js +3 -0
- package/dist/domain/ports/error-handler.port.js +3 -0
- package/dist/domain/ports/index.js +46 -0
- package/dist/domain/ports/instance-manager.port.js +3 -0
- package/dist/domain/ports/instance-metadata.port.js +8 -0
- package/dist/domain/ports/instance-storage.port.js +3 -0
- package/dist/domain/ports/k8s-deployer.port.js +3 -0
- package/dist/domain/ports/logger.port.js +14 -0
- package/dist/domain/ports/output.port.js +3 -0
- package/dist/domain/ports/runtime-environment.port.js +6 -0
- package/dist/domain/ports/user-interaction.port.js +9 -0
- package/dist/domain/ports/user-settings.port.js +3 -0
- package/dist/domain/types/index.js +22 -0
- package/dist/domain/types/logger.types.js +29 -0
- package/dist/domain/types/validation.types.js +9 -0
- package/dist/domain/value-objects/acr-credentials.value-object.js +92 -0
- package/dist/domain/value-objects/chart-version.value-object.js +124 -0
- package/dist/domain/value-objects/config-log-level.value-object.js +84 -0
- package/dist/domain/value-objects/connection-info.value-object.js +65 -0
- package/dist/domain/value-objects/index.js +25 -0
- package/dist/domain/value-objects/instance-name.value-object.js +91 -0
- package/dist/domain/value-objects/jwt-key.value-object.js +97 -0
- package/dist/domain/value-objects/mssql-password.value-object.js +140 -0
- package/dist/domain/value-objects/rsa-key-pair.value-object.js +181 -0
- package/dist/index.js +6 -0
- package/dist/infrastructure/config/app-config.interface.js +3 -0
- package/dist/infrastructure/config/app-config.service.js +280 -0
- package/dist/infrastructure/config/config-validator.js +31 -0
- package/dist/infrastructure/config/crypto.service.js +125 -0
- package/dist/infrastructure/deployment/deployment.adapter.js +118 -0
- package/dist/infrastructure/deployment/interfaces/acr-credential-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/app-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/helm-registry.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/infra-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/k8s-job-runner.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-database-init.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-helm-deployment.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-storage.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/mssql-user-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/oci-artifact.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/secret-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/service-manager.interface.js +3 -0
- package/dist/infrastructure/deployment/interfaces/version-compatibility.interface.js +3 -0
- package/dist/infrastructure/deployment/services/acr-credential-manager.service.js +144 -0
- package/dist/infrastructure/deployment/services/app-manager.service.js +193 -0
- package/dist/infrastructure/deployment/services/base-helm-deployment.service.js +163 -0
- package/dist/infrastructure/deployment/services/helm-registry.service.js +126 -0
- package/dist/infrastructure/deployment/services/infra-manager.service.js +130 -0
- package/dist/infrastructure/deployment/services/k8s-job-runner.service.js +194 -0
- package/dist/infrastructure/deployment/services/mssql-database-init.service.js +139 -0
- package/dist/infrastructure/deployment/services/mssql-helm-deployment.service.js +100 -0
- package/dist/infrastructure/deployment/services/mssql-storage.service.js +54 -0
- package/dist/infrastructure/deployment/services/mssql-user-manager.service.js +66 -0
- package/dist/infrastructure/deployment/services/oci-artifact.service.js +289 -0
- package/dist/infrastructure/deployment/services/secret-manager.service.js +179 -0
- package/dist/infrastructure/deployment/services/service-manager.service.js +82 -0
- package/dist/infrastructure/deployment/services/version-compatibility.service.js +291 -0
- package/dist/infrastructure/environment/interfaces/hardware-info.interface.js +3 -0
- package/dist/infrastructure/environment/interfaces/network-checker.interface.js +3 -0
- package/dist/infrastructure/environment/services/hardware-info.service.js +135 -0
- package/dist/infrastructure/environment/services/network-checker.service.js +142 -0
- package/dist/infrastructure/environment/windows-environment.adapter.js +162 -0
- package/dist/infrastructure/errors/app-error.js +73 -0
- package/dist/infrastructure/errors/error-handler.interface.js +3 -0
- package/dist/infrastructure/errors/error-handler.js +218 -0
- package/dist/infrastructure/errors/exit-codes.js +27 -0
- package/dist/infrastructure/errors/index.js +25 -0
- package/dist/infrastructure/execution/builders/base-command.builder.js +122 -0
- package/dist/infrastructure/execution/builders/host-command.builder.js +58 -0
- package/dist/infrastructure/execution/builders/windows-host-command.builder.js +50 -0
- package/dist/infrastructure/execution/builders/wsl-command.builder.js +29 -0
- package/dist/infrastructure/execution/command-builder.js +252 -0
- package/dist/infrastructure/execution/command-executor.service.js +230 -0
- package/dist/infrastructure/execution/environments/wsl-execution.environment.js +70 -0
- package/dist/infrastructure/execution/execution-environment.factory.js +53 -0
- package/dist/infrastructure/execution/index.js +25 -0
- package/dist/infrastructure/execution/interfaces/command-builder.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/command-executor.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/execution-environment-factory.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/execution-environment.interface.js +7 -0
- package/dist/infrastructure/execution/interfaces/host-command-builder.interface.js +3 -0
- package/dist/infrastructure/execution/interfaces/index.js +23 -0
- package/dist/infrastructure/execution/interfaces/script-executor.interface.js +3 -0
- package/dist/infrastructure/execution/script-executor.service.js +171 -0
- package/dist/infrastructure/http/http-client.service.js +176 -0
- package/dist/infrastructure/http/index.js +18 -0
- package/dist/infrastructure/http/interfaces/http-client.interface.js +3 -0
- package/dist/infrastructure/interceptors/index.js +8 -0
- package/dist/infrastructure/interceptors/interceptor.factory.js +44 -0
- package/dist/infrastructure/interceptors/interceptor.interface.js +3 -0
- package/dist/infrastructure/interceptors/logging.interceptor.js +171 -0
- package/dist/infrastructure/logger/correlation-id.adapter.js +68 -0
- package/dist/infrastructure/logger/index.js +23 -0
- package/dist/infrastructure/logger/interfaces/index.js +22 -0
- package/dist/infrastructure/logger/interfaces/log-reader.repository.interface.js +7 -0
- package/dist/infrastructure/logger/interfaces/log-writer.repository.interface.js +7 -0
- package/dist/infrastructure/logger/logger.adapter.js +274 -0
- package/dist/infrastructure/logger/services/file-log-reader.repository.js +148 -0
- package/dist/infrastructure/logger/services/file-log-writer.repository.js +307 -0
- package/dist/infrastructure/logger/services/index.js +22 -0
- package/dist/infrastructure/persistence/index.js +25 -0
- package/dist/infrastructure/persistence/instance-metadata.adapter.js +100 -0
- package/dist/infrastructure/persistence/instance-storage.adapter.js +64 -0
- package/dist/infrastructure/persistence/interfaces/config.repository.interface.js +3 -0
- package/dist/infrastructure/persistence/interfaces/index.js +22 -0
- package/dist/infrastructure/persistence/interfaces/instance.repository.interface.js +3 -0
- package/dist/infrastructure/persistence/services/file-system-config.repository.js +168 -0
- package/dist/infrastructure/persistence/services/file-system-instance.repository.js +170 -0
- package/dist/infrastructure/persistence/services/index.js +22 -0
- package/dist/infrastructure/persistence/user-settings.adapter.js +55 -0
- package/dist/infrastructure/platform-detector.js +71 -0
- package/dist/infrastructure/platforms/windows/interfaces/microk8s.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/rootfs-manager.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/windows-features.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/windows-info.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-config.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-info.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-inspection.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-lifecycle.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-instance-naming.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-manager.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-resources.interface.js +8 -0
- package/dist/infrastructure/platforms/windows/interfaces/wsl-updater.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/interfaces/wslconfig-parser.interface.js +3 -0
- package/dist/infrastructure/platforms/windows/parsers/wsl-version.parser.js +133 -0
- package/dist/infrastructure/platforms/windows/services/microk8s.service.js +168 -0
- package/dist/infrastructure/platforms/windows/services/rootfs-manager.service.js +336 -0
- package/dist/infrastructure/platforms/windows/services/windows-features.service.js +191 -0
- package/dist/infrastructure/platforms/windows/services/windows-info.service.js +138 -0
- package/dist/infrastructure/platforms/windows/services/wsl-config.service.js +171 -0
- package/dist/infrastructure/platforms/windows/services/wsl-info.service.js +226 -0
- package/dist/infrastructure/platforms/windows/services/wsl-instance-inspection.service.js +325 -0
- package/dist/infrastructure/platforms/windows/services/wsl-instance-lifecycle.service.js +442 -0
- package/dist/infrastructure/platforms/windows/services/wsl-instance-naming.service.js +93 -0
- package/dist/infrastructure/platforms/windows/services/wsl-updater.service.js +273 -0
- package/dist/infrastructure/platforms/windows/services/wslconfig-parser.service.js +222 -0
- package/dist/infrastructure/platforms/windows/wsl-base-image.adapter.js +41 -0
- package/dist/infrastructure/platforms/windows/wsl-instance-manager.adapter.js +150 -0
- package/dist/infrastructure/utils/error-formatter.util.js +29 -0
- package/dist/infrastructure/utils/file-operations.util.js +201 -0
- package/dist/infrastructure/utils/input-validator.util.js +152 -0
- package/dist/infrastructure/utils/retry.util.js +98 -0
- package/dist/presentation/controllers/config.controller.js +146 -0
- package/dist/presentation/controllers/credentials.controller.js +105 -0
- package/dist/presentation/controllers/index.js +25 -0
- package/dist/presentation/controllers/instance.controller.js +363 -0
- package/dist/presentation/controllers/logs.controller.js +103 -0
- package/dist/presentation/controllers/setup.controller.js +175 -0
- package/dist/presentation/interfaces/cli-options.interface.js +8 -0
- package/dist/presentation/prompts/acr-credentials.prompt.js +76 -0
- package/dist/presentation/prompts/index.js +21 -0
- package/dist/presentation/ui/cli-progress.service.js +193 -0
- package/dist/presentation/ui/constants/output-symbols.js +42 -0
- package/dist/presentation/ui/index.js +27 -0
- package/dist/presentation/ui/interaction.service.js +276 -0
- package/dist/presentation/ui/interfaces/cli-progress.interface.js +9 -0
- package/dist/presentation/ui/interfaces/output-formatter.interface.js +23 -0
- package/dist/presentation/ui/log-level.enum.js +66 -0
- package/dist/presentation/ui/output-builder.service.js +378 -0
- package/dist/presentation/ui/output-formatter.service.js +393 -0
- package/package.json +65 -0
|
@@ -0,0 +1,135 @@
|
|
|
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.HardwareInfoService = 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
|
+
* 硬體資訊服務
|
|
22
|
+
*
|
|
23
|
+
* 負責取得系統硬體資訊(記憶體、磁碟)
|
|
24
|
+
*/
|
|
25
|
+
let HardwareInfoService = class HardwareInfoService {
|
|
26
|
+
constructor(commandExecutor) {
|
|
27
|
+
this.commandExecutor = commandExecutor;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 取得總實體記憶體 (GB)
|
|
31
|
+
* @returns 記憶體大小 (GB)
|
|
32
|
+
*/
|
|
33
|
+
async getTotalMemoryGB() {
|
|
34
|
+
try {
|
|
35
|
+
const builder = command_builder_1.CommandBuilder.create('powershell')
|
|
36
|
+
.powershell('(Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory / 1GB');
|
|
37
|
+
const result = await builder.exec(this.commandExecutor);
|
|
38
|
+
const output = result.stdout.trim();
|
|
39
|
+
const memoryGB = Math.round(parseFloat(output));
|
|
40
|
+
if (isNaN(memoryGB) || memoryGB <= 0) {
|
|
41
|
+
throw new errors_1.AppError('Failed to parse total memory', {
|
|
42
|
+
exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
|
|
43
|
+
solution: 'Unable to parse memory information from system. Check if PowerShell is available.',
|
|
44
|
+
context: { operation: 'getTotalMemoryGB', resource: 'System Memory' }
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return memoryGB;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (error instanceof errors_1.AppError) {
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
throw new errors_1.AppError('Failed to query total memory', {
|
|
54
|
+
exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
|
|
55
|
+
solution: 'Check if PowerShell is available and system memory can be queried',
|
|
56
|
+
cause: error instanceof Error ? error : undefined,
|
|
57
|
+
context: { operation: 'getTotalMemoryGB', resource: 'System Memory' }
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 取得可用實體記憶體 (GB)
|
|
63
|
+
* @returns 可用記憶體大小 (GB)
|
|
64
|
+
*/
|
|
65
|
+
async getAvailableMemoryGB() {
|
|
66
|
+
try {
|
|
67
|
+
// FreePhysicalMemory 單位是 KB
|
|
68
|
+
// PowerShell 的 1MB = 1024 * 1024 = 1048576
|
|
69
|
+
// KB / 1048576 = GB(因為 1GB = 1048576 KB)
|
|
70
|
+
const builder = command_builder_1.CommandBuilder.create('powershell')
|
|
71
|
+
.powershell('(Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory / 1MB');
|
|
72
|
+
const result = await builder.exec(this.commandExecutor);
|
|
73
|
+
const output = result.stdout.trim();
|
|
74
|
+
const memoryGB = Math.round(parseFloat(output) * 100) / 100;
|
|
75
|
+
if (isNaN(memoryGB) || memoryGB < 0) {
|
|
76
|
+
throw new errors_1.AppError('Failed to parse available memory', {
|
|
77
|
+
exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
|
|
78
|
+
solution: 'Unable to parse available memory information from system. Check if PowerShell is available.',
|
|
79
|
+
context: { operation: 'getAvailableMemoryGB', resource: 'System Memory' }
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return memoryGB;
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (error instanceof errors_1.AppError) {
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
throw new errors_1.AppError('Failed to query available memory', {
|
|
89
|
+
exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
|
|
90
|
+
solution: 'Check if PowerShell is available and system memory can be queried',
|
|
91
|
+
cause: error instanceof Error ? error : undefined,
|
|
92
|
+
context: { operation: 'getAvailableMemoryGB', resource: 'System Memory' }
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 取得可用磁碟空間 (GB)
|
|
98
|
+
* @returns 可用空間 (GB)
|
|
99
|
+
*/
|
|
100
|
+
async getAvailableDiskGB() {
|
|
101
|
+
try {
|
|
102
|
+
const builder = command_builder_1.CommandBuilder.create('powershell')
|
|
103
|
+
.powershell('(Get-PSDrive C).Free / 1GB');
|
|
104
|
+
const result = await builder.exec(this.commandExecutor);
|
|
105
|
+
const output = result.stdout.trim();
|
|
106
|
+
const diskGB = Math.round(parseFloat(output));
|
|
107
|
+
if (isNaN(diskGB) || diskGB < 0) {
|
|
108
|
+
throw new errors_1.AppError('Failed to parse disk space', {
|
|
109
|
+
exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
|
|
110
|
+
solution: 'Unable to parse disk space information from system. Check if PowerShell is available.',
|
|
111
|
+
context: { operation: 'getAvailableDiskGB', resource: 'Disk Space' }
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return diskGB;
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (error instanceof errors_1.AppError) {
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
throw new errors_1.AppError('Failed to query disk space', {
|
|
121
|
+
exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
|
|
122
|
+
solution: 'Check if PowerShell is available and disk space can be queried',
|
|
123
|
+
cause: error instanceof Error ? error : undefined,
|
|
124
|
+
context: { operation: 'getAvailableDiskGB', resource: 'Disk Space' }
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
exports.HardwareInfoService = HardwareInfoService;
|
|
130
|
+
exports.HardwareInfoService = HardwareInfoService = __decorate([
|
|
131
|
+
(0, tsyringe_1.injectable)(),
|
|
132
|
+
__param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.ICommandExecutor)),
|
|
133
|
+
__metadata("design:paramtypes", [Object])
|
|
134
|
+
], HardwareInfoService);
|
|
135
|
+
//# sourceMappingURL=hardware-info.service.js.map
|
|
@@ -0,0 +1,142 @@
|
|
|
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 __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.NetworkCheckerService = void 0;
|
|
13
|
+
const tsyringe_1 = require("tsyringe");
|
|
14
|
+
const https_1 = __importDefault(require("https"));
|
|
15
|
+
/**
|
|
16
|
+
* 網路連線檢查服務
|
|
17
|
+
*
|
|
18
|
+
* 負責檢查必要的網路連線,包含:
|
|
19
|
+
* - 單一 URL 連線檢查
|
|
20
|
+
* - 多個網址批量檢查
|
|
21
|
+
* - 連線狀態摘要統計
|
|
22
|
+
*/
|
|
23
|
+
let NetworkCheckerService = class NetworkCheckerService {
|
|
24
|
+
async checkUrlConnectivity(url, timeoutMs = 30000) {
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
const parsedUrl = new URL(url);
|
|
27
|
+
const options = {
|
|
28
|
+
hostname: parsedUrl.hostname,
|
|
29
|
+
port: parsedUrl.port || 443,
|
|
30
|
+
path: parsedUrl.pathname || '/',
|
|
31
|
+
method: 'HEAD',
|
|
32
|
+
timeout: timeoutMs,
|
|
33
|
+
agent: false, // 停用連線池,請求完成後立即關閉連線
|
|
34
|
+
headers: {
|
|
35
|
+
'User-Agent': 'uofx-cli/1.0'
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const req = https_1.default.request(options, (res) => {
|
|
39
|
+
resolve({
|
|
40
|
+
url: parsedUrl.hostname,
|
|
41
|
+
reachable: true,
|
|
42
|
+
statusCode: res.statusCode
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
req.on('error', (error) => {
|
|
46
|
+
let errorMessage = 'Connection failed';
|
|
47
|
+
if (error.code === 'ENOTFOUND') {
|
|
48
|
+
errorMessage = 'Host not found (DNS resolution failed)';
|
|
49
|
+
}
|
|
50
|
+
else if (error.code === 'ETIMEDOUT' || error.code === 'ESOCKETTIMEDOUT') {
|
|
51
|
+
errorMessage = 'Connection timed out';
|
|
52
|
+
}
|
|
53
|
+
else if (error.code === 'ECONNREFUSED') {
|
|
54
|
+
errorMessage = 'Connection refused';
|
|
55
|
+
}
|
|
56
|
+
else if (error.code === 'ECONNRESET') {
|
|
57
|
+
errorMessage = 'Connection reset';
|
|
58
|
+
}
|
|
59
|
+
else if (error.message) {
|
|
60
|
+
errorMessage = error.message;
|
|
61
|
+
}
|
|
62
|
+
resolve({
|
|
63
|
+
url: parsedUrl.hostname,
|
|
64
|
+
reachable: false,
|
|
65
|
+
errorMessage
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
req.on('timeout', () => {
|
|
69
|
+
req.destroy();
|
|
70
|
+
resolve({
|
|
71
|
+
url: parsedUrl.hostname,
|
|
72
|
+
reachable: false,
|
|
73
|
+
errorMessage: 'Request timed out after 30 seconds'
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
req.end();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async checkUbuntuImages() {
|
|
80
|
+
return await this.checkUrlConnectivity('https://cloud-images.ubuntu.com');
|
|
81
|
+
}
|
|
82
|
+
async checkAzureContainerRegistry(acrName) {
|
|
83
|
+
const url = `https://${acrName}.azurecr.io`;
|
|
84
|
+
return await this.checkUrlConnectivity(url);
|
|
85
|
+
}
|
|
86
|
+
async performNetworkChecks(acrName) {
|
|
87
|
+
const results = [];
|
|
88
|
+
// Check Ubuntu Cloud Images
|
|
89
|
+
const ubuntuResult = await this.checkUbuntuImages();
|
|
90
|
+
results.push(ubuntuResult);
|
|
91
|
+
// Check ACR if provided
|
|
92
|
+
if (acrName) {
|
|
93
|
+
const acrResult = await this.checkAzureContainerRegistry(acrName);
|
|
94
|
+
results.push(acrResult);
|
|
95
|
+
}
|
|
96
|
+
const allPassed = results.every(r => r.reachable);
|
|
97
|
+
return {
|
|
98
|
+
allPassed,
|
|
99
|
+
results
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
formatNetworkSuccess(result) {
|
|
103
|
+
return `✓ ${result.url} - Reachable`;
|
|
104
|
+
}
|
|
105
|
+
formatNetworkError(result) {
|
|
106
|
+
const lines = [
|
|
107
|
+
`✗ Error: Unable to connect to ${result.url}`,
|
|
108
|
+
'',
|
|
109
|
+
'Possible causes:',
|
|
110
|
+
' • No internet connection',
|
|
111
|
+
' • Firewall blocking HTTPS traffic',
|
|
112
|
+
' • DNS resolution issues',
|
|
113
|
+
'',
|
|
114
|
+
'Troubleshooting:',
|
|
115
|
+
' 1. Check your internet connection',
|
|
116
|
+
' 2. Try accessing the URL in a browser',
|
|
117
|
+
' 3. Check firewall settings',
|
|
118
|
+
' 4. Verify DNS settings'
|
|
119
|
+
];
|
|
120
|
+
if (result.errorMessage) {
|
|
121
|
+
lines.splice(3, 0, ` • ${result.errorMessage}`);
|
|
122
|
+
}
|
|
123
|
+
return lines.join('\n');
|
|
124
|
+
}
|
|
125
|
+
formatNetworkCheckSummary(summary) {
|
|
126
|
+
const lines = [];
|
|
127
|
+
for (const result of summary.results) {
|
|
128
|
+
if (result.reachable) {
|
|
129
|
+
lines.push(this.formatNetworkSuccess(result));
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
lines.push(this.formatNetworkError(result));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return lines.join('\n');
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
exports.NetworkCheckerService = NetworkCheckerService;
|
|
139
|
+
exports.NetworkCheckerService = NetworkCheckerService = __decorate([
|
|
140
|
+
(0, tsyringe_1.injectable)()
|
|
141
|
+
], NetworkCheckerService);
|
|
142
|
+
//# sourceMappingURL=network-checker.service.js.map
|
|
@@ -0,0 +1,162 @@
|
|
|
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.WindowsEnvironmentAdapter = void 0;
|
|
49
|
+
const tsyringe_1 = require("tsyringe");
|
|
50
|
+
const tokens_1 = require("../../di/tokens");
|
|
51
|
+
/**
|
|
52
|
+
* Windows Environment Adapter
|
|
53
|
+
*
|
|
54
|
+
* implements IRuntimeEnvironmentPort for Windows platform
|
|
55
|
+
* 整合 Windows 資訊、WSL 資訊、系統資源、網路檢查
|
|
56
|
+
*/
|
|
57
|
+
let WindowsEnvironmentAdapter = class WindowsEnvironmentAdapter {
|
|
58
|
+
constructor(windowsInfo, wslInfo, hardware, networkChecker, appConfig, wslConfigParser) {
|
|
59
|
+
this.windowsInfo = windowsInfo;
|
|
60
|
+
this.wslInfo = wslInfo;
|
|
61
|
+
this.hardware = hardware;
|
|
62
|
+
this.networkChecker = networkChecker;
|
|
63
|
+
this.appConfig = appConfig;
|
|
64
|
+
this.wslConfigParser = wslConfigParser;
|
|
65
|
+
}
|
|
66
|
+
async getOsInfo() {
|
|
67
|
+
const windowsVersion = await this.windowsInfo.getWindowsVersion();
|
|
68
|
+
return {
|
|
69
|
+
platform: 'win32',
|
|
70
|
+
version: windowsVersion.version,
|
|
71
|
+
arch: process.arch,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async getRuntimeInfo() {
|
|
75
|
+
const versionInfo = await this.wslInfo.getWslVersionInfo();
|
|
76
|
+
const isInstalled = await this.wslInfo.isWslInstalled();
|
|
77
|
+
// 若版本無法取得,視為未正確安裝
|
|
78
|
+
const hasValidVersion = !!versionInfo.wslVersion;
|
|
79
|
+
return {
|
|
80
|
+
type: 'WSL',
|
|
81
|
+
version: versionInfo.wslVersion || 'unknown',
|
|
82
|
+
isInstalled: isInstalled && hasValidVersion,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async isRuntimeInstalled() {
|
|
86
|
+
return await this.wslInfo.isWslInstalled();
|
|
87
|
+
}
|
|
88
|
+
async checkRuntimeUpdate() {
|
|
89
|
+
const versionInfo = await this.wslInfo.getWslVersionInfo();
|
|
90
|
+
if (!versionInfo.installed) {
|
|
91
|
+
return {
|
|
92
|
+
required: true,
|
|
93
|
+
reason: 'WSL is not installed',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const updateReq = this.wslInfo.checkWslUpdateRequirement(versionInfo);
|
|
97
|
+
return {
|
|
98
|
+
required: updateReq.needsUpdate || updateReq.needsDefaultVersion,
|
|
99
|
+
currentVersion: updateReq.currentVersion,
|
|
100
|
+
reason: updateReq.steps.join('; '),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async getSystemResources() {
|
|
104
|
+
const totalMemoryGB = await this.hardware.getTotalMemoryGB();
|
|
105
|
+
const availableMemoryGB = await this.hardware.getAvailableMemoryGB();
|
|
106
|
+
const availableDiskGB = await this.hardware.getAvailableDiskGB();
|
|
107
|
+
// 讀取 WSL 記憶體配置
|
|
108
|
+
const wslConfig = await this.wslConfigParser.readWslConfig();
|
|
109
|
+
return {
|
|
110
|
+
totalMemory: totalMemoryGB * 1024 * 1024 * 1024,
|
|
111
|
+
freeMemory: availableMemoryGB * 1024 * 1024 * 1024,
|
|
112
|
+
cpuCount: (await Promise.resolve().then(() => __importStar(require('os')))).cpus().length,
|
|
113
|
+
diskSpace: {
|
|
114
|
+
total: 0, // 服務不提供此資訊
|
|
115
|
+
free: availableDiskGB * 1024 * 1024 * 1024,
|
|
116
|
+
},
|
|
117
|
+
wslMemory: {
|
|
118
|
+
limitGB: wslConfig.memoryGB,
|
|
119
|
+
isConfigured: wslConfig.configured,
|
|
120
|
+
source: wslConfig.configured ? 'wslconfig' : 'default',
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async checkNetworkConnectivity() {
|
|
125
|
+
const config = this.appConfig.getConfig();
|
|
126
|
+
// 從設定讀取 ACR 名稱;若未設定,則不檢查 registry 連線
|
|
127
|
+
const acrName = config.acr?.name;
|
|
128
|
+
const summary = await this.networkChecker.performNetworkChecks(acrName);
|
|
129
|
+
return {
|
|
130
|
+
isOnline: summary.allPassed,
|
|
131
|
+
// 當 acrName 為 undefined 時,不會有 ACR 檢查結果,canReachRegistry 會是 false
|
|
132
|
+
canReachRegistry: summary.results.some(r => r.reachable && r.url.includes('azurecr.io')),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
async getMemoryAvailability() {
|
|
136
|
+
const info = await this.wslConfigParser.getMemoryAvailability();
|
|
137
|
+
const sourceText = info.wslLimitSource === 'wslconfig'
|
|
138
|
+
? 'from .wslconfig'
|
|
139
|
+
: 'WSL2 default';
|
|
140
|
+
return {
|
|
141
|
+
availableGB: info.availableForUofxGB,
|
|
142
|
+
details: [
|
|
143
|
+
{ label: 'System available memory', valueGB: info.systemAvailableGB },
|
|
144
|
+
{ label: 'WSL memory limit', valueGB: info.wslLimitGB, suffix: sourceText },
|
|
145
|
+
{ label: 'WSL current usage', valueGB: info.wslCurrentUsageGB },
|
|
146
|
+
{ label: 'Available for UOFX', valueGB: info.availableForUofxGB },
|
|
147
|
+
],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
exports.WindowsEnvironmentAdapter = WindowsEnvironmentAdapter;
|
|
152
|
+
exports.WindowsEnvironmentAdapter = WindowsEnvironmentAdapter = __decorate([
|
|
153
|
+
(0, tsyringe_1.injectable)(),
|
|
154
|
+
__param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.WindowsInfoService)),
|
|
155
|
+
__param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.WslInfoService)),
|
|
156
|
+
__param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IHardwareInfo)),
|
|
157
|
+
__param(3, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.NetworkCheckerService)),
|
|
158
|
+
__param(4, (0, tsyringe_1.inject)(tokens_1.TOKENS.IAppConfigPort)),
|
|
159
|
+
__param(5, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.IWslConfigParser)),
|
|
160
|
+
__metadata("design:paramtypes", [Object, Object, Object, Object, Object, Object])
|
|
161
|
+
], WindowsEnvironmentAdapter);
|
|
162
|
+
//# sourceMappingURL=windows-environment.adapter.js.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 統一應用程式錯誤類別
|
|
4
|
+
*
|
|
5
|
+
* 使用範例:
|
|
6
|
+
* ```typescript
|
|
7
|
+
* throw new AppError('WSL is not installed', {
|
|
8
|
+
* exitCode: EXIT_CODES.SYSTEM_ERROR,
|
|
9
|
+
* solution: 'Install WSL 2 by running: wsl --install',
|
|
10
|
+
* cause: originalError,
|
|
11
|
+
* context: { version: '2.0' }
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.AppError = void 0;
|
|
17
|
+
/**
|
|
18
|
+
* 應用程式錯誤類別
|
|
19
|
+
*
|
|
20
|
+
* 這是整個應用程式唯一的錯誤類別,簡化錯誤處理邏輯。
|
|
21
|
+
*/
|
|
22
|
+
class AppError extends Error {
|
|
23
|
+
/**
|
|
24
|
+
* 建立 AppError 實例
|
|
25
|
+
*
|
|
26
|
+
* @param message - 錯誤訊息(必填)
|
|
27
|
+
* @param options - 選項設定
|
|
28
|
+
*/
|
|
29
|
+
constructor(message, options) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = 'AppError';
|
|
32
|
+
this.exitCode = options?.exitCode ?? 1;
|
|
33
|
+
this.solution = options?.solution;
|
|
34
|
+
this.cause = options?.cause;
|
|
35
|
+
this.context = options?.context;
|
|
36
|
+
this.timestamp = new Date();
|
|
37
|
+
// 保持 stack trace 的正確性
|
|
38
|
+
if (Error.captureStackTrace) {
|
|
39
|
+
Error.captureStackTrace(this, this.constructor);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 取得完整的錯誤資訊(包含 cause chain)
|
|
44
|
+
*/
|
|
45
|
+
getFullMessage() {
|
|
46
|
+
const messages = [this.message];
|
|
47
|
+
if (this.cause) {
|
|
48
|
+
messages.push(`Caused by: ${this.cause.message}`);
|
|
49
|
+
}
|
|
50
|
+
return messages.join('\n');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 將錯誤轉換為 JSON 格式(用於日誌記錄)
|
|
54
|
+
*/
|
|
55
|
+
toJSON() {
|
|
56
|
+
return {
|
|
57
|
+
name: this.name,
|
|
58
|
+
message: this.message,
|
|
59
|
+
exitCode: this.exitCode,
|
|
60
|
+
solution: this.solution,
|
|
61
|
+
timestamp: this.timestamp.toISOString(),
|
|
62
|
+
context: this.context,
|
|
63
|
+
stack: this.stack,
|
|
64
|
+
cause: this.cause ? {
|
|
65
|
+
name: this.cause.name,
|
|
66
|
+
message: this.cause.message,
|
|
67
|
+
stack: this.cause.stack,
|
|
68
|
+
} : undefined,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.AppError = AppError;
|
|
73
|
+
//# sourceMappingURL=app-error.js.map
|