prime-dev-cli 1.0.20 → 1.0.21

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 (75) hide show
  1. package/dist/server/.next/BUILD_ID +1 -1
  2. package/dist/server/.next/app-build-manifest.json +1 -1
  3. package/dist/server/.next/app-path-routes-manifest.json +2 -0
  4. package/dist/server/.next/build-manifest.json +6 -6
  5. package/dist/server/.next/cache/.tsbuildinfo +1 -1
  6. package/dist/server/.next/cache/eslint/.cache_1qa5vxt +1 -1
  7. package/dist/server/.next/fallback-build-manifest.json +6 -6
  8. package/dist/server/.next/next-minimal-server.js.nft.json +1 -1
  9. package/dist/server/.next/next-server.js.nft.json +1 -1
  10. package/dist/server/.next/prerender-manifest.json +12 -12
  11. package/dist/server/.next/server/app/_not-found.html +1 -1
  12. package/dist/server/.next/server/app/_not-found.rsc +1 -1
  13. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route/app-build-manifest.json +10 -0
  14. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route/app-paths-manifest.json +3 -0
  15. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route/build-manifest.json +16 -0
  16. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route/next-font-manifest.json +6 -0
  17. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route/react-loadable-manifest.json +1 -0
  18. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route/server-reference-manifest.json +4 -0
  19. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route.js +8 -0
  20. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route.js.map +5 -0
  21. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route.js.nft.json +1 -0
  22. package/dist/server/.next/server/app/api/admin-git-batch-create-branch/route_client-reference-manifest.js +2 -0
  23. package/dist/server/.next/server/app/api/admin-git-batch-merge/route/app-build-manifest.json +10 -0
  24. package/dist/server/.next/server/app/api/admin-git-batch-merge/route/app-paths-manifest.json +3 -0
  25. package/dist/server/.next/server/app/api/admin-git-batch-merge/route/build-manifest.json +16 -0
  26. package/dist/server/.next/server/app/api/admin-git-batch-merge/route/next-font-manifest.json +6 -0
  27. package/dist/server/.next/server/app/api/admin-git-batch-merge/route/react-loadable-manifest.json +1 -0
  28. package/dist/server/.next/server/app/api/admin-git-batch-merge/route/server-reference-manifest.json +4 -0
  29. package/dist/server/.next/server/app/api/admin-git-batch-merge/route.js +8 -0
  30. package/dist/server/.next/server/app/api/admin-git-batch-merge/route.js.map +5 -0
  31. package/dist/server/.next/server/app/api/admin-git-batch-merge/route.js.nft.json +1 -0
  32. package/dist/server/.next/server/app/api/admin-git-batch-merge/route_client-reference-manifest.js +2 -0
  33. package/dist/server/.next/server/app/api/uat-git-flow/route.js +1 -1
  34. package/dist/server/.next/server/app/api/uat-git-flow/route.js.nft.json +1 -1
  35. package/dist/server/.next/server/app/api/uat-git-flow/step/route.js +1 -1
  36. package/dist/server/.next/server/app/api/uat-git-flow/step/route.js.nft.json +1 -1
  37. package/dist/server/.next/server/app/configuration.html +1 -1
  38. package/dist/server/.next/server/app/configuration.rsc +1 -1
  39. package/dist/server/.next/server/app/index.html +1 -1
  40. package/dist/server/.next/server/app/index.rsc +1 -1
  41. package/dist/server/.next/server/app/initialization/page/app-build-manifest.json +1 -1
  42. package/dist/server/.next/server/app/initialization/page_client-reference-manifest.js +1 -1
  43. package/dist/server/.next/server/app/initialization.html +1 -1
  44. package/dist/server/.next/server/app/initialization.rsc +2 -2
  45. package/dist/server/.next/server/app-paths-manifest.json +2 -0
  46. package/dist/server/.next/server/chunks/[root-of-the-server]__8a8561ea._.js +16 -0
  47. package/dist/server/.next/server/chunks/[root-of-the-server]__8a8561ea._.js.map +1 -0
  48. package/dist/server/.next/server/chunks/{[root-of-the-server]__4ad2e049._.js → [root-of-the-server]__978c4dda._.js} +2 -2
  49. package/dist/server/.next/server/chunks/{[root-of-the-server]__4ad2e049._.js.map → [root-of-the-server]__978c4dda._.js.map} +1 -1
  50. package/dist/server/.next/server/chunks/{[root-of-the-server]__a8ae0f8f._.js → [root-of-the-server]__bc84f5d7._.js} +2 -2
  51. package/dist/server/.next/server/chunks/{[root-of-the-server]__a8ae0f8f._.js.map → [root-of-the-server]__bc84f5d7._.js.map} +1 -1
  52. package/dist/server/.next/server/chunks/[root-of-the-server]__f111df8e._.js +16 -0
  53. package/dist/server/.next/server/chunks/[root-of-the-server]__f111df8e._.js.map +1 -0
  54. package/dist/server/.next/server/chunks/ssr/packages_server_src_7cef6dbd._.js +1 -1
  55. package/dist/server/.next/server/chunks/ssr/packages_server_src_7cef6dbd._.js.map +1 -1
  56. package/dist/server/.next/server/middleware-build-manifest.js +4 -4
  57. package/dist/server/.next/server/pages/404.html +1 -1
  58. package/dist/server/.next/server/pages/500.html +1 -1
  59. package/dist/server/.next/server/pages/_app/build-manifest.json +2 -2
  60. package/dist/server/.next/server/pages/_error/build-manifest.json +2 -2
  61. package/dist/server/.next/static/chunks/{2602bf706e977560.js.map → 263bfd9c535a6eda.js.map} +1 -1
  62. package/dist/server/.next/static/chunks/{1091ba2f3c451a47.js → 2693a47bbc4fc75c.js} +1 -1
  63. package/dist/server/.next/static/chunks/{1aa036ed62a506c8.js → 352f266165580042.js} +2 -2
  64. package/dist/server/.next/static/chunks/67cde2756fdf3a91.js +3 -0
  65. package/dist/server/.next/static/chunks/{1154a499e8e3867b.js → ac48e758a0b74c2b.js} +1 -1
  66. package/dist/server/.next/static/chunks/c198f02ea70fda25.js.map +1 -0
  67. package/dist/server/.next/static/chunks/pages/_app.js +2 -2
  68. package/dist/server/.next/static/chunks/pages/_error.js +2 -2
  69. package/dist/server/.next/trace +1 -1
  70. package/package.json +1 -1
  71. package/dist/server/.next/static/chunks/36cdd24a97bd8ed5.js +0 -3
  72. package/dist/server/.next/static/chunks/df7954b7bd4ea3eb.js.map +0 -1
  73. /package/dist/server/.next/static/{y0HjvfId3sNkXoR9vLiLd → TxLJ_6S5QAvwM1pkwjUrZ}/_buildManifest.js +0 -0
  74. /package/dist/server/.next/static/{y0HjvfId3sNkXoR9vLiLd → TxLJ_6S5QAvwM1pkwjUrZ}/_clientMiddlewareManifest.json +0 -0
  75. /package/dist/server/.next/static/{y0HjvfId3sNkXoR9vLiLd → TxLJ_6S5QAvwM1pkwjUrZ}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["turbopack:///[project]/packages/server/src/lib/workspace-types.ts","turbopack:///[project]/packages/server/src/lib/workspace-config.ts","turbopack:///[project]/packages/server/src/lib/git-operations.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/state.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/git-status-utils.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/temp-repo.ts"],"sourcesContent":["import { homedir, cpus } from 'os';\nimport { join } from 'path';\n\n/**\n * 工作空间配置常量\n */\nexport const WORKSPACE_CONFIG = {\n // 工作空间根目录路径\n WORKSPACE_ROOT: join(homedir(), 'Documents', 'prime-workspace'),\n\n // Git 操作超时时间 (毫秒)\n GIT_TIMEOUT: 300000, // 5分钟\n\n // 最大并发克隆数量(基于CPU核心数,最小2个,最大8个)\n MAX_CONCURRENT_CLONES: Math.max(2, Math.min(cpus().length, 8)),\n\n // 重试次数限制\n MAX_RETRY_ATTEMPTS: 3,\n} as const;\n\nexport const PROJECT_CONFIG_PATH = join(homedir(), '.prime-projects.json');\n\nexport interface ProjectConfig {\n repo: string;\n mockingIntercept?: boolean;\n mockOpen?: boolean;\n envs: {\n [envName: string]: {\n host: string;\n currentProxy: string;\n proxyEnv: {\n [key: string]: string;\n };\n envFileName: string;\n proxyKey: string;\n subApps?: string[];\n };\n };\n}\n\nexport interface ProjectsConfig {\n [projectName: string]: ProjectConfig;\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n INCOMPLETE = 'incomplete', // 不完整的项目,需要清理\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n onLog?: (projectName: string, logType: 'stdout' | 'stderr' | 'progress', content: string) => void;\n}\n","import { readFile, writeFile, access, constants, rename } from 'fs/promises';\nimport type { ProjectsConfig } from './workspace-types';\nimport { PROJECT_CONFIG_PATH } from './workspace-types';\n\n/**\n * 读取并解析项目配置文件\n * @returns {Promise<ProjectsConfig>} 项目配置对象\n */\nexport async function getProjectsConfig(): Promise<ProjectsConfig> {\n try {\n await access(PROJECT_CONFIG_PATH, constants.F_OK);\n } catch {\n // 文件不存在,创建并写入空对象\n await saveProjectsConfig({});\n return {};\n }\n\n try {\n const configContent = await readFile(PROJECT_CONFIG_PATH, 'utf-8');\n // 如果文件为空,返回空对象\n if (!configContent) {\n return {};\n }\n return JSON.parse(configContent);\n } catch (error) {\n console.error('读取或解析项目配置文件失败:', error);\n // 在出错时返回空对象或抛出错误,这里选择抛出以通知调用者\n throw new Error('无法加载项目配置');\n }\n}\n\n/**\n * 将项目配置写入文件(原子操作)\n * @param {ProjectsConfig} config - 要保存的配置对象\n */\nexport async function saveProjectsConfig(config: ProjectsConfig): Promise<void> {\n const tempConfigPath = PROJECT_CONFIG_PATH + '.tmp';\n try {\n await writeFile(tempConfigPath, JSON.stringify(config, null, 2), 'utf-8');\n await rename(tempConfigPath, PROJECT_CONFIG_PATH);\n } catch (error) {\n console.error('保存项目配置文件失败:', error);\n throw new Error('无法保存项目配置');\n }\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n}\n","import { spawn, ChildProcess } from 'child_process';\nimport { existsSync, mkdirSync } from 'fs';\nimport { promises as fs } from 'fs';\nimport { join, basename } from 'path';\nimport {\n ProjectStatus,\n type GitOperationConfig,\n type ProjectProgress,\n} from './workspace-types';\n\n/**\n * 创建工作空间目录\n * @param workspacePath 工作空间路径\n * @returns 创建结果\n */\nexport async function createWorkspaceDirectory(workspacePath: string): Promise<{ success: boolean; error?: string }> {\n try {\n if (!existsSync(workspacePath)) {\n mkdirSync(workspacePath, { recursive: true });\n }\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: `创建工作空间目录失败: ${error instanceof Error ? error.message : String(error)}` \n };\n }\n}\n\n/**\n * 执行 Git 克隆操作\n * @param config Git 操作配置\n * @returns Promise<ProjectProgress>\n */\nexport async function cloneRepository(config: GitOperationConfig): Promise<ProjectProgress> {\n const { repoUrl, projectName: configuredProjectName, targetDir, timeout, onProgress, onError, onLog } = config;\n const projectName = configuredProjectName?.trim() || basename(repoUrl, '.git');\n \n return new Promise<ProjectProgress>((resolve) => {\n const startTime = Date.now();\n \n // 更新开始状态\n const initialProgress: ProjectProgress = {\n projectName,\n status: ProjectStatus.CLONING,\n progress: 0,\n message: '开始克隆项目...',\n startTime,\n };\n onProgress?.(0, '开始克隆项目...');\n\n // 执行 git clone 命令\n const targetPath = join(targetDir, projectName);\n // 添加 --progress 参数来强制显示进度,--verbose 显示详细信息\n const gitArgs = ['clone', '--progress', '--verbose', repoUrl, targetPath];\n \n // 记录命令启动信息\n onLog?.(projectName, 'stdout', `[开始克隆] 执行命令: git ${gitArgs.join(' ')}\\n`);\n onLog?.(projectName, 'stdout', `[目标目录] ${targetPath}\\n`);\n onLog?.(projectName, 'stdout', `[仓库地址] ${repoUrl}\\n`);\n \n const gitProcess: ChildProcess = spawn('git', gitArgs, {\n cwd: targetDir,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n let errorOutput = '';\n let progressValue = 0;\n \n // 记录进程启动成功\n onLog?.(projectName, 'stdout', `[进程启动] Git 进程 PID: ${gitProcess.pid}\\n`);\n\n // 设置超时\n const timeoutId = setTimeout(() => {\n onLog?.(projectName, 'stderr', `[超时警告] Git 进程运行超过 ${timeout / 1000}s,即将终止\\n`);\n gitProcess.kill('SIGTERM');\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆操作超时',\n error: `克隆操作超时 (${timeout / 1000}s)`,\n endTime: Date.now(),\n };\n onLog?.(projectName, 'stderr', `[进程终止] 克隆操作超时\\n`);\n onError?.(`${projectName}: 克隆操作超时`);\n resolve(errorResult);\n }, timeout);\n\n // 处理标准输出\n gitProcess.stdout?.on('data', (data: Buffer) => {\n const stdoutText = data.toString();\n \n // 实时发送日志\n onLog?.(projectName, 'stdout', stdoutText);\n \n // 模拟进度更新(Git 克隆没有内置进度,这里基于时间估算)\n progressValue = Math.min(progressValue + 10, 80);\n onProgress?.(progressValue, '正在克隆代码...');\n });\n\n // 处理错误输出\n gitProcess.stderr?.on('data', (data: Buffer) => {\n const stderrText = data.toString();\n errorOutput += stderrText;\n \n // 判断是进度信息还是错误信息\n const isProgressInfo = stderrText.includes('remote:') || \n stderrText.includes('Receiving objects') || \n stderrText.includes('Resolving deltas') ||\n stderrText.includes('Counting objects') ||\n stderrText.includes('Enumerating objects') ||\n stderrText.includes('Compressing objects') ||\n stderrText.includes('upload-pack') ||\n stderrText.includes('POST git-') ||\n stderrText.includes('正克隆到') ||\n stderrText.includes('Cloning into');\n \n // 根据内容类型发送不同的日志\n if (isProgressInfo) {\n onLog?.(projectName, 'progress', stderrText);\n } else {\n onLog?.(projectName, 'stderr', stderrText);\n }\n \n // Git 的进度信息通常在 stderr 中\n if (stderrText.includes('Receiving objects') || stderrText.includes('Resolving deltas')) {\n progressValue = Math.min(progressValue + 5, 90);\n onProgress?.(progressValue, '正在接收对象...');\n } else if (stderrText.includes('Counting objects')) {\n progressValue = Math.min(progressValue + 2, 70);\n onProgress?.(progressValue, '正在计算对象...');\n } else if (stderrText.includes('Enumerating objects')) {\n progressValue = Math.min(progressValue + 2, 50);\n onProgress?.(progressValue, '正在枚举对象...');\n }\n });\n\n // 处理进程结束\n gitProcess.on('close', (code: number | null) => {\n clearTimeout(timeoutId);\n const endTime = Date.now();\n const duration = endTime - startTime;\n \n onLog?.(projectName, 'stdout', `[进程结束] Git 进程退出,代码: ${code},耗时: ${Math.round(duration / 1000)}s\\n`);\n \n if (code === 0) {\n // 克隆成功\n onLog?.(projectName, 'stdout', `[克隆成功] 项目已成功克隆到: ${targetPath}\\n`);\n const successResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.SUCCESS,\n progress: 100,\n message: '克隆完成',\n endTime,\n };\n onProgress?.(100, '克隆完成');\n resolve(successResult);\n } else {\n // 克隆失败\n const parsedError = parseGitError(errorOutput);\n onLog?.(projectName, 'stderr', `[克隆失败] 错误信息: ${parsedError}\\n`);\n onLog?.(projectName, 'stderr', `[完整错误输出]\\n${errorOutput}\\n`);\n \n const failureResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆失败',\n error: parsedError || `Git 进程退出,代码: ${code}`,\n endTime,\n };\n onError?.(`${projectName}: ${failureResult.error}`);\n resolve(failureResult);\n }\n });\n\n // 处理进程错误\n gitProcess.on('error', (error: Error) => {\n clearTimeout(timeoutId);\n onLog?.(projectName, 'stderr', `[进程错误] Git 进程启动失败: ${error.message}\\n`);\n onLog?.(projectName, 'stderr', `[错误详情] ${error.stack || 'No stack trace'}\\n`);\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '进程启动失败',\n error: `进程启动失败: ${error.message}`,\n endTime: Date.now(),\n };\n onError?.(`${projectName}: ${error.message}`);\n resolve(errorResult);\n });\n });\n}\n\n/**\n * 解析 Git 错误信息,提供用户友好的错误描述\n * @param errorOutput Git stderr 输出\n * @returns 用户友好的错误描述\n */\nfunction parseGitError(errorOutput: string): string {\n const lowerOutput = errorOutput.toLowerCase();\n \n if (lowerOutput.includes('authentication failed') || lowerOutput.includes('access denied')) {\n return '身份验证失败,请检查仓库访问权限';\n }\n \n if (lowerOutput.includes('repository not found') || lowerOutput.includes('not found')) {\n return '仓库不存在或无法访问';\n }\n \n if (lowerOutput.includes('network') || lowerOutput.includes('connection')) {\n return '网络连接问题,请检查网络设置';\n }\n \n if (lowerOutput.includes('timeout')) {\n return '网络超时,请重试';\n }\n \n if (lowerOutput.includes('permission denied')) {\n return '权限被拒绝,请检查文件系统权限';\n }\n \n if (lowerOutput.includes('already exists')) {\n return '目标目录已存在';\n }\n \n // 返回原始错误的前200个字符\n return errorOutput.slice(0, 200) + (errorOutput.length > 200 ? '...' : '');\n}\n\n/**\n * 验证 Git 仓库 URL 格式\n * @param url Git 仓库 URL\n * @returns 是否有效\n */\nexport function isValidGitUrl(url: string): boolean {\n const gitUrlPattern = /^(https?:\\/\\/|git@)[^\\s]+\\.git$/i;\n return gitUrlPattern.test(url);\n}\n\n/**\n * 清理项目名称,移除不安全字符\n * @param projectName 项目名称\n * @returns 清理后的项目名称\n */\nexport function sanitizeProjectName(projectName: string): string {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '');\n}\n\n/**\n * 项目检查结果类型\n */\nexport type ProjectCheckResult = {\n exists: boolean;\n status: 'not_exists' | 'complete' | 'incomplete';\n needsCleanup: boolean;\n};\n\n/**\n * 检查项目状态(详细版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<ProjectCheckResult> 详细的项目状态\n */\nexport async function checkProjectStatus(workspacePath: string, projectName: string): Promise<ProjectCheckResult> {\n try {\n const projectPath = join(workspacePath, projectName);\n \n // 检查项目目录是否存在\n if (!existsSync(projectPath)) {\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n \n // 检查是否为 Git 仓库(存在 .git 目录)\n const gitPath = join(projectPath, '.git');\n if (!existsSync(gitPath)) {\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n // 更严格的完整性检查\n const isComplete = await isGitRepositoryComplete(projectPath);\n if (!isComplete) {\n console.log(`检测到不完整的Git仓库: ${projectPath}`);\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n return {\n exists: true,\n status: 'complete',\n needsCleanup: false\n };\n } catch (error) {\n console.error(`检查项目 ${projectName} 状态时出错:`, error);\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n}\n\n/**\n * 检查项目是否已存在于工作空间中(兼容版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<boolean> 项目是否存在且为有效的 Git 仓库\n */\nexport async function checkProjectExists(workspacePath: string, projectName: string): Promise<boolean> {\n const result = await checkProjectStatus(workspacePath, projectName);\n return result.status === 'complete';\n}\n\n/**\n * 检查Git仓库是否完整\n * @param projectPath 项目路径\n * @returns Promise<boolean> 仓库是否完整\n */\nasync function isGitRepositoryComplete(projectPath: string): Promise<boolean> {\n try {\n const gitPath = join(projectPath, '.git');\n \n // 检查关键的Git文件是否存在\n const requiredFiles = ['HEAD', 'config', 'refs'];\n for (const file of requiredFiles) {\n const filePath = join(gitPath, file);\n if (!existsSync(filePath)) {\n return false;\n }\n }\n \n // 检查是否有实际的项目文件(不只是.git目录)\n const entries = await fs.readdir(projectPath);\n const nonGitFiles = entries.filter((entry: string) => entry !== '.git');\n \n // 如果只有.git目录,说明克隆未完成\n if (nonGitFiles.length === 0) {\n return false;\n }\n \n // 检查HEAD文件是否有效\n const headPath = join(gitPath, 'HEAD');\n const headContent = await fs.readFile(headPath, 'utf-8');\n if (!headContent.trim() || headContent.includes('unborn')) {\n return false;\n }\n \n return true;\n } catch (error) {\n console.error('检查Git仓库完整性时出错:', error);\n return false;\n }\n}\n\n/**\n * 清理不完整的项目目录\n * @param projectPath 项目路径\n */\nexport async function cleanupIncompleteProject(projectPath: string): Promise<void> {\n try {\n console.log(`正在清理不完整的项目: ${projectPath}`);\n await fs.rm(projectPath, { recursive: true, force: true });\n console.log(`清理完成: ${projectPath}`);\n } catch (error) {\n console.error(`清理项目失败 ${projectPath}:`, error);\n // 清理失败不抛出错误,避免阻塞后续流程\n }\n}\n\n/**\n * 批量检查多个项目的存在状态\n * @param workspacePath 工作空间路径\n * @param projectNames 项目名称列表\n * @returns Promise<Record<string, boolean>> 项目名称到存在状态的映射\n */\nexport async function checkMultipleProjectsExist(\n workspacePath: string, \n projectNames: string[]\n): Promise<Record<string, boolean>> {\n const results: Record<string, boolean> = {};\n \n // 并行检查所有项目\n const checks = projectNames.map(async (projectName) => {\n const exists = await checkProjectExists(workspacePath, projectName);\n results[projectName] = exists;\n });\n \n await Promise.all(checks);\n return results;\n} \n","type AbortState = {\n aborted: boolean;\n updatedAt: number;\n};\n\nconst abortStates = new Map<string, AbortState>();\nconst ABORT_STATE_TTL = 1000 * 60 * 30;\n\nfunction cleanupAbortStates() {\n const now = Date.now();\n for (const [runId, state] of abortStates.entries()) {\n if (now - state.updatedAt > ABORT_STATE_TTL) {\n abortStates.delete(runId);\n }\n }\n}\n\nexport function createUatGitFlowState(runId: string) {\n cleanupAbortStates();\n abortStates.set(runId, { aborted: false, updatedAt: Date.now() });\n}\n\nexport function markUatGitFlowAbort(runId: string) {\n const existing = abortStates.get(runId);\n abortStates.set(runId, {\n aborted: true,\n updatedAt: Date.now(),\n });\n if (!existing) {\n cleanupAbortStates();\n }\n}\n\nexport function isUatGitFlowAborted(runId: string) {\n cleanupAbortStates();\n return abortStates.get(runId)?.aborted ?? false;\n}\n\nexport function clearUatGitFlowState(runId: string) {\n abortStates.delete(runId);\n}\n","const unableToRmdirWarningPattern = /warning:\\s+unable to rmdir '([^']+)': Directory not empty/g;\n\nfunction normalizeGitPath(path: string) {\n return path\n .trim()\n .replace(/\\\\/g, '/')\n .replace(/^\\.\\/+/, '')\n .replace(/\\/+$/, '');\n}\n\nfunction parseStatusPath(line: string) {\n const rawPath = line.length >= 3 ? line.slice(3).trim() : '';\n if (!rawPath) return '';\n\n const unquoted = rawPath.startsWith('\"') && rawPath.endsWith('\"')\n ? rawPath.slice(1, -1)\n : rawPath;\n const renamedSeparator = ' -> ';\n const renamedIndex = unquoted.lastIndexOf(renamedSeparator);\n const targetPath = renamedIndex === -1\n ? unquoted\n : unquoted.slice(renamedIndex + renamedSeparator.length);\n\n return normalizeGitPath(targetPath);\n}\n\nexport function extractUnableToRmdirPaths(stderr: string) {\n const matchedPaths = new Set<string>();\n let match: RegExpExecArray | null;\n\n while ((match = unableToRmdirWarningPattern.exec(stderr)) !== null) {\n const normalizedPath = normalizeGitPath(match[1] || '');\n if (normalizedPath) {\n matchedPaths.add(normalizedPath);\n }\n }\n\n unableToRmdirWarningPattern.lastIndex = 0;\n return [...matchedPaths];\n}\n\nexport function appendIgnoredPathsFromCheckoutWarning(stderr: string, ignoredPaths: Set<string>) {\n const addedPaths: string[] = [];\n for (const path of extractUnableToRmdirPaths(stderr)) {\n if (!ignoredPaths.has(path)) {\n ignoredPaths.add(path);\n addedPaths.push(path);\n }\n }\n return addedPaths;\n}\n\nexport function hasBlockingWorkspaceChanges(statusOutput: string, ignoredUntrackedPaths?: Iterable<string>) {\n const ignoredPathSet = new Set<string>();\n if (ignoredUntrackedPaths) {\n for (const path of ignoredUntrackedPaths) {\n const normalizedPath = normalizeGitPath(path);\n if (normalizedPath) {\n ignoredPathSet.add(normalizedPath);\n }\n }\n }\n\n if (ignoredPathSet.size === 0) {\n return statusOutput.trim().length > 0;\n }\n\n const lines = statusOutput.split(/\\r?\\n/).filter(line => line.length > 0);\n for (const line of lines) {\n const statusCode = line.slice(0, 2);\n if (statusCode !== '??') {\n return true;\n }\n\n const statusPath = parseStatusPath(line);\n if (!statusPath) {\n return true;\n }\n\n let shouldIgnore = false;\n for (const ignoredPath of ignoredPathSet) {\n if (statusPath === ignoredPath || statusPath.startsWith(`${ignoredPath}/`)) {\n shouldIgnore = true;\n break;\n }\n }\n\n if (!shouldIgnore) {\n return true;\n }\n }\n\n return false;\n}\n","import { spawn } from 'child_process';\nimport { mkdtemp, rm } from 'fs/promises';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\n\ntype GitResult = {\n code: number | null;\n stdout: string;\n stderr: string;\n};\n\nasync function runGitCommand(cwd: string, args: string[]): Promise<GitResult> {\n return new Promise((resolve, reject) => {\n const child = spawn('git', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('close', (code) => {\n resolve({ code, stdout, stderr });\n });\n\n child.on('error', (error) => {\n reject(error);\n });\n });\n}\n\nfunction sanitizeProjectNameForTemp(projectName: string) {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '-');\n}\n\nexport type TempExecutionRepo = {\n tempRootPath: string;\n projectPath: string;\n};\n\nexport async function createTempExecutionRepo(sourceProjectPath: string, projectName: string): Promise<{\n success: true;\n value: TempExecutionRepo;\n} | {\n success: false;\n error: string;\n}> {\n const remoteResult = await runGitCommand(sourceProjectPath, ['remote', 'get-url', 'origin']);\n if (remoteResult.code !== 0) {\n return {\n success: false,\n error: remoteResult.stderr || remoteResult.stdout || '读取 origin 地址失败',\n };\n }\n\n const remoteUrl = remoteResult.stdout.trim();\n if (!remoteUrl) {\n return {\n success: false,\n error: 'origin 远端地址为空',\n };\n }\n\n const prefix = `prime-uat-${sanitizeProjectNameForTemp(projectName)}-`;\n const tempRootPath = await mkdtemp(join(tmpdir(), prefix));\n const tempProjectPath = join(tempRootPath, projectName);\n\n const cloneResult = await runGitCommand(tempRootPath, ['clone', '--no-tags', remoteUrl, tempProjectPath]);\n if (cloneResult.code !== 0) {\n await rm(tempRootPath, { recursive: true, force: true });\n return {\n success: false,\n error: cloneResult.stderr || cloneResult.stdout || '克隆临时仓库失败',\n };\n }\n\n return {\n success: true,\n value: {\n tempRootPath,\n projectPath: tempProjectPath,\n },\n };\n}\n\nexport async function cleanupTempExecutionRepo(tempRootPath: string) {\n await rm(tempRootPath, { recursive: true, force: true });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"sources":["turbopack:///[project]/packages/server/src/lib/workspace-types.ts","turbopack:///[project]/packages/server/src/lib/workspace-config.ts","turbopack:///[project]/packages/server/src/lib/git-operations.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/git-status-utils.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/temp-repo.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/state.ts"],"sourcesContent":["import { homedir, cpus } from 'os';\nimport { join } from 'path';\n\n/**\n * 工作空间配置常量\n */\nexport const WORKSPACE_CONFIG = {\n // 工作空间根目录路径\n WORKSPACE_ROOT: join(homedir(), 'Documents', 'prime-workspace'),\n\n // Git 操作超时时间 (毫秒)\n GIT_TIMEOUT: 300000, // 5分钟\n\n // 最大并发克隆数量(基于CPU核心数,最小2个,最大8个)\n MAX_CONCURRENT_CLONES: Math.max(2, Math.min(cpus().length, 8)),\n\n // 重试次数限制\n MAX_RETRY_ATTEMPTS: 3,\n} as const;\n\nexport const PROJECT_CONFIG_PATH = join(homedir(), '.prime-projects.json');\n\nexport interface ProjectConfig {\n repo: string;\n mockingIntercept?: boolean;\n mockOpen?: boolean;\n envs: {\n [envName: string]: {\n host: string;\n currentProxy: string;\n proxyEnv: {\n [key: string]: string;\n };\n envFileName: string;\n proxyKey: string;\n subApps?: string[];\n };\n };\n}\n\nexport interface ProjectsConfig {\n [projectName: string]: ProjectConfig;\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n INCOMPLETE = 'incomplete', // 不完整的项目,需要清理\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n onLog?: (projectName: string, logType: 'stdout' | 'stderr' | 'progress', content: string) => void;\n}\n","import { readFile, writeFile, access, constants, rename } from 'fs/promises';\nimport type { ProjectsConfig } from './workspace-types';\nimport { PROJECT_CONFIG_PATH } from './workspace-types';\n\n/**\n * 读取并解析项目配置文件\n * @returns {Promise<ProjectsConfig>} 项目配置对象\n */\nexport async function getProjectsConfig(): Promise<ProjectsConfig> {\n try {\n await access(PROJECT_CONFIG_PATH, constants.F_OK);\n } catch {\n // 文件不存在,创建并写入空对象\n await saveProjectsConfig({});\n return {};\n }\n\n try {\n const configContent = await readFile(PROJECT_CONFIG_PATH, 'utf-8');\n // 如果文件为空,返回空对象\n if (!configContent) {\n return {};\n }\n return JSON.parse(configContent);\n } catch (error) {\n console.error('读取或解析项目配置文件失败:', error);\n // 在出错时返回空对象或抛出错误,这里选择抛出以通知调用者\n throw new Error('无法加载项目配置');\n }\n}\n\n/**\n * 将项目配置写入文件(原子操作)\n * @param {ProjectsConfig} config - 要保存的配置对象\n */\nexport async function saveProjectsConfig(config: ProjectsConfig): Promise<void> {\n const tempConfigPath = PROJECT_CONFIG_PATH + '.tmp';\n try {\n await writeFile(tempConfigPath, JSON.stringify(config, null, 2), 'utf-8');\n await rename(tempConfigPath, PROJECT_CONFIG_PATH);\n } catch (error) {\n console.error('保存项目配置文件失败:', error);\n throw new Error('无法保存项目配置');\n }\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n}\n","import { spawn, ChildProcess } from 'child_process';\nimport { existsSync, mkdirSync } from 'fs';\nimport { promises as fs } from 'fs';\nimport { join, basename } from 'path';\nimport {\n ProjectStatus,\n type GitOperationConfig,\n type ProjectProgress,\n} from './workspace-types';\n\n/**\n * 创建工作空间目录\n * @param workspacePath 工作空间路径\n * @returns 创建结果\n */\nexport async function createWorkspaceDirectory(workspacePath: string): Promise<{ success: boolean; error?: string }> {\n try {\n if (!existsSync(workspacePath)) {\n mkdirSync(workspacePath, { recursive: true });\n }\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: `创建工作空间目录失败: ${error instanceof Error ? error.message : String(error)}` \n };\n }\n}\n\n/**\n * 执行 Git 克隆操作\n * @param config Git 操作配置\n * @returns Promise<ProjectProgress>\n */\nexport async function cloneRepository(config: GitOperationConfig): Promise<ProjectProgress> {\n const { repoUrl, projectName: configuredProjectName, targetDir, timeout, onProgress, onError, onLog } = config;\n const projectName = configuredProjectName?.trim() || basename(repoUrl, '.git');\n \n return new Promise<ProjectProgress>((resolve) => {\n const startTime = Date.now();\n \n // 更新开始状态\n const initialProgress: ProjectProgress = {\n projectName,\n status: ProjectStatus.CLONING,\n progress: 0,\n message: '开始克隆项目...',\n startTime,\n };\n onProgress?.(0, '开始克隆项目...');\n\n // 执行 git clone 命令\n const targetPath = join(targetDir, projectName);\n // 添加 --progress 参数来强制显示进度,--verbose 显示详细信息\n const gitArgs = ['clone', '--progress', '--verbose', repoUrl, targetPath];\n \n // 记录命令启动信息\n onLog?.(projectName, 'stdout', `[开始克隆] 执行命令: git ${gitArgs.join(' ')}\\n`);\n onLog?.(projectName, 'stdout', `[目标目录] ${targetPath}\\n`);\n onLog?.(projectName, 'stdout', `[仓库地址] ${repoUrl}\\n`);\n \n const gitProcess: ChildProcess = spawn('git', gitArgs, {\n cwd: targetDir,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n let errorOutput = '';\n let progressValue = 0;\n \n // 记录进程启动成功\n onLog?.(projectName, 'stdout', `[进程启动] Git 进程 PID: ${gitProcess.pid}\\n`);\n\n // 设置超时\n const timeoutId = setTimeout(() => {\n onLog?.(projectName, 'stderr', `[超时警告] Git 进程运行超过 ${timeout / 1000}s,即将终止\\n`);\n gitProcess.kill('SIGTERM');\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆操作超时',\n error: `克隆操作超时 (${timeout / 1000}s)`,\n endTime: Date.now(),\n };\n onLog?.(projectName, 'stderr', `[进程终止] 克隆操作超时\\n`);\n onError?.(`${projectName}: 克隆操作超时`);\n resolve(errorResult);\n }, timeout);\n\n // 处理标准输出\n gitProcess.stdout?.on('data', (data: Buffer) => {\n const stdoutText = data.toString();\n \n // 实时发送日志\n onLog?.(projectName, 'stdout', stdoutText);\n \n // 模拟进度更新(Git 克隆没有内置进度,这里基于时间估算)\n progressValue = Math.min(progressValue + 10, 80);\n onProgress?.(progressValue, '正在克隆代码...');\n });\n\n // 处理错误输出\n gitProcess.stderr?.on('data', (data: Buffer) => {\n const stderrText = data.toString();\n errorOutput += stderrText;\n \n // 判断是进度信息还是错误信息\n const isProgressInfo = stderrText.includes('remote:') || \n stderrText.includes('Receiving objects') || \n stderrText.includes('Resolving deltas') ||\n stderrText.includes('Counting objects') ||\n stderrText.includes('Enumerating objects') ||\n stderrText.includes('Compressing objects') ||\n stderrText.includes('upload-pack') ||\n stderrText.includes('POST git-') ||\n stderrText.includes('正克隆到') ||\n stderrText.includes('Cloning into');\n \n // 根据内容类型发送不同的日志\n if (isProgressInfo) {\n onLog?.(projectName, 'progress', stderrText);\n } else {\n onLog?.(projectName, 'stderr', stderrText);\n }\n \n // Git 的进度信息通常在 stderr 中\n if (stderrText.includes('Receiving objects') || stderrText.includes('Resolving deltas')) {\n progressValue = Math.min(progressValue + 5, 90);\n onProgress?.(progressValue, '正在接收对象...');\n } else if (stderrText.includes('Counting objects')) {\n progressValue = Math.min(progressValue + 2, 70);\n onProgress?.(progressValue, '正在计算对象...');\n } else if (stderrText.includes('Enumerating objects')) {\n progressValue = Math.min(progressValue + 2, 50);\n onProgress?.(progressValue, '正在枚举对象...');\n }\n });\n\n // 处理进程结束\n gitProcess.on('close', (code: number | null) => {\n clearTimeout(timeoutId);\n const endTime = Date.now();\n const duration = endTime - startTime;\n \n onLog?.(projectName, 'stdout', `[进程结束] Git 进程退出,代码: ${code},耗时: ${Math.round(duration / 1000)}s\\n`);\n \n if (code === 0) {\n // 克隆成功\n onLog?.(projectName, 'stdout', `[克隆成功] 项目已成功克隆到: ${targetPath}\\n`);\n const successResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.SUCCESS,\n progress: 100,\n message: '克隆完成',\n endTime,\n };\n onProgress?.(100, '克隆完成');\n resolve(successResult);\n } else {\n // 克隆失败\n const parsedError = parseGitError(errorOutput);\n onLog?.(projectName, 'stderr', `[克隆失败] 错误信息: ${parsedError}\\n`);\n onLog?.(projectName, 'stderr', `[完整错误输出]\\n${errorOutput}\\n`);\n \n const failureResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆失败',\n error: parsedError || `Git 进程退出,代码: ${code}`,\n endTime,\n };\n onError?.(`${projectName}: ${failureResult.error}`);\n resolve(failureResult);\n }\n });\n\n // 处理进程错误\n gitProcess.on('error', (error: Error) => {\n clearTimeout(timeoutId);\n onLog?.(projectName, 'stderr', `[进程错误] Git 进程启动失败: ${error.message}\\n`);\n onLog?.(projectName, 'stderr', `[错误详情] ${error.stack || 'No stack trace'}\\n`);\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '进程启动失败',\n error: `进程启动失败: ${error.message}`,\n endTime: Date.now(),\n };\n onError?.(`${projectName}: ${error.message}`);\n resolve(errorResult);\n });\n });\n}\n\n/**\n * 解析 Git 错误信息,提供用户友好的错误描述\n * @param errorOutput Git stderr 输出\n * @returns 用户友好的错误描述\n */\nfunction parseGitError(errorOutput: string): string {\n const lowerOutput = errorOutput.toLowerCase();\n \n if (lowerOutput.includes('authentication failed') || lowerOutput.includes('access denied')) {\n return '身份验证失败,请检查仓库访问权限';\n }\n \n if (lowerOutput.includes('repository not found') || lowerOutput.includes('not found')) {\n return '仓库不存在或无法访问';\n }\n \n if (lowerOutput.includes('network') || lowerOutput.includes('connection')) {\n return '网络连接问题,请检查网络设置';\n }\n \n if (lowerOutput.includes('timeout')) {\n return '网络超时,请重试';\n }\n \n if (lowerOutput.includes('permission denied')) {\n return '权限被拒绝,请检查文件系统权限';\n }\n \n if (lowerOutput.includes('already exists')) {\n return '目标目录已存在';\n }\n \n // 返回原始错误的前200个字符\n return errorOutput.slice(0, 200) + (errorOutput.length > 200 ? '...' : '');\n}\n\n/**\n * 验证 Git 仓库 URL 格式\n * @param url Git 仓库 URL\n * @returns 是否有效\n */\nexport function isValidGitUrl(url: string): boolean {\n const gitUrlPattern = /^(https?:\\/\\/|git@)[^\\s]+\\.git$/i;\n return gitUrlPattern.test(url);\n}\n\n/**\n * 清理项目名称,移除不安全字符\n * @param projectName 项目名称\n * @returns 清理后的项目名称\n */\nexport function sanitizeProjectName(projectName: string): string {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '');\n}\n\n/**\n * 项目检查结果类型\n */\nexport type ProjectCheckResult = {\n exists: boolean;\n status: 'not_exists' | 'complete' | 'incomplete';\n needsCleanup: boolean;\n};\n\n/**\n * 检查项目状态(详细版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<ProjectCheckResult> 详细的项目状态\n */\nexport async function checkProjectStatus(workspacePath: string, projectName: string): Promise<ProjectCheckResult> {\n try {\n const projectPath = join(workspacePath, projectName);\n \n // 检查项目目录是否存在\n if (!existsSync(projectPath)) {\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n \n // 检查是否为 Git 仓库(存在 .git 目录)\n const gitPath = join(projectPath, '.git');\n if (!existsSync(gitPath)) {\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n // 更严格的完整性检查\n const isComplete = await isGitRepositoryComplete(projectPath);\n if (!isComplete) {\n console.log(`检测到不完整的Git仓库: ${projectPath}`);\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n return {\n exists: true,\n status: 'complete',\n needsCleanup: false\n };\n } catch (error) {\n console.error(`检查项目 ${projectName} 状态时出错:`, error);\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n}\n\n/**\n * 检查项目是否已存在于工作空间中(兼容版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<boolean> 项目是否存在且为有效的 Git 仓库\n */\nexport async function checkProjectExists(workspacePath: string, projectName: string): Promise<boolean> {\n const result = await checkProjectStatus(workspacePath, projectName);\n return result.status === 'complete';\n}\n\n/**\n * 检查Git仓库是否完整\n * @param projectPath 项目路径\n * @returns Promise<boolean> 仓库是否完整\n */\nasync function isGitRepositoryComplete(projectPath: string): Promise<boolean> {\n try {\n const gitPath = join(projectPath, '.git');\n \n // 检查关键的Git文件是否存在\n const requiredFiles = ['HEAD', 'config', 'refs'];\n for (const file of requiredFiles) {\n const filePath = join(gitPath, file);\n if (!existsSync(filePath)) {\n return false;\n }\n }\n \n // 检查是否有实际的项目文件(不只是.git目录)\n const entries = await fs.readdir(projectPath);\n const nonGitFiles = entries.filter((entry: string) => entry !== '.git');\n \n // 如果只有.git目录,说明克隆未完成\n if (nonGitFiles.length === 0) {\n return false;\n }\n \n // 检查HEAD文件是否有效\n const headPath = join(gitPath, 'HEAD');\n const headContent = await fs.readFile(headPath, 'utf-8');\n if (!headContent.trim() || headContent.includes('unborn')) {\n return false;\n }\n \n return true;\n } catch (error) {\n console.error('检查Git仓库完整性时出错:', error);\n return false;\n }\n}\n\n/**\n * 清理不完整的项目目录\n * @param projectPath 项目路径\n */\nexport async function cleanupIncompleteProject(projectPath: string): Promise<void> {\n try {\n console.log(`正在清理不完整的项目: ${projectPath}`);\n await fs.rm(projectPath, { recursive: true, force: true });\n console.log(`清理完成: ${projectPath}`);\n } catch (error) {\n console.error(`清理项目失败 ${projectPath}:`, error);\n // 清理失败不抛出错误,避免阻塞后续流程\n }\n}\n\n/**\n * 批量检查多个项目的存在状态\n * @param workspacePath 工作空间路径\n * @param projectNames 项目名称列表\n * @returns Promise<Record<string, boolean>> 项目名称到存在状态的映射\n */\nexport async function checkMultipleProjectsExist(\n workspacePath: string, \n projectNames: string[]\n): Promise<Record<string, boolean>> {\n const results: Record<string, boolean> = {};\n \n // 并行检查所有项目\n const checks = projectNames.map(async (projectName) => {\n const exists = await checkProjectExists(workspacePath, projectName);\n results[projectName] = exists;\n });\n \n await Promise.all(checks);\n return results;\n} \n","const unableToRmdirWarningPattern = /warning:\\s+unable to rmdir '([^']+)': Directory not empty/g;\n\nfunction normalizeGitPath(path: string) {\n return path\n .trim()\n .replace(/\\\\/g, '/')\n .replace(/^\\.\\/+/, '')\n .replace(/\\/+$/, '');\n}\n\nfunction parseStatusPath(line: string) {\n const rawPath = line.length >= 3 ? line.slice(3).trim() : '';\n if (!rawPath) return '';\n\n const unquoted = rawPath.startsWith('\"') && rawPath.endsWith('\"')\n ? rawPath.slice(1, -1)\n : rawPath;\n const renamedSeparator = ' -> ';\n const renamedIndex = unquoted.lastIndexOf(renamedSeparator);\n const targetPath = renamedIndex === -1\n ? unquoted\n : unquoted.slice(renamedIndex + renamedSeparator.length);\n\n return normalizeGitPath(targetPath);\n}\n\nexport function extractUnableToRmdirPaths(stderr: string) {\n const matchedPaths = new Set<string>();\n let match: RegExpExecArray | null;\n\n while ((match = unableToRmdirWarningPattern.exec(stderr)) !== null) {\n const normalizedPath = normalizeGitPath(match[1] || '');\n if (normalizedPath) {\n matchedPaths.add(normalizedPath);\n }\n }\n\n unableToRmdirWarningPattern.lastIndex = 0;\n return [...matchedPaths];\n}\n\nexport function appendIgnoredPathsFromCheckoutWarning(stderr: string, ignoredPaths: Set<string>) {\n const addedPaths: string[] = [];\n for (const path of extractUnableToRmdirPaths(stderr)) {\n if (!ignoredPaths.has(path)) {\n ignoredPaths.add(path);\n addedPaths.push(path);\n }\n }\n return addedPaths;\n}\n\nexport function hasBlockingWorkspaceChanges(statusOutput: string, ignoredUntrackedPaths?: Iterable<string>) {\n const ignoredPathSet = new Set<string>();\n if (ignoredUntrackedPaths) {\n for (const path of ignoredUntrackedPaths) {\n const normalizedPath = normalizeGitPath(path);\n if (normalizedPath) {\n ignoredPathSet.add(normalizedPath);\n }\n }\n }\n\n if (ignoredPathSet.size === 0) {\n return statusOutput.trim().length > 0;\n }\n\n const lines = statusOutput.split(/\\r?\\n/).filter(line => line.length > 0);\n for (const line of lines) {\n const statusCode = line.slice(0, 2);\n if (statusCode !== '??') {\n return true;\n }\n\n const statusPath = parseStatusPath(line);\n if (!statusPath) {\n return true;\n }\n\n let shouldIgnore = false;\n for (const ignoredPath of ignoredPathSet) {\n if (statusPath === ignoredPath || statusPath.startsWith(`${ignoredPath}/`)) {\n shouldIgnore = true;\n break;\n }\n }\n\n if (!shouldIgnore) {\n return true;\n }\n }\n\n return false;\n}\n","import { spawn } from 'child_process';\nimport { mkdtemp, rm } from 'fs/promises';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\n\ntype GitResult = {\n code: number | null;\n stdout: string;\n stderr: string;\n};\n\nasync function runGitCommand(cwd: string, args: string[]): Promise<GitResult> {\n return new Promise((resolve, reject) => {\n const child = spawn('git', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('close', (code) => {\n resolve({ code, stdout, stderr });\n });\n\n child.on('error', (error) => {\n reject(error);\n });\n });\n}\n\nfunction sanitizeProjectNameForTemp(projectName: string) {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '-');\n}\n\nexport type TempExecutionRepo = {\n tempRootPath: string;\n projectPath: string;\n};\n\nexport async function createTempExecutionRepo(sourceProjectPath: string, projectName: string): Promise<{\n success: true;\n value: TempExecutionRepo;\n} | {\n success: false;\n error: string;\n}> {\n const remoteResult = await runGitCommand(sourceProjectPath, ['remote', 'get-url', 'origin']);\n if (remoteResult.code !== 0) {\n return {\n success: false,\n error: remoteResult.stderr || remoteResult.stdout || '读取 origin 地址失败',\n };\n }\n\n const remoteUrl = remoteResult.stdout.trim();\n if (!remoteUrl) {\n return {\n success: false,\n error: 'origin 远端地址为空',\n };\n }\n\n const prefix = `prime-uat-${sanitizeProjectNameForTemp(projectName)}-`;\n const tempRootPath = await mkdtemp(join(tmpdir(), prefix));\n const tempProjectPath = join(tempRootPath, projectName);\n\n const cloneResult = await runGitCommand(tempRootPath, ['clone', '--no-tags', remoteUrl, tempProjectPath]);\n if (cloneResult.code !== 0) {\n await rm(tempRootPath, { recursive: true, force: true });\n return {\n success: false,\n error: cloneResult.stderr || cloneResult.stdout || '克隆临时仓库失败',\n };\n }\n\n return {\n success: true,\n value: {\n tempRootPath,\n projectPath: tempProjectPath,\n },\n };\n}\n\nexport async function cleanupTempExecutionRepo(tempRootPath: string) {\n await rm(tempRootPath, { recursive: true, force: true });\n}\n","type AbortState = {\n aborted: boolean;\n updatedAt: number;\n};\n\nconst abortStates = new Map<string, AbortState>();\nconst ABORT_STATE_TTL = 1000 * 60 * 30;\n\nfunction cleanupAbortStates() {\n const now = Date.now();\n for (const [runId, state] of abortStates.entries()) {\n if (now - state.updatedAt > ABORT_STATE_TTL) {\n abortStates.delete(runId);\n }\n }\n}\n\nexport function createUatGitFlowState(runId: string) {\n cleanupAbortStates();\n abortStates.set(runId, { aborted: false, updatedAt: Date.now() });\n}\n\nexport function markUatGitFlowAbort(runId: string) {\n const existing = abortStates.get(runId);\n abortStates.set(runId, {\n aborted: true,\n updatedAt: Date.now(),\n });\n if (!existing) {\n cleanupAbortStates();\n }\n}\n\nexport function isUatGitFlowAborted(runId: string) {\n cleanupAbortStates();\n return abortStates.get(runId)?.aborted ?? false;\n}\n\nexport function clearUatGitFlowState(runId: string) {\n abortStates.delete(runId);\n}\n"],"names":[],"mappings":"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"}
@@ -11,6 +11,6 @@ module.exports={83886:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("
11
11
  ${x}
12
12
  `);let n={...p,status:o.ProjectStatus.FAILED,progress:w,message:"克隆失败",error:r||`Git 进程退出,代码: ${t}`,endTime:s};u?.(`${d}: ${n.error}`),e(n)}}),f.on("error",t=>{clearTimeout(j),l?.(d,"stderr",`[进程错误] Git 进程启动失败: ${t.message}
13
13
  `),l?.(d,"stderr",`[错误详情] ${t.stack||"No stack trace"}
14
- `);let r={...p,status:o.ProjectStatus.FAILED,progress:w,message:"进程启动失败",error:`进程启动失败: ${t.message}`,endTime:Date.now()};u?.(`${d}: ${t.message}`),e(r)})})}function u(e){return/^(https?:\/\/|git@)[^\s]+\.git$/i.test(e)}function l(e){return e.replace(/[^a-zA-Z0-9\-_]/g,"")}async function d(e,t){try{let r=(0,i.join)(e,t);if(!(0,n.existsSync)(r))return{exists:!1,status:"not_exists",needsCleanup:!1};let s=(0,i.join)(r,".git");if(!(0,n.existsSync)(s))return{exists:!0,status:"incomplete",needsCleanup:!0};if(!await g(r))return console.log(`检测到不完整的Git仓库: ${r}`),{exists:!0,status:"incomplete",needsCleanup:!0};return{exists:!0,status:"complete",needsCleanup:!1}}catch(e){return console.error(`检查项目 ${t} 状态时出错:`,e),{exists:!1,status:"not_exists",needsCleanup:!1}}}async function p(e,t){return"complete"===(await d(e,t)).status}async function g(e){try{let t=(0,i.join)(e,".git");for(let e of["HEAD","config","refs"]){let r=(0,i.join)(t,e);if(!(0,n.existsSync)(r))return!1}let r=(await n.promises.readdir(e)).filter(e=>".git"!==e);if(0===r.length)return!1;let s=(0,i.join)(t,"HEAD"),o=await n.promises.readFile(s,"utf-8");if(!o.trim()||o.includes("unborn"))return!1;return!0}catch(e){return console.error("检查Git仓库完整性时出错:",e),!1}}async function m(e){try{console.log(`正在清理不完整的项目: ${e}`),await n.promises.rm(e,{recursive:!0,force:!0}),console.log(`清理完成: ${e}`)}catch(t){console.error(`清理项目失败 ${e}:`,t)}}async function f(e,t){let r={},s=t.map(async t=>{let s=await p(e,t);r[t]=s});return await Promise.all(s),r}},79810:e=>{"use strict";var{g:t,__dirname:r}=e;{e.s({clearUatGitFlowState:()=>a,createUatGitFlowState:()=>n,isUatGitFlowAborted:()=>o,markUatGitFlowAbort:()=>i});let t=new Map;function s(){let e=Date.now();for(let[r,s]of t.entries())e-s.updatedAt>18e5&&t.delete(r)}function n(e){s(),t.set(e,{aborted:!1,updatedAt:Date.now()})}function i(e){let r=t.get(e);t.set(e,{aborted:!0,updatedAt:Date.now()}),r||s()}function o(e){return s(),t.get(e)?.aborted??!1}function a(e){t.delete(e)}}},34926:e=>{"use strict";var{g:t,__dirname:r}=e;{e.s({appendIgnoredPathsFromCheckoutWarning:()=>i,extractUnableToRmdirPaths:()=>n,hasBlockingWorkspaceChanges:()=>o});let t=/warning:\s+unable to rmdir '([^']+)': Directory not empty/g;function s(e){return e.trim().replace(/\\/g,"/").replace(/^\.\/+/,"").replace(/\/+$/,"")}function n(e){let r,n=new Set;for(;null!==(r=t.exec(e));){let e=s(r[1]||"");e&&n.add(e)}return t.lastIndex=0,[...n]}function i(e,t){let r=[];for(let s of n(e))t.has(s)||(t.add(s),r.push(s));return r}function o(e,t){let r=new Set;if(t)for(let e of t){let t=s(e);t&&r.add(t)}if(0===r.size)return e.trim().length>0;for(let t of e.split(/\r?\n/).filter(e=>e.length>0)){if("??"!==t.slice(0,2))return!0;let e=function(e){let t=e.length>=3?e.slice(3).trim():"";if(!t)return"";let r=t.startsWith('"')&&t.endsWith('"')?t.slice(1,-1):t,n=" -> ",i=r.lastIndexOf(n);return s(-1===i?r:r.slice(i+n.length))}(t);if(!e)return!0;let n=!1;for(let t of r)if(e===t||e.startsWith(`${t}/`)){n=!0;break}if(!n)return!0}return!1}}},33808:e=>{"use strict";var{g:t,__dirname:r}=e;e.s({cleanupTempExecutionRepo:()=>u,createTempExecutionRepo:()=>c});var s=e.i(87485),n=e.i(9892),i=e.i(13442),o=e.i(30331);async function a(e,t){return new Promise((r,n)=>{let i=(0,s.spawn)("git",t,{cwd:e,stdio:["ignore","pipe","pipe"]}),o="",a="";i.stdout?.on("data",e=>{o+=e.toString()}),i.stderr?.on("data",e=>{a+=e.toString()}),i.on("close",e=>{r({code:e,stdout:o,stderr:a})}),i.on("error",e=>{n(e)})})}async function c(e,t){let r=await a(e,["remote","get-url","origin"]);if(0!==r.code)return{success:!1,error:r.stderr||r.stdout||"读取 origin 地址失败"};let s=r.stdout.trim();if(!s)return{success:!1,error:"origin 远端地址为空"};let c=`prime-uat-${t.replace(/[^a-zA-Z0-9\-_]/g,"-")}-`,u=await (0,n.mkdtemp)((0,o.join)((0,i.tmpdir)(),c)),l=(0,o.join)(u,t),d=await a(u,["clone","--no-tags",s,l]);return 0!==d.code?(await (0,n.rm)(u,{recursive:!0,force:!0}),{success:!1,error:d.stderr||d.stdout||"克隆临时仓库失败"}):{success:!0,value:{tempRootPath:u,projectPath:l}}}async function u(e){await (0,n.rm)(e,{recursive:!0,force:!0})}},26921:function(e){var{g:t,__dirname:r,m:s,e:n}=e}};
14
+ `);let r={...p,status:o.ProjectStatus.FAILED,progress:w,message:"进程启动失败",error:`进程启动失败: ${t.message}`,endTime:Date.now()};u?.(`${d}: ${t.message}`),e(r)})})}function u(e){return/^(https?:\/\/|git@)[^\s]+\.git$/i.test(e)}function l(e){return e.replace(/[^a-zA-Z0-9\-_]/g,"")}async function d(e,t){try{let r=(0,i.join)(e,t);if(!(0,n.existsSync)(r))return{exists:!1,status:"not_exists",needsCleanup:!1};let s=(0,i.join)(r,".git");if(!(0,n.existsSync)(s))return{exists:!0,status:"incomplete",needsCleanup:!0};if(!await g(r))return console.log(`检测到不完整的Git仓库: ${r}`),{exists:!0,status:"incomplete",needsCleanup:!0};return{exists:!0,status:"complete",needsCleanup:!1}}catch(e){return console.error(`检查项目 ${t} 状态时出错:`,e),{exists:!1,status:"not_exists",needsCleanup:!1}}}async function p(e,t){return"complete"===(await d(e,t)).status}async function g(e){try{let t=(0,i.join)(e,".git");for(let e of["HEAD","config","refs"]){let r=(0,i.join)(t,e);if(!(0,n.existsSync)(r))return!1}let r=(await n.promises.readdir(e)).filter(e=>".git"!==e);if(0===r.length)return!1;let s=(0,i.join)(t,"HEAD"),o=await n.promises.readFile(s,"utf-8");if(!o.trim()||o.includes("unborn"))return!1;return!0}catch(e){return console.error("检查Git仓库完整性时出错:",e),!1}}async function m(e){try{console.log(`正在清理不完整的项目: ${e}`),await n.promises.rm(e,{recursive:!0,force:!0}),console.log(`清理完成: ${e}`)}catch(t){console.error(`清理项目失败 ${e}:`,t)}}async function f(e,t){let r={},s=t.map(async t=>{let s=await p(e,t);r[t]=s});return await Promise.all(s),r}},34926:e=>{"use strict";var{g:t,__dirname:r}=e;{e.s({appendIgnoredPathsFromCheckoutWarning:()=>i,extractUnableToRmdirPaths:()=>n,hasBlockingWorkspaceChanges:()=>o});let t=/warning:\s+unable to rmdir '([^']+)': Directory not empty/g;function s(e){return e.trim().replace(/\\/g,"/").replace(/^\.\/+/,"").replace(/\/+$/,"")}function n(e){let r,n=new Set;for(;null!==(r=t.exec(e));){let e=s(r[1]||"");e&&n.add(e)}return t.lastIndex=0,[...n]}function i(e,t){let r=[];for(let s of n(e))t.has(s)||(t.add(s),r.push(s));return r}function o(e,t){let r=new Set;if(t)for(let e of t){let t=s(e);t&&r.add(t)}if(0===r.size)return e.trim().length>0;for(let t of e.split(/\r?\n/).filter(e=>e.length>0)){if("??"!==t.slice(0,2))return!0;let e=function(e){let t=e.length>=3?e.slice(3).trim():"";if(!t)return"";let r=t.startsWith('"')&&t.endsWith('"')?t.slice(1,-1):t,n=" -> ",i=r.lastIndexOf(n);return s(-1===i?r:r.slice(i+n.length))}(t);if(!e)return!0;let n=!1;for(let t of r)if(e===t||e.startsWith(`${t}/`)){n=!0;break}if(!n)return!0}return!1}}},33808:e=>{"use strict";var{g:t,__dirname:r}=e;e.s({cleanupTempExecutionRepo:()=>u,createTempExecutionRepo:()=>c});var s=e.i(87485),n=e.i(9892),i=e.i(13442),o=e.i(30331);async function a(e,t){return new Promise((r,n)=>{let i=(0,s.spawn)("git",t,{cwd:e,stdio:["ignore","pipe","pipe"]}),o="",a="";i.stdout?.on("data",e=>{o+=e.toString()}),i.stderr?.on("data",e=>{a+=e.toString()}),i.on("close",e=>{r({code:e,stdout:o,stderr:a})}),i.on("error",e=>{n(e)})})}async function c(e,t){let r=await a(e,["remote","get-url","origin"]);if(0!==r.code)return{success:!1,error:r.stderr||r.stdout||"读取 origin 地址失败"};let s=r.stdout.trim();if(!s)return{success:!1,error:"origin 远端地址为空"};let c=`prime-uat-${t.replace(/[^a-zA-Z0-9\-_]/g,"-")}-`,u=await (0,n.mkdtemp)((0,o.join)((0,i.tmpdir)(),c)),l=(0,o.join)(u,t),d=await a(u,["clone","--no-tags",s,l]);return 0!==d.code?(await (0,n.rm)(u,{recursive:!0,force:!0}),{success:!1,error:d.stderr||d.stdout||"克隆临时仓库失败"}):{success:!0,value:{tempRootPath:u,projectPath:l}}}async function u(e){await (0,n.rm)(e,{recursive:!0,force:!0})}},79810:e=>{"use strict";var{g:t,__dirname:r}=e;{e.s({clearUatGitFlowState:()=>a,createUatGitFlowState:()=>n,isUatGitFlowAborted:()=>o,markUatGitFlowAbort:()=>i});let t=new Map;function s(){let e=Date.now();for(let[r,s]of t.entries())e-s.updatedAt>18e5&&t.delete(r)}function n(e){s(),t.set(e,{aborted:!1,updatedAt:Date.now()})}function i(e){let r=t.get(e);t.set(e,{aborted:!0,updatedAt:Date.now()}),r||s()}function o(e){return s(),t.get(e)?.aborted??!1}function a(e){t.delete(e)}}},28814:function(e){var{g:t,__dirname:r,m:s,e:n}=e}};
15
15
 
