@lambertkeith/spec-go 0.2.4 → 0.2.5

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/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import { Command } from "commander";
13
13
  import pc6 from "picocolors";
14
14
 
15
15
  // package.json
16
- var version = "0.2.4";
16
+ var version = "0.2.5";
17
17
 
18
18
  // src/prompts.ts
19
19
  import path2 from "path";
@@ -25,6 +25,39 @@ import pc from "picocolors";
25
25
  import path from "path";
26
26
  import { fileURLToPath } from "url";
27
27
  import { spawn } from "child_process";
28
+
29
+ // src/debug.ts
30
+ var debugEnabled = false;
31
+ function setDebugEnabled(enabled) {
32
+ debugEnabled = enabled;
33
+ }
34
+ function isDebugEnabled() {
35
+ return debugEnabled;
36
+ }
37
+ function debug(category, message, data) {
38
+ if (!debugEnabled) return;
39
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
40
+ const prefix = `[DEBUG ${timestamp}] [${category}]`;
41
+ if (data !== void 0) {
42
+ const dataStr = formatData(data);
43
+ console.error(`${prefix} ${message}`, dataStr);
44
+ } else {
45
+ console.error(`${prefix} ${message}`);
46
+ }
47
+ }
48
+ function formatData(data) {
49
+ try {
50
+ const str = JSON.stringify(data, null, 2);
51
+ if (str.length > 500) {
52
+ return str.slice(0, 500) + "...(truncated)";
53
+ }
54
+ return str;
55
+ } catch {
56
+ return String(data);
57
+ }
58
+ }
59
+
60
+ // src/utils.ts
28
61
  var __filename = fileURLToPath(import.meta.url);
29
62
  var __dirname = path.dirname(__filename);
