@zjex/git-workflow 0.5.2 → 0.6.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.
@@ -40,6 +40,74 @@ describe("Init 模块测试", () => {
40
40
  const mockJoin = vi.mocked(join);
41
41
  const mockHomedir = vi.mocked(homedir);
42
42
 
43
+ async function mockBasicInitFlow(options?: {
44
+ scope?: "global" | "project";
45
+ exists?: boolean;
46
+ overwrite?: boolean;
47
+ requireId?: boolean;
48
+ featureRequireDescription?: boolean;
49
+ hotfixRequireDescription?: boolean;
50
+ tagLookupStrategy?: "all" | "latest";
51
+ autoPushChoice?: "ask" | "yes" | "no";
52
+ autoStage?: boolean;
53
+ useEmoji?: boolean;
54
+ enableAI?: boolean;
55
+ inputs?: {
56
+ baseBranch?: string;
57
+ featurePrefix?: string;
58
+ hotfixPrefix?: string;
59
+ featureIdLabel?: string;
60
+ hotfixIdLabel?: string;
61
+ defaultTagPrefix?: string;
62
+ };
63
+ }) {
64
+ const {
65
+ scope = "project",
66
+ exists = false,
67
+ overwrite,
68
+ requireId = false,
69
+ featureRequireDescription = false,
70
+ hotfixRequireDescription = false,
71
+ tagLookupStrategy = "latest",
72
+ autoPushChoice = "ask",
73
+ autoStage = true,
74
+ useEmoji = true,
75
+ enableAI = false,
76
+ inputs = {},
77
+ } = options ?? {};
78
+
79
+ mockExistsSync.mockReturnValue(exists);
80
+
81
+ const { select, input } = await import("@inquirer/prompts");
82
+ const selectMock = vi.mocked(select);
83
+ const inputMock = vi.mocked(input);
84
+
85
+ selectMock.mockResolvedValueOnce(scope);
86
+ if (exists) {
87
+ selectMock.mockResolvedValueOnce(overwrite ?? true);
88
+ }
89
+
90
+ selectMock
91
+ .mockResolvedValueOnce(requireId)
92
+ .mockResolvedValueOnce(featureRequireDescription)
93
+ .mockResolvedValueOnce(hotfixRequireDescription)
94
+ .mockResolvedValueOnce(tagLookupStrategy)
95
+ .mockResolvedValueOnce(autoPushChoice)
96
+ .mockResolvedValueOnce(autoStage)
97
+ .mockResolvedValueOnce(useEmoji)
98
+ .mockResolvedValueOnce(enableAI);
99
+
100
+ inputMock
101
+ .mockResolvedValueOnce(inputs.baseBranch ?? "")
102
+ .mockResolvedValueOnce(inputs.featurePrefix ?? "feature")
103
+ .mockResolvedValueOnce(inputs.hotfixPrefix ?? "hotfix")
104
+ .mockResolvedValueOnce(inputs.featureIdLabel ?? "Story ID")
105
+ .mockResolvedValueOnce(inputs.hotfixIdLabel ?? "Issue ID")
106
+ .mockResolvedValueOnce(inputs.defaultTagPrefix ?? "");
107
+
108
+ return { select: selectMock, input: inputMock };
109
+ }
110
+
43
111
  beforeEach(() => {
44
112
  vi.clearAllMocks();
45
113
  vi.spyOn(console, "log").mockImplementation(() => {});
@@ -53,24 +121,7 @@ describe("Init 模块测试", () => {
53
121
 
54
122
  describe("配置范围选择", () => {
55
123
  it("应该支持全局配置", async () => {
56
- mockExistsSync.mockReturnValue(false);
57
- const { select, input } = await import("@inquirer/prompts");
58
- vi.mocked(select)
59
- .mockResolvedValueOnce("global")
60
- .mockResolvedValueOnce(false)
61
- .mockResolvedValueOnce(false)
62
- .mockResolvedValueOnce(false)
63
- .mockResolvedValueOnce("ask")
64
- .mockResolvedValueOnce(true)
65
- .mockResolvedValueOnce(true)
66
- .mockResolvedValueOnce(false);
67
- vi.mocked(input)
68
- .mockResolvedValueOnce("")
69
- .mockResolvedValueOnce("feature")
70
- .mockResolvedValueOnce("hotfix")
71
- .mockResolvedValueOnce("Story ID")
72
- .mockResolvedValueOnce("Issue ID")
73
- .mockResolvedValueOnce("");
124
+ await mockBasicInitFlow({ scope: "global" });
74
125
  const { init } = await import("../src/commands/init.js");
75
126
  await init();
76
127
  expect(mockJoin).toHaveBeenCalledWith("/home/user", ".gwrc.json");
@@ -81,24 +132,7 @@ describe("Init 模块测试", () => {
81
132
  });
82
133
 
83
134
  it("应该支持项目配置", async () => {
84
- mockExistsSync.mockReturnValue(false);
85
- const { select, input } = await import("@inquirer/prompts");
86
- vi.mocked(select)
87
- .mockResolvedValueOnce("project")
88
- .mockResolvedValueOnce(false)
89
- .mockResolvedValueOnce(false)
90
- .mockResolvedValueOnce(false)
91
- .mockResolvedValueOnce("ask")
92
- .mockResolvedValueOnce(true)
93
- .mockResolvedValueOnce(true)
94
- .mockResolvedValueOnce(false);
95
- vi.mocked(input)
96
- .mockResolvedValueOnce("")
97
- .mockResolvedValueOnce("feature")
98
- .mockResolvedValueOnce("hotfix")
99
- .mockResolvedValueOnce("Story ID")
100
- .mockResolvedValueOnce("Issue ID")
101
- .mockResolvedValueOnce("");
135
+ await mockBasicInitFlow({ scope: "project" });
102
136
  const { init } = await import("../src/commands/init.js");
103
137
  await init();
104
138
  expect(mockWriteFileSync).toHaveBeenCalledWith(
@@ -110,25 +144,7 @@ describe("Init 模块测试", () => {
110
144
 
111
145
  describe("配置文件覆盖", () => {
112
146
  it("应该处理配置文件已存在的情况", async () => {
113
- mockExistsSync.mockReturnValue(true);
114
- const { select, input } = await import("@inquirer/prompts");
115
- vi.mocked(select)
116
- .mockResolvedValueOnce("global")
117
- .mockResolvedValueOnce(true)
118
- .mockResolvedValueOnce(false)
119
- .mockResolvedValueOnce(false)
120
- .mockResolvedValueOnce(false)
121
- .mockResolvedValueOnce("ask")
122
- .mockResolvedValueOnce(true)
123
- .mockResolvedValueOnce(true)
124
- .mockResolvedValueOnce(false);
125
- vi.mocked(input)
126
- .mockResolvedValueOnce("")
127
- .mockResolvedValueOnce("feature")
128
- .mockResolvedValueOnce("hotfix")
129
- .mockResolvedValueOnce("Story ID")
130
- .mockResolvedValueOnce("Issue ID")
131
- .mockResolvedValueOnce("");
147
+ await mockBasicInitFlow({ scope: "global", exists: true, overwrite: true });
132
148
  const { init } = await import("../src/commands/init.js");
133
149
  await init();
134
150
  expect(mockWriteFileSync).toHaveBeenCalled();
@@ -149,24 +165,16 @@ describe("Init 模块测试", () => {
149
165
 
150
166
  describe("基础配置", () => {
151
167
  it("应该正确配置分支前缀", async () => {
152
- mockExistsSync.mockReturnValue(false);
153
- const { select, input } = await import("@inquirer/prompts");
154
- vi.mocked(select)
155
- .mockResolvedValueOnce("project")
156
- .mockResolvedValueOnce(false)
157
- .mockResolvedValueOnce(false)
158
- .mockResolvedValueOnce(false)
159
- .mockResolvedValueOnce("ask")
160
- .mockResolvedValueOnce(true)
161
- .mockResolvedValueOnce(true)
162
- .mockResolvedValueOnce(false);
163
- vi.mocked(input)
164
- .mockResolvedValueOnce("develop")
165
- .mockResolvedValueOnce("feat")
166
- .mockResolvedValueOnce("fix")
167
- .mockResolvedValueOnce("Jira ID")
168
- .mockResolvedValueOnce("Bug ID")
169
- .mockResolvedValueOnce("v");
168
+ await mockBasicInitFlow({
169
+ inputs: {
170
+ baseBranch: "develop",
171
+ featurePrefix: "feat",
172
+ hotfixPrefix: "fix",
173
+ featureIdLabel: "Jira ID",
174
+ hotfixIdLabel: "Bug ID",
175
+ defaultTagPrefix: "v",
176
+ },
177
+ });
170
178
  const { init } = await import("../src/commands/init.js");
171
179
  await init();
172
180
  const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
@@ -177,27 +185,11 @@ describe("Init 模块测试", () => {
177
185
  expect(config.featureIdLabel).toBe("Jira ID");
178
186
  expect(config.hotfixIdLabel).toBe("Bug ID");
179
187
  expect(config.defaultTagPrefix).toBe("v");
188
+ expect(config.tagLookupStrategy).toBe("latest");
180
189
  });
181
190
 
182
191
  it("应该正确配置 ID 要求", async () => {
183
- mockExistsSync.mockReturnValue(false);
184
- const { select, input } = await import("@inquirer/prompts");
185
- vi.mocked(select)
186
- .mockResolvedValueOnce("project")
187
- .mockResolvedValueOnce(true)
188
- .mockResolvedValueOnce(false)
189
- .mockResolvedValueOnce(false)
190
- .mockResolvedValueOnce("ask")
191
- .mockResolvedValueOnce(true)
192
- .mockResolvedValueOnce(true)
193
- .mockResolvedValueOnce(false);
194
- vi.mocked(input)
195
- .mockResolvedValueOnce("")
196
- .mockResolvedValueOnce("feature")
197
- .mockResolvedValueOnce("hotfix")
198
- .mockResolvedValueOnce("Story ID")
199
- .mockResolvedValueOnce("Issue ID")
200
- .mockResolvedValueOnce("");
192
+ await mockBasicInitFlow({ requireId: true });
201
193
  const { init } = await import("../src/commands/init.js");
202
194
  await init();
203
195
  const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
@@ -206,57 +198,33 @@ describe("Init 模块测试", () => {
206
198
  });
207
199
 
208
200
  it("应该正确配置自动推送选项", async () => {
209
- mockExistsSync.mockReturnValue(false);
210
- const { select, input } = await import("@inquirer/prompts");
211
- vi.mocked(select)
212
- .mockResolvedValueOnce("project")
213
- .mockResolvedValueOnce(false)
214
- .mockResolvedValueOnce(false)
215
- .mockResolvedValueOnce(false)
216
- .mockResolvedValueOnce("yes")
217
- .mockResolvedValueOnce(true)
218
- .mockResolvedValueOnce(true)
219
- .mockResolvedValueOnce(false);
220
- vi.mocked(input)
221
- .mockResolvedValueOnce("")
222
- .mockResolvedValueOnce("feature")
223
- .mockResolvedValueOnce("hotfix")
224
- .mockResolvedValueOnce("Story ID")
225
- .mockResolvedValueOnce("Issue ID")
226
- .mockResolvedValueOnce("");
201
+ await mockBasicInitFlow({ autoPushChoice: "yes" });
227
202
  const { init } = await import("../src/commands/init.js");
228
203
  await init();
229
204
  const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
230
205
  const config = JSON.parse(writtenConfig);
231
206
  expect(config.autoPush).toBe(true);
232
207
  });
208
+
209
+ it("应该支持配置 tagLookupStrategy 为 latest", async () => {
210
+ await mockBasicInitFlow({ tagLookupStrategy: "latest" });
211
+ const { init } = await import("../src/commands/init.js");
212
+ await init();
213
+ const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
214
+ const config = JSON.parse(writtenConfig);
215
+ expect(config.tagLookupStrategy).toBe("latest");
216
+ });
233
217
  });
234
218
 
235
219
  describe("AI 配置", () => {
236
220
  it("应该正确配置 GitHub Models", async () => {
237
- mockExistsSync.mockReturnValue(false);
238
- const { select, input } = await import("@inquirer/prompts");
239
- vi.mocked(select)
240
- .mockResolvedValueOnce("project")
241
- .mockResolvedValueOnce(false)
242
- .mockResolvedValueOnce(false)
243
- .mockResolvedValueOnce(false)
244
- .mockResolvedValueOnce("ask")
245
- .mockResolvedValueOnce(true)
246
- .mockResolvedValueOnce(true)
247
- .mockResolvedValueOnce(true)
221
+ const { select, input } = await mockBasicInitFlow({ enableAI: true });
222
+ select
248
223
  .mockResolvedValueOnce("github")
249
224
  .mockResolvedValueOnce("zh-CN")
250
225
  .mockResolvedValueOnce(true)
251
226
  .mockResolvedValueOnce(true);
252
- vi.mocked(input)
253
- .mockResolvedValueOnce("")
254
- .mockResolvedValueOnce("feature")
255
- .mockResolvedValueOnce("hotfix")
256
- .mockResolvedValueOnce("Story ID")
257
- .mockResolvedValueOnce("Issue ID")
258
- .mockResolvedValueOnce("")
259
- .mockResolvedValueOnce("ghp_test_token");
227
+ input.mockResolvedValueOnce("ghp_test_token");
260
228
  const { init } = await import("../src/commands/init.js");
261
229
  await init();
262
230
  const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
@@ -269,29 +237,13 @@ describe("Init 模块测试", () => {
269
237
  });
270
238
 
271
239
  it("应该正确配置 OpenAI", async () => {
272
- mockExistsSync.mockReturnValue(false);
273
- const { select, input } = await import("@inquirer/prompts");
274
- vi.mocked(select)
275
- .mockResolvedValueOnce("project")
276
- .mockResolvedValueOnce(false)
277
- .mockResolvedValueOnce(false)
278
- .mockResolvedValueOnce(false)
279
- .mockResolvedValueOnce("ask")
280
- .mockResolvedValueOnce(true)
281
- .mockResolvedValueOnce(true)
282
- .mockResolvedValueOnce(true)
240
+ const { select, input } = await mockBasicInitFlow({ enableAI: true });
241
+ select
283
242
  .mockResolvedValueOnce("openai")
284
243
  .mockResolvedValueOnce("en-US")
285
244
  .mockResolvedValueOnce(true)
286
245
  .mockResolvedValueOnce(true);
287
- vi.mocked(input)
288
- .mockResolvedValueOnce("")
289
- .mockResolvedValueOnce("feature")
290
- .mockResolvedValueOnce("hotfix")
291
- .mockResolvedValueOnce("Story ID")
292
- .mockResolvedValueOnce("Issue ID")
293
- .mockResolvedValueOnce("")
294
- .mockResolvedValueOnce("sk-test-key");
246
+ input.mockResolvedValueOnce("sk-test-key");
295
247
  const { init } = await import("../src/commands/init.js");
296
248
  await init();
297
249
  const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
@@ -304,28 +256,12 @@ describe("Init 模块测试", () => {
304
256
  });
305
257
 
306
258
  it("应该正确配置 Ollama", async () => {
307
- mockExistsSync.mockReturnValue(false);
308
- const { select, input } = await import("@inquirer/prompts");
309
- vi.mocked(select)
310
- .mockResolvedValueOnce("project")
311
- .mockResolvedValueOnce(false)
312
- .mockResolvedValueOnce(false)
313
- .mockResolvedValueOnce(false)
314
- .mockResolvedValueOnce("ask")
315
- .mockResolvedValueOnce(true)
316
- .mockResolvedValueOnce(true)
317
- .mockResolvedValueOnce(true)
259
+ const { select } = await mockBasicInitFlow({ enableAI: true });
260
+ select
318
261
  .mockResolvedValueOnce("ollama")
319
262
  .mockResolvedValueOnce("zh-CN")
320
263
  .mockResolvedValueOnce(true)
321
264
  .mockResolvedValueOnce(true);
322
- vi.mocked(input)
323
- .mockResolvedValueOnce("")
324
- .mockResolvedValueOnce("feature")
325
- .mockResolvedValueOnce("hotfix")
326
- .mockResolvedValueOnce("Story ID")
327
- .mockResolvedValueOnce("Issue ID")
328
- .mockResolvedValueOnce("");
329
265
  const { init } = await import("../src/commands/init.js");
330
266
  await init();
331
267
  const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
@@ -338,24 +274,7 @@ describe("Init 模块测试", () => {
338
274
  });
339
275
 
340
276
  it("应该正确配置禁用 AI", async () => {
341
- mockExistsSync.mockReturnValue(false);
342
- const { select, input } = await import("@inquirer/prompts");
343
- vi.mocked(select)
344
- .mockResolvedValueOnce("project")
345
- .mockResolvedValueOnce(false)
346
- .mockResolvedValueOnce(false)
347
- .mockResolvedValueOnce(false)
348
- .mockResolvedValueOnce("ask")
349
- .mockResolvedValueOnce(true)
350
- .mockResolvedValueOnce(true)
351
- .mockResolvedValueOnce(false);
352
- vi.mocked(input)
353
- .mockResolvedValueOnce("")
354
- .mockResolvedValueOnce("feature")
355
- .mockResolvedValueOnce("hotfix")
356
- .mockResolvedValueOnce("Story ID")
357
- .mockResolvedValueOnce("Issue ID")
358
- .mockResolvedValueOnce("");
277
+ await mockBasicInitFlow({ enableAI: false });
359
278
  const { init } = await import("../src/commands/init.js");
360
279
  await init();
361
280
  const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
@@ -366,29 +285,13 @@ describe("Init 模块测试", () => {
366
285
 
367
286
  describe("配置验证", () => {
368
287
  it("应该验证 GitHub Token 不为空", async () => {
369
- mockExistsSync.mockReturnValue(false);
370
- const { select, input } = await import("@inquirer/prompts");
371
- vi.mocked(select)
372
- .mockResolvedValueOnce("project")
373
- .mockResolvedValueOnce(false)
374
- .mockResolvedValueOnce(false)
375
- .mockResolvedValueOnce(false)
376
- .mockResolvedValueOnce("ask")
377
- .mockResolvedValueOnce(true)
378
- .mockResolvedValueOnce(true)
379
- .mockResolvedValueOnce(true)
288
+ const { select, input } = await mockBasicInitFlow({ enableAI: true });
289
+ select
380
290
  .mockResolvedValueOnce("github")
381
291
  .mockResolvedValueOnce("zh-CN")
382
292
  .mockResolvedValueOnce(true)
383
293
  .mockResolvedValueOnce(true);
384
- vi.mocked(input)
385
- .mockResolvedValueOnce("")
386
- .mockResolvedValueOnce("feature")
387
- .mockResolvedValueOnce("hotfix")
388
- .mockResolvedValueOnce("Story ID")
389
- .mockResolvedValueOnce("Issue ID")
390
- .mockResolvedValueOnce("")
391
- .mockResolvedValueOnce("ghp_valid_token");
294
+ input.mockResolvedValueOnce("ghp_valid_token");
392
295
  const { init } = await import("../src/commands/init.js");
393
296
  await init();
394
297
  const inputCalls = vi.mocked(input).mock.calls;
@@ -403,29 +306,13 @@ describe("Init 模块测试", () => {
403
306
  });
404
307
 
405
308
  it("应该验证 OpenAI API Key 不为空", async () => {
406
- mockExistsSync.mockReturnValue(false);
407
- const { select, input } = await import("@inquirer/prompts");
408
- vi.mocked(select)
409
- .mockResolvedValueOnce("project")
410
- .mockResolvedValueOnce(false)
411
- .mockResolvedValueOnce(false)
412
- .mockResolvedValueOnce(false)
413
- .mockResolvedValueOnce("ask")
414
- .mockResolvedValueOnce(true)
415
- .mockResolvedValueOnce(true)
416
- .mockResolvedValueOnce(true)
309
+ const { select, input } = await mockBasicInitFlow({ enableAI: true });
310
+ select
417
311
  .mockResolvedValueOnce("openai")
418
312
  .mockResolvedValueOnce("en-US")
419
313
  .mockResolvedValueOnce(true)
420
314
  .mockResolvedValueOnce(true);
421
- vi.mocked(input)
422
- .mockResolvedValueOnce("")
423
- .mockResolvedValueOnce("feature")
424
- .mockResolvedValueOnce("hotfix")
425
- .mockResolvedValueOnce("Story ID")
426
- .mockResolvedValueOnce("Issue ID")
427
- .mockResolvedValueOnce("")
428
- .mockResolvedValueOnce("sk-valid-key");
315
+ input.mockResolvedValueOnce("sk-valid-key");
429
316
  const { init } = await import("../src/commands/init.js");
430
317
  await init();
431
318
  const inputCalls = vi.mocked(input).mock.calls;
@@ -442,24 +329,7 @@ describe("Init 模块测试", () => {
442
329
 
443
330
  describe("配置输出", () => {
444
331
  it("应该包含默认的 commit emojis", async () => {
445
- mockExistsSync.mockReturnValue(false);
446
- const { select, input } = await import("@inquirer/prompts");
447
- vi.mocked(select)
448
- .mockResolvedValueOnce("project")
449
- .mockResolvedValueOnce(false)
450
- .mockResolvedValueOnce(false)
451
- .mockResolvedValueOnce(false)
452
- .mockResolvedValueOnce("ask")
453
- .mockResolvedValueOnce(true)
454
- .mockResolvedValueOnce(true)
455
- .mockResolvedValueOnce(false);
456
- vi.mocked(input)
457
- .mockResolvedValueOnce("")
458
- .mockResolvedValueOnce("feature")
459
- .mockResolvedValueOnce("hotfix")
460
- .mockResolvedValueOnce("Story ID")
461
- .mockResolvedValueOnce("Issue ID")
462
- .mockResolvedValueOnce("");
332
+ await mockBasicInitFlow();
463
333
  const { init } = await import("../src/commands/init.js");
464
334
  await init();
465
335
  const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
@@ -471,24 +341,7 @@ describe("Init 模块测试", () => {
471
341
  });
472
342
 
473
343
  it("应该显示成功消息", async () => {
474
- mockExistsSync.mockReturnValue(false);
475
- const { select, input } = await import("@inquirer/prompts");
476
- vi.mocked(select)
477
- .mockResolvedValueOnce("global")
478
- .mockResolvedValueOnce(false)
479
- .mockResolvedValueOnce(false)
480
- .mockResolvedValueOnce(false)
481
- .mockResolvedValueOnce("ask")
482
- .mockResolvedValueOnce(true)
483
- .mockResolvedValueOnce(true)
484
- .mockResolvedValueOnce(false);
485
- vi.mocked(input)
486
- .mockResolvedValueOnce("")
487
- .mockResolvedValueOnce("feature")
488
- .mockResolvedValueOnce("hotfix")
489
- .mockResolvedValueOnce("Story ID")
490
- .mockResolvedValueOnce("Issue ID")
491
- .mockResolvedValueOnce("");
344
+ await mockBasicInitFlow({ scope: "global" });
492
345
  const { init } = await import("../src/commands/init.js");
493
346
  await init();
494
347
  expect(console.log).toHaveBeenCalledWith(
@@ -497,24 +350,7 @@ describe("Init 模块测试", () => {
497
350
  });
498
351
 
499
352
  it("应该显示全局配置的提示信息", async () => {
500
- mockExistsSync.mockReturnValue(false);
501
- const { select, input } = await import("@inquirer/prompts");
502
- vi.mocked(select)
503
- .mockResolvedValueOnce("global")
504
- .mockResolvedValueOnce(false)
505
- .mockResolvedValueOnce(false)
506
- .mockResolvedValueOnce(false)
507
- .mockResolvedValueOnce("ask")
508
- .mockResolvedValueOnce(true)
509
- .mockResolvedValueOnce(true)
510
- .mockResolvedValueOnce(false);
511
- vi.mocked(input)
512
- .mockResolvedValueOnce("")
513
- .mockResolvedValueOnce("feature")
514
- .mockResolvedValueOnce("hotfix")
515
- .mockResolvedValueOnce("Story ID")
516
- .mockResolvedValueOnce("Issue ID")
517
- .mockResolvedValueOnce("");
353
+ await mockBasicInitFlow({ scope: "global" });
518
354
  const { init } = await import("../src/commands/init.js");
519
355
  await init();
520
356
  expect(console.log).toHaveBeenCalledWith(