@lambertkeith/spec-go 0.2.5 → 0.3.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.
@@ -6,27 +6,75 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
6
6
  throw Error('Dynamic require of "' + x + '" is not supported');
7
7
  });
8
8
 
9
- // src/cli.ts
9
+ // src/cli/cli.ts
10
10
  import path7 from "path";
11
11
  import fs5 from "fs";
12
12
  import { Command } from "commander";
13
- import pc6 from "picocolors";
13
+ import pc5 from "picocolors";
14
14
 
15
15
  // package.json
16
- var version = "0.2.5";
16
+ var version = "0.3.0";
17
17
 
18
- // src/prompts.ts
19
- import path2 from "path";
20
- import fs from "fs";
18
+ // src/cli/prompts.ts
19
+ import path5 from "path";
20
+ import fs3 from "fs";
21
21
  import { input, select, confirm, Separator } from "@inquirer/prompts";
22
22
  import pc from "picocolors";
23
23
 
24
- // src/utils.ts
24
+ // src/core/types.ts
25
+ var silentLogger = {
26
+ info: () => {
27
+ },
28
+ success: () => {
29
+ },
30
+ warn: () => {
31
+ },
32
+ error: () => {
33
+ },
34
+ dim: () => {
35
+ }
36
+ };
37
+
38
+ // src/core/config.ts
39
+ import fs from "fs";
25
40
  import path from "path";
26
- import { fileURLToPath } from "url";
27
- import { spawn } from "child_process";
41
+ import os from "os";
42
+ var CONFIG_PATH = path.join(os.homedir(), ".spec-go.json");
43
+ var DEFAULT_CONFIG = {
44
+ defaults: {
45
+ github: false,
46
+ public: false,
47
+ template: ""
48
+ },
49
+ github: {
50
+ token: "",
51
+ defaultOrg: ""
52
+ }
53
+ };
54
+ function ensureConfigExists() {
55
+ if (!fs.existsSync(CONFIG_PATH)) {
56
+ saveConfig(DEFAULT_CONFIG);
57
+ }
58
+ }
59
+ function loadConfig() {
60
+ try {
61
+ if (fs.existsSync(CONFIG_PATH)) {
62
+ const content = fs.readFileSync(CONFIG_PATH, "utf-8");
63
+ return JSON.parse(content);
64
+ }
65
+ } catch {
66
+ }
67
+ return {};
68
+ }
69
+ function saveConfig(config) {
70
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
71
+ fs.chmodSync(CONFIG_PATH, 384);
72
+ }
73
+ function getConfigPath() {
74
+ return CONFIG_PATH;
75
+ }
28
76
 
29
- // src/debug.ts
77
+ // src/core/debug.ts
30
78
  var debugEnabled = false;
31
79
  function setDebugEnabled(enabled) {
32
80
  debugEnabled = enabled;
@@ -57,11 +105,39 @@ function formatData(data) {
57
105
  }
58
106
  }
59
107
 
60
- // src/utils.ts
108
+ // src/core/exit-codes.ts
109
+ var ExitCodes = {
110
+ /** 成功完成 */
111
+ SUCCESS: 0,
112
+ /** 用户错误:参数错误、输入无效 */
113
+ USER_ERROR: 1,
114
+ /** 外部错误:网络、GitHub API、包管理器 */
115
+ EXTERNAL_ERROR: 2,
116
+ /** 未知内部错误 */
117
+ INTERNAL_ERROR: 10,
118
+ /** 模板相关错误 */
119
+ TEMPLATE_ERROR: 11,
120
+ /** 文件系统错误 */
121
+ FILE_SYSTEM_ERROR: 12,
122
+ /** Git 操作错误 */
123
+ GIT_ERROR: 13
124
+ };
125
+ var CliError = class extends Error {
126
+ constructor(message, exitCode = ExitCodes.INTERNAL_ERROR) {
127
+ super(message);
128
+ this.exitCode = exitCode;
129
+ this.name = "CliError";
130
+ }
131
+ };
132
+
133
+ // src/core/utils.ts
134
+ import path2 from "path";
135
+ import { fileURLToPath } from "url";
136
+ import { spawn } from "child_process";
61
137
  var __filename = fileURLToPath(import.meta.url);
62
- var __dirname = path.dirname(__filename);
138
+ var __dirname = path2.dirname(__filename);
63
139
  function getTemplatesDir() {
64
- return path.resolve(__dirname, "..", "templates");
140
+ return path2.resolve(__dirname, "..", "..", "templates");
65
141
  }
66
142
  function isValidPackageName(name) {
67
143
  return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name);
@@ -108,157 +184,7 @@ function execAsync(command, args, options = {}) {
108
184
  });
109
185
  }
110
186
 
