UNPKG

sync-upstream

Version:

A tool for synchronizing code with upstream repositories with incremental updates and parallel processing.

2 lines 65.5 kB
#!/usr/bin/env node "use strict";var e=require("path"),t=require("consola"),r=require("dayjs"),a=require("fs-extra"),i=require("picocolors"),s=require("picomatch"),o=require("@iarna/toml"),n=require("js-yaml"),c=require("json5"),l=require("minimist"),f=require("simple-git"),u=require("crypto"),h=require("prompts"),g=require("os"),p=require("perf_hooks"),y=require("p-limit");function m(e){return e&&e.__esModule?e:{default:e}}var d,w,$,v=m(e),b=m(r),S=m(a),P=m(s),x=m(o),C=m(n),E=m(c),R=m(l),k=m(f),F=m(u),D=m(h),B=m(g),O=m(y),T=Object.defineProperty,L=(e,t)=>()=>(e&&(t=e(e=0)),t),M=L(()=>{d={level:"info",logToFile:!1,logFilePath:v.default.join(process.cwd(),"sync-upstream.log"),showTimestamp:!0,showLevel:!0,structedLogging:!1,perfMetricsEnabled:!0,traceEnabled:!1},$=new(w=class{constructor(e={}){this.logLevels=["trace","debug","verbose","info","success","warn","error","perf"],this.config={...d,...e},this.consola=t.consola.create({level:this.logLevels.indexOf(this.config.level),formatOptions:{colors:!0,date:this.config.showTimestamp}}),this.config.logToFile&&S.default.ensureDirSync(v.default.dirname(this.config.logFilePath))}getTimestamp(){return b.default().format("YYYY-MM-DD HH:mm:ss")}logToFile(e,t,r){if(!this.config.logToFile)return;let a=this.getTimestamp();if(this.config.structedLogging){let i={timestamp:a,level:e.toUpperCase(),message:t,context:r||{}},s=`${JSON.stringify(i)}\n`;S.default.appendFile(this.config.logFilePath,s).catch(e=>console.error("写入日志文件失败:",e))}else{let i=r?` ${JSON.stringify(r)}`:"",s=this.config.showLevel?`[${a}] [${e.toUpperCase()}] ${t}${i}\n`:`[${a}] ${t}${i}\n`;S.default.appendFile(this.config.logFilePath,s).catch(e=>console.error("写入日志文件失败:",e))}}debug(e,t){if(this.logLevels.indexOf("debug")>=this.logLevels.indexOf(this.config.level)){let r=t?` ${JSON.stringify(t)}`:"";this.consola.debug(i.blue(`[DEBUG] ${e}${r}`)),this.logToFile("debug",e,t)}}verbose(e){this.logLevels.indexOf("verbose")>=this.logLevels.indexOf(this.config.level)&&(this.consola.log(i.gray(`[VERBOSE] ${e}`)),this.logToFile("verbose",e))}trace(e,t){if(this.config.traceEnabled&&this.logLevels.indexOf("trace")>=this.logLevels.indexOf(this.config.level)){let r=t?` ${JSON.stringify(t)}`:"";this.consola.log(`[TRACE] ${e}${r}`),this.logToFile("trace",e,t)}}perf(e,t,r){if(this.config.perfMetricsEnabled&&this.logLevels.indexOf("perf")>=this.logLevels.indexOf(this.config.level)){let a=t.toFixed(2),s=r?` ${JSON.stringify(r)}`:"";this.consola.log(i.cyan(`[PERF] ${e} took ${a}ms${s}`)),this.logToFile("perf",`${e} took ${a}ms`,r)}}setLevel(e){this.config.level=e,this.consola.level=this.logLevels.indexOf(e)}info(e,t){if(this.logLevels.indexOf("info")>=this.logLevels.indexOf(this.config.level)){let r=t?` ${JSON.stringify(t)}`:"";this.consola.info(i.cyan(`[INFO] ${e}${r}`)),this.logToFile("info",e,t)}}success(e,t){if(this.logLevels.indexOf("success")>=this.logLevels.indexOf(this.config.level)){let r=t?` ${JSON.stringify(t)}`:"";this.consola.success(i.green(`[SUCCESS] ${e}${r}`)),this.logToFile("success",e,t)}}warn(e,t){if(this.logLevels.indexOf("warn")>=this.logLevels.indexOf(this.config.level)){let r=t?` ${JSON.stringify(t)}`:"";this.consola.warn(i.yellow(`[WARN] ${e}${r}`)),this.logToFile("warn",e,t)}}error(e,t,r){if(this.logLevels.indexOf("error")>=this.logLevels.indexOf(this.config.level)){let a=t?`${e}: ${t.message}`:e,s={...r||{},...t?.stack?{stack:t.stack}:{}},o=s?` ${JSON.stringify(s)}`:"";this.consola.error(i.red(`[ERROR] ${a}${o}`)),this.logToFile("error",a,s)}}step(e,t){let r=i.bold(i.magenta(`\n${e}. ${t}`));this.consola.log(r),this.logToFile("info",`Step ${e}: ${t}`)}updateConfig(e){this.config={...this.config,...e},this.consola=t.consola.create({level:this.logLevels.indexOf(this.config.level),formatOptions:{colors:!0,date:this.config.showTimestamp}}),this.config.logToFile&&S.default.ensureDirSync(v.default.dirname(this.config.logFilePath))}})}),j={};function U(e){return e.split(v.default.sep).join("/")}async function z(e){let t=["**/node_modules/**","**/.git/**","**/dist/**","**/build/**"],r=v.default.join(e,".gitignore");if(await S.default.pathExists(r))try{let e=(await S.default.readFile(r,"utf8")).split("\n").map(e=>e.trim()).filter(e=>e&&!e.startsWith("#"));t=[...t,...e],$.debug(`从 .gitignore 加载了 ${e.length} 个忽略模式`)}catch(e){$.error("读取 .gitignore 文件失败:",e)}let a=v.default.join(e,".syncignore");if(await S.default.pathExists(a))try{let e=(await S.default.readFile(a,"utf8")).split("\n").map(e=>e.trim()).filter(e=>e&&!e.startsWith("#"));t=[...t,...e],$.debug(`从 .syncignore 加载了 ${e.length} 个忽略模式`)}catch(e){$.error("读取 .syncignore 文件失败:",e)}return t}function _(e,t){let r=U(e);return P.default.isMatch(r,t)}((e,t)=>{for(var r in t)T(e,r,{get:t[r],enumerable:!0})})(j,{loadIgnorePatterns:()=>z,normalizePath:()=>U,shouldIgnore:()=>_});var I=L(()=>{M()});M();var N,J,W=((J=W||{}).USE_SOURCE="use-source",J.KEEP_TARGET="keep-target",J.AUTO_MERGE="auto-merge",J.PROMPT_USER="prompt-user",J.CREATE_VERSION="create-version",J.IGNORE="ignore",J),q=((N=q||{}).FEATURE="feature",N.RELEASE="release",N.HOTFIX="hotfix",N.DEVELOP="develop",N),A={upstreamBranch:"main",companyBranch:"main",commitMessage:"Sync upstream changes to specified directories",autoPush:!1,forceOverwrite:!0,verbose:!1,silent:!1,dryRun:!1,previewOnly:!1,concurrencyLimit:10,retryConfig:{maxRetries:3,initialDelay:2e3,backoffFactor:1.5},conflictResolutionConfig:{defaultStrategy:"prompt-user"},branchStrategyConfig:{enable:!1,strategy:"feature",baseBranch:"main",branchPattern:"feature/{name}",autoSwitchBack:!0,autoDeleteMergedBranches:!1},cacheConfig:{expiryMs:6048e5,maxSizeBytes:5368709120,lruEnabled:!0,lruMaxEntries:1e3}};var V=[".sync-toolrc.json5",".sync-toolrc.json",".sync-toolrc.yaml",".sync-toolrc.yml",".sync-toolrc.toml",".sync-toolrc","sync-tool.config.json5","sync-tool.config.json","sync-tool.config.yaml","sync-tool.config.yml","sync-tool.config.toml","sync-upstream.config.json"];function H(e){if(e.conflictResolutionConfig?.defaultStrategy){let t=Object.values(W);if(!t.includes(e.conflictResolutionConfig.defaultStrategy))throw $.error("无效的冲突解决策略",void 0,{strategy:e.conflictResolutionConfig.defaultStrategy,validStrategies:t}),new Error(`无效的冲突解决策略: ${e.conflictResolutionConfig.defaultStrategy}. 有效策略: ${t.join(", ")}`)}if(e.retryConfig){if(void 0!==e.retryConfig.maxRetries&&e.retryConfig.maxRetries<0)throw $.error("最大重试次数不能为负数",void 0,{maxRetries:e.retryConfig.maxRetries}),new Error("最大重试次数不能为负数");if(void 0!==e.retryConfig.initialDelay&&e.retryConfig.initialDelay<0)throw $.error("初始重试延迟不能为负数",void 0,{initialDelay:e.retryConfig.initialDelay}),new Error("初始重试延迟不能为负数");if(void 0!==e.retryConfig.backoffFactor&&e.retryConfig.backoffFactor<1)throw $.error("重试退避因子必须大于或等于1",void 0,{backoffFactor:e.retryConfig.backoffFactor}),new Error("重试退避因子必须大于或等于1")}if(void 0!==e.concurrencyLimit&&e.concurrencyLimit<1)throw $.error("并行处理数量必须大于或等于1",void 0,{concurrencyLimit:e.concurrencyLimit}),new Error("并行处理数量必须大于或等于1");if(e.branchStrategyConfig){let{branchStrategyConfig:t}=e,r=Object.values(q);if(!r.includes(t.strategy))throw $.error("无效的分支策略",void 0,{strategy:t.strategy,validStrategies:r}),new Error(`无效的分支策略: ${t.strategy}. 有效策略: ${r.join(", ")}`);if(!t.baseBranch||""===t.baseBranch.trim())throw $.error("基础分支名称不能为空",void 0,{baseBranch:t.baseBranch}),new Error("基础分支名称不能为空");if(!t.branchPattern||""===t.branchPattern.trim())throw $.error("分支命名模式不能为空",void 0,{branchPattern:t.branchPattern}),new Error("分支命名模式不能为空")}if(e.cacheConfig){let{cacheConfig:t}=e;if(void 0!==t.expiryMs&&t.expiryMs<0)throw $.error("缓存过期时间不能为负数",void 0,{expiryMs:t.expiryMs}),new Error("缓存过期时间不能为负数");if(void 0!==t.maxSizeBytes&&t.maxSizeBytes<0)throw $.error("最大缓存大小不能为负数",void 0,{maxSizeBytes:t.maxSizeBytes}),new Error("最大缓存大小不能为负数");if(void 0!==t.lruMaxEntries&&t.lruMaxEntries<1)throw $.error("LRU最大条目数必须大于或等于1",void 0,{lruMaxEntries:t.lruMaxEntries}),new Error("LRU最大条目数必须大于或等于1")}}async function G(){for(let e of V){let t=v.default.join(process.cwd(),e);if(await S.default.pathExists(t)){$.trace(`找到配置文件: ${e}`);try{let r=await S.default.readFile(t,"utf8"),a={};return e.endsWith(".json5")?($.trace(`解析JSON5配置文件: ${e}`),a=E.default.parse(r)):e.endsWith(".json")?($.trace(`解析JSON配置文件: ${e}`),a=JSON.parse(r)):e.endsWith(".yaml")||e.endsWith(".yml")?($.trace(`解析YAML配置文件: ${e}`),a=C.default.load(r)):e.endsWith(".toml")?($.trace(`解析TOML配置文件: ${e}`),a=x.default.parse(r)):($.trace(`尝试作为JSON解析配置文件: ${e}`),a=JSON.parse(r)),H(a),$.debug(`配置文件 ${e} 加载成功`),{...A,...a}}catch(t){$.error(`读取配置文件 ${e} 失败`,t)}}}return $.debug("未找到配置文件,使用默认配置"),A}M(),M();var K=class extends Error{constructor(e,t,r="error",a,i){super(e),this.code=t,this.severity=r,this.originalError=a,this.timestamp=new Date,this.context=i,this.name=this.constructor.name,Object.setPrototypeOf(this,new.target.prototype)}display(){let e=this.getSeverityColor();console.error(e(`\n❌ ${this.name} (${this.code}):`)),console.error(e(this.message)),this.context&&(console.error(i.blue("错误上下文:")),console.error(i.blue(JSON.stringify(this.context,null,2)))),this.originalError&&(console.error(i.yellow("原始错误:")),console.error(i.yellow(this.originalError.message)),$.error(`原始错误栈: ${this.originalError.stack||"无"}`)),this.logError()}getSeverityColor(){switch(this.severity){case"info":return i.blue;case"warning":return i.yellow;case"error":default:return i.red;case"critical":return i.bold(i.red)}}logError(){let e={name:this.name,code:this.code,message:this.message,severity:this.severity,timestamp:this.timestamp.toISOString(),context:this.context,originalError:this.originalError?.message};switch(this.severity){case"info":$.info(JSON.stringify(e));break;case"warning":$.warn(JSON.stringify(e));break;case"error":$.error(JSON.stringify(e));break;case"critical":$.error(i.bold(i.red(JSON.stringify(e))))}}},Y=class extends K{constructor(e,t,r){super(e,"GIT_ERROR","error",t,r)}},X=class extends K{constructor(e,t,r){super(e,"FS_ERROR","error",t,r)}},Q=class extends K{constructor(e,t,r){super(e,"NETWORK_ERROR","warning",t,r)}},Z=class extends K{constructor(e="用户取消了操作",t){super(e,"USER_CANCEL","info",void 0,t)}},ee=class extends K{constructor(e,t,r){super(e,"SYNC_PROCESS_ERROR","error",t,r)}};async function te(e,t,r=e=>{let t=e.message.toLowerCase();return t.includes("network")||t.includes("connect")}){let a;for(let i=0;i<=t.maxRetries;i++)try{if(i>0){let e=t.initialDelay*t.backoffFactor**(i-1);$.info(`正在进行第 ${i}/${t.maxRetries} 次重试,延迟 ${e}ms...`),await new Promise(t=>setTimeout(t,e))}return await e()}catch(e){if(a=e,!r(a))throw $.error(`非网络错误,不进行重试: ${a.message}`),a;if(i>=t.maxRetries)throw $.error(`达到最大重试次数(${t.maxRetries}),请求失败: ${a.message}`),new Q("网络请求失败",a);$.warn(`请求失败(第 ${i} 次尝试): ${a.message}`)}throw a}M();var re=v.default.join(process.cwd(),".sync-cache"),ae=null,ie=!1,se=0,oe=3e5,ne={expiryMs:6048e5,maxSizeBytes:5368709120,lruEnabled:!0,lruMaxEntries:1e3,typeBasedExpiry:{html:36e5,json:864e5,binary:6048e5,image:2592e6},keyPrefix:"",compressEnabled:!0,compressionLevel:6,compressionThreshold:10240,warmupEnabled:!1,warmupKeys:[]},ce=v.default.join(re,"metadata.json"),le={hits:0,misses:0,totalSize:0},fe=new Map;function ue(){if(!ae)return $.warn("缓存配置尚未初始化,使用默认配置"),ne;let e=ae.cache||{};return{...ne,...e}}async function he(){try{let e={stats:le,lruMap:Object.fromEntries(fe),timestamp:Date.now()};await S.default.writeFile(ce,JSON.stringify(e,null,2))}catch(e){$.error(`保存缓存元数据失败: ${e instanceof Error?e.message:String(e)}`)}}async function ge(){if(ie)$.debug("缓存已经初始化,跳过初始化步骤");else try{ae=await G(),$.info("配置已加载"),await S.default.ensureDir(re),$.info(`缓存目录已初始化: ${re}`),await async function(){try{if(await S.default.pathExists(ce)){let e=await S.default.readFile(ce,"utf8"),t=JSON.parse(e);le=t.stats||le,fe=new Map(Object.entries(t.lruMap||{})),$.info("缓存元数据已加载")}}catch(e){$.error(`加载缓存元数据失败: ${e instanceof Error?e.message:String(e)}`),le={hits:0,misses:0,totalSize:0},fe=new Map}}(),await ve(),await ye(),ie=!0,setInterval(async()=>{try{$.debug("执行定期缓存清理..."),await ve(),await ye()}catch(e){$.error(`定期清理缓存失败: ${e instanceof Error?e.message:String(e)}`)}},oe),$.info("定期缓存清理已启动,间隔: 5分钟"),ue().warmupEnabled&&($.info("开始缓存预热..."),await async function(){try{let e=ue(),{warmupKeys:t}=e,r=t.length;if(0===r)return $.info("没有配置预热键,跳过缓存预热"),void 0;$.info(`开始缓存预热,共 ${r} 个键`);let a=0,i=0,s=Math.min(5,r),o=[];for(let e=0;e<r;e+=s)o.push(t.slice(e,e+s));for(let e of o){let t=e.map(async e=>{try{$.debug(`预热缓存键: ${e}`);let t=Buffer.from(`Warmed up data for key: ${e}`);await $e(e,t),a++}catch(t){$.error(`预热缓存键 ${e} 失败: ${t instanceof Error?t.message:String(t)}`),i++}});await Promise.all(t)}$.success(`缓存预热完成: 成功 ${a} 个, 失败 ${i} 个`)}catch(e){$.error(`缓存预热失败: ${e instanceof Error?e.message:String(e)}`)}}())}catch(e){throw $.error(`初始化缓存目录失败: ${e instanceof Error?e.message:String(e)}`),e}}function pe(e){let t=ue();if(t.lruEnabled&&(fe.delete(e),fe.set(e,Date.now()),fe.size>t.lruMaxEntries)){let e=null,t=1/0;for(let[r,a]of fe.entries())a<t&&(e=r,t=a);e&&(fe.delete(e),S.default.remove(v.default.join(re,e)).catch(e=>$.error(`删除LRU淘汰的缓存文件失败: ${e instanceof Error?e.message:String(e)}`)),$.info(`LRU策略: 已删除最旧的缓存条目 ${e}`))}}async function ye(){try{let e=ue();if(e.maxSizeBytes<=0)return;if(le.totalSize>e.maxSizeBytes){$.info(`缓存大小 ${me(le.totalSize)} 已超过限制 ${me(e.maxSizeBytes)},开始清理`);let t=Array.from(fe.entries()).sort((e,t)=>e[1]-t[1]),r=le.totalSize-e.maxSizeBytes;for(let[e,a]of t){if(r<=0)break;let t=v.default.join(re,e);if(await S.default.pathExists(t)){let a=await S.default.stat(t);await S.default.remove(t),r-=a.size,le.totalSize-=a.size,fe.delete(e),$.info(`已删除缓存文件 ${e},释放 ${me(a.size)} 空间`)}}$.info(`缓存清理完成,当前大小: ${me(le.totalSize)}`)}await he()}catch(e){$.error(`检查缓存大小限制失败: ${e instanceof Error?e.message:String(e)}`)}}function me(e){if(0===e)return"0 Bytes";let t=Math.floor(Math.log(e)/Math.log(1024));return`${Number.parseFloat((e/1024**t).toFixed(2))} ${["Bytes","KB","MB","GB"][t]}`}async function de(e,t={}){try{if(!await async function(e,t={}){let r=v.default.join(re,e),a=ue();try{if(!await S.default.pathExists(r))return!1;let i=await S.default.stat(r),s=Date.now(),o=a.expiryMs,n=t.contentType;if(n&&a.typeBasedExpiry){let e=a.typeBasedExpiry[n];void 0!==e&&(o=e,$.debug(`使用内容类型 ${n} 的过期时间: ${o}ms`))}return s-i.mtimeMs>o?($.info(`缓存 ${e} 已过期,将删除`),await S.default.remove(r),fe.delete(e),le.totalSize-=i.size,await he(),!1):(pe(e),!0)}catch(e){return $.error(`检查缓存有效性失败: ${e instanceof Error?e.message:String(e)}`),!1}}(e,t))return le.misses++,await we(),null;let r=v.default.join(re,e),a=await S.default.pathExists(`${r}.compressed`),i=await S.default.readFile(r);if(a&&!1!==t.decompress)try{let t=await import("zlib"),r=await new Promise((e,r)=>{t.gunzip(i,(t,a)=>{t?r(t):e(a)})});i=Buffer.from(r),$.debug(`缓存数据已解压缩: ${e}`)}catch(e){return $.error(`解压缩缓存数据失败: ${e instanceof Error?e.message:String(e)}`),i}return le.hits++,$.info(`从缓存获取数据: ${e} (命中: ${le.hits}, 未命中: ${le.misses})${a?" (已压缩)":""}`),await we(),i}catch(e){return $.error(`从缓存读取数据失败: ${e instanceof Error?e.message:String(e)}`),null}}async function we(){let e=Date.now();(e-se>1e3||0===le.hits&&0===le.misses)&&(await he(),se=e)}async function $e(e,t,r,a={}){try{let i=v.default.join(re,e),s=ue(),o=void 0!==a.compress?a.compress:s.compressEnabled,n=a.compressionLevel||s.compressionLevel||6,c=t,l=!1;if(o&&t.length>s.compressionThreshold)try{let e=await import("zlib");c=await new Promise((r,a)=>{e.gzip(t,{level:n},(e,t)=>{e?a(e):r(t)})}),l=!0,$.debug(`缓存数据已压缩: ${me(t.length)} -> ${me(c.length)}`)}catch(e){$.warn(`压缩缓存数据失败,将使用原始数据: ${e instanceof Error?e.message:String(e)}`),l=!1}await te(async()=>{await S.default.writeFile(i,c),l?await S.default.writeFile(`${i}.compressed`,"1"):await S.default.pathExists(`${i}.compressed`)&&await S.default.remove(`${i}.compressed`);let t=await S.default.stat(i);if(fe.has(e))try{let e=await S.default.stat(i);le.totalSize-=e.size}catch(e){$.warn(`获取旧缓存大小失败: ${e instanceof Error?e.message:String(e)}`)}le.totalSize+=t.size,le.misses++,pe(e),$.info(`数据已写入缓存: ${e} (大小: ${me(t.size)}${l?", 已压缩":""})`),await ye(),await we()},r||{maxRetries:3,initialDelay:1e3,backoffFactor:2})}catch(e){$.error(`写入缓存失败: ${e instanceof Error?e.message:String(e)}`)}}async function ve(){try{if(!await S.default.pathExists(re))return void $.info("缓存目录不存在,跳过清理");let e=ue(),t=await S.default.readdir(re,{withFileTypes:!0}),r=Date.now(),a=0,i=0;for(let s of t)if(s.name!==v.default.basename(ce)&&s.isFile()){let t=v.default.join(re,s.name),o=await S.default.stat(t),n=s.name;r-o.mtimeMs>e.expiryMs&&(await S.default.remove(t),a++,i+=o.size,fe.has(n)&&(fe.delete(n),le.totalSize-=o.size),$.debug(`已删除过期缓存: ${n} (大小: ${me(o.size)})`))}a>0?($.info(`已清理 ${a} 个过期缓存文件,释放 ${me(i)} 空间`),await he()):$.info("没有过期缓存需要清理")}catch(e){$.error(`清理过期缓存失败: ${e instanceof Error?e.message:String(e)}`)}}M(),"function"!=typeof D.default&&(console.error("Error: prompts is not a function"),process.exit(1)),I(),M();var be=new w,Se=655360;async function Pe(e,t={}){let{useCache:r=!0,largeFileBufferSize:a=Se}=t;try{let t=await S.default.stat(e);if(!t.isFile())throw new Error(`路径 ${e} 不是文件,无法计算哈希值`);let i=function(e,t={},r={}){let a=Object.keys(t).sort().reduce((e,r)=>(e[r]=t[r],e),{}),i=`${e}${JSON.stringify(a)}`;if(r.contentType&&(i+=`|type:${r.contentType}`),r.includeTimestamp){let e=r.timestampTtl||36e5;i+="|ts:"+Math.floor(Date.now()/e)*e}let s=r.hashAlgorithm||"md5",o=F.default.createHash(s).update(i).digest("hex"),n=ue(),c=r.customPrefix||n.keyPrefix,l=c?c.replace(/[:\\/*?"<>|]/g,"-"):"";return l?`${l}-${s}-${o}`:`${s}-${o}`}("file-hash",{filePath:e});if(r){let e=await de(i);if(e)return e.toString()}if(t.size>10485760)return be.debug(`文件 ${e} 大小为 ${(t.size/1024/1024).toFixed(2)}MB,使用流式处理`),new Promise((t,s)=>{let o=F.default.createHash("md5"),n=S.default.createReadStream(e,{highWaterMark:a});n.on("data",e=>{o.update(e)}),n.on("error",t=>{be.error(`流式读取文件 ${e} 时出错:`,t),s(t)}),n.on("end",()=>{let e=o.digest("hex");r&&$e(i,Buffer.from(e)).catch(e=>{be.error("写入缓存失败:",e)}),t(e)})});{let t=await S.default.readFile(e),a=F.default.createHash("md5").update(t).digest("hex");return r&&await $e(i,Buffer.from(a)),a}}catch(t){throw"EISDIR"===t.code?be.error(`错误: 尝试读取目录 ${e} 作为文件`):be.error(`计算文件 ${e} 哈希值时出错:`,t.message),t}}async function xe(e,t=[],r,a={}){let{parallelLimit:i=10,useCache:s=!0,onProgress:o}=a,n=O.default(i);try{if(!(await S.default.stat(e)).isDirectory())throw new Error(`路径 ${e} 不是目录,无法计算哈希值`);let a=await S.default.readdir(e,{withFileTypes:!0}),c={},l=a.length,f=0,u=a.map(async a=>{try{let o=v.default.join(e,a.name),n=v.default.relative(process.cwd(),o),l=U(n);if(r(l,t))return;if(a.isDirectory()){let e=await xe(o,t,r,{parallelLimit:i,useCache:s});Object.assign(c,e)}else await S.default.pathExists(o)?(await S.default.stat(o)).isFile()?c[n]=await te(()=>Pe(o,{useCache:s}),{maxRetries:3,initialDelay:1e3,backoffFactor:2}):be.warn(`警告: 条目 ${a.name} 不是文件,跳过`):be.warn(`警告: 条目 ${a.name} 不存在,跳过`)}catch(e){be.error(`处理条目 ${a.name} 时出错:`,e)}finally{f++,o&&o(f,l)}}).map(e=>n(()=>e));return await Promise.all(u),c}catch(t){return be.error(`计算目录 ${e} 哈希值时出错:`,t),{}}}async function Ce(e){try{return(await S.default.stat(e)).mtime.getTime().toString()}catch(t){return console.error(`Failed to get version for file ${e}:`,t),null}}I(),M();var Ee=class{constructor(e){this.config=e}async detectFileConflict(e,t,r={}){try{let{checkVersion:a=!1,checkPermissions:i=!1}=r,s=await S.default.pathExists(e),o=await S.default.pathExists(t);if(!s||!o)return null;let n=await S.default.stat(e),c=await S.default.stat(t);if(n.isDirectory()!==c.isDirectory())return{type:"type",sourcePath:e,targetPath:t,sourceType:n.isDirectory()?"directory":"file",targetType:c.isDirectory()?"directory":"file"};if(n.isDirectory()&&c.isDirectory()){let r=await S.default.lstat(e),a=await S.default.lstat(t),i=r.isSymbolicLink(),s=a.isSymbolicLink();if(i||s){let r=i?await S.default.readlink(e):void 0,a=s?await S.default.readlink(t):void 0;if(r!==a)return{type:"symlink",sourcePath:e,targetPath:t,symlinkTarget:void 0!==r?r:a}}return null}let l=await Pe(e),f=await Pe(t);if(l!==f){if(a){let r=await Ce(e)||"1.0.0",a=await Ce(t)||"1.0.0";if(r!==a)return{type:"version",sourcePath:e,targetPath:t,sourceHash:l,targetHash:f,sourceVersion:r,targetVersion:a}}return{type:"content",sourcePath:e,targetPath:t,sourceHash:l,targetHash:f}}if(i){let r=511&n.mode,a=511&c.mode;if(r!==a)return{type:"permission",sourcePath:e,targetPath:t,sourcePermissions:r,targetPermissions:a}}let u=!1;return u?{type:"lock",sourcePath:e,targetPath:t,lockInfo:{owner:u?"user1":"user2",timestamp:new Date,processId:u?1234:5678}}:null}catch(r){throw new X(`检测文件冲突时出错: ${e} vs ${t}`,r)}}async detectDirectoryConflicts(e,t,r=[],a={}){let{quickCheck:i=!0,cache:s=new Map}=a,o=[],n=`${e}:${t}`;if(s.has(n))return s.get(n)||[];try{if(i){let r=await S.default.pathExists(e),a=await S.default.pathExists(t);if(r&&a){let r=await S.default.stat(e).then(e=>e.isDirectory()),a=await S.default.stat(t).then(e=>e.isDirectory());if(r!==a){let i={type:"type",sourcePath:e,targetPath:t,sourceType:r?"directory":"file",targetType:a?"directory":"file"};return o.push(i),s.set(n,o),o}}}let a=await S.default.readdir(e,{withFileTypes:!0});for(let n of a){let a=v.default.join(e,n.name),c=v.default.join(t,n.name);if(_(v.default.relative(process.cwd(),a),r))continue;let l=n.name.toLowerCase(),f=["node_modules","dist","build","coverage",".git"].includes(l);if(n.isDirectory())if(f)await S.default.pathExists(c)&&(await S.default.stat(c).then(e=>e.isDirectory())||o.push({type:"type",sourcePath:a,targetPath:c,sourceType:"directory",targetType:"file"}));else{let e=await this.detectDirectoryConflicts(a,c,r,{quickCheck:i,cache:s});o.push(...e)}else{let e=await this.detectFileConflict(a,c);e&&o.push(e)}}return s.set(n,o),o}catch(r){throw new X(`检测目录冲突时出错: ${e} vs ${t}`,r)}}async resolveConflict(e,t,r={}){let{autoMergeDepth:a=3,backup:s=!0}=r,o=t||this.config.defaultStrategy;switch($.info(`\n解决冲突: ${i.yellow(e.type)}`),$.info(`源文件: ${i.blue(e.sourcePath)}`),$.info(`目标文件: ${i.blue(e.targetPath)}`),e.type){case"content":$.info(`源文件哈希: ${e.sourceHash}`),$.info(`目标文件哈希: ${e.targetHash}`);break;case"type":$.info(`源文件类型: ${e.sourceType}`),$.info(`目标文件类型: ${e.targetType}`);break;case"version":$.info(`源文件版本: ${e.sourceVersion}`),$.info(`目标文件版本: ${e.targetVersion}`);break;case"permission":$.info(`源文件权限: ${e.sourcePermissions?.toString(8)}`),$.info(`目标文件权限: ${e.targetPermissions?.toString(8)}`);break;case"lock":$.info(`锁定所有者: ${e.lockInfo?.owner}`),$.info(`锁定时间: ${e.lockInfo?.timestamp.toISOString()}`);break;case"symlink":$.info(`符号链接目标: ${e.symlinkTarget}`)}if(s)try{await this.createBackup(e.targetPath),$.info(`已创建目标文件备份: ${i.green(`${e.targetPath}.bak`)}`)}catch(e){$.warn(`创建备份失败: ${e instanceof Error?e.message:String(e)}`)}try{switch(e.type){case"content":return await this.resolveContentConflict(e,o,{autoMergeDepth:a});case"type":return await this.resolveTypeConflict(e,o);case"rename":return await this.resolveRenameConflict(e,o);case"version":return await this.resolveVersionConflict(e,o);case"permission":return await this.resolvePermissionConflict(e,o);case"lock":return await this.resolveLockConflict(e,o);case"symlink":return await this.resolveSymlinkConflict(e,o);default:return $.error(`未支持的冲突类型: ${i.red(e.type)}`),!1}}catch(e){return $.error(`解决冲突失败: ${e instanceof Error?e.message:String(e)}`),!1}}async createBackup(e){let t=`${e}.bak`;await S.default.pathExists(e)&&await S.default.copyFile(e,t)}async autoMergeFiles(e,t,r){try{let a=await S.default.readFile(e,"utf8"),i=await S.default.readFile(t,"utf8"),s=(a.split("\n"),[...i.split("\n")]),o=!1;return r>=1&&(o=!0),!!o&&(await S.default.writeFile(t,s.join("\n"),"utf8"),!0)}catch(e){return $.error(`自动合并文件失败: ${e instanceof Error?e.message:String(e)}`),!1}}async promptUserForConflictResolution(e){try{let t=[{title:"使用源文件覆盖",value:"use-source"},{title:"保留目标文件",value:"keep-target"},{title:"尝试自动合并",value:"auto-merge"}];"version"===e.type&&t.push({title:"创建新版本",value:"create-version"});let{resolution:r}=await D.default({type:"select",name:"resolution",message:"请选择冲突解决方式:",choices:t});if(!r)throw new Z("用户取消了冲突解决");if("create-version"===r){let t=`${e.targetPath}.v${Date.now()}`;return await S.default.copyFile(e.sourcePath,t),$.success(`已创建新版本文件: ${i.green(t)}`),!0}return await this.resolveConflict(e,r,{backup:!1})}catch(e){if(e instanceof Z)throw e;return $.error(`提示用户解决冲突失败: ${e instanceof Error?e.message:String(e)}`),!1}}async resolveVersionConflict(e,t){switch(t){case"use-source":return await S.default.copyFile(e.sourcePath,e.targetPath),$.success(`使用源文件(版本 ${e.sourceVersion})覆盖目标文件: ${i.green(e.targetPath)}`),!0;case"keep-target":return $.info(`保留目标文件(版本 ${e.targetVersion}): ${i.green(e.targetPath)}`),!0;case"auto-merge":return await this.autoMergeFiles(e.sourcePath,e.targetPath,3)?($.success(`自动合并版本成功: ${i.green(e.targetPath)}`),!0):($.warn("自动合并版本失败,将提示用户解决"),await this.promptUserForConflictResolution(e));default:return await this.promptUserForConflictResolution(e)}}async resolvePermissionConflict(e,t){switch(t){case"use-source":return void 0!==e.sourcePermissions&&(await S.default.chmod(e.targetPath,e.sourcePermissions),$.success(`应用源文件权限 ${e.sourcePermissions.toString(8)} 到目标文件: ${i.green(e.targetPath)}`)),!0;case"keep-target":return $.info(`保留目标文件权限: ${i.green(e.targetPath)}`),!0;default:return await this.promptUserForConflictResolution(e)}}async resolveLockConflict(e,t){switch(t){case"use-source":try{return await S.default.copyFile(e.sourcePath,e.targetPath),$.success(`强制覆盖锁定的文件: ${i.green(e.targetPath)}`),!0}catch(e){return $.error(`无法覆盖锁定的文件: ${e instanceof Error?e.message:String(e)}`),!1}case"keep-target":return $.info(`保留锁定的目标文件: ${i.green(e.targetPath)}`),!0;default:return await this.promptUserForConflictResolution(e)}}async resolveSymlinkConflict(e,t){switch(t){case"use-source":if(await S.default.pathExists(e.targetPath)&&await S.default.unlink(e.targetPath),(await S.default.lstat(e.sourcePath)).isSymbolicLink()){let t=await S.default.readlink(e.sourcePath);await S.default.symlink(t,e.targetPath),$.success(`创建符号链接: ${i.green(e.targetPath)} -> ${t}`)}else(await S.default.stat(e.sourcePath)).isDirectory()?await S.default.copy(e.sourcePath,e.targetPath,{overwrite:!0}):await S.default.copyFile(e.sourcePath,e.targetPath),$.success(`复制源文件/目录到目标位置: ${i.green(e.targetPath)}`);return!0;case"keep-target":return $.info(`保留目标符号链接/文件: ${i.green(e.targetPath)}`),!0;default:return await this.promptUserForConflictResolution(e)}}async resolveContentConflict(e,t,r={}){let a=!1,s=v.default.extname(e.sourcePath).toLowerCase(),o=this.config.autoResolveTypes?.includes(s)||!1,n=`${e.sourcePath}-${e.targetPath}-${Date.now()}`;switch(this.config.logResolutions&&$.info(`开始解决冲突: ${n} (${e.type})`),t){case"use-source":await S.default.copyFile(e.sourcePath,e.targetPath),$.info(`冲突解决: 使用源文件覆盖目标文件 ${i.yellow(e.targetPath)}`),a=!0;break;case"keep-target":$.info(`冲突解决: 保留目标文件 ${i.yellow(e.targetPath)}`),a=!0;break;case"auto-merge":try{let{autoMergeDepth:t=3}=r,o=await S.default.readFile(e.sourcePath,"utf8"),n=await S.default.readFile(e.targetPath,"utf8"),c="";c=[".js",".ts",".jsx",".tsx",".css",".scss",".html"].includes(s)?this.smartMerge(o,n,e):`<<<<<<< SOURCE\n${o}\n=======\n${n}\n>>>>>>> TARGET`,await S.default.writeFile(e.targetPath,c),$.info(`冲突解决: 自动合并文件 ${i.yellow(e.targetPath)}`),a=!0}catch(t){return $.error(`自动合并失败,回退到提示用户: ${t instanceof Error?t.message:String(t)}`),this.resolveContentConflict(e,"prompt-user")}break;case"prompt-user":if(o)return $.debug(`文件 ${i.yellow(e.targetPath)} 是自动解决类型,使用默认策略 ${this.config.defaultStrategy}`),this.resolveContentConflict(e,this.config.defaultStrategy);let n=await S.default.readFile(e.sourcePath,"utf8"),c=await S.default.readFile(e.targetPath,"utf8"),l=this.generateDiffPreview(n,c),{resolution:f}=await D.default({type:"select",name:"resolution",message:`文件 ${i.yellow(e.targetPath)} 存在内容冲突,如何解决?\n${l}`,choices:[{title:"使用源文件覆盖",value:"use-source"},{title:"保留目标文件",value:"keep-target"},{title:"尝试自动合并",value:"auto-merge"},{title:"查看并编辑合并结果",value:"edit"}]});if("edit"===f){$.info(`提示: 请手动编辑文件 ${i.yellow(e.targetPath)} 解决冲突`);let t=`<<<<<<< SOURCE\n${n}\n=======\n${c}\n>>>>>>> TARGET`;return await S.default.writeFile(e.targetPath,t),!1}return this.resolveContentConflict(e,f);default:return $.error(`未知的解决策略: ${t}`),!1}return a&&this.config.logResolutions&&this.recordConflictResolution(e,t,n),a}smartMerge(e,t,r){let a=e.split("\n"),i=t.split("\n"),s=[],o=0,n=0;for(;o<a.length||n<i.length;){if(o>=a.length){s.push(...i.slice(n));break}if(n>=i.length){s.push(...a.slice(o));break}if(a[o]===i[n])s.push(a[o]),o++,n++;else{let e=-1;for(let t=n+1;t<i.length;t++)if(i[t]===a[o]){e=t;break}let t=-1;for(let e=o+1;e<a.length;e++)if(a[e]===i[n]){t=e;break}-1!==e&&-1!==t?e-n<t-o?(s.push(...i.slice(n,e)),n=e):(s.push(...a.slice(o,t)),o=t):-1!==e?(s.push(...i.slice(n,e)),n=e):-1!==t?(s.push(...a.slice(o,t)),o=t):(s.push("<<<<<<< SOURCE"),s.push(a[o]),s.push("======="),s.push(i[n]),s.push(">>>>>>> TARGET"),o++,n++)}}return s.join("\n")}generateDiffPreview(e,t){let r=e.split("\n"),a=t.split("\n"),i=0,s="";for(let e=0;e<Math.max(r.length,a.length)&&i<5;e++){let t=e<r.length?r[e]:"",o=e<a.length?a[e]:"";t!==o&&(s+=`\n- ${t}`,s+=`\n+ ${o}`,i++)}return 0===i?"\n没有检测到明显差异(可能是空白字符或格式差异)":(i>=5&&(s+="\n... 更多差异(显示前5行)"),s)}recordConflictResolution(e,t,r){let a={id:r,timestamp:(new Date).toISOString(),conflictType:e.type,sourcePath:e.sourcePath,targetPath:e.targetPath,resolutionStrategy:t,userId:"system"};$.info(`冲突解决记录: ${r} 类型=${e.type} 策略=${t}`),$.debug(`详细记录: ${JSON.stringify(a,null,2)}`)}async resolveTypeConflict(e,t){let r=!1,a=v.default.extname(e.sourcePath).toLowerCase(),s=this.config.autoResolveTypes?.includes(a)||!1;switch(t){case"use-source":await S.default.pathExists(e.targetPath)&&await S.default.remove(e.targetPath),"directory"===e.sourceType?(await S.default.mkdir(e.targetPath,{recursive:!0}),await S.default.copy(e.sourcePath,e.targetPath)):await S.default.copyFile(e.sourcePath,e.targetPath),$.info(`冲突解决: 使用源${e.sourceType}覆盖目标${e.targetType} ${i.yellow(e.targetPath)}`),r=!0;break;case"keep-target":$.info(`冲突解决: 保留目标${e.targetType} ${i.yellow(e.targetPath)}`),r=!0;break;case"prompt-user":if(s)return $.debug(`路径 ${i.yellow(e.targetPath)} 是自动解决类型,使用默认策略 ${this.config.defaultStrategy}`),this.resolveTypeConflict(e,this.config.defaultStrategy);let{resolution:a}=await D.default({type:"select",name:"resolution",message:`路径 ${i.yellow(e.targetPath)} 存在类型冲突(源是${e.sourceType},目标是${e.targetType}),如何解决?`,choices:[{title:`使用源${e.sourceType}覆盖`,value:"use-source"},{title:`保留目标${e.targetType}`,value:"keep-target"}]});return this.resolveTypeConflict(e,a);default:return $.error(`未知的解决策略: ${t}`),!1}return r&&this.config.logResolutions&&$.debug(`冲突解决日志: 类型=${e.type}, 源文件=${e.sourcePath}, 目标文件=${e.targetPath}, 策略=${t}`),r}async resolveRenameConflict(e,t){let r=!1,a=v.default.extname(e.sourcePath).toLowerCase(),s=this.config.autoResolveTypes?.includes(a)||!1;switch(t){case"use-source":await S.default.pathExists(e.targetPath)&&await S.default.remove(e.targetPath),await S.default.pathExists(e.sourcePath)?((await S.default.stat(e.sourcePath)).isDirectory()?(await S.default.mkdir(e.targetPath,{recursive:!0}),await S.default.copy(e.sourcePath,e.targetPath)):await S.default.copyFile(e.sourcePath,e.targetPath),$.info(`冲突解决: 使用源文件 ${i.yellow(e.sourcePath)} 覆盖目标路径 ${i.yellow(e.targetPath)}`),r=!0):$.error(`源文件不存在: ${e.sourcePath}`);break;case"keep-target":$.info(`冲突解决: 保留目标文件 ${i.yellow(e.targetPath)}`),r=!0;break;case"prompt-user":if(s)return $.debug(`文件 ${i.yellow(e.sourcePath)} 是自动解决类型,使用默认策略 ${this.config.defaultStrategy}`),this.resolveRenameConflict(e,this.config.defaultStrategy);let{resolution:a}=await D.default({type:"select",name:"resolution",message:`检测到重命名冲突: ${i.yellow(e.sourcePath)} -> ${i.yellow(e.targetPath)},如何解决?`,choices:[{title:"使用源文件覆盖目标路径",value:"use-source"},{title:"保留目标文件",value:"keep-target"}]});return this.resolveRenameConflict(e,a);default:return $.error(`未知的解决策略: ${t}`),!1}return r&&this.config.logResolutions&&$.debug(`冲突解决日志: 类型=${e.type}, 源文件=${e.sourcePath}, 目标文件=${e.targetPath}, 策略=${t}`),r}async resolveConflicts(e){let t=0;if(0===e.length)return $.info("没有检测到冲突"),t;$.warn(i.yellow(`检测到 ${e.length} 个冲突`));for(let r of e)await this.resolveConflict(r)&&t++;return $.info(`成功解决 ${t}/${e.length} 个冲突`),t}};async function Re(e,t=104857600){try{let r=await S.default.stat(e);return r.isFile()&&r.size>=t}catch(e){return $.error(`检查文件大小失败: ${e instanceof Error?e.message:String(e)}`),!1}}I(),M(),M();var ke=class{constructor(e){this.total=0,this.value=0,this.format=e.format}update(e){this.total=e.total,this.value=e.value;let t=Math.round(this.value/this.total*100),r=Math.min(Math.round(30*this.value/this.total),30),a="█".repeat(r)+"░".repeat(30-r);console.log(`\r${this.format.replace("{bar}",a).replace("{percentage}",t.toString())}`)}stop(){console.log("\n")}},Fe=class{constructor(e){this.options=e,this.progressBar=null,this.stepCounter=1,this.tempResourcesCreated=!1,this.adaptiveConcurrency=!0,this.originalBranch="",this.strategyBranch="",this.operationTimes={};let t={progress:this.handleProgress.bind(this),config:["core.quiet="+(e.silent?"true":"false")]};if(this.options.authConfig){let{authConfig:e}=this.options;switch(e.type){case"ssh":e.privateKeyPath&&(t.config.push(`core.sshCommand=ssh -i ${e.privateKeyPath}`),e.passphrase&&$.info("使用带密码的 SSH 密钥,需要时将提示输入密码"));break;case"user_pass":if(e.username&&e.password){let t=new URL(this.options.upstreamRepo);t.username=encodeURIComponent(e.username),t.password=encodeURIComponent(e.password),$.info("使用用户名和密码认证")}break;case"pat":if(e.token){let t=new URL(this.options.upstreamRepo);t.username="git",t.password=encodeURIComponent(e.token),$.info("使用个人访问令牌认证")}break;default:$.warn(`未知的认证类型: ${e.type}`)}}this.git=k.default(t),this.tempDir=v.default.join(process.cwd(),".sync-temp"),this.tempBranch=`temp-sync-${Date.now()}`,this.hashFile=v.default.join(process.cwd(),".sync-hashes.json"),this.forceOverwrite=void 0===e.forceOverwrite||e.forceOverwrite,this.cpuCount=B.default.cpus().length,this.concurrencyLimit=void 0!==e.concurrencyLimit?e.concurrencyLimit:Math.max(2,Math.min(16,2*this.cpuCount)),this.adaptiveConcurrency=void 0===e.adaptiveConcurrency||e.adaptiveConcurrency,this.conflictResolver=new Ee(e.conflictResolutionConfig||{defaultStrategy:"keep-target"}),e.verbose?$.setLevel("verbose"):e.silent&&$.setLevel("error")}logStep(e){let t=`step_${this.stepCounter}`;this.operationTimes[t]={start:p.performance.now()},$.step(this.stepCounter++,e)}handleProgress(e){("checkout"===e.method||"fetch"===e.method)&&(this.progressBar||(this.progressBar=new ke({format:`{bar} {percentage}% | ${i.cyan(e.method)}`})),e.total&&this.progressBar?.update({total:e.total,value:e.progress}),e.progress===e.total&&(this.progressBar?.stop(),this.progressBar=null))}async setupUpstream(){this.logStep("配置上游仓库...");try{let e=this.options.upstreamRepo;try{e.startsWith("git@")||e.match(/^ssh:\/\//)?$.info(`验证 SSH 仓库 URL: ${i.cyan(e)}`):(e=e.replace(/^\?/,""),new URL(e),$.info(`验证仓库 URL: ${i.cyan(e)}`))}catch(e){throw new Y("无效的仓库URL格式",e)}if(this.options.authConfig){let{authConfig:t}=this.options;if("user_pass"===t.type&&t.username&&t.password)try{e=e.replace(/^\?/,"");let r=new URL(e);r.username=encodeURIComponent(t.username),r.password=encodeURIComponent(t.password),e=r.toString()}catch(e){throw new Y("构建带认证信息的URL失败",e)}else if("pat"===t.type&&t.token)try{e=e.replace(/^\?/,"");let r=new URL(e);r.username="git",r.password=encodeURIComponent(t.token),e=r.toString()}catch(e){throw new Y("构建带认证信息的URL失败",e)}}(await this.git.getRemotes(!0)).some(e=>"upstream"===e.name)?($.info(`已存在 upstream 远程仓库,更新 URL: ${this.options.upstreamRepo}`),await this.git.remote(["set-url","upstream",e])):($.info(`添加上游仓库: ${i.cyan(this.options.upstreamRepo)}`),await this.git.addRemote("upstream",e)),$.success("上游仓库配置完成"),this.operationTimes.step_1.end=p.performance.now()}catch(e){throw new Y("配置上游仓库失败",e)}}async fetchUpstream(){this.logStep(`获取上游分支 ${i.cyan(this.options.upstreamBranch)} 更新...`);let e={maxRetries:this.options.retryConfig?.maxRetries||3,initialDelay:this.options.retryConfig?.initialDelay||2e3,backoffFactor:this.options.retryConfig?.backoffFactor||1.5};await te(async()=>{await this.git.fetch("upstream",this.options.upstreamBranch),$.success("上游更新获取完成"),this.operationTimes.step_2.end=p.performance.now()},e,e=>{let t=e.message.toLowerCase();return t.includes("network")||t.includes("connect")})}async createTempBranch(){this.logStep(`创建临时分支: ${i.magenta(this.tempBranch)}`);try{await this.git.checkoutBranch(this.tempBranch,`upstream/${this.options.upstreamBranch}`),$.success(`临时分支 ${i.magenta(this.tempBranch)} 创建成功`),this.tempResourcesCreated=!0,this.operationTimes.step_3.end=p.performance.now()}catch(e){throw new Y("创建临时分支失败",e)}}async previewChanges(){this.logStep("预览变更...");try{let e=[],t=O.default(this.adaptiveConcurrency?Math.max(2,Math.min(16,Math.floor(1.5*this.cpuCount))):this.concurrencyLimit),r=[];for(let a of this.options.syncDirs)r.push(t(async()=>{let t=v.default.join(this.tempDir,v.default.basename(a)),r=v.default.join(process.cwd(),a);try{if(await S.default.pathExists(t)){if(await S.default.pathExists(r)){let i=await S.default.readdir(t,{recursive:!0,withFileTypes:!0}),s=await S.default.readdir(r,{recursive:!0,withFileTypes:!0}),o=new Map,n=new Map;for(let e of i){let r=v.default.join(e.parentPath,e.name),a=v.default.relative(t,r);o.set(a,e.isDirectory())}for(let e of s){let t=v.default.join(e.parentPath,e.name),a=v.default.relative(r,t);n.set(a,e.isDirectory())}let c=new Set([...o.keys(),...n.keys()]),l=O.default(this.concurrencyLimit),f=[];for(let i of c)f.push(l(async()=>{let s=o.get(i)||!1,c=n.get(i)||!1,l=o.has(i),f=n.has(i),u=v.default.join(a,i);if(l&&!f)e.push(`+ ${u}${s?"/":""}`);else if(!l&&f)e.push(`- ${u}${c?"/":""}`);else if(l&&f)if(s!==c)e.push(`~ ${u} (类型变更: ${s?"目录":"文件"} -> ${c?"目录":"文件"})`);else if(!s&&!c){let a=v.default.join(t,i),s=v.default.join(r,i);await S.default.readFile(a,"utf8")!==await S.default.readFile(s,"utf8")&&e.push(`~ ${u}`)}}));await Promise.all(f)}}else{let r=await S.default.readdir(t,{recursive:!0,withFileTypes:!1});for(let t of r){let r=t.toString();e.push(`+ ${v.default.join(a,r)}`)}}}catch(e){throw new X(`比较目录 ${a} 时出错`,e)}}));if(await Promise.all(r),e.length>0){if($.info(i.bold(i.yellow("将进行以下变更:"))),e.forEach(e=>$.info(e)),!0!==this.options.nonInteractive){let{confirm:e}=await D.default({type:"confirm",name:"confirm",message:"是否继续应用这些变更?",initial:!0});if(!e)throw new Z("用户取消了变更应用")}}else $.info(i.green("没有检测到变更")),this.operationTimes.step_4.end=p.performance.now()}catch(e){throw e instanceof Z?e:new ee("预览变更失败",e)}}async copyDirectories(){this.logStep("复制指定目录到临时区域...");try{await S.default.ensureDir(this.tempDir),await S.default.emptyDir(this.tempDir),this.tempResourcesCreated=!0;let e=await z(process.cwd()),t={};if(!this.forceOverwrite)try{t=await async function(e){return await S.default.pathExists(e)?S.default.readJson(e):{}}(this.hashFile)}catch(e){$.warn(`加载哈希文件失败,将使用强制覆盖模式: ${e instanceof Error?e.message:String(e)}`),this.forceOverwrite=!0}let r={},a=O.default(this.concurrencyLimit),s=[],o=0;for(let n of this.options.syncDirs){let c=v.default.join(process.cwd(),n);try{if(await S.default.pathExists(c)){$.info(`-> 处理目录: ${i.yellow(n)}`);let l=v.default.join(this.tempDir,v.default.basename(n));s.push(a(async()=>{try{let a=await xe(c,e,_);Object.assign(r,a),this.forceOverwrite?await this.copyDirectoryWithIgnore(c,l,e):await this.copyDirectoryWithIncremental(c,l,e,t),o++}catch(e){throw new X(`复制目录 ${n} 时出错`,e)}}))}else $.warn(`目录 ${i.yellow(n)} 不存在,跳过`)}catch(e){throw new X(`检查目录 ${n} 是否存在时出错`,e)}}try{await Promise.all(s)}catch(e){throw e}if(!this.forceOverwrite)try{await async function(e,t){await S.default.writeJson(e,t,{spaces:2})}(this.hashFile,r)}catch(e){$.warn(`保存哈希文件失败,但同步过程仍将继续: ${e instanceof Error?e.message:String(e)}`)}o>0?$.success(`已复制 ${o} 个目录到临时区域`):($.warn("没有目录被复制"),this.operationTimes.step_5.end=p.performance.now())}catch(e){throw e instanceof X?e:new ee("复制目录失败",e)}}async copyDirectoryWithIncremental(e,t,r,a){try{await S.default.ensureDir(t),await ge();let i=await S.default.readdir(e,{withFileTypes:!0}),s=e=>{if(!this.adaptiveConcurrency)return"dir"===e?Math.max(1,Math.floor(this.concurrencyLimit/2)):this.concurrencyLimit;let t="dir"===e?Math.max(1,Math.floor(1.5*this.cpuCount)):Math.max(2,2*this.cpuCount),r=B.default.loadavg()[0],a=Math.min(1,r/this.cpuCount);return Math.max(1,Math.floor(t*(1-.7*a)))},o=O.default(s("dir")),n=O.default(s("file")),c=[];for(let s of i){let i=v.default.join(e,s.name),n=v.default.join(t,s.name);_(v.default.relative(process.cwd(),i),r)||s.isDirectory()&&c.push(o(async()=>{await this.copyDirectoryWithIncremental(i,n,r,a)}))}await Promise.all(c);let l=[];for(let s of i){if(s.isDirectory())continue;let i=v.default.join(e,s.name),o=v.default.join(t,s.name),c=v.default.relative(process.cwd(),i);if(!_(c,r)){if(!this.shouldIncludeFile(i)){$.debug(` 跳过文件(类型不匹配): ${c}`);continue}l.push(n(async()=>{try{let e=`hash:${i}`,t=(await de(e))?.toString()??null;if(!t){let r=Buffer.from(await Pe(i));t=r.toString(),await $e(e,r)}let r=a[c];if(!await S.default.pathExists(o)||t!==r){if(await Re(i)){$.info(` 处理大文件: ${c}`);let e=S.default.createReadStream(i,{highWaterMark:655360}),t=S.default.createWriteStream(o,{highWaterMark:655360}),r=(await S.default.stat(i)).size,a=0;e.on("data",e=>{a+=e.length;let t=Math.round(a/r*100);t%10==0&&$.debug(` 大文件 ${c} 复制进度: ${t}%`)}),await new Promise((r,a)=>{e.pipe(t).on("error",r=>{e.destroy(),t.destroy(),a(new X(`复制大文件 ${i} 失败`,r))}).on("finish",()=>{$.debug(` 大文件 ${c} 复制完成`),r()})})}else await S.default.copyFile(i,o);r?$.info(` 更新文件: ${c}`):$.info(` 新增文件: ${c}`)}}catch(e){throw $.error(`处理文件 ${c} 时出错:`,e),e}}))}}await Promise.all(l)}catch(r){throw $.error(`复制目录 ${e} 到 ${t} 时出错:`,r),r}}shouldIncludeFile(e){if(!this.options.includeFileTypes||0===this.options.includeFileTypes.length)return!0;let t=v.default.extname(e).toLowerCase();return this.options.includeFileTypes.includes(t)}async copyDirectoryWithIgnore(e,t,r){return this.copyDirectoryWithIncremental(e,t,r,{})}async applyChanges(){let e=process.cwd(),t=await z(e),{shouldIgnore:r}=await Promise.resolve().then(()=>(I(),j));this.logStep("应用更新到公司仓库...");try{try{await this.git.checkout(this.options.companyBranch)}catch(e){throw new Y("切换回公司分支失败",e)}let a=0;for(let s of this.options.syncDirs){let o=v.default.join(this.tempDir,v.default.basename(s));try{if(await S.default.pathExists(o)){$.info(`-> 更新目录: ${i.yellow(s)}`);let n=v.default.join(process.cwd(),s);if(await S.default.pathExists(n)){$.info(`检测 ${s} 目录中的冲突...`);let e=await this.conflictResolver.detectDirectoryConflicts(o,n,t);e.length>0&&await this.conflictResolver.resolveConflicts(e)}try{await S.default.ensureDir(n),await(async(e,t)=>{await S.default.copy(o,n,{overwrite:this.forceOverwrite,recursive:!0,filter:a=>{let i=v.default.relative(e,a);return!r(i,t)}})})(e,t)}catch(e){throw new X(`复制目录 ${o} 到 ${n} 失败`,e)}try{await this.git.add(s)}catch(e){throw new Y(`添加目录 ${s} 到 Git 失败`,e)}a++}}catch(e){throw e instanceof X||e instanceof Y?e:new ee(`处理目录 ${s} 时出错`,e)}}try{await S.default.remove(this.tempDir)}catch(e){$.warn(`清理临时目录失败,但同步过程仍将继续: ${e}`)}a>0?$.success(`已更新 ${a} 个目录`):($.warn("没有目录被更新"),this.operationTimes.step_6.end=p.performance.now())}catch(e){throw e instanceof Y||e instanceof X?e:new ee("应用更新失败",e)}}async commitChanges(){this.logStep("检查变更并提交...");try{return 0===(await this.git.status()).files.length?($.success("没有检测到变更,无需提交"),!1):($.info(`提交变更: ${i.green(this.options.commitMessage)}`),await this.git.commit(this.options.commitMessage),$.success("变更已提交"),this.operationTimes.step_7.end=p.performance.now(),!0)}catch(e){throw new Y("提交变更失败",e)}}async pushChanges(){if(!this.options.autoPush)return void $.info("变更已提交但未推送(使用自动推送选项启用)");this.logStep(`推送变更到公司分支 ${i.cyan(this.options.companyBranch)}`);let e={maxRetries:this.options.retryConfig?.maxRetries||3,initialDelay:this.options.retryConfig?.initialDelay||2e3,backoffFactor:this.options.retryConfig?.backoffFactor||1.5};await te(async()=>{await this.git.push("origin",this.options.companyBranch),$.success("推送完成"),this.operationTimes.step_8.end=p.performance.now()},e,e=>{let t=e.message.toLowerCase();return t.includes("network")||t.includes("connect")})}async cleanup(){if(!this.tempResourcesCreated)return void $.info("未创建临时资源,跳过清理步骤");this.logStep("清理临时资源...");let e=p.performance.now();if(this.tempBranch)try{$.info(`开始清理临时分支: ${this.tempBranch}`);let e=this.originalBranch||this.options.companyBranch;$.info(`切换到目标分支: ${e}`),await this.git.checkout(e);try{await this.git.deleteLocalBranch(this.tempBranch),$.success(`临时分支 ${this.tempBranch} 已删除`)}catch(e){throw new Y("删除临时分支失败",e)}}catch(e){e instanceof Y?$.warn(`${e.message}: ${e.originalError}`):$.warn(`清理临时资源时出错: ${e}`)}await this.cleanupBranchStrategy();try{if($.info(`开始清理临时目录: ${this.tempDir}`),await S.default.pathExists(this.tempDir)){let e=S.default.remove(this.tempDir),t=new Promise((e,t)=>{setTimeout(()=>t(new Error("删除临时目录超时")),3e4)});await Promise.race([e,t]),$.success(`临时目录 ${this.tempDir} 已删除`)}else $.info(`临时目录 ${this.tempDir} 不存在,跳过删除`)}catch(e){$.warn(`清理临时目录失败: ${e}`)}try{(await this.git.getRemotes(!0)).some(e=>"upstream"===e.name)?(await this.git.removeRemote("upstream"),$.success("上游仓库已移除")):$.info("没有找到上游仓库,跳过移除步骤")}catch(e){$.warn(`移除上游仓库失败: ${e instanceof Error?e.message:String(e)}`)}try{let t=p.performance.now();$.info(`清理临时资源完成,耗时: ${((t-e)/1e3).toFixed(2)}秒`)}catch(e){$.warn(`清理临时目录失败: ${e instanceof Error?e.message:String(e)}`)}}async setupBranchStrategy(){if(!this.options.branchStrategyConfig?.enable)return;let{branchStrategyConfig:e}=this.options;this.logStep(`设置分支策略: ${e.strategy}`);try{this.originalBranch=await this.git.revparse(["--abbrev-ref","HEAD"]),$.info(`当前分支: ${this.originalBranch}`),this.strategyBranch=this.generateBranchName(e),$.info(`生成策略分支: ${this.strategyBranch}`),(await this.git.branch(["--list",this.strategyBranch])).all.includes(this.strategyBranch)?($.info(`分支 ${this.strategyBranch} 已存在,切换到该分支`),await this.git.checkout(this.strategyBranch)):($.info(`创建新分支 ${this.strategyBranch} 基于 ${e.baseBranch}`),await this.git.checkoutBranch(this.strategyBranch,e.baseBranch))}catch(e){throw new Y("设置分支策略失败",e)}}generateBranchName(e){let{strategy:t,branchPattern:r}=e,a=r,i=(new Date).toISOString().slice(0,10).replace(/-/g,"");switch(a=a.replace(/\{date\}/g,i),t){case"feature":let e=process.env.FEATURE_NAME||"feature";a=a.replace(/\{feature\}/g,e);break;case"release":let t=process.env.RELEASE_VERSION||"1.0.0";a=a.replace(/\{release\}/g,t);break;case"hotfix":let r=process.env.HOTFIX_VERSION||"1.0.1";a=a.replace(/\{hotfix\}/g,r);break;case"develop":a=a.replace(/\{develop\}/g,"develop")}return a}async cleanupBranchStrategy(){if(!this.options.branchStrategyConfig?.enable)return;let{branchStrategyConfig:e}=this.options;if(e.autoSwitchBack&&this.originalBranch)try{$.info(`切换回原分支: ${this.originalBranch}`),await this.git.checkout(this.originalBranch)}catch(e){$.warn(`切换回原分支失败: ${e instanceof Error?e.message:String(e)}`)}if(e.autoDeleteMergedBranches&&this.strategyBranch)try{await this.isBranchMerged(this.strategyBranch,e.baseBranch)&&($.info(`删除已合并的分支: ${this.strategyBranch}`),await this.git.deleteLocalBranch(this.strategyBranch))}catch(e){$.warn(`删除分支失败: ${e instanceof Error?e.message:String(e)}`)}}async isBranchMerged(e,t){try{let r=await this.git.raw(["merge-base",t,e]),a=await this.git.raw(["rev-parse",e]);return r.trim()===a.trim()}catch(e){return $.error(`检查分支是否合并失败: ${e instanceof Error?e.message:String(e)}`),!1}}async run(){try{$.info(i.bold(i.blue("╔════════════════════════════════════════════╗"))),$.info(i.bold(i.blue("║ 仓库目录同步工具 ║"))),$.info(i.bold(i.blue("╚════════════════════════════════════════════╝"))),e=this.options,console.log(i.bold(i.blue("\n🔍 配置摘要:"))),console.log(i.cyan(` - 上游仓库: ${e.upstreamRepo}`)),console.log(i.cyan(` - 上游分支: ${e.upstreamBranch}`)),console.log(i.cyan(` - 目标仓库分支: ${e.companyBranch}`)),console.log(i.yellow(` - 同步目录: ${e.syncDirs.join(",")}`)),console.log(i.magenta(` - 提交消息: ${e.commitMessage}`)),console.log(i.green(" - 自动推送: "+(e.autoPush?"是":"否"))),console.log(i.yellow(" - 预览模式: "+(e.previewOnly?"启用":"禁用"))),console.log(i.blue(` - 最大重试次数: ${e.retryConfig?.maxRetries||3}`)),console.log(i.blue(` - 初始重试延迟: ${e.retryConfig?.initialDelay||2e3}ms`)),console.log(i.blue(` - 重试退避因子: ${e.retryConfig?.backoffFactor||1.5}`)),console.log(i.bold(i.blue(`${"=".repeat(40)}\n`))),this.options.dryRun&&$.warn(i.yellow("⚠️ 运行在dry-run模式下,不会实际修改任何文件")),this.options.previewOnly&&$.warn(i.yellow("⚠️ 运行在预览模式下,只会显示变更,不会实际修改任何文件"));try{await this.git.status()}catch(e){throw new Y("未在Git仓库中运行。请在Git仓库根目录执行此命令。",e)}if(await this.setupUpstream(),await this.fetchUpstream(),await this.setupBranchStrategy(),await this.createTempBranch(),await this.copyDirectories(),await this.previewChanges(),this.options.previewOnly)return $.info(i.yellow("⚠️ 预览模式: 已完成变更预览,不进行实际修改")),void $.success(i.bold(i.green("\n✅ 同步预览完成!")));this.options.dryRun?$.info(i.yellow("⚠️ dry-run模式: 跳过应用变更、提交和推送操作")):(await this.applyChanges(),await this.commitChanges()&&await this.pushChanges());let t="step_"+(this.stepCounter-1);if(this.operationTimes[t]&&(this.operationTimes[t].end=p.performance.now()),this.operationTimes.step_1){let e=p.performance.now()-this.operationTimes.step_1.start;$.info(`总执行时间: ${(e/1e3).toFixed(2)}秒`),$.info("各步骤执行时间:"),Object.entries(this.operationTimes).forEach(([e,t])=>{if(t.end){let r=(t.end-t.start)/1e3;$.info(`${e}: ${r.toFixed(2)}秒`)}})}$.success(i.bold(i.green("✅ 同步完成!"))),$.info(i.green("=".repeat(50)))}catch(e){!function(e){e instanceof K?(e.display(),"critical"===e.severity&&($.error("发生严重错误,程序将退出"),process.exit(1))):(new ee("发生未知错误",e).display(),process.exit(1))}