@uofx/cli 1.0.1 → 1.0.2

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.
@@ -117,13 +117,23 @@ let WslUpdaterService = class WslUpdaterService {
117
117
  return false;
118
118
  }
119
119
  }
120
+ /**
121
+ * 檢查輸出是否指示需要重新啟動
122
+ * @param output - 命令輸出或錯誤訊息
123
+ * @returns 是否需要重新啟動
124
+ */
125
+ checkNeedsRestart(output) {
126
+ return /restart|reboot|重新啟動|重启|再起動|rebooted/i.test(output);
127
+ }
120
128
  /**
121
129
  * 安裝或更新 WSL
122
- * 統一使用 wsl --update 命令,適用於所有 Windows 版本
130
+ * - install: 使用 wsl --install --no-distribution(首次安裝 WSL)
131
+ * - update: 使用 wsl --update(更新現有 WSL 安裝)
132
+ *
123
133
  * 如果以管理員身分執行,則在當前控制台中執行
124
134
  * 否則,提示用戶以管理員身份重新執行
125
135
  *
126
- * @param action 'install' 或 'update'(統一執行 --update)
136
+ * @param action 'install' 或 'update'
127
137
  * @param output - 輸出介面
128
138
  * @returns 物件指示是否需要重新啟動
129
139
  */