30
63
  function getTemplatesDir() {
@@ -45,6 +78,7 @@ function isEmpty(dirPath) {
45
78
  return files.length === 0 || files.length === 1 && files[0] === ".git";
46
79
  }
47
80
  function execAsync(command, args, options = {}) {
81
+ debug("exec", `\u6267\u884C\u547D\u4EE4: ${command} ${args.join(" ")}`, { cwd: options.cwd });
48
82
  return new Promise((resolve) => {
49
83
  const proc = spawn(command, args, {
50
84
  cwd: options.cwd,
@@ -64,24 +98,58 @@ function execAsync(command, args, options = {}) {
64
98
  });
65
99
  }
66
100
  proc.on("close", (code) => {
101
+ debug("exec", `\u547D\u4EE4\u5B8C\u6210\uFF0C\u9000\u51FA\u7801: ${code ?? 1}`);
67
102
  resolve({ code: code ?? 1, stdout, stderr });
68
103
  });
69
- proc.on("error", () => {
104
+ proc.on("error", (err) => {
105
+ debug("exec", `\u547D\u4EE4\u9519\u8BEF: ${err.message}`);
70
106
  resolve({ code: 1, stdout, stderr });
71
107
  });
72
108
  });
73
109
  }
74
110
 
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
+
75
136
  // src/prompts.ts
76
- async function runPrompts(argProjectName, options, userConfig = {}) {
137
+ var DEFAULT_TEMPLATE = "node-ts";
138
+ async function runPrompts(argProjectName, options, userConfig = {}, interactive = true) {
77
139
  const defaults = userConfig.defaults ?? {};
78
140
  const templatesDir = getTemplatesDir();
79
141
  const registryPath = path2.join(templatesDir, "template.config.json");
80
142
  const registry = JSON.parse(
81
143
  fs.readFileSync(registryPath, "utf-8")
82
144
  );
145
+ debug("prompts", `\u4EA4\u4E92\u6A21\u5F0F: ${interactive}`);
146
+ debug("prompts", `CLI \u53C2\u6570`, { argProjectName, options });
83
147
  let projectName = argProjectName;
84
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
+ }
85
153
  projectName = await input({
86
154
  message: "\u9879\u76EE\u540D\u79F0:",
87
155
  default: "my-project",
@@ -99,66 +167,74 @@ async function runPrompts(argProjectName, options, userConfig = {}) {
99
167
  const validName = toValidPackageName(projectName);
100
168
  const targetDir = path2.resolve(process.cwd(), validName);
101
169
  if (fs.existsSync(targetDir) && !isEmpty(targetDir)) {
102
- const overwrite = await confirm({
103
- message: `\u76EE\u6807\u76EE\u5F55 "${validName}" \u975E\u7A7A\uFF0C\u662F\u5426\u7EE7\u7EED? (\u5C06\u8986\u76D6\u5DF2\u6709\u6587\u4EF6)`,
104
- default: false
105
- });
106
- if (!overwrite) {
107
- const error = new Error("PROMPT_CANCELLED");
108
- throw error;
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
+ }
109
181
  }
110
182
  }
111
183
  let template = options.template;
112
184
  if (!template) {
113
- const defaultTemplate = defaults.template;
114
- const singleTemplates = registry.templates.filter((t) => t.category !== "fullstack");
115
- const fullstackTemplates = registry.templates.filter((t) => t.category === "fullstack");
116
- const templateChoices = [];
117
- templateChoices.push(new Separator("\u2500\u2500 \u5355\u4F53\u9879\u76EE \u2500\u2500"));
118
- for (const t of singleTemplates) {
119
- templateChoices.push({
120
- name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,
121
- value: t.name
122
- });
123
- }
124
- if (fullstackTemplates.length > 0) {
125
- templateChoices.push(new Separator("\u2500\u2500 \u524D\u540E\u7AEF\u5206\u79BB \u2500\u2500"));
126
- for (const t of fullstackTemplates) {
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) {
127
195
  templateChoices.push({
128
196
  name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,
129
197
  value: t.name
130
198
  });
131
199
  }
132
- }
133
- template = await select({
134
- message: "\u9009\u62E9\u6A21\u677F:",
135
- choices: templateChoices,
136
- default: defaultTemplate && registry.templates.some((t) => t.name === defaultTemplate) ? defaultTemplate : void 0
137
- });
138
- } else {
139
- const found = registry.templates.find((t) => t.name === template);
140
- if (!found) {
141
- console.log(pc.red(`\u9519\u8BEF: \u672A\u627E\u5230\u6A21\u677F "${template}"`));
142
- console.log(pc.dim(`\u53EF\u7528\u6A21\u677F: ${registry.templates.map((t) => t.name).join(", ")}`));
143
- process.exit(1);
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
+ });
144
214
  }
145
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
+ }
146
222
  let initGit2 = options.git !== false;
147
- if (options.git === void 0) {
223
+ if (options.git === void 0 && interactive) {
148
224
  initGit2 = await confirm({
149
225
  message: "\u521D\u59CB\u5316 Git \u4ED3\u5E93?",
150
226
  default: true
151
227
  });
152
228
  }
153
229
  let createGithub = options.github ?? false;
154
- if (initGit2 && options.github === void 0) {
230
+ if (initGit2 && options.github === void 0 && interactive) {
155
231
  createGithub = await confirm({
156
232
  message: "\u5728 GitHub \u521B\u5EFA\u8FDC\u7A0B\u4ED3\u5E93?",
157
233
  default: defaults.github ?? false
158
234
  });
159
235
  }
160
236
  let isPublic = options.public ?? false;
161
- if (createGithub && options.public === void 0) {
237
+ if (createGithub && options.public === void 0 && interactive) {
162
238
  const publicDefault = defaults.public ?? false;
163
239
  isPublic = await select({
164
240
  message: "\u4ED3\u5E93\u53EF\u89C1\u6027:",
@@ -169,7 +245,7 @@ async function runPrompts(argProjectName, options, userConfig = {}) {
169
245
  default: publicDefault
170
246
  });
171
247
  }
172
- return {
248
+ const result = {
173
249
  projectName: validName,
174
250
  template,
175
251
  targetDir,
@@ -178,6 +254,8 @@ async function runPrompts(argProjectName, options, userConfig = {}) {
178
254
  isPublic,
179
255
  noInstall: options.install === false
180
256
  };
257
+ debug("prompts", "\u6700\u7EC8\u9879\u76EE\u9009\u9879", result);
258
+ return result;
181
259
  }
182
260
 
183
261
  // src/scaffold.ts
@@ -187,18 +265,24 @@ async function scaffoldProject(options) {
187
265
  const templatesDir = getTemplatesDir();
188
266
  const registryPath = path3.join(templatesDir, "template.config.json");
189
267
  const registry = await fs2.readJson(registryPath);
268
+ debug("scaffold", `\u5F00\u59CB\u811A\u624B\u67B6\u9879\u76EE: ${options.projectName}`);
269
+ debug("scaffold", `\u6A21\u677F: ${options.template}`);
270
+ debug("scaffold", `\u76EE\u6807\u76EE\u5F55: ${options.targetDir}`);
190
271
  const templateEntry = registry.templates.find((t) => t.name === options.template);
191
272
  if (!templateEntry) {
192
273
  throw new Error(`\u672A\u627E\u5230\u6A21\u677F: ${options.template}`);
193
274
  }
194
275
  const templateDir = path3.join(templatesDir, templateEntry.dir);
195
276
  const templateConfigPath = path3.join(templateDir, "_template.json");
277
+ debug("scaffold", `\u6A21\u677F\u76EE\u5F55: ${templateDir}`);
196
278
  let templateConfig = null;
197
279
  if (await fs2.pathExists(templateConfigPath)) {
198
280
  templateConfig = await fs2.readJson(templateConfigPath);
281
+ debug("scaffold", "\u6A21\u677F\u914D\u7F6E", templateConfig);
199
282
  }
200
283
  await fs2.ensureDir(options.targetDir);
201
284
  const files = await fs2.readdir(templateDir);
285
+ debug("scaffold", `\u6A21\u677F\u6587\u4EF6\u6570\u91CF: ${files.length}`);
202
286
  for (const file of files) {
203
287
  if (file === "_template.json") {
204
288
  continue;
@@ -213,12 +297,14 @@ async function scaffoldProject(options) {
213
297
  }
214
298
  const destPath = path3.join(options.targetDir, destFileName);
215
299
  const stat = await fs2.stat(srcPath);
300
+ debug("scaffold", `\u590D\u5236: ${file} -> ${destFileName}`);
216
301
  if (stat.isDirectory()) {
217
302
  await copyDirectory(srcPath, destPath, options.projectName, templateConfig);
218
303
  } else {
219
304
  await copyFile(srcPath, destPath, options.projectName, templateConfig);
220
305
  }
221
306
  }
307
+ debug("scaffold", "\u811A\u624B\u67B6\u5B8C\u6210");
222
308
  return templateConfig;
223
309
  }
224
310
  async function copyDirectory(srcDir, destDir, projectName, config) {
@@ -321,20 +407,23 @@ function getConfigPath() {
321
407
  var GITHUB_API_BASE = "https://api.github.com";
322
408
  async function githubFetch(endpoint, token, options = {}) {
323
409
  const url = `${GITHUB_API_BASE}${endpoint}`;
410
+ debug("github-api", `\u8BF7\u6C42: ${options.method || "GET"} ${endpoint}`);
324
411
  try {
325
412
  const response = await fetch(url, {
326
413
  ...options,
327
414
  headers: {
328
415
  "Accept": "application/vnd.github+json",
329
- "Authorization": `Bearer ${token}`,
416
+ "Authorization": `Bearer ${token.slice(0, 8)}...`,
330
417
  "X-GitHub-Api-Version": "2022-11-28",
331
418
  "User-Agent": "spec-go",
332
419
  ...options.headers
333
420
  }
334
421
  });
422
+ debug("github-api", `\u54CD\u5E94\u72B6\u6001: ${response.status}`);
335
423
  if (response.status === 403) {
336
424
  const rateLimitRemaining = response.headers.get("x-ratelimit-remaining");
337
425
  const rateLimitReset = response.headers.get("x-ratelimit-reset");
426
+ debug("github-api", `Rate Limit \u4FE1\u606F`, { rateLimitRemaining, rateLimitReset });
338
427
  if (rateLimitRemaining === "0" && rateLimitReset) {
339
428
  const resetDate = new Date(parseInt(rateLimitReset) * 1e3);
340
429
  return {
@@ -346,6 +435,7 @@ async function githubFetch(endpoint, token, options = {}) {
346
435
  }
347
436
  }
348
437
  if (response.status === 401) {
438
+ debug("github-api", "Token \u9A8C\u8BC1\u5931\u8D25");
349
439
  return {
350
440
  success: false,
351
441
  error: "Token \u65E0\u6548\u6216\u5DF2\u8FC7\u671F",
@@ -354,6 +444,7 @@ async function githubFetch(endpoint, token, options = {}) {
354
444
  }
355
445
  if (!response.ok) {
356
446
  const errorData = await response.json();
447
+ debug("github-api", "\u8BF7\u6C42\u5931\u8D25", errorData);
357
448
  return {
358
449
  success: false,
359
450
  error: errorData.message || `\u8BF7\u6C42\u5931\u8D25: ${response.status}`,
@@ -361,8 +452,10 @@ async function githubFetch(endpoint, token, options = {}) {
361
452
  };
362
453
  }
363
454
  const data = await response.json();
455
+ debug("github-api", "\u8BF7\u6C42\u6210\u529F");
364
456
  return { success: true, data };
365
457
  } catch (err) {
458
+ debug("github-api", "\u7F51\u7EDC\u8BF7\u6C42\u5F02\u5E38", { error: err instanceof Error ? err.message : String(err) });
366
459
  return {
367
460
  success: false,
368
461
  error: err instanceof Error ? err.message : "\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25"
@@ -388,11 +481,14 @@ async function createRepository(token, options) {
388
481
 
389
482
  // src/git.ts
390
483
  async function initGit(targetDir) {
484
+ debug("git", `\u521D\u59CB\u5316 Git \u4ED3\u5E93: ${targetDir}`);
391
485
  await execAsync("git", ["init"], { cwd: targetDir });
392
486
  await execAsync("git", ["add", "-A"], { cwd: targetDir });
393
487
  await execAsync("git", ["commit", "-m", "Initial commit"], { cwd: targetDir });
488
+ debug("git", "Git \u521D\u59CB\u5316\u5B8C\u6210");
394
489
  }
395
490
  async function createGithubRepo(repoName, targetDir, isPublic) {
491
+ debug("git", `\u521B\u5EFA GitHub \u4ED3\u5E93: ${repoName}, \u516C\u5F00: ${isPublic}`);
396
492
  const config = loadConfig();
397
493
  if (!config.github?.token) {
398
494
  console.log(pc2.yellow("\u26A0 \u672A\u914D\u7F6E GitHub Token\uFF0C\u8DF3\u8FC7\u4ED3\u5E93\u521B\u5EFA"));
@@ -585,7 +681,7 @@ async function runUpdate(currentVersion, checkOnly) {
585
681
  const latestVersion = await fetchLatestVersion();
586
682
  if (!latestVersion) {
587
683
  console.log(pc4.red("\u2717 \u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u4FE1\u606F"));
588
- process.exit(1);
684
+ process.exit(ExitCodes.EXTERNAL_ERROR);
589
685
  }
590
686
  const comparison = compareVersions(currentVersion, latestVersion);
591
687
  if (comparison >= 0) {
@@ -605,7 +701,7 @@ async function runUpdate(currentVersion, checkOnly) {
605
701
  console.log(pc4.green(`\u2714 \u66F4\u65B0\u5B8C\u6210`));
606
702
  } catch {
607
703
  console.log(pc4.red("\u2717 \u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C\u66F4\u65B0\u547D\u4EE4"));
608
- process.exit(1);
704
+ process.exit(ExitCodes.EXTERNAL_ERROR);
609
705
  }
610
706
  }
611
707
 
@@ -726,33 +822,53 @@ function showConfig() {
726
822
  }
727
823
 
728
824
  // src/cli.ts
825
+ function isInteractive(options) {
826
+ if (options.yes) return false;
827
+ return process.stdin.isTTY === true;
828
+ }
729
829
  async function createCli() {
730
830
  const program = new Command();
731
- program.name("spec-go").description("CLI \u811A\u624B\u67B6\u5DE5\u5177\uFF0C\u5FEB\u901F\u521B\u5EFA\u9879\u76EE\u5E76\u53EF\u9009\u521D\u59CB\u5316 GitHub \u4ED3\u5E93").version(version).argument("[project-name]", "\u9879\u76EE\u540D\u79F0").option("-t, --template <template>", "\u4F7F\u7528\u6307\u5B9A\u6A21\u677F").option("--github", "\u5728 GitHub \u521B\u5EFA\u8FDC\u7A0B\u4ED3\u5E93").option("--public", "\u521B\u5EFA\u516C\u5F00\u4ED3\u5E93 (\u9ED8\u8BA4\u79C1\u6709)").option("--no-git", "\u8DF3\u8FC7 Git \u521D\u59CB\u5316").option("--no-install", "\u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5").action(async (projectName, options) => {
831
+ program.name("spec-go").description("CLI \u811A\u624B\u67B6\u5DE5\u5177\uFF0C\u5FEB\u901F\u521B\u5EFA\u9879\u76EE\u5E76\u53EF\u9009\u521D\u59CB\u5316 GitHub \u4ED3\u5E93").version(version).argument("[project-name]", "\u9879\u76EE\u540D\u79F0").option("-t, --template <template>", "\u4F7F\u7528\u6307\u5B9A\u6A21\u677F").option("--github", "\u5728 GitHub \u521B\u5EFA\u8FDC\u7A0B\u4ED3\u5E93").option("--public", "\u521B\u5EFA\u516C\u5F00\u4ED3\u5E93 (\u9ED8\u8BA4\u79C1\u6709)").option("--no-git", "\u8DF3\u8FC7 Git \u521D\u59CB\u5316").option("--no-install", "\u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5").option("-y, --yes", "\u8DF3\u8FC7\u6240\u6709\u786E\u8BA4\u63D0\u793A\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C\uFF08\u975E\u4EA4\u4E92\u6A21\u5F0F\uFF09").option("--debug", "\u542F\u7528\u8C03\u8BD5\u8F93\u51FA").action(async (projectName, options) => {
832
+ if (options.debug) {
833
+ setDebugEnabled(true);
834
+ }
732
835
  console.log();
733
836
  console.log(` ${pc6.cyan("spec-go")} ${pc6.dim(`v${version}`)}`);
734
837
  console.log();
735
838
  checkForUpdates(version).catch(() => {
736
839
  });
737
840
  const userConfig = loadConfig();
841
+ const interactive = isInteractive(options);
738
842
  try {
739
- const projectOptions = await runPrompts(projectName, options, userConfig);
843
+ const projectOptions = await runPrompts(projectName, options, userConfig, interactive);
740
844
  await executeProject(projectOptions);
741
845
  } catch (err) {
742
846
  const error = err;
743
847
  if (error.message === "PROMPT_CANCELLED" || error.name === "ExitPromptError" || error.message.includes("User force closed")) {
744
848
  console.log(pc6.yellow("\n\u64CD\u4F5C\u5DF2\u53D6\u6D88"));
745
- process.exit(0);
849
+ process.exit(ExitCodes.SUCCESS);
746
850
  }
747
851
  throw err;
748
852
  }
749
853
  });
750
- program.command("list").description("\u5217\u51FA\u6240\u6709\u53EF\u7528\u6A21\u677F").action(() => {
854
+ program.command("list").description("\u5217\u51FA\u6240\u6709\u53EF\u7528\u6A21\u677F").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA").action((options) => {
751
855
  const templatesDir = getTemplatesDir();
752
856
  const registryPath = path7.join(templatesDir, "template.config.json");
753
857
  const registry = JSON.parse(
754
858
  fs5.readFileSync(registryPath, "utf-8")
755
859
  );
860
+ if (options.json) {
861
+ const output = {
862
+ templates: registry.templates.map((t) => ({
863
+ name: t.name,
864
+ displayName: t.displayName,
865
+ description: t.description,
866
+ category: t.category || "single"
867
+ }))
868
+ };
869
+ console.log(JSON.stringify(output, null, 2));
870
+ return;
871
+ }
756
872
  const singleTemplates = registry.templates.filter((t) => t.category !== "fullstack");
757
873
  const fullstackTemplates = registry.templates.filter((t) => t.category === "fullstack");
758
874
  console.log();
@@ -772,7 +888,7 @@ async function createCli() {
772
888
  program.command("config").description("\u7BA1\u7406\u914D\u7F6E").option("--setup-github", "\u914D\u7F6E GitHub Token").option("--show", "\u663E\u793A\u5F53\u524D\u914D\u7F6E").option("--path", "\u663E\u793A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").action(async (options) => {
773
889
  if (options.setupGithub) {
774
890
  const success = await runGitHubSetup();
775
- process.exit(success ? 0 : 1);
891
+ process.exit(success ? ExitCodes.SUCCESS : ExitCodes.USER_ERROR);
776
892
  } else if (options.show) {
777
893
  showConfig();
778
894
  } else if (options.path) {
@@ -844,7 +960,13 @@ async function main() {
844
960
  await program.parseAsync(process.argv);
845
961
  }
846
962
  main().catch((err) => {
963
+ if (err instanceof CliError) {
964
+ if (isDebugEnabled()) {
965
+ console.error(err);
966
+ }
967
+ process.exit(err.exitCode);
968
+ }
847
969
  console.error(err);
848
- process.exit(1);
970
+ process.exit(ExitCodes.INTERNAL_ERROR);
849
971
  });
850
972
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../package.json","../src/prompts.ts","../src/utils.ts","../src/scaffold.ts","../src/git.ts","../src/config.ts","../src/github-api.ts","../src/post-init.ts","../src/update-check.ts","../src/github-setup.ts","../src/index.ts"],"sourcesContent":["import path from 'node:path'\nimport fs from 'node:fs'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { version } from '../package.json'\nimport { runPrompts } from './prompts.js'\nimport { scaffoldProject } from './scaffold.js'\nimport { initGit, createGithubRepo } from './git.js'\nimport { runPostInit, runWorkspacePostInit } from './post-init.js'\nimport { loadConfig, getConfigPath } from './config.js'\nimport { checkForUpdates, runUpdate } from './update-check.js'\nimport { runGitHubSetup, showConfig } from './github-setup.js'\nimport { getTemplatesDir } from './utils.js'\nimport type { CliOptions, ProjectOptions, TemplateRegistry } from './types.js'\n\nexport async function createCli(): Promise<Command> {\n const program = new Command()\n\n program\n .name('spec-go')\n .description('CLI 脚手架工具,快速创建项目并可选初始化 GitHub 仓库')\n .version(version)\n .argument('[project-name]', '项目名称')\n .option('-t, --template <template>', '使用指定模板')\n .option('--github', '在 GitHub 创建远程仓库')\n .option('--public', '创建公开仓库 (默认私有)')\n .option('--no-git', '跳过 Git 初始化')\n .option('--no-install', '跳过依赖安装')\n .action(async (projectName: string | undefined, options: CliOptions) => {\n console.log()\n console.log(` ${pc.cyan('spec-go')} ${pc.dim(`v${version}`)}`)\n console.log()\n\n // 异步检查更新(不阻塞主流程)\n checkForUpdates(version).catch(() => {})\n\n // 加载用户配置\n const userConfig = loadConfig()\n\n try {\n const projectOptions = await runPrompts(projectName, options, userConfig)\n await executeProject(projectOptions)\n } catch (err) {\n const error = err as Error\n // @inquirer/prompts 在 Ctrl+C 时抛出 ExitPromptError\n // 检查多种可能的中断标识\n if (\n error.message === 'PROMPT_CANCELLED' ||\n error.name === 'ExitPromptError' ||\n error.message.includes('User force closed')\n ) {\n console.log(pc.yellow('\\n操作已取消'))\n process.exit(0)\n }\n throw err\n }\n })\n\n // list 子命令\n program\n .command('list')\n .description('列出所有可用模板')\n .action(() => {\n const templatesDir = getTemplatesDir()\n const registryPath = path.join(templatesDir, 'template.config.json')\n const registry: TemplateRegistry = JSON.parse(\n fs.readFileSync(registryPath, 'utf-8')\n )\n\n const singleTemplates = registry.templates.filter(t => t.category !== 'fullstack')\n const fullstackTemplates = registry.templates.filter(t => t.category === 'fullstack')\n\n console.log()\n console.log(pc.cyan(' 单体项目:'))\n for (const t of singleTemplates) {\n console.log(` ${pc.green(t.name.padEnd(24))} ${pc.dim(t.displayName)}`)\n }\n\n if (fullstackTemplates.length > 0) {\n console.log()\n console.log(pc.cyan(' 前后端分离:'))\n for (const t of fullstackTemplates) {\n console.log(` ${pc.green(t.name.padEnd(24))} ${pc.dim(t.displayName)}`)\n }\n }\n console.log()\n })\n\n // config 子命令\n program\n .command('config')\n .description('管理配置')\n .option('--setup-github', '配置 GitHub Token')\n .option('--show', '显示当前配置')\n .option('--path', '显示配置文件路径')\n .action(async (options: { setupGithub?: boolean; show?: boolean; path?: boolean }) => {\n if (options.setupGithub) {\n const success = await runGitHubSetup()\n process.exit(success ? 0 : 1)\n } else if (options.show) {\n showConfig()\n } else if (options.path) {\n console.log(getConfigPath())\n } else {\n // 默认显示帮助\n console.log()\n console.log(pc.cyan('配置管理命令:'))\n console.log()\n console.log(` ${pc.dim('spec-go config --setup-github')} 配置 GitHub Token`)\n console.log(` ${pc.dim('spec-go config --show')} 显示当前配置`)\n console.log(` ${pc.dim('spec-go config --path')} 显示配置文件路径`)\n console.log()\n }\n })\n\n // update 子命令\n program\n .command('update')\n .description('检查并更新到最新版本')\n .option('--check', '仅检查版本,不执行更新')\n .action(async (options: { check?: boolean }) => {\n await runUpdate(version, options.check ?? false)\n })\n\n return program\n}\n\nasync function executeProject(options: ProjectOptions): Promise<void> {\n const templateConfig = await scaffoldProject(options)\n console.log(pc.green('✔ 项目文件已生成'))\n\n if (!options.noInstall && templateConfig) {\n if (templateConfig.type === 'workspace') {\n await runWorkspacePostInit(options.targetDir, templateConfig)\n console.log(pc.green('✔ 依赖安装完成'))\n } else if (templateConfig.postInit) {\n await runPostInit(options.targetDir, templateConfig.postInit)\n console.log(pc.green('✔ 依赖安装完成'))\n }\n }\n\n if (options.initGit) {\n await initGit(options.targetDir)\n console.log(pc.green('✔ Git 仓库已初始化'))\n }\n\n if (options.createGithub) {\n const repoUrl = await createGithubRepo(\n options.projectName,\n options.targetDir,\n options.isPublic\n )\n if (repoUrl) {\n console.log(pc.green(`✔ GitHub 仓库已创建: ${pc.cyan(repoUrl)}`))\n }\n }\n\n console.log()\n const pm = templateConfig?.packageManager ?? 'pnpm'\n const cdCmd = options.targetDir !== process.cwd()\n ? `cd ${options.projectName} && `\n : ''\n\n // workspace 类型的项目显示不同的提示\n if (templateConfig?.type === 'workspace') {\n if (pm === 'pnpm') {\n console.log(pc.dim(` ${cdCmd}pnpm dev`))\n } else {\n console.log(pc.dim(` ${cdCmd}make dev`))\n }\n } else if (pm === 'maven') {\n console.log(pc.dim(` ${cdCmd}./mvnw spring-boot:run`))\n } else if (pm === 'gradle') {\n console.log(pc.dim(` ${cdCmd}./gradlew bootRun`))\n } else {\n console.log(pc.dim(` ${cdCmd}${pm} dev`))\n }\n console.log()\n}\n","{\n \"name\": \"@lambertkeith/spec-go\",\n \"version\": \"0.2.4\",\n \"description\": \"CLI 脚手架工具,快速创建项目并可选初始化 GitHub 仓库\",\n \"type\": \"module\",\n \"bin\": {\n \"spec-go\": \"./dist/index.js\"\n },\n \"files\": [\n \"dist\",\n \"templates\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest\",\n \"test:run\": \"vitest run\",\n \"prepublishOnly\": \"pnpm build\"\n },\n \"keywords\": [\n \"cli\",\n \"scaffold\",\n \"create\",\n \"spec-go\",\n \"template\",\n \"generator\"\n ],\n \"author\": \"\",\n \"license\": \"MIT\",\n \"devDependencies\": {\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/node\": \"^22.10.7\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.7.3\",\n \"vitest\": \"^3.0.4\"\n },\n \"dependencies\": {\n \"@inquirer/prompts\": \"^7.2.1\",\n \"commander\": \"^13.0.0\",\n \"fs-extra\": \"^11.2.0\",\n \"picocolors\": \"^1.1.1\"\n },\n \"engines\": {\n \"node\": \">=18.0.0\"\n }\n}\n","import path from 'node:path'\nimport fs from 'node:fs'\nimport { input, select, confirm, Separator } from '@inquirer/prompts'\nimport pc from 'picocolors'\nimport { getTemplatesDir, isValidPackageName, toValidPackageName, isEmpty } from './utils.js'\nimport type { CliOptions, ProjectOptions, TemplateRegistry, UserConfig } from './types.js'\n\nexport async function runPrompts(\n argProjectName: string | undefined,\n options: CliOptions,\n userConfig: UserConfig = {}\n): Promise<ProjectOptions> {\n const defaults = userConfig.defaults ?? {}\n const templatesDir = getTemplatesDir()\n const registryPath = path.join(templatesDir, 'template.config.json')\n const registry: TemplateRegistry = JSON.parse(\n fs.readFileSync(registryPath, 'utf-8')\n )\n\n let projectName = argProjectName\n\n if (!projectName) {\n projectName = await input({\n message: '项目名称:',\n default: 'my-project',\n validate: (value) => {\n if (!value.trim()) {\n return '项目名称不能为空'\n }\n if (!isValidPackageName(toValidPackageName(value))) {\n return '无效的项目名称'\n }\n return true\n }\n })\n }\n\n const validName = toValidPackageName(projectName)\n const targetDir = path.resolve(process.cwd(), validName)\n\n if (fs.existsSync(targetDir) && !isEmpty(targetDir)) {\n const overwrite = await confirm({\n message: `目标目录 \"${validName}\" 非空,是否继续? (将覆盖已有文件)`,\n default: false\n })\n if (!overwrite) {\n const error = new Error('PROMPT_CANCELLED')\n throw error\n }\n }\n\n let template = options.template\n if (!template) {\n // 配置文件中的默认模板\n const defaultTemplate = defaults.template\n\n // 分组模板\n const singleTemplates = registry.templates.filter(t => t.category !== 'fullstack')\n const fullstackTemplates = registry.templates.filter(t => t.category === 'fullstack')\n\n const templateChoices: Array<{ name: string; value: string } | Separator> = []\n\n // 单体项目组\n templateChoices.push(new Separator('── 单体项目 ──'))\n for (const t of singleTemplates) {\n templateChoices.push({\n name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,\n value: t.name\n })\n }\n\n // 前后端分离组\n if (fullstackTemplates.length > 0) {\n templateChoices.push(new Separator('── 前后端分离 ──'))\n for (const t of fullstackTemplates) {\n templateChoices.push({\n name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,\n value: t.name\n })\n }\n }\n\n template = await select({\n message: '选择模板:',\n choices: templateChoices,\n default: defaultTemplate && registry.templates.some((t) => t.name === defaultTemplate)\n ? defaultTemplate\n : undefined\n })\n } else {\n const found = registry.templates.find((t) => t.name === template)\n if (!found) {\n console.log(pc.red(`错误: 未找到模板 \"${template}\"`))\n console.log(pc.dim(`可用模板: ${registry.templates.map((t) => t.name).join(', ')}`))\n process.exit(1)\n }\n }\n\n let initGit = options.git !== false\n if (options.git === undefined) {\n initGit = await confirm({\n message: '初始化 Git 仓库?',\n default: true\n })\n }\n\n let createGithub = options.github ?? false\n if (initGit && options.github === undefined) {\n createGithub = await confirm({\n message: '在 GitHub 创建远程仓库?',\n default: defaults.github ?? false\n })\n }\n\n let isPublic = options.public ?? false\n if (createGithub && options.public === undefined) {\n const publicDefault = defaults.public ?? false\n isPublic = await select({\n message: '仓库可见性:',\n choices: [\n { name: 'private (私有)', value: false },\n { name: 'public (公开)', value: true }\n ],\n default: publicDefault\n }) as boolean\n }\n\n return {\n projectName: validName,\n template,\n targetDir,\n initGit,\n createGithub,\n isPublic,\n noInstall: options.install === false\n }\n}\n","import path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { spawn } from 'node:child_process'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nexport function getTemplatesDir(): string {\n return path.resolve(__dirname, '..', 'templates')\n}\n\nexport function isValidPackageName(name: string): boolean {\n return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name)\n}\n\nexport function toValidPackageName(name: string): string {\n return name\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/^[._]/, '')\n .replace(/[^a-z0-9-~]+/g, '-')\n}\n\nexport function isEmpty(dirPath: string): boolean {\n const fs = require('node:fs')\n if (!fs.existsSync(dirPath)) {\n return true\n }\n const files = fs.readdirSync(dirPath)\n return files.length === 0 || (files.length === 1 && files[0] === '.git')\n}\n\nexport function execAsync(\n command: string,\n args: string[],\n options: { cwd?: string; stdio?: 'inherit' | 'pipe' } = {}\n): Promise<{ code: number; stdout: string; stderr: string }> {\n return new Promise((resolve) => {\n const proc = spawn(command, args, {\n cwd: options.cwd,\n stdio: options.stdio === 'inherit' ? 'inherit' : 'pipe',\n shell: true\n })\n\n let stdout = ''\n let stderr = ''\n\n if (proc.stdout) {\n proc.stdout.on('data', (data) => {\n stdout += data.toString()\n })\n }\n\n if (proc.stderr) {\n proc.stderr.on('data', (data) => {\n stderr += data.toString()\n })\n }\n\n proc.on('close', (code) => {\n resolve({ code: code ?? 1, stdout, stderr })\n })\n\n proc.on('error', () => {\n resolve({ code: 1, stdout, stderr })\n })\n })\n}\n\nexport async function commandExists(command: string): Promise<boolean> {\n const result = await execAsync('which', [command])\n return result.code === 0\n}\n","import path from 'node:path'\nimport fs from 'fs-extra'\nimport { getTemplatesDir } from './utils.js'\nimport type { ProjectOptions, TemplateConfig, TemplateRegistry } from './types.js'\n\nexport async function scaffoldProject(\n options: ProjectOptions\n): Promise<TemplateConfig | null> {\n const templatesDir = getTemplatesDir()\n const registryPath = path.join(templatesDir, 'template.config.json')\n const registry: TemplateRegistry = await fs.readJson(registryPath)\n\n const templateEntry = registry.templates.find((t) => t.name === options.template)\n if (!templateEntry) {\n throw new Error(`未找到模板: ${options.template}`)\n }\n\n const templateDir = path.join(templatesDir, templateEntry.dir)\n const templateConfigPath = path.join(templateDir, '_template.json')\n\n let templateConfig: TemplateConfig | null = null\n if (await fs.pathExists(templateConfigPath)) {\n templateConfig = await fs.readJson(templateConfigPath)\n }\n\n await fs.ensureDir(options.targetDir)\n\n const files = await fs.readdir(templateDir)\n\n for (const file of files) {\n if (file === '_template.json') {\n continue\n }\n\n const srcPath = path.join(templateDir, file)\n let destFileName = file\n\n if (templateConfig?.fileRenames?.[file]) {\n destFileName = templateConfig.fileRenames[file]\n if (destFileName === '{{projectName}}') {\n destFileName = options.projectName\n }\n }\n\n const destPath = path.join(options.targetDir, destFileName)\n const stat = await fs.stat(srcPath)\n\n if (stat.isDirectory()) {\n await copyDirectory(srcPath, destPath, options.projectName, templateConfig)\n } else {\n await copyFile(srcPath, destPath, options.projectName, templateConfig)\n }\n }\n\n return templateConfig\n}\n\nasync function copyDirectory(\n srcDir: string,\n destDir: string,\n projectName: string,\n config: TemplateConfig | null\n): Promise<void> {\n await fs.ensureDir(destDir)\n const files = await fs.readdir(srcDir)\n\n for (const file of files) {\n const srcPath = path.join(srcDir, file)\n let destFileName = file\n\n if (config?.fileRenames?.[file]) {\n destFileName = config.fileRenames[file]\n if (destFileName === '{{projectName}}') {\n destFileName = projectName\n }\n }\n\n const destPath = path.join(destDir, destFileName)\n const stat = await fs.stat(srcPath)\n\n if (stat.isDirectory()) {\n await copyDirectory(srcPath, destPath, projectName, config)\n } else {\n await copyFile(srcPath, destPath, projectName, config)\n }\n }\n}\n\nasync function copyFile(\n srcPath: string,\n destPath: string,\n projectName: string,\n config: TemplateConfig | null\n): Promise<void> {\n const binaryExtensions = [\n '.png', '.jpg', '.jpeg', '.gif', '.ico', '.webp',\n '.woff', '.woff2', '.ttf', '.eot',\n '.zip', '.tar', '.gz'\n ]\n\n const ext = path.extname(srcPath).toLowerCase()\n\n if (binaryExtensions.includes(ext)) {\n await fs.copy(srcPath, destPath)\n return\n }\n\n let content = await fs.readFile(srcPath, 'utf-8')\n\n content = content.replace(/\\{\\{projectName\\}\\}/g, projectName)\n\n if (config?.variables) {\n for (const [key, value] of Object.entries(config.variables)) {\n const placeholder = `{{${key}}}`\n const replacement = value === '{{projectName}}' ? projectName : value\n content = content.replace(new RegExp(placeholder.replace(/[{}]/g, '\\\\$&'), 'g'), replacement)\n }\n }\n\n await fs.writeFile(destPath, content, 'utf-8')\n}\n","import pc from 'picocolors'\nimport { execAsync } from './utils.js'\nimport { loadConfig, getConfigPath } from './config.js'\nimport { validateToken, createRepository } from './github-api.js'\n\nexport async function initGit(targetDir: string): Promise<void> {\n await execAsync('git', ['init'], { cwd: targetDir })\n await execAsync('git', ['add', '-A'], { cwd: targetDir })\n await execAsync('git', ['commit', '-m', 'Initial commit'], { cwd: targetDir })\n}\n\nexport interface CreateGithubRepoResult {\n success: boolean\n repoUrl?: string\n error?: string\n}\n\nexport async function createGithubRepo(\n repoName: string,\n targetDir: string,\n isPublic: boolean\n): Promise<string | null> {\n const config = loadConfig()\n\n // 检查 Token 是否配置\n if (!config.github?.token) {\n console.log(pc.yellow('⚠ 未配置 GitHub Token,跳过仓库创建'))\n console.log(pc.dim(` 运行 ${pc.cyan('spec-go config --setup-github')} 配置 Token`))\n console.log(pc.dim(` 配置文件路径: ${getConfigPath()}`))\n return null\n }\n\n const token = config.github.token\n const defaultOrg = config.github.defaultOrg\n\n // 验证 Token\n const validateResult = await validateToken(token)\n if (!validateResult.success) {\n console.log(pc.yellow(`⚠ GitHub Token 无效: ${validateResult.error}`))\n if (validateResult.rateLimitReset) {\n console.log(pc.dim(` Rate limit 将在 ${validateResult.rateLimitReset.toLocaleString()} 重置`))\n }\n console.log(pc.dim(` 运行 ${pc.cyan('spec-go config --setup-github')} 重新配置`))\n return null\n }\n\n const username = validateResult.data.login\n\n // 创建仓库\n const createResult = await createRepository(token, {\n name: repoName,\n isPrivate: !isPublic,\n org: defaultOrg\n })\n\n if (!createResult.success) {\n if (createResult.statusCode === 422) {\n console.log(pc.yellow(`⚠ 仓库 \"${repoName}\" 已存在,请选择其他名称`))\n } else if (createResult.rateLimitReset) {\n console.log(pc.yellow(`⚠ API 请求次数已达上限`))\n console.log(pc.dim(` 将在 ${createResult.rateLimitReset.toLocaleString()} 重置`))\n } else {\n console.log(pc.yellow(`⚠ 创建仓库失败: ${createResult.error}`))\n }\n return null\n }\n\n const repo = createResult.data\n\n // 添加远程仓库并推送\n const remoteResult = await execAsync(\n 'git',\n ['remote', 'add', 'origin', repo.clone_url],\n { cwd: targetDir }\n )\n\n if (remoteResult.code !== 0) {\n // remote 可能已存在,尝试更新\n await execAsync(\n 'git',\n ['remote', 'set-url', 'origin', repo.clone_url],\n { cwd: targetDir }\n )\n }\n\n // 推送到远程\n const pushResult = await execAsync(\n 'git',\n ['push', '-u', 'origin', 'main'],\n { cwd: targetDir }\n )\n\n if (pushResult.code !== 0) {\n // 尝试推送 master 分支\n const pushMaster = await execAsync(\n 'git',\n ['push', '-u', 'origin', 'master'],\n { cwd: targetDir }\n )\n if (pushMaster.code !== 0) {\n console.log(pc.yellow(`⚠ 推送失败: ${pushResult.stderr || pushMaster.stderr}`))\n console.log(pc.dim(` 仓库已创建: ${repo.html_url}`))\n console.log(pc.dim(' 请手动推送代码'))\n return repo.html_url\n }\n }\n\n return repo.html_url\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport type { UserConfig } from './types.js'\n\nconst CONFIG_PATH = path.join(os.homedir(), '.spec-go.json')\n\nconst DEFAULT_CONFIG: UserConfig = {\n defaults: {\n github: false,\n public: false,\n template: ''\n },\n github: {\n token: '',\n defaultOrg: ''\n }\n}\n\n/**\n * 确保配置文件存在,如果不存在则创建默认配置\n */\nexport function ensureConfigExists(): void {\n if (!fs.existsSync(CONFIG_PATH)) {\n saveConfig(DEFAULT_CONFIG)\n }\n}\n\nexport function loadConfig(): UserConfig {\n try {\n if (fs.existsSync(CONFIG_PATH)) {\n const content = fs.readFileSync(CONFIG_PATH, 'utf-8')\n return JSON.parse(content) as UserConfig\n }\n } catch {\n // 配置文件损坏或读取失败,返回空配置\n }\n return {}\n}\n\nexport function saveConfig(config: UserConfig): void {\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8')\n // 设置文件权限为 600 (仅所有者可读写),保护 Token 安全\n fs.chmodSync(CONFIG_PATH, 0o600)\n}\n\nexport function getConfigPath(): string {\n return CONFIG_PATH\n}\n","import type { GitHubUser, GitHubRepoResponse, GitHubApiError } from './types.js'\n\nconst GITHUB_API_BASE = 'https://api.github.com'\n\ninterface GitHubApiResult<T> {\n success: true\n data: T\n}\n\ninterface GitHubApiFailure {\n success: false\n error: string\n statusCode?: number\n rateLimitReset?: Date\n}\n\ntype GitHubApiResponse<T> = GitHubApiResult<T> | GitHubApiFailure\n\nasync function githubFetch<T>(\n endpoint: string,\n token: string,\n options: RequestInit = {}\n): Promise<GitHubApiResponse<T>> {\n const url = `${GITHUB_API_BASE}${endpoint}`\n\n try {\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Accept': 'application/vnd.github+json',\n 'Authorization': `Bearer ${token}`,\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': 'spec-go',\n ...options.headers,\n },\n })\n\n // 处理 Rate Limit\n if (response.status === 403) {\n const rateLimitRemaining = response.headers.get('x-ratelimit-remaining')\n const rateLimitReset = response.headers.get('x-ratelimit-reset')\n\n if (rateLimitRemaining === '0' && rateLimitReset) {\n const resetDate = new Date(parseInt(rateLimitReset) * 1000)\n return {\n success: false,\n error: 'API 请求次数已达上限',\n statusCode: 403,\n rateLimitReset: resetDate,\n }\n }\n }\n\n // 处理未授权\n if (response.status === 401) {\n return {\n success: false,\n error: 'Token 无效或已过期',\n statusCode: 401,\n }\n }\n\n // 处理其他错误\n if (!response.ok) {\n const errorData = await response.json() as GitHubApiError\n return {\n success: false,\n error: errorData.message || `请求失败: ${response.status}`,\n statusCode: response.status,\n }\n }\n\n const data = await response.json() as T\n return { success: true, data }\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : '网络请求失败',\n }\n }\n}\n\n/**\n * 验证 Token 并获取用户信息\n */\nexport async function validateToken(token: string): Promise<GitHubApiResponse<GitHubUser>> {\n return githubFetch<GitHubUser>('/user', token)\n}\n\nexport interface CreateRepoOptions {\n name: string\n description?: string\n isPrivate: boolean\n org?: string\n}\n\n/**\n * 创建 GitHub 仓库\n */\nexport async function createRepository(\n token: string,\n options: CreateRepoOptions\n): Promise<GitHubApiResponse<GitHubRepoResponse>> {\n const endpoint = options.org\n ? `/orgs/${options.org}/repos`\n : '/user/repos'\n\n const body = {\n name: options.name,\n description: options.description || `Created with spec-go`,\n private: options.isPrivate,\n auto_init: false,\n }\n\n return githubFetch<GitHubRepoResponse>(endpoint, token, {\n method: 'POST',\n body: JSON.stringify(body),\n })\n}\n\n/**\n * 检查仓库是否存在\n */\nexport async function checkRepoExists(\n token: string,\n owner: string,\n repo: string\n): Promise<boolean> {\n const result = await githubFetch<GitHubRepoResponse>(\n `/repos/${owner}/${repo}`,\n token\n )\n return result.success\n}\n","import path from 'node:path'\nimport pc from 'picocolors'\nimport { execAsync } from './utils.js'\nimport type { PostInitCommand, TemplateConfig } from './types.js'\n\nexport async function runPostInit(\n targetDir: string,\n commands: PostInitCommand[]\n): Promise<void> {\n for (const cmd of commands) {\n console.log(pc.dim(` ${cmd.description}...`))\n const [command, ...args] = cmd.command.split(' ')\n const result = await execAsync(command, args, {\n cwd: targetDir,\n stdio: 'pipe'\n })\n\n if (result.code !== 0) {\n console.log(pc.yellow(`⚠ ${cmd.description} 失败`))\n if (result.stderr) {\n console.log(pc.dim(result.stderr.slice(0, 200)))\n }\n }\n }\n}\n\nexport async function runWorkspacePostInit(\n targetDir: string,\n config: TemplateConfig\n): Promise<void> {\n // 先执行根目录的 postInit 命令(如果有)\n if (config.postInit && config.postInit.length > 0) {\n await runPostInit(targetDir, config.postInit)\n }\n\n // 再执行各子目录的 postInit 命令\n if (config.workspaces) {\n for (const ws of config.workspaces) {\n if (ws.postInit && ws.postInit.length > 0) {\n const wsDir = path.join(targetDir, ws.name)\n console.log(pc.dim(` [${ws.name}]`))\n await runPostInit(wsDir, ws.postInit)\n }\n }\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { execSync } from 'node:child_process'\nimport pc from 'picocolors'\n\nconst CACHE_PATH = path.join(os.homedir(), '.spec-go-update-check')\nconst CACHE_TTL = 24 * 60 * 60 * 1000 // 24 小时\nconst PACKAGE_NAME = '@lambertkeith/spec-go'\n\ninterface UpdateCache {\n lastCheck: number\n latestVersion: string\n}\n\nfunction readCache(): UpdateCache | null {\n try {\n if (fs.existsSync(CACHE_PATH)) {\n const content = fs.readFileSync(CACHE_PATH, 'utf-8')\n return JSON.parse(content) as UpdateCache\n }\n } catch {\n // 忽略缓存读取错误\n }\n return null\n}\n\nfunction writeCache(cache: UpdateCache): void {\n try {\n fs.writeFileSync(CACHE_PATH, JSON.stringify(cache), 'utf-8')\n } catch {\n // 忽略缓存写入错误\n }\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const response = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`)\n if (!response.ok) {\n return null\n }\n const data = (await response.json()) as { version: string }\n return data.version\n } catch {\n // 网络请求失败,静默处理\n return null\n }\n}\n\nfunction compareVersions(current: string, latest: string): number {\n const currentParts = current.split('.').map(Number)\n const latestParts = latest.split('.').map(Number)\n\n for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {\n const c = currentParts[i] || 0\n const l = latestParts[i] || 0\n if (c < l) return -1\n if (c > l) return 1\n }\n return 0\n}\n\nexport async function checkForUpdates(currentVersion: string): Promise<void> {\n const cache = readCache()\n const now = Date.now()\n\n let latestVersion: string | null = null\n\n // 检查缓存是否有效\n if (cache && now - cache.lastCheck < CACHE_TTL) {\n latestVersion = cache.latestVersion\n } else {\n // 缓存过期,重新获取\n latestVersion = await fetchLatestVersion()\n if (latestVersion) {\n writeCache({ lastCheck: now, latestVersion })\n }\n }\n\n // 比较版本并提示\n if (latestVersion && compareVersions(currentVersion, latestVersion) < 0) {\n console.log()\n console.log(\n pc.yellow(` \\u26A0 发现新版本 ${pc.bold(latestVersion)},当前 ${currentVersion}`)\n )\n console.log(pc.cyan(` 运行 ${pc.bold(`npm update -g ${PACKAGE_NAME}`)} 更新`))\n console.log()\n }\n}\n\ntype PackageManager = 'npm' | 'pnpm' | 'yarn'\n\nfunction detectPackageManager(): PackageManager {\n // 检查 spec-go 是通过哪个包管理器安装的\n // 方法:检查全局安装路径中是否包含 pnpm/yarn 特征\n const execPath = process.argv[1] || ''\n\n if (execPath.includes('pnpm')) return 'pnpm'\n if (execPath.includes('yarn')) return 'yarn'\n return 'npm'\n}\n\nfunction getUpdateCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return `pnpm update -g ${PACKAGE_NAME}`\n case 'yarn':\n return `yarn global upgrade ${PACKAGE_NAME}`\n default:\n return `npm update -g ${PACKAGE_NAME}`\n }\n}\n\nexport async function runUpdate(currentVersion: string, checkOnly: boolean): Promise<void> {\n // 1. 强制获取最新版本(跳过缓存)\n const latestVersion = await fetchLatestVersion()\n\n if (!latestVersion) {\n console.log(pc.red('✗ 无法获取最新版本信息'))\n process.exit(1)\n }\n\n // 2. 版本比较\n const comparison = compareVersions(currentVersion, latestVersion)\n\n if (comparison >= 0) {\n console.log(pc.green(`✔ 已是最新版本 (${currentVersion})`))\n return\n }\n\n console.log(pc.cyan(`发现新版本: ${currentVersion} → ${latestVersion}`))\n\n if (checkOnly) {\n console.log(pc.dim(`运行 spec-go update 更新`))\n return\n }\n\n // 3. 检测包管理器并执行更新\n const pm = detectPackageManager()\n const updateCmd = getUpdateCommand(pm)\n\n console.log(pc.dim(`正在执行: ${updateCmd}`))\n\n // 4. 执行更新命令\n try {\n execSync(updateCmd, { stdio: 'inherit' })\n console.log(pc.green(`✔ 更新完成`))\n } catch {\n console.log(pc.red('✗ 更新失败,请手动执行更新命令'))\n process.exit(1)\n }\n}\n","import { input, confirm } from '@inquirer/prompts'\nimport pc from 'picocolors'\nimport { loadConfig, saveConfig } from './config.js'\nimport { validateToken } from './github-api.js'\n\nconst TOKEN_HELP_URL = 'https://github.com/settings/tokens/new?scopes=repo&description=spec-go'\n\n/**\n * 检查是否为用户中断操作(Ctrl+C)\n */\nfunction isUserCancelled(err: unknown): boolean {\n const error = err as Error\n return (\n error.message === 'PROMPT_CANCELLED' ||\n error.name === 'ExitPromptError' ||\n error.message.includes('User force closed')\n )\n}\n\n/**\n * 运行 GitHub Token 配置引导\n */\nexport async function runGitHubSetup(): Promise<boolean> {\n console.log()\n console.log(pc.cyan('配置 GitHub Token'))\n console.log()\n console.log('需要一个具有 repo 权限的 Personal Access Token (Classic) 来创建仓库。')\n console.log()\n console.log(pc.dim('获取步骤:'))\n console.log(pc.dim('1. 访问 GitHub Settings > Developer settings > Personal access tokens'))\n console.log(pc.dim('2. 点击 \"Generate new token (classic)\"'))\n console.log(pc.dim('3. 勾选 \"repo\" 权限'))\n console.log(pc.dim('4. 生成并复制 Token'))\n console.log()\n console.log(pc.dim(`快捷链接: ${TOKEN_HELP_URL}`))\n console.log()\n\n try {\n const token = await input({\n message: '请输入 GitHub Token:',\n validate: (value) => {\n if (!value.trim()) {\n return 'Token 不能为空'\n }\n if (!value.startsWith('ghp_') && !value.startsWith('github_pat_')) {\n return 'Token 格式不正确,应以 ghp_ 或 github_pat_ 开头'\n }\n return true\n }\n })\n\n console.log()\n console.log(pc.dim('正在验证 Token...'))\n\n const result = await validateToken(token.trim())\n\n if (!result.success) {\n console.log(pc.red(`✗ Token 验证失败: ${result.error}`))\n if (result.rateLimitReset) {\n console.log(pc.dim(` Rate limit 将在 ${result.rateLimitReset.toLocaleString()} 重置`))\n }\n return false\n }\n\n const user = result.data\n console.log(pc.green(`✔ Token 有效,已登录为: ${user.login}${user.name ? ` (${user.name})` : ''}`))\n console.log()\n\n // 询问是否设置默认组织\n const setOrg = await confirm({\n message: '是否设置默认组织? (否则仓库将创建在个人账户下)',\n default: false\n })\n\n let defaultOrg: string | undefined\n if (setOrg) {\n defaultOrg = await input({\n message: '默认组织名称:',\n validate: (value) => {\n if (!value.trim()) {\n return '组织名称不能为空'\n }\n return true\n }\n })\n defaultOrg = defaultOrg.trim()\n }\n\n // 保存配置\n const config = loadConfig()\n config.github = {\n token: token.trim(),\n ...(defaultOrg && { defaultOrg })\n }\n saveConfig(config)\n\n console.log()\n console.log(pc.green('✔ GitHub 配置已保存'))\n console.log(pc.dim(' 配置文件已设置为仅当前用户可读'))\n\n return true\n } catch (err) {\n if (isUserCancelled(err)) {\n console.log(pc.yellow('\\n操作已取消'))\n return false\n }\n throw err\n }\n}\n\n/**\n * 显示当前配置\n */\nexport function showConfig(): void {\n const config = loadConfig()\n\n console.log()\n console.log(pc.cyan('当前配置:'))\n console.log()\n\n if (config.defaults) {\n console.log(pc.dim('defaults:'))\n if (config.defaults.github !== undefined) {\n console.log(` github: ${config.defaults.github}`)\n }\n if (config.defaults.public !== undefined) {\n console.log(` public: ${config.defaults.public}`)\n }\n if (config.defaults.template !== undefined) {\n console.log(` template: ${config.defaults.template}`)\n }\n }\n\n if (config.github) {\n console.log(pc.dim('github:'))\n if (config.github.token) {\n const masked = config.github.token.slice(0, 8) + '...' + config.github.token.slice(-4)\n console.log(` token: ${masked}`)\n }\n if (config.github.defaultOrg) {\n console.log(` defaultOrg: ${config.github.defaultOrg}`)\n }\n }\n\n if (!config.defaults && !config.github) {\n console.log(pc.dim('(无配置)'))\n }\n\n console.log()\n}\n","import { createCli } from './cli.js'\nimport { ensureConfigExists } from './config.js'\n\nasync function main(): Promise<void> {\n // 确保配置文件存在\n ensureConfigExists()\n\n const program = await createCli()\n await program.parseAsync(process.argv)\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n"],"mappings":"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","names":["path","fs","pc","path","fs","path","initGit","path","fs","path","fs","pc","fs","path","pc","path","pc","pc","path","fs","path","os","pc","input","confirm","pc","pc","input","confirm","pc","path","fs"]}
1
+ {"version":3,"sources":["../src/cli.ts","../package.json","../src/prompts.ts","../src/utils.ts","../src/debug.ts","../src/exit-codes.ts","../src/scaffold.ts","../src/git.ts","../src/config.ts","../src/github-api.ts","../src/post-init.ts","../src/update-check.ts","../src/github-setup.ts","../src/index.ts"],"sourcesContent":["import path from 'node:path'\nimport fs from 'node:fs'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { version } from '../package.json'\nimport { runPrompts } from './prompts.js'\nimport { scaffoldProject } from './scaffold.js'\nimport { initGit, createGithubRepo } from './git.js'\nimport { runPostInit, runWorkspacePostInit } from './post-init.js'\nimport { loadConfig, getConfigPath } from './config.js'\nimport { checkForUpdates, runUpdate } from './update-check.js'\nimport { runGitHubSetup, showConfig } from './github-setup.js'\nimport { getTemplatesDir } from './utils.js'\nimport { ExitCodes, CliError } from './exit-codes.js'\nimport { setDebugEnabled } from './debug.js'\nimport type { CliOptions, ProjectOptions, TemplateRegistry } from './types.js'\n\n/**\n * 检查是否在交互模式下运行\n */\nfunction isInteractive(options: CliOptions): boolean {\n // --yes 选项强制非交互模式\n if (options.yes) return false\n // 检查 stdin 是否是 TTY\n return process.stdin.isTTY === true\n}\n\nexport async function createCli(): Promise<Command> {\n const program = new Command()\n\n program\n .name('spec-go')\n .description('CLI 脚手架工具,快速创建项目并可选初始化 GitHub 仓库')\n .version(version)\n .argument('[project-name]', '项目名称')\n .option('-t, --template <template>', '使用指定模板')\n .option('--github', '在 GitHub 创建远程仓库')\n .option('--public', '创建公开仓库 (默认私有)')\n .option('--no-git', '跳过 Git 初始化')\n .option('--no-install', '跳过依赖安装')\n .option('-y, --yes', '跳过所有确认提示,使用默认值(非交互模式)')\n .option('--debug', '启用调试输出')\n .action(async (projectName: string | undefined, options: CliOptions) => {\n // 启用调试模式\n if (options.debug) {\n setDebugEnabled(true)\n }\n\n console.log()\n console.log(` ${pc.cyan('spec-go')} ${pc.dim(`v${version}`)}`)\n console.log()\n\n // 异步检查更新(不阻塞主流程)\n checkForUpdates(version).catch(() => {})\n\n // 加载用户配置\n const userConfig = loadConfig()\n\n // 检查是否为交互模式\n const interactive = isInteractive(options)\n\n try {\n const projectOptions = await runPrompts(projectName, options, userConfig, interactive)\n await executeProject(projectOptions)\n } catch (err) {\n const error = err as Error\n // @inquirer/prompts 在 Ctrl+C 时抛出 ExitPromptError\n // 检查多种可能的中断标识\n if (\n error.message === 'PROMPT_CANCELLED' ||\n error.name === 'ExitPromptError' ||\n error.message.includes('User force closed')\n ) {\n console.log(pc.yellow('\\n操作已取消'))\n process.exit(ExitCodes.SUCCESS)\n }\n throw err\n }\n })\n\n // list 子命令\n program\n .command('list')\n .description('列出所有可用模板')\n .option('--json', '以 JSON 格式输出')\n .action((options: { json?: boolean }) => {\n const templatesDir = getTemplatesDir()\n const registryPath = path.join(templatesDir, 'template.config.json')\n const registry: TemplateRegistry = JSON.parse(\n fs.readFileSync(registryPath, 'utf-8')\n )\n\n // JSON 输出模式\n if (options.json) {\n const output = {\n templates: registry.templates.map(t => ({\n name: t.name,\n displayName: t.displayName,\n description: t.description,\n category: t.category || 'single'\n }))\n }\n console.log(JSON.stringify(output, null, 2))\n return\n }\n\n // 人类可读输出模式\n const singleTemplates = registry.templates.filter(t => t.category !== 'fullstack')\n const fullstackTemplates = registry.templates.filter(t => t.category === 'fullstack')\n\n console.log()\n console.log(pc.cyan(' 单体项目:'))\n for (const t of singleTemplates) {\n console.log(` ${pc.green(t.name.padEnd(24))} ${pc.dim(t.displayName)}`)\n }\n\n if (fullstackTemplates.length > 0) {\n console.log()\n console.log(pc.cyan(' 前后端分离:'))\n for (const t of fullstackTemplates) {\n console.log(` ${pc.green(t.name.padEnd(24))} ${pc.dim(t.displayName)}`)\n }\n }\n console.log()\n })\n\n // config 子命令\n program\n .command('config')\n .description('管理配置')\n .option('--setup-github', '配置 GitHub Token')\n .option('--show', '显示当前配置')\n .option('--path', '显示配置文件路径')\n .action(async (options: { setupGithub?: boolean; show?: boolean; path?: boolean }) => {\n if (options.setupGithub) {\n const success = await runGitHubSetup()\n process.exit(success ? ExitCodes.SUCCESS : ExitCodes.USER_ERROR)\n } else if (options.show) {\n showConfig()\n } else if (options.path) {\n console.log(getConfigPath())\n } else {\n // 默认显示帮助\n console.log()\n console.log(pc.cyan('配置管理命令:'))\n console.log()\n console.log(` ${pc.dim('spec-go config --setup-github')} 配置 GitHub Token`)\n console.log(` ${pc.dim('spec-go config --show')} 显示当前配置`)\n console.log(` ${pc.dim('spec-go config --path')} 显示配置文件路径`)\n console.log()\n }\n })\n\n // update 子命令\n program\n .command('update')\n .description('检查并更新到最新版本')\n .option('--check', '仅检查版本,不执行更新')\n .action(async (options: { check?: boolean }) => {\n await runUpdate(version, options.check ?? false)\n })\n\n return program\n}\n\nasync function executeProject(options: ProjectOptions): Promise<void> {\n const templateConfig = await scaffoldProject(options)\n console.log(pc.green('✔ 项目文件已生成'))\n\n if (!options.noInstall && templateConfig) {\n if (templateConfig.type === 'workspace') {\n await runWorkspacePostInit(options.targetDir, templateConfig)\n console.log(pc.green('✔ 依赖安装完成'))\n } else if (templateConfig.postInit) {\n await runPostInit(options.targetDir, templateConfig.postInit)\n console.log(pc.green('✔ 依赖安装完成'))\n }\n }\n\n if (options.initGit) {\n await initGit(options.targetDir)\n console.log(pc.green('✔ Git 仓库已初始化'))\n }\n\n if (options.createGithub) {\n const repoUrl = await createGithubRepo(\n options.projectName,\n options.targetDir,\n options.isPublic\n )\n if (repoUrl) {\n console.log(pc.green(`✔ GitHub 仓库已创建: ${pc.cyan(repoUrl)}`))\n }\n }\n\n console.log()\n const pm = templateConfig?.packageManager ?? 'pnpm'\n const cdCmd = options.targetDir !== process.cwd()\n ? `cd ${options.projectName} && `\n : ''\n\n // workspace 类型的项目显示不同的提示\n if (templateConfig?.type === 'workspace') {\n if (pm === 'pnpm') {\n console.log(pc.dim(` ${cdCmd}pnpm dev`))\n } else {\n console.log(pc.dim(` ${cdCmd}make dev`))\n }\n } else if (pm === 'maven') {\n console.log(pc.dim(` ${cdCmd}./mvnw spring-boot:run`))\n } else if (pm === 'gradle') {\n console.log(pc.dim(` ${cdCmd}./gradlew bootRun`))\n } else {\n console.log(pc.dim(` ${cdCmd}${pm} dev`))\n }\n console.log()\n}\n","{\n \"name\": \"@lambertkeith/spec-go\",\n \"version\": \"0.2.5\",\n \"description\": \"CLI 脚手架工具,快速创建项目并可选初始化 GitHub 仓库\",\n \"type\": \"module\",\n \"bin\": {\n \"spec-go\": \"./dist/index.js\"\n },\n \"files\": [\n \"dist\",\n \"templates\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest\",\n \"test:run\": \"vitest run\",\n \"prepublishOnly\": \"pnpm build\"\n },\n \"keywords\": [\n \"cli\",\n \"scaffold\",\n \"create\",\n \"spec-go\",\n \"template\",\n \"generator\"\n ],\n \"author\": \"\",\n \"license\": \"MIT\",\n \"devDependencies\": {\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/node\": \"^22.10.7\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.7.3\",\n \"vitest\": \"^3.0.4\"\n },\n \"dependencies\": {\n \"@inquirer/prompts\": \"^7.2.1\",\n \"commander\": \"^13.0.0\",\n \"fs-extra\": \"^11.2.0\",\n \"picocolors\": \"^1.1.1\"\n },\n \"engines\": {\n \"node\": \">=18.0.0\"\n }\n}\n","import path from 'node:path'\nimport fs from 'node:fs'\nimport { input, select, confirm, Separator } from '@inquirer/prompts'\nimport pc from 'picocolors'\nimport { getTemplatesDir, isValidPackageName, toValidPackageName, isEmpty } from './utils.js'\nimport { ExitCodes, CliError } from './exit-codes.js'\nimport { debug } from './debug.js'\nimport type { CliOptions, ProjectOptions, TemplateRegistry, UserConfig } from './types.js'\n\n/** 默认模板名称 */\nconst DEFAULT_TEMPLATE = 'node-ts'\n\nexport async function runPrompts(\n argProjectName: string | undefined,\n options: CliOptions,\n userConfig: UserConfig = {},\n interactive: boolean = true\n): Promise<ProjectOptions> {\n const defaults = userConfig.defaults ?? {}\n const templatesDir = getTemplatesDir()\n const registryPath = path.join(templatesDir, 'template.config.json')\n const registry: TemplateRegistry = JSON.parse(\n fs.readFileSync(registryPath, 'utf-8')\n )\n\n debug('prompts', `交互模式: ${interactive}`)\n debug('prompts', `CLI 参数`, { argProjectName, options })\n\n let projectName = argProjectName\n\n // 获取项目名称\n if (!projectName) {\n if (!interactive) {\n // 非交互模式下,项目名称是必需的\n console.log(pc.red('错误: 非交互模式下必须提供项目名称'))\n throw new CliError('非交互模式下必须提供项目名称', ExitCodes.USER_ERROR)\n }\n projectName = await input({\n message: '项目名称:',\n default: 'my-project',\n validate: (value) => {\n if (!value.trim()) {\n return '项目名称不能为空'\n }\n if (!isValidPackageName(toValidPackageName(value))) {\n return '无效的项目名称'\n }\n return true\n }\n })\n }\n\n const validName = toValidPackageName(projectName)\n const targetDir = path.resolve(process.cwd(), validName)\n\n // 检查目标目录\n if (fs.existsSync(targetDir) && !isEmpty(targetDir)) {\n if (!interactive) {\n // 非交互模式下,警告并覆盖\n console.log(pc.yellow(`警告: 目标目录 \"${validName}\" 非空,将覆盖已有文件`))\n } else {\n const overwrite = await confirm({\n message: `目标目录 \"${validName}\" 非空,是否继续? (将覆盖已有文件)`,\n default: false\n })\n if (!overwrite) {\n const error = new Error('PROMPT_CANCELLED')\n throw error\n }\n }\n }\n\n // 选择模板\n let template = options.template\n if (!template) {\n if (!interactive) {\n // 非交互模式下,使用配置默认值或 node-ts\n template = defaults.template || DEFAULT_TEMPLATE\n console.log(pc.dim(`使用默认模板: ${template}`))\n } else {\n // 配置文件中的默认模板\n const defaultTemplate = defaults.template\n\n // 分组模板\n const singleTemplates = registry.templates.filter(t => t.category !== 'fullstack')\n const fullstackTemplates = registry.templates.filter(t => t.category === 'fullstack')\n\n const templateChoices: Array<{ name: string; value: string } | Separator> = []\n\n // 单体项目组\n templateChoices.push(new Separator('── 单体项目 ──'))\n for (const t of singleTemplates) {\n templateChoices.push({\n name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,\n value: t.name\n })\n }\n\n // 前后端分离组\n if (fullstackTemplates.length > 0) {\n templateChoices.push(new Separator('── 前后端分离 ──'))\n for (const t of fullstackTemplates) {\n templateChoices.push({\n name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,\n value: t.name\n })\n }\n }\n\n template = await select({\n message: '选择模板:',\n choices: templateChoices,\n default: defaultTemplate && registry.templates.some((t) => t.name === defaultTemplate)\n ? defaultTemplate\n : undefined\n })\n }\n }\n\n // 验证模板是否存在\n const found = registry.templates.find((t) => t.name === template)\n if (!found) {\n console.log(pc.red(`错误: 未找到模板 \"${template}\"`))\n console.log(pc.dim(`可用模板: ${registry.templates.map((t) => t.name).join(', ')}`))\n throw new CliError(`未找到模板 \"${template}\"`, ExitCodes.USER_ERROR)\n }\n\n // Git 初始化\n let initGit = options.git !== false\n if (options.git === undefined && interactive) {\n initGit = await confirm({\n message: '初始化 Git 仓库?',\n default: true\n })\n }\n\n // GitHub 仓库创建\n let createGithub = options.github ?? false\n if (initGit && options.github === undefined && interactive) {\n createGithub = await confirm({\n message: '在 GitHub 创建远程仓库?',\n default: defaults.github ?? false\n })\n }\n\n // 仓库可见性\n let isPublic = options.public ?? false\n if (createGithub && options.public === undefined && interactive) {\n const publicDefault = defaults.public ?? false\n isPublic = await select({\n message: '仓库可见性:',\n choices: [\n { name: 'private (私有)', value: false },\n { name: 'public (公开)', value: true }\n ],\n default: publicDefault\n }) as boolean\n }\n\n const result: ProjectOptions = {\n projectName: validName,\n template,\n targetDir,\n initGit,\n createGithub,\n isPublic,\n noInstall: options.install === false\n }\n\n debug('prompts', '最终项目选项', result)\n\n return result\n}\n","import path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { spawn } from 'node:child_process'\nimport { debug } from './debug.js'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nexport function getTemplatesDir(): string {\n return path.resolve(__dirname, '..', 'templates')\n}\n\nexport function isValidPackageName(name: string): boolean {\n return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name)\n}\n\nexport function toValidPackageName(name: string): string {\n return name\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/^[._]/, '')\n .replace(/[^a-z0-9-~]+/g, '-')\n}\n\nexport function isEmpty(dirPath: string): boolean {\n const fs = require('node:fs')\n if (!fs.existsSync(dirPath)) {\n return true\n }\n const files = fs.readdirSync(dirPath)\n return files.length === 0 || (files.length === 1 && files[0] === '.git')\n}\n\nexport function execAsync(\n command: string,\n args: string[],\n options: { cwd?: string; stdio?: 'inherit' | 'pipe' } = {}\n): Promise<{ code: number; stdout: string; stderr: string }> {\n debug('exec', `执行命令: ${command} ${args.join(' ')}`, { cwd: options.cwd })\n\n return new Promise((resolve) => {\n const proc = spawn(command, args, {\n cwd: options.cwd,\n stdio: options.stdio === 'inherit' ? 'inherit' : 'pipe',\n shell: true\n })\n\n let stdout = ''\n let stderr = ''\n\n if (proc.stdout) {\n proc.stdout.on('data', (data) => {\n stdout += data.toString()\n })\n }\n\n if (proc.stderr) {\n proc.stderr.on('data', (data) => {\n stderr += data.toString()\n })\n }\n\n proc.on('close', (code) => {\n debug('exec', `命令完成,退出码: ${code ?? 1}`)\n resolve({ code: code ?? 1, stdout, stderr })\n })\n\n proc.on('error', (err) => {\n debug('exec', `命令错误: ${err.message}`)\n resolve({ code: 1, stdout, stderr })\n })\n })\n}\n\nexport async function commandExists(command: string): Promise<boolean> {\n const result = await execAsync('which', [command])\n return result.code === 0\n}\n","/**\n * 调试输出模块\n *\n * 用于在 --debug 模式下输出详细的调试信息到 stderr\n */\n\nlet debugEnabled = false\n\n/**\n * 设置调试模式是否启用\n */\nexport function setDebugEnabled(enabled: boolean): void {\n debugEnabled = enabled\n}\n\n/**\n * 检查调试模式是否启用\n */\nexport function isDebugEnabled(): boolean {\n return debugEnabled\n}\n\n/**\n * 输出调试信息到 stderr\n *\n * @param category 日志分类,如 'github-api', 'scaffold', 'git'\n * @param message 日志消息\n * @param data 可选的附加数据\n */\nexport function debug(category: string, message: string, data?: unknown): void {\n if (!debugEnabled) return\n\n const timestamp = new Date().toISOString()\n const prefix = `[DEBUG ${timestamp}] [${category}]`\n\n if (data !== undefined) {\n // 限制数据长度,避免输出过长\n const dataStr = formatData(data)\n console.error(`${prefix} ${message}`, dataStr)\n } else {\n console.error(`${prefix} ${message}`)\n }\n}\n\n/**\n * 格式化数据输出,限制长度\n */\nfunction formatData(data: unknown): string {\n try {\n const str = JSON.stringify(data, null, 2)\n // 限制每个值不超过 255 字符\n if (str.length > 500) {\n return str.slice(0, 500) + '...(truncated)'\n }\n return str\n } catch {\n return String(data)\n }\n}\n","/**\n * 标准化退出码定义\n *\n * 用于确保 CLI 工具在不同场景下返回一致的退出码\n */\nexport const ExitCodes = {\n /** 成功完成 */\n SUCCESS: 0,\n /** 用户错误:参数错误、输入无效 */\n USER_ERROR: 1,\n /** 外部错误:网络、GitHub API、包管理器 */\n EXTERNAL_ERROR: 2,\n /** 未知内部错误 */\n INTERNAL_ERROR: 10,\n /** 模板相关错误 */\n TEMPLATE_ERROR: 11,\n /** 文件系统错误 */\n FILE_SYSTEM_ERROR: 12,\n /** Git 操作错误 */\n GIT_ERROR: 13,\n} as const\n\nexport type ExitCode = (typeof ExitCodes)[keyof typeof ExitCodes]\n\n/**\n * 带退出码的错误类\n */\nexport class CliError extends Error {\n constructor(\n message: string,\n public readonly exitCode: ExitCode = ExitCodes.INTERNAL_ERROR\n ) {\n super(message)\n this.name = 'CliError'\n }\n}\n","import path from 'node:path'\nimport fs from 'fs-extra'\nimport { getTemplatesDir } from './utils.js'\nimport { debug } from './debug.js'\nimport type { ProjectOptions, TemplateConfig, TemplateRegistry } from './types.js'\n\nexport async function scaffoldProject(\n options: ProjectOptions\n): Promise<TemplateConfig | null> {\n const templatesDir = getTemplatesDir()\n const registryPath = path.join(templatesDir, 'template.config.json')\n const registry: TemplateRegistry = await fs.readJson(registryPath)\n\n debug('scaffold', `开始脚手架项目: ${options.projectName}`)\n debug('scaffold', `模板: ${options.template}`)\n debug('scaffold', `目标目录: ${options.targetDir}`)\n\n const templateEntry = registry.templates.find((t) => t.name === options.template)\n if (!templateEntry) {\n throw new Error(`未找到模板: ${options.template}`)\n }\n\n const templateDir = path.join(templatesDir, templateEntry.dir)\n const templateConfigPath = path.join(templateDir, '_template.json')\n\n debug('scaffold', `模板目录: ${templateDir}`)\n\n let templateConfig: TemplateConfig | null = null\n if (await fs.pathExists(templateConfigPath)) {\n templateConfig = await fs.readJson(templateConfigPath)\n debug('scaffold', '模板配置', templateConfig)\n }\n\n await fs.ensureDir(options.targetDir)\n\n const files = await fs.readdir(templateDir)\n debug('scaffold', `模板文件数量: ${files.length}`)\n\n for (const file of files) {\n if (file === '_template.json') {\n continue\n }\n\n const srcPath = path.join(templateDir, file)\n let destFileName = file\n\n if (templateConfig?.fileRenames?.[file]) {\n destFileName = templateConfig.fileRenames[file]\n if (destFileName === '{{projectName}}') {\n destFileName = options.projectName\n }\n }\n\n const destPath = path.join(options.targetDir, destFileName)\n const stat = await fs.stat(srcPath)\n\n debug('scaffold', `复制: ${file} -> ${destFileName}`)\n\n if (stat.isDirectory()) {\n await copyDirectory(srcPath, destPath, options.projectName, templateConfig)\n } else {\n await copyFile(srcPath, destPath, options.projectName, templateConfig)\n }\n }\n\n debug('scaffold', '脚手架完成')\n\n return templateConfig\n}\n\nasync function copyDirectory(\n srcDir: string,\n destDir: string,\n projectName: string,\n config: TemplateConfig | null\n): Promise<void> {\n await fs.ensureDir(destDir)\n const files = await fs.readdir(srcDir)\n\n for (const file of files) {\n const srcPath = path.join(srcDir, file)\n let destFileName = file\n\n if (config?.fileRenames?.[file]) {\n destFileName = config.fileRenames[file]\n if (destFileName === '{{projectName}}') {\n destFileName = projectName\n }\n }\n\n const destPath = path.join(destDir, destFileName)\n const stat = await fs.stat(srcPath)\n\n if (stat.isDirectory()) {\n await copyDirectory(srcPath, destPath, projectName, config)\n } else {\n await copyFile(srcPath, destPath, projectName, config)\n }\n }\n}\n\nasync function copyFile(\n srcPath: string,\n destPath: string,\n projectName: string,\n config: TemplateConfig | null\n): Promise<void> {\n const binaryExtensions = [\n '.png', '.jpg', '.jpeg', '.gif', '.ico', '.webp',\n '.woff', '.woff2', '.ttf', '.eot',\n '.zip', '.tar', '.gz'\n ]\n\n const ext = path.extname(srcPath).toLowerCase()\n\n if (binaryExtensions.includes(ext)) {\n await fs.copy(srcPath, destPath)\n return\n }\n\n let content = await fs.readFile(srcPath, 'utf-8')\n\n content = content.replace(/\\{\\{projectName\\}\\}/g, projectName)\n\n if (config?.variables) {\n for (const [key, value] of Object.entries(config.variables)) {\n const placeholder = `{{${key}}}`\n const replacement = value === '{{projectName}}' ? projectName : value\n content = content.replace(new RegExp(placeholder.replace(/[{}]/g, '\\\\$&'), 'g'), replacement)\n }\n }\n\n await fs.writeFile(destPath, content, 'utf-8')\n}\n","import pc from 'picocolors'\nimport { execAsync } from './utils.js'\nimport { loadConfig, getConfigPath } from './config.js'\nimport { validateToken, createRepository } from './github-api.js'\nimport { debug } from './debug.js'\n\nexport async function initGit(targetDir: string): Promise<void> {\n debug('git', `初始化 Git 仓库: ${targetDir}`)\n await execAsync('git', ['init'], { cwd: targetDir })\n await execAsync('git', ['add', '-A'], { cwd: targetDir })\n await execAsync('git', ['commit', '-m', 'Initial commit'], { cwd: targetDir })\n debug('git', 'Git 初始化完成')\n}\n\nexport interface CreateGithubRepoResult {\n success: boolean\n repoUrl?: string\n error?: string\n}\n\nexport async function createGithubRepo(\n repoName: string,\n targetDir: string,\n isPublic: boolean\n): Promise<string | null> {\n debug('git', `创建 GitHub 仓库: ${repoName}, 公开: ${isPublic}`)\n const config = loadConfig()\n\n // 检查 Token 是否配置\n if (!config.github?.token) {\n console.log(pc.yellow('⚠ 未配置 GitHub Token,跳过仓库创建'))\n console.log(pc.dim(` 运行 ${pc.cyan('spec-go config --setup-github')} 配置 Token`))\n console.log(pc.dim(` 配置文件路径: ${getConfigPath()}`))\n return null\n }\n\n const token = config.github.token\n const defaultOrg = config.github.defaultOrg\n\n // 验证 Token\n const validateResult = await validateToken(token)\n if (!validateResult.success) {\n console.log(pc.yellow(`⚠ GitHub Token 无效: ${validateResult.error}`))\n if (validateResult.rateLimitReset) {\n console.log(pc.dim(` Rate limit 将在 ${validateResult.rateLimitReset.toLocaleString()} 重置`))\n }\n console.log(pc.dim(` 运行 ${pc.cyan('spec-go config --setup-github')} 重新配置`))\n return null\n }\n\n const username = validateResult.data.login\n\n // 创建仓库\n const createResult = await createRepository(token, {\n name: repoName,\n isPrivate: !isPublic,\n org: defaultOrg\n })\n\n if (!createResult.success) {\n if (createResult.statusCode === 422) {\n console.log(pc.yellow(`⚠ 仓库 \"${repoName}\" 已存在,请选择其他名称`))\n } else if (createResult.rateLimitReset) {\n console.log(pc.yellow(`⚠ API 请求次数已达上限`))\n console.log(pc.dim(` 将在 ${createResult.rateLimitReset.toLocaleString()} 重置`))\n } else {\n console.log(pc.yellow(`⚠ 创建仓库失败: ${createResult.error}`))\n }\n return null\n }\n\n const repo = createResult.data\n\n // 添加远程仓库并推送\n const remoteResult = await execAsync(\n 'git',\n ['remote', 'add', 'origin', repo.clone_url],\n { cwd: targetDir }\n )\n\n if (remoteResult.code !== 0) {\n // remote 可能已存在,尝试更新\n await execAsync(\n 'git',\n ['remote', 'set-url', 'origin', repo.clone_url],\n { cwd: targetDir }\n )\n }\n\n // 推送到远程\n const pushResult = await execAsync(\n 'git',\n ['push', '-u', 'origin', 'main'],\n { cwd: targetDir }\n )\n\n if (pushResult.code !== 0) {\n // 尝试推送 master 分支\n const pushMaster = await execAsync(\n 'git',\n ['push', '-u', 'origin', 'master'],\n { cwd: targetDir }\n )\n if (pushMaster.code !== 0) {\n console.log(pc.yellow(`⚠ 推送失败: ${pushResult.stderr || pushMaster.stderr}`))\n console.log(pc.dim(` 仓库已创建: ${repo.html_url}`))\n console.log(pc.dim(' 请手动推送代码'))\n return repo.html_url\n }\n }\n\n return repo.html_url\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport type { UserConfig } from './types.js'\n\nconst CONFIG_PATH = path.join(os.homedir(), '.spec-go.json')\n\nconst DEFAULT_CONFIG: UserConfig = {\n defaults: {\n github: false,\n public: false,\n template: ''\n },\n github: {\n token: '',\n defaultOrg: ''\n }\n}\n\n/**\n * 确保配置文件存在,如果不存在则创建默认配置\n */\nexport function ensureConfigExists(): void {\n if (!fs.existsSync(CONFIG_PATH)) {\n saveConfig(DEFAULT_CONFIG)\n }\n}\n\nexport function loadConfig(): UserConfig {\n try {\n if (fs.existsSync(CONFIG_PATH)) {\n const content = fs.readFileSync(CONFIG_PATH, 'utf-8')\n return JSON.parse(content) as UserConfig\n }\n } catch {\n // 配置文件损坏或读取失败,返回空配置\n }\n return {}\n}\n\nexport function saveConfig(config: UserConfig): void {\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8')\n // 设置文件权限为 600 (仅所有者可读写),保护 Token 安全\n fs.chmodSync(CONFIG_PATH, 0o600)\n}\n\nexport function getConfigPath(): string {\n return CONFIG_PATH\n}\n","import { debug } from './debug.js'\nimport type { GitHubUser, GitHubRepoResponse, GitHubApiError } from './types.js'\n\nconst GITHUB_API_BASE = 'https://api.github.com'\n\ninterface GitHubApiResult<T> {\n success: true\n data: T\n}\n\ninterface GitHubApiFailure {\n success: false\n error: string\n statusCode?: number\n rateLimitReset?: Date\n}\n\ntype GitHubApiResponse<T> = GitHubApiResult<T> | GitHubApiFailure\n\nasync function githubFetch<T>(\n endpoint: string,\n token: string,\n options: RequestInit = {}\n): Promise<GitHubApiResponse<T>> {\n const url = `${GITHUB_API_BASE}${endpoint}`\n\n debug('github-api', `请求: ${options.method || 'GET'} ${endpoint}`)\n\n try {\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Accept': 'application/vnd.github+json',\n 'Authorization': `Bearer ${token.slice(0, 8)}...`,\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': 'spec-go',\n ...options.headers,\n },\n })\n\n debug('github-api', `响应状态: ${response.status}`)\n\n // 处理 Rate Limit\n if (response.status === 403) {\n const rateLimitRemaining = response.headers.get('x-ratelimit-remaining')\n const rateLimitReset = response.headers.get('x-ratelimit-reset')\n\n debug('github-api', `Rate Limit 信息`, { rateLimitRemaining, rateLimitReset })\n\n if (rateLimitRemaining === '0' && rateLimitReset) {\n const resetDate = new Date(parseInt(rateLimitReset) * 1000)\n return {\n success: false,\n error: 'API 请求次数已达上限',\n statusCode: 403,\n rateLimitReset: resetDate,\n }\n }\n }\n\n // 处理未授权\n if (response.status === 401) {\n debug('github-api', 'Token 验证失败')\n return {\n success: false,\n error: 'Token 无效或已过期',\n statusCode: 401,\n }\n }\n\n // 处理其他错误\n if (!response.ok) {\n const errorData = await response.json() as GitHubApiError\n debug('github-api', '请求失败', errorData)\n return {\n success: false,\n error: errorData.message || `请求失败: ${response.status}`,\n statusCode: response.status,\n }\n }\n\n const data = await response.json() as T\n debug('github-api', '请求成功')\n return { success: true, data }\n } catch (err) {\n debug('github-api', '网络请求异常', { error: err instanceof Error ? err.message : String(err) })\n return {\n success: false,\n error: err instanceof Error ? err.message : '网络请求失败',\n }\n }\n}\n\n/**\n * 验证 Token 并获取用户信息\n */\nexport async function validateToken(token: string): Promise<GitHubApiResponse<GitHubUser>> {\n return githubFetch<GitHubUser>('/user', token)\n}\n\nexport interface CreateRepoOptions {\n name: string\n description?: string\n isPrivate: boolean\n org?: string\n}\n\n/**\n * 创建 GitHub 仓库\n */\nexport async function createRepository(\n token: string,\n options: CreateRepoOptions\n): Promise<GitHubApiResponse<GitHubRepoResponse>> {\n const endpoint = options.org\n ? `/orgs/${options.org}/repos`\n : '/user/repos'\n\n const body = {\n name: options.name,\n description: options.description || `Created with spec-go`,\n private: options.isPrivate,\n auto_init: false,\n }\n\n return githubFetch<GitHubRepoResponse>(endpoint, token, {\n method: 'POST',\n body: JSON.stringify(body),\n })\n}\n\n/**\n * 检查仓库是否存在\n */\nexport async function checkRepoExists(\n token: string,\n owner: string,\n repo: string\n): Promise<boolean> {\n const result = await githubFetch<GitHubRepoResponse>(\n `/repos/${owner}/${repo}`,\n token\n )\n return result.success\n}\n","import path from 'node:path'\nimport pc from 'picocolors'\nimport { execAsync } from './utils.js'\nimport type { PostInitCommand, TemplateConfig } from './types.js'\n\nexport async function runPostInit(\n targetDir: string,\n commands: PostInitCommand[]\n): Promise<void> {\n for (const cmd of commands) {\n console.log(pc.dim(` ${cmd.description}...`))\n const [command, ...args] = cmd.command.split(' ')\n const result = await execAsync(command, args, {\n cwd: targetDir,\n stdio: 'pipe'\n })\n\n if (result.code !== 0) {\n console.log(pc.yellow(`⚠ ${cmd.description} 失败`))\n if (result.stderr) {\n console.log(pc.dim(result.stderr.slice(0, 200)))\n }\n }\n }\n}\n\nexport async function runWorkspacePostInit(\n targetDir: string,\n config: TemplateConfig\n): Promise<void> {\n // 先执行根目录的 postInit 命令(如果有)\n if (config.postInit && config.postInit.length > 0) {\n await runPostInit(targetDir, config.postInit)\n }\n\n // 再执行各子目录的 postInit 命令\n if (config.workspaces) {\n for (const ws of config.workspaces) {\n if (ws.postInit && ws.postInit.length > 0) {\n const wsDir = path.join(targetDir, ws.name)\n console.log(pc.dim(` [${ws.name}]`))\n await runPostInit(wsDir, ws.postInit)\n }\n }\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { execSync } from 'node:child_process'\nimport pc from 'picocolors'\nimport { ExitCodes } from './exit-codes.js'\n\nconst CACHE_PATH = path.join(os.homedir(), '.spec-go-update-check')\nconst CACHE_TTL = 24 * 60 * 60 * 1000 // 24 小时\nconst PACKAGE_NAME = '@lambertkeith/spec-go'\n\ninterface UpdateCache {\n lastCheck: number\n latestVersion: string\n}\n\nfunction readCache(): UpdateCache | null {\n try {\n if (fs.existsSync(CACHE_PATH)) {\n const content = fs.readFileSync(CACHE_PATH, 'utf-8')\n return JSON.parse(content) as UpdateCache\n }\n } catch {\n // 忽略缓存读取错误\n }\n return null\n}\n\nfunction writeCache(cache: UpdateCache): void {\n try {\n fs.writeFileSync(CACHE_PATH, JSON.stringify(cache), 'utf-8')\n } catch {\n // 忽略缓存写入错误\n }\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const response = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`)\n if (!response.ok) {\n return null\n }\n const data = (await response.json()) as { version: string }\n return data.version\n } catch {\n // 网络请求失败,静默处理\n return null\n }\n}\n\nfunction compareVersions(current: string, latest: string): number {\n const currentParts = current.split('.').map(Number)\n const latestParts = latest.split('.').map(Number)\n\n for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {\n const c = currentParts[i] || 0\n const l = latestParts[i] || 0\n if (c < l) return -1\n if (c > l) return 1\n }\n return 0\n}\n\nexport async function checkForUpdates(currentVersion: string): Promise<void> {\n const cache = readCache()\n const now = Date.now()\n\n let latestVersion: string | null = null\n\n // 检查缓存是否有效\n if (cache && now - cache.lastCheck < CACHE_TTL) {\n latestVersion = cache.latestVersion\n } else {\n // 缓存过期,重新获取\n latestVersion = await fetchLatestVersion()\n if (latestVersion) {\n writeCache({ lastCheck: now, latestVersion })\n }\n }\n\n // 比较版本并提示\n if (latestVersion && compareVersions(currentVersion, latestVersion) < 0) {\n console.log()\n console.log(\n pc.yellow(` \\u26A0 发现新版本 ${pc.bold(latestVersion)},当前 ${currentVersion}`)\n )\n console.log(pc.cyan(` 运行 ${pc.bold(`npm update -g ${PACKAGE_NAME}`)} 更新`))\n console.log()\n }\n}\n\ntype PackageManager = 'npm' | 'pnpm' | 'yarn'\n\nfunction detectPackageManager(): PackageManager {\n // 检查 spec-go 是通过哪个包管理器安装的\n // 方法:检查全局安装路径中是否包含 pnpm/yarn 特征\n const execPath = process.argv[1] || ''\n\n if (execPath.includes('pnpm')) return 'pnpm'\n if (execPath.includes('yarn')) return 'yarn'\n return 'npm'\n}\n\nfunction getUpdateCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return `pnpm update -g ${PACKAGE_NAME}`\n case 'yarn':\n return `yarn global upgrade ${PACKAGE_NAME}`\n default:\n return `npm update -g ${PACKAGE_NAME}`\n }\n}\n\nexport async function runUpdate(currentVersion: string, checkOnly: boolean): Promise<void> {\n // 1. 强制获取最新版本(跳过缓存)\n const latestVersion = await fetchLatestVersion()\n\n if (!latestVersion) {\n console.log(pc.red('✗ 无法获取最新版本信息'))\n process.exit(ExitCodes.EXTERNAL_ERROR)\n }\n\n // 2. 版本比较\n const comparison = compareVersions(currentVersion, latestVersion)\n\n if (comparison >= 0) {\n console.log(pc.green(`✔ 已是最新版本 (${currentVersion})`))\n return\n }\n\n console.log(pc.cyan(`发现新版本: ${currentVersion} → ${latestVersion}`))\n\n if (checkOnly) {\n console.log(pc.dim(`运行 spec-go update 更新`))\n return\n }\n\n // 3. 检测包管理器并执行更新\n const pm = detectPackageManager()\n const updateCmd = getUpdateCommand(pm)\n\n console.log(pc.dim(`正在执行: ${updateCmd}`))\n\n // 4. 执行更新命令\n try {\n execSync(updateCmd, { stdio: 'inherit' })\n console.log(pc.green(`✔ 更新完成`))\n } catch {\n console.log(pc.red('✗ 更新失败,请手动执行更新命令'))\n process.exit(ExitCodes.EXTERNAL_ERROR)\n }\n}\n","import { input, confirm } from '@inquirer/prompts'\nimport pc from 'picocolors'\nimport { loadConfig, saveConfig } from './config.js'\nimport { validateToken } from './github-api.js'\n\nconst TOKEN_HELP_URL = 'https://github.com/settings/tokens/new?scopes=repo&description=spec-go'\n\n/**\n * 检查是否为用户中断操作(Ctrl+C)\n */\nfunction isUserCancelled(err: unknown): boolean {\n const error = err as Error\n return (\n error.message === 'PROMPT_CANCELLED' ||\n error.name === 'ExitPromptError' ||\n error.message.includes('User force closed')\n )\n}\n\n/**\n * 运行 GitHub Token 配置引导\n */\nexport async function runGitHubSetup(): Promise<boolean> {\n console.log()\n console.log(pc.cyan('配置 GitHub Token'))\n console.log()\n console.log('需要一个具有 repo 权限的 Personal Access Token (Classic) 来创建仓库。')\n console.log()\n console.log(pc.dim('获取步骤:'))\n console.log(pc.dim('1. 访问 GitHub Settings > Developer settings > Personal access tokens'))\n console.log(pc.dim('2. 点击 \"Generate new token (classic)\"'))\n console.log(pc.dim('3. 勾选 \"repo\" 权限'))\n console.log(pc.dim('4. 生成并复制 Token'))\n console.log()\n console.log(pc.dim(`快捷链接: ${TOKEN_HELP_URL}`))\n console.log()\n\n try {\n const token = await input({\n message: '请输入 GitHub Token:',\n validate: (value) => {\n if (!value.trim()) {\n return 'Token 不能为空'\n }\n if (!value.startsWith('ghp_') && !value.startsWith('github_pat_')) {\n return 'Token 格式不正确,应以 ghp_ 或 github_pat_ 开头'\n }\n return true\n }\n })\n\n console.log()\n console.log(pc.dim('正在验证 Token...'))\n\n const result = await validateToken(token.trim())\n\n if (!result.success) {\n console.log(pc.red(`✗ Token 验证失败: ${result.error}`))\n if (result.rateLimitReset) {\n console.log(pc.dim(` Rate limit 将在 ${result.rateLimitReset.toLocaleString()} 重置`))\n }\n return false\n }\n\n const user = result.data\n console.log(pc.green(`✔ Token 有效,已登录为: ${user.login}${user.name ? ` (${user.name})` : ''}`))\n console.log()\n\n // 询问是否设置默认组织\n const setOrg = await confirm({\n message: '是否设置默认组织? (否则仓库将创建在个人账户下)',\n default: false\n })\n\n let defaultOrg: string | undefined\n if (setOrg) {\n defaultOrg = await input({\n message: '默认组织名称:',\n validate: (value) => {\n if (!value.trim()) {\n return '组织名称不能为空'\n }\n return true\n }\n })\n defaultOrg = defaultOrg.trim()\n }\n\n // 保存配置\n const config = loadConfig()\n config.github = {\n token: token.trim(),\n ...(defaultOrg && { defaultOrg })\n }\n saveConfig(config)\n\n console.log()\n console.log(pc.green('✔ GitHub 配置已保存'))\n console.log(pc.dim(' 配置文件已设置为仅当前用户可读'))\n\n return true\n } catch (err) {\n if (isUserCancelled(err)) {\n console.log(pc.yellow('\\n操作已取消'))\n return false\n }\n throw err\n }\n}\n\n/**\n * 显示当前配置\n */\nexport function showConfig(): void {\n const config = loadConfig()\n\n console.log()\n console.log(pc.cyan('当前配置:'))\n console.log()\n\n if (config.defaults) {\n console.log(pc.dim('defaults:'))\n if (config.defaults.github !== undefined) {\n console.log(` github: ${config.defaults.github}`)\n }\n if (config.defaults.public !== undefined) {\n console.log(` public: ${config.defaults.public}`)\n }\n if (config.defaults.template !== undefined) {\n console.log(` template: ${config.defaults.template}`)\n }\n }\n\n if (config.github) {\n console.log(pc.dim('github:'))\n if (config.github.token) {\n const masked = config.github.token.slice(0, 8) + '...' + config.github.token.slice(-4)\n console.log(` token: ${masked}`)\n }\n if (config.github.defaultOrg) {\n console.log(` defaultOrg: ${config.github.defaultOrg}`)\n }\n }\n\n if (!config.defaults && !config.github) {\n console.log(pc.dim('(无配置)'))\n }\n\n console.log()\n}\n","import { createCli } from './cli.js'\nimport { ensureConfigExists } from './config.js'\nimport { ExitCodes, CliError } from './exit-codes.js'\nimport { isDebugEnabled } from './debug.js'\n\nasync function main(): Promise<void> {\n // 确保配置文件存在\n ensureConfigExists()\n\n const program = await createCli()\n await program.parseAsync(process.argv)\n}\n\nmain().catch((err) => {\n // CliError 已经在 prompts.ts 等地方输出了用户友好的错误信息\n // 只在调试模式下输出完整堆栈\n if (err instanceof CliError) {\n if (isDebugEnabled()) {\n console.error(err)\n }\n process.exit(err.exitCode)\n }\n // 其他未知错误始终输出\n console.error(err)\n process.exit(ExitCodes.INTERNAL_ERROR)\n})\n"],"mappings":"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","names":["path","fs","pc","path","fs","path","initGit","path","fs","path","fs","pc","fs","path","pc","path","pc","pc","path","fs","path","os","pc","path","os","fs","pc","input","confirm","pc","pc","input","confirm","pc","path","fs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambertkeith/spec-go",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "CLI 脚手架工具,快速创建项目并可选初始化 GitHub 仓库",
5
5
  "type": "module",
6
6
  "bin": {