@flowscripter/dynamic-cli-framework 2.3.2 → 2.3.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultUpgradeService.d.ts","sourceRoot":"","sources":["../../../../src/service/upgrade/DefaultUpgradeService.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACd,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,aAAa,EACb,aAAa,EACb,WAAW,EACX,KAAK,cAAc,EACpB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAe1E,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,cAAc;;gBAM/C,MAAM,EAAE,sBAAsB,EAAE,SAAS,EAAE,SAAS;IAKhE,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI;IAKpF,QAAQ,IAAI,WAAW,GAAG,SAAS;IAanC,UAAU,IAAI,aAAa,GAAG,SAAS;IAWjC,mBAAmB,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAgBxE,eAAe,CAC1B,UAAU,CAAC,EAAE,WAAW,EACxB,YAAY,CAAC,EAAE,aAAa,EAC5B,qBAAqB,CAAC,EAAE,aAAa,GACpC,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC;IAmC7B,OAAO,CAClB,UAAU,CAAC,EAAE,WAAW,EACxB,YAAY,CAAC,EAAE,aAAa,EAC5B,qBAAqB,CAAC,EAAE,aAAa,GACpC,OAAO,CAAC,aAAa,CAAC;CA2Q1B"}
1
+ {"version":3,"file":"DefaultUpgradeService.d.ts","sourceRoot":"","sources":["../../../../src/service/upgrade/DefaultUpgradeService.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACd,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,aAAa,EACb,aAAa,EACb,WAAW,EACX,KAAK,cAAc,EACpB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AA0B1E,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,cAAc;;gBAM/C,MAAM,EAAE,sBAAsB,EAAE,SAAS,EAAE,SAAS;IAKhE,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI;IAKpF,QAAQ,IAAI,WAAW,GAAG,SAAS;IAanC,UAAU,IAAI,aAAa,GAAG,SAAS;IAWjC,mBAAmB,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAgBxE,eAAe,CAC1B,UAAU,CAAC,EAAE,WAAW,EACxB,YAAY,CAAC,EAAE,aAAa,EAC5B,qBAAqB,CAAC,EAAE,aAAa,GACpC,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC;IAmC7B,OAAO,CAClB,UAAU,CAAC,EAAE,WAAW,EACxB,YAAY,CAAC,EAAE,aAAa,EAC5B,qBAAqB,CAAC,EAAE,aAAa,GACpC,OAAO,CAAC,aAAa,CAAC;CAiR1B"}
@@ -9,6 +9,16 @@ const logger = getLogger("DefaultUpgradeService");
9
9
  // checkForUpgrade() runs opportunistically on every CLI invocation (via BannerServiceProvider),
10
10
  // so its version-check network calls must never be allowed to stall CLI startup.
11
11
  const VERSION_CHECK_TIMEOUT_MS = 250;
12
+ // SpawnService has no built-in cancellation, so a stalled `brew`/`winget` invocation (e.g. winget's
13
+ // first-ever run on a machine prompting to accept Microsoft Store terms) can otherwise hang
14
+ // checkForUpgrade() indefinitely. Racing against this bounds how long we wait for a result; the
15
+ // underlying process is not killed, but the CLI stops blocking on it.
16
+ async function withSpawnTimeout(spawnPromise, fallback) {
17
+ return Promise.race([
18
+ spawnPromise,
19
+ new Promise((resolve) => setTimeout(() => resolve(fallback), VERSION_CHECK_TIMEOUT_MS)),
20
+ ]);
21
+ }
12
22
  const OS_LABELS = {
13
23
  [SupportedOs.LINUX]: "Linux",
14
24
  [SupportedOs.MACOS]: "MacOS",
@@ -135,14 +145,20 @@ export default class DefaultUpgradeService {
135
145
  if (!this.#spawnService || !this.#config.homebrew) {
136
146
  return false;
137
147
  }
138
- const result = await this.#spawnService.spawn(["brew", "list", "--versions", this.#config.homebrew.formula], { stdio: "wrapped", longRunning: false });
148
+ const result = await withSpawnTimeout(this.#spawnService.spawn(["brew", "list", "--versions", this.#config.homebrew.formula], {
149
+ stdio: "wrapped",
150
+ longRunning: false,
151
+ }), { ok: false });
139
152
  return result.ok;
140
153
  }
141
154
  async #isWingetInstalled() {
142
155
  if (!this.#spawnService || !this.#config.winget) {
143
156
  return false;
144
157
  }
