UNPKG

sync-upstream

Version:

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

2 lines 55.7 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("crypto"),n=require("@iarna/toml"),l=require("js-yaml"),c=require("json5"),h=require("os"),u=require("perf_hooks"),f=require("p-limit"),g=require("prompts"),p=require("simple-git");function d(e){return e&&e.__esModule?e:{default:e}}var y,w,m,$=d(e),v=d(r),S=d(a),b=d(s),P=d(o),E=d(n),C=d(l),x=d(c),R=d(h),k=d(f),F=d(g),T=d(p),B=Object.defineProperty,O=(e,t)=>()=>(e&&(t=e(e=0)),t),D=O(()=>{y={level:"info",logToFile:!1,logFilePath:$.default.join(process.cwd(),"sync-upstream.log"),showTimestamp:!0,showLevel:!0,structedLogging:!1,perfMetricsEnabled:!0,traceEnabled:!1},m=new(w=class{constructor(e={}){this.logLevels=["trace","debug","verbose","info","success","warn","error","perf"],this.config={...y,...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($.default.dirname(this.config.logFilePath))}getTimestamp(){return v.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($.default.dirname(this.config.logFilePath))}})}),L={};function M(e){return e.split($.default.sep).join("/")}async function j(e){let t=["**/node_modules/**","**/.git/**","**/dist/**","**/build/**"],r=$.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],m.debug(`从 .gitignore 加载了 ${e.length} 个忽略模式`)}catch(e){m.error("读取 .gitignore 文件失败:",e)}let a=$.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],m.debug(`从 .syncignore 加载了 ${e.length} 个忽略模式`)}catch(e){m.error("读取 .syncignore 文件失败:",e)}return t}function U(e,t){let r=M(e);return b.default.isMatch(r,t)}((e,t)=>{for(var r in t)B(e,r,{get:t[r],enumerable:!0})})(L,{loadIgnorePatterns:()=>j,normalizePath:()=>M,shouldIgnore:()=>U});var z=O(()=>{D()});D();var I,N,_=((N=_||{}).USE_SOURCE="use-source",N.KEEP_TARGET="keep-target",N.AUTO_MERGE="auto-merge",N.PROMPT_USER="prompt-user",N.CREATE_VERSION="create-version",N.IGNORE="ignore",N),J=((I=J||{}).FEATURE="feature",I.RELEASE="release",I.HOTFIX="hotfix",I.DEVELOP="develop",I),W={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}},q=[".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 A(e){if(e.conflictResolutionConfig?.defaultStrategy){let t=Object.values(_);if(!t.includes(e.conflictResolutionConfig.defaultStrategy))throw m.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 m.error("最大重试次数不能为负数",void 0,{maxRetries:e.retryConfig.maxRetries}),new Error("最大重试次数不能为负数");if(void 0!==e.retryConfig.initialDelay&&e.retryConfig.initialDelay<0)throw m.error("初始重试延迟不能为负数",void 0,{initialDelay:e.retryConfig.initialDelay}),new Error("初始重试延迟不能为负数");if(void 0!==e.retryConfig.backoffFactor&&e.retryConfig.backoffFactor<1)throw m.error("重试退避因子必须大于或等于1",void 0,{backoffFactor:e.retryConfig.backoffFactor}),new Error("重试退避因子必须大于或等于1")}if(void 0!==e.concurrencyLimit&&e.concurrencyLimit<1)throw m.error("并行处理数量必须大于或等于1",void 0,{concurrencyLimit:e.concurrencyLimit}),new Error("并行处理数量必须大于或等于1");if(e.branchStrategyConfig){let{branchStrategyConfig:t}=e,r=Object.values(J);if(!r.includes(t.strategy))throw m.error("无效的分支策略",void 0,{strategy:t.strategy,validStrategies:r}),new Error(`无效的分支策略: ${t.strategy}. 有效策略: ${r.join(", ")}`);if(!t.baseBranch||""===t.baseBranch.trim())throw m.error("基础分支名称不能为空",void 0,{baseBranch:t.baseBranch}),new Error("基础分支名称不能为空");if(!t.branchPattern||""===t.branchPattern.trim())throw m.error("分支命名模式不能为空",void 0,{branchPattern:t.branchPattern}),new Error("分支命名模式不能为空")}if(e.cacheConfig){let{cacheConfig:t}=e;if(void 0!==t.expiryMs&&t.expiryMs<0)throw m.error("缓存过期时间不能为负数",void 0,{expiryMs:t.expiryMs}),new Error("缓存过期时间不能为负数");if(void 0!==t.maxSizeBytes&&t.maxSizeBytes<0)throw m.error("最大缓存大小不能为负数",void 0,{maxSizeBytes:t.maxSizeBytes}),new Error("最大缓存大小不能为负数");if(void 0!==t.lruMaxEntries&&t.lruMaxEntries<1)throw m.error("LRU最大条目数必须大于或等于1",void 0,{lruMaxEntries:t.lruMaxEntries}),new Error("LRU最大条目数必须大于或等于1")}}async function H(){for(let e of q){let t=$.default.join(process.cwd(),e);if(await S.default.pathExists(t)){m.trace(`找到配置文件: ${e}`);try{let r=await S.default.readFile(t,"utf8"),a={};return e.endsWith(".json5")?(m.trace(`解析JSON5配置文件: ${e}`),a=x.default.parse(r)):e.endsWith(".json")?(m.trace(`解析JSON配置文件: ${e}`),a=JSON.parse(r)):e.endsWith(".yaml")||e.endsWith(".yml")?(m.trace(`解析YAML配置文件: ${e}`),a=C.default.load(r)):e.endsWith(".toml")?(m.trace(`解析TOML配置文件: ${e}`),a=E.default.parse(r)):(m.trace(`尝试作为JSON解析配置文件: ${e}`),a=JSON.parse(r)),A(a),m.debug(`配置文件 ${e} 加载成功`),{...W,...a}}catch(t){m.error(`读取配置文件 ${e} 失败`,t)}}}return m.debug("未找到配置文件,使用默认配置"),W}D(),D();var V=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)),m.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":m.info(JSON.stringify(e));break;case"warning":m.warn(JSON.stringify(e));break;case"error":m.error(JSON.stringify(e));break;case"critical":m.error(i.bold(i.red(JSON.stringify(e))))}}},G=class extends V{constructor(e,t,r){super(e,"GIT_ERROR","error",t,r)}},K=class extends V{constructor(e,t,r){super(e,"FS_ERROR","error",t,r)}},Y=class extends V{constructor(e,t,r){super(e,"NETWORK_ERROR","warning",t,r)}},X=class extends V{constructor(e="用户取消了操作",t){super(e,"USER_CANCEL","info",void 0,t)}},Q=class extends V{constructor(e,t,r){super(e,"SYNC_PROCESS_ERROR","error",t,r)}};async function Z(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);m.info(`正在进行第 ${i}/${t.maxRetries} 次重试,延迟 ${e}ms...`),await new Promise(t=>setTimeout(t,e))}return await e()}catch(e){if(a=e,!r(a))throw m.error(`非网络错误,不进行重试: ${a.message}`),a;if(i>=t.maxRetries)throw m.error(`达到最大重试次数(${t.maxRetries}),请求失败: ${a.message}`),new Y("网络请求失败",a);m.warn(`请求失败(第 ${i} 次尝试): ${a.message}`)}throw a}D();var ee=$.default.join(process.cwd(),".sync-cache"),te=null,re=!1,ae=0,ie=3e5,se={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:[]},oe=$.default.join(ee,"metadata.json"),ne={hits:0,misses:0,totalSize:0},le=new Map;function ce(){if(!te)return m.warn("缓存配置尚未初始化,使用默认配置"),se;let e=te.cache||{};return{...se,...e}}async function he(){try{let e={stats:ne,lruMap:Object.fromEntries(le),timestamp:Date.now()};await S.default.writeFile(oe,JSON.stringify(e,null,2))}catch(e){m.error(`保存缓存元数据失败: ${e instanceof Error?e.message:String(e)}`)}}async function ue(){if(re)m.debug("缓存已经初始化,跳过初始化步骤");else try{te=await H(),m.info("配置已加载"),await S.default.ensureDir(ee),m.info(`缓存目录已初始化: ${ee}`),await async function(){try{if(await S.default.pathExists(oe)){let e=await S.default.readFile(oe,"utf8"),t=JSON.parse(e);ne=t.stats||ne,le=new Map(Object.entries(t.lruMap||{})),m.info("缓存元数据已加载")}}catch(e){m.error(`加载缓存元数据失败: ${e instanceof Error?e.message:String(e)}`),ne={hits:0,misses:0,totalSize:0},le=new Map}}(),await me(),await ge(),re=!0,setInterval(async()=>{try{m.debug("执行定期缓存清理..."),await me(),await ge()}catch(e){m.error(`定期清理缓存失败: ${e instanceof Error?e.message:String(e)}`)}},ie),m.info("定期缓存清理已启动,间隔: 5分钟"),ce().warmupEnabled&&(m.info("开始缓存预热..."),await async function(){try{let e=ce(),{warmupKeys:t}=e,r=t.length;if(0===r)return m.info("没有配置预热键,跳过缓存预热"),void 0;m.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{m.debug(`预热缓存键: ${e}`);let t=Buffer.from(`Warmed up data for key: ${e}`);await we(e,t),a++}catch(t){m.error(`预热缓存键 ${e} 失败: ${t instanceof Error?t.message:String(t)}`),i++}});await Promise.all(t)}m.success(`缓存预热完成: 成功 ${a} 个, 失败 ${i} 个`)}catch(e){m.error(`缓存预热失败: ${e instanceof Error?e.message:String(e)}`)}}())}catch(e){throw m.error(`初始化缓存目录失败: ${e instanceof Error?e.message:String(e)}`),e}}function fe(e){let t=ce();if(t.lruEnabled&&(le.delete(e),le.set(e,Date.now()),le.size>t.lruMaxEntries)){let e=null,t=1/0;for(let[r,a]of le.entries())a<t&&(e=r,t=a);e&&(le.delete(e),S.default.remove($.default.join(ee,e)).catch(e=>m.error(`删除LRU淘汰的缓存文件失败: ${e instanceof Error?e.message:String(e)}`)),m.info(`LRU策略: 已删除最旧的缓存条目 ${e}`))}}async function ge(){try{let e=ce();if(e.maxSizeBytes<=0)return;if(ne.totalSize>e.maxSizeBytes){m.info(`缓存大小 ${pe(ne.totalSize)} 已超过限制 ${pe(e.maxSizeBytes)},开始清理`);let t=Array.from(le.entries()).sort((e,t)=>e[1]-t[1]),r=ne.totalSize-e.maxSizeBytes;for(let[e,a]of t){if(r<=0)break;let t=$.default.join(ee,e);if(await S.default.pathExists(t)){let a=await S.default.stat(t);await S.default.remove(t),r-=a.size,ne.totalSize-=a.size,le.delete(e),m.info(`已删除缓存文件 ${e},释放 ${pe(a.size)} 空间`)}}m.info(`缓存清理完成,当前大小: ${pe(ne.totalSize)}`)}await he()}catch(e){m.error(`检查缓存大小限制失败: ${e instanceof Error?e.message:String(e)}`)}}function pe(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=$.default.join(ee,e),a=ce();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,m.debug(`使用内容类型 ${n} 的过期时间: ${o}ms`))}return s-i.mtimeMs>o?(m.info(`缓存 ${e} 已过期,将删除`),await S.default.remove(r),le.delete(e),ne.totalSize-=i.size,await he(),!1):(fe(e),!0)}catch(e){return m.error(`检查缓存有效性失败: ${e instanceof Error?e.message:String(e)}`),!1}}(e,t))return ne.misses++,await ye(),null;let r=$.default.join(ee,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),m.debug(`缓存数据已解压缩: ${e}`)}catch(e){return m.error(`解压缩缓存数据失败: ${e instanceof Error?e.message:String(e)}`),i}return ne.hits++,m.info(`从缓存获取数据: ${e} (命中: ${ne.hits}, 未命中: ${ne.misses})${a?" (已压缩)":""}`),await ye(),i}catch(e){return m.error(`从缓存读取数据失败: ${e instanceof Error?e.message:String(e)}`),null}}async function ye(){let e=Date.now();(e-ae>1e3||0===ne.hits&&0===ne.misses)&&(await he(),ae=e)}async function we(e,t,r,a={}){try{let i=$.default.join(ee,e),s=ce(),o=void 0!==a.compress?a.compress:s.compressEnabled,n=a.compressionLevel||s.compressionLevel||6,l=t,c=!1;if(o&&t.length>s.compressionThreshold)try{let e=await import("zlib");l=await new Promise((r,a)=>{e.gzip(t,{level:n},(e,t)=>{e?a(e):r(t)})}),c=!0,m.debug(`缓存数据已压缩: ${pe(t.length)} -> ${pe(l.length)}`)}catch(e){m.warn(`压缩缓存数据失败,将使用原始数据: ${e instanceof Error?e.message:String(e)}`),c=!1}await Z(async()=>{await S.default.writeFile(i,l),c?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(le.has(e))try{let e=await S.default.stat(i);ne.totalSize-=e.size}catch(e){m.warn(`获取旧缓存大小失败: ${e instanceof Error?e.message:String(e)}`)}ne.totalSize+=t.size,ne.misses++,fe(e),m.info(`数据已写入缓存: ${e} (大小: ${pe(t.size)}${c?", 已压缩":""})`),await ge(),await ye()},r||{maxRetries:3,initialDelay:1e3,backoffFactor:2})}catch(e){m.error(`写入缓存失败: ${e instanceof Error?e.message:String(e)}`)}}async function me(){try{if(!await S.default.pathExists(ee))return void m.info("缓存目录不存在,跳过清理");let e=ce(),t=await S.default.readdir(ee,{withFileTypes:!0}),r=Date.now(),a=0,i=0;for(let s of t)if(s.name!==$.default.basename(oe)&&s.isFile()){let t=$.default.join(ee,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,le.has(n)&&(le.delete(n),ne.totalSize-=o.size),m.debug(`已删除过期缓存: ${n} (大小: ${pe(o.size)})`))}a>0?(m.info(`已清理 ${a} 个过期缓存文件,释放 ${pe(i)} 空间`),await he()):m.info("没有过期缓存需要清理")}catch(e){m.error(`清理过期缓存失败: ${e instanceof Error?e.message:String(e)}`)}}z(),D();var $e=new w,ve=655360;async function Se(e,t={}){let{useCache:r=!0,largeFileBufferSize:a=ve}=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=P.default.createHash(s).update(i).digest("hex"),n=ce(),l=r.customPrefix||n.keyPrefix,c=l?l.replace(/[:\\/*?"<>|]/g,"-"):"";return c?`${c}-${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 $e.debug(`文件 ${e} 大小为 ${(t.size/1024/1024).toFixed(2)}MB,使用流式处理`),new Promise((t,s)=>{let o=P.default.createHash("md5"),n=S.default.createReadStream(e,{highWaterMark:a});n.on("data",e=>{o.update(e)}),n.on("error",t=>{$e.error(`流式读取文件 ${e} 时出错:`,t),s(t)}),n.on("end",()=>{let e=o.digest("hex");r&&we(i,Buffer.from(e)).catch(e=>{$e.error("写入缓存失败:",e)}),t(e)})});{let t=await S.default.readFile(e),a=P.default.createHash("md5").update(t).digest("hex");return r&&await we(i,Buffer.from(a)),a}}catch(t){throw"EISDIR"===t.code?$e.error(`错误: 尝试读取目录 ${e} 作为文件`):$e.error(`计算文件 ${e} 哈希值时出错:`,t.message),t}}async function be(e,t=[],r,a={}){let{parallelLimit:i=10,useCache:s=!0,onProgress:o}=a,n=k.default(i);try{if(!(await S.default.stat(e)).isDirectory())throw new Error(`路径 ${e} 不是目录,无法计算哈希值`);let a=await S.default.readdir(e,{withFileTypes:!0}),l={},c=a.length,h=0,u=a.map(async a=>{try{let o=$.default.join(e,a.name),n=$.default.relative(process.cwd(),o),c=M(n);if(r(c,t))return;if(a.isDirectory()){let e=await be(o,t,r,{parallelLimit:i,useCache:s});Object.assign(l,e)}else await S.default.pathExists(o)?(await S.default.stat(o)).isFile()?l[n]=await Z(()=>Se(o,{useCache:s}),{maxRetries:3,initialDelay:1e3,backoffFactor:2}):$e.warn(`警告: 条目 ${a.name} 不是文件,跳过`):$e.warn(`警告: 条目 ${a.name} 不存在,跳过`)}catch(e){$e.error(`处理条目 ${a.name} 时出错:`,e)}finally{h++,o&&o(h,c)}}).map(e=>n(()=>e));return await Promise.all(u),l}catch(t){return $e.error(`计算目录 ${e} 哈希值时出错:`,t),{}}}async function Pe(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}}z(),D();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),l=await S.default.stat(t);if(n.isDirectory()!==l.isDirectory())return{type:"type",sourcePath:e,targetPath:t,sourceType:n.isDirectory()?"directory":"file",targetType:l.isDirectory()?"directory":"file"};if(n.isDirectory()&&l.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 c=await Se(e),h=await Se(t);if(c!==h){if(a){let r=await Pe(e)||"1.0.0",a=await Pe(t)||"1.0.0";if(r!==a)return{type:"version",sourcePath:e,targetPath:t,sourceHash:c,targetHash:h,sourceVersion:r,targetVersion:a}}return{type:"content",sourcePath:e,targetPath:t,sourceHash:c,targetHash:h}}if(i){let r=511&n.mode,a=511&l.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 K(`检测文件冲突时出错: ${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=$.default.join(e,n.name),l=$.default.join(t,n.name);if(U($.default.relative(process.cwd(),a),r))continue;let c=n.name.toLowerCase(),h=["node_modules","dist","build","coverage",".git"].includes(c);if(n.isDirectory())if(h)await S.default.pathExists(l)&&(await S.default.stat(l).then(e=>e.isDirectory())||o.push({type:"type",sourcePath:a,targetPath:l,sourceType:"directory",targetType:"file"}));else{let e=await this.detectDirectoryConflicts(a,l,r,{quickCheck:i,cache:s});o.push(...e)}else{let e=await this.detectFileConflict(a,l);e&&o.push(e)}}return s.set(n,o),o}catch(r){throw new K(`检测目录冲突时出错: ${e} vs ${t}`,r)}}async resolveConflict(e,t,r={}){let{autoMergeDepth:a=3,backup:s=!0}=r,o=t||this.config.defaultStrategy;switch(m.info(`\n解决冲突: ${i.yellow(e.type)}`),m.info(`源文件: ${i.blue(e.sourcePath)}`),m.info(`目标文件: ${i.blue(e.targetPath)}`),e.type){case"content":m.info(`源文件哈希: ${e.sourceHash}`),m.info(`目标文件哈希: ${e.targetHash}`);break;case"type":m.info(`源文件类型: ${e.sourceType}`),m.info(`目标文件类型: ${e.targetType}`);break;case"version":m.info(`源文件版本: ${e.sourceVersion}`),m.info(`目标文件版本: ${e.targetVersion}`);break;case"permission":m.info(`源文件权限: ${e.sourcePermissions?.toString(8)}`),m.info(`目标文件权限: ${e.targetPermissions?.toString(8)}`);break;case"lock":m.info(`锁定所有者: ${e.lockInfo?.owner}`),m.info(`锁定时间: ${e.lockInfo?.timestamp.toISOString()}`);break;case"symlink":m.info(`符号链接目标: ${e.symlinkTarget}`)}if(s)try{await this.createBackup(e.targetPath),m.info(`已创建目标文件备份: ${i.green(`${e.targetPath}.bak`)}`)}catch(e){m.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 m.error(`未支持的冲突类型: ${i.red(e.type)}`),!1}}catch(e){return m.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 m.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 F.default({type:"select",name:"resolution",message:"请选择冲突解决方式:",choices:t});if(!r)throw new X("用户取消了冲突解决");if("create-version"===r){let t=`${e.targetPath}.v${Date.now()}`;return await S.default.copyFile(e.sourcePath,t),m.success(`已创建新版本文件: ${i.green(t)}`),!0}return await this.resolveConflict(e,r,{backup:!1})}catch(e){if(e instanceof X)throw e;return m.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),m.success(`使用源文件(版本 ${e.sourceVersion})覆盖目标文件: ${i.green(e.targetPath)}`),!0;case"keep-target":return m.info(`保留目标文件(版本 ${e.targetVersion}): ${i.green(e.targetPath)}`),!0;case"auto-merge":return await this.autoMergeFiles(e.sourcePath,e.targetPath,3)?(m.success(`自动合并版本成功: ${i.green(e.targetPath)}`),!0):(m.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),m.success(`应用源文件权限 ${e.sourcePermissions.toString(8)} 到目标文件: ${i.green(e.targetPath)}`)),!0;case"keep-target":return m.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),m.success(`强制覆盖锁定的文件: ${i.green(e.targetPath)}`),!0}catch(e){return m.error(`无法覆盖锁定的文件: ${e instanceof Error?e.message:String(e)}`),!1}case"keep-target":return m.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),m.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),m.success(`复制源文件/目录到目标位置: ${i.green(e.targetPath)}`);return!0;case"keep-target":return m.info(`保留目标符号链接/文件: ${i.green(e.targetPath)}`),!0;default:return await this.promptUserForConflictResolution(e)}}async resolveContentConflict(e,t,r={}){let a=!1,s=$.default.extname(e.sourcePath).toLowerCase(),o=this.config.autoResolveTypes?.includes(s)||!1,n=`${e.sourcePath}-${e.targetPath}-${Date.now()}`;switch(this.config.logResolutions&&m.info(`开始解决冲突: ${n} (${e.type})`),t){case"use-source":await S.default.copyFile(e.sourcePath,e.targetPath),m.info(`冲突解决: 使用源文件覆盖目标文件 ${i.yellow(e.targetPath)}`),a=!0;break;case"keep-target":m.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"),l="";l=[".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,l),m.info(`冲突解决: 自动合并文件 ${i.yellow(e.targetPath)}`),a=!0}catch(t){return m.error(`自动合并失败,回退到提示用户: ${t instanceof Error?t.message:String(t)}`),this.resolveContentConflict(e,"prompt-user")}break;case"prompt-user":if(o)return m.debug(`文件 ${i.yellow(e.targetPath)} 是自动解决类型,使用默认策略 ${this.config.defaultStrategy}`),this.resolveContentConflict(e,this.config.defaultStrategy);let n=await S.default.readFile(e.sourcePath,"utf8"),l=await S.default.readFile(e.targetPath,"utf8"),c=this.generateDiffPreview(n,l),{resolution:h}=await F.default({type:"select",name:"resolution",message:`文件 ${i.yellow(e.targetPath)} 存在内容冲突,如何解决?\n${c}`,choices:[{title:"使用源文件覆盖",value:"use-source"},{title:"保留目标文件",value:"keep-target"},{title:"尝试自动合并",value:"auto-merge"},{title:"查看并编辑合并结果",value:"edit"}]});if("edit"===h){m.info(`提示: 请手动编辑文件 ${i.yellow(e.targetPath)} 解决冲突`);let t=`<<<<<<< SOURCE\n${n}\n=======\n${l}\n>>>>>>> TARGET`;return await S.default.writeFile(e.targetPath,t),!1}return this.resolveContentConflict(e,h);default:return m.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"};m.info(`冲突解决记录: ${r} 类型=${e.type} 策略=${t}`),m.debug(`详细记录: ${JSON.stringify(a,null,2)}`)}async resolveTypeConflict(e,t){let r=!1,a=$.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),m.info(`冲突解决: 使用源${e.sourceType}覆盖目标${e.targetType} ${i.yellow(e.targetPath)}`),r=!0;break;case"keep-target":m.info(`冲突解决: 保留目标${e.targetType} ${i.yellow(e.targetPath)}`),r=!0;break;case"prompt-user":if(s)return m.debug(`路径 ${i.yellow(e.targetPath)} 是自动解决类型,使用默认策略 ${this.config.defaultStrategy}`),this.resolveTypeConflict(e,this.config.defaultStrategy);let{resolution:a}=await F.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 m.error(`未知的解决策略: ${t}`),!1}return r&&this.config.logResolutions&&m.debug(`冲突解决日志: 类型=${e.type}, 源文件=${e.sourcePath}, 目标文件=${e.targetPath}, 策略=${t}`),r}async resolveRenameConflict(e,t){let r=!1,a=$.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),m.info(`冲突解决: 使用源文件 ${i.yellow(e.sourcePath)} 覆盖目标路径 ${i.yellow(e.targetPath)}`),r=!0):m.error(`源文件不存在: ${e.sourcePath}`);break;case"keep-target":m.info(`冲突解决: 保留目标文件 ${i.yellow(e.targetPath)}`),r=!0;break;case"prompt-user":if(s)return m.debug(`文件 ${i.yellow(e.sourcePath)} 是自动解决类型,使用默认策略 ${this.config.defaultStrategy}`),this.resolveRenameConflict(e,this.config.defaultStrategy);let{resolution:a}=await F.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 m.error(`未知的解决策略: ${t}`),!1}return r&&this.config.logResolutions&&m.debug(`冲突解决日志: 类型=${e.type}, 源文件=${e.sourcePath}, 目标文件=${e.targetPath}, 策略=${t}`),r}async resolveConflicts(e){let t=0;if(0===e.length)return m.info("没有检测到冲突"),t;m.warn(i.yellow(`检测到 ${e.length} 个冲突`));for(let r of e)await this.resolveConflict(r)&&t++;return m.info(`成功解决 ${t}/${e.length} 个冲突`),t}};async function Ce(e,t=104857600){try{let r=await S.default.stat(e);return r.isFile()&&r.size>=t}catch(e){return m.error(`检查文件大小失败: ${e instanceof Error?e.message:String(e)}`),!1}}z(),D(),D(),"function"!=typeof F.default&&(console.error("Error: prompts is not a function"),process.exit(1));var xe=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")}};exports.UpstreamSyncer=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&&m.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),m.info("使用用户名和密码认证")}break;case"pat":if(e.token){let t=new URL(this.options.upstreamRepo);t.username="git",t.password=encodeURIComponent(e.token),m.info("使用个人访问令牌认证")}break;default:m.warn(`未知的认证类型: ${e.type}`)}}this.git=T.default(t),this.tempDir=$.default.join(process.cwd(),".sync-temp"),this.tempBranch=`temp-sync-${Date.now()}`,this.hashFile=$.default.join(process.cwd(),".sync-hashes.json"),this.forceOverwrite=void 0===e.forceOverwrite||e.forceOverwrite,this.cpuCount=R.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?m.setLevel("verbose"):e.silent&&m.setLevel("error")}logStep(e){let t=`step_${this.stepCounter}`;this.operationTimes[t]={start:u.performance.now()},m.step(this.stepCounter++,e)}handleProgress(e){("checkout"===e.method||"fetch"===e.method)&&(this.progressBar||(this.progressBar=new xe({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:\/\//)?m.info(`验证 SSH 仓库 URL: ${i.cyan(e)}`):(e=e.replace(/^\?/,""),new URL(e),m.info(`验证仓库 URL: ${i.cyan(e)}`))}catch(e){throw new G("无效的仓库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 G("构建带认证信息的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 G("构建带认证信息的URL失败",e)}}(await this.git.getRemotes(!0)).some(e=>"upstream"===e.name)?(m.info(`已存在 upstream 远程仓库,更新 URL: ${this.options.upstreamRepo}`),await this.git.remote(["set-url","upstream",e])):(m.info(`添加上游仓库: ${i.cyan(this.options.upstreamRepo)}`),await this.git.addRemote("upstream",e)),m.success("上游仓库配置完成"),this.operationTimes.step_1.end=u.performance.now()}catch(e){throw new G("配置上游仓库失败",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 Z(async()=>{await this.git.fetch("upstream",this.options.upstreamBranch),m.success("上游更新获取完成"),this.operationTimes.step_2.end=u.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}`),m.success(`临时分支 ${i.magenta(this.tempBranch)} 创建成功`),this.tempResourcesCreated=!0,this.operationTimes.step_3.end=u.performance.now()}catch(e){throw new G("创建临时分支失败",e)}}async previewChanges(){this.logStep("预览变更...");try{let e=[],t=k.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=$.default.join(this.tempDir,$.default.basename(a)),r=$.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=$.default.join(e.parentPath,e.name),a=$.default.relative(t,r);o.set(a,e.isDirectory())}for(let e of s){let t=$.default.join(e.parentPath,e.name),a=$.default.relative(r,t);n.set(a,e.isDirectory())}let l=new Set([...o.keys(),...n.keys()]),c=k.default(this.concurrencyLimit),h=[];for(let i of l)h.push(c(async()=>{let s=o.get(i)||!1,l=n.get(i)||!1,c=o.has(i),h=n.has(i),u=$.default.join(a,i);if(c&&!h)e.push(`+ ${u}${s?"/":""}`);else if(!c&&h)e.push(`- ${u}${l?"/":""}`);else if(c&&h)if(s!==l)e.push(`~ ${u} (类型变更: ${s?"目录":"文件"} -> ${l?"目录":"文件"})`);else if(!s&&!l){let a=$.default.join(t,i),s=$.default.join(r,i);await S.default.readFile(a,"utf8")!==await S.default.readFile(s,"utf8")&&e.push(`~ ${u}`)}}));await Promise.all(h)}}else{let r=await S.default.readdir(t,{recursive:!0,withFileTypes:!1});for(let t of r){let r=t.toString();e.push(`+ ${$.default.join(a,r)}`)}}}catch(e){throw new K(`比较目录 ${a} 时出错`,e)}}));if(await Promise.all(r),e.length>0){if(m.info(i.bold(i.yellow("将进行以下变更:"))),e.forEach(e=>m.info(e)),!0!==this.options.nonInteractive){let{confirm:e}=await F.default({type:"confirm",name:"confirm",message:"是否继续应用这些变更?",initial:!0});if(!e)throw new X("用户取消了变更应用")}}else m.info(i.green("没有检测到变更")),this.operationTimes.step_4.end=u.performance.now()}catch(e){throw e instanceof X?e:new Q("预览变更失败",e)}}async copyDirectories(){this.logStep("复制指定目录到临时区域...");try{await S.default.ensureDir(this.tempDir),await S.default.emptyDir(this.tempDir),this.tempResourcesCreated=!0;let e=await j(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){m.warn(`加载哈希文件失败,将使用强制覆盖模式: ${e instanceof Error?e.message:String(e)}`),this.forceOverwrite=!0}let r={},a=k.default(this.concurrencyLimit),s=[],o=0;for(let n of this.options.syncDirs){let l=$.default.join(process.cwd(),n);try{if(await S.default.pathExists(l)){m.info(`-> 处理目录: ${i.yellow(n)}`);let c=$.default.join(this.tempDir,$.default.basename(n));s.push(a(async()=>{try{let a=await be(l,e,U);Object.assign(r,a),this.forceOverwrite?await this.copyDirectoryWithIgnore(l,c,e):await this.copyDirectoryWithIncremental(l,c,e,t),o++}catch(e){throw new K(`复制目录 ${n} 时出错`,e)}}))}else m.warn(`目录 ${i.yellow(n)} 不存在,跳过`)}catch(e){throw new K(`检查目录 ${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){m.warn(`保存哈希文件失败,但同步过程仍将继续: ${e instanceof Error?e.message:String(e)}`)}o>0?m.success(`已复制 ${o} 个目录到临时区域`):(m.warn("没有目录被复制"),this.operationTimes.step_5.end=u.performance.now())}catch(e){throw e instanceof K?e:new Q("复制目录失败",e)}}async copyDirectoryWithIncremental(e,t,r,a){try{await S.default.ensureDir(t),await ue();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=R.default.loadavg()[0],a=Math.min(1,r/this.cpuCount);return Math.max(1,Math.floor(t*(1-.7*a)))},o=k.default(s("dir")),n=k.default(s("file")),l=[];for(let s of i){let i=$.default.join(e,s.name),n=$.default.join(t,s.name);U($.default.relative(process.cwd(),i),r)||s.isDirectory()&&l.push(o(async()=>{await this.copyDirectoryWithIncremental(i,n,r,a)}))}await Promise.all(l);let c=[];for(let s of i){if(s.isDirectory())continue;let i=$.default.join(e,s.name),o=$.default.join(t,s.name),l=$.default.relative(process.cwd(),i);if(!U(l,r)){if(!this.shouldIncludeFile(i)){m.debug(` 跳过文件(类型不匹配): ${l}`);continue}c.push(n(async()=>{try{let e=`hash:${i}`,t=(await de(e))?.toString()??null;if(!t){let r=Buffer.from(await Se(i));t=r.toString(),await we(e,r)}let r=a[l];if(!await S.default.pathExists(o)||t!==r){if(await Ce(i)){m.info(` 处理大文件: ${l}`);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&&m.debug(` 大文件 ${l} 复制进度: ${t}%`)}),await new Promise((r,a)=>{e.pipe(t).on("error",r=>{e.destroy(),t.destroy(),a(new K(`复制大文件 ${i} 失败`,r))}).on("finish",()=>{m.debug(` 大文件 ${l} 复制完成`),r()})})}else await S.default.copyFile(i,o);r?m.info(` 更新文件: ${l}`):m.info(` 新增文件: ${l}`)}}catch(e){throw m.error(`处理文件 ${l} 时出错:`,e),e}}))}}await Promise.all(c)}catch(r){throw m.error(`复制目录 ${e} 到 ${t} 时出错:`,r),r}}shouldIncludeFile(e){if(!this.options.includeFileTypes||0===this.options.includeFileTypes.length)return!0;let t=$.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 j(e),{shouldIgnore:r}=await Promise.resolve().then(()=>(z(),L));this.logStep("应用更新到公司仓库...");try{try{await this.git.checkout(this.options.companyBranch)}catch(e){throw new G("切换回公司分支失败",e)}let a=0;for(let s of this.options.syncDirs){let o=$.default.join(this.tempDir,$.default.basename(s));try{if(await S.default.pathExists(o)){m.info(`-> 更新目录: ${i.yellow(s)}`);let n=$.default.join(process.cwd(),s);if(await S.default.pathExists(n)){m.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=$.default.relative(e,a);return!r(i,t)}})})(e,t)}catch(e){throw new K(`复制目录 ${o} 到 ${n} 失败`,e)}try{await this.git.add(s)}catch(e){throw new G(`添加目录 ${s} 到 Git 失败`,e)}a++}}catch(e){throw e instanceof K||e instanceof G?e:new Q(`处理目录 ${s} 时出错`,e)}}try{await S.default.remove(this.tempDir)}catch(e){m.warn(`清理临时目录失败,但同步过程仍将继续: ${e}`)}a>0?m.success(`已更新 ${a} 个目录`):(m.warn("没有目录被更新"),this.operationTimes.step_6.end=u.performance.now())}catch(e){throw e instanceof G||e instanceof K?e:new Q("应用更新失败",e)}}async commitChanges(){this.logStep("检查变更并提交...");try{return 0===(await this.git.status()).files.length?(m.success("没有检测到变更,无需提交"),!1):(m.info(`提交变更: ${i.green(this.options.commitMessage)}`),await this.git.commit(this.options.commitMessage),m.success("变更已提交"),this.operationTimes.step_7.end=u.performance.now(),!0)}catch(e){throw new G("提交变更失败",e)}}async pushChanges(){if(!this.options.autoPush)return void m.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 Z(async()=>{await this.git.push("origin",this.options.companyBranch),m.success("推送完成"),this.operationTimes.step_8.end=u.performance.now()},e,e=>{let t=e.message.toLowerCase();return t.includes("network")||t.includes("connect")})}async cleanup(){if(!this.tempResourcesCreated)return void m.info("未创建临时资源,跳过清理步骤");this.logStep("清理临时资源...");let e=u.performance.now();if(this.tempBranch)try{m.info(`开始清理临时分支: ${this.tempBranch}`);let e=this.originalBranch||this.options.companyBranch;m.info(`切换到目标分支: ${e}`),await this.git.checkout(e);try{await this.git.deleteLocalBranch(this.tempBranch),m.success(`临时分支 ${this.tempBranch} 已删除`)}catch(e){throw new G("删除临时分支失败",e)}}catch(e){e instanceof G?m.warn(`${e.message}: ${e.originalError}`):m.warn(`清理临时资源时出错: ${e}`)}await this.cleanupBranchStrategy();try{if(m.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]),m.success(`临时目录 ${this.tempDir} 已删除`)}else m.info(`临时目录 ${this.tempDir} 不存在,跳过删除`)}catch(e){m.warn(`清理临时目录失败: ${e}`)}try{(await this.git.getRemotes(!0)).some(e=>"upstream"===e.name)?(await this.git.removeRemote("upstream"),m.success("上游仓库已移除")):m.info("没有找到上游仓库,跳过移除步骤")}catch(e){m.warn(`移除上游仓库失败: ${e instanceof Error?e.message:String(e)}`)}try{let t=u.performance.now();m.info(`清理临时资源完成,耗时: ${((t-e)/1e3).toFixed(2)}秒`)}catch(e){m.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"]),m.info(`当前分支: ${this.originalBranch}`),this.strategyBranch=this.generateBranchName(e),m.info(`生成策略分支: ${this.strategyBranch}`),(await this.git.branch(["--list",this.strategyBranch])).all.includes(this.strategyBranch)?(m.info(`分支 ${this.strategyBranch} 已存在,切换到该分支`),await this.git.checkout(this.strategyBranch)):(m.info(`创建新分支 ${this.strategyBranch} 基于 ${e.baseBranch}`),await this.git.checkoutBranch(this.strategyBranch,e.baseBranch))}catch(e){throw new G("设置分支策略失败",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{m.info(`切换回原分支: ${this.originalBranch}`),await this.git.checkout(this.originalBranch)}catch(e){m.warn(`切换回原分支失败: ${e instanceof Error?e.message:String(e)}`)}if(e.autoDeleteMergedBranches&&this.strategyBranch)try{await this.isBranchMerged(this.strategyBranch,e.baseBranch)&&(m.info(`删除已合并的分支: ${this.strategyBranch}`),await this.git.deleteLocalBranch(this.strategyBranch))}catch(e){m.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 m.error(`检查分支是否合并失败: ${e instanceof Error?e.message:String(e)}`),!1}}async run(){try{m.info(i.bold(i.blue("╔════════════════════════════════════════════╗"))),m.info(i.bold(i.blue("║ 仓库目录同步工具 ║"))),m.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&&m.warn(i.yellow("⚠️ 运行在dry-run模式下,不会实际修改任何文件")),this.options.previewOnly&&m.warn(i.yellow("⚠️ 运行在预览模式下,只会显示变更,不会实际修改任何文件"));try{await this.git.status()}catch(e){throw new G("未在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 m.info(i.yellow("⚠️ 预览模式: 已完成变更预览,不进行实际修改")),void m.success(i.bold(i.green("\n✅ 同步预览完成!")));this.options.dryRun?m.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=u.performance.now()),this.operationTimes.step_1){let e=u.performance.now()-this.operationTimes.step_1.start;m.info(`总执行时间: ${(e/1e3).toFixed(2)}秒`),m.info("各步骤执行时间:"),Object.entries(this.operationTimes).forEach(([e,t])=>{if(t.end){let r=(t.end-t.start)/1e3;m.info(`${e}: ${r.toFixed(2)}秒`)}})}m.success(i.bold(i.green("✅ 同步完成!"))),m.info(i.green("=".repeat(50)))}catch(e){!function(e){e instanceof V?(e.display(),"critical"===e.severity&&(m.error("发生严重错误,程序将退出"),process.exit(1))):(new Q("发生未知错误",e).display(),process.exit(1))}(e)}finally{try{this.options