@@ -134,23 +144,30 @@ let WslUpdaterService = class WslUpdaterService {
134
144
  if (isAdmin) {
135
145
  output?.info(`Running WSL ${actionDescription} in the current console...`).flush();
136
146
  try {
137
- // 統一使用 --update,適用於所有 Windows 版本
138
- const builder = command_builder_1.CommandBuilder.create('wsl')
139
- .wslCmd('--update')
140
- .inheritStdio();
147
+ // 根據 action 決定使用的命令
148
+ // install: 使用 wsl --install --no-distribution(首次安裝)
149
+ // update: 使用 wsl --update(更新現有安裝)
150
+ const builder = action === 'install'
151
+ ? command_builder_1.CommandBuilder.create('wsl')
152
+ .arg('--install')
153
+ .arg('--no-distribution')
154
+ .inheritStdio()
155
+ : command_builder_1.CommandBuilder.create('wsl')
156
+ .wslCmd('--update')
157
+ .inheritStdio();
141
158
  const result = await builder.exec(this.commandExecutor);
142
159
  const cmdOutput = result.stdout + result.stderr;
143
160
  if (result.exitCode !== 0) {
144
161
  // 即使命令 "失敗",也可能已經成功但需要重新啟動
145
162
  // Windows 經常在需要重新啟動時返回非零退出碼
146
- if (/restart|reboot|重新啟動/i.test(cmdOutput)) {
163
+ if (this.checkNeedsRestart(cmdOutput)) {
147
164
  output?.success(`WSL ${actionDescription} completed (restart required).`).flush();
148
165
  return { needsRestart: true };
149
166
  }
150
167
  throw new Error('Command failed');
151
168
  }
152
169
  // 根據輸出檢查是否需要重新啟動
153
- const needsRestart = /restart|reboot|重新啟動/i.test(cmdOutput);
170
+ const needsRestart = this.checkNeedsRestart(cmdOutput);
154
171
  if (needsRestart) {
155
172
  output?.success(`WSL ${actionDescription} completed.`).flush();
156
173
  output?.warning('A system restart is required.').flush();
@@ -163,7 +180,7 @@ let WslUpdaterService = class WslUpdaterService {
163
180
  catch (error) {
164
181
  // 檢查錯誤訊息中是否包含重啟提示
165
182
  const errorMessage = (0, error_formatter_util_1.formatErrorMessage)(error);
166
- if (/restart|reboot|重新啟動/i.test(errorMessage)) {
183
+ if (this.checkNeedsRestart(errorMessage)) {
167
184
  output?.success(`WSL ${actionDescription} completed (restart required).`).flush();
168
185
  return { needsRestart: true };
169
186
  }
@@ -174,7 +191,9 @@ let WslUpdaterService = class WslUpdaterService {
174
191
  });
175
192
  throw new errors_1.AppError(`Failed to execute WSL ${actionDescription}`, {
176
193
  exitCode: errors_1.EXIT_CODES.SYSTEM_ERROR,
177
- solution: 'Try running the command as administrator or check Windows Event Viewer for details',
194
+ solution: action === 'install'
195
+ ? 'Try running: wsl --install --no-distribution'
196
+ : 'Try running: wsl --update',
178
197
  });
179
198
  }
180
199
  }
@@ -238,7 +257,13 @@ let WslUpdaterService = class WslUpdaterService {
238
257
  lines.push('');
239
258
  lines.push('To continue setup manually, please run:');
240
259
  if (requirement.needsUpdate) {
241
- lines.push(' wsl --update');
260
+ // 根據是否有 currentVersion 判斷是安裝還是更新
261
+ if (!requirement.currentVersion) {
262
+ lines.push(' wsl --install --no-distribution');
263
+ }
264
+ else {
265
+ lines.push(' wsl --update');
266
+ }
242
267
  }
243
268
  if (requirement.needsDefaultVersion) {
244
269
  lines.push(' wsl --set-default-version 2');
@@ -24,9 +24,10 @@ const error_formatter_util_1 = require("../../infrastructure/utils/error-formatt
24
24
  * 處理環境設定相關的 CLI 命令
25
25
  */
26
26
  let SetupController = class SetupController {
27
- constructor(setupUseCase, output, wslUpdater, runtimeEnvironment) {
27
+ constructor(setupUseCase, output, wslInfo, wslUpdater, runtimeEnvironment) {
28
28
  this.setupUseCase = setupUseCase;
29
29
  this.output = output;
30
+ this.wslInfo = wslInfo;
30
31
  this.wslUpdater = wslUpdater;
31
32
  this.runtimeEnvironment = runtimeEnvironment;
32
33
  }
@@ -55,6 +56,40 @@ let SetupController = class SetupController {
55
56
  .item('bullet', `Version: ${result.runtimeInfo.version}`);
56
57
  if (result.runtimeInfo.isInstalled) {
57
58
  this.output.success('Runtime installed');
59
+ // 檢查是否需要更新
60
+ const versionInfo = await this.wslInfo.getWslVersionInfo();
61
+ const updateReq = this.wslInfo.checkWslUpdateRequirement(versionInfo);
62
+ if (updateReq.needsUpdate || updateReq.needsDefaultVersion) {
63
+ this.output.newline().render();
64
+ // 詢問使用者是否要更新
65
+ const shouldSetup = await this.wslUpdater.promptWslSetup(updateReq, this.output);
66
+ if (shouldSetup) {
67
+ // 執行更新
68
+ if (updateReq.needsUpdate) {
69
+ const { needsRestart } = await this.wslUpdater.installWsl('update', this.output);
70
+ if (needsRestart) {
71
+ this.output
72
+ .newline()
73
+ .info('Please restart your computer and run "uofx env setup" again.')
74
+ .render();
75
+ return;
76
+ }
77
+ }
78
+ // 設定預設版本
79
+ if (updateReq.needsDefaultVersion) {
80
+ await this.wslUpdater.setDefaultVersion(this.output);
81
+ }
82
+ this.output
83
+ .newline()
84
+ .success('WSL setup completed.')
85
+ .render();
86
+ return;
87
+ }
88
+ else {
89
+ // 使用者取消
90
+ this.wslUpdater.handleSetupCancelled(updateReq, this.output);
91
+ }
92
+ }
58
93
  }
59
94
  else {
60
95
  this.output.error('Runtime not installed').newline().render();
@@ -168,8 +203,9 @@ exports.SetupController = SetupController = __decorate([
168
203
  (0, tsyringe_1.injectable)(),
169
204
  __param(0, (0, tsyringe_1.inject)(tokens_1.TOKENS.SetupEnvironmentUseCase)),
170
205
  __param(1, (0, tsyringe_1.inject)(tokens_1.TOKENS.IOutputPort)),
171
- __param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.WslUpdaterService)),
172
- __param(3, (0, tsyringe_1.inject)(tokens_1.TOKENS.IRuntimeEnvironmentPort)),
173
- __metadata("design:paramtypes", [setup_environment_use_case_1.SetupEnvironmentUseCase, Object, Object, Object])
206
+ __param(2, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.WslInfoService)),
207
+ __param(3, (0, tsyringe_1.inject)(tokens_1.TOKENS.Internal.WslUpdaterService)),
208
+ __param(4, (0, tsyringe_1.inject)(tokens_1.TOKENS.IRuntimeEnvironmentPort)),
209
+ __metadata("design:paramtypes", [setup_environment_use_case_1.SetupEnvironmentUseCase, Object, Object, Object, Object])
174
210
  ], SetupController);
175
211
  //# sourceMappingURL=setup.controller.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uofx/cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "CLI tool for installing and managing the UOFX development environment on WSL",
5
5
  "main": "dist/index.js",
6
6
  "bin": {