@lambertkeith/spec-go 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -0
- package/dist/{index.js → cli/index.js} +418 -387
- package/dist/cli/index.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.js +591 -0
- package/dist/mcp/index.js.map +1 -0
- package/package.json +8 -4
- package/dist/index.js.map +0 -1
- /package/dist/{index.d.ts → cli/index.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/server.ts","../../src/mcp/tools.ts","../../src/core/config.ts","../../src/core/debug.ts","../../src/core/utils.ts","../../src/core/scaffold.ts","../../src/core/github-api.ts","../../src/core/git.ts","../../src/core/post-init.ts","../../src/mcp/index.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport {\n createProject,\n getTemplateList,\n validateProjectName,\n initGitRepo,\n createGithubRepository,\n createProjectSchema,\n validateProjectNameSchema,\n initGitRepoSchema,\n createGithubRepoSchema,\n} from './tools.js'\n\n/**\n * 创建并配置 MCP Server\n */\nexport function createMcpServer(): McpServer {\n const server = new McpServer({\n name: 'spec-go',\n version: '0.2.5',\n })\n\n // 注册工具\n\n // 1. create_project - 使用模板创建新项目\n server.tool(\n 'create_project',\n '使用模板创建新项目。支持多种模板如 node-ts, react-ts, vue-ts 等。',\n createProjectSchema.shape,\n async (params) => {\n const result = await createProject(params as any)\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n }\n }\n )\n\n // 2. list_templates - 列出所有可用模板\n server.tool(\n 'list_templates',\n '列出所有可用的项目模板,包括单体项目和前后端分离项目。',\n {},\n async () => {\n const result = await getTemplateList()\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n }\n }\n )\n\n // 3. validate_project_name - 验证项目名称\n server.tool(\n 'validate_project_name',\n '验证项目名称是否有效,并返回规范化后的名称。',\n validateProjectNameSchema.shape,\n async (params) => {\n const result = validateProjectName(params as any)\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n }\n }\n )\n\n // 4. init_git_repo - 初始化 Git 仓库\n server.tool(\n 'init_git_repo',\n '在指定目录初始化 Git 仓库,执行 git init、git add 和初始提交。',\n initGitRepoSchema.shape,\n async (params) => {\n const result = await initGitRepo(params as any)\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n }\n }\n )\n\n // 5. create_github_repo - 创建 GitHub 仓库并推送\n server.tool(\n 'create_github_repo',\n '创建 GitHub 仓库并将本地代码推送到远程。需要先配置 GitHub Token。',\n createGithubRepoSchema.shape,\n async (params) => {\n const result = await createGithubRepository(params as any)\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n }\n }\n )\n\n return server\n}\n\n/**\n * 启动 MCP Server\n */\nexport async function startServer(): Promise<void> {\n const server = createMcpServer()\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n","import { z } from 'zod'\nimport path from 'node:path'\nimport {\n scaffoldProject,\n listTemplates,\n initGit,\n createGithubRepoOnly,\n isValidPackageName,\n toValidPackageName,\n execAsync,\n} from '../core/index.js'\nimport type { ProjectOptions } from '../core/index.js'\n\n/**\n * MCP 工具定义\n */\n\n// 工具参数 Schema\nexport const createProjectSchema = z.object({\n projectName: z.string().describe('项目名称'),\n template: z.string().describe('模板名称,如 node-ts, react-ts, vue-ts 等'),\n targetDir: z.string().optional().describe('目标目录,默认为当前目录下的项目名称'),\n skipGit: z.boolean().optional().default(false).describe('是否跳过 Git 初始化'),\n skipInstall: z.boolean().optional().default(false).describe('是否跳过依赖安装'),\n})\n\nexport const validateProjectNameSchema = z.object({\n name: z.string().describe('要验证的项目名称'),\n})\n\nexport const initGitRepoSchema = z.object({\n targetDir: z.string().describe('目标目录的绝对路径'),\n})\n\nexport const createGithubRepoSchema = z.object({\n repoName: z.string().describe('仓库名称'),\n targetDir: z.string().describe('本地项目目录的绝对路径'),\n isPublic: z.boolean().optional().default(false).describe('是否创建公开仓库'),\n organization: z.string().optional().describe('GitHub 组织名称,不填则创建在个人账户下'),\n})\n\n// 工具实现\n\n/**\n * 创建项目\n */\nexport async function createProject(params: z.infer<typeof createProjectSchema>): Promise<{\n success: boolean\n projectPath?: string\n template?: string\n error?: string\n}> {\n const { projectName, template, targetDir, skipGit, skipInstall } = params\n\n // 验证项目名称\n const validName = toValidPackageName(projectName)\n if (!isValidPackageName(validName)) {\n return {\n success: false,\n error: `无效的项目名称: ${projectName}`,\n }\n }\n\n // 获取可用模板列表\n const registry = await listTemplates()\n const templateEntry = registry.templates.find(t => t.name === template)\n if (!templateEntry) {\n const availableTemplates = registry.templates.map(t => t.name).join(', ')\n return {\n success: false,\n error: `未找到模板 \"${template}\",可用模板: ${availableTemplates}`,\n }\n }\n\n // 确定目标目录\n const resolvedTargetDir = targetDir\n ? path.resolve(targetDir)\n : path.resolve(process.cwd(), validName)\n\n const options: ProjectOptions = {\n projectName: validName,\n template,\n targetDir: resolvedTargetDir,\n initGit: !skipGit,\n createGithub: false,\n isPublic: false,\n noInstall: skipInstall,\n }\n\n try {\n const templateConfig = await scaffoldProject(options)\n\n // 执行依赖安装(如果需要)\n if (!skipInstall && templateConfig?.postInit) {\n for (const cmd of templateConfig.postInit) {\n const [command, ...args] = cmd.command.split(' ')\n await execAsync(command, args, { cwd: resolvedTargetDir, stdio: 'pipe' })\n }\n }\n\n // 初始化 Git(如果需要)\n if (!skipGit) {\n await initGit(resolvedTargetDir)\n }\n\n return {\n success: true,\n projectPath: resolvedTargetDir,\n template,\n }\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n}\n\n/**\n * 列出所有可用模板\n */\nexport async function getTemplateList(): Promise<{\n templates: Array<{\n name: string\n displayName: string\n description: string\n category: string\n }>\n}> {\n const registry = await listTemplates()\n return {\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}\n\n/**\n * 验证项目名称\n */\nexport function validateProjectName(params: z.infer<typeof validateProjectNameSchema>): {\n valid: boolean\n normalizedName?: string\n error?: string\n} {\n const { name } = params\n\n if (!name || !name.trim()) {\n return {\n valid: false,\n error: '项目名称不能为空',\n }\n }\n\n const normalizedName = toValidPackageName(name)\n\n if (!isValidPackageName(normalizedName)) {\n return {\n valid: false,\n error: `无效的项目名称: ${name}`,\n }\n }\n\n return {\n valid: true,\n normalizedName,\n }\n}\n\n/**\n * 初始化 Git 仓库\n */\nexport async function initGitRepo(params: z.infer<typeof initGitRepoSchema>): Promise<{\n success: boolean\n error?: string\n}> {\n const { targetDir } = params\n\n try {\n await initGit(targetDir)\n return { success: true }\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n}\n\n/**\n * 创建 GitHub 仓库并推送\n */\nexport async function createGithubRepository(params: z.infer<typeof createGithubRepoSchema>): Promise<{\n success: boolean\n repoUrl?: string\n error?: string\n}> {\n const { repoName, targetDir, isPublic, organization } = params\n\n // 先创建仓库\n const result = await createGithubRepoOnly(repoName, isPublic, organization)\n\n if (!result.success) {\n return result\n }\n\n // 添加远程仓库并推送\n try {\n const remoteResult = await execAsync(\n 'git',\n ['remote', 'add', 'origin', `https://github.com/${organization || 'USER'}/${repoName}.git`],\n { cwd: targetDir }\n )\n\n if (remoteResult.code !== 0) {\n // remote 可能已存在,尝试更新\n await execAsync(\n 'git',\n ['remote', 'set-url', 'origin', `https://github.com/${organization || 'USER'}/${repoName}.git`],\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 return {\n success: true,\n repoUrl: result.repoUrl,\n error: `仓库已创建但推送失败: ${pushResult.stderr || pushMaster.stderr}`,\n }\n }\n }\n\n return {\n success: true,\n repoUrl: result.repoUrl,\n }\n } catch (err) {\n return {\n success: true,\n repoUrl: result.repoUrl,\n error: `仓库已创建但推送失败: ${err instanceof Error ? err.message : String(err)}`,\n }\n }\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","/**\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","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","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\n/**\n * 获取所有可用模板列表\n */\nexport async function listTemplates(): Promise<TemplateRegistry> {\n const templatesDir = getTemplatesDir()\n const registryPath = path.join(templatesDir, 'template.config.json')\n return fs.readJson(registryPath)\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\nexport type 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}`,\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 { execAsync } from './utils.js'\nimport { loadConfig, getConfigPath } from './config.js'\nimport { validateToken, createRepository } from './github-api.js'\nimport { debug } from './debug.js'\nimport { silentLogger } from './types.js'\nimport type { Logger } from './types.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 interface CreateGithubRepoOptions {\n repoName: string\n targetDir: string\n isPublic: boolean\n organization?: string\n logger?: Logger\n}\n\n/**\n * 创建 GitHub 仓库并推送代码\n * @param options 创建选项\n * @returns 仓库 URL 或 null(失败时)\n */\nexport async function createGithubRepo(\n options: CreateGithubRepoOptions\n): Promise<string | null> {\n const { repoName, targetDir, isPublic, organization, logger = silentLogger } = options\n\n debug('git', `创建 GitHub 仓库: ${repoName}, 公开: ${isPublic}`)\n const config = loadConfig()\n\n // 检查 Token 是否配置\n if (!config.github?.token) {\n logger.warn('⚠ 未配置 GitHub Token,跳过仓库创建')\n logger.dim(` 运行 spec-go config --setup-github 配置 Token`)\n logger.dim(` 配置文件路径: ${getConfigPath()}`)\n return null\n }\n\n const token = config.github.token\n const defaultOrg = organization || config.github.defaultOrg\n\n // 验证 Token\n const validateResult = await validateToken(token)\n if (!validateResult.success) {\n logger.warn(`⚠ GitHub Token 无效: ${validateResult.error}`)\n if (validateResult.rateLimitReset) {\n logger.dim(` Rate limit 将在 ${validateResult.rateLimitReset.toLocaleString()} 重置`)\n }\n logger.dim(` 运行 spec-go config --setup-github 重新配置`)\n return null\n }\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 logger.warn(`⚠ 仓库 \"${repoName}\" 已存在,请选择其他名称`)\n } else if (createResult.rateLimitReset) {\n logger.warn(`⚠ API 请求次数已达上限`)\n logger.dim(` 将在 ${createResult.rateLimitReset.toLocaleString()} 重置`)\n } else {\n logger.warn(`⚠ 创建仓库失败: ${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 logger.warn(`⚠ 推送失败: ${pushResult.stderr || pushMaster.stderr}`)\n logger.dim(` 仓库已创建: ${repo.html_url}`)\n logger.dim(' 请手动推送代码')\n return repo.html_url\n }\n }\n\n return repo.html_url\n}\n\n/**\n * 仅创建 GitHub 仓库(不推送代码)- 用于 MCP\n */\nexport async function createGithubRepoOnly(\n repoName: string,\n isPublic: boolean,\n organization?: string\n): Promise<CreateGithubRepoResult> {\n const config = loadConfig()\n\n if (!config.github?.token) {\n return {\n success: false,\n error: '未配置 GitHub Token,请运行 spec-go config --setup-github 配置'\n }\n }\n\n const token = config.github.token\n const defaultOrg = organization || config.github.defaultOrg\n\n const validateResult = await validateToken(token)\n if (!validateResult.success) {\n return {\n success: false,\n error: `GitHub Token 无效: ${validateResult.error}`\n }\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 return { success: false, error: `仓库 \"${repoName}\" 已存在` }\n }\n return { success: false, error: createResult.error }\n }\n\n return {\n success: true,\n repoUrl: createResult.data.html_url\n }\n}\n","import path from 'node:path'\nimport { execAsync } from './utils.js'\nimport { silentLogger } from './types.js'\nimport type { PostInitCommand, TemplateConfig, Logger } from './types.js'\n\nexport interface RunPostInitOptions {\n logger?: Logger\n}\n\nexport async function runPostInit(\n targetDir: string,\n commands: PostInitCommand[],\n options: RunPostInitOptions = {}\n): Promise<void> {\n const { logger = silentLogger } = options\n\n for (const cmd of commands) {\n logger.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 logger.warn(`⚠ ${cmd.description} 失败`)\n if (result.stderr) {\n logger.dim(result.stderr.slice(0, 200))\n }\n }\n }\n}\n\nexport async function runWorkspacePostInit(\n targetDir: string,\n config: TemplateConfig,\n options: RunPostInitOptions = {}\n): Promise<void> {\n const { logger = silentLogger } = options\n\n // 先执行根目录的 postInit 命令(如果有)\n if (config.postInit && config.postInit.length > 0) {\n await runPostInit(targetDir, config.postInit, options)\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 logger.dim(` [${ws.name}]`)\n await runPostInit(wsDir, ws.postInit, options)\n }\n }\n }\n}\n","import { startServer } from './server.js'\n\nstartServer().catch((err) => {\n console.error('MCP Server 启动失败:', err)\n process.exit(1)\n})\n"],"mappings":"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","names":["path","path","path","path","fs","path","fs","path","path"]}
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lambertkeith/spec-go",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "CLI 脚手架工具,快速创建项目并可选初始化 GitHub 仓库",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"spec-go": "./dist/index.js"
|
|
7
|
+
"spec-go": "./dist/cli/index.js",
|
|
8
|
+
"spec-go-mcp": "./dist/mcp/index.js"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
10
11
|
"dist",
|
|
@@ -23,7 +24,8 @@
|
|
|
23
24
|
"create",
|
|
24
25
|
"spec-go",
|
|
25
26
|
"template",
|
|
26
|
-
"generator"
|
|
27
|
+
"generator",
|
|
28
|
+
"mcp"
|
|
27
29
|
],
|
|
28
30
|
"author": "",
|
|
29
31
|
"license": "MIT",
|
|
@@ -36,9 +38,11 @@
|
|
|
36
38
|
},
|
|
37
39
|
"dependencies": {
|
|
38
40
|
"@inquirer/prompts": "^7.2.1",
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
39
42
|
"commander": "^13.0.0",
|
|
40
43
|
"fs-extra": "^11.2.0",
|
|
41
|
-
"picocolors": "^1.1.1"
|
|
44
|
+
"picocolors": "^1.1.1",
|
|
45
|
+
"zod": "^4.3.6"
|
|
42
46
|
},
|
|
43
47
|
"engines": {
|
|
44
48
|
"node": ">=18.0.0"
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
|
File without changes
|