create-idp 0.1.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +205 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +702 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +46 -0
  7. package/templates/empty/README.md +3 -0
  8. package/templates/empty/_gitignore +6 -0
  9. package/templates/empty/_template.json +6 -0
  10. package/templates/node-ts/README.md +21 -0
  11. package/templates/node-ts/_gitignore +7 -0
  12. package/templates/node-ts/_template.json +16 -0
  13. package/templates/node-ts/package.json +19 -0
  14. package/templates/node-ts/src/index.ts +1 -0
  15. package/templates/node-ts/tsconfig.json +17 -0
  16. package/templates/node-ts/tsup.config.ts +9 -0
  17. package/templates/python-uv/README.md +22 -0
  18. package/templates/python-uv/_gitignore +30 -0
  19. package/templates/python-uv/_template.json +14 -0
  20. package/templates/python-uv/pyproject.toml +20 -0
  21. package/templates/python-uv/src/project_name/__init__.py +10 -0
  22. package/templates/python-uv/src/project_name/__main__.py +4 -0
  23. package/templates/react-ts/_gitignore +6 -0
  24. package/templates/react-ts/_template.json +13 -0
  25. package/templates/react-ts/index.html +13 -0
  26. package/templates/react-ts/package.json +23 -0
  27. package/templates/react-ts/src/App.css +14 -0
  28. package/templates/react-ts/src/App.tsx +12 -0
  29. package/templates/react-ts/src/index.css +11 -0
  30. package/templates/react-ts/src/main.tsx +10 -0
  31. package/templates/react-ts/tsconfig.json +20 -0
  32. package/templates/react-ts/vite.config.ts +6 -0
  33. package/templates/template.config.json +34 -0
  34. package/templates/vue-ts/_gitignore +6 -0
  35. package/templates/vue-ts/_template.json +13 -0
  36. package/templates/vue-ts/index.html +13 -0
  37. package/templates/vue-ts/package.json +20 -0
  38. package/templates/vue-ts/src/App.vue +37 -0
  39. package/templates/vue-ts/src/main.ts +5 -0
  40. package/templates/vue-ts/src/style.css +11 -0
  41. package/templates/vue-ts/src/vite-env.d.ts +7 -0
  42. package/templates/vue-ts/tsconfig.json +20 -0
  43. package/templates/vue-ts/vite.config.ts +6 -0