16
- //# sourceMappingURL=%5Broot-of-the-server%5D__a8ae0f8f._.js.map
16
+ //# sourceMappingURL=%5Broot-of-the-server%5D__bc84f5d7._.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["turbopack:///[project]/packages/server/src/lib/workspace-types.ts","turbopack:///[project]/packages/server/src/lib/workspace-config.ts","turbopack:///[project]/packages/server/src/lib/git-operations.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/state.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/git-status-utils.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/temp-repo.ts"],"sourcesContent":["import { homedir, cpus } from 'os';\nimport { join } from 'path';\n\n/**\n * 工作空间配置常量\n */\nexport const WORKSPACE_CONFIG = {\n // 工作空间根目录路径\n WORKSPACE_ROOT: join(homedir(), 'Documents', 'prime-workspace'),\n\n // Git 操作超时时间 (毫秒)\n GIT_TIMEOUT: 300000, // 5分钟\n\n // 最大并发克隆数量(基于CPU核心数,最小2个,最大8个)\n MAX_CONCURRENT_CLONES: Math.max(2, Math.min(cpus().length, 8)),\n\n // 重试次数限制\n MAX_RETRY_ATTEMPTS: 3,\n} as const;\n\nexport const PROJECT_CONFIG_PATH = join(homedir(), '.prime-projects.json');\n\nexport interface ProjectConfig {\n repo: string;\n mockingIntercept?: boolean;\n mockOpen?: boolean;\n envs: {\n [envName: string]: {\n host: string;\n currentProxy: string;\n proxyEnv: {\n [key: string]: string;\n };\n envFileName: string;\n proxyKey: string;\n subApps?: string[];\n };\n };\n}\n\nexport interface ProjectsConfig {\n [projectName: string]: ProjectConfig;\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n INCOMPLETE = 'incomplete', // 不完整的项目,需要清理\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n onLog?: (projectName: string, logType: 'stdout' | 'stderr' | 'progress', content: string) => void;\n}\n","import { readFile, writeFile, access, constants, rename } from 'fs/promises';\nimport type { ProjectsConfig } from './workspace-types';\nimport { PROJECT_CONFIG_PATH } from './workspace-types';\n\n/**\n * 读取并解析项目配置文件\n * @returns {Promise<ProjectsConfig>} 项目配置对象\n */\nexport async function getProjectsConfig(): Promise<ProjectsConfig> {\n try {\n await access(PROJECT_CONFIG_PATH, constants.F_OK);\n } catch {\n // 文件不存在,创建并写入空对象\n await saveProjectsConfig({});\n return {};\n }\n\n try {\n const configContent = await readFile(PROJECT_CONFIG_PATH, 'utf-8');\n // 如果文件为空,返回空对象\n if (!configContent) {\n return {};\n }\n return JSON.parse(configContent);\n } catch (error) {\n console.error('读取或解析项目配置文件失败:', error);\n // 在出错时返回空对象或抛出错误,这里选择抛出以通知调用者\n throw new Error('无法加载项目配置');\n }\n}\n\n/**\n * 将项目配置写入文件(原子操作)\n * @param {ProjectsConfig} config - 要保存的配置对象\n */\nexport async function saveProjectsConfig(config: ProjectsConfig): Promise<void> {\n const tempConfigPath = PROJECT_CONFIG_PATH + '.tmp';\n try {\n await writeFile(tempConfigPath, JSON.stringify(config, null, 2), 'utf-8');\n await rename(tempConfigPath, PROJECT_CONFIG_PATH);\n } catch (error) {\n console.error('保存项目配置文件失败:', error);\n throw new Error('无法保存项目配置');\n }\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n}\n","import { spawn, ChildProcess } from 'child_process';\nimport { existsSync, mkdirSync } from 'fs';\nimport { promises as fs } from 'fs';\nimport { join, basename } from 'path';\nimport {\n ProjectStatus,\n type GitOperationConfig,\n type ProjectProgress,\n} from './workspace-types';\n\n/**\n * 创建工作空间目录\n * @param workspacePath 工作空间路径\n * @returns 创建结果\n */\nexport async function createWorkspaceDirectory(workspacePath: string): Promise<{ success: boolean; error?: string }> {\n try {\n if (!existsSync(workspacePath)) {\n mkdirSync(workspacePath, { recursive: true });\n }\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: `创建工作空间目录失败: ${error instanceof Error ? error.message : String(error)}` \n };\n }\n}\n\n/**\n * 执行 Git 克隆操作\n * @param config Git 操作配置\n * @returns Promise<ProjectProgress>\n */\nexport async function cloneRepository(config: GitOperationConfig): Promise<ProjectProgress> {\n const { repoUrl, projectName: configuredProjectName, targetDir, timeout, onProgress, onError, onLog } = config;\n const projectName = configuredProjectName?.trim() || basename(repoUrl, '.git');\n \n return new Promise<ProjectProgress>((resolve) => {\n const startTime = Date.now();\n \n // 更新开始状态\n const initialProgress: ProjectProgress = {\n projectName,\n status: ProjectStatus.CLONING,\n progress: 0,\n message: '开始克隆项目...',\n startTime,\n };\n onProgress?.(0, '开始克隆项目...');\n\n // 执行 git clone 命令\n const targetPath = join(targetDir, projectName);\n // 添加 --progress 参数来强制显示进度,--verbose 显示详细信息\n const gitArgs = ['clone', '--progress', '--verbose', repoUrl, targetPath];\n \n // 记录命令启动信息\n onLog?.(projectName, 'stdout', `[开始克隆] 执行命令: git ${gitArgs.join(' ')}\\n`);\n onLog?.(projectName, 'stdout', `[目标目录] ${targetPath}\\n`);\n onLog?.(projectName, 'stdout', `[仓库地址] ${repoUrl}\\n`);\n \n const gitProcess: ChildProcess = spawn('git', gitArgs, {\n cwd: targetDir,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n let errorOutput = '';\n let progressValue = 0;\n \n // 记录进程启动成功\n onLog?.(projectName, 'stdout', `[进程启动] Git 进程 PID: ${gitProcess.pid}\\n`);\n\n // 设置超时\n const timeoutId = setTimeout(() => {\n onLog?.(projectName, 'stderr', `[超时警告] Git 进程运行超过 ${timeout / 1000}s,即将终止\\n`);\n gitProcess.kill('SIGTERM');\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆操作超时',\n error: `克隆操作超时 (${timeout / 1000}s)`,\n endTime: Date.now(),\n };\n onLog?.(projectName, 'stderr', `[进程终止] 克隆操作超时\\n`);\n onError?.(`${projectName}: 克隆操作超时`);\n resolve(errorResult);\n }, timeout);\n\n // 处理标准输出\n gitProcess.stdout?.on('data', (data: Buffer) => {\n const stdoutText = data.toString();\n \n // 实时发送日志\n onLog?.(projectName, 'stdout', stdoutText);\n \n // 模拟进度更新(Git 克隆没有内置进度,这里基于时间估算)\n progressValue = Math.min(progressValue + 10, 80);\n onProgress?.(progressValue, '正在克隆代码...');\n });\n\n // 处理错误输出\n gitProcess.stderr?.on('data', (data: Buffer) => {\n const stderrText = data.toString();\n errorOutput += stderrText;\n \n // 判断是进度信息还是错误信息\n const isProgressInfo = stderrText.includes('remote:') || \n stderrText.includes('Receiving objects') || \n stderrText.includes('Resolving deltas') ||\n stderrText.includes('Counting objects') ||\n stderrText.includes('Enumerating objects') ||\n stderrText.includes('Compressing objects') ||\n stderrText.includes('upload-pack') ||\n stderrText.includes('POST git-') ||\n stderrText.includes('正克隆到') ||\n stderrText.includes('Cloning into');\n \n // 根据内容类型发送不同的日志\n if (isProgressInfo) {\n onLog?.(projectName, 'progress', stderrText);\n } else {\n onLog?.(projectName, 'stderr', stderrText);\n }\n \n // Git 的进度信息通常在 stderr 中\n if (stderrText.includes('Receiving objects') || stderrText.includes('Resolving deltas')) {\n progressValue = Math.min(progressValue + 5, 90);\n onProgress?.(progressValue, '正在接收对象...');\n } else if (stderrText.includes('Counting objects')) {\n progressValue = Math.min(progressValue + 2, 70);\n onProgress?.(progressValue, '正在计算对象...');\n } else if (stderrText.includes('Enumerating objects')) {\n progressValue = Math.min(progressValue + 2, 50);\n onProgress?.(progressValue, '正在枚举对象...');\n }\n });\n\n // 处理进程结束\n gitProcess.on('close', (code: number | null) => {\n clearTimeout(timeoutId);\n const endTime = Date.now();\n const duration = endTime - startTime;\n \n onLog?.(projectName, 'stdout', `[进程结束] Git 进程退出,代码: ${code},耗时: ${Math.round(duration / 1000)}s\\n`);\n \n if (code === 0) {\n // 克隆成功\n onLog?.(projectName, 'stdout', `[克隆成功] 项目已成功克隆到: ${targetPath}\\n`);\n const successResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.SUCCESS,\n progress: 100,\n message: '克隆完成',\n endTime,\n };\n onProgress?.(100, '克隆完成');\n resolve(successResult);\n } else {\n // 克隆失败\n const parsedError = parseGitError(errorOutput);\n onLog?.(projectName, 'stderr', `[克隆失败] 错误信息: ${parsedError}\\n`);\n onLog?.(projectName, 'stderr', `[完整错误输出]\\n${errorOutput}\\n`);\n \n const failureResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆失败',\n error: parsedError || `Git 进程退出,代码: ${code}`,\n endTime,\n };\n onError?.(`${projectName}: ${failureResult.error}`);\n resolve(failureResult);\n }\n });\n\n // 处理进程错误\n gitProcess.on('error', (error: Error) => {\n clearTimeout(timeoutId);\n onLog?.(projectName, 'stderr', `[进程错误] Git 进程启动失败: ${error.message}\\n`);\n onLog?.(projectName, 'stderr', `[错误详情] ${error.stack || 'No stack trace'}\\n`);\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '进程启动失败',\n error: `进程启动失败: ${error.message}`,\n endTime: Date.now(),\n };\n onError?.(`${projectName}: ${error.message}`);\n resolve(errorResult);\n });\n });\n}\n\n/**\n * 解析 Git 错误信息,提供用户友好的错误描述\n * @param errorOutput Git stderr 输出\n * @returns 用户友好的错误描述\n */\nfunction parseGitError(errorOutput: string): string {\n const lowerOutput = errorOutput.toLowerCase();\n \n if (lowerOutput.includes('authentication failed') || lowerOutput.includes('access denied')) {\n return '身份验证失败,请检查仓库访问权限';\n }\n \n if (lowerOutput.includes('repository not found') || lowerOutput.includes('not found')) {\n return '仓库不存在或无法访问';\n }\n \n if (lowerOutput.includes('network') || lowerOutput.includes('connection')) {\n return '网络连接问题,请检查网络设置';\n }\n \n if (lowerOutput.includes('timeout')) {\n return '网络超时,请重试';\n }\n \n if (lowerOutput.includes('permission denied')) {\n return '权限被拒绝,请检查文件系统权限';\n }\n \n if (lowerOutput.includes('already exists')) {\n return '目标目录已存在';\n }\n \n // 返回原始错误的前200个字符\n return errorOutput.slice(0, 200) + (errorOutput.length > 200 ? '...' : '');\n}\n\n/**\n * 验证 Git 仓库 URL 格式\n * @param url Git 仓库 URL\n * @returns 是否有效\n */\nexport function isValidGitUrl(url: string): boolean {\n const gitUrlPattern = /^(https?:\\/\\/|git@)[^\\s]+\\.git$/i;\n return gitUrlPattern.test(url);\n}\n\n/**\n * 清理项目名称,移除不安全字符\n * @param projectName 项目名称\n * @returns 清理后的项目名称\n */\nexport function sanitizeProjectName(projectName: string): string {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '');\n}\n\n/**\n * 项目检查结果类型\n */\nexport type ProjectCheckResult = {\n exists: boolean;\n status: 'not_exists' | 'complete' | 'incomplete';\n needsCleanup: boolean;\n};\n\n/**\n * 检查项目状态(详细版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<ProjectCheckResult> 详细的项目状态\n */\nexport async function checkProjectStatus(workspacePath: string, projectName: string): Promise<ProjectCheckResult> {\n try {\n const projectPath = join(workspacePath, projectName);\n \n // 检查项目目录是否存在\n if (!existsSync(projectPath)) {\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n \n // 检查是否为 Git 仓库(存在 .git 目录)\n const gitPath = join(projectPath, '.git');\n if (!existsSync(gitPath)) {\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n // 更严格的完整性检查\n const isComplete = await isGitRepositoryComplete(projectPath);\n if (!isComplete) {\n console.log(`检测到不完整的Git仓库: ${projectPath}`);\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n return {\n exists: true,\n status: 'complete',\n needsCleanup: false\n };\n } catch (error) {\n console.error(`检查项目 ${projectName} 状态时出错:`, error);\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n}\n\n/**\n * 检查项目是否已存在于工作空间中(兼容版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<boolean> 项目是否存在且为有效的 Git 仓库\n */\nexport async function checkProjectExists(workspacePath: string, projectName: string): Promise<boolean> {\n const result = await checkProjectStatus(workspacePath, projectName);\n return result.status === 'complete';\n}\n\n/**\n * 检查Git仓库是否完整\n * @param projectPath 项目路径\n * @returns Promise<boolean> 仓库是否完整\n */\nasync function isGitRepositoryComplete(projectPath: string): Promise<boolean> {\n try {\n const gitPath = join(projectPath, '.git');\n \n // 检查关键的Git文件是否存在\n const requiredFiles = ['HEAD', 'config', 'refs'];\n for (const file of requiredFiles) {\n const filePath = join(gitPath, file);\n if (!existsSync(filePath)) {\n return false;\n }\n }\n \n // 检查是否有实际的项目文件(不只是.git目录)\n const entries = await fs.readdir(projectPath);\n const nonGitFiles = entries.filter((entry: string) => entry !== '.git');\n \n // 如果只有.git目录,说明克隆未完成\n if (nonGitFiles.length === 0) {\n return false;\n }\n \n // 检查HEAD文件是否有效\n const headPath = join(gitPath, 'HEAD');\n const headContent = await fs.readFile(headPath, 'utf-8');\n if (!headContent.trim() || headContent.includes('unborn')) {\n return false;\n }\n \n return true;\n } catch (error) {\n console.error('检查Git仓库完整性时出错:', error);\n return false;\n }\n}\n\n/**\n * 清理不完整的项目目录\n * @param projectPath 项目路径\n */\nexport async function cleanupIncompleteProject(projectPath: string): Promise<void> {\n try {\n console.log(`正在清理不完整的项目: ${projectPath}`);\n await fs.rm(projectPath, { recursive: true, force: true });\n console.log(`清理完成: ${projectPath}`);\n } catch (error) {\n console.error(`清理项目失败 ${projectPath}:`, error);\n // 清理失败不抛出错误,避免阻塞后续流程\n }\n}\n\n/**\n * 批量检查多个项目的存在状态\n * @param workspacePath 工作空间路径\n * @param projectNames 项目名称列表\n * @returns Promise<Record<string, boolean>> 项目名称到存在状态的映射\n */\nexport async function checkMultipleProjectsExist(\n workspacePath: string, \n projectNames: string[]\n): Promise<Record<string, boolean>> {\n const results: Record<string, boolean> = {};\n \n // 并行检查所有项目\n const checks = projectNames.map(async (projectName) => {\n const exists = await checkProjectExists(workspacePath, projectName);\n results[projectName] = exists;\n });\n \n await Promise.all(checks);\n return results;\n} \n","type AbortState = {\n aborted: boolean;\n updatedAt: number;\n};\n\nconst abortStates = new Map<string, AbortState>();\nconst ABORT_STATE_TTL = 1000 * 60 * 30;\n\nfunction cleanupAbortStates() {\n const now = Date.now();\n for (const [runId, state] of abortStates.entries()) {\n if (now - state.updatedAt > ABORT_STATE_TTL) {\n abortStates.delete(runId);\n }\n }\n}\n\nexport function createUatGitFlowState(runId: string) {\n cleanupAbortStates();\n abortStates.set(runId, { aborted: false, updatedAt: Date.now() });\n}\n\nexport function markUatGitFlowAbort(runId: string) {\n const existing = abortStates.get(runId);\n abortStates.set(runId, {\n aborted: true,\n updatedAt: Date.now(),\n });\n if (!existing) {\n cleanupAbortStates();\n }\n}\n\nexport function isUatGitFlowAborted(runId: string) {\n cleanupAbortStates();\n return abortStates.get(runId)?.aborted ?? false;\n}\n\nexport function clearUatGitFlowState(runId: string) {\n abortStates.delete(runId);\n}\n","const unableToRmdirWarningPattern = /warning:\\s+unable to rmdir '([^']+)': Directory not empty/g;\n\nfunction normalizeGitPath(path: string) {\n return path\n .trim()\n .replace(/\\\\/g, '/')\n .replace(/^\\.\\/+/, '')\n .replace(/\\/+$/, '');\n}\n\nfunction parseStatusPath(line: string) {\n const rawPath = line.length >= 3 ? line.slice(3).trim() : '';\n if (!rawPath) return '';\n\n const unquoted = rawPath.startsWith('\"') && rawPath.endsWith('\"')\n ? rawPath.slice(1, -1)\n : rawPath;\n const renamedSeparator = ' -> ';\n const renamedIndex = unquoted.lastIndexOf(renamedSeparator);\n const targetPath = renamedIndex === -1\n ? unquoted\n : unquoted.slice(renamedIndex + renamedSeparator.length);\n\n return normalizeGitPath(targetPath);\n}\n\nexport function extractUnableToRmdirPaths(stderr: string) {\n const matchedPaths = new Set<string>();\n let match: RegExpExecArray | null;\n\n while ((match = unableToRmdirWarningPattern.exec(stderr)) !== null) {\n const normalizedPath = normalizeGitPath(match[1] || '');\n if (normalizedPath) {\n matchedPaths.add(normalizedPath);\n }\n }\n\n unableToRmdirWarningPattern.lastIndex = 0;\n return [...matchedPaths];\n}\n\nexport function appendIgnoredPathsFromCheckoutWarning(stderr: string, ignoredPaths: Set<string>) {\n const addedPaths: string[] = [];\n for (const path of extractUnableToRmdirPaths(stderr)) {\n if (!ignoredPaths.has(path)) {\n ignoredPaths.add(path);\n addedPaths.push(path);\n }\n }\n return addedPaths;\n}\n\nexport function hasBlockingWorkspaceChanges(statusOutput: string, ignoredUntrackedPaths?: Iterable<string>) {\n const ignoredPathSet = new Set<string>();\n if (ignoredUntrackedPaths) {\n for (const path of ignoredUntrackedPaths) {\n const normalizedPath = normalizeGitPath(path);\n if (normalizedPath) {\n ignoredPathSet.add(normalizedPath);\n }\n }\n }\n\n if (ignoredPathSet.size === 0) {\n return statusOutput.trim().length > 0;\n }\n\n const lines = statusOutput.split(/\\r?\\n/).filter(line => line.length > 0);\n for (const line of lines) {\n const statusCode = line.slice(0, 2);\n if (statusCode !== '??') {\n return true;\n }\n\n const statusPath = parseStatusPath(line);\n if (!statusPath) {\n return true;\n }\n\n let shouldIgnore = false;\n for (const ignoredPath of ignoredPathSet) {\n if (statusPath === ignoredPath || statusPath.startsWith(`${ignoredPath}/`)) {\n shouldIgnore = true;\n break;\n }\n }\n\n if (!shouldIgnore) {\n return true;\n }\n }\n\n return false;\n}\n","import { spawn } from 'child_process';\nimport { mkdtemp, rm } from 'fs/promises';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\n\ntype GitResult = {\n code: number | null;\n stdout: string;\n stderr: string;\n};\n\nasync function runGitCommand(cwd: string, args: string[]): Promise<GitResult> {\n return new Promise((resolve, reject) => {\n const child = spawn('git', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('close', (code) => {\n resolve({ code, stdout, stderr });\n });\n\n child.on('error', (error) => {\n reject(error);\n });\n });\n}\n\nfunction sanitizeProjectNameForTemp(projectName: string) {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '-');\n}\n\nexport type TempExecutionRepo = {\n tempRootPath: string;\n projectPath: string;\n};\n\nexport async function createTempExecutionRepo(sourceProjectPath: string, projectName: string): Promise<{\n success: true;\n value: TempExecutionRepo;\n} | {\n success: false;\n error: string;\n}> {\n const remoteResult = await runGitCommand(sourceProjectPath, ['remote', 'get-url', 'origin']);\n if (remoteResult.code !== 0) {\n return {\n success: false,\n error: remoteResult.stderr || remoteResult.stdout || '读取 origin 地址失败',\n };\n }\n\n const remoteUrl = remoteResult.stdout.trim();\n if (!remoteUrl) {\n return {\n success: false,\n error: 'origin 远端地址为空',\n };\n }\n\n const prefix = `prime-uat-${sanitizeProjectNameForTemp(projectName)}-`;\n const tempRootPath = await mkdtemp(join(tmpdir(), prefix));\n const tempProjectPath = join(tempRootPath, projectName);\n\n const cloneResult = await runGitCommand(tempRootPath, ['clone', '--no-tags', remoteUrl, tempProjectPath]);\n if (cloneResult.code !== 0) {\n await rm(tempRootPath, { recursive: true, force: true });\n return {\n success: false,\n error: cloneResult.stderr || cloneResult.stdout || '克隆临时仓库失败',\n };\n }\n\n return {\n success: true,\n value: {\n tempRootPath,\n projectPath: tempProjectPath,\n },\n };\n}\n\nexport async function cleanupTempExecutionRepo(tempRootPath: string) {\n await rm(tempRootPath, { recursive: true, force: true });\n}\n"],"names":[],"mappings":"ubAAA,IAAA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OAKO,IAAM,EAAmB,CAE9B,eAAgB,CAAA,EAAA,EAAA,IAAA,AAAG,EAAE,CAAA,EAAA,EAAA,OAAA,AAAM,IAAK,YAAa,EAA7B,WAAK,MAGrB,YAAa,IAGb,sBAAuB,KAAK,GAAG,CAAC,EAAG,KAAK,GAAG,CAAC,CAAA,EAAA,EAAA,IAAA,AAAG,IAAI,MAAM,CAAE,IAG3D,iBAH4C,EAGxB,CACtB,EAEa,EAAsB,CAAA,EAAA,EAAA,IAAA,AAAG,EAAE,CAAA,EAAA,EAAA,OAAA,AAAM,IAAK,cAAhB,UA2B5B,CA3BiC,GA2B5B,EAAA,SAAA,CAAA,6JAAA,s3CC/CZ,IAAA,EAAA,EAAA,CAAA,CAAA,MAEA,EAAA,EAAA,CAAA,CAAA,OAMO,eAAe,IACpB,GAAI,CACF,MAAM,CAAA,EAAA,EAAA,MAAA,AAAK,EAAE,EAAA,mBAAmB,CAAE,EAAA,GAA5B,MAAqC,CAAC,IAA/B,AAAmC,CAClD,CAAE,KAAM,CAGN,OADA,MAAM,AAH4B,EAGT,CAAC,GACnB,CAAC,CACV,CAEA,GAAI,CACF,IAAM,EAAgB,MAAM,CAAA,EAAA,EAAA,QAAA,AAAO,EAAE,EAAA,mBAAmB,CAAE,GAA9B,MAE5B,GAAI,CAAC,EACH,CAHmC,KAG5B,CAAC,EAEV,IAHoB,GAGb,KAAK,KAAK,CAAC,EACpB,CAAE,MAAO,EAAO,CAGd,MAFA,QAAQ,KAAK,CAAC,iBAAkB,GAE1B,AAAI,MAAM,WAClB,CACF,CAMO,eAAe,EAAmB,CAAsB,EAC7D,IAAM,EAAiB,EAAA,mBAAmB,CAAG,OAC7C,GAAI,CACF,KAFqB,CAEf,CAAA,EAAA,EAAA,SAAA,AAAQ,EAAE,EAAgB,KAAK,SAAS,CAAC,EAAQ,KAAjD,AAAuD,GAAI,SACjE,MAAM,GAAA,EAAA,MAAA,AAAK,EAAE,EAAgB,EAAA,mBAAmB,CAClD,CAAE,EADM,IACC,EAAO,CAEd,MAH6B,AAE7B,QAAQ,KAAK,CAAC,cAAe,GACvB,AAAI,MAAM,WAClB,CACF,CAKO,IAAK,EAAA,SAAA,CAAA,mIAAA,gYCjDZ,IAAA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OAEA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OAWO,eAAe,EAAyB,CAAqB,EAClE,GAAI,CAIF,MAHI,AAAC,CAAA,EAAA,EAAA,UAAA,AAAS,EAAE,IACd,GAAA,EAAA,OAD8B,EAC9B,AAAQ,EAAE,EAAe,CAAE,CADxB,UACmC,CAAK,GAEtC,CAAE,MAFP,GAEgB,CAAK,CACzB,CAAE,MAAO,EAAO,CACd,MAAO,CACL,SAAS,EACT,MAAO,CAAC,YAAY,EAAE,aAAiB,MAAQ,EAAM,OAAO,CAAG,OAAO,GAAA,CACxE,AADgF,CAElF,CACF,CAOO,eAAe,EAAgB,CAA0B,EAC9D,GAAM,SAAE,CAAO,CAAE,YAAa,CAAqB,WAAE,CAAS,SAAE,CAAO,YAAE,CAAU,SAAE,CAAO,OAAE,CAAK,CAAE,CAAG,EAClG,EAAc,GAAuB,QAAU,GAAA,EAAA,QAAA,AAAO,EAAE,EAAS,QAEvE,OAAO,IAAI,KAF0C,GAEhB,AAAD,IAClC,IAAM,EAAY,KAAK,GAAG,GAGpB,EAAmC,aACvC,EACA,OAAQ,EAAA,aAAa,CAAC,OAAO,CAC7B,SAAU,EACV,GAFQ,KAEC,sBACT,CACF,EACA,IAAa,EAAG,aAGhB,IAAM,EAAa,GAAA,EAAA,IAAA,AAAG,EAAE,EAAW,GAE7B,EAAU,CAAC,QAAS,aAAc,CAFrB,WAEkC,EAAS,EAAW,CAGzE,IAAQ,EAAa,SAAU,CAAC,iBAAiB,EAAE,EAAQ,IAAI,CAAC,KAAK;AAAE,CAAC,EACxE,IAAQ,EAAa,SAAU,CAAC,OAAO,EAAE,WAAW;AAAE,CAAC,EACvD,IAAQ,EAAa,SAAU,CAAC,OAAO,EAAE,QAAQ;AAAE,CAAC,EAEpD,IAAM,EAA2B,CAAA,EAAA,EAAA,KAAA,AAAI,EAAE,MAAO,EAAS,CACrD,IAAK,EACL,MAAO,CAAC,OAFuB,AAEf,OAAQ,OAAO,AACjC,GAEI,EAAc,GACd,EAAgB,EAGpB,IAAQ,EAAa,SAAU,CAAC,mBAAmB,EAAE,EAAW,GAAG,CAAC;AAAE,CAAC,EAGvE,IAAM,EAAY,WAAW,KAC3B,IAAQ,EAAa,SAAU,CAAC,kBAAkB,EAAE,EAAU,IAAK;AAAQ,CAAC,EAC5E,EAAW,IAAI,CAAC,WAEhB,IAAM,EAA+B,CACnC,GAAG,CAAe,CAClB,OAAQ,EAAA,aAAa,CAAC,MAAM,CAC5B,SAAU,EACV,IAFQ,IAEC,SACT,MAAO,CAAC,QAAQ,EAAE,EAAU,IAAK,EAAE,CAAC,CACpC,QAAS,KAAK,GAAG,EACnB,EACA,IAAQ,EAAa,SAAU,CAAC;AAAe,CAAC,EAChD,IAAU,CAAA,EAAG,EAAY,QAAQ,CAAC,EAClC,EAAQ,EACV,EAAG,GAGH,EAAW,MAAM,EAAE,GAAG,OAAQ,AAAC,IAC7B,IAAM,EAAa,EAAK,QAAQ,GAGhC,IAAQ,EAAa,SAAU,GAG/B,EAAgB,KAAK,GAAG,CAAC,EAAgB,GAAI,IAC7C,IAAa,EAAe,YAC9B,GAGA,EAAW,MAAM,EAAE,GAAG,OAAQ,AAAC,IAC7B,IAAM,EAAa,EAAK,QAAQ,GAChC,GAAe,EAGQ,EAAW,QAAQ,CAAC,YACtB,EAAW,QAAQ,CAAC,sBACpB,EAAW,QAAQ,CAAC,qBACpB,EAAW,QAAQ,CAAC,qBACpB,EAAW,QAAQ,CAAC,wBACpB,EAAW,QAAQ,CAAC,wBACpB,EAAW,QAAQ,CAAC,gBACpB,EAAW,QAAQ,CAAC,cACpB,EAAW,QAAQ,CAAC,SACpB,EAAW,QAAQ,CAAC,gBAIvC,IAAQ,EAAa,WAAY,GAEjC,IAAQ,EAAa,SAAU,GAI7B,EAAW,QAAQ,CAAC,sBAAwB,EAAW,QAAQ,CAAC,qBAAqB,AACvF,EAAgB,KAAK,GAAG,CAAC,EAAgB,EAAG,IAC5C,IAAa,EAAe,cACnB,EAAW,QAAQ,CAAC,qBAAqB,AAClD,EAAgB,KAAK,GAAG,CAAC,EAAgB,EAAG,IAC5C,IAAa,EAAe,cACnB,EAAW,QAAQ,CAAC,wBAAwB,CACrD,EAAgB,KAAK,GAAG,CAAC,EAAgB,EAAG,IAC5C,IAAa,EAAe,aAEhC,GAGA,EAAW,EAAE,CAAC,QAAU,AAAD,IACrB,aAAa,GACb,IAAM,EAAU,KAAK,GAAG,GAClB,EAAW,EAAU,EAI3B,GAFA,IAAQ,EAAa,SAAU,CAAC,oBAAoB,EAAE,EAAK,KAAK,EAAE,KAAK,KAAK,CAAC,EAAW,KAAM;AAAG,CAAC,EAErF,IAAT,EAAY,CAEd,IAAQ,EAAa,SAAU,CAAC,iBAAiB,EAAE,WAAW;AAAE,CAAC,EACjE,IAAM,EAAiC,CACrC,GAAG,CAAe,CAClB,OAAQ,EAAA,aAAa,CAAC,OAAO,CAC7B,SAAU,IACV,CAFQ,OAEC,eACT,CACF,EACA,IAAa,IAAK,QAClB,EAAQ,EACV,KAAO,CAEL,IAAM,EAAc,AA0C5B,SAAS,AAAc,CAAmB,EACxC,IAAM,EAAc,EAAY,WAAW,UAE3C,AAAI,EAAY,QAAQ,CAAC,0BAA4B,EAAY,QAAQ,CAAC,iBACjE,CADmF,kBAIxF,EAAY,QAAQ,CAAC,yBAA2B,EAAY,QAAQ,CAAC,aAChE,CAD8E,YAInF,EAAY,QAAQ,CAAC,YAAc,EAAY,QAAQ,CAAC,cACnD,CADkE,gBAIvE,EAAY,QAAQ,CAAC,WAChB,CAD4B,UAIjC,EAAY,QAAQ,CAAC,qBAChB,CADsC,iBAI3C,EAAY,QAAQ,CAAC,kBAChB,CADmC,SAKrC,EAAY,KAAK,CAAC,EAAG,MAAQ,CAAD,CAAa,MAAM,CAAG,IAAM,MAAQ,EAAA,CAAE,AAC3E,EAvE0C,GAClC,IAAQ,EAAa,SAAU,CAAC,aAAa,EAAE,YAAY;AAAE,CAAC,EAC9D,IAAQ,EAAa,SAAU,CAAC;AAAU,EAAE,YAAY;AAAE,CAAC,EAE3D,IAAM,EAAiC,CACrC,GAAG,CAAe,CAClB,OAAQ,EAAA,aAAa,CAAC,MAAM,CAC5B,SAAU,EACV,IAFQ,IAEC,OACT,MAAO,GAAe,CAAC,aAAa,EAAE,EAAA,CAAM,SAC5C,CACF,EACA,IAAU,CAAA,EAAG,EAAY,EAAE,EAAE,EAAc,KAAK,CAAA,CAAE,EAClD,EAAQ,EACV,CACF,GAGA,EAAW,EAAE,CAAC,QAAS,AAAC,IACtB,aAAa,GACb,IAAQ,EAAa,SAAU,CAAC,mBAAmB,EAAE,EAAM,OAAO,CAAC;AAAE,CAAC,EACtE,IAAQ,EAAa,SAAU,CAAC,OAAO,EAAE,EAAM,KAAK,EAAI,iBAAiB;AAAE,CAAC,EAE5E,IAAM,EAA+B,CACnC,GAAG,CAAe,CAClB,OAAQ,EAAA,aAAa,CAAC,MAAM,CAC5B,SAAU,EACV,IAFQ,IAEC,SACT,MAAO,CAAC,QAAQ,EAAE,EAAM,OAAO,CAAA,CAAE,CACjC,QAAS,KAAK,GAAG,EACnB,EACA,IAAU,CAAA,EAAG,EAAY,EAAE,EAAE,EAAM,OAAO,CAAA,CAAE,EAC5C,EAAQ,EACV,EACF,EACF,CA2CO,SAAS,EAAc,CAAW,EAEvC,MADsB,AACf,mCAAc,IAAI,CAAC,EAC5B,CAOO,SAAS,EAAoB,CAAmB,EACrD,OAAO,EAAY,OAAO,CAAC,mBAAoB,GACjD,CAiBO,eAAe,EAAmB,CAAqB,CAAE,CAAmB,EACjF,GAAI,CACF,IAAM,EAAc,CAAA,EAAA,EAAA,IAAA,AAAG,EAAE,EAAe,GAGxC,GAAI,CAAC,GAAA,EAAA,UAAA,AAAS,EAAE,GACd,CAJkB,KAIX,CACL,IAF0B,IAElB,EACR,IAHC,GAGO,aACR,cAAc,CAChB,EAIF,IAAM,EAAU,CAAA,EAAA,EAAA,IAAA,AAAG,EAAE,EAAa,QAClC,GAAI,CAAC,CAAA,EAAA,EAAA,UAAA,AAAS,CADE,CACA,GACd,MAAO,CADiB,AAEtB,QAAQ,EACR,IAHC,GAGO,aACR,cAAc,CAChB,EAKF,GAAI,CAAC,AADc,MAAM,EAAwB,GAG/C,CAFe,MACf,QAAQ,GAAG,CAAC,CAAC,cAAc,EAAE,EAAA,CAAa,EACnC,CACL,QAAQ,EACR,OAAQ,aACR,cAAc,CAChB,EAGF,MAAO,CACL,QAAQ,EACR,OAAQ,WACR,cAAc,CAChB,CACF,CAAE,MAAO,EAAO,CAEd,OADA,QAAQ,KAAK,CAAC,CAAC,KAAK,EAAE,EAAY,OAAO,CAAC,CAAE,GACrC,CACL,QAAQ,EACR,OAAQ,aACR,cAAc,CAChB,CACF,CACF,CAQO,eAAe,EAAmB,CAAqB,CAAE,CAAmB,EAEjF,MAAyB,aAAlB,CADQ,MAAM,EAAmB,EAAe,EAAA,EACzC,MAAM,AACtB,CAOA,eAAe,EAAwB,CAAmB,EACxD,GAAI,CACF,IAAM,EAAU,CAAA,EAAA,EAAA,IAAG,AAAH,EAAK,EAAa,QAIlC,IAAK,IAAM,IADW,CAAC,GACJ,IADY,AAHf,SAGyB,OAAO,CACd,CAChC,IAAM,EAAW,CAAA,EAAA,EAAA,IAAA,AAAG,EAAE,EAAS,GAC/B,GAAI,CAAC,CAAA,EAAA,EAAA,UAAA,AAAS,EAAE,GACd,CAFe,MAER,CADkB,AAG7B,CAIA,IAAM,EAAc,CADJ,KANT,CAMe,EAAA,QAAE,CAAC,OAAO,CAAC,EAAA,EACL,MAAM,CAAC,AAAC,GAAkB,AAAU,KAD1C,OAItB,GAA2B,GAAG,CAA1B,EAAY,MAAM,CACpB,OAAO,EAIT,IAAM,EAAW,CAAA,EAAA,EAAA,IAAG,AAAH,EAAK,EAAS,QACzB,EAAc,MAAM,EAAA,QAAE,CAAC,CADZ,OACoB,CAAC,EAAU,SAChD,GAAI,CAAC,EAAY,CADS,GACL,IAAM,EAAY,QAAQ,CAAC,UAC9C,CADyD,MAClD,EAGT,OAAO,CACT,CAAE,MAAO,EAAO,CAEd,OADA,QAAQ,KAAK,CAAC,iBAAkB,IACzB,CACT,CACF,CAMO,eAAe,EAAyB,CAAmB,EAChE,GAAI,CACF,QAAQ,GAAG,CAAC,CAAC,YAAY,EAAE,EAAA,CAAa,EACxC,MAAM,EAAA,QAAE,CAAC,EAAE,CAAC,EAAa,CAAE,UAAW,GAAM,OAAO,CAAK,AAAlD,GACN,QAAQ,GAAG,CAAC,CAAC,MAAM,EAAE,EAAA,CAAa,CACpC,CAAE,MAAO,EAAO,CACd,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,EAAY,CAAC,CAAC,CAAE,EAE1C,CACF,CAQO,eAAe,EACpB,CAAqB,CACrB,CAAsB,EAEtB,IAAM,EAAmC,CAAC,EAGpC,EAAS,EAAa,GAAG,CAAC,MAAO,IACrC,IAAM,EAAS,MAAM,EAAmB,EAAe,GACvD,CAAO,CAAC,EAAY,CAAG,CACzB,GAGA,OADA,MAAM,QAAQ,GAAG,CAAC,GACX,CACT,oKC/YA,IAAM,EAAc,IAAI,IAGxB,SAAS,IACP,IAAM,EAAM,KAAK,GAAG,GACpB,IAAK,GAAM,CAAC,EAAO,EAAM,GAAI,EAAY,OAAO,GAAI,AAC9C,EAAM,EAAM,SAAS,CALL,EAKQ,IAC1B,CANyB,CAMb,IANkB,EAMZ,CAAC,EAGzB,CAEO,CAN0C,QAMjC,EAAsB,CAAa,EACjD,IACA,EAAY,GAAG,CAAC,EAAO,CAAE,SAAS,EAAO,UAAW,KAAK,GAAG,EAAG,EACjE,CAEO,SAAS,EAAoB,CAAa,EAC/C,IAAM,EAAW,EAAY,GAAG,CAAC,GACjC,EAAY,GAAG,CAAC,EAAO,CACrB,SAAS,EACT,UAAW,KAAK,GAAG,EACrB,GACI,AAAC,GACH,GAEJ,CAEO,GALU,MAKD,EAAoB,CAAa,EAE/C,OADA,IACO,EAAY,GAAG,CAAC,IAAQ,UAAW,CAC5C,CAEO,SAAS,EAAqB,CAAa,EAChD,EAAY,MAAM,CAAC,EACrB,wKCxCA,IAAM,EAA8B,6DAEpC,SAAS,EAAiB,CAAY,EACpC,OAAO,EACJ,IAAI,GACJ,OAAO,CAAC,MAAO,KACf,OAAO,CAAC,SAAU,IAClB,OAAO,CAAC,OAAQ,GACrB,CAkBO,SAAS,EAA0B,CAAc,EACtD,IACI,EADE,EAAe,IAAI,IAGzB,KAAO,AAAuD,QAAtD,EAAQ,EAA4B,IAAI,CAAC,EAAA,CAAO,EAAY,CAClE,IAAM,EAAiB,EAAiB,CAAK,CAAC,EAAE,EAAI,GAChD,IACF,EAAa,GAAG,CAAC,EAErB,CAGA,GANsB,IAKtB,EAA4B,SAAS,CAAG,EACjC,IAAI,EAAa,AAC1B,CAEO,SAAS,EAAsC,CAAc,CAAE,CAAyB,EAC7F,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAQ,EAA0B,GACtC,EAAa,GADkC,AAC/B,CAAC,KACpB,EAD2B,AACd,GAAG,CAAC,GACjB,EAAW,IAAI,CAAC,IAGpB,OAAO,CACT,CAEO,SAAS,EAA4B,CAAoB,CAAE,CAAwC,EACxG,IAAM,EAAiB,IAAI,IAC3B,GAAI,EACF,IAAK,IAAM,KAAQ,EAAuB,CACxC,IAAM,CAFiB,CAEA,EAAiB,EACpC,IACF,EAAe,GAAG,CAAC,EAEvB,CAGF,GANwB,AAMI,GAAG,CAA3B,EAAe,IAAI,CACrB,OAAO,EAAa,IAAI,GAAG,MAAM,CAAG,EAItC,IAAK,IAAM,KADG,EAAa,CACR,IADa,CAAC,SAAS,MAAM,CAAC,GAAQ,EAAK,MAAM,CAAG,GAC7C,CAExB,GAAI,AAAe,MAAM,CADN,EAAK,KAAK,CAAC,EAAG,GAE/B,OAAO,EAGT,IAAM,EAhEV,AAgEuB,SAhEd,AAAgB,CAAY,EACnC,IAAM,EAAU,EAAK,MAAM,EAAI,EAAI,EAAK,KAAK,CAAC,GAAG,IAAI,GAAK,GAC1D,GAAI,CAAC,EAAS,MAAO,GAErB,IAAM,EAAW,EAAQ,UAAU,CAAC,MAAQ,EAAQ,QAAQ,CAAC,KACzD,EAAQ,KAAK,CAAC,EAAG,CAAC,GAClB,EACE,EAAmB,OACnB,EAAe,EAAS,WAAW,CAAC,GAK1C,OAAO,EAJ6B,CAAC,IAAlB,EACf,EACA,EAAS,IAEW,CAFN,CAAC,EAAe,EAAiB,MAAM,EAG3D,EAkDuC,GACnC,GAAI,CAAC,EACH,OAAO,EAGT,CAJiB,GAIb,GAAe,EACnB,IAAK,IAAM,KAAe,EACxB,GAAI,IAAe,GAAe,EAAW,CADL,SACe,CAAC,CAAA,EAAG,EAAY,CAAC,CAAC,EAAG,CAC1E,GAAe,EACf,KACF,CAGF,GAAI,CAAC,EACH,OAAO,CAEX,CAEA,GALqB,GAKd,EACT,sHC7FA,IAAA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,MACA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OAQA,eAAe,EAAc,CAAW,CAAE,CAAc,EACtD,OAAO,IAAI,QAAQ,CAAC,EAAS,KAC3B,IAAM,EAAQ,CAAA,EAAA,EAAA,KAAA,AAAI,EAAE,MAAO,EAAM,KAC/B,EACA,MAAO,CAAC,OAFI,EAEM,OAAQ,OAAO,AACnC,GAEI,EAAS,GACT,EAAS,GAEb,EAAM,MAAM,EAAE,GAAG,OAAQ,AAAC,IACxB,GAAU,EAAK,QAAQ,EACzB,GAEA,EAAM,MAAM,EAAE,GAAG,OAAQ,AAAC,IACxB,GAAU,EAAK,QAAQ,EACzB,GAEA,EAAM,EAAE,CAAC,QAAU,AAAD,IAChB,EAAQ,CAAE,OAAM,gBAAQ,CAAO,EACjC,GAEA,EAAM,EAAE,CAAC,QAAS,AAAC,IACjB,EAAO,EACT,EACF,EACF,CAWO,eAAe,EAAwB,CAAyB,CAAE,CAAmB,EAO1F,IAAM,EAAe,MAAM,EAAc,EAAmB,CAAC,SAAU,UAAW,SAAS,EAC3F,GAA0B,GAAG,CAAzB,EAAa,IAAI,CACnB,MAAO,CACL,SAAS,EACT,MAAO,EAAa,MAAM,EAAI,EAAa,MAAM,EAAI,gBACvD,EAGF,IAAM,EAAY,EAAa,MAAM,CAAC,IAAI,GAC1C,GAAI,CAAC,EACH,MAAO,CACL,EAFY,OAEH,EACT,MAAO,eACT,EAGF,IAAM,EAAS,CAAC,UAAU,EAAE,AAA2B,AA/BhD,EAAY,OAAO,CAAC,mBAAoB,KA+BqB,CAAC,CAAC,CAChE,EAAe,MAAM,CAAA,EAAA,EAAA,OAAA,AAAM,EAAE,CAAA,EAAA,EAAA,IAAA,AAAG,EAAE,CAAA,EAAA,EAAA,MAAA,AAAK,IAAlB,AAAuB,IAC5C,EAAkB,CAAA,EAAA,EAAA,IADW,AACX,AAAG,EAAE,EAAc,GAErC,EAAc,EAHoB,IAGd,EAAc,EAAc,CAAC,QAAS,IAFxC,QAEqD,EAAW,EAAgB,SACxG,AAAyB,GAAG,CAAxB,EAAY,IAAI,EAClB,MAAM,CAAA,EAAA,EAAA,EAAA,AAAC,EAAE,EAAc,CAAE,UAAW,GAAM,OAAO,CAAK,GAC/C,CACL,GAFI,MAEK,EACT,MAAO,EAAY,MAAM,EAAI,EAAY,MAAM,EAAI,UACrD,GAGK,CACL,SAAS,EACT,MAAO,cACL,EACA,YAAa,CACf,CACF,CACF,CAEO,eAAe,EAAyB,CAAoB,EACjE,MAAM,CAAA,EAAA,EAAA,EAAA,AAAC,EAAE,EAAc,CAAE,WAAW,EAAM,OAAO,CAAK,EACxD,KADQ"}
1
+ {"version":3,"sources":["turbopack:///[project]/packages/server/src/lib/workspace-types.ts","turbopack:///[project]/packages/server/src/lib/workspace-config.ts","turbopack:///[project]/packages/server/src/lib/git-operations.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/git-status-utils.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/temp-repo.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/state.ts"],"sourcesContent":["import { homedir, cpus } from 'os';\nimport { join } from 'path';\n\n/**\n * 工作空间配置常量\n */\nexport const WORKSPACE_CONFIG = {\n // 工作空间根目录路径\n WORKSPACE_ROOT: join(homedir(), 'Documents', 'prime-workspace'),\n\n // Git 操作超时时间 (毫秒)\n GIT_TIMEOUT: 300000, // 5分钟\n\n // 最大并发克隆数量(基于CPU核心数,最小2个,最大8个)\n MAX_CONCURRENT_CLONES: Math.max(2, Math.min(cpus().length, 8)),\n\n // 重试次数限制\n MAX_RETRY_ATTEMPTS: 3,\n} as const;\n\nexport const PROJECT_CONFIG_PATH = join(homedir(), '.prime-projects.json');\n\nexport interface ProjectConfig {\n repo: string;\n mockingIntercept?: boolean;\n mockOpen?: boolean;\n envs: {\n [envName: string]: {\n host: string;\n currentProxy: string;\n proxyEnv: {\n [key: string]: string;\n };\n envFileName: string;\n proxyKey: string;\n subApps?: string[];\n };\n };\n}\n\nexport interface ProjectsConfig {\n [projectName: string]: ProjectConfig;\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n INCOMPLETE = 'incomplete', // 不完整的项目,需要清理\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n onLog?: (projectName: string, logType: 'stdout' | 'stderr' | 'progress', content: string) => void;\n}\n","import { readFile, writeFile, access, constants, rename } from 'fs/promises';\nimport type { ProjectsConfig } from './workspace-types';\nimport { PROJECT_CONFIG_PATH } from './workspace-types';\n\n/**\n * 读取并解析项目配置文件\n * @returns {Promise<ProjectsConfig>} 项目配置对象\n */\nexport async function getProjectsConfig(): Promise<ProjectsConfig> {\n try {\n await access(PROJECT_CONFIG_PATH, constants.F_OK);\n } catch {\n // 文件不存在,创建并写入空对象\n await saveProjectsConfig({});\n return {};\n }\n\n try {\n const configContent = await readFile(PROJECT_CONFIG_PATH, 'utf-8');\n // 如果文件为空,返回空对象\n if (!configContent) {\n return {};\n }\n return JSON.parse(configContent);\n } catch (error) {\n console.error('读取或解析项目配置文件失败:', error);\n // 在出错时返回空对象或抛出错误,这里选择抛出以通知调用者\n throw new Error('无法加载项目配置');\n }\n}\n\n/**\n * 将项目配置写入文件(原子操作)\n * @param {ProjectsConfig} config - 要保存的配置对象\n */\nexport async function saveProjectsConfig(config: ProjectsConfig): Promise<void> {\n const tempConfigPath = PROJECT_CONFIG_PATH + '.tmp';\n try {\n await writeFile(tempConfigPath, JSON.stringify(config, null, 2), 'utf-8');\n await rename(tempConfigPath, PROJECT_CONFIG_PATH);\n } catch (error) {\n console.error('保存项目配置文件失败:', error);\n throw new Error('无法保存项目配置');\n }\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n}\n","import { spawn, ChildProcess } from 'child_process';\nimport { existsSync, mkdirSync } from 'fs';\nimport { promises as fs } from 'fs';\nimport { join, basename } from 'path';\nimport {\n ProjectStatus,\n type GitOperationConfig,\n type ProjectProgress,\n} from './workspace-types';\n\n/**\n * 创建工作空间目录\n * @param workspacePath 工作空间路径\n * @returns 创建结果\n */\nexport async function createWorkspaceDirectory(workspacePath: string): Promise<{ success: boolean; error?: string }> {\n try {\n if (!existsSync(workspacePath)) {\n mkdirSync(workspacePath, { recursive: true });\n }\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: `创建工作空间目录失败: ${error instanceof Error ? error.message : String(error)}` \n };\n }\n}\n\n/**\n * 执行 Git 克隆操作\n * @param config Git 操作配置\n * @returns Promise<ProjectProgress>\n */\nexport async function cloneRepository(config: GitOperationConfig): Promise<ProjectProgress> {\n const { repoUrl, projectName: configuredProjectName, targetDir, timeout, onProgress, onError, onLog } = config;\n const projectName = configuredProjectName?.trim() || basename(repoUrl, '.git');\n \n return new Promise<ProjectProgress>((resolve) => {\n const startTime = Date.now();\n \n // 更新开始状态\n const initialProgress: ProjectProgress = {\n projectName,\n status: ProjectStatus.CLONING,\n progress: 0,\n message: '开始克隆项目...',\n startTime,\n };\n onProgress?.(0, '开始克隆项目...');\n\n // 执行 git clone 命令\n const targetPath = join(targetDir, projectName);\n // 添加 --progress 参数来强制显示进度,--verbose 显示详细信息\n const gitArgs = ['clone', '--progress', '--verbose', repoUrl, targetPath];\n \n // 记录命令启动信息\n onLog?.(projectName, 'stdout', `[开始克隆] 执行命令: git ${gitArgs.join(' ')}\\n`);\n onLog?.(projectName, 'stdout', `[目标目录] ${targetPath}\\n`);\n onLog?.(projectName, 'stdout', `[仓库地址] ${repoUrl}\\n`);\n \n const gitProcess: ChildProcess = spawn('git', gitArgs, {\n cwd: targetDir,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n let errorOutput = '';\n let progressValue = 0;\n \n // 记录进程启动成功\n onLog?.(projectName, 'stdout', `[进程启动] Git 进程 PID: ${gitProcess.pid}\\n`);\n\n // 设置超时\n const timeoutId = setTimeout(() => {\n onLog?.(projectName, 'stderr', `[超时警告] Git 进程运行超过 ${timeout / 1000}s,即将终止\\n`);\n gitProcess.kill('SIGTERM');\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆操作超时',\n error: `克隆操作超时 (${timeout / 1000}s)`,\n endTime: Date.now(),\n };\n onLog?.(projectName, 'stderr', `[进程终止] 克隆操作超时\\n`);\n onError?.(`${projectName}: 克隆操作超时`);\n resolve(errorResult);\n }, timeout);\n\n // 处理标准输出\n gitProcess.stdout?.on('data', (data: Buffer) => {\n const stdoutText = data.toString();\n \n // 实时发送日志\n onLog?.(projectName, 'stdout', stdoutText);\n \n // 模拟进度更新(Git 克隆没有内置进度,这里基于时间估算)\n progressValue = Math.min(progressValue + 10, 80);\n onProgress?.(progressValue, '正在克隆代码...');\n });\n\n // 处理错误输出\n gitProcess.stderr?.on('data', (data: Buffer) => {\n const stderrText = data.toString();\n errorOutput += stderrText;\n \n // 判断是进度信息还是错误信息\n const isProgressInfo = stderrText.includes('remote:') || \n stderrText.includes('Receiving objects') || \n stderrText.includes('Resolving deltas') ||\n stderrText.includes('Counting objects') ||\n stderrText.includes('Enumerating objects') ||\n stderrText.includes('Compressing objects') ||\n stderrText.includes('upload-pack') ||\n stderrText.includes('POST git-') ||\n stderrText.includes('正克隆到') ||\n stderrText.includes('Cloning into');\n \n // 根据内容类型发送不同的日志\n if (isProgressInfo) {\n onLog?.(projectName, 'progress', stderrText);\n } else {\n onLog?.(projectName, 'stderr', stderrText);\n }\n \n // Git 的进度信息通常在 stderr 中\n if (stderrText.includes('Receiving objects') || stderrText.includes('Resolving deltas')) {\n progressValue = Math.min(progressValue + 5, 90);\n onProgress?.(progressValue, '正在接收对象...');\n } else if (stderrText.includes('Counting objects')) {\n progressValue = Math.min(progressValue + 2, 70);\n onProgress?.(progressValue, '正在计算对象...');\n } else if (stderrText.includes('Enumerating objects')) {\n progressValue = Math.min(progressValue + 2, 50);\n onProgress?.(progressValue, '正在枚举对象...');\n }\n });\n\n // 处理进程结束\n gitProcess.on('close', (code: number | null) => {\n clearTimeout(timeoutId);\n const endTime = Date.now();\n const duration = endTime - startTime;\n \n onLog?.(projectName, 'stdout', `[进程结束] Git 进程退出,代码: ${code},耗时: ${Math.round(duration / 1000)}s\\n`);\n \n if (code === 0) {\n // 克隆成功\n onLog?.(projectName, 'stdout', `[克隆成功] 项目已成功克隆到: ${targetPath}\\n`);\n const successResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.SUCCESS,\n progress: 100,\n message: '克隆完成',\n endTime,\n };\n onProgress?.(100, '克隆完成');\n resolve(successResult);\n } else {\n // 克隆失败\n const parsedError = parseGitError(errorOutput);\n onLog?.(projectName, 'stderr', `[克隆失败] 错误信息: ${parsedError}\\n`);\n onLog?.(projectName, 'stderr', `[完整错误输出]\\n${errorOutput}\\n`);\n \n const failureResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆失败',\n error: parsedError || `Git 进程退出,代码: ${code}`,\n endTime,\n };\n onError?.(`${projectName}: ${failureResult.error}`);\n resolve(failureResult);\n }\n });\n\n // 处理进程错误\n gitProcess.on('error', (error: Error) => {\n clearTimeout(timeoutId);\n onLog?.(projectName, 'stderr', `[进程错误] Git 进程启动失败: ${error.message}\\n`);\n onLog?.(projectName, 'stderr', `[错误详情] ${error.stack || 'No stack trace'}\\n`);\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '进程启动失败',\n error: `进程启动失败: ${error.message}`,\n endTime: Date.now(),\n };\n onError?.(`${projectName}: ${error.message}`);\n resolve(errorResult);\n });\n });\n}\n\n/**\n * 解析 Git 错误信息,提供用户友好的错误描述\n * @param errorOutput Git stderr 输出\n * @returns 用户友好的错误描述\n */\nfunction parseGitError(errorOutput: string): string {\n const lowerOutput = errorOutput.toLowerCase();\n \n if (lowerOutput.includes('authentication failed') || lowerOutput.includes('access denied')) {\n return '身份验证失败,请检查仓库访问权限';\n }\n \n if (lowerOutput.includes('repository not found') || lowerOutput.includes('not found')) {\n return '仓库不存在或无法访问';\n }\n \n if (lowerOutput.includes('network') || lowerOutput.includes('connection')) {\n return '网络连接问题,请检查网络设置';\n }\n \n if (lowerOutput.includes('timeout')) {\n return '网络超时,请重试';\n }\n \n if (lowerOutput.includes('permission denied')) {\n return '权限被拒绝,请检查文件系统权限';\n }\n \n if (lowerOutput.includes('already exists')) {\n return '目标目录已存在';\n }\n \n // 返回原始错误的前200个字符\n return errorOutput.slice(0, 200) + (errorOutput.length > 200 ? '...' : '');\n}\n\n/**\n * 验证 Git 仓库 URL 格式\n * @param url Git 仓库 URL\n * @returns 是否有效\n */\nexport function isValidGitUrl(url: string): boolean {\n const gitUrlPattern = /^(https?:\\/\\/|git@)[^\\s]+\\.git$/i;\n return gitUrlPattern.test(url);\n}\n\n/**\n * 清理项目名称,移除不安全字符\n * @param projectName 项目名称\n * @returns 清理后的项目名称\n */\nexport function sanitizeProjectName(projectName: string): string {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '');\n}\n\n/**\n * 项目检查结果类型\n */\nexport type ProjectCheckResult = {\n exists: boolean;\n status: 'not_exists' | 'complete' | 'incomplete';\n needsCleanup: boolean;\n};\n\n/**\n * 检查项目状态(详细版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<ProjectCheckResult> 详细的项目状态\n */\nexport async function checkProjectStatus(workspacePath: string, projectName: string): Promise<ProjectCheckResult> {\n try {\n const projectPath = join(workspacePath, projectName);\n \n // 检查项目目录是否存在\n if (!existsSync(projectPath)) {\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n \n // 检查是否为 Git 仓库(存在 .git 目录)\n const gitPath = join(projectPath, '.git');\n if (!existsSync(gitPath)) {\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n // 更严格的完整性检查\n const isComplete = await isGitRepositoryComplete(projectPath);\n if (!isComplete) {\n console.log(`检测到不完整的Git仓库: ${projectPath}`);\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n return {\n exists: true,\n status: 'complete',\n needsCleanup: false\n };\n } catch (error) {\n console.error(`检查项目 ${projectName} 状态时出错:`, error);\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n}\n\n/**\n * 检查项目是否已存在于工作空间中(兼容版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<boolean> 项目是否存在且为有效的 Git 仓库\n */\nexport async function checkProjectExists(workspacePath: string, projectName: string): Promise<boolean> {\n const result = await checkProjectStatus(workspacePath, projectName);\n return result.status === 'complete';\n}\n\n/**\n * 检查Git仓库是否完整\n * @param projectPath 项目路径\n * @returns Promise<boolean> 仓库是否完整\n */\nasync function isGitRepositoryComplete(projectPath: string): Promise<boolean> {\n try {\n const gitPath = join(projectPath, '.git');\n \n // 检查关键的Git文件是否存在\n const requiredFiles = ['HEAD', 'config', 'refs'];\n for (const file of requiredFiles) {\n const filePath = join(gitPath, file);\n if (!existsSync(filePath)) {\n return false;\n }\n }\n \n // 检查是否有实际的项目文件(不只是.git目录)\n const entries = await fs.readdir(projectPath);\n const nonGitFiles = entries.filter((entry: string) => entry !== '.git');\n \n // 如果只有.git目录,说明克隆未完成\n if (nonGitFiles.length === 0) {\n return false;\n }\n \n // 检查HEAD文件是否有效\n const headPath = join(gitPath, 'HEAD');\n const headContent = await fs.readFile(headPath, 'utf-8');\n if (!headContent.trim() || headContent.includes('unborn')) {\n return false;\n }\n \n return true;\n } catch (error) {\n console.error('检查Git仓库完整性时出错:', error);\n return false;\n }\n}\n\n/**\n * 清理不完整的项目目录\n * @param projectPath 项目路径\n */\nexport async function cleanupIncompleteProject(projectPath: string): Promise<void> {\n try {\n console.log(`正在清理不完整的项目: ${projectPath}`);\n await fs.rm(projectPath, { recursive: true, force: true });\n console.log(`清理完成: ${projectPath}`);\n } catch (error) {\n console.error(`清理项目失败 ${projectPath}:`, error);\n // 清理失败不抛出错误,避免阻塞后续流程\n }\n}\n\n/**\n * 批量检查多个项目的存在状态\n * @param workspacePath 工作空间路径\n * @param projectNames 项目名称列表\n * @returns Promise<Record<string, boolean>> 项目名称到存在状态的映射\n */\nexport async function checkMultipleProjectsExist(\n workspacePath: string, \n projectNames: string[]\n): Promise<Record<string, boolean>> {\n const results: Record<string, boolean> = {};\n \n // 并行检查所有项目\n const checks = projectNames.map(async (projectName) => {\n const exists = await checkProjectExists(workspacePath, projectName);\n results[projectName] = exists;\n });\n \n await Promise.all(checks);\n return results;\n} \n","const unableToRmdirWarningPattern = /warning:\\s+unable to rmdir '([^']+)': Directory not empty/g;\n\nfunction normalizeGitPath(path: string) {\n return path\n .trim()\n .replace(/\\\\/g, '/')\n .replace(/^\\.\\/+/, '')\n .replace(/\\/+$/, '');\n}\n\nfunction parseStatusPath(line: string) {\n const rawPath = line.length >= 3 ? line.slice(3).trim() : '';\n if (!rawPath) return '';\n\n const unquoted = rawPath.startsWith('\"') && rawPath.endsWith('\"')\n ? rawPath.slice(1, -1)\n : rawPath;\n const renamedSeparator = ' -> ';\n const renamedIndex = unquoted.lastIndexOf(renamedSeparator);\n const targetPath = renamedIndex === -1\n ? unquoted\n : unquoted.slice(renamedIndex + renamedSeparator.length);\n\n return normalizeGitPath(targetPath);\n}\n\nexport function extractUnableToRmdirPaths(stderr: string) {\n const matchedPaths = new Set<string>();\n let match: RegExpExecArray | null;\n\n while ((match = unableToRmdirWarningPattern.exec(stderr)) !== null) {\n const normalizedPath = normalizeGitPath(match[1] || '');\n if (normalizedPath) {\n matchedPaths.add(normalizedPath);\n }\n }\n\n unableToRmdirWarningPattern.lastIndex = 0;\n return [...matchedPaths];\n}\n\nexport function appendIgnoredPathsFromCheckoutWarning(stderr: string, ignoredPaths: Set<string>) {\n const addedPaths: string[] = [];\n for (const path of extractUnableToRmdirPaths(stderr)) {\n if (!ignoredPaths.has(path)) {\n ignoredPaths.add(path);\n addedPaths.push(path);\n }\n }\n return addedPaths;\n}\n\nexport function hasBlockingWorkspaceChanges(statusOutput: string, ignoredUntrackedPaths?: Iterable<string>) {\n const ignoredPathSet = new Set<string>();\n if (ignoredUntrackedPaths) {\n for (const path of ignoredUntrackedPaths) {\n const normalizedPath = normalizeGitPath(path);\n if (normalizedPath) {\n ignoredPathSet.add(normalizedPath);\n }\n }\n }\n\n if (ignoredPathSet.size === 0) {\n return statusOutput.trim().length > 0;\n }\n\n const lines = statusOutput.split(/\\r?\\n/).filter(line => line.length > 0);\n for (const line of lines) {\n const statusCode = line.slice(0, 2);\n if (statusCode !== '??') {\n return true;\n }\n\n const statusPath = parseStatusPath(line);\n if (!statusPath) {\n return true;\n }\n\n let shouldIgnore = false;\n for (const ignoredPath of ignoredPathSet) {\n if (statusPath === ignoredPath || statusPath.startsWith(`${ignoredPath}/`)) {\n shouldIgnore = true;\n break;\n }\n }\n\n if (!shouldIgnore) {\n return true;\n }\n }\n\n return false;\n}\n","import { spawn } from 'child_process';\nimport { mkdtemp, rm } from 'fs/promises';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\n\ntype GitResult = {\n code: number | null;\n stdout: string;\n stderr: string;\n};\n\nasync function runGitCommand(cwd: string, args: string[]): Promise<GitResult> {\n return new Promise((resolve, reject) => {\n const child = spawn('git', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('close', (code) => {\n resolve({ code, stdout, stderr });\n });\n\n child.on('error', (error) => {\n reject(error);\n });\n });\n}\n\nfunction sanitizeProjectNameForTemp(projectName: string) {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '-');\n}\n\nexport type TempExecutionRepo = {\n tempRootPath: string;\n projectPath: string;\n};\n\nexport async function createTempExecutionRepo(sourceProjectPath: string, projectName: string): Promise<{\n success: true;\n value: TempExecutionRepo;\n} | {\n success: false;\n error: string;\n}> {\n const remoteResult = await runGitCommand(sourceProjectPath, ['remote', 'get-url', 'origin']);\n if (remoteResult.code !== 0) {\n return {\n success: false,\n error: remoteResult.stderr || remoteResult.stdout || '读取 origin 地址失败',\n };\n }\n\n const remoteUrl = remoteResult.stdout.trim();\n if (!remoteUrl) {\n return {\n success: false,\n error: 'origin 远端地址为空',\n };\n }\n\n const prefix = `prime-uat-${sanitizeProjectNameForTemp(projectName)}-`;\n const tempRootPath = await mkdtemp(join(tmpdir(), prefix));\n const tempProjectPath = join(tempRootPath, projectName);\n\n const cloneResult = await runGitCommand(tempRootPath, ['clone', '--no-tags', remoteUrl, tempProjectPath]);\n if (cloneResult.code !== 0) {\n await rm(tempRootPath, { recursive: true, force: true });\n return {\n success: false,\n error: cloneResult.stderr || cloneResult.stdout || '克隆临时仓库失败',\n };\n }\n\n return {\n success: true,\n value: {\n tempRootPath,\n projectPath: tempProjectPath,\n },\n };\n}\n\nexport async function cleanupTempExecutionRepo(tempRootPath: string) {\n await rm(tempRootPath, { recursive: true, force: true });\n}\n","type AbortState = {\n aborted: boolean;\n updatedAt: number;\n};\n\nconst abortStates = new Map<string, AbortState>();\nconst ABORT_STATE_TTL = 1000 * 60 * 30;\n\nfunction cleanupAbortStates() {\n const now = Date.now();\n for (const [runId, state] of abortStates.entries()) {\n if (now - state.updatedAt > ABORT_STATE_TTL) {\n abortStates.delete(runId);\n }\n }\n}\n\nexport function createUatGitFlowState(runId: string) {\n cleanupAbortStates();\n abortStates.set(runId, { aborted: false, updatedAt: Date.now() });\n}\n\nexport function markUatGitFlowAbort(runId: string) {\n const existing = abortStates.get(runId);\n abortStates.set(runId, {\n aborted: true,\n updatedAt: Date.now(),\n });\n if (!existing) {\n cleanupAbortStates();\n }\n}\n\nexport function isUatGitFlowAborted(runId: string) {\n cleanupAbortStates();\n return abortStates.get(runId)?.aborted ?? false;\n}\n\nexport function clearUatGitFlowState(runId: string) {\n abortStates.delete(runId);\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ module.exports={83886:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("fs",()=>require("fs"))},45935:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},88941:e=>{"use strict";var{g:t,__dirname:r}=e;{e.s({PROJECT_CONFIG_PATH:()=>r,ProjectStatus:()=>i,WORKSPACE_CONFIG:()=>t});var s=e.i(13442),n=e.i(30331);let t={WORKSPACE_ROOT:(0,n.join)((0,s.homedir)(),"Documents","prime-workspace"),GIT_TIMEOUT:3e5,MAX_CONCURRENT_CLONES:Math.max(2,Math.min((0,s.cpus)().length,8)),MAX_RETRY_ATTEMPTS:3},r=(0,n.join)((0,s.homedir)(),".prime-projects.json");var i=function(e){return e.PENDING="pending",e.EXISTING="existing",e.CLONING="cloning",e.SUCCESS="success",e.FAILED="failed",e.RETRYING="retrying",e.INCOMPLETE="incomplete",e}({})}},30331:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("path",()=>require("path"))},29549:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},83943:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},86103:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},23430:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("next/dist/compiled/@opentelemetry/api",()=>require("next/dist/compiled/@opentelemetry/api"))},52670:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("next/dist/compiled/next-server/app-route-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-route-turbo.runtime.prod.js"))},13442:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("os",()=>require("os"))},9892:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("fs/promises",()=>require("fs/promises"))},35692:e=>{"use strict";var{g:t,__dirname:r}=e;e.s({ProjectStatus:()=>a,getProjectsConfig:()=>i,saveProjectsConfig:()=>o});var s=e.i(9892),n=e.i(88941);async function i(){try{await (0,s.access)(n.PROJECT_CONFIG_PATH,s.constants.F_OK)}catch{return await o({}),{}}try{let e=await (0,s.readFile)(n.PROJECT_CONFIG_PATH,"utf-8");if(!e)return{};return JSON.parse(e)}catch(e){throw console.error("读取或解析项目配置文件失败:",e),Error("无法加载项目配置")}}async function o(e){let t=n.PROJECT_CONFIG_PATH+".tmp";try{await (0,s.writeFile)(t,JSON.stringify(e,null,2),"utf-8"),await (0,s.rename)(t,n.PROJECT_CONFIG_PATH)}catch(e){throw console.error("保存项目配置文件失败:",e),Error("无法保存项目配置")}}var a=function(e){return e.PENDING="pending",e.EXISTING="existing",e.CLONING="cloning",e.SUCCESS="success",e.FAILED="failed",e.RETRYING="retrying",e}({})},87485:function(e){var{g:t,__dirname:r,m:s,e:n}=e;s.exports=e.x("child_process",()=>require("child_process"))},77159:e=>{"use strict";var{g:t,__dirname:r}=e;e.s({checkMultipleProjectsExist:()=>h,checkProjectExists:()=>d,checkProjectStatus:()=>p,cleanupIncompleteProject:()=>f,cloneRepository:()=>c,createWorkspaceDirectory:()=>a,isValidGitUrl:()=>u,sanitizeProjectName:()=>l});var s=e.i(87485),n=e.i(83886),i=e.i(30331),o=e.i(88941);async function a(e){try{return(0,n.existsSync)(e)||(0,n.mkdirSync)(e,{recursive:!0}),{success:!0}}catch(e){return{success:!1,error:`创建工作空间目录失败: ${e instanceof Error?e.message:String(e)}`}}}async function c(e){let{repoUrl:t,projectName:r,targetDir:n,timeout:a,onProgress:c,onError:u,onLog:l}=e,p=r?.trim()||(0,i.basename)(t,".git");return new Promise(e=>{let r=Date.now(),d={projectName:p,status:o.ProjectStatus.CLONING,progress:0,message:"开始克隆项目...",startTime:r};c?.(0,"开始克隆项目...");let g=(0,i.join)(n,p),f=["clone","--progress","--verbose",t,g];l?.(p,"stdout",`[开始克隆] 执行命令: git ${f.join(" ")}
2
+ `),l?.(p,"stdout",`[目标目录] ${g}
3
+ `),l?.(p,"stdout",`[仓库地址] ${t}
4
+ `);let h=(0,s.spawn)("git",f,{cwd:n,stdio:["pipe","pipe","pipe"]}),m="",$=0;l?.(p,"stdout",`[进程启动] Git 进程 PID: ${h.pid}
5
+ `);let x=setTimeout(()=>{l?.(p,"stderr",`[超时警告] Git 进程运行超过 ${a/1e3}s,即将终止
6
+ `),h.kill("SIGTERM");let t={...d,status:o.ProjectStatus.FAILED,progress:$,message:"克隆操作超时",error:`克隆操作超时 (${a/1e3}s)`,endTime:Date.now()};l?.(p,"stderr",`[进程终止] 克隆操作超时
7
+ `),u?.(`${p}: 克隆操作超时`),e(t)},a);h.stdout?.on("data",e=>{let t=e.toString();l?.(p,"stdout",t),$=Math.min($+10,80),c?.($,"正在克隆代码...")}),h.stderr?.on("data",e=>{let t=e.toString();m+=t,t.includes("remote:")||t.includes("Receiving objects")||t.includes("Resolving deltas")||t.includes("Counting objects")||t.includes("Enumerating objects")||t.includes("Compressing objects")||t.includes("upload-pack")||t.includes("POST git-")||t.includes("正克隆到")||t.includes("Cloning into")?l?.(p,"progress",t):l?.(p,"stderr",t),t.includes("Receiving objects")||t.includes("Resolving deltas")?($=Math.min($+5,90),c?.($,"正在接收对象...")):t.includes("Counting objects")?($=Math.min($+2,70),c?.($,"正在计算对象...")):t.includes("Enumerating objects")&&($=Math.min($+2,50),c?.($,"正在枚举对象..."))}),h.on("close",t=>{clearTimeout(x);let s=Date.now(),n=s-r;if(l?.(p,"stdout",`[进程结束] Git 进程退出,代码: ${t},耗时: ${Math.round(n/1e3)}s
8
+ `),0===t){l?.(p,"stdout",`[克隆成功] 项目已成功克隆到: ${g}
9
+ `);let t={...d,status:o.ProjectStatus.SUCCESS,progress:100,message:"克隆完成",endTime:s};c?.(100,"克隆完成"),e(t)}else{let r=function(e){let t=e.toLowerCase();return t.includes("authentication failed")||t.includes("access denied")?"身份验证失败,请检查仓库访问权限":t.includes("repository not found")||t.includes("not found")?"仓库不存在或无法访问":t.includes("network")||t.includes("connection")?"网络连接问题,请检查网络设置":t.includes("timeout")?"网络超时,请重试":t.includes("permission denied")?"权限被拒绝,请检查文件系统权限":t.includes("already exists")?"目标目录已存在":e.slice(0,200)+(e.length>200?"...":"")}(m);l?.(p,"stderr",`[克隆失败] 错误信息: ${r}
10
+ `),l?.(p,"stderr",`[完整错误输出]
11
+ ${m}
12
+ `);let n={...d,status:o.ProjectStatus.FAILED,progress:$,message:"克隆失败",error:r||`Git 进程退出,代码: ${t}`,endTime:s};u?.(`${p}: ${n.error}`),e(n)}}),h.on("error",t=>{clearTimeout(x),l?.(p,"stderr",`[进程错误] Git 进程启动失败: ${t.message}
13
+ `),l?.(p,"stderr",`[错误详情] ${t.stack||"No stack trace"}
14
+ `);let r={...d,status:o.ProjectStatus.FAILED,progress:$,message:"进程启动失败",error:`进程启动失败: ${t.message}`,endTime:Date.now()};u?.(`${p}: ${t.message}`),e(r)})})}function u(e){return/^(https?:\/\/|git@)[^\s]+\.git$/i.test(e)}function l(e){return e.replace(/[^a-zA-Z0-9\-_]/g,"")}async function p(e,t){try{let r=(0,i.join)(e,t);if(!(0,n.existsSync)(r))return{exists:!1,status:"not_exists",needsCleanup:!1};let s=(0,i.join)(r,".git");if(!(0,n.existsSync)(s))return{exists:!0,status:"incomplete",needsCleanup:!0};if(!await g(r))return console.log(`检测到不完整的Git仓库: ${r}`),{exists:!0,status:"incomplete",needsCleanup:!0};return{exists:!0,status:"complete",needsCleanup:!1}}catch(e){return console.error(`检查项目 ${t} 状态时出错:`,e),{exists:!1,status:"not_exists",needsCleanup:!1}}}async function d(e,t){return"complete"===(await p(e,t)).status}async function g(e){try{let t=(0,i.join)(e,".git");for(let e of["HEAD","config","refs"]){let r=(0,i.join)(t,e);if(!(0,n.existsSync)(r))return!1}let r=(await n.promises.readdir(e)).filter(e=>".git"!==e);if(0===r.length)return!1;let s=(0,i.join)(t,"HEAD"),o=await n.promises.readFile(s,"utf-8");if(!o.trim()||o.includes("unborn"))return!1;return!0}catch(e){return console.error("检查Git仓库完整性时出错:",e),!1}}async function f(e){try{console.log(`正在清理不完整的项目: ${e}`),await n.promises.rm(e,{recursive:!0,force:!0}),console.log(`清理完成: ${e}`)}catch(t){console.error(`清理项目失败 ${e}:`,t)}}async function h(e,t){let r={},s=t.map(async t=>{let s=await d(e,t);r[t]=s});return await Promise.all(s),r}},33808:e=>{"use strict";var{g:t,__dirname:r}=e;e.s({cleanupTempExecutionRepo:()=>u,createTempExecutionRepo:()=>c});var s=e.i(87485),n=e.i(9892),i=e.i(13442),o=e.i(30331);async function a(e,t){return new Promise((r,n)=>{let i=(0,s.spawn)("git",t,{cwd:e,stdio:["ignore","pipe","pipe"]}),o="",a="";i.stdout?.on("data",e=>{o+=e.toString()}),i.stderr?.on("data",e=>{a+=e.toString()}),i.on("close",e=>{r({code:e,stdout:o,stderr:a})}),i.on("error",e=>{n(e)})})}async function c(e,t){let r=await a(e,["remote","get-url","origin"]);if(0!==r.code)return{success:!1,error:r.stderr||r.stdout||"读取 origin 地址失败"};let s=r.stdout.trim();if(!s)return{success:!1,error:"origin 远端地址为空"};let c=`prime-uat-${t.replace(/[^a-zA-Z0-9\-_]/g,"-")}-`,u=await (0,n.mkdtemp)((0,o.join)((0,i.tmpdir)(),c)),l=(0,o.join)(u,t),p=await a(u,["clone","--no-tags",s,l]);return 0!==p.code?(await (0,n.rm)(u,{recursive:!0,force:!0}),{success:!1,error:p.stderr||p.stdout||"克隆临时仓库失败"}):{success:!0,value:{tempRootPath:u,projectPath:l}}}async function u(e){await (0,n.rm)(e,{recursive:!0,force:!0})}},34926:e=>{"use strict";var{g:t,__dirname:r}=e;{e.s({appendIgnoredPathsFromCheckoutWarning:()=>i,extractUnableToRmdirPaths:()=>n,hasBlockingWorkspaceChanges:()=>o});let t=/warning:\s+unable to rmdir '([^']+)': Directory not empty/g;function s(e){return e.trim().replace(/\\/g,"/").replace(/^\.\/+/,"").replace(/\/+$/,"")}function n(e){let r,n=new Set;for(;null!==(r=t.exec(e));){let e=s(r[1]||"");e&&n.add(e)}return t.lastIndex=0,[...n]}function i(e,t){let r=[];for(let s of n(e))t.has(s)||(t.add(s),r.push(s));return r}function o(e,t){let r=new Set;if(t)for(let e of t){let t=s(e);t&&r.add(t)}if(0===r.size)return e.trim().length>0;for(let t of e.split(/\r?\n/).filter(e=>e.length>0)){if("??"!==t.slice(0,2))return!0;let e=function(e){let t=e.length>=3?e.slice(3).trim():"";if(!t)return"";let r=t.startsWith('"')&&t.endsWith('"')?t.slice(1,-1):t,n=" -> ",i=r.lastIndexOf(n);return s(-1===i?r:r.slice(i+n.length))}(t);if(!e)return!0;let n=!1;for(let t of r)if(e===t||e.startsWith(`${t}/`)){n=!0;break}if(!n)return!0}return!1}}},50473:function(e){var{g:t,__dirname:r,m:s,e:n}=e},89710:e=>{"use strict";var{g:t,__dirname:r}=e;{e.s({POST:()=>$});var s=e.i(15494),n=e.i(87485),i=e.i(83886),o=e.i(30331),a=e.i(35692),c=e.i(77159),u=e.i(88941),l=e.i(33808),p=e.i(34926);let t=/\s/;function d(e){return!(!e||t.test(e)||e.startsWith("-"))}function g(e,t){return new Promise((r,s)=>{let i=(0,n.spawn)("git",t,{cwd:e,stdio:["ignore","pipe","pipe"]}),o="",a="";i.stdout?.on("data",e=>{o+=e.toString()}),i.stderr?.on("data",e=>{a+=e.toString()}),i.on("close",e=>{r({code:e,stdout:o,stderr:a})}),i.on("error",e=>{s(e)})})}function f(e){return`git ${e.join(" ")}`}function h(e,t,r,s){0===s.code?e.push(`[${t}] 完成: ${r}`):e.push(`[${t}] 失败: ${r} ${s.stderr||s.stdout}`)}function m(e,t,r,s){let n=(0,p.appendIgnoredPathsFromCheckoutWarning)(s.stderr,r.ignoredUntrackedPaths);n.length>0&&e.push(`[${t}] 提示: 检测到子模块残留目录 ${n.join(", ")},状态检查将忽略对应未跟踪路径`)}async function $(e){let t=new Set;try{let r=await e.json(),n=Array.isArray(r.projects)?r.projects:[],p="string"==typeof r.createBranch?r.createBranch.trim():"",$="string"==typeof r.baseBranch?r.baseBranch.trim():"",x=!!r.dryRun,j=[],w=[],y=[],P=new Map,v=(e,t,r,s)=>{P.has(e)||(P.set(e,{success:t,reason:r,rollbackActions:s}),y.push({projectName:e,success:t,reason:r,rollbackActions:s}))};if(0===n.length||!p||!$)return s.NextResponse.json({success:!1,operationLogs:j,feedbacks:["缺少必要参数,请填写完整后重试。"]},{status:400});if(!d(p)||!d($))return s.NextResponse.json({success:!1,operationLogs:j,feedbacks:["分支名称不合法,请避免空格或以 - 开头。"]},{status:400});let S=await (0,a.getProjectsConfig)(),C=u.WORKSPACE_CONFIG.WORKSPACE_ROOT;for(let e of n){let r=String(e),s=(0,c.sanitizeProjectName)(r);if(!s||s!==r){j.push(`[${r}] 失败: 项目名称包含无效字符`),w.push(`[${r}] 项目名称包含无效字符,已跳过。`),v(r,!1,"项目名称包含无效字符");continue}if(!S[s]){j.push(`[${s}] 失败: 未在项目配置中找到`),w.push(`[${s}] 未在项目配置中找到,已跳过。`),v(s,!1,"未在项目配置中找到");continue}let n=(0,o.join)(C,s);if(!(0,i.existsSync)(n)){j.push(`[${s}] 失败: 项目目录不存在`),w.push(`[${s}] 项目目录不存在,已跳过。`),v(s,!1,"项目目录不存在");continue}if(!(0,i.existsSync)((0,o.join)(n,".git"))){j.push(`[${s}] 失败: 非 Git 仓库`),w.push(`[${s}] 不是有效的 Git 仓库,已跳过。`),v(s,!1,"不是有效的 Git 仓库");continue}if(x){j.push(`[${s}] ${f(["fetch","origin"])}`),j.push(`[${s}] ${f(["ls-remote","--heads","origin",$])}`),j.push(`[${s}] ${f(["ls-remote","--heads","origin",p])}`),j.push(`[${s}] ${f(["checkout","-B",p,`origin/${$}`])}`),j.push(`[${s}] ${f(["push","-u","origin",p])}`),v(s,!0);continue}let a=await (0,l.createTempExecutionRepo)(n,s);if(!a.success){j.push(`[${s}] 失败: 创建临时执行仓库失败 ${a.error}`),w.push(`[${s}] 创建临时执行仓库失败: ${a.error}`),v(s,!1,"创建临时执行仓库失败");continue}let u=a.value.projectPath;t.add(a.value.tempRootPath),j.push(`[${s}] 使用临时目录执行: ${u}`);let d={ignoredUntrackedPaths:new Set};j.push(`[${s}] ${f(["fetch","origin"])}`);let y=await g(u,["fetch","origin"]);if(h(j,s,"拉取远端",y),0!==y.code){w.push(`[${s}] 拉取远端失败: ${y.stderr||y.stdout}`),v(s,!1,"拉取远端失败");continue}j.push(`[${s}] ${f(["ls-remote","--heads","origin",$])}`);let P=await g(u,["ls-remote","--heads","origin",$]);if(h(j,s,`检查 origin/${$}`,P),!P.stdout.trim()){w.push(`[${s}] origin/${$} 不存在,无法创建分支。`),v(s,!1,`origin/${$} 不存在`);continue}j.push(`[${s}] ${f(["ls-remote","--heads","origin",p])}`);let E=await g(u,["ls-remote","--heads","origin",p]);if(h(j,s,`检查 origin/${p}`,E),E.stdout.trim()){j.push(`[${s}] ${f(["checkout","-B",p,`origin/${p}`])}`);let e=await g(u,["checkout","-B",p,`origin/${p}`]);if(h(j,s,`切换到远端分支 ${p}`,e),m(j,s,d,e),0!==e.code){w.push(`[${s}] 切换到已有远端分支失败: ${e.stderr||e.stdout}`),v(s,!1,"切换到已有远端分支失败");continue}w.push(`[${s}] origin/${p} 已存在,已直接使用该分支。`),v(s,!0);continue}j.push(`[${s}] ${f(["checkout","-B",p,`origin/${$}`])}`);let R=await g(u,["checkout","-B",p,`origin/${$}`]);if(h(j,s,`创建分支 ${p}`,R),m(j,s,d,R),0!==R.code){w.push(`[${s}] 创建分支失败: ${R.stderr||R.stdout}`),v(s,!1,"创建分支失败");continue}j.push(`[${s}] ${f(["push","-u","origin",p])}`);let T=await g(u,["push","-u","origin",p]);if(h(j,s,`推送分支 ${p}`,T),0!==T.code){w.push(`[${s}] 推送新分支失败: ${T.stderr||T.stdout}`),v(s,!1,"推送新分支失败");continue}v(s,!0)}return s.NextResponse.json({success:0===w.filter(e=>e.includes("失败")).length,operationLogs:j,feedbacks:w,projectResults:y})}catch(e){return console.error("批量新建分支执行失败:",e),s.NextResponse.json({success:!1,operationLogs:[],feedbacks:[e instanceof Error?e.message:"执行失败"]},{status:500})}finally{for(let e of t)try{await (0,l.cleanupTempExecutionRepo)(e)}catch(t){console.error(`清理临时目录失败: ${e}`,t)}}}}},30156:e=>{"use strict";var{g:t,__dirname:r}=e;{e.s({patchFetch:()=>a,routeModule:()=>t,serverHooks:()=>u,workAsyncStorage:()=>r,workUnitAsyncStorage:()=>c});var s=e.i(45746),n=e.i(93828),i=e.i(18250),o=e.i(89710);let t=new s.AppRouteRouteModule({definition:{kind:n.RouteKind.APP_ROUTE,page:"/api/admin-git-batch-create-branch/route",pathname:"/api/admin-git-batch-create-branch",filename:"route",bundlePath:""},resolvedPagePath:"[project]/packages/server/src/app/api/admin-git-batch-create-branch/route.ts",nextConfigOutput:"",userland:o}),{workAsyncStorage:r,workUnitAsyncStorage:c,serverHooks:u}=t;function a(){return(0,i.patchFetch)({workAsyncStorage:r,workUnitAsyncStorage:c})}}}};
15
+
16
+ //# sourceMappingURL=%5Broot-of-the-server%5D__f111df8e._.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["turbopack:///[project]/packages/server/src/lib/workspace-types.ts","turbopack:///[project]/packages/server/src/lib/workspace-config.ts","turbopack:///[project]/packages/server/src/lib/git-operations.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/temp-repo.ts","turbopack:///[project]/packages/server/src/app/api/uat-git-flow/git-status-utils.ts","turbopack:///[project]/packages/server/src/app/api/admin-git-batch-create-branch/route.ts","turbopack:///[project]/node_modules/.pnpm/next@15.3.4_react-dom@19.1.0_react@19.1.0__react@19.1.0/node_modules/next/dist/src/build/templates/app-route.ts"],"sourcesContent":["import { homedir, cpus } from 'os';\nimport { join } from 'path';\n\n/**\n * 工作空间配置常量\n */\nexport const WORKSPACE_CONFIG = {\n // 工作空间根目录路径\n WORKSPACE_ROOT: join(homedir(), 'Documents', 'prime-workspace'),\n\n // Git 操作超时时间 (毫秒)\n GIT_TIMEOUT: 300000, // 5分钟\n\n // 最大并发克隆数量(基于CPU核心数,最小2个,最大8个)\n MAX_CONCURRENT_CLONES: Math.max(2, Math.min(cpus().length, 8)),\n\n // 重试次数限制\n MAX_RETRY_ATTEMPTS: 3,\n} as const;\n\nexport const PROJECT_CONFIG_PATH = join(homedir(), '.prime-projects.json');\n\nexport interface ProjectConfig {\n repo: string;\n mockingIntercept?: boolean;\n mockOpen?: boolean;\n envs: {\n [envName: string]: {\n host: string;\n currentProxy: string;\n proxyEnv: {\n [key: string]: string;\n };\n envFileName: string;\n proxyKey: string;\n subApps?: string[];\n };\n };\n}\n\nexport interface ProjectsConfig {\n [projectName: string]: ProjectConfig;\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n INCOMPLETE = 'incomplete', // 不完整的项目,需要清理\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n onLog?: (projectName: string, logType: 'stdout' | 'stderr' | 'progress', content: string) => void;\n}\n","import { readFile, writeFile, access, constants, rename } from 'fs/promises';\nimport type { ProjectsConfig } from './workspace-types';\nimport { PROJECT_CONFIG_PATH } from './workspace-types';\n\n/**\n * 读取并解析项目配置文件\n * @returns {Promise<ProjectsConfig>} 项目配置对象\n */\nexport async function getProjectsConfig(): Promise<ProjectsConfig> {\n try {\n await access(PROJECT_CONFIG_PATH, constants.F_OK);\n } catch {\n // 文件不存在,创建并写入空对象\n await saveProjectsConfig({});\n return {};\n }\n\n try {\n const configContent = await readFile(PROJECT_CONFIG_PATH, 'utf-8');\n // 如果文件为空,返回空对象\n if (!configContent) {\n return {};\n }\n return JSON.parse(configContent);\n } catch (error) {\n console.error('读取或解析项目配置文件失败:', error);\n // 在出错时返回空对象或抛出错误,这里选择抛出以通知调用者\n throw new Error('无法加载项目配置');\n }\n}\n\n/**\n * 将项目配置写入文件(原子操作)\n * @param {ProjectsConfig} config - 要保存的配置对象\n */\nexport async function saveProjectsConfig(config: ProjectsConfig): Promise<void> {\n const tempConfigPath = PROJECT_CONFIG_PATH + '.tmp';\n try {\n await writeFile(tempConfigPath, JSON.stringify(config, null, 2), 'utf-8');\n await rename(tempConfigPath, PROJECT_CONFIG_PATH);\n } catch (error) {\n console.error('保存项目配置文件失败:', error);\n throw new Error('无法保存项目配置');\n }\n}\n\n/**\n * 项目状态枚举\n */\nexport enum ProjectStatus {\n PENDING = 'pending',\n EXISTING = 'existing',\n CLONING = 'cloning',\n SUCCESS = 'success',\n FAILED = 'failed',\n RETRYING = 'retrying',\n}\n\n/**\n * 项目进度信息接口\n */\nexport interface ProjectProgress {\n projectName: string;\n status: ProjectStatus;\n progress: number; // 0-100\n message: string;\n error?: string;\n startTime?: number;\n endTime?: number;\n}\n\n/**\n * 初始化结果接口\n */\nexport interface InitializationResult {\n success: boolean;\n totalProjects: number;\n successCount: number;\n failedCount: number;\n failedProjects: string[];\n workspacePath: string;\n duration: number;\n}\n\n/**\n * Git 操作配置接口\n */\nexport interface GitOperationConfig {\n repoUrl: string;\n projectName?: string;\n targetDir: string;\n timeout: number;\n onProgress?: (progress: number, message: string) => void;\n onError?: (error: string) => void;\n}\n","import { spawn, ChildProcess } from 'child_process';\nimport { existsSync, mkdirSync } from 'fs';\nimport { promises as fs } from 'fs';\nimport { join, basename } from 'path';\nimport {\n ProjectStatus,\n type GitOperationConfig,\n type ProjectProgress,\n} from './workspace-types';\n\n/**\n * 创建工作空间目录\n * @param workspacePath 工作空间路径\n * @returns 创建结果\n */\nexport async function createWorkspaceDirectory(workspacePath: string): Promise<{ success: boolean; error?: string }> {\n try {\n if (!existsSync(workspacePath)) {\n mkdirSync(workspacePath, { recursive: true });\n }\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: `创建工作空间目录失败: ${error instanceof Error ? error.message : String(error)}` \n };\n }\n}\n\n/**\n * 执行 Git 克隆操作\n * @param config Git 操作配置\n * @returns Promise<ProjectProgress>\n */\nexport async function cloneRepository(config: GitOperationConfig): Promise<ProjectProgress> {\n const { repoUrl, projectName: configuredProjectName, targetDir, timeout, onProgress, onError, onLog } = config;\n const projectName = configuredProjectName?.trim() || basename(repoUrl, '.git');\n \n return new Promise<ProjectProgress>((resolve) => {\n const startTime = Date.now();\n \n // 更新开始状态\n const initialProgress: ProjectProgress = {\n projectName,\n status: ProjectStatus.CLONING,\n progress: 0,\n message: '开始克隆项目...',\n startTime,\n };\n onProgress?.(0, '开始克隆项目...');\n\n // 执行 git clone 命令\n const targetPath = join(targetDir, projectName);\n // 添加 --progress 参数来强制显示进度,--verbose 显示详细信息\n const gitArgs = ['clone', '--progress', '--verbose', repoUrl, targetPath];\n \n // 记录命令启动信息\n onLog?.(projectName, 'stdout', `[开始克隆] 执行命令: git ${gitArgs.join(' ')}\\n`);\n onLog?.(projectName, 'stdout', `[目标目录] ${targetPath}\\n`);\n onLog?.(projectName, 'stdout', `[仓库地址] ${repoUrl}\\n`);\n \n const gitProcess: ChildProcess = spawn('git', gitArgs, {\n cwd: targetDir,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n let errorOutput = '';\n let progressValue = 0;\n \n // 记录进程启动成功\n onLog?.(projectName, 'stdout', `[进程启动] Git 进程 PID: ${gitProcess.pid}\\n`);\n\n // 设置超时\n const timeoutId = setTimeout(() => {\n onLog?.(projectName, 'stderr', `[超时警告] Git 进程运行超过 ${timeout / 1000}s,即将终止\\n`);\n gitProcess.kill('SIGTERM');\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆操作超时',\n error: `克隆操作超时 (${timeout / 1000}s)`,\n endTime: Date.now(),\n };\n onLog?.(projectName, 'stderr', `[进程终止] 克隆操作超时\\n`);\n onError?.(`${projectName}: 克隆操作超时`);\n resolve(errorResult);\n }, timeout);\n\n // 处理标准输出\n gitProcess.stdout?.on('data', (data: Buffer) => {\n const stdoutText = data.toString();\n \n // 实时发送日志\n onLog?.(projectName, 'stdout', stdoutText);\n \n // 模拟进度更新(Git 克隆没有内置进度,这里基于时间估算)\n progressValue = Math.min(progressValue + 10, 80);\n onProgress?.(progressValue, '正在克隆代码...');\n });\n\n // 处理错误输出\n gitProcess.stderr?.on('data', (data: Buffer) => {\n const stderrText = data.toString();\n errorOutput += stderrText;\n \n // 判断是进度信息还是错误信息\n const isProgressInfo = stderrText.includes('remote:') || \n stderrText.includes('Receiving objects') || \n stderrText.includes('Resolving deltas') ||\n stderrText.includes('Counting objects') ||\n stderrText.includes('Enumerating objects') ||\n stderrText.includes('Compressing objects') ||\n stderrText.includes('upload-pack') ||\n stderrText.includes('POST git-') ||\n stderrText.includes('正克隆到') ||\n stderrText.includes('Cloning into');\n \n // 根据内容类型发送不同的日志\n if (isProgressInfo) {\n onLog?.(projectName, 'progress', stderrText);\n } else {\n onLog?.(projectName, 'stderr', stderrText);\n }\n \n // Git 的进度信息通常在 stderr 中\n if (stderrText.includes('Receiving objects') || stderrText.includes('Resolving deltas')) {\n progressValue = Math.min(progressValue + 5, 90);\n onProgress?.(progressValue, '正在接收对象...');\n } else if (stderrText.includes('Counting objects')) {\n progressValue = Math.min(progressValue + 2, 70);\n onProgress?.(progressValue, '正在计算对象...');\n } else if (stderrText.includes('Enumerating objects')) {\n progressValue = Math.min(progressValue + 2, 50);\n onProgress?.(progressValue, '正在枚举对象...');\n }\n });\n\n // 处理进程结束\n gitProcess.on('close', (code: number | null) => {\n clearTimeout(timeoutId);\n const endTime = Date.now();\n const duration = endTime - startTime;\n \n onLog?.(projectName, 'stdout', `[进程结束] Git 进程退出,代码: ${code},耗时: ${Math.round(duration / 1000)}s\\n`);\n \n if (code === 0) {\n // 克隆成功\n onLog?.(projectName, 'stdout', `[克隆成功] 项目已成功克隆到: ${targetPath}\\n`);\n const successResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.SUCCESS,\n progress: 100,\n message: '克隆完成',\n endTime,\n };\n onProgress?.(100, '克隆完成');\n resolve(successResult);\n } else {\n // 克隆失败\n const parsedError = parseGitError(errorOutput);\n onLog?.(projectName, 'stderr', `[克隆失败] 错误信息: ${parsedError}\\n`);\n onLog?.(projectName, 'stderr', `[完整错误输出]\\n${errorOutput}\\n`);\n \n const failureResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '克隆失败',\n error: parsedError || `Git 进程退出,代码: ${code}`,\n endTime,\n };\n onError?.(`${projectName}: ${failureResult.error}`);\n resolve(failureResult);\n }\n });\n\n // 处理进程错误\n gitProcess.on('error', (error: Error) => {\n clearTimeout(timeoutId);\n onLog?.(projectName, 'stderr', `[进程错误] Git 进程启动失败: ${error.message}\\n`);\n onLog?.(projectName, 'stderr', `[错误详情] ${error.stack || 'No stack trace'}\\n`);\n \n const errorResult: ProjectProgress = {\n ...initialProgress,\n status: ProjectStatus.FAILED,\n progress: progressValue,\n message: '进程启动失败',\n error: `进程启动失败: ${error.message}`,\n endTime: Date.now(),\n };\n onError?.(`${projectName}: ${error.message}`);\n resolve(errorResult);\n });\n });\n}\n\n/**\n * 解析 Git 错误信息,提供用户友好的错误描述\n * @param errorOutput Git stderr 输出\n * @returns 用户友好的错误描述\n */\nfunction parseGitError(errorOutput: string): string {\n const lowerOutput = errorOutput.toLowerCase();\n \n if (lowerOutput.includes('authentication failed') || lowerOutput.includes('access denied')) {\n return '身份验证失败,请检查仓库访问权限';\n }\n \n if (lowerOutput.includes('repository not found') || lowerOutput.includes('not found')) {\n return '仓库不存在或无法访问';\n }\n \n if (lowerOutput.includes('network') || lowerOutput.includes('connection')) {\n return '网络连接问题,请检查网络设置';\n }\n \n if (lowerOutput.includes('timeout')) {\n return '网络超时,请重试';\n }\n \n if (lowerOutput.includes('permission denied')) {\n return '权限被拒绝,请检查文件系统权限';\n }\n \n if (lowerOutput.includes('already exists')) {\n return '目标目录已存在';\n }\n \n // 返回原始错误的前200个字符\n return errorOutput.slice(0, 200) + (errorOutput.length > 200 ? '...' : '');\n}\n\n/**\n * 验证 Git 仓库 URL 格式\n * @param url Git 仓库 URL\n * @returns 是否有效\n */\nexport function isValidGitUrl(url: string): boolean {\n const gitUrlPattern = /^(https?:\\/\\/|git@)[^\\s]+\\.git$/i;\n return gitUrlPattern.test(url);\n}\n\n/**\n * 清理项目名称,移除不安全字符\n * @param projectName 项目名称\n * @returns 清理后的项目名称\n */\nexport function sanitizeProjectName(projectName: string): string {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '');\n}\n\n/**\n * 项目检查结果类型\n */\nexport type ProjectCheckResult = {\n exists: boolean;\n status: 'not_exists' | 'complete' | 'incomplete';\n needsCleanup: boolean;\n};\n\n/**\n * 检查项目状态(详细版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<ProjectCheckResult> 详细的项目状态\n */\nexport async function checkProjectStatus(workspacePath: string, projectName: string): Promise<ProjectCheckResult> {\n try {\n const projectPath = join(workspacePath, projectName);\n \n // 检查项目目录是否存在\n if (!existsSync(projectPath)) {\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n \n // 检查是否为 Git 仓库(存在 .git 目录)\n const gitPath = join(projectPath, '.git');\n if (!existsSync(gitPath)) {\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n // 更严格的完整性检查\n const isComplete = await isGitRepositoryComplete(projectPath);\n if (!isComplete) {\n console.log(`检测到不完整的Git仓库: ${projectPath}`);\n return {\n exists: true,\n status: 'incomplete',\n needsCleanup: true\n };\n }\n \n return {\n exists: true,\n status: 'complete',\n needsCleanup: false\n };\n } catch (error) {\n console.error(`检查项目 ${projectName} 状态时出错:`, error);\n return {\n exists: false,\n status: 'not_exists',\n needsCleanup: false\n };\n }\n}\n\n/**\n * 检查项目是否已存在于工作空间中(兼容版本)\n * @param workspacePath 工作空间路径\n * @param projectName 项目名称\n * @returns Promise<boolean> 项目是否存在且为有效的 Git 仓库\n */\nexport async function checkProjectExists(workspacePath: string, projectName: string): Promise<boolean> {\n const result = await checkProjectStatus(workspacePath, projectName);\n return result.status === 'complete';\n}\n\n/**\n * 检查Git仓库是否完整\n * @param projectPath 项目路径\n * @returns Promise<boolean> 仓库是否完整\n */\nasync function isGitRepositoryComplete(projectPath: string): Promise<boolean> {\n try {\n const gitPath = join(projectPath, '.git');\n \n // 检查关键的Git文件是否存在\n const requiredFiles = ['HEAD', 'config', 'refs'];\n for (const file of requiredFiles) {\n const filePath = join(gitPath, file);\n if (!existsSync(filePath)) {\n return false;\n }\n }\n \n // 检查是否有实际的项目文件(不只是.git目录)\n const entries = await fs.readdir(projectPath);\n const nonGitFiles = entries.filter((entry: string) => entry !== '.git');\n \n // 如果只有.git目录,说明克隆未完成\n if (nonGitFiles.length === 0) {\n return false;\n }\n \n // 检查HEAD文件是否有效\n const headPath = join(gitPath, 'HEAD');\n const headContent = await fs.readFile(headPath, 'utf-8');\n if (!headContent.trim() || headContent.includes('unborn')) {\n return false;\n }\n \n return true;\n } catch (error) {\n console.error('检查Git仓库完整性时出错:', error);\n return false;\n }\n}\n\n/**\n * 清理不完整的项目目录\n * @param projectPath 项目路径\n */\nexport async function cleanupIncompleteProject(projectPath: string): Promise<void> {\n try {\n console.log(`正在清理不完整的项目: ${projectPath}`);\n await fs.rm(projectPath, { recursive: true, force: true });\n console.log(`清理完成: ${projectPath}`);\n } catch (error) {\n console.error(`清理项目失败 ${projectPath}:`, error);\n // 清理失败不抛出错误,避免阻塞后续流程\n }\n}\n\n/**\n * 批量检查多个项目的存在状态\n * @param workspacePath 工作空间路径\n * @param projectNames 项目名称列表\n * @returns Promise<Record<string, boolean>> 项目名称到存在状态的映射\n */\nexport async function checkMultipleProjectsExist(\n workspacePath: string, \n projectNames: string[]\n): Promise<Record<string, boolean>> {\n const results: Record<string, boolean> = {};\n \n // 并行检查所有项目\n const checks = projectNames.map(async (projectName) => {\n const exists = await checkProjectExists(workspacePath, projectName);\n results[projectName] = exists;\n });\n \n await Promise.all(checks);\n return results;\n} \n","import { spawn } from 'child_process';\nimport { mkdtemp, rm } from 'fs/promises';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\n\ntype GitResult = {\n code: number | null;\n stdout: string;\n stderr: string;\n};\n\nasync function runGitCommand(cwd: string, args: string[]): Promise<GitResult> {\n return new Promise((resolve, reject) => {\n const child = spawn('git', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('close', (code) => {\n resolve({ code, stdout, stderr });\n });\n\n child.on('error', (error) => {\n reject(error);\n });\n });\n}\n\nfunction sanitizeProjectNameForTemp(projectName: string) {\n return projectName.replace(/[^a-zA-Z0-9\\-_]/g, '-');\n}\n\nexport type TempExecutionRepo = {\n tempRootPath: string;\n projectPath: string;\n};\n\nexport async function createTempExecutionRepo(sourceProjectPath: string, projectName: string): Promise<{\n success: true;\n value: TempExecutionRepo;\n} | {\n success: false;\n error: string;\n}> {\n const remoteResult = await runGitCommand(sourceProjectPath, ['remote', 'get-url', 'origin']);\n if (remoteResult.code !== 0) {\n return {\n success: false,\n error: remoteResult.stderr || remoteResult.stdout || '读取 origin 地址失败',\n };\n }\n\n const remoteUrl = remoteResult.stdout.trim();\n if (!remoteUrl) {\n return {\n success: false,\n error: 'origin 远端地址为空',\n };\n }\n\n const prefix = `prime-uat-${sanitizeProjectNameForTemp(projectName)}-`;\n const tempRootPath = await mkdtemp(join(tmpdir(), prefix));\n const tempProjectPath = join(tempRootPath, projectName);\n\n const cloneResult = await runGitCommand(tempRootPath, ['clone', '--no-tags', remoteUrl, tempProjectPath]);\n if (cloneResult.code !== 0) {\n await rm(tempRootPath, { recursive: true, force: true });\n return {\n success: false,\n error: cloneResult.stderr || cloneResult.stdout || '克隆临时仓库失败',\n };\n }\n\n return {\n success: true,\n value: {\n tempRootPath,\n projectPath: tempProjectPath,\n },\n };\n}\n\nexport async function cleanupTempExecutionRepo(tempRootPath: string) {\n await rm(tempRootPath, { recursive: true, force: true });\n}\n","const unableToRmdirWarningPattern = /warning:\\s+unable to rmdir '([^']+)': Directory not empty/g;\n\nfunction normalizeGitPath(path: string) {\n return path\n .trim()\n .replace(/\\\\/g, '/')\n .replace(/^\\.\\/+/, '')\n .replace(/\\/+$/, '');\n}\n\nfunction parseStatusPath(line: string) {\n const rawPath = line.length >= 3 ? line.slice(3).trim() : '';\n if (!rawPath) return '';\n\n const unquoted = rawPath.startsWith('\"') && rawPath.endsWith('\"')\n ? rawPath.slice(1, -1)\n : rawPath;\n const renamedSeparator = ' -> ';\n const renamedIndex = unquoted.lastIndexOf(renamedSeparator);\n const targetPath = renamedIndex === -1\n ? unquoted\n : unquoted.slice(renamedIndex + renamedSeparator.length);\n\n return normalizeGitPath(targetPath);\n}\n\nexport function extractUnableToRmdirPaths(stderr: string) {\n const matchedPaths = new Set<string>();\n let match: RegExpExecArray | null;\n\n while ((match = unableToRmdirWarningPattern.exec(stderr)) !== null) {\n const normalizedPath = normalizeGitPath(match[1] || '');\n if (normalizedPath) {\n matchedPaths.add(normalizedPath);\n }\n }\n\n unableToRmdirWarningPattern.lastIndex = 0;\n return [...matchedPaths];\n}\n\nexport function appendIgnoredPathsFromCheckoutWarning(stderr: string, ignoredPaths: Set<string>) {\n const addedPaths: string[] = [];\n for (const path of extractUnableToRmdirPaths(stderr)) {\n if (!ignoredPaths.has(path)) {\n ignoredPaths.add(path);\n addedPaths.push(path);\n }\n }\n return addedPaths;\n}\n\nexport function hasBlockingWorkspaceChanges(statusOutput: string, ignoredUntrackedPaths?: Iterable<string>) {\n const ignoredPathSet = new Set<string>();\n if (ignoredUntrackedPaths) {\n for (const path of ignoredUntrackedPaths) {\n const normalizedPath = normalizeGitPath(path);\n if (normalizedPath) {\n ignoredPathSet.add(normalizedPath);\n }\n }\n }\n\n if (ignoredPathSet.size === 0) {\n return statusOutput.trim().length > 0;\n }\n\n const lines = statusOutput.split(/\\r?\\n/).filter(line => line.length > 0);\n for (const line of lines) {\n const statusCode = line.slice(0, 2);\n if (statusCode !== '??') {\n return true;\n }\n\n const statusPath = parseStatusPath(line);\n if (!statusPath) {\n return true;\n }\n\n let shouldIgnore = false;\n for (const ignoredPath of ignoredPathSet) {\n if (statusPath === ignoredPath || statusPath.startsWith(`${ignoredPath}/`)) {\n shouldIgnore = true;\n break;\n }\n }\n\n if (!shouldIgnore) {\n return true;\n }\n }\n\n return false;\n}\n","import { NextRequest, NextResponse } from 'next/server';\nimport { spawn } from 'child_process';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getProjectsConfig } from '@/lib/workspace-config';\nimport { sanitizeProjectName } from '@/lib/git-operations';\nimport { WORKSPACE_CONFIG } from '@/lib/workspace-types';\nimport { cleanupTempExecutionRepo, createTempExecutionRepo } from '@/app/api/uat-git-flow/temp-repo';\nimport { appendIgnoredPathsFromCheckoutWarning } from '@/app/api/uat-git-flow/git-status-utils';\n\ntype GitResult = {\n code: number | null;\n stdout: string;\n stderr: string;\n};\n\ntype BatchCreateProjectInfo = {\n ignoredUntrackedPaths: Set<string>;\n};\n\nconst invalidBranchChars = /\\s/;\n\nfunction isValidBranchName(name: string) {\n if (!name) return false;\n if (invalidBranchChars.test(name)) return false;\n if (name.startsWith('-')) return false;\n return true;\n}\n\nfunction runGitCommand(cwd: string, args: string[]): Promise<GitResult> {\n return new Promise((resolve, reject) => {\n const child = spawn('git', args, {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('close', (code) => {\n resolve({ code, stdout, stderr });\n });\n\n child.on('error', (error) => {\n reject(error);\n });\n });\n}\n\nfunction formatCommand(args: string[]) {\n return `git ${args.join(' ')}`;\n}\n\nfunction logCommandResult(operationLogs: string[], projectName: string, step: string, result: GitResult) {\n if (result.code === 0) {\n operationLogs.push(`[${projectName}] 完成: ${step}`);\n } else {\n operationLogs.push(`[${projectName}] 失败: ${step} ${result.stderr || result.stdout}`);\n }\n}\n\nfunction trackCheckoutWarnings(\n operationLogs: string[],\n projectName: string,\n projectInfo: BatchCreateProjectInfo,\n result: GitResult,\n) {\n const addedPaths = appendIgnoredPathsFromCheckoutWarning(result.stderr, projectInfo.ignoredUntrackedPaths);\n if (addedPaths.length > 0) {\n operationLogs.push(`[${projectName}] 提示: 检测到子模块残留目录 ${addedPaths.join(', ')},状态检查将忽略对应未跟踪路径`);\n }\n}\n\nexport async function POST(request: NextRequest) {\n const tempRootPaths = new Set<string>();\n try {\n const body = await request.json();\n const projects = Array.isArray(body.projects) ? body.projects : [];\n const createBranch = typeof body.createBranch === 'string' ? body.createBranch.trim() : '';\n const baseBranch = typeof body.baseBranch === 'string' ? body.baseBranch.trim() : '';\n const dryRun = Boolean(body.dryRun);\n\n const operationLogs: string[] = [];\n const feedbacks: string[] = [];\n const projectResults: Array<{\n projectName: string;\n success: boolean;\n reason?: string;\n rollbackActions?: string[];\n }> = [];\n\n const resultMap = new Map<string, { success: boolean; reason?: string; rollbackActions?: string[] }>();\n const setProjectResult = (\n projectName: string,\n success: boolean,\n reason?: string,\n rollbackActions?: string[],\n ) => {\n if (resultMap.has(projectName)) return;\n resultMap.set(projectName, { success, reason, rollbackActions });\n projectResults.push({ projectName, success, reason, rollbackActions });\n };\n\n if (projects.length === 0 || !createBranch || !baseBranch) {\n return NextResponse.json({\n success: false,\n operationLogs,\n feedbacks: ['缺少必要参数,请填写完整后重试。'],\n }, { status: 400 });\n }\n\n if (!isValidBranchName(createBranch) || !isValidBranchName(baseBranch)) {\n return NextResponse.json({\n success: false,\n operationLogs,\n feedbacks: ['分支名称不合法,请避免空格或以 - 开头。'],\n }, { status: 400 });\n }\n\n const projectsConfig = await getProjectsConfig();\n const workspacePath = WORKSPACE_CONFIG.WORKSPACE_ROOT;\n\n for (const rawProjectName of projects) {\n const originalName = String(rawProjectName);\n const projectName = sanitizeProjectName(originalName);\n\n if (!projectName || projectName !== originalName) {\n operationLogs.push(`[${originalName}] 失败: 项目名称包含无效字符`);\n feedbacks.push(`[${originalName}] 项目名称包含无效字符,已跳过。`);\n setProjectResult(originalName, false, '项目名称包含无效字符');\n continue;\n }\n\n if (!projectsConfig[projectName]) {\n operationLogs.push(`[${projectName}] 失败: 未在项目配置中找到`);\n feedbacks.push(`[${projectName}] 未在项目配置中找到,已跳过。`);\n setProjectResult(projectName, false, '未在项目配置中找到');\n continue;\n }\n\n const projectPath = join(workspacePath, projectName);\n if (!existsSync(projectPath)) {\n operationLogs.push(`[${projectName}] 失败: 项目目录不存在`);\n feedbacks.push(`[${projectName}] 项目目录不存在,已跳过。`);\n setProjectResult(projectName, false, '项目目录不存在');\n continue;\n }\n\n if (!existsSync(join(projectPath, '.git'))) {\n operationLogs.push(`[${projectName}] 失败: 非 Git 仓库`);\n feedbacks.push(`[${projectName}] 不是有效的 Git 仓库,已跳过。`);\n setProjectResult(projectName, false, '不是有效的 Git 仓库');\n continue;\n }\n\n if (dryRun) {\n operationLogs.push(`[${projectName}] ${formatCommand(['fetch', 'origin'])}`);\n operationLogs.push(`[${projectName}] ${formatCommand(['ls-remote', '--heads', 'origin', baseBranch])}`);\n operationLogs.push(`[${projectName}] ${formatCommand(['ls-remote', '--heads', 'origin', createBranch])}`);\n operationLogs.push(`[${projectName}] ${formatCommand(['checkout', '-B', createBranch, `origin/${baseBranch}`])}`);\n operationLogs.push(`[${projectName}] ${formatCommand(['push', '-u', 'origin', createBranch])}`);\n setProjectResult(projectName, true);\n continue;\n }\n\n const tempRepoResult = await createTempExecutionRepo(projectPath, projectName);\n if (!tempRepoResult.success) {\n operationLogs.push(`[${projectName}] 失败: 创建临时执行仓库失败 ${tempRepoResult.error}`);\n feedbacks.push(`[${projectName}] 创建临时执行仓库失败: ${tempRepoResult.error}`);\n setProjectResult(projectName, false, '创建临时执行仓库失败');\n continue;\n }\n\n const executionPath = tempRepoResult.value.projectPath;\n tempRootPaths.add(tempRepoResult.value.tempRootPath);\n operationLogs.push(`[${projectName}] 使用临时目录执行: ${executionPath}`);\n\n const projectInfo: BatchCreateProjectInfo = {\n ignoredUntrackedPaths: new Set<string>(),\n };\n\n operationLogs.push(`[${projectName}] ${formatCommand(['fetch', 'origin'])}`);\n const fetchResult = await runGitCommand(executionPath, ['fetch', 'origin']);\n logCommandResult(operationLogs, projectName, '拉取远端', fetchResult);\n if (fetchResult.code !== 0) {\n feedbacks.push(`[${projectName}] 拉取远端失败: ${fetchResult.stderr || fetchResult.stdout}`);\n setProjectResult(projectName, false, '拉取远端失败');\n continue;\n }\n\n operationLogs.push(`[${projectName}] ${formatCommand(['ls-remote', '--heads', 'origin', baseBranch])}`);\n const baseExists = await runGitCommand(executionPath, ['ls-remote', '--heads', 'origin', baseBranch]);\n logCommandResult(operationLogs, projectName, `检查 origin/${baseBranch}`, baseExists);\n if (!baseExists.stdout.trim()) {\n feedbacks.push(`[${projectName}] origin/${baseBranch} 不存在,无法创建分支。`);\n setProjectResult(projectName, false, `origin/${baseBranch} 不存在`);\n continue;\n }\n\n operationLogs.push(`[${projectName}] ${formatCommand(['ls-remote', '--heads', 'origin', createBranch])}`);\n const remoteCreateExists = await runGitCommand(executionPath, ['ls-remote', '--heads', 'origin', createBranch]);\n logCommandResult(operationLogs, projectName, `检查 origin/${createBranch}`, remoteCreateExists);\n\n if (remoteCreateExists.stdout.trim()) {\n operationLogs.push(`[${projectName}] ${formatCommand(['checkout', '-B', createBranch, `origin/${createBranch}`])}`);\n const checkoutRemote = await runGitCommand(executionPath, ['checkout', '-B', createBranch, `origin/${createBranch}`]);\n logCommandResult(operationLogs, projectName, `切换到远端分支 ${createBranch}`, checkoutRemote);\n trackCheckoutWarnings(operationLogs, projectName, projectInfo, checkoutRemote);\n if (checkoutRemote.code !== 0) {\n feedbacks.push(`[${projectName}] 切换到已有远端分支失败: ${checkoutRemote.stderr || checkoutRemote.stdout}`);\n setProjectResult(projectName, false, '切换到已有远端分支失败');\n continue;\n }\n feedbacks.push(`[${projectName}] origin/${createBranch} 已存在,已直接使用该分支。`);\n setProjectResult(projectName, true);\n continue;\n }\n\n operationLogs.push(`[${projectName}] ${formatCommand(['checkout', '-B', createBranch, `origin/${baseBranch}`])}`);\n const createResult = await runGitCommand(executionPath, ['checkout', '-B', createBranch, `origin/${baseBranch}`]);\n logCommandResult(operationLogs, projectName, `创建分支 ${createBranch}`, createResult);\n trackCheckoutWarnings(operationLogs, projectName, projectInfo, createResult);\n if (createResult.code !== 0) {\n feedbacks.push(`[${projectName}] 创建分支失败: ${createResult.stderr || createResult.stdout}`);\n setProjectResult(projectName, false, '创建分支失败');\n continue;\n }\n\n operationLogs.push(`[${projectName}] ${formatCommand(['push', '-u', 'origin', createBranch])}`);\n const pushResult = await runGitCommand(executionPath, ['push', '-u', 'origin', createBranch]);\n logCommandResult(operationLogs, projectName, `推送分支 ${createBranch}`, pushResult);\n if (pushResult.code !== 0) {\n feedbacks.push(`[${projectName}] 推送新分支失败: ${pushResult.stderr || pushResult.stdout}`);\n setProjectResult(projectName, false, '推送新分支失败');\n continue;\n }\n\n setProjectResult(projectName, true);\n }\n\n return NextResponse.json({\n success: feedbacks.filter(message => message.includes('失败')).length === 0,\n operationLogs,\n feedbacks,\n projectResults,\n });\n } catch (error) {\n console.error('批量新建分支执行失败:', error);\n return NextResponse.json({\n success: false,\n operationLogs: [],\n feedbacks: [error instanceof Error ? error.message : '执行失败'],\n }, { status: 500 });\n } finally {\n for (const tempRootPath of tempRootPaths) {\n try {\n await cleanupTempExecutionRepo(tempRootPath);\n } catch (cleanupError) {\n console.error(`清理临时目录失败: ${tempRootPath}`, cleanupError);\n }\n }\n }\n}\n","import {\n AppRouteRouteModule,\n type AppRouteRouteModuleOptions,\n} from '../../server/route-modules/app-route/module.compiled'\nimport { RouteKind } from '../../server/route-kind'\nimport { patchFetch as _patchFetch } from '../../server/lib/patch-fetch'\n\nimport * as userland from 'VAR_USERLAND'\n\n// These are injected by the loader afterwards. This is injected as a variable\n// instead of a replacement because this could also be `undefined` instead of\n// an empty string.\ndeclare const nextConfigOutput: AppRouteRouteModuleOptions['nextConfigOutput']\n\n// We inject the nextConfigOutput here so that we can use them in the route\n// module.\n// INJECT:nextConfigOutput\n\nconst routeModule = new AppRouteRouteModule({\n definition: {\n kind: RouteKind.APP_ROUTE,\n page: 'VAR_DEFINITION_PAGE',\n pathname: 'VAR_DEFINITION_PATHNAME',\n filename: 'VAR_DEFINITION_FILENAME',\n bundlePath: 'VAR_DEFINITION_BUNDLE_PATH',\n },\n resolvedPagePath: 'VAR_RESOLVED_PAGE_PATH',\n nextConfigOutput,\n userland,\n})\n\n// Pull out the exports that we need to expose from the module. This should\n// be eliminated when we've moved the other routes to the new format. These\n// are used to hook into the route.\nconst { workAsyncStorage, workUnitAsyncStorage, serverHooks } = routeModule\n\nfunction patchFetch() {\n return _patchFetch({\n workAsyncStorage,\n workUnitAsyncStorage,\n })\n}\n\nexport {\n routeModule,\n workAsyncStorage,\n workUnitAsyncStorage,\n serverHooks,\n patchFetch,\n}\n"],"names":["AppRouteRouteModule","RouteKind","patchFetch","_patchFetch","userland","routeModule","definition","kind","APP_ROUTE","page","pathname","filename","bundlePath","resolvedPagePath","nextConfigOutput","workAsyncStorage","workUnitAsyncStorage","serverHooks"],"mappings":"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","ignoreList":[6]}