111
- // src/exit-codes.ts
112
- var ExitCodes = {
113
- /** 成功完成 */
114
- SUCCESS: 0,
115
- /** 用户错误:参数错误、输入无效 */
116
- USER_ERROR: 1,
117
- /** 外部错误:网络、GitHub API、包管理器 */
118
- EXTERNAL_ERROR: 2,
119
- /** 未知内部错误 */
120
- INTERNAL_ERROR: 10,
121
- /** 模板相关错误 */
122
- TEMPLATE_ERROR: 11,
123
- /** 文件系统错误 */
124
- FILE_SYSTEM_ERROR: 12,
125
- /** Git 操作错误 */
126
- GIT_ERROR: 13
127
- };
128
- var CliError = class extends Error {
129
- constructor(message, exitCode = ExitCodes.INTERNAL_ERROR) {
130
- super(message);
131
- this.exitCode = exitCode;
132
- this.name = "CliError";
133
- }
134
- };
135
-
136
- // src/prompts.ts
137
- var DEFAULT_TEMPLATE = "node-ts";
138
- async function runPrompts(argProjectName, options, userConfig = {}, interactive = true) {
139
- const defaults = userConfig.defaults ?? {};
140
- const templatesDir = getTemplatesDir();
141
- const registryPath = path2.join(templatesDir, "template.config.json");
142
- const registry = JSON.parse(
143
- fs.readFileSync(registryPath, "utf-8")
144
- );
145
- debug("prompts", `\u4EA4\u4E92\u6A21\u5F0F: ${interactive}`);
146
- debug("prompts", `CLI \u53C2\u6570`, { argProjectName, options });
147
- let projectName = argProjectName;
148
- if (!projectName) {
149
- if (!interactive) {
150
- console.log(pc.red("\u9519\u8BEF: \u975E\u4EA4\u4E92\u6A21\u5F0F\u4E0B\u5FC5\u987B\u63D0\u4F9B\u9879\u76EE\u540D\u79F0"));
151
- throw new CliError("\u975E\u4EA4\u4E92\u6A21\u5F0F\u4E0B\u5FC5\u987B\u63D0\u4F9B\u9879\u76EE\u540D\u79F0", ExitCodes.USER_ERROR);
152
- }
153
- projectName = await input({
154
- message: "\u9879\u76EE\u540D\u79F0:",
155
- default: "my-project",
156
- validate: (value) => {
157
- if (!value.trim()) {
158
- return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
159
- }
160
- if (!isValidPackageName(toValidPackageName(value))) {
161
- return "\u65E0\u6548\u7684\u9879\u76EE\u540D\u79F0";
162
- }
163
- return true;
164
- }
165
- });
166
- }
167
- const validName = toValidPackageName(projectName);
168
- const targetDir = path2.resolve(process.cwd(), validName);
169
- if (fs.existsSync(targetDir) && !isEmpty(targetDir)) {
170
- if (!interactive) {
171
- console.log(pc.yellow(`\u8B66\u544A: \u76EE\u6807\u76EE\u5F55 "${validName}" \u975E\u7A7A\uFF0C\u5C06\u8986\u76D6\u5DF2\u6709\u6587\u4EF6`));
172
- } else {
173
- const overwrite = await confirm({
174
- message: `\u76EE\u6807\u76EE\u5F55 "${validName}" \u975E\u7A7A\uFF0C\u662F\u5426\u7EE7\u7EED? (\u5C06\u8986\u76D6\u5DF2\u6709\u6587\u4EF6)`,
175
- default: false
176
- });
177
- if (!overwrite) {
178
- const error = new Error("PROMPT_CANCELLED");
179
- throw error;
180
- }
181
- }
182
- }
183
- let template = options.template;
184
- if (!template) {
185
- if (!interactive) {
186
- template = defaults.template || DEFAULT_TEMPLATE;
187
- console.log(pc.dim(`\u4F7F\u7528\u9ED8\u8BA4\u6A21\u677F: ${template}`));
188
- } else {
189
- const defaultTemplate = defaults.template;
190
- const singleTemplates = registry.templates.filter((t) => t.category !== "fullstack");
191
- const fullstackTemplates = registry.templates.filter((t) => t.category === "fullstack");
192
- const templateChoices = [];
193
- templateChoices.push(new Separator("\u2500\u2500 \u5355\u4F53\u9879\u76EE \u2500\u2500"));
194
- for (const t of singleTemplates) {
195
- templateChoices.push({
196
- name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,
197
- value: t.name
198
- });
199
- }
200
- if (fullstackTemplates.length > 0) {
201
- templateChoices.push(new Separator("\u2500\u2500 \u524D\u540E\u7AEF\u5206\u79BB \u2500\u2500"));
202
- for (const t of fullstackTemplates) {
203
- templateChoices.push({
204
- name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,
205
- value: t.name
206
- });
207
- }
208
- }
209
- template = await select({
210
- message: "\u9009\u62E9\u6A21\u677F:",
211
- choices: templateChoices,
212
- default: defaultTemplate && registry.templates.some((t) => t.name === defaultTemplate) ? defaultTemplate : void 0
213
- });
214
- }
215
- }
216
- const found = registry.templates.find((t) => t.name === template);
217
- if (!found) {
218
- console.log(pc.red(`\u9519\u8BEF: \u672A\u627E\u5230\u6A21\u677F "${template}"`));
219
- console.log(pc.dim(`\u53EF\u7528\u6A21\u677F: ${registry.templates.map((t) => t.name).join(", ")}`));
220
- throw new CliError(`\u672A\u627E\u5230\u6A21\u677F "${template}"`, ExitCodes.USER_ERROR);
221
- }
222
- let initGit2 = options.git !== false;
223
- if (options.git === void 0 && interactive) {
224
- initGit2 = await confirm({
225
- message: "\u521D\u59CB\u5316 Git \u4ED3\u5E93?",
226
- default: true
227
- });
228
- }
229
- let createGithub = options.github ?? false;
230
- if (initGit2 && options.github === void 0 && interactive) {
231
- createGithub = await confirm({
232
- message: "\u5728 GitHub \u521B\u5EFA\u8FDC\u7A0B\u4ED3\u5E93?",
233
- default: defaults.github ?? false
234
- });
235
- }
236
- let isPublic = options.public ?? false;
237
- if (createGithub && options.public === void 0 && interactive) {
238
- const publicDefault = defaults.public ?? false;
239
- isPublic = await select({
240
- message: "\u4ED3\u5E93\u53EF\u89C1\u6027:",
241
- choices: [
242
- { name: "private (\u79C1\u6709)", value: false },
243
- { name: "public (\u516C\u5F00)", value: true }
244
- ],
245
- default: publicDefault
246
- });
247
- }
248
- const result = {
249
- projectName: validName,
250
- template,
251
- targetDir,
252
- initGit: initGit2,
253
- createGithub,
254
- isPublic,
255
- noInstall: options.install === false
256
- };
257
- debug("prompts", "\u6700\u7EC8\u9879\u76EE\u9009\u9879", result);
258
- return result;
259
- }
260
-
261
- // src/scaffold.ts
187
+ // src/core/scaffold.ts
262
188
  import path3 from "path";
263
189
  import fs2 from "fs-extra";