package/dist/index.js ADDED
@@ -0,0 +1,702 @@
1
+ #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ // src/cli.ts
10
+ import { Command } from "commander";
11
+ import pc6 from "picocolors";
12
+
13
+ // package.json
14
+ var version = "0.1.0";
15
+
16
+ // src/prompts.ts
17
+ import path2 from "path";
18
+ import fs from "fs";
19
+ import { input, select, confirm } from "@inquirer/prompts";
20
+ import pc from "picocolors";
21
+
22
+ // src/utils.ts
23
+ import path from "path";
24
+ import { fileURLToPath } from "url";
25
+ import { spawn } from "child_process";
26
+ var __filename = fileURLToPath(import.meta.url);
27
+ var __dirname = path.dirname(__filename);
28
+ function getTemplatesDir() {
29
+ return path.resolve(__dirname, "..", "templates");
30
+ }
31
+ function isValidPackageName(name) {
32
+ return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name);
33
+ }
34
+ function toValidPackageName(name) {
35
+ return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9-~]+/g, "-");
36
+ }
37
+ function isEmpty(dirPath) {
38
+ const fs5 = __require("fs");
39
+ if (!fs5.existsSync(dirPath)) {
40
+ return true;
41
+ }
42
+ const files = fs5.readdirSync(dirPath);
43
+ return files.length === 0 || files.length === 1 && files[0] === ".git";
44
+ }
45
+ function execAsync(command, args, options = {}) {
46
+ return new Promise((resolve) => {
47
+ const proc = spawn(command, args, {
48
+ cwd: options.cwd,
49
+ stdio: options.stdio === "inherit" ? "inherit" : "pipe",
50
+ shell: true
51
+ });
52
+ let stdout = "";
53
+ let stderr = "";
54
+ if (proc.stdout) {
55
+ proc.stdout.on("data", (data) => {
56
+ stdout += data.toString();
57
+ });
58
+ }
59
+ if (proc.stderr) {
60
+ proc.stderr.on("data", (data) => {
61
+ stderr += data.toString();
62
+ });
63
+ }
64
+ proc.on("close", (code) => {
65
+ resolve({ code: code ?? 1, stdout, stderr });
66
+ });
67
+ proc.on("error", () => {
68
+ resolve({ code: 1, stdout, stderr });
69
+ });
70
+ });
71
+ }
72
+
73
+ // src/prompts.ts
74
+ async function runPrompts(argProjectName, options, userConfig = {}) {
75
+ const defaults = userConfig.defaults ?? {};
76
+ const templatesDir = getTemplatesDir();
77
+ const registryPath = path2.join(templatesDir, "template.config.json");
78
+ const registry = JSON.parse(
79
+ fs.readFileSync(registryPath, "utf-8")
80
+ );
81
+ let projectName = argProjectName;
82
+ if (!projectName) {
83
+ projectName = await input({
84
+ message: "\u9879\u76EE\u540D\u79F0:",
85
+ default: "my-project",
86
+ validate: (value) => {
87
+ if (!value.trim()) {
88
+ return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
89
+ }
90
+ if (!isValidPackageName(toValidPackageName(value))) {
91
+ return "\u65E0\u6548\u7684\u9879\u76EE\u540D\u79F0";
92
+ }
93
+ return true;
94
+ }
95
+ });
96
+ }
97
+ const validName = toValidPackageName(projectName);
98
+ const targetDir = path2.resolve(process.cwd(), validName);
99
+ if (fs.existsSync(targetDir) && !isEmpty(targetDir)) {
100
+ const overwrite = await confirm({
101
+ message: `\u76EE\u6807\u76EE\u5F55 "${validName}" \u975E\u7A7A\uFF0C\u662F\u5426\u7EE7\u7EED? (\u5C06\u8986\u76D6\u5DF2\u6709\u6587\u4EF6)`,
102
+ default: false
103
+ });
104
+ if (!overwrite) {
105
+ const error = new Error("PROMPT_CANCELLED");
106
+ throw error;
107
+ }
108
+ }
109
+ let template = options.template;
110
+ if (!template) {
111
+ const defaultTemplate = defaults.template;
112
+ const templateChoices = registry.templates.map((t) => ({
113
+ name: `${t.displayName} ${pc.dim(`- ${t.description}`)}`,
114
+ value: t.name
115
+ }));
116
+ template = await select({
117
+ message: "\u9009\u62E9\u6A21\u677F:",
118
+ choices: templateChoices,
119
+ default: defaultTemplate && registry.templates.some((t) => t.name === defaultTemplate) ? defaultTemplate : void 0
120
+ });
121
+ } else {
122
+ const found = registry.templates.find((t) => t.name === template);
123
+ if (!found) {
124
+ console.log(pc.red(`\u9519\u8BEF: \u672A\u627E\u5230\u6A21\u677F "${template}"`));
125
+ console.log(pc.dim(`\u53EF\u7528\u6A21\u677F: ${registry.templates.map((t) => t.name).join(", ")}`));
126
+ process.exit(1);
127
+ }
128
+ }
129
+ let initGit2 = options.git !== false;
130
+ if (options.git === void 0) {
131
+ initGit2 = await confirm({
132
+ message: "\u521D\u59CB\u5316 Git \u4ED3\u5E93?",
133
+ default: true
134
+ });
135
+ }
136
+ let createGithub = options.github ?? false;
137
+ if (initGit2 && options.github === void 0) {
138
+ createGithub = await confirm({
139
+ message: "\u5728 GitHub \u521B\u5EFA\u8FDC\u7A0B\u4ED3\u5E93?",
140
+ default: defaults.github ?? false
141
+ });
142
+ }
143
+ let isPublic = options.public ?? false;
144
+ if (createGithub && options.public === void 0) {
145
+ const publicDefault = defaults.public ?? false;
146
+ isPublic = await select({
147
+ message: "\u4ED3\u5E93\u53EF\u89C1\u6027:",
148
+ choices: [
149
+ { name: "private (\u79C1\u6709)", value: false },
150
+ { name: "public (\u516C\u5F00)", value: true }
151
+ ],
152
+ default: publicDefault
153
+ });
154
+ }
155
+ return {
156
+ projectName: validName,
157
+ template,
158
+ targetDir,
159
+ initGit: initGit2,
160
+ createGithub,
161
+ isPublic,
162
+ noInstall: options.install === false
163
+ };
164
+ }
165
+
166
+ // src/scaffold.ts
167
+ import path3 from "path";
168
+ import fs2 from "fs-extra";
169
+ async function scaffoldProject(options) {
170
+ const templatesDir = getTemplatesDir();
171
+ const registryPath = path3.join(templatesDir, "template.config.json");
172
+ const registry = await fs2.readJson(registryPath);
173
+ const templateEntry = registry.templates.find((t) => t.name === options.template);
174
+ if (!templateEntry) {
175
+ throw new Error(`\u672A\u627E\u5230\u6A21\u677F: ${options.template}`);
176
+ }
177
+ const templateDir = path3.join(templatesDir, templateEntry.dir);
178
+ const templateConfigPath = path3.join(templateDir, "_template.json");
179
+ let templateConfig = null;
180
+ if (await fs2.pathExists(templateConfigPath)) {
181
+ templateConfig = await fs2.readJson(templateConfigPath);
182
+ }
183
+ await fs2.ensureDir(options.targetDir);
184
+ const files = await fs2.readdir(templateDir);
185
+ for (const file of files) {
186
+ if (file === "_template.json") {
187
+ continue;
188
+ }
189
+ const srcPath = path3.join(templateDir, file);
190
+ let destFileName = file;
191
+ if (templateConfig?.fileRenames?.[file]) {
192
+ destFileName = templateConfig.fileRenames[file];
193
+ if (destFileName === "{{projectName}}") {
194
+ destFileName = options.projectName;
195
+ }
196
+ }
197
+ const destPath = path3.join(options.targetDir, destFileName);
198
+ const stat = await fs2.stat(srcPath);
199
+ if (stat.isDirectory()) {
200
+ await copyDirectory(srcPath, destPath, options.projectName, templateConfig);
201
+ } else {
202
+ await copyFile(srcPath, destPath, options.projectName, templateConfig);
203
+ }
204
+ }
205
+ return templateConfig;
206
+ }
207
+ async function copyDirectory(srcDir, destDir, projectName, config) {
208
+ await fs2.ensureDir(destDir);
209
+ const files = await fs2.readdir(srcDir);
210
+ for (const file of files) {
211
+ const srcPath = path3.join(srcDir, file);
212
+ let destFileName = file;
213
+ if (config?.fileRenames?.[file]) {
214
+ destFileName = config.fileRenames[file];
215
+ if (destFileName === "{{projectName}}") {
216
+ destFileName = projectName;
217
+ }
218
+ }
219
+ const destPath = path3.join(destDir, destFileName);
220
+ const stat = await fs2.stat(srcPath);
221
+ if (stat.isDirectory()) {
222
+ await copyDirectory(srcPath, destPath, projectName, config);
223
+ } else {
224
+ await copyFile(srcPath, destPath, projectName, config);
225
+ }
226
+ }
227
+ }
228
+ async function copyFile(srcPath, destPath, projectName, config) {
229
+ const binaryExtensions = [
230
+ ".png",
231
+ ".jpg",
232
+ ".jpeg",
233
+ ".gif",
234
+ ".ico",
235
+ ".webp",
236
+ ".woff",
237
+ ".woff2",
238
+ ".ttf",
239
+ ".eot",
240
+ ".zip",
241
+ ".tar",
242
+ ".gz"
243
+ ];
244
+ const ext = path3.extname(srcPath).toLowerCase();
245
+ if (binaryExtensions.includes(ext)) {
246
+ await fs2.copy(srcPath, destPath);
247
+ return;
248
+ }
249
+ let content = await fs2.readFile(srcPath, "utf-8");
250
+ content = content.replace(/\{\{projectName\}\}/g, projectName);
251
+ if (config?.variables) {
252
+ for (const [key, value] of Object.entries(config.variables)) {
253
+ const placeholder = `{{${key}}}`;
254
+ const replacement = value === "{{projectName}}" ? projectName : value;
255
+ content = content.replace(new RegExp(placeholder.replace(/[{}]/g, "\\$&"), "g"), replacement);
256
+ }
257
+ }
258
+ await fs2.writeFile(destPath, content, "utf-8");
259
+ }
260
+
261
+ // src/git.ts
262
+ import pc2 from "picocolors";
263
+
264
+ // src/config.ts
265
+ import fs3 from "fs";
266
+ import path4 from "path";
267
+ import os from "os";
268
+ var CONFIG_PATH = path4.join(os.homedir(), ".create-idp.json");
269
+ function loadConfig() {
270
+ try {
271
+ if (fs3.existsSync(CONFIG_PATH)) {
272
+ const content = fs3.readFileSync(CONFIG_PATH, "utf-8");
273
+ return JSON.parse(content);
274
+ }
275
+ } catch {
276
+ }
277
+ return {};
278
+ }
279
+ function saveConfig(config) {
280
+ fs3.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
281
+ fs3.chmodSync(CONFIG_PATH, 384);
282
+ }
283
+ function getConfigPath() {
284
+ return CONFIG_PATH;
285
+ }
286
+
287
+ // src/github-api.ts
288
+ var GITHUB_API_BASE = "https://api.github.com";
289
+ async function githubFetch(endpoint, token, options = {}) {
290
+ const url = `${GITHUB_API_BASE}${endpoint}`;
291
+ try {
292
+ const response = await fetch(url, {
293
+ ...options,
294
+ headers: {
295
+ "Accept": "application/vnd.github+json",
296
+ "Authorization": `Bearer ${token}`,
297
+ "X-GitHub-Api-Version": "2022-11-28",
298
+ "User-Agent": "create-idp",
299
+ ...options.headers
300
+ }
301
+ });
302
+ if (response.status === 403) {
303
+ const rateLimitRemaining = response.headers.get("x-ratelimit-remaining");
304
+ const rateLimitReset = response.headers.get("x-ratelimit-reset");
305
+ if (rateLimitRemaining === "0" && rateLimitReset) {
306
+ const resetDate = new Date(parseInt(rateLimitReset) * 1e3);
307
+ return {
308
+ success: false,
309
+ error: "API \u8BF7\u6C42\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650",
310
+ statusCode: 403,
311
+ rateLimitReset: resetDate
312
+ };
313
+ }
314
+ }
315
+ if (response.status === 401) {
316
+ return {
317
+ success: false,
318
+ error: "Token \u65E0\u6548\u6216\u5DF2\u8FC7\u671F",
319
+ statusCode: 401
320
+ };
321
+ }
322
+ if (!response.ok) {
323
+ const errorData = await response.json();
324
+ return {
325
+ success: false,
326
+ error: errorData.message || `\u8BF7\u6C42\u5931\u8D25: ${response.status}`,
327
+ statusCode: response.status
328
+ };
329
+ }
330
+ const data = await response.json();
331
+ return { success: true, data };
332
+ } catch (err) {
333
+ return {
334
+ success: false,
335
+ error: err instanceof Error ? err.message : "\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25"
336
+ };
337
+ }
338
+ }
339
+ async function validateToken(token) {
340
+ return githubFetch("/user", token);
341
+ }
342
+ async function createRepository(token, options) {
343
+ const endpoint = options.org ? `/orgs/${options.org}/repos` : "/user/repos";
344
+ const body = {
345
+ name: options.name,
346
+ description: options.description || `Created with create-idp`,
347
+ private: options.isPrivate,
348
+ auto_init: false
349
+ };
350
+ return githubFetch(endpoint, token, {
351
+ method: "POST",
352
+ body: JSON.stringify(body)
353
+ });
354
+ }
355
+
356
+ // src/git.ts
357
+ async function initGit(targetDir) {
358
+ await execAsync("git", ["init"], { cwd: targetDir });
359
+ await execAsync("git", ["add", "-A"], { cwd: targetDir });
360
+ await execAsync("git", ["commit", "-m", "Initial commit"], { cwd: targetDir });
361
+ }
362
+ async function createGithubRepo(repoName, targetDir, isPublic) {
363
+ const config = loadConfig();
364
+ if (!config.github?.token) {
365
+ console.log(pc2.yellow("\u26A0 \u672A\u914D\u7F6E GitHub Token\uFF0C\u8DF3\u8FC7\u4ED3\u5E93\u521B\u5EFA"));
366
+ console.log(pc2.dim(` \u8FD0\u884C ${pc2.cyan("create-idp config --setup-github")} \u914D\u7F6E Token`));
367
+ console.log(pc2.dim(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${getConfigPath()}`));
368
+ return null;
369
+ }
370
+ const token = config.github.token;
371
+ const defaultOrg = config.github.defaultOrg;
372
+ const validateResult = await validateToken(token);
373
+ if (!validateResult.success) {
374
+ console.log(pc2.yellow(`\u26A0 GitHub Token \u65E0\u6548: ${validateResult.error}`));
375
+ if (validateResult.rateLimitReset) {
376
+ console.log(pc2.dim(` Rate limit \u5C06\u5728 ${validateResult.rateLimitReset.toLocaleString()} \u91CD\u7F6E`));
377
+ }
378
+ console.log(pc2.dim(` \u8FD0\u884C ${pc2.cyan("create-idp config --setup-github")} \u91CD\u65B0\u914D\u7F6E`));
379
+ return null;
380
+ }
381
+ const username = validateResult.data.login;
382
+ const createResult = await createRepository(token, {
383
+ name: repoName,
384
+ isPrivate: !isPublic,
385
+ org: defaultOrg
386
+ });
387
+ if (!createResult.success) {
388
+ if (createResult.statusCode === 422) {
389
+ console.log(pc2.yellow(`\u26A0 \u4ED3\u5E93 "${repoName}" \u5DF2\u5B58\u5728\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6\u540D\u79F0`));
390
+ } else if (createResult.rateLimitReset) {
391
+ console.log(pc2.yellow(`\u26A0 API \u8BF7\u6C42\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650`));
392
+ console.log(pc2.dim(` \u5C06\u5728 ${createResult.rateLimitReset.toLocaleString()} \u91CD\u7F6E`));
393
+ } else {
394
+ console.log(pc2.yellow(`\u26A0 \u521B\u5EFA\u4ED3\u5E93\u5931\u8D25: ${createResult.error}`));
395
+ }
396
+ return null;
397
+ }
398
+ const repo = createResult.data;
399
+ const remoteResult = await execAsync(
400
+ "git",
401
+ ["remote", "add", "origin", repo.clone_url],
402
+ { cwd: targetDir }
403
+ );
404
+ if (remoteResult.code !== 0) {
405
+ await execAsync(
406
+ "git",
407
+ ["remote", "set-url", "origin", repo.clone_url],
408
+ { cwd: targetDir }
409
+ );
410
+ }
411
+ const pushResult = await execAsync(
412
+ "git",
413
+ ["push", "-u", "origin", "main"],
414
+ { cwd: targetDir }
415
+ );
416
+ if (pushResult.code !== 0) {
417
+ const pushMaster = await execAsync(
418
+ "git",
419
+ ["push", "-u", "origin", "master"],
420
+ { cwd: targetDir }
421
+ );
422
+ if (pushMaster.code !== 0) {
423
+ console.log(pc2.yellow(`\u26A0 \u63A8\u9001\u5931\u8D25: ${pushResult.stderr || pushMaster.stderr}`));
424
+ console.log(pc2.dim(` \u4ED3\u5E93\u5DF2\u521B\u5EFA: ${repo.html_url}`));
425
+ console.log(pc2.dim(" \u8BF7\u624B\u52A8\u63A8\u9001\u4EE3\u7801"));
426
+ return repo.html_url;
427
+ }
428
+ }
429
+ return repo.html_url;
430
+ }
431
+
432
+ // src/post-init.ts
433
+ import pc3 from "picocolors";
434
+ async function runPostInit(targetDir, commands) {
435
+ for (const cmd of commands) {
436
+ console.log(pc3.dim(` ${cmd.description}...`));
437
+ const [command, ...args] = cmd.command.split(" ");
438
+ const result = await execAsync(command, args, {
439
+ cwd: targetDir,
440
+ stdio: "pipe"
441
+ });
442
+ if (result.code !== 0) {
443
+ console.log(pc3.yellow(`\u26A0 ${cmd.description} \u5931\u8D25`));
444
+ if (result.stderr) {
445
+ console.log(pc3.dim(result.stderr.slice(0, 200)));
446
+ }
447
+ }
448
+ }
449
+ }
450
+
451
+ // src/update-check.ts
452
+ import fs4 from "fs";
453
+ import path5 from "path";
454
+ import os2 from "os";
455
+ import pc4 from "picocolors";
456
+ var CACHE_PATH = path5.join(os2.homedir(), ".create-idp-update-check");
457
+ var CACHE_TTL = 24 * 60 * 60 * 1e3;
458
+ var PACKAGE_NAME = "create-idp";
459
+ function readCache() {
460
+ try {
461
+ if (fs4.existsSync(CACHE_PATH)) {
462
+ const content = fs4.readFileSync(CACHE_PATH, "utf-8");
463
+ return JSON.parse(content);
464
+ }
465
+ } catch {
466
+ }
467
+ return null;
468
+ }
469
+ function writeCache(cache) {
470
+ try {
471
+ fs4.writeFileSync(CACHE_PATH, JSON.stringify(cache), "utf-8");
472
+ } catch {
473
+ }
474
+ }
475
+ async function fetchLatestVersion() {
476
+ try {
477
+ const response = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`);
478
+ if (!response.ok) {
479
+ return null;
480
+ }
481
+ const data = await response.json();
482
+ return data.version;
483
+ } catch {
484
+ return null;
485
+ }
486
+ }
487
+ function compareVersions(current, latest) {
488
+ const currentParts = current.split(".").map(Number);
489
+ const latestParts = latest.split(".").map(Number);
490
+ for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
491
+ const c = currentParts[i] || 0;
492
+ const l = latestParts[i] || 0;
493
+ if (c < l) return -1;
494
+ if (c > l) return 1;
495
+ }
496
+ return 0;
497
+ }
498
+ async function checkForUpdates(currentVersion) {
499
+ const cache = readCache();
500
+ const now = Date.now();
501
+ let latestVersion = null;
502
+ if (cache && now - cache.lastCheck < CACHE_TTL) {
503
+ latestVersion = cache.latestVersion;
504
+ } else {
505
+ latestVersion = await fetchLatestVersion();
506
+ if (latestVersion) {
507
+ writeCache({ lastCheck: now, latestVersion });
508
+ }
509
+ }
510
+ if (latestVersion && compareVersions(currentVersion, latestVersion) < 0) {
511
+ console.log();
512
+ console.log(
513
+ pc4.yellow(` \u26A0 \u53D1\u73B0\u65B0\u7248\u672C ${pc4.bold(latestVersion)}\uFF0C\u5F53\u524D ${currentVersion}`)
514
+ );
515
+ console.log(pc4.cyan(` \u8FD0\u884C ${pc4.bold(`npm update -g ${PACKAGE_NAME}`)} \u66F4\u65B0`));
516
+ console.log();
517
+ }
518
+ }
519
+
520
+ // src/github-setup.ts
521
+ import { input as input2, confirm as confirm2 } from "@inquirer/prompts";
522
+ import pc5 from "picocolors";
523
+ var TOKEN_HELP_URL = "https://github.com/settings/tokens/new?scopes=repo&description=create-idp";
524
+ async function runGitHubSetup() {
525
+ console.log();
526
+ console.log(pc5.cyan("\u914D\u7F6E GitHub Token"));
527
+ console.log();
528
+ console.log("\u9700\u8981\u4E00\u4E2A\u5177\u6709 repo \u6743\u9650\u7684 Personal Access Token (Classic) \u6765\u521B\u5EFA\u4ED3\u5E93\u3002");
529
+ console.log();
530
+ console.log(pc5.dim("\u83B7\u53D6\u6B65\u9AA4:"));
531
+ console.log(pc5.dim("1. \u8BBF\u95EE GitHub Settings > Developer settings > Personal access tokens"));
532
+ console.log(pc5.dim('2. \u70B9\u51FB "Generate new token (classic)"'));
533
+ console.log(pc5.dim('3. \u52FE\u9009 "repo" \u6743\u9650'));
534
+ console.log(pc5.dim("4. \u751F\u6210\u5E76\u590D\u5236 Token"));
535
+ console.log();
536
+ console.log(pc5.dim(`\u5FEB\u6377\u94FE\u63A5: ${TOKEN_HELP_URL}`));
537
+ console.log();
538
+ const token = await input2({
539
+ message: "\u8BF7\u8F93\u5165 GitHub Token:",
540
+ validate: (value) => {
541
+ if (!value.trim()) {
542
+ return "Token \u4E0D\u80FD\u4E3A\u7A7A";
543
+ }
544
+ if (!value.startsWith("ghp_") && !value.startsWith("github_pat_")) {
545
+ return "Token \u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u5E94\u4EE5 ghp_ \u6216 github_pat_ \u5F00\u5934";
546
+ }
547
+ return true;
548
+ }
549
+ });
550
+ console.log();
551
+ console.log(pc5.dim("\u6B63\u5728\u9A8C\u8BC1 Token..."));
552
+ const result = await validateToken(token.trim());
553
+ if (!result.success) {
554
+ console.log(pc5.red(`\u2717 Token \u9A8C\u8BC1\u5931\u8D25: ${result.error}`));
555
+ if (result.rateLimitReset) {
556
+ console.log(pc5.dim(` Rate limit \u5C06\u5728 ${result.rateLimitReset.toLocaleString()} \u91CD\u7F6E`));
557
+ }
558
+ return false;
559
+ }
560
+ const user = result.data;
561
+ console.log(pc5.green(`\u2714 Token \u6709\u6548\uFF0C\u5DF2\u767B\u5F55\u4E3A: ${user.login}${user.name ? ` (${user.name})` : ""}`));
562
+ console.log();
563
+ const setOrg = await confirm2({
564
+ message: "\u662F\u5426\u8BBE\u7F6E\u9ED8\u8BA4\u7EC4\u7EC7? (\u5426\u5219\u4ED3\u5E93\u5C06\u521B\u5EFA\u5728\u4E2A\u4EBA\u8D26\u6237\u4E0B)",
565
+ default: false
566
+ });
567
+ let defaultOrg;
568
+ if (setOrg) {
569
+ defaultOrg = await input2({
570
+ message: "\u9ED8\u8BA4\u7EC4\u7EC7\u540D\u79F0:",
571
+ validate: (value) => {
572
+ if (!value.trim()) {
573
+ return "\u7EC4\u7EC7\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
574
+ }
575
+ return true;
576
+ }
577
+ });
578
+ defaultOrg = defaultOrg.trim();
579
+ }
580
+ const config = loadConfig();
581
+ config.github = {
582
+ token: token.trim(),
583
+ ...defaultOrg && { defaultOrg }
584
+ };
585
+ saveConfig(config);
586
+ console.log();
587
+ console.log(pc5.green("\u2714 GitHub \u914D\u7F6E\u5DF2\u4FDD\u5B58"));
588
+ console.log(pc5.dim(" \u914D\u7F6E\u6587\u4EF6\u5DF2\u8BBE\u7F6E\u4E3A\u4EC5\u5F53\u524D\u7528\u6237\u53EF\u8BFB"));
589
+ return true;
590
+ }
591
+ function showConfig() {
592
+ const config = loadConfig();
593
+ console.log();
594
+ console.log(pc5.cyan("\u5F53\u524D\u914D\u7F6E:"));
595
+ console.log();
596
+ if (config.defaults) {
597
+ console.log(pc5.dim("defaults:"));
598
+ if (config.defaults.github !== void 0) {
599
+ console.log(` github: ${config.defaults.github}`);
600
+ }
601
+ if (config.defaults.public !== void 0) {
602
+ console.log(` public: ${config.defaults.public}`);
603
+ }
604
+ if (config.defaults.template !== void 0) {
605
+ console.log(` template: ${config.defaults.template}`);
606
+ }
607
+ }
608
+ if (config.github) {
609
+ console.log(pc5.dim("github:"));
610
+ if (config.github.token) {
611
+ const masked = config.github.token.slice(0, 8) + "..." + config.github.token.slice(-4);
612
+ console.log(` token: ${masked}`);
613
+ }
614
+ if (config.github.defaultOrg) {
615
+ console.log(` defaultOrg: ${config.github.defaultOrg}`);
616
+ }
617
+ }
618
+ if (!config.defaults && !config.github) {
619
+ console.log(pc5.dim("(\u65E0\u914D\u7F6E)"));
620
+ }
621
+ console.log();
622
+ }
623
+
624
+ // src/cli.ts
625
+ async function createCli() {
626
+ const program = new Command();
627
+ program.name("create-idp").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) => {
628
+ console.log();
629
+ console.log(` ${pc6.cyan("create-idp")} ${pc6.dim(`v${version}`)}`);
630
+ console.log();
631
+ checkForUpdates(version).catch(() => {
632
+ });
633
+ const userConfig = loadConfig();
634
+ try {
635
+ const projectOptions = await runPrompts(projectName, options, userConfig);
636
+ await executeProject(projectOptions);
637
+ } catch (err) {
638
+ if (err.message === "PROMPT_CANCELLED") {
639
+ console.log(pc6.yellow("\n\u64CD\u4F5C\u5DF2\u53D6\u6D88"));
640
+ process.exit(0);
641
+ }
642
+ throw err;
643
+ }
644
+ });
645
+ 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) => {
646
+ if (options.setupGithub) {
647
+ const success = await runGitHubSetup();
648
+ process.exit(success ? 0 : 1);
649
+ } else if (options.show) {
650
+ showConfig();
651
+ } else if (options.path) {
652
+ console.log(getConfigPath());
653
+ } else {
654
+ console.log();
655
+ console.log(pc6.cyan("\u914D\u7F6E\u7BA1\u7406\u547D\u4EE4:"));
656
+ console.log();
657
+ console.log(` ${pc6.dim("create-idp config --setup-github")} \u914D\u7F6E GitHub Token`);
658
+ console.log(` ${pc6.dim("create-idp config --show")} \u663E\u793A\u5F53\u524D\u914D\u7F6E`);
659
+ console.log(` ${pc6.dim("create-idp config --path")} \u663E\u793A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84`);
660
+ console.log();
661
+ }
662
+ });
663
+ return program;
664
+ }
665
+ async function executeProject(options) {
666
+ const templateConfig = await scaffoldProject(options);
667
+ console.log(pc6.green("\u2714 \u9879\u76EE\u6587\u4EF6\u5DF2\u751F\u6210"));
668
+ if (!options.noInstall && templateConfig?.postInit) {
669
+ await runPostInit(options.targetDir, templateConfig.postInit);
670
+ console.log(pc6.green("\u2714 \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210"));
671
+ }
672
+ if (options.initGit) {
673
+ await initGit(options.targetDir);
674
+ console.log(pc6.green("\u2714 Git \u4ED3\u5E93\u5DF2\u521D\u59CB\u5316"));
675
+ }
676
+ if (options.createGithub) {
677
+ const repoUrl = await createGithubRepo(
678
+ options.projectName,
679
+ options.targetDir,
680
+ options.isPublic
681
+ );
682
+ if (repoUrl) {
683
+ console.log(pc6.green(`\u2714 GitHub \u4ED3\u5E93\u5DF2\u521B\u5EFA: ${pc6.cyan(repoUrl)}`));
684
+ }
685
+ }
686
+ console.log();
687
+ const pm = templateConfig?.packageManager ?? "pnpm";
688
+ const cdCmd = options.targetDir !== process.cwd() ? `cd ${options.projectName} && ` : "";
689
+ console.log(pc6.dim(` ${cdCmd}${pm} dev`));
690
+ console.log();
691
+ }
692
+
693
+ // src/index.ts
694
+ async function main() {
695
+ const program = await createCli();
696
+ await program.parseAsync(process.argv);
697
+ }
698
+ main().catch((err) => {
699
+ console.error(err);
700
+ process.exit(1);
701
+ });
702
+ //# sourceMappingURL=index.js.map