145
- const result = await this.#spawnService.spawn(["winget", "list", "--id", this.#config.winget.packageId], { stdio: "wrapped", longRunning: false });
158
+ const result = await withSpawnTimeout(this.#spawnService.spawn(["winget", "list", "--id", this.#config.winget.packageId], {
159
+ stdio: "wrapped",
160
+ longRunning: false,
161
+ }), { ok: false });
146
162
  return result.ok;
147
163
  }
148
164
  #isLinuxScriptInstall() {
@@ -206,11 +222,11 @@ export default class DefaultUpgradeService {
206
222
  return undefined;
207
223
  }
208
224
  const lines = [];
209
- const result = await this.#spawnService.spawn(["winget", "show", "--id", this.#config.winget.packageId], {
225
+ const result = await withSpawnTimeout(this.#spawnService.spawn(["winget", "show", "--id", this.#config.winget.packageId], {
210
226
  stdio: "wrapped",
211
227
  longRunning: false,
212
228
  onOutput: (line) => lines.push(line),
213
- });
229
+ }), { ok: false });
214
230
  if (!result.ok) {
215
231
  return undefined;
216
232
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowscripter/dynamic-cli-framework",
3
- "version": "2.3.2",
3
+ "version": "2.3.3",
4
4
  "description": "A framework for developing CLI applications which supports dynamic discovery and installation of new commands",
5
5
  "keywords": [
6
6
  "bun",
@@ -25,6 +25,17 @@ const logger = getLogger("DefaultUpgradeService");
25
25
  // so its version-check network calls must never be allowed to stall CLI startup.
26
26
  const VERSION_CHECK_TIMEOUT_MS = 250;
27
27
 
28
+ // SpawnService has no built-in cancellation, so a stalled `brew`/`winget` invocation (e.g. winget's
29
+ // first-ever run on a machine prompting to accept Microsoft Store terms) can otherwise hang
30
+ // checkForUpgrade() indefinitely. Racing against this bounds how long we wait for a result; the
31
+ // underlying process is not killed, but the CLI stops blocking on it.
32
+ async function withSpawnTimeout<T>(spawnPromise: Promise<T>, fallback: T): Promise<T> {
33
+ return Promise.race([
34
+ spawnPromise,
35
+ new Promise<T>((resolve) => setTimeout(() => resolve(fallback), VERSION_CHECK_TIMEOUT_MS)),
36
+ ]);
37
+ }
38
+
28
39
  const OS_LABELS: Record<SupportedOs, string> = {
29
40
  [SupportedOs.LINUX]: "Linux",
30
41
  [SupportedOs.MACOS]: "MacOS",
@@ -175,9 +186,12 @@ export default class DefaultUpgradeService implements UpgradeService {
175
186
  if (!this.#spawnService || !this.#config.homebrew) {
176
187
  return false;
177
188
  }
178
- const result = await this.#spawnService.spawn(
179
- ["brew", "list", "--versions", this.#config.homebrew.formula],
180
- { stdio: "wrapped", longRunning: false },
189
+ const result = await withSpawnTimeout(
190
+ this.#spawnService.spawn(["brew", "list", "--versions", this.#config.homebrew.formula], {
191
+ stdio: "wrapped",
192
+ longRunning: false,
193
+ }),
194
+ { ok: false } as const,
181
195
  );
182
196
  return result.ok;
183
197
  }
@@ -186,9 +200,12 @@ export default class DefaultUpgradeService implements UpgradeService {
186
200
  if (!this.#spawnService || !this.#config.winget) {
187
201
  return false;
188
202
  }
189
- const result = await this.#spawnService.spawn(
190
- ["winget", "list", "--id", this.#config.winget.packageId],
191
- { stdio: "wrapped", longRunning: false },
203
+ const result = await withSpawnTimeout(
204
+ this.#spawnService.spawn(["winget", "list", "--id", this.#config.winget.packageId], {
205
+ stdio: "wrapped",
206
+ longRunning: false,
207
+ }),
208
+ { ok: false } as const,
192
209
  );
193
210
  return result.ok;
194
211
  }
@@ -262,13 +279,13 @@ export default class DefaultUpgradeService implements UpgradeService {
262
279
  return undefined;
263
280
  }
264
281
  const lines: string[] = [];
265
- const result = await this.#spawnService.spawn(
266
- ["winget", "show", "--id", this.#config.winget.packageId],
267
- {
282
+ const result = await withSpawnTimeout(
283
+ this.#spawnService.spawn(["winget", "show", "--id", this.#config.winget.packageId], {
268
284
  stdio: "wrapped",
269
285
  longRunning: false,
270
286
  onOutput: (line) => lines.push(line),
271
- },
287
+ }),
288
+ { ok: false } as const,
272
289
  );
273
290
  if (!result.ok) {
274
291
  return undefined;