264
190
  async function scaffoldProject(options) {
@@ -361,49 +287,7 @@ async function copyFile(srcPath, destPath, projectName, config) {
361
287
  await fs2.writeFile(destPath, content, "utf-8");
362
288
  }
363
289
 
364
- // src/git.ts
365
- import pc2 from "picocolors";
366
-
367
- // src/config.ts
368
- import fs3 from "fs";
369
- import path4 from "path";
370
- import os from "os";
371
- var CONFIG_PATH = path4.join(os.homedir(), ".spec-go.json");
372
- var DEFAULT_CONFIG = {
373
- defaults: {
374
- github: false,
375
- public: false,
376
- template: ""
377
- },
378
- github: {
379
- token: "",
380
- defaultOrg: ""
381
- }
382
- };
383
- function ensureConfigExists() {
384
- if (!fs3.existsSync(CONFIG_PATH)) {
385
- saveConfig(DEFAULT_CONFIG);
386
- }
387
- }
388
- function loadConfig() {
389
- try {
390
- if (fs3.existsSync(CONFIG_PATH)) {
391
- const content = fs3.readFileSync(CONFIG_PATH, "utf-8");
392
- return JSON.parse(content);
393
- }
394
- } catch {
395
- }
396
- return {};
397
- }
398
- function saveConfig(config) {
399
- fs3.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
400
- fs3.chmodSync(CONFIG_PATH, 384);
401
- }
402
- function getConfigPath() {
403
- return CONFIG_PATH;
404
- }
405
-
406
- // src/github-api.ts
290
+ // src/core/github-api.ts
407
291
  var GITHUB_API_BASE = "https://api.github.com";
408
292
  async function githubFetch(endpoint, token, options = {}) {
409
293
  const url = `${GITHUB_API_BASE}${endpoint}`;
@@ -413,7 +297,7 @@ async function githubFetch(endpoint, token, options = {}) {
413
297
  ...options,
414
298
  headers: {
415
299
  "Accept": "application/vnd.github+json",
416
- "Authorization": `Bearer ${token.slice(0, 8)}...`,
300
+ "Authorization": `Bearer ${token}`,
417
301
  "X-GitHub-Api-Version": "2022-11-28",
418
302
  "User-Agent": "spec-go",
419
303
  ...options.headers
@@ -479,7 +363,7 @@ async function createRepository(token, options) {
479
363
  });
480
364
  }
481
365
 
482
- // src/git.ts
366
+ // src/core/git.ts
483
367
  async function initGit(targetDir) {
484
368
  debug("git", `\u521D\u59CB\u5316 Git \u4ED3\u5E93: ${targetDir}`);
485
369
  await execAsync("git", ["init"], { cwd: targetDir });
@@ -487,27 +371,27 @@ async function initGit(targetDir) {
487
371
  await execAsync("git", ["commit", "-m", "Initial commit"], { cwd: targetDir });
488
372
  debug("git", "Git \u521D\u59CB\u5316\u5B8C\u6210");
489
373
  }
490
- async function createGithubRepo(repoName, targetDir, isPublic) {
374
+ async function createGithubRepo(options) {
375
+ const { repoName, targetDir, isPublic, organization, logger = silentLogger } = options;
491
376
  debug("git", `\u521B\u5EFA GitHub \u4ED3\u5E93: ${repoName}, \u516C\u5F00: ${isPublic}`);
492
377
  const config = loadConfig();
493
378
  if (!config.github?.token) {
494
- console.log(pc2.yellow("\u26A0 \u672A\u914D\u7F6E GitHub Token\uFF0C\u8DF3\u8FC7\u4ED3\u5E93\u521B\u5EFA"));
495
- console.log(pc2.dim(` \u8FD0\u884C ${pc2.cyan("spec-go config --setup-github")} \u914D\u7F6E Token`));
496
- console.log(pc2.dim(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${getConfigPath()}`));
379
+ logger.warn("\u26A0 \u672A\u914D\u7F6E GitHub Token\uFF0C\u8DF3\u8FC7\u4ED3\u5E93\u521B\u5EFA");
380
+ logger.dim(` \u8FD0\u884C spec-go config --setup-github \u914D\u7F6E Token`);
381
+ logger.dim(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${getConfigPath()}`);
497
382
  return null;
498
383
  }
499
384
  const token = config.github.token;
500
- const defaultOrg = config.github.defaultOrg;
385
+ const defaultOrg = organization || config.github.defaultOrg;
501
386
  const validateResult = await validateToken(token);
502
387
  if (!validateResult.success) {
503
- console.log(pc2.yellow(`\u26A0 GitHub Token \u65E0\u6548: ${validateResult.error}`));
388
+ logger.warn(`\u26A0 GitHub Token \u65E0\u6548: ${validateResult.error}`);
504
389
  if (validateResult.rateLimitReset) {
505
- console.log(pc2.dim(` Rate limit \u5C06\u5728 ${validateResult.rateLimitReset.toLocaleString()} \u91CD\u7F6E`));
390
+ logger.dim(` Rate limit \u5C06\u5728 ${validateResult.rateLimitReset.toLocaleString()} \u91CD\u7F6E`);
506
391
  }
507
- console.log(pc2.dim(` \u8FD0\u884C ${pc2.cyan("spec-go config --setup-github")} \u91CD\u65B0\u914D\u7F6E`));
392
+ logger.dim(` \u8FD0\u884C spec-go config --setup-github \u91CD\u65B0\u914D\u7F6E`);
508
393
  return null;
509
394
  }
510
- const username = validateResult.data.login;
511
395
  const createResult = await createRepository(token, {
512
396
  name: repoName,
513
397
  isPrivate: !isPublic,
@@ -515,12 +399,12 @@ async function createGithubRepo(repoName, targetDir, isPublic) {
515
399
  });
516
400
  if (!createResult.success) {
517
401
  if (createResult.statusCode === 422) {
518
- console.log(pc2.yellow(`\u26A0 \u4ED3\u5E93 "${repoName}" \u5DF2\u5B58\u5728\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6\u540D\u79F0`));
402
+ logger.warn(`\u26A0 \u4ED3\u5E93 "${repoName}" \u5DF2\u5B58\u5728\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6\u540D\u79F0`);
519
403
  } else if (createResult.rateLimitReset) {
520
- console.log(pc2.yellow(`\u26A0 API \u8BF7\u6C42\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650`));
521
- console.log(pc2.dim(` \u5C06\u5728 ${createResult.rateLimitReset.toLocaleString()} \u91CD\u7F6E`));
404
+ logger.warn(`\u26A0 API \u8BF7\u6C42\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650`);
405
+ logger.dim(` \u5C06\u5728 ${createResult.rateLimitReset.toLocaleString()} \u91CD\u7F6E`);
522
406
  } else {
523
- console.log(pc2.yellow(`\u26A0 \u521B\u5EFA\u4ED3\u5E93\u5931\u8D25: ${createResult.error}`));
407
+ logger.warn(`\u26A0 \u521B\u5EFA\u4ED3\u5E93\u5931\u8D25: ${createResult.error}`);
524
408
  }
525
409
  return null;
526
410
  }
@@ -549,165 +433,178 @@ async function createGithubRepo(repoName, targetDir, isPublic) {
549
433
  { cwd: targetDir }
550
434
  );
551
435
  if (pushMaster.code !== 0) {
552
- console.log(pc2.yellow(`\u26A0 \u63A8\u9001\u5931\u8D25: ${pushResult.stderr || pushMaster.stderr}`));
553
- console.log(pc2.dim(` \u4ED3\u5E93\u5DF2\u521B\u5EFA: ${repo.html_url}`));
554
- console.log(pc2.dim(" \u8BF7\u624B\u52A8\u63A8\u9001\u4EE3\u7801"));
436
+ logger.warn(`\u26A0 \u63A8\u9001\u5931\u8D25: ${pushResult.stderr || pushMaster.stderr}`);
437
+ logger.dim(` \u4ED3\u5E93\u5DF2\u521B\u5EFA: ${repo.html_url}`);
438
+ logger.dim(" \u8BF7\u624B\u52A8\u63A8\u9001\u4EE3\u7801");
555
439
  return repo.html_url;
556
440
  }
557
441
  }
558
442
  return repo.html_url;
559
443
  }
560
444
 
561
- // src/post-init.ts
562
- import path5 from "path";
563
- import pc3 from "picocolors";
564
- async function runPostInit(targetDir, commands) {
445
+ // src/core/post-init.ts
446
+ import path4 from "path";
447
+ async function runPostInit(targetDir, commands, options = {}) {
448
+ const { logger = silentLogger } = options;
565
449
  for (const cmd of commands) {
566
- console.log(pc3.dim(` ${cmd.description}...`));
450
+ logger.dim(` ${cmd.description}...`);
567
451
  const [command, ...args] = cmd.command.split(" ");
568
452
  const result = await execAsync(command, args, {
569
453
  cwd: targetDir,
570
454
  stdio: "pipe"
571
455
  });
572
456
  if (result.code !== 0) {
573
- console.log(pc3.yellow(`\u26A0 ${cmd.description} \u5931\u8D25`));
457
+ logger.warn(`\u26A0 ${cmd.description} \u5931\u8D25`);
574
458
  if (result.stderr) {
575
- console.log(pc3.dim(result.stderr.slice(0, 200)));
459
+ logger.dim(result.stderr.slice(0, 200));
576
460
  }
577
461
  }
578
462
  }
579
463
  }
580
- async function runWorkspacePostInit(targetDir, config) {
464
+ async function runWorkspacePostInit(targetDir, config, options = {}) {
465
+ const { logger = silentLogger } = options;
581
466
  if (config.postInit && config.postInit.length > 0) {
582
- await runPostInit(targetDir, config.postInit);
467
+ await runPostInit(targetDir, config.postInit, options);
583
468
  }
584
469
  if (config.workspaces) {
585
470
  for (const ws of config.workspaces) {
586
471
  if (ws.postInit && ws.postInit.length > 0) {
587
- const wsDir = path5.join(targetDir, ws.name);
588
- console.log(pc3.dim(` [${ws.name}]`));
589
- await runPostInit(wsDir, ws.postInit);
472
+ const wsDir = path4.join(targetDir, ws.name);
473
+ logger.dim(` [${ws.name}]`);
474
+ await runPostInit(wsDir, ws.postInit, options);
590
475
  }
591
476
  }
592
477
  }
593
478
  }
594
479
 
595
- // src/update-check.ts
596
- import fs4 from "fs";
597
- import path6 from "path";
598
- import os2 from "os";
599
- import { execSync } from "child_process";
600
- import pc4 from "picocolors";
601
- var CACHE_PATH = path6.join(os2.homedir(), ".spec-go-update-check");
602
- var CACHE_TTL = 24 * 60 * 60 * 1e3;
603
- var PACKAGE_NAME = "@lambertkeith/spec-go";
604
- function readCache() {
605
- try {
606
- if (fs4.existsSync(CACHE_PATH)) {
607
- const content = fs4.readFileSync(CACHE_PATH, "utf-8");
608
- return JSON.parse(content);
480
+ // src/cli/prompts.ts
481
+ var DEFAULT_TEMPLATE = "node-ts";
482
+ async function runPrompts(argProjectName, options, userConfig = {}, interactive = true) {
483
+ const defaults = userConfig.defaults ?? {};
484
+ const templatesDir = getTemplatesDir();
485
+ const registryPath = path5.join(templatesDir, "template.config.json");
486
+ const registry = JSON.parse(
487
+ fs3.readFileSync(registryPath, "utf-8")
488
+ );
489
+ debug("prompts", `\u4EA4\u4E92\u6A21\u5F0F: ${interactive}`);
490
+ debug("prompts", `CLI \u53C2\u6570`, { argProjectName, options });
491
+ let projectName = argProjectName;
492
+ if (!projectName) {
493
+ if (!interactive) {
494
+ console.log(pc.red("\u9519\u8BEF: \u975E\u4EA4\u4E92\u6A21\u5F0F\u4E0B\u5FC5\u987B\u63D0\u4F9B\u9879\u76EE\u540D\u79F0"));
495
+ throw new CliError("\u975E\u4EA4\u4E92\u6A21\u5F0F\u4E0B\u5FC5\u987B\u63D0\u4F9B\u9879\u76EE\u540D\u79F0", ExitCodes.USER_ERROR);
609
496
  }
610
- } catch {
611
- }
612
- return null;
613
- }
614
- function writeCache(cache) {
615
- try {
616
- fs4.writeFileSync(CACHE_PATH, JSON.stringify(cache), "utf-8");
617
- } catch {
497
+ projectName = await input({
498
+ message: "\u9879\u76EE\u540D\u79F0:",
499
+ default: "my-project",
500
+ validate: (value) => {
501
+ if (!value.trim()) {
502
+ return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
503
+ }
504
+ if (!isValidPackageName(toValidPackageName(value))) {
505
+ return "\u65E0\u6548\u7684\u9879\u76EE\u540D\u79F0";
506
+ }
507
+ return true;
508
+ }
509
+ });
618
510
  }
619
- }
620
- async function fetchLatestVersion() {
621
- try {
622
- const response = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`);
623
- if (!response.ok) {
624
- return null;
511
+ const validName = toValidPackageName(projectName);
512
+ const targetDir = path5.resolve(process.cwd(), validName);
513
+ if (fs3.existsSync(targetDir) && !isEmpty(targetDir)) {
514
+ if (!interactive) {
515
+ console.log(pc.yellow(`\u8B66\u544A: \u76EE\u6807\u76EE\u5F55 "${validName}" \u975E\u7A7A\uFF0C\u5C06\u8986\u76D6\u5DF2\u6709\u6587\u4EF6`));
516
+ } else {
517
+ const overwrite = await confirm({
518
+ message: `\u76EE\u6807\u76EE\u5F55 "${validName}" \u975E\u7A7A\uFF0C\u662F\u5426\u7EE7\u7EED? (\u5C06\u8986\u76D6\u5DF2\u6709\u6587\u4EF6)`,
519
+ default: false
520
+ });
521
+ if (!overwrite) {
522
+ const error = new Error("PROMPT_CANCELLED");
523
+ throw error;
524
+ }
625
525
  }
626
- const data = await response.json();
627
- return data.version;
628
- } catch {
629
- return null;
630
526
  }
631
- }
632
- function compareVersions(current, latest) {
633
- const currentParts = current.split(".").map(Number);
634
- const latestParts = latest.split(".").map(Number);
635
- for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
636
- const c = currentParts[i] || 0;
637
- const l = latestParts[i] || 0;
638
- if (c < l) return -1;
639
- if (c > l) return 1;
640
- }
641
- return 0;
642
- }
643
- async function checkForUpdates(currentVersion) {
644
- const cache = readCache();
645
- const now = Date.now();
646
- let latestVersion = null;
647
- if (cache && now - cache.lastCheck < CACHE_TTL) {
648
- latestVersion = cache.latestVersion;
649
- } else {
650
- latestVersion = await fetchLatestVersion();
651
- if (latestVersion) {
652
- writeCache({ lastCheck: now, latestVersion });
527
+ let template = options.template;
528
+ if (!template) {
529
+ if (!interactive) {
530
+ template = defaults.template || DEFAULT_TEMPLATE;
531
+ console.log(pc.dim(`\u4F7F\u7528\u9ED8\u8BA4\u6A21\u677F: ${template}`));
532
+ } else {
533
+ const defaultTemplate = defaults.template;
534
+ const singleTemplates = registry.templates.filter((t) => t.category !== "fullstack");
535
+ const fullstackTemplates = registry.templates.filter((t) => t.category === "fullstack");
536
+ const templateChoices = [];
537
+ templateChoices.push(new Separator("\u2500\u2500 \u5355\u4F53\u9879\u76EE \u2500\u2500"));
538
+ for (const t of singleTemplates) {
539
+ templateChoices.push({
540
+ name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,
541
+ value: t.name
542
+ });
543
+ }
544
+ if (fullstackTemplates.length > 0) {
545
+ templateChoices.push(new Separator("\u2500\u2500 \u524D\u540E\u7AEF\u5206\u79BB \u2500\u2500"));
546
+ for (const t of fullstackTemplates) {
547
+ templateChoices.push({
548
+ name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,
549
+ value: t.name
550
+ });
551
+ }
552
+ }
553
+ template = await select({
554
+ message: "\u9009\u62E9\u6A21\u677F:",
555
+ choices: templateChoices,
556
+ default: defaultTemplate && registry.templates.some((t) => t.name === defaultTemplate) ? defaultTemplate : void 0
557
+ });
653
558
  }
654
559
  }
655
- if (latestVersion && compareVersions(currentVersion, latestVersion) < 0) {
656
- console.log();
657
- console.log(
658
- pc4.yellow(` \u26A0 \u53D1\u73B0\u65B0\u7248\u672C ${pc4.bold(latestVersion)}\uFF0C\u5F53\u524D ${currentVersion}`)
659
- );
660
- console.log(pc4.cyan(` \u8FD0\u884C ${pc4.bold(`npm update -g ${PACKAGE_NAME}`)} \u66F4\u65B0`));
661
- console.log();
662
- }
663
- }
664
- function detectPackageManager() {
665
- const execPath = process.argv[1] || "";
666
- if (execPath.includes("pnpm")) return "pnpm";
667
- if (execPath.includes("yarn")) return "yarn";
668
- return "npm";
669
- }
670
- function getUpdateCommand(pm) {
671
- switch (pm) {
672
- case "pnpm":
673
- return `pnpm update -g ${PACKAGE_NAME}`;
674
- case "yarn":
675
- return `yarn global upgrade ${PACKAGE_NAME}`;
676
- default:
677
- return `npm update -g ${PACKAGE_NAME}`;
678
- }
679
- }
680
- async function runUpdate(currentVersion, checkOnly) {
681
- const latestVersion = await fetchLatestVersion();
682
- if (!latestVersion) {
683
- console.log(pc4.red("\u2717 \u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
684
- process.exit(ExitCodes.EXTERNAL_ERROR);
560
+ const found = registry.templates.find((t) => t.name === template);
561
+ if (!found) {
562
+ console.log(pc.red(`\u9519\u8BEF: \u672A\u627E\u5230\u6A21\u677F "${template}"`));
563
+ console.log(pc.dim(`\u53EF\u7528\u6A21\u677F: ${registry.templates.map((t) => t.name).join(", ")}`));
564
+ throw new CliError(`\u672A\u627E\u5230\u6A21\u677F "${template}"`, ExitCodes.USER_ERROR);
685
565
  }
686
- const comparison = compareVersions(currentVersion, latestVersion);
687
- if (comparison >= 0) {
688
- console.log(pc4.green(`\u2714 \u5DF2\u662F\u6700\u65B0\u7248\u672C (${currentVersion})`));
689
- return;
566
+ let initGit2 = options.git !== false;
567
+ if (options.git === void 0 && interactive) {
568
+ initGit2 = await confirm({
569
+ message: "\u521D\u59CB\u5316 Git \u4ED3\u5E93?",
570
+ default: true
571
+ });
690
572
  }
691
- console.log(pc4.cyan(`\u53D1\u73B0\u65B0\u7248\u672C: ${currentVersion} \u2192 ${latestVersion}`));
692
- if (checkOnly) {
693
- console.log(pc4.dim(`\u8FD0\u884C spec-go update \u66F4\u65B0`));
694
- return;
573
+ let createGithub = options.github ?? false;
574
+ if (initGit2 && options.github === void 0 && interactive) {
575
+ createGithub = await confirm({
576
+ message: "\u5728 GitHub \u521B\u5EFA\u8FDC\u7A0B\u4ED3\u5E93?",
577
+ default: defaults.github ?? false
578
+ });
695
579
  }
696
- const pm = detectPackageManager();
697
- const updateCmd = getUpdateCommand(pm);
698
- console.log(pc4.dim(`\u6B63\u5728\u6267\u884C: ${updateCmd}`));
699
- try {
700
- execSync(updateCmd, { stdio: "inherit" });
701
- console.log(pc4.green(`\u2714 \u66F4\u65B0\u5B8C\u6210`));
702
- } catch {
703
- console.log(pc4.red("\u2717 \u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C\u66F4\u65B0\u547D\u4EE4"));
704
- process.exit(ExitCodes.EXTERNAL_ERROR);
580
+ let isPublic = options.public ?? false;
581
+ if (createGithub && options.public === void 0 && interactive) {
582
+ const publicDefault = defaults.public ?? false;
583
+ isPublic = await select({
584
+ message: "\u4ED3\u5E93\u53EF\u89C1\u6027:",
585
+ choices: [
586
+ { name: "private (\u79C1\u6709)", value: false },
587
+ { name: "public (\u516C\u5F00)", value: true }
588
+ ],
589
+ default: publicDefault
590
+ });
705
591
  }
592
+ const result = {
593
+ projectName: validName,
594
+ template,
595
+ targetDir,
596
+ initGit: initGit2,
597
+ createGithub,
598
+ isPublic,
599
+ noInstall: options.install === false
600
+ };
601
+ debug("prompts", "\u6700\u7EC8\u9879\u76EE\u9009\u9879", result);
602
+ return result;
706
603
  }
707
604
 
708
- // src/github-setup.ts
605
+ // src/cli/github-setup.ts
709
606
  import { input as input2, confirm as confirm2 } from "@inquirer/prompts";
710
- import pc5 from "picocolors";
607
+ import pc2 from "picocolors";
711
608
  var TOKEN_HELP_URL = "https://github.com/settings/tokens/new?scopes=repo&description=spec-go";
712
609
  function isUserCancelled(err) {
713
610
  const error = err;
@@ -715,17 +612,17 @@ function isUserCancelled(err) {
715
612
  }
716
613
  async function runGitHubSetup() {
717
614
  console.log();
718
- console.log(pc5.cyan("\u914D\u7F6E GitHub Token"));
615
+ console.log(pc2.cyan("\u914D\u7F6E GitHub Token"));
719
616
  console.log();
720
617
  console.log("\u9700\u8981\u4E00\u4E2A\u5177\u6709 repo \u6743\u9650\u7684 Personal Access Token (Classic) \u6765\u521B\u5EFA\u4ED3\u5E93\u3002");
721
618
  console.log();
722
- console.log(pc5.dim("\u83B7\u53D6\u6B65\u9AA4:"));
723
- console.log(pc5.dim("1. \u8BBF\u95EE GitHub Settings > Developer settings > Personal access tokens"));
724
- console.log(pc5.dim('2. \u70B9\u51FB "Generate new token (classic)"'));
725
- console.log(pc5.dim('3. \u52FE\u9009 "repo" \u6743\u9650'));
726
- console.log(pc5.dim("4. \u751F\u6210\u5E76\u590D\u5236 Token"));
619
+ console.log(pc2.dim("\u83B7\u53D6\u6B65\u9AA4:"));
620
+ console.log(pc2.dim("1. \u8BBF\u95EE GitHub Settings > Developer settings > Personal access tokens"));
621
+ console.log(pc2.dim('2. \u70B9\u51FB "Generate new token (classic)"'));
622
+ console.log(pc2.dim('3. \u52FE\u9009 "repo" \u6743\u9650'));
623
+ console.log(pc2.dim("4. \u751F\u6210\u5E76\u590D\u5236 Token"));
727
624
  console.log();
728
- console.log(pc5.dim(`\u5FEB\u6377\u94FE\u63A5: ${TOKEN_HELP_URL}`));
625
+ console.log(pc2.dim(`\u5FEB\u6377\u94FE\u63A5: ${TOKEN_HELP_URL}`));
729
626
  console.log();
730
627
  try {
731
628
  const token = await input2({
@@ -741,17 +638,17 @@ async function runGitHubSetup() {
741
638
  }
742
639
  });
743
640
  console.log();
744
- console.log(pc5.dim("\u6B63\u5728\u9A8C\u8BC1 Token..."));
641
+ console.log(pc2.dim("\u6B63\u5728\u9A8C\u8BC1 Token..."));
745
642
  const result = await validateToken(token.trim());
746
643
  if (!result.success) {
747
- console.log(pc5.red(`\u2717 Token \u9A8C\u8BC1\u5931\u8D25: ${result.error}`));
644
+ console.log(pc2.red(`\u2717 Token \u9A8C\u8BC1\u5931\u8D25: ${result.error}`));
748
645
  if (result.rateLimitReset) {
749
- console.log(pc5.dim(` Rate limit \u5C06\u5728 ${result.rateLimitReset.toLocaleString()} \u91CD\u7F6E`));
646
+ console.log(pc2.dim(` Rate limit \u5C06\u5728 ${result.rateLimitReset.toLocaleString()} \u91CD\u7F6E`));
750
647
  }
751
648
  return false;
752
649
  }
753
650
  const user = result.data;
754
- console.log(pc5.green(`\u2714 Token \u6709\u6548\uFF0C\u5DF2\u767B\u5F55\u4E3A: ${user.login}${user.name ? ` (${user.name})` : ""}`));
651
+ console.log(pc2.green(`\u2714 Token \u6709\u6548\uFF0C\u5DF2\u767B\u5F55\u4E3A: ${user.login}${user.name ? ` (${user.name})` : ""}`));
755
652
  console.log();
756
653
  const setOrg = await confirm2({
757
654
  message: "\u662F\u5426\u8BBE\u7F6E\u9ED8\u8BA4\u7EC4\u7EC7? (\u5426\u5219\u4ED3\u5E93\u5C06\u521B\u5EFA\u5728\u4E2A\u4EBA\u8D26\u6237\u4E0B)",
@@ -777,12 +674,12 @@ async function runGitHubSetup() {
777
674
  };
778
675
  saveConfig(config);
779
676
  console.log();
780
- console.log(pc5.green("\u2714 GitHub \u914D\u7F6E\u5DF2\u4FDD\u5B58"));
781
- console.log(pc5.dim(" \u914D\u7F6E\u6587\u4EF6\u5DF2\u8BBE\u7F6E\u4E3A\u4EC5\u5F53\u524D\u7528\u6237\u53EF\u8BFB"));
677
+ console.log(pc2.green("\u2714 GitHub \u914D\u7F6E\u5DF2\u4FDD\u5B58"));
678
+ console.log(pc2.dim(" \u914D\u7F6E\u6587\u4EF6\u5DF2\u8BBE\u7F6E\u4E3A\u4EC5\u5F53\u524D\u7528\u6237\u53EF\u8BFB"));
782
679
  return true;
783
680
  } catch (err) {
784
681
  if (isUserCancelled(err)) {
785
- console.log(pc5.yellow("\n\u64CD\u4F5C\u5DF2\u53D6\u6D88"));
682
+ console.log(pc2.yellow("\n\u64CD\u4F5C\u5DF2\u53D6\u6D88"));
786
683
  return false;
787
684
  }
788
685
  throw err;
@@ -791,10 +688,10 @@ async function runGitHubSetup() {
791
688
  function showConfig() {
792
689
  const config = loadConfig();
793
690
  console.log();
794
- console.log(pc5.cyan("\u5F53\u524D\u914D\u7F6E:"));
691
+ console.log(pc2.cyan("\u5F53\u524D\u914D\u7F6E:"));
795
692
  console.log();
796
693
  if (config.defaults) {
797
- console.log(pc5.dim("defaults:"));
694
+ console.log(pc2.dim("defaults:"));
798
695
  if (config.defaults.github !== void 0) {
799
696
  console.log(` github: ${config.defaults.github}`);
800
697
  }
@@ -806,7 +703,7 @@ function showConfig() {
806
703
  }
807
704
  }
808
705
  if (config.github) {
809
- console.log(pc5.dim("github:"));
706
+ console.log(pc2.dim("github:"));
810
707
  if (config.github.token) {
811
708
  const masked = config.github.token.slice(0, 8) + "..." + config.github.token.slice(-4);
812
709
  console.log(` token: ${masked}`);
@@ -816,12 +713,145 @@ function showConfig() {
816
713
  }
817
714
  }
818
715
  if (!config.defaults && !config.github) {
819
- console.log(pc5.dim("(\u65E0\u914D\u7F6E)"));
716
+ console.log(pc2.dim("(\u65E0\u914D\u7F6E)"));
820
717
  }
821
718
  console.log();
822
719
  }
823
720
 
824
- // src/cli.ts
721
+ // src/cli/update-check.ts
722
+ import fs4 from "fs";
723
+ import path6 from "path";
724
+ import os2 from "os";
725
+ import { execSync } from "child_process";
726
+ import pc3 from "picocolors";
727
+ var CACHE_PATH = path6.join(os2.homedir(), ".spec-go-update-check");
728
+ var CACHE_TTL = 24 * 60 * 60 * 1e3;
729
+ var PACKAGE_NAME = "@lambertkeith/spec-go";
730
+ function readCache() {
731
+ try {
732
+ if (fs4.existsSync(CACHE_PATH)) {
733
+ const content = fs4.readFileSync(CACHE_PATH, "utf-8");
734
+ return JSON.parse(content);
735
+ }
736
+ } catch {
737
+ }
738
+ return null;
739
+ }
740
+ function writeCache(cache) {
741
+ try {
742
+ fs4.writeFileSync(CACHE_PATH, JSON.stringify(cache), "utf-8");
743
+ } catch {
744
+ }
745
+ }
746
+ async function fetchLatestVersion() {
747
+ try {
748
+ const response = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`);
749
+ if (!response.ok) {
750
+ return null;
751
+ }
752
+ const data = await response.json();
753
+ return data.version;
754
+ } catch {
755
+ return null;
756
+ }
757
+ }
758
+ function compareVersions(current, latest) {
759
+ const currentParts = current.split(".").map(Number);
760
+ const latestParts = latest.split(".").map(Number);
761
+ for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
762
+ const c = currentParts[i] || 0;
763
+ const l = latestParts[i] || 0;
764
+ if (c < l) return -1;
765
+ if (c > l) return 1;
766
+ }
767
+ return 0;
768
+ }
769
+ async function checkForUpdates(currentVersion) {
770
+ const cache = readCache();
771
+ const now = Date.now();
772
+ let latestVersion = null;
773
+ if (cache && now - cache.lastCheck < CACHE_TTL) {
774
+ latestVersion = cache.latestVersion;
775
+ } else {
776
+ latestVersion = await fetchLatestVersion();
777
+ if (latestVersion) {
778
+ writeCache({ lastCheck: now, latestVersion });
779
+ }
780
+ }
781
+ if (latestVersion && compareVersions(currentVersion, latestVersion) < 0) {
782
+ console.log();
783
+ console.log(
784
+ pc3.yellow(` \u26A0 \u53D1\u73B0\u65B0\u7248\u672C ${pc3.bold(latestVersion)}\uFF0C\u5F53\u524D ${currentVersion}`)
785
+ );
786
+ console.log(pc3.cyan(` \u8FD0\u884C ${pc3.bold(`npm update -g ${PACKAGE_NAME}`)} \u66F4\u65B0`));
787
+ console.log();
788
+ }
789
+ }
790
+ function detectPackageManager() {
791
+ const execPath = process.argv[1] || "";
792
+ if (execPath.includes("pnpm")) return "pnpm";
793
+ if (execPath.includes("yarn")) return "yarn";
794
+ return "npm";
795
+ }
796
+ function getUpdateCommand(pm) {
797
+ switch (pm) {
798
+ case "pnpm":
799
+ return `pnpm update -g ${PACKAGE_NAME}`;
800
+ case "yarn":
801
+ return `yarn global upgrade ${PACKAGE_NAME}`;
802
+ default:
803
+ return `npm update -g ${PACKAGE_NAME}`;
804
+ }
805
+ }
806
+ async function runUpdate(currentVersion, checkOnly) {
807
+ const latestVersion = await fetchLatestVersion();
808
+ if (!latestVersion) {
809
+ console.log(pc3.red("\u2717 \u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
810
+ process.exit(ExitCodes.EXTERNAL_ERROR);
811
+ }
812
+ const comparison = compareVersions(currentVersion, latestVersion);
813
+ if (comparison >= 0) {
814
+ console.log(pc3.green(`\u2714 \u5DF2\u662F\u6700\u65B0\u7248\u672C (${currentVersion})`));
815
+ return;
816
+ }
817
+ console.log(pc3.cyan(`\u53D1\u73B0\u65B0\u7248\u672C: ${currentVersion} \u2192 ${latestVersion}`));
818
+ if (checkOnly) {
819
+ console.log(pc3.dim(`\u8FD0\u884C spec-go update \u66F4\u65B0`));
820
+ return;
821
+ }
822
+ const pm = detectPackageManager();
823
+ const updateCmd = getUpdateCommand(pm);
824
+ console.log(pc3.dim(`\u6B63\u5728\u6267\u884C: ${updateCmd}`));
825
+ try {
826
+ execSync(updateCmd, { stdio: "inherit" });
827
+ console.log(pc3.green(`\u2714 \u66F4\u65B0\u5B8C\u6210`));
828
+ } catch {
829
+ console.log(pc3.red("\u2717 \u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C\u66F4\u65B0\u547D\u4EE4"));
830
+ process.exit(ExitCodes.EXTERNAL_ERROR);
831
+ }
832
+ }
833
+
834
+ // src/cli/console-logger.ts
835
+ import pc4 from "picocolors";
836
+ var consoleLogger = {
837
+ info(message) {
838
+ console.log(message);
839
+ },
840
+ success(message) {
841
+ console.log(pc4.green(message));
842
+ },
843
+ warn(message) {
844
+ console.log(pc4.yellow(message));
845
+ },
846
+ error(message) {
847
+ console.log(pc4.red(message));
848
+ },
849
+ dim(message) {
850
+ console.log(pc4.dim(message));
851
+ }
852
+ };
853
+
854
+ // src/cli/cli.ts
825
855
  function isInteractive(options) {
826
856
  if (options.yes) return false;
827
857
  return process.stdin.isTTY === true;
@@ -833,7 +863,7 @@ async function createCli() {
833
863
  setDebugEnabled(true);
834
864
  }
835
865
  console.log();
836
- console.log(` ${pc6.cyan("spec-go")} ${pc6.dim(`v${version}`)}`);
866
+ console.log(` ${pc5.cyan("spec-go")} ${pc5.dim(`v${version}`)}`);
837
867
  console.log();
838
868
  checkForUpdates(version).catch(() => {
839
869
  });
@@ -845,7 +875,7 @@ async function createCli() {
845
875
  } catch (err) {
846
876
  const error = err;
847
877
  if (error.message === "PROMPT_CANCELLED" || error.name === "ExitPromptError" || error.message.includes("User force closed")) {
848
- console.log(pc6.yellow("\n\u64CD\u4F5C\u5DF2\u53D6\u6D88"));
878
+ console.log(pc5.yellow("\n\u64CD\u4F5C\u5DF2\u53D6\u6D88"));
849
879
  process.exit(ExitCodes.SUCCESS);
850
880
  }
851
881
  throw err;
@@ -872,15 +902,15 @@ async function createCli() {
872
902
  const singleTemplates = registry.templates.filter((t) => t.category !== "fullstack");
873
903
  const fullstackTemplates = registry.templates.filter((t) => t.category === "fullstack");
874
904
  console.log();
875
- console.log(pc6.cyan(" \u5355\u4F53\u9879\u76EE:"));
905
+ console.log(pc5.cyan(" \u5355\u4F53\u9879\u76EE:"));
876
906
  for (const t of singleTemplates) {
877
- console.log(` ${pc6.green(t.name.padEnd(24))} ${pc6.dim(t.displayName)}`);
907
+ console.log(` ${pc5.green(t.name.padEnd(24))} ${pc5.dim(t.displayName)}`);
878
908
  }
879
909
  if (fullstackTemplates.length > 0) {
880
910
  console.log();
881
- console.log(pc6.cyan(" \u524D\u540E\u7AEF\u5206\u79BB:"));
911
+ console.log(pc5.cyan(" \u524D\u540E\u7AEF\u5206\u79BB:"));
882
912
  for (const t of fullstackTemplates) {
883
- console.log(` ${pc6.green(t.name.padEnd(24))} ${pc6.dim(t.displayName)}`);
913
+ console.log(` ${pc5.green(t.name.padEnd(24))} ${pc5.dim(t.displayName)}`);
884
914
  }
885
915
  }
886
916
  console.log();
@@ -895,11 +925,11 @@ async function createCli() {
895
925
  console.log(getConfigPath());
896
926
  } else {
897
927
  console.log();
898
- console.log(pc6.cyan("\u914D\u7F6E\u7BA1\u7406\u547D\u4EE4:"));
928
+ console.log(pc5.cyan("\u914D\u7F6E\u7BA1\u7406\u547D\u4EE4:"));
899
929
  console.log();
900
- console.log(` ${pc6.dim("spec-go config --setup-github")} \u914D\u7F6E GitHub Token`);
901
- console.log(` ${pc6.dim("spec-go config --show")} \u663E\u793A\u5F53\u524D\u914D\u7F6E`);
902
- console.log(` ${pc6.dim("spec-go config --path")} \u663E\u793A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84`);
930
+ console.log(` ${pc5.dim("spec-go config --setup-github")} \u914D\u7F6E GitHub Token`);
931
+ console.log(` ${pc5.dim("spec-go config --show")} \u663E\u793A\u5F53\u524D\u914D\u7F6E`);
932
+ console.log(` ${pc5.dim("spec-go config --path")} \u663E\u793A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84`);
903
933
  console.log();
904
934
  }
905
935
  });
@@ -910,28 +940,29 @@ async function createCli() {
910
940
  }
911
941
  async function executeProject(options) {
912
942
  const templateConfig = await scaffoldProject(options);
913
- console.log(pc6.green("\u2714 \u9879\u76EE\u6587\u4EF6\u5DF2\u751F\u6210"));
943
+ console.log(pc5.green("\u2714 \u9879\u76EE\u6587\u4EF6\u5DF2\u751F\u6210"));
914
944
  if (!options.noInstall && templateConfig) {
915
945
  if (templateConfig.type === "workspace") {
916
- await runWorkspacePostInit(options.targetDir, templateConfig);
917
- console.log(pc6.green("\u2714 \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210"));
946
+ await runWorkspacePostInit(options.targetDir, templateConfig, { logger: consoleLogger });
947
+ console.log(pc5.green("\u2714 \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210"));
918
948
  } else if (templateConfig.postInit) {
919
- await runPostInit(options.targetDir, templateConfig.postInit);
920
- console.log(pc6.green("\u2714 \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210"));
949
+ await runPostInit(options.targetDir, templateConfig.postInit, { logger: consoleLogger });
950
+ console.log(pc5.green("\u2714 \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210"));
921
951
  }
922
952
  }
923
953
  if (options.initGit) {
924
954
  await initGit(options.targetDir);
925
- console.log(pc6.green("\u2714 Git \u4ED3\u5E93\u5DF2\u521D\u59CB\u5316"));
955
+ console.log(pc5.green("\u2714 Git \u4ED3\u5E93\u5DF2\u521D\u59CB\u5316"));
926
956
  }
927
957
  if (options.createGithub) {
928
- const repoUrl = await createGithubRepo(
929
- options.projectName,
930
- options.targetDir,
931
- options.isPublic
932
- );
958
+ const repoUrl = await createGithubRepo({
959
+ repoName: options.projectName,
960
+ targetDir: options.targetDir,
961
+ isPublic: options.isPublic,
962
+ logger: consoleLogger
963
+ });
933
964
  if (repoUrl) {
934
- console.log(pc6.green(`\u2714 GitHub \u4ED3\u5E93\u5DF2\u521B\u5EFA: ${pc6.cyan(repoUrl)}`));
965
+ console.log(pc5.green(`\u2714 GitHub \u4ED3\u5E93\u5DF2\u521B\u5EFA: ${pc5.cyan(repoUrl)}`));
935
966
  }
936
967
  }
937
968
  console.log();
@@ -939,21 +970,21 @@ async function executeProject(options) {
939
970
  const cdCmd = options.targetDir !== process.cwd() ? `cd ${options.projectName} && ` : "";
940
971
  if (templateConfig?.type === "workspace") {
941
972
  if (pm === "pnpm") {
942
- console.log(pc6.dim(` ${cdCmd}pnpm dev`));
973
+ console.log(pc5.dim(` ${cdCmd}pnpm dev`));
943
974
  } else {
944
- console.log(pc6.dim(` ${cdCmd}make dev`));
975
+ console.log(pc5.dim(` ${cdCmd}make dev`));
945
976
  }
946
977
  } else if (pm === "maven") {
947
- console.log(pc6.dim(` ${cdCmd}./mvnw spring-boot:run`));
978
+ console.log(pc5.dim(` ${cdCmd}./mvnw spring-boot:run`));
948
979
  } else if (pm === "gradle") {
949
- console.log(pc6.dim(` ${cdCmd}./gradlew bootRun`));
980
+ console.log(pc5.dim(` ${cdCmd}./gradlew bootRun`));
950
981
  } else {
951
- console.log(pc6.dim(` ${cdCmd}${pm} dev`));
982
+ console.log(pc5.dim(` ${cdCmd}${pm} dev`));
952
983
  }
953
984
  console.log();
954
985
  }
955
986
 
956
- // src/index.ts
987
+ // src/cli/index.ts
957
988
  async function main() {
958
989
  ensureConfigExists();
959
990
  const program = await createCli();