// @bun
import{f as a,j as OK}from"./chunk-wkct9j9q.js";import{k as QK,l as XK}from"./chunk-fz6g3nqe.js";import{p as e,q as KK}from"./chunk-xey07r6k.js";import{x as l}from"./chunk-j3wvheq5.js";import{z as WK}from"./chunk-dgw5sv04.js";import{G as o,H as $K}from"./chunk-dpaxpy69.js";import{N as i,O as t}from"./chunk-nmj3neqg.js";import{Zb as A}from"./chunk-bqh4yh6g.js";import EK from"fs";import b from"process";class f{generateDashboard(Q,K={}){let{showOpenPRs:X=!0,showDetectedDependencies:W=!0,showDeprecatedDependencies:O=!0,bodyTemplate:Y}=K,$="Dependency Dashboard";if(Y)return{title:"Dependency Dashboard",body:this.applyTemplate(Y,Q)};let q=this.generateDefaultHeader(Q);if(O&&Q.deprecatedDependencies&&Q.deprecatedDependencies.length>0)q+=this.generateDeprecatedDependenciesSection(Q.deprecatedDependencies);if(X&&Q.openPRs.length>0)q+=this.generateOpenPRsSection(Q.openPRs);if(W)q+=this.generateDetectedDependenciesSection(Q.detectedDependencies);return q+=this.generateFooter(),{title:"Dependency Dashboard",body:q}}generateDefaultHeader(Q){return`This issue lists Buddy Bot updates and detected dependencies. Read the [Dependency Dashboard](https://buddy-bot.sh/features/dependency-dashboard) docs to learn more.

`}sanitizeReferences(Q){return Q.replace(/(?<![`\w])#(\d+)(?!\d)/g,"`#$1`")}generateOpenPRsSection(Q){let K=`## Open

The following updates have all been created. To force a retry/rebase of any, click on a checkbox below.

`;for(let X of Q){let W=this.extractPackageInfo(X),O=X.head,Y=X.url.includes("/pull/")&&X.url.includes("github.com")?`../pull/${X.number}`:X.url,$=this.sanitizeReferences(X.title);if(K+=` - [ ] <!-- rebase-branch=${O} -->[${$}](${Y})`,W.length>0)K+=` (\`${W.join("`, `")}\`)`;K+=`
`}return K+=` - [ ] <!-- rebase-all-open-prs -->**Click on this checkbox to rebase all open PRs at once**
`,K+=`
`,K}generateDetectedDependenciesSection(Q){let K=`## Detected dependencies

`;if(Q.packageJson.length>0)K+=this.generatePackageJsonSection(Q.packageJson);let X=Q.dependencyFiles.filter(($)=>$.path==="composer.json"||$.path.endsWith("/composer.json")),W=X.filter(($)=>$.path==="composer.json"),O=X.filter(($)=>$.path!=="composer.json");if(W.length>0)K+=this.generateComposerSection(W);if(Q.githubActions.length>0)K+=this.generateGitHubActionsSection(Q.githubActions);let Y=Q.dependencyFiles.filter(($)=>!$.path.endsWith("/composer.json")&&$.path!=="composer.json");if(Y.length>0||O.length>0)K+=this.generateDependencyFilesSection([...Y,...O]);return K}generatePackageJsonSection(Q){let K=`<details><summary>npm</summary>
<blockquote>

`;for(let X of Q){let W=X.path.split("/").pop()||X.path;K+=`<details><summary>${W}</summary>

`;let O={dependencies:X.dependencies.filter((Y)=>Y.type==="dependencies"),devDependencies:X.dependencies.filter((Y)=>Y.type==="devDependencies"),peerDependencies:X.dependencies.filter((Y)=>Y.type==="peerDependencies"),optionalDependencies:X.dependencies.filter((Y)=>Y.type==="optionalDependencies")};for(let[Y,$]of Object.entries(O))if($.length>0)for(let q of $)K+=` - \`${q.name} ${q.currentVersion}\`
`;K+=`
</details>

`}return K+=`</blockquote>
</details>

`,K}generateGitHubActionsSection(Q){let K=`<details><summary>github-actions</summary>
<blockquote>

`;for(let X of Q){K+=`<details><summary>${X.path}</summary>

`;let W=new Map;for(let O of X.dependencies){let Y=`${O.name}@${O.currentVersion}`;if(!W.has(Y))W.set(Y,{name:O.name,currentVersion:O.currentVersion})}for(let O of W.values())K+=` - \`${O.name} ${O.currentVersion}\`
`;K+=`
</details>

`}return K+=`</blockquote>
</details>

`,K}generateDependencyFilesSection(Q){let K=`<details><summary>dependency-files</summary>
<blockquote>

`;for(let X of Q){K+=`<details><summary>${X.path}</summary>

`;for(let W of X.dependencies)K+=` - \`${W.name} ${W.currentVersion}\`
`;K+=`
</details>

`}return K+=`</blockquote>
</details>

`,K}generateComposerSection(Q){let K=`<details><summary>composer</summary>
<blockquote>

`;for(let X of Q){let W=X.path.split("/").pop()||X.path;K+=`<details><summary>${W}</summary>

`;let O={require:X.dependencies.filter((Y)=>Y.type==="require"),"require-dev":X.dependencies.filter((Y)=>Y.type==="require-dev")};for(let[Y,$]of Object.entries(O))if($.length>0)for(let q of $)K+=` - \`${q.name} ${q.currentVersion}\`
`;K+=`
</details>

`}return K+=`</blockquote>
</details>

`,K}generateDeprecatedDependenciesSection(Q){let K=`> [!WARNING]
> These dependencies are deprecated and should be updated to avoid potential security risks and compatibility issues.

| Datasource | Name | Replacement PR? |
|------------|------|-----------------|
`;for(let X of Q){let W=`\`${X.name}\``,Y=(X.replacementAvailable?"available":"unavailable")==="available"?"![available](https://img.shields.io/badge/available-green)":"![unavailable](https://img.shields.io/badge/unavailable-orange)";K+=`| ${X.datasource} | ${W} | ${Y} |
`}return K+=`
`,K}generateFooter(){return`---

- [ ] <!-- manual job -->Check this box to trigger a request for Buddy Bot to run again on this repository
`}extractPackageInfo(Q){let K=[],X=[/update.*?dependency\s+(\S+)/i,/update\s+require(?:-dev)?\s+(\S+)\s+to\s+v?\d+/i,/update\s+(\S+)\s+to\s+v?\d+/i,/bump\s+(\S+)\s+from/i,/chore\(deps\):\s*update\s+dependency\s+(\S+)/i];for(let O of X){let Y=Q.title.match(O);if(Y&&Y[1]&&!K.includes(Y[1]))K.push(Y[1])}let W=[{name:"npm",pattern:/### npm Dependencies[\s\S]*?(?=###|\n\n---|z)/i},{name:"pkgx",pattern:/### Launchpad\/pkgx Dependencies[\s\S]*?(?=###|\n\n---|z)/i},{name:"actions",pattern:/### GitHub Actions[\s\S]*?(?=###|\n\n---|z)/i}];for(let O of W){let Y=Q.body.match(O.pattern);if(Y){let q=Y[0].match(/\|\s*\[([^\]]+)\]\([^)]+\)\s*\|/g);if(q)for(let H of q){let _=H.match(/\|\s*\[([^\]]+)\]/);if(_&&_[1]){let z=_[1].trim();if(z.includes("`")&&z.includes("->")){let Z=H.match(/\]\(([^)]+)\)/);if(Z&&Z[1]){let j=Z[1].match(/\/diffs\/npm\/([^/]+)\//);if(j&&j[1]){let V=decodeURIComponent(j[1]);if(V&&V.length>1&&!K.includes(V))K.push(V)}}continue}if(!z.includes("://")&&!z.includes("Compare Source")&&!z.includes("badge")&&!z.includes("!")&&!z.startsWith("[![")&&!z.includes("`")&&!z.includes("->")&&!z.includes(" -> ")&&!z.match(/^\d+\.\d+/)&&!z.includes(" ")&&z.length>0&&!K.includes(z))K.push(z)}}}}if(K.length<3){let O=Q.body.match(/`([^`]+)`/g);if(O)for(let Y of O){let $=Y.replace(/`/g,"").trim();if($.includes("->")||$.includes(" -> ")||$.includes("` -> `")||$.match(/^\d+\.\d+/)||$.match(/^v\d+/)||$.match(/[\d.]+\s*->\s*[\d.]+/)||$.match(/^[\d.]+$/)||$.match(/^\d+\.\d+\.\d+/)||$.match(/^\d+\.\d+\.\d+\./)||$.match(/^\^?\d+\.\d+/)||$.match(/^~\d+\.\d+/)||$.includes("://")||$.includes("Compare Source")||$.includes("badge")||$.includes(" "))continue;if($=$.split(",")[0].trim(),$&&$.length>1&&!K.includes($)&&($.startsWith("@")||$.includes("/")||$.match(/^[a-z][a-z0-9.-]*$/i)))K.push($)}}return K}applyTemplate(Q,K){return Q.replace(/\{\{repository\.owner\}\}/g,K.repository.owner).replace(/\{\{repository\.name\}\}/g,K.repository.name).replace(/\{\{openPRs\.count\}\}/g,K.openPRs.length.toString()).replace(/\{\{lastUpdated\}\}/g,K.lastUpdated.toISOString()).replace(/\{\{detectedDependencies\.packageJson\.count\}\}/g,K.detectedDependencies.packageJson.length.toString()).replace(/\{\{detectedDependencies\.githubActions\.count\}\}/g,K.detectedDependencies.githubActions.length.toString()).replace(/\{\{detectedDependencies\.dependencyFiles\.count\}\}/g,K.detectedDependencies.dependencyFiles.length.toString())}}var{Glob:_K}=globalThis.Bun;import{readdir as u,readFile as U,stat as m}from"fs/promises";import{join as D}from"path";function HK(Q){return(Q.split(/[/\\]/).pop()||"")==="build.zig.zon"}async function s(Q,K){try{if(!HK(Q))return null;let X=[],W=K.match(/\.dependencies\s*=\s*\.?\{/);if(W){let O=W.index+W[0].length,Y=1,$=O;while($<K.length&&Y>0){if(K[$]==="{")Y++;else if(K[$]==="}")Y--;$++}let q=K.slice(O,$-1),H=/\.(\w+)\s*=\s*\.?\{/g,_=H.exec(q);while(_!==null){let z=_[1],Z=_.index+_[0].length,E=1,j=Z;while(j<q.length&&E>0){if(q[j]==="{")E++;else if(q[j]==="}")E--;j++}let V=q.slice(Z,j-1),M=V.match(/\.url\s*=\s*"([^"]+)"/),B=V.match(/\.hash\s*=\s*"([^"]+)"/);if(M){let C=M[1],w=C.match(/\/v?(\d+\.\d+\.\d+(?:-[\w.]+)?)/i),N=w?w[1]:"unknown",S={url:C};if(B)S.hash=B[1];X.push({name:z,currentVersion:N,type:"zig-dependencies",file:Q,metadata:S})}_=H.exec(q)}}return{path:Q,type:"build.zig.zon",content:K,dependencies:X}}catch(X){return console.warn(`Failed to parse Zig manifest ${Q}:`,X),null}}class g{projectPath;logger;ignoreGlobs=[];constructor(Q,K,X){this.projectPath=Q;this.logger=K;if(X&&X.length>0)this.ignoreGlobs=X.map((W)=>new _K(W)),this.logger.info(`Initialized ${this.ignoreGlobs.length} ignore patterns: ${X.join(", ")}`)}async scanProject(){this.logger.info("Scanning project for package files...");let Q=Date.now(),K=[];try{let X=await this.findFiles("package.json");for(let z of X){if(this.shouldIgnorePath(z))continue;let Z=await this.parsePackageJsonFile(z);if(Z)K.push(Z)}let W=await this.findDependencyFiles();for(let z of W){if(this.shouldIgnorePath(z))continue;let Z=await this.parseDependencyFile(z);if(Z)K.push(Z)}let O=await this.findLockFiles();for(let z of O){if(this.shouldIgnorePath(z))continue;let Z=await this.parseLockFile(z);if(Z)K.push(Z)}let Y=await this.findComposerFiles();for(let z of Y){if(this.shouldIgnorePath(z))continue;let Z=await this.parseComposerFile(z);if(Z)K.push(Z)}let $=await this.findGitHubActionsFiles();for(let z of $){if(this.shouldIgnorePath(z))continue;let Z=await this.parseGitHubActionsFile(z);if(Z)K.push(Z)}let q=await this.findDockerfiles();this.logger.info(`\uD83D\uDD0D Found ${q.length} Dockerfile(s): ${q.join(", ")}`);for(let z of q){if(this.shouldIgnorePath(z))continue;let Z=await this.parseDockerfile(z);if(Z)K.push(Z),this.logger.info(`\uD83D\uDCE6 Parsed Dockerfile: ${z} with ${Z.dependencies.length} dependencies`)}let H=await this.findZigManifests();this.logger.info(`\uD83D\uDD0D Found ${H.length} Zig manifest(s): ${H.join(", ")}`);for(let z of H){if(this.shouldIgnorePath(z))continue;let Z=await this.parseZigManifestFile(z);if(Z)K.push(Z),this.logger.info(`\uD83D\uDCE6 Parsed Zig manifest: ${z} with ${Z.dependencies.length} dependencies`)}let _=Date.now()-Q;return this.logger.success(`Found ${K.length} package files in ${_}ms`),K}catch(X){throw this.logger.error("Failed to scan project:",X),new a(`Failed to scan project: ${X instanceof Error?X.message:"Unknown error"}`)}}async parsePackageJsonFile(Q){try{let K=D(this.projectPath,Q),X=await U(K,"utf-8"),W=JSON.parse(X),O=[];return this.extractDependencies(W.dependencies,"dependencies",Q,O),this.extractDependencies(W.devDependencies,"devDependencies",Q,O),this.extractDependencies(W.peerDependencies,"peerDependencies",Q,O),this.extractDependencies(W.optionalDependencies,"optionalDependencies",Q,O),{path:Q,type:"package.json",content:X,dependencies:O}}catch(K){return this.logger.warn(`Failed to parse package.json file ${Q}:`,K),null}}async parseLockFile(Q){try{let K=D(this.projectPath,Q),X=await U(K,"utf-8"),W=Q.split("/").pop()||"",O;if(W==="bun.lockb")O="bun.lockb";else if(W==="package-lock.json")O="package-lock.json";else if(W==="yarn.lock")O="yarn.lock";else if(W==="pnpm-lock.yaml")O="pnpm-lock.yaml";else return null;let Y=await this.extractLockFileDependencies(X,O,Q);return{path:Q,type:O,content:X,dependencies:Y}}catch(K){return this.logger.warn(`Failed to parse lock file ${Q}:`,K),null}}async parseDependencyFile(Q){try{let K=D(this.projectPath,Q),X=await U(K,"utf-8");return await t(Q,X)}catch(K){return this.logger.warn(`Failed to parse dependency file ${Q}:`,K),null}}async findDependencyFiles(){let Q=[],K=["deps.yaml","deps.yml","dependencies.yaml","dependencies.yml","pkgx.yaml","pkgx.yml",".deps.yaml",".deps.yml"];for(let O of K){let Y=await this.findFiles(O);Q.push(...Y)}let X=await this.findFilesByPattern("*.yaml"),W=await this.findFilesByPattern("*.yml");for(let O of[...X,...W])if(i(O)&&!Q.includes(O))Q.push(O);return Q}async findGitHubActionsFiles(){let Q=[];try{let X=D(this.projectPath,".github","workflows");if((await m(X).catch(()=>null))?.isDirectory()){let O=await this.findFilesByPatternInDir("*.yaml",X),Y=await this.findFilesByPatternInDir("*.yml",X);for(let $ of[...O,...Y])if(QK($))Q.push($)}}catch{}return Q}async findDockerfiles(){let Q=[];try{let K=["Dockerfile","dockerfile","Dockerfile.dev","Dockerfile.prod","Dockerfile.production","Dockerfile.development","Dockerfile.test","Dockerfile.staging"];for(let W of K){let O=await this.findFiles(W);Q.push(...O)}let X=await this.findFilesByPattern("Dockerfile*");for(let W of X)if(!Q.includes(W)&&e(W))Q.push(W)}catch{}return Q}async parseGitHubActionsFile(Q){try{let K=D(this.projectPath,Q),X=await U(K,"utf-8");return await XK(Q,X)}catch(K){return this.logger.warn(`Failed to parse GitHub Actions file ${Q}:`,K),null}}async parseDockerfile(Q){try{let K=D(this.projectPath,Q),X=await U(K,"utf-8");return await KK(Q,X)}catch(K){return this.logger.warn(`Failed to parse Dockerfile ${Q}:`,K),null}}async findZigManifests(){let Q=[];try{let K=await this.findFiles("build.zig.zon");Q.push(...K)}catch{}return Q}async parseZigManifestFile(Q){try{let K=D(this.projectPath,Q),X=await U(K,"utf-8");return await s(Q,X)}catch(K){return this.logger.warn(`Failed to parse Zig manifest ${Q}:`,K),null}}async findComposerFiles(){let Q=[];try{let K=await this.findFiles("composer.json");Q.push(...K);let X=await this.findFiles("composer.lock");Q.push(...X)}catch{}return Q}async parseComposerFile(Q){try{let K=D(this.projectPath,Q),X=await U(K,"utf-8"),{parseComposerFile:W}=await import("./chunk-qerc8z7c.js");return await W(Q,X)}catch(K){return this.logger.warn(`Failed to parse Composer file ${Q}:`,K),null}}extractDependencies(Q,K,X,W){if(!Q)return;for(let[O,Y]of Object.entries(Q))W.push({name:O,currentVersion:Y,type:K,file:this.getRelativePath(X)})}async extractLockFileDependencies(Q,K,X){let W=[];if(K==="package-lock.json")try{let O=JSON.parse(Q);if(O.packages){for(let[Y,$]of Object.entries(O.packages))if(Y&&Y!==""&&$&&typeof $==="object"){let q=$;if(q.version){let H=Y.startsWith("node_modules/")?Y.replace("node_modules/",""):Y;W.push({name:H,currentVersion:q.version,type:q.dev?"devDependencies":"dependencies",file:this.getRelativePath(X)})}}}}catch(O){this.logger.warn("Failed to parse package-lock.json:",O)}return W}async findFiles(Q,K=this.projectPath){let X=[];try{let W=await u(K);for(let O of W){let Y=D(K,O);try{let $=await m(Y);if($.isDirectory()){if(!this.shouldSkipDirectory(O)){let q=await this.findFiles(Q,Y);X.push(...q)}}else if($.isFile()&&O===Q){let q=A("path"),H=q.relative(this.projectPath,Y);X.push(H.split(q.sep).join("/"))}}catch{continue}}}catch{}return X}async findLockFiles(){let Q=["bun.lock","bun.lockb","package-lock.json","yarn.lock","pnpm-lock.yaml"],K=[];for(let X of Q){let W=await this.findFiles(X);K.push(...W)}return K}async findFilesByPattern(Q){let K=[],X=Q.replace("*.","");try{let W=await u(this.projectPath);for(let O of W){let Y=D(this.projectPath,O),$=await m(Y);if($.isFile()&&O.endsWith(`.${X}`)){let q=A("path"),H=q.relative(this.projectPath,Y);K.push(H.split(q.sep).join("/"))}else if($.isDirectory()&&!this.shouldSkipDirectory(O)){let q=await this.findFilesByPatternInDir(Q,Y);K.push(...q)}}}catch{}return K}async findFilesByPatternInDir(Q,K){let X=[],W=Q.replace("*.","");try{let O=await u(K);for(let Y of O){let $=D(K,Y),q=await m($);if(q.isFile()&&Y.endsWith(`.${W}`)){let H=A("path"),_=H.relative(this.projectPath,$);X.push(_.split(H.sep).join("/"))}else if(q.isDirectory()&&!this.shouldSkipDirectory(Y)){let H=await this.findFilesByPatternInDir(Q,$);X.push(...H)}}}catch{}return X}shouldIgnorePath(Q){if(this.ignoreGlobs.length===0)return!1;let K=Q;if(Q.startsWith("/")||Q.includes(":"))K=this.getRelativePath(Q);for(let X of this.ignoreGlobs)if(X.match(K))return this.logger.debug(`Ignoring path: ${K} (matched pattern)`),!0;return!1}shouldSkipDirectory(Q){return["node_modules",".git",".next",".nuxt","dist","build","coverage",".nyc_output","tmp","temp",".cache",".vscode",".idea"].includes(Q)||Q.startsWith(".")}getRelativePath(Q){let K=A("path");return K.relative(this.projectPath,Q).split(K.sep).join("/")}async getDependencyCount(){return(await this.scanProject()).reduce((K,X)=>K+X.dependencies.length,0)}async getUniqueDependencies(){return(await this.scanProject()).flatMap((W)=>W.dependencies).filter((W,O,Y)=>O===Y.findIndex(($)=>$.name===W.name))}}class c{async checkDeprecatedDependencies(Q){let K=[];for(let X of Q){let W=await this.checkFileForDeprecatedDependencies(X);K.push(...W)}return K}async checkFileForDeprecatedDependencies(Q){let K=[];for(let X of Q.dependencies){let W=await this.checkDependencyDeprecation(X,Q.type);if(W.deprecated)K.push({name:X.name,currentVersion:X.currentVersion,datasource:this.getDatasourceFromFileType(Q.type),file:Q.path,type:X.type,replacementAvailable:!1,deprecationMessage:W.message,suggestedReplacement:W.suggestedReplacement})}return K}async checkDependencyDeprecation(Q,K){try{if(K==="package.json"||K.includes("lock"))return await this.checkNpmDeprecation(Q);else if(K==="composer.json"||K==="composer.lock")return await this.checkComposerDeprecation(Q);else if(K==="deps.yaml"||K==="deps.yml"||K.includes("deps"))return await this.checkBunDeprecation(Q);return{deprecated:!1}}catch(X){return console.warn(`Failed to check deprecation for ${Q.name}:`,X),{deprecated:!1}}}async checkNpmDeprecation(Q){try{let K=await fetch(`https://registry.npmjs.org/${Q.name}`);if(!K.ok)return{deprecated:!1};let X=await K.json();if(X.deprecated)return{deprecated:!0,message:X.deprecated,suggestedReplacement:this.extractSuggestedReplacement(X.deprecated)};let W=X.versions?.[Q.currentVersion];if(W?.deprecated)return{deprecated:!0,message:W.deprecated,suggestedReplacement:this.extractSuggestedReplacement(W.deprecated)};return{deprecated:!1}}catch(K){return console.warn(`Failed to check npm deprecation for ${Q.name}:`,K),{deprecated:!1}}}async checkComposerDeprecation(Q){try{let K=await fetch(`https://packagist.org/packages/${Q.name}.json`);if(!K.ok)return{deprecated:!1};let X=await K.json();if(X.package?.abandoned){let W=typeof X.package.abandoned==="string"?X.package.abandoned:null;return{deprecated:!0,message:`Package is abandoned${W?`, use ${W} instead`:""}`,suggestedReplacement:W||void 0}}return{deprecated:!1}}catch(K){return console.warn(`Failed to check Composer deprecation for ${Q.name}:`,K),{deprecated:!1}}}async checkBunDeprecation(Q){return await this.checkNpmDeprecation(Q)}extractSuggestedReplacement(Q){let K=[/use\s+([a-z0-9@/-]+)\s+instead/i,/replaced\s+by\s+([a-z0-9@/-]+)/i,/migrate\s+to\s+([a-z0-9@/-]+)/i,/switch\s+to\s+([a-z0-9@/-]+)/i];for(let X of K){let W=Q.match(X);if(W)return W[1]}return}getDatasourceFromFileType(Q){if(Q==="package.json"||Q.includes("lock"))return"npm";else if(Q==="composer.json"||Q==="composer.lock")return"composer";else if(Q==="deps.yaml"||Q==="deps.yml"||Q.includes("deps"))return"bun";else if(Q==="github-actions")return"github-actions";return"unknown"}}class x{verbose;constructor(Q=!1){this.verbose=Q}info(Q,...K){console.log(Q,...K)}warn(Q,...K){console.warn(Q,...K)}error(Q,...K){console.error(Q,...K)}debug(Q,...K){if(this.verbose)console.log(`\x1B[90m\uD83D\uDC1B\x1B[0m ${Q}`,...K)}success(Q,...K){console.log(`\x1B[32m\u2713\x1B[0m ${Q}`,...K)}static verbose(){return new x(!0)}static quiet(){return new x(!1)}}class jK{config;projectPath;logger;scanner;registryClient;dashboardGenerator;constructor(Q,K=b.cwd()){this.config=Q;this.projectPath=K;this.logger=new x(Q.verbose??!1),this.resolveRepositoryConfig(),this.scanner=new g(this.projectPath,this.logger,this.config.packages?.ignorePaths),this.registryClient=new OK(this.projectPath,this.logger,this.config),this.dashboardGenerator=new f}resolveRepositoryConfig(){if(!this.config.repository)return;if(this.config.repository.owner&&this.config.repository.name)return;let Q=b.env.GITHUB_REPOSITORY;if(Q){let[K,X]=Q.split("/");if(K&&X){if(!this.config.repository.owner)this.config.repository.owner=K;if(!this.config.repository.name)this.config.repository.name=X;this.logger.info(`Auto-detected repository: ${K}/${X} from GITHUB_REPOSITORY`)}}}async scanForUpdates(){let Q=Date.now();this.logger.info("Starting dependency update scan...");try{let K=Date.now(),X=await this.scanner.scanProject();this.logger.info(`\u23F1\uFE0F  Package file scan took ${Date.now()-K}ms`);let W=X.reduce((S,J)=>S+J.dependencies.length,0),O=[],Y=Date.now();if(this.config.packages?.ignore&&this.config.packages.ignore.length>0)O=(await this.registryClient.getOutdatedPackages()).filter((J)=>!this.config.packages.ignore.includes(J.name));else O=await this.registryClient.getOutdatedPackages();this.logger.info(`\u23F1\uFE0F  bun outdated check took ${Date.now()-Y}ms (found ${O.length} updates)`);let $=Date.now(),q=await this.checkDependencyFilesForUpdates(X);this.logger.info(`\u23F1\uFE0F  Dependency file checks took ${Date.now()-$}ms (found ${q.length} updates)`);let H=Date.now(),_=await this.checkGitHubActionsForUpdates(X);this.logger.info(`\u23F1\uFE0F  GitHub Actions checks took ${Date.now()-H}ms (found ${_.length} updates)`);let z=Date.now(),Z=await this.checkDockerfilesForUpdates(X);this.logger.info(`\u23F1\uFE0F  Docker image checks took ${Date.now()-z}ms (found ${Z.length} updates)`);let E=[...O,...q,..._,...Z];if(this.config.packages?.ignore&&this.config.packages.ignore.length>0)E=E.filter((S)=>!this.config.packages.ignore.includes(S.name));let j=Date.now();if(this.config.packages?.strategy)E=this.filterUpdatesByStrategy(E,this.config.packages.strategy);this.logger.info(`\u23F1\uFE0F  Strategy filtering took ${Date.now()-j}ms`);let V=Date.now();E=await this.filterUpdatesByMinimumReleaseAge(E),this.logger.info(`\u23F1\uFE0F  Minimum release age filtering took ${Date.now()-V}ms`);let M=Date.now();E=$K(E),this.logger.info(`\u23F1\uFE0F  Sorting took ${Date.now()-M}ms`);let B=Date.now(),C=this.config.packages?.groups?this.groupUpdatesByConfig(E):o(E);this.logger.info(`\u23F1\uFE0F  Grouping took ${Date.now()-B}ms`);let w=Date.now()-Q,N={totalPackages:W,updates:E,groups:C,scannedAt:new Date,duration:w};return this.logger.success(`Scan completed in ${w}ms. Found ${E.length} updates.`),N}catch(K){throw this.logger.error("Failed to scan for updates:",K),K}}async createPullRequests(Q){let K=Date.now();this.logger.info("Creating pull requests for updates...");try{if(!this.config.repository){this.logger.error("\u274C Repository configuration required for PR creation"),this.logger.info("Configure repository.provider, repository.owner, repository.name in buddy-bot.config.ts");return}if(!this.config.repository.owner||!this.config.repository.name){this.logger.error("\u274C Repository owner and name are required for PR creation"),this.logger.info("Set them in buddy-bot.config.ts or ensure GITHUB_REPOSITORY env var is available");return}let X=b.env.GITHUB_TOKEN,W=b.env.BUDDY_BOT_TOKEN;if(!X&&!W){this.logger.error("\u274C GITHUB_TOKEN or BUDDY_BOT_TOKEN environment variable required for PR creation");return}let O=X||W,Y=!!W;if(W)console.log("\u2705 BUDDY_BOT_TOKEN detected - workflow file permissions enabled");else console.log("\u2139\uFE0F No BUDDY_BOT_TOKEN \u2014 workflow file updates will be skipped");let $=new l(O,this.config.repository.owner,this.config.repository.name,Y,W),q=new WK(this.config),H=this.config.maxPRsPerRun??10,_=0;for(let Z of Q.groups)try{let E=Date.now();this.logger.info(`Creating PR for group: ${Z.name} (${Z.updates.length} updates)`);let j=Z.title,V=Date.now(),M=await q.generateBody(Z),B=Date.now()-V;this.logger.info(`\u23F1\uFE0F  PR body generation took ${B}ms`);let C=await $.getPullRequests("open"),w=this.generateBranchName(Z),N=`buddy-bot/update-${Z.name.toLowerCase().replace(/\s+/g,"-")}-`,S=C.find((G)=>(G.head===w||G.title===j||G.head.startsWith(N)||this.isSimilarPRTitle(G.title,j))&&(G.author==="github-actions[bot]"||G.author.includes("buddy")||G.head.startsWith("buddy-bot/"))&&!G.head.includes("renovate/")&&!G.head.includes("dependabot/")&&!G.author.toLowerCase().includes("renovate")&&!G.author.toLowerCase().includes("dependabot"));if(S){if(this.logger.info(`\uD83D\uDD04 Found existing PR #${S.number}: ${S.title}`),this.shouldAutoClosePR(S,Z.updates)){this.logger.info(`\uD83D\uDD12 Auto-closing PR #${S.number} due to respectLatest config change`);try{await $.closePullRequest(S.number),await $.deleteBranch(S.head),this.logger.success(`\u2705 Auto-closed PR #${S.number} and deleted branch ${S.head}`);continue}catch(L){this.logger.error(`\u274C Failed to auto-close PR #${S.number}:`,L)}}if(this.checkIfUpdatesMatch(S.body,Z.updates)){this.logger.info("\u2705 Existing PR has the same updates, skipping creation");continue}else{this.logger.info("\uD83D\uDD04 Updates differ, will update existing PR with new content");let L=S.head;try{let{spawn:T}=await import("child_process"),R=(k,ZK)=>{return new Promise((zK,d)=>{let r=T(k,ZK,{stdio:"pipe"});r.on("close",(p)=>{if(p===0)zK();else d(Error(`Git command failed with code ${p}`))}),r.on("error",d)})};await R("git",["checkout","main"]),await R("git",["reset","--hard","HEAD"]),await R("git",["clean","-fd"]),console.log(`\uD83E\uDDF9 Reset to clean main state before updating existing PR ${S.number}`)}catch(T){console.warn("\u26A0\uFE0F Failed to reset to clean state, continuing anyway:",T)}let v=await this.generateAllFileUpdates(Z.updates);if(v.length===0)this.logger.warn(`\u2139\uFE0F No file changes generated for existing PR ${S.number}, updating metadata only`);else{this.logger.info(`\uD83D\uDCDD Regenerated ${v.length} file changes for existing PR ${S.number}`);try{let{hasBranchDifferences:T}=await import("./chunk-52s867bm.js");if(!await T(v,L))this.logger.info(`\u2139\uFE0F No content differences for ${L}; recreating from ${this.config.repository.baseBranch||"main"} with same dependency changes to keep branch up-to-date`),await $.commitChanges(L,`${Z.title} (rebased)`,v,this.config.repository.baseBranch||"main"),this.logger.success(`\u2705 Recreated ${L} from ${this.config.repository.baseBranch||"main"} (dependency versions unchanged)`);else await $.commitChanges(L,`${Z.title} (updated)`,v,this.config.repository.baseBranch||"main"),this.logger.success(`\u2705 Recreated branch ${L} with latest dependency versions`)}catch(T){this.logger.warn("\u26A0\uFE0F Failed to compare branch content, proceeding with commit:",T),await $.commitChanges(L,`${Z.title} (updated)`,v,this.config.repository.baseBranch||"main"),this.logger.success(`\u2705 Recreated branch ${L} with latest dependency versions`)}}let h=q.generateLabels(Z);await $.updatePullRequest(S.number,{title:j,body:M,labels:h,reviewers:this.config.pullRequest?.reviewers,assignees:this.config.pullRequest?.assignees}),this.logger.success(`\u2705 Updated existing PR #${S.number}: ${j}`),this.logger.info(`\uD83D\uDD17 ${S.url}`);continue}}if(_>=H){this.logger.warn(`\u26A0\uFE0F Rate limit reached: already created ${_} PRs this run (max: ${H}). Skipping remaining groups.`);break}let J=this.generateBranchName(Z);if(await $.branchExists(J)){this.logger.info(`\uD83D\uDD04 Branch ${J} already exists, checking for associated PR...`);let G=C.find((I)=>I.head===J);if(G){this.logger.info(`\u2705 Found existing PR #${G.number} for branch ${J}, updating it...`);let I=await this.generateAllFileUpdates(Z.updates);if(I.length>0)await $.commitChanges(J,`${Z.title} (updated)`,I,this.config.repository.baseBranch||"main");let L=q.generateLabels(Z);await $.updatePullRequest(G.number,{title:j,body:M,labels:L,reviewers:this.config.pullRequest?.reviewers,assignees:this.config.pullRequest?.assignees}),this.logger.success(`\u2705 Updated existing PR #${G.number}: ${j}`),this.logger.info(`\uD83D\uDD17 ${G.url}`);continue}this.logger.info(`\uD83E\uDDF9 Branch ${J} exists but has no open PR, cleaning up...`);try{await $.deleteBranch(J)}catch(I){this.logger.warn(`\u26A0\uFE0F Failed to delete orphaned branch ${J}:`,I)}}await $.createBranch(J,this.config.repository.baseBranch||"main");try{let{spawn:G}=await import("child_process"),I=(L,v)=>{return new Promise((h,T)=>{let R=G(L,v,{stdio:"pipe"});R.on("close",(k)=>{if(k===0)h();else T(Error(`Git command failed with code ${k}`))}),R.on("error",T)})};await I("git",["checkout","main"]),await I("git",["reset","--hard","HEAD"]),await I("git",["clean","-fd"]),console.log(`\uD83E\uDDF9 Reset to clean main state before generating updates for ${Z.name}`)}catch(G){console.warn("\u26A0\uFE0F Failed to reset to clean state, continuing anyway:",G)}let F=await this.generateAllFileUpdates(Z.updates);if(F.length===0){this.logger.warn(`\u2139\uFE0F No file changes generated for group ${Z.name}, skipping PR creation`);continue}let y=!1;for(let G of F)try{let I=await import("fs");if(I.existsSync(G.path)){if(I.readFileSync(G.path,"utf-8")!==G.content){y=!0;break}}else{y=!0;break}}catch{y=!0;break}if(!y){this.logger.warn(`\u2139\uFE0F No actual content changes for group ${Z.name}, skipping PR creation`);continue}this.logger.info(`\uD83D\uDCDD Generated ${F.length} file changes for ${Z.name}`),await $.commitChanges(J,Z.title,F,this.config.repository.baseBranch||"main");let YK=q.generateLabels(Z),P=await $.createPullRequest({title:j,body:M,head:J,base:this.config.repository.baseBranch||"main",draft:!1,reviewers:this.config.pullRequest?.reviewers,assignees:this.config.pullRequest?.assignees,labels:YK});_++,this.logger.success(`\u2705 Created PR #${P.number}: ${P.title} (${_}/${H} this run)`),this.logger.info(`\uD83D\uDD17 ${P.url}`);let qK=Date.now()-E;this.logger.info(`\u23F1\uFE0F  Total group processing took ${qK}ms`)}catch(E){this.logger.error(`\u274C Failed to create PR for group ${Z.name}:`,E)}let z=Date.now()-K;this.logger.success(`\u2705 Completed PR creation for ${Q.groups.length} group(s) in ${z}ms`)}catch(X){throw this.logger.error("Failed to create pull requests:",X),X}}shouldRespectVersion(Q){if(!(this.config.packages?.respectLatest??!0))return!1;let X=["latest","*","main","master","develop","dev"],W=Q.toLowerCase().trim();return X.includes(W)}async checkDependencyFilesForUpdates(Q){let{isDependencyFile:K}=await import("./chunk-mkrxqseg.js"),{resolveDependencyFile:X}=await import("./chunk-q2bcjht7.js"),W=[],O=Q.filter((q)=>K(q.path));this.logger.info(`\u26A1 Checking ${O.length} dependency files in parallel...`);let Y=O.map(async(q)=>{try{this.logger.info(`Checking dependency file: ${q.path}`);let H=await X(q.path),_=[];for(let z of H.allDependencies||[]){if(this.shouldRespectVersion(z.constraint)){this.logger.debug(`Skipping ${z.name} - version "${z.constraint}" should be respected`);continue}if(z.constraint!==z.version&&z.version){let Z=z.constraint.replace(/^[\^~>=<]+/,"");if(!this.isNewerVersion(Z,z.version)){this.logger.debug(`Skipping ${z.name} - latest (${z.version}) is not newer than constraint (${Z})`);continue}let E=this.getUpdateType(Z,z.version),j=z.version;_.push({name:z.name,currentVersion:z.constraint,newVersion:j,updateType:E,dependencyType:"dependencies",file:q.path,metadata:void 0,releaseNotesUrl:void 0,changelogUrl:void 0,homepage:void 0})}}return _}catch(H){return this.logger.error(`Failed to check dependency file ${q.path}:`,H),[]}}),$=await Promise.all(Y);return W.push(...$.flat()),W}async checkGitHubActionsForUpdates(Q){let{isGitHubActionsFile:K}=await import("./chunk-ekk7xs0n.js"),{fetchLatestActionVersion:X}=await import("./chunk-ekk7xs0n.js"),W=[],O=Q.filter((z)=>K(z.path));this.logger.info(`\uD83D\uDD0D Found ${O.length} GitHub Actions workflow files`);let Y=[];for(let z of O){let Z=z.dependencies.filter((E)=>E.type==="github-actions");this.logger.info(`Found ${Z.length} GitHub Actions in ${z.path}`),Z.forEach((E)=>Y.push({file:z,dep:E}))}this.logger.info(`\u26A1 Checking ${Y.length} GitHub Actions in parallel...`);let $=Y.map(async({file:z,dep:Z})=>{try{this.logger.info(`Checking action: ${Z.name}@${Z.currentVersion}`);let E=await X(Z.name);if(E)if(this.logger.info(`Latest version for ${Z.name}: ${E}`),E!==Z.currentVersion){let j=this.getUpdateType(Z.currentVersion,E);return this.logger.info(`Update available: ${Z.name} ${Z.currentVersion} \u2192 ${E} (${j})`),{name:Z.name,currentVersion:Z.currentVersion,newVersion:E,updateType:j,dependencyType:"github-actions",file:z.path,metadata:void 0,releaseNotesUrl:`https://github.com/${Z.name}/releases`,changelogUrl:void 0,homepage:`https://github.com/${Z.name}`}}else this.logger.info(`No update needed for ${Z.name}: already at ${E}`);else this.logger.warn(`Could not fetch latest version for ${Z.name}`);return null}catch(E){return this.logger.warn(`Failed to check version for action ${Z.name}:`,E),null}}),H=(await Promise.all($)).filter((z)=>z!==null);W.push(...H),this.logger.info(`Generated ${W.length} GitHub Actions updates`);let _=W.reduce((z,Z)=>{if(!z.find((j)=>j.name===Z.name&&j.currentVersion===Z.currentVersion&&j.newVersion===Z.newVersion&&j.file===Z.file))z.push(Z);return z},[]);return this.logger.info(`After deduplication: ${_.length} unique GitHub Actions updates`),_}async checkDockerfilesForUpdates(Q){let{isDockerfile:K}=await import("./chunk-g0vvfnks.js"),{fetchLatestDockerImageVersion:X}=await import("./chunk-g0vvfnks.js"),W=[],O=Q.filter((z)=>K(z.path));this.logger.info(`\uD83D\uDD0D Found ${O.length} Dockerfile(s)`);let Y=[];for(let z of O){let Z=z.dependencies.filter((E)=>E.type==="docker-image");this.logger.info(`Found ${Z.length} Docker images in ${z.path}`),Z.forEach((E)=>Y.push({file:z,dep:E}))}this.logger.info(`\u26A1 Checking ${Y.length} Docker images in parallel...`);let $=Y.map(async({file:z,dep:Z})=>{try{if(this.logger.info(`Checking Docker image: ${Z.name}:${Z.currentVersion}`),this.shouldRespectVersion(Z.currentVersion))return this.logger.debug(`Skipping ${Z.name} - version "${Z.currentVersion}" should be respected`),null;let E=await X(Z.name);if(E)if(this.logger.info(`Latest version for ${Z.name}: ${E}`),E!==Z.currentVersion){let j=this.getUpdateType(Z.currentVersion,E);return this.logger.info(`Update available: ${Z.name} ${Z.currentVersion} \u2192 ${E} (${j})`),{name:Z.name,currentVersion:Z.currentVersion,newVersion:E,updateType:j,dependencyType:"docker-image",file:z.path,metadata:void 0,releaseNotesUrl:`https://hub.docker.com/r/${Z.name}/tags`,changelogUrl:void 0,homepage:`https://hub.docker.com/r/${Z.name}`}}else this.logger.info(`No update needed for ${Z.name}: already at ${E}`);else this.logger.warn(`Could not fetch latest version for Docker image ${Z.name}`);return null}catch(E){return this.logger.warn(`Failed to check version for Docker image ${Z.name}:`,E),null}}),H=(await Promise.all($)).filter((z)=>z!==null);W.push(...H),this.logger.info(`Generated ${W.length} Docker image updates`);let _=W.reduce((z,Z)=>{if(!z.find((j)=>j.name===Z.name&&j.currentVersion===Z.currentVersion&&j.newVersion===Z.newVersion&&j.file===Z.file))z.push(Z);return z},[]);return this.logger.info(`After deduplication: ${_.length} unique Docker image updates`),_}getUpdateType(Q,K){try{let X=Q.replace(/^[v^~>=<@]+/,""),W=K.replace(/^[v^~>=<@]+/,""),O=(q)=>{let H=q.split(".");while(H.length<3)H.push("0");return H.join(".")};if(X=O(X),W=O(W),Bun.semver.order(W,X)<=0)return"patch";let Y=X.split(".").map(Number),$=W.split(".").map(Number);if($[0]>Y[0])return"major";if($[0]===Y[0]&&$[1]>Y[1])return"minor";return"patch"}catch{return"patch"}}isNewerVersion(Q,K){try{return Bun.semver.order(K.replace(/^[v^~>=<@]+/,""),Q.replace(/^[v^~>=<@]+/,""))>0}catch{return!1}}async generateAllFileUpdates(Q){let K=[],X=Q.filter((H)=>H.file.endsWith("package.json")&&!H.file.includes(".yaml")&&!H.file.includes(".yml")&&!H.file.includes(".github/workflows/")),W=new Map;for(let H of X){if(!W.has(H.file))W.set(H.file,[]);W.get(H.file).push(H)}for(let[H,_]of W)try{let z=EK.readFileSync(H,"utf-8"),Z=JSON.parse(z);for(let E of _){let j=!1,V=E.name.replace(/\s*\(dev\)$/,"").replace(/\s*\(peer\)$/,"").replace(/\s*\(optional\)$/,""),M=["dependencies","devDependencies","peerDependencies","optionalDependencies"];for(let B of M)if(Z[B]&&Z[B][V]){let w=Z[B][V].match(/^(\D*)/),N=w?w[1]:"",S=V.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),J=B.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),n=new RegExp(`("${J}"\\s*:\\s*\\{[^}]*?)("${S}"\\s*:\\s*")([^"]+)(")([^}]*?\\})`,"gs"),F=`${N}${E.newVersion}`;z=z.replace(n,`$1$2${F}$4$5`),j=!0;break}if(!j)console.warn(`Package ${V} not found in ${H}`)}K.push({path:H,content:z,type:"update"})}catch(z){console.warn(`Failed to update ${H}:`,z)}let O=Q.filter((H)=>{let _=H.file.toLowerCase();return(_.endsWith("deps.yaml")||_.endsWith("deps.yml")||_.endsWith("dependencies.yaml")||_.endsWith("dependencies.yml"))&&!H.file.includes(".github/workflows/")});if(O.length>0)try{let{generateDependencyFileUpdates:H}=await import("./chunk-mkrxqseg.js"),_=await H(O);K.push(..._)}catch(H){this.logger.error("Failed to generate dependency file updates:",H)}let Y=Q.filter((H)=>H.file.endsWith("composer.json")||H.file.endsWith("composer.lock"));if(Y.length>0)try{let{generateComposerUpdates:H}=await import("./chunk-qerc8z7c.js"),_=await H(Y);K.push(..._)}catch(H){this.logger.error("Failed to generate Composer updates:",H)}let $=Q.filter((H)=>H.file.includes(".github/workflows/"));if($.length>0)try{let{generateGitHubActionsUpdates:H}=await import("./chunk-ekk7xs0n.js"),_=await H($);K.push(..._)}catch(H){this.logger.error("Failed to generate GitHub Actions updates:",H)}let q=Q.filter((H)=>H.dependencyType==="docker-image");if(q.length>0)try{let{generateDockerfileUpdates:H}=await import("./chunk-g0vvfnks.js"),_=await H(q);K.push(..._)}catch(H){this.logger.error("Failed to generate Dockerfile updates:",H)}return K}async run(){let Q=await this.scanForUpdates();if(Q.updates.length===0)return this.logger.info("No updates available!"),Q;if(this.config.pullRequest)await this.createPullRequests(Q);return Q}async checkPackages(Q){return this.logger.info(`Checking specific packages: ${Q.join(", ")}`),this.registryClient.getUpdatesForPackages(Q)}async checkPackagesWithPattern(Q){return this.logger.info(`Checking packages with pattern: ${Q}`),this.registryClient.getUpdatesWithPattern(Q)}filterUpdatesByStrategy(Q,K){if(K==="all")return Q;return Q.filter((X)=>{switch(K){case"major":return X.updateType==="major";case"minor":return X.updateType==="major"||X.updateType==="minor";case"patch":return!0;default:return!0}})}async filterUpdatesByMinimumReleaseAge(Q){let K=this.config.packages?.minimumReleaseAge??0;if(K===0)return Q;this.logger.info(`Applying minimum release age filter (${K} minutes) in parallel...`);let X=Q.map(async($)=>{try{if(await this.registryClient.meetsMinimumReleaseAge($.name,$.newVersion,$.dependencyType))return $;else return this.logger.debug(`Filtered out ${$.name}@${$.newVersion} (${$.dependencyType}) due to minimum release age requirement`),null}catch(q){return this.logger.warn(`Error checking release age for ${$.name}@${$.newVersion} (${$.dependencyType}), including update:`,q),$}}),O=(await Promise.all(X)).filter(($)=>$!==null),Y=Q.length-O.length;if(Y>0)this.logger.info(`Filtered out ${Y} updates due to minimum release age requirement`);return O}groupUpdatesByConfig(Q){let K=[],X=[...Q];if(this.config.packages?.groups)for(let W of this.config.packages.groups){let O=[];for(let Y of W.patterns){let $=new RegExp(Y.replace("*",".*")),q=X.filter((H)=>$.test(H.name));O.push(...q),q.forEach((H)=>{let _=X.indexOf(H);if(_>-1)X.splice(_,1)})}if(O.length>0){let Y=O;if(W.strategy)Y=this.filterUpdatesByStrategy(O,W.strategy);K.push({name:W.name,updates:Y,updateType:this.getHighestUpdateType(Y),title:`chore(deps): update ${W.name}`,body:`Update ${Y.length} packages in ${W.name} group`})}}if(X.length>0){let W=o(X);K.push(...W)}return K}getHighestUpdateType(Q){if(Q.some((K)=>K.updateType==="major"))return"major";if(Q.some((K)=>K.updateType==="minor"))return"minor";return"patch"}generateBranchName(Q){return`buddy-bot/update-${Q.name.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,"").replace(/-+/g,"-").replace(/^-|-$/g,"")}`}isSimilarPRTitle(Q,K){if(Q.toLowerCase()===K.toLowerCase())return!0;let X=Q.toLowerCase(),W=K.toLowerCase(),O=X.includes("github actions"),Y=W.includes("github actions");if(O&&Y)return!0;if(O!==Y)return!1;let $=X.includes("docker image"),q=W.includes("docker image");if($&&q)return!0;if($!==q)return!1;let H=[/update all non-major/i,/update \d+ dependenc(y|ies)/i,/update.*\(minor\)/i,/update.*\(patch\)/i,/update.*\(major\)/i],_=H.some((Z)=>Z.test(Q)),z=H.some((Z)=>Z.test(K));if(_&&z){let Z=X.includes("(major)")||X.includes("major update"),E=W.includes("(major)")||W.includes("major update");return Z===E}if(W.includes("update dependency ")){let Z=K.match(/update dependency (\S+)/i),E=Q.match(/update dependency (\S+)/i);if(Z&&E)return Z[1]===E[1]}if(_!==z)return!1;if(X.includes("dependency ")&&W.includes("dependency "))return!1;return!1}checkIfUpdatesMatch(Q,K){if(!Q)return!1;let X=/([\w@\-./]+):\s*(\d+\.\d+\.\d\S*)\s*\u2192\s*(\d+\.\d+\.\d\S*)/g,W=new Map,O;while((O=X.exec(Q))!==null){let[,Y,$,q]=O;W.set(Y,{from:$,to:q})}for(let Y of K){let $=W.get(Y.name);if(!$||$.to!==Y.newVersion)return!1}return W.size===K.length}generatePRLabels(Q){let K=new Set;K.add("dependencies");let X=Q.updates.map(($)=>$.updateType),W={major:X.includes("major"),minor:X.includes("minor"),patch:X.includes("patch")};if(W.major)K.add("major");if(W.minor)K.add("minor");if(W.patch)K.add("patch");if(Q.updates.length>5)K.add("dependencies");let O=["helmet","express-rate-limit","cors","bcrypt","jsonwebtoken"];if(Q.updates.some(($)=>O.some((q)=>$.name.includes(q))))K.add("security");if(this.config.pullRequest?.labels)this.config.pullRequest.labels.forEach(($)=>{if($!=="dependencies")K.add($)});return Array.from(K)}shouldAutoClosePR(Q,K){if(this.shouldAutoCloseForRespectLatest(Q))return!0;if(this.shouldAutoCloseForIgnorePaths(Q))return!0;if(this.shouldAutoCloseForRemovedFiles(Q))return!0;return!1}shouldAutoCloseForRespectLatest(Q){if(!(this.config.packages?.respectLatest??!0))return!1;let X=["latest","*","main","master","develop","dev"],W=Q.body.toLowerCase();if(!X.some((q)=>W.includes(q.toLowerCase())))return!1;return this.extractPackagesFromPRBody(Q.body).filter((q)=>{let H=new RegExp(`\\|\\s*\\[${q.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\]\\([^)]+\\)\\s*\\|\\s*([^|]+)\\s*\\|`,"i"),_=Q.body.match(H);if(!_){let j=new RegExp(`${q.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}[^\\w]*[:=]\\s*["']?([^"'
]+)["']?`,"i"),V=Q.body.match(j);if(!V)return!1;let M=V[1].toLowerCase().trim();return X.includes(M)}let Z=_[1].trim().match(/^([^\u2192]+)\u2192/);if(!Z)return!1;let E=Z[1].trim().toLowerCase();return X.includes(E)}).length>0}shouldAutoCloseForIgnorePaths(Q){let K=this.config.packages?.ignorePaths;if(!K||K.length===0)return!1;let X=this.extractFilePathsFromPRBody(Q.body);if(X.length===0)return!1;let{Glob:W}=globalThis.Bun,O=X.filter((Y)=>{let $=Y.replace(/^\.\//,"");return K.some((q)=>{try{return new W(q).match($)}catch(H){return this.logger.debug(`Failed to match path ${$} against pattern ${q}: ${H}`),!1}})});if(O.length>0)return this.logger.debug(`PR #${Q.number} contains files now in ignorePaths: ${O.join(", ")}`),!0;return!1}shouldAutoCloseForRemovedFiles(Q){try{let K=this.extractFilePathsFromPRBody(Q.body);if(K.length===0)return!1;let X=A("fs"),W=A("path"),O=K.filter((Y)=>{let $=W.join(this.projectPath,Y);return!X.existsSync($)});if(O.length>0){if(this.logger.info(`PR #${Q.number} references removed files: ${O.join(", ")}`),this.config.packages?.ignorePaths&&this.config.packages.ignorePaths.length>0){let{Glob:z}=globalThis.Bun;if(O.filter((E)=>{return!this.config.packages.ignorePaths.some((j)=>{try{return new z(j).match(E)}catch(V){return this.logger.warn(`Invalid glob pattern '${j}':`,V),!1}})}).length>0)return this.logger.info(`Some removed files are outside ignored paths - not auto-closing PR #${Q.number}`),!1}if(O.some((z)=>z.endsWith("composer.json")))return this.logger.info(`composer.json was removed - PR #${Q.number} should be auto-closed`),!0;let $=Q.body.toLowerCase(),q=$.includes("composer")||O.some((z)=>z.includes("composer")),H=$.includes("package.json")||O.some((z)=>z.includes("package.json")),_=O.some((z)=>z.endsWith("deps.yaml")||z.endsWith("deps.yml")||z.endsWith("dependencies.yaml")||z.endsWith("dependencies.yml"));if(q||H||_)return this.logger.info(`PR #${Q.number} is about removed dependency system - should be auto-closed`),!0}return!1}catch(K){return this.logger.debug(`Failed to check for removed files in PR #${Q.number}: ${K}`),!1}}extractFilePathsFromPRBody(Q){let K=[],X=/\|\s*\[[^\]]+\]\([^)]*\)\s*\|[^|]*\|\s*\*\*([^*]+)\*\*\s*\|/g,W;while((W=X.exec(Q))!==null){let q=W[1].trim();if(q&&!K.includes(q))K.push(q)}let O=/\*\*([^*]+\.(?:json|yaml|yml|lock))\*\*/g;while((W=O.exec(Q))!==null){let q=W[1].trim();if(q&&!K.includes(q))K.push(q)}let Y=/\|[^|]+\|[^|]+\|([^|]+)\|[^|]*\|/g;while((W=Y.exec(Q))!==null){let q=W[1].trim();if(q&&(q.includes("/")||/\.(?:json|yaml|yml|lock)$/.test(q))&&!K.includes(q))K.push(q)}let $=/(?:^|\s)([\w-]+(?:\/[\w.-]+)*\/[\w.-]+\.(?:json|yaml|yml|lock))(?:\s|$)/gm;while((W=$.exec(Q))!==null){let q=W[1].trim();if(q&&!K.includes(q))K.push(q)}return K}extractPackagesFromPRBody(Q){let K=[],X=Q.match(/\|[^|]*\|[^|]*\|[^|]*\|[^|]*\|/g);if(X)for(let O of X){let Y=O.match(/\[([^\]]+)\]\([^)]*\)/);if(Y)K.push(Y[1])}let W=Q.match(/<summary>([^<]+)<\/summary>/g);if(W)for(let O of W){let Y=O.replace(/<summary>/,"").replace(/<\/summary>/,"").trim();if(Y&&!K.includes(Y))K.push(Y)}return K}extractPackageUpdatesFromPRBody(Q){let K=[],X=/\|\s*\[([^\]]+)\][^|]*\|\s*\[?`\^?([^`]+)`\s*->\s*`\^?([^`]+)`\]?/g,W;while((W=X.exec(Q))!==null){let[,O,Y,$]=W;K.push({name:O,currentVersion:Y,newVersion:$})}return K}getConfig(){return this.config}getProjectPath(){return this.projectPath}async checkAndCloseObsoletePRs(Q,K=!1){try{this.logger.info("\uD83D\uDD0D Scanning for obsolete PRs due to removed dependency files...");let W=(await Q.getPullRequests("open")).filter((Y)=>Y.head.startsWith("buddy-bot/")||Y.author==="github-actions[bot]"||Y.labels.includes("dependencies")||Y.labels.includes("dependency")||Y.title.toLowerCase().includes("update")||Y.title.toLowerCase().includes("chore(deps)")||Y.title.toLowerCase().includes("composer"));this.logger.info(`Found ${W.length} dependency-related PRs to check`);let O=0;for(let Y of W)try{if(this.shouldAutoCloseForRemovedFiles(Y))if(this.logger.info(`\uD83D\uDD12 PR #${Y.number} should be auto-closed: ${Y.title}`),K)this.logger.info(`\uD83D\uDD0D [DRY RUN] Would auto-close PR #${Y.number}`),O++;else try{let q=this.generateCloseReason(Y);try{await Q.createComment(Y.number,q)}catch(H){this.logger.warn(`\u26A0\uFE0F Could not add close reason comment to PR #${Y.number}:`,H)}if(await Q.closePullRequest(Y.number),Y.head.startsWith("buddy-bot/"))try{await Q.deleteBranch(Y.head),this.logger.success(`\u2705 Auto-closed PR #${Y.number} and deleted branch ${Y.head}`)}catch(H){this.logger.warn(`\u26A0\uFE0F Auto-closed PR #${Y.number} but failed to delete branch: ${H}`)}else this.logger.success(`\u2705 Auto-closed PR #${Y.number}`);O++}catch(q){this.logger.error(`\u274C Failed to auto-close PR #${Y.number}:`,q)}}catch($){this.logger.warn(`\u26A0\uFE0F Error checking PR #${Y.number}:`,$)}if(O>0)this.logger.success(`\u2705 ${K?"Would auto-close":"Auto-closed"} ${O} obsolete PR(s)`);else this.logger.info("\uD83D\uDCCB No obsolete PRs found")}catch(X){throw this.logger.error("Failed to check for obsolete PRs:",X),X}}async checkAndCloseSatisfiedPRs(Q,K=!1){try{this.logger.info("\uD83D\uDD0D Checking for PRs where dependencies are already at target version...");let W=(await Q.getPullRequests("open")).filter((q)=>q.head.startsWith("buddy-bot/")||q.author==="github-actions[bot]"||q.labels.includes("dependencies")||q.labels.includes("dependency"));this.logger.info(`Found ${W.length} dependency PRs to validate`);let O=0,Y=await this.scanForUpdates(),$=new Map;for(let q of Y.updates)$.set(q.name,q);for(let q of W)try{let H=this.extractPackageUpdatesFromPRBody(q.body);if(H.length===0){this.logger.debug(`PR #${q.number}: Could not extract package updates, skipping`);continue}if(H.every((z)=>{let Z=$.get(z.name);if(!Z)return this.logger.debug(`PR #${q.number}: ${z.name} not in current scan (satisfied - no longer needs direct update)`),!0;if(Z.newVersion===z.newVersion)return this.logger.debug(`PR #${q.number}: ${z.name} still needs update to ${z.newVersion}`),!1;try{if(!this.isNewerVersion(Z.currentVersion,z.newVersion))return this.logger.debug(`PR #${q.number}: ${z.name} already at or beyond ${z.newVersion}`),!0}catch{return!1}return!1}))if(this.logger.info(`\u2705 PR #${q.number} is satisfied (dependencies at target version): ${q.title}`),K)this.logger.info(`\uD83D\uDD0D [DRY RUN] Would close PR #${q.number}`),O++;else try{let z=H.filter((j)=>!$.has(j.name)),Z=H.filter((j)=>{let V=$.get(j.name);if(!V)return!1;try{return!this.isNewerVersion(V.currentVersion,j.newVersion)}catch{return!1}}),E=`\uD83E\uDD16 **Auto-closing satisfied PR**

`;if(z.length>0)E+=`This PR was automatically closed because the following packages are no longer direct dependencies (possibly moved to peer dependencies, transitive dependencies, or removed):

`,z.forEach((j)=>{E+=`- **${j.name}**: ${j.currentVersion} \u2192 ${j.newVersion}
`}),E+=`
`;if(Z.length>0)E+=`The following packages are already at the target version or newer:

`,Z.forEach((j)=>{E+=`- **${j.name}**: ${j.currentVersion} \u2192 ${j.newVersion}
`}),E+=`
`;E+="If this was closed in error, please reopen and add a comment explaining why.";try{await Q.createComment(q.number,E)}catch(j){this.logger.warn(`\u26A0\uFE0F Could not add comment to PR #${q.number}:`,j)}if(await Q.closePullRequest(q.number),q.head.startsWith("buddy-bot/"))try{await Q.deleteBranch(q.head),this.logger.success(`\u2705 Closed PR #${q.number} and deleted branch ${q.head}`)}catch(j){this.logger.warn(`\u26A0\uFE0F Closed PR #${q.number} but failed to delete branch: ${j}`)}else this.logger.success(`\u2705 Closed PR #${q.number}`);O++}catch(z){this.logger.error(`\u274C Failed to close PR #${q.number}:`,z)}}catch(H){this.logger.warn(`\u26A0\uFE0F Error validating PR #${q.number}:`,H)}if(O>0)this.logger.success(`\u2705 ${K?"Would close":"Closed"} ${O} satisfied PR(s)`);else this.logger.info("\uD83D\uDCCB No satisfied PRs found")}catch(X){throw this.logger.error("Failed to check for satisfied PRs:",X),X}}generateCloseReason(Q){let X=this.extractFilePathsFromPRBody(Q.body).filter((q)=>{let H=A("fs"),z=A("path").join(this.projectPath,q);return!H.existsSync(z)}),W=X.some((q)=>q.includes("composer")),O=X.some((q)=>q.includes("package.json")),Y=X.some((q)=>q.endsWith("deps.yaml")||q.endsWith("deps.yml")||q.endsWith("dependencies.yaml")||q.endsWith("dependencies.yml")),$=`\uD83E\uDD16 **Auto-closing obsolete PR**

`;if(W)$+="This PR was automatically closed because `composer.json` has been removed from the project, indicating that Composer is no longer used for dependency management.\n\n";else if(O)$+="This PR was automatically closed because `package.json` has been removed from the project, indicating that npm/yarn/pnpm is no longer used for dependency management.\n\n";else if(Y)$+=`This PR was automatically closed because the dependency files it references have been removed from the project.

`;else $+=`This PR was automatically closed because the dependency files it references are no longer present in the project.

`;if(X.length>0)$+=`**Removed files:**
${X.map((q)=>`- \`${q}\``).join(`
`)}

`;return $+="If this was closed in error, please reopen the PR and update the dependency files accordingly.",$}async createOrUpdateDashboard(){try{if(this.logger.info("Creating or updating dependency dashboard..."),!this.config.repository)throw Error("Repository configuration is required for dashboard");if(this.config.repository.provider!=="github")throw Error("Dashboard is currently only supported for GitHub repositories");if(!this.config.repository.owner||!this.config.repository.name)throw Error("Repository owner and name are required for dashboard. Set them in buddy-bot.config.ts or ensure GITHUB_REPOSITORY env var is available.");let Q=this.config.repository.token||b.env.GITHUB_TOKEN||b.env.BUDDY_BOT_TOKEN||"",K=!!b.env.BUDDY_BOT_TOKEN,X=new l(Q,this.config.repository.owner,this.config.repository.name,K),W=await this.collectDashboardData(X),O=this.config.dashboard||{},{title:Y,body:$}=this.dashboardGenerator.generateDashboard(W,{showOpenPRs:O.showOpenPRs??!0,showDetectedDependencies:O.showDetectedDependencies??!0,showDeprecatedDependencies:O.showDeprecatedDependencies??!0,bodyTemplate:O.bodyTemplate}),q=await this.findExistingDashboard(X,O.issueNumber),H;if(q)this.logger.info(`Updating existing dashboard issue #${q.number}`),H=await X.updateIssue(q.number,{title:O.title||Y,body:$,labels:O.labels||["dependencies","dashboard"],assignees:O.assignees}),this.logger.success(`\u2705 Successfully updated dashboard issue #${H.number}`);else{this.logger.info("Creating new dashboard issue"),this.logger.info("Performing final check for existing dashboards before creation...");let _=await this.findExistingDashboard(X,O.issueNumber);if(_)this.logger.info(`Race condition detected! Found existing dashboard #${_.number} during final check`),H=await X.updateIssue(_.number,{title:O.title||Y,body:$,labels:O.labels||["dependencies","dashboard"],assignees:O.assignees}),this.logger.success(`\u2705 Updated existing dashboard issue #${H.number} (race condition avoided)`);else H=await X.createIssue({title:O.title||Y,body:$,labels:O.labels||["dependencies","dashboard"],assignees:O.assignees}),this.logger.success(`\u2705 Successfully created new dashboard issue #${H.number}`)}return this.logger.success(`\u2705 Dashboard updated: ${H.url}`),H}catch(Q){throw this.logger.error("Failed to create or update dashboard:",Q),Q}}async collectDashboardData(Q){let[K,X]=await Promise.all([this.scanner.scanProject(),Q.getPullRequests("open")]),W=X.filter((_)=>_.labels.includes("dependencies")||_.labels.includes("dependency")||_.labels.includes("deps")||_.title.toLowerCase().includes("update")||_.title.toLowerCase().includes("chore(deps)")||_.title.toLowerCase().includes("bump")||_.title.toLowerCase().includes("upgrade")||_.title.toLowerCase().includes("renovate")||_.head.includes("renovate/")||_.head.includes("dependabot/")||_.head.includes("buddy-bot/")||_.head.includes("update-")||_.head.includes("bump-")),O=K.filter((_)=>_.type==="package.json"),Y=K.filter((_)=>_.path.includes(".github/workflows/")&&(_.path.endsWith(".yml")||_.path.endsWith(".yaml"))),$=K.filter((_)=>!_.path.includes(".github/workflows/")&&_.type!=="package.json"),H=await new c().checkDeprecatedDependencies(K);return{openPRs:W,detectedDependencies:{packageJson:O,dependencyFiles:$,githubActions:Y},deprecatedDependencies:H,repository:{owner:this.config.repository.owner,name:this.config.repository.name,provider:this.config.repository.provider},lastUpdated:new Date}}async findExistingDashboard(Q,K){try{if(this.logger.info("Searching for existing dashboard issue..."),K){this.logger.info(`Looking for specific dashboard issue #${K}`);let q=(await Q.getIssues("open")).find((H)=>H.number===K);if(q)return this.logger.info(`Found specified dashboard issue #${q.number}: ${q.title}`),q;else return this.logger.warn(`Specified dashboard issue #${K} not found`),null}let X=await Q.getIssues("open");this.logger.info(`Found ${X.length} open issues to search through`);for(let $ of X){let q=$.labels.includes("dashboard")&&$.labels.includes("dependencies"),H=$.title.toLowerCase().includes("dependency dashboard"),_=$.body.includes("This issue lists Buddy Bot updates and detected dependencies");if(q&&(H||_))return this.logger.info(`Found existing dashboard issue #${$.number}: ${$.title}`),this.logger.info(`  - Labels: ${$.labels.join(", ")}`),this.logger.info(`  - Title matches: ${H}`),this.logger.info(`  - Body has marker: ${_}`),$}let W=X.filter(($)=>$.labels.includes("dashboard")),O=X.filter(($)=>$.labels.includes("dependencies")),Y=X.filter(($)=>$.title.toLowerCase().includes("dependency dashboard"));if(this.logger.info("Dashboard search results:"),this.logger.info(`  - Issues with 'dashboard' label: ${W.length}`),this.logger.info(`  - Issues with 'dependencies' label: ${O.length}`),this.logger.info(`  - Issues with 'dependency dashboard' in title: ${Y.length}`),W.length>0){this.logger.info("Issues with 'dashboard' label:");for(let $ of W)this.logger.info(`  - #${$.number}: ${$.title} (labels: ${$.labels.join(", ")})`)}return this.logger.info("No existing dashboard issue found"),null}catch(X){return this.logger.warn(`Failed to search for existing dashboard: ${X}`),null}}}
export{g as c,x as d,jK as e};

//# debugId=2DB312290295C57564756E2164756E21
