pastoralist
Version:
A tool to watch over node module resolutions and overrides
70 lines (63 loc) • 34.5 kB
JavaScript
import{$ as tt,E as P,I as V,J as q,Z as De,_ as Ee,aa as qe,b as _e,ba as Me,c as O,d as we,da as Ve,e as Je,f as m,fa as D,g as Be,h as $e,i as ge,j as N,k as Oe,l as Qe,m as Xe,n as Ze,o as se,p as oe,q as ae,r as ue,s as x,t as xe,u as Ae,v as y,w as et}from"./index-d8dv2kv3.js";import{existsSync as xr,readFileSync as Ar}from"fs";import{dirname as Dr,resolve as nt}from"path";import{fileURLToPath as Vr}from"url";var j=[{flags:["-h","--help"],hasValue:!1},{flags:["-v","--version"],hasValue:!1},{flags:["--debug"],hasValue:!1},{flags:["--dry-run"],hasValue:!1},{flags:["--outputFormat"],hasValue:!0,defaultValue:"text"},{flags:["-p","--path"],hasValue:!0,defaultValue:"package.json"},{flags:["-d","--depPaths"],hasValue:!0,isArray:!0},{flags:["--ignore"],hasValue:!0,isArray:!0},{flags:["-r","--root"],hasValue:!0},{flags:["-t","--isTestingCLI"],hasValue:!1},{flags:["--isTesting"],hasValue:!1},{flags:["--init"],hasValue:!1},{flags:["--checkSecurity"],hasValue:!1},{flags:["--forceSecurityRefactor"],hasValue:!1},{flags:["--securityProvider"],hasValue:!0,isArray:!0},{flags:["--securityProviderToken"],hasValue:!0},{flags:["--interactive"],hasValue:!1},{flags:["--hasWorkspaceSecurityChecks"],hasValue:!1},{flags:["--promptForReasons"],hasValue:!1},{flags:["--strict"],hasValue:!1},{flags:["--summary"],hasValue:!1},{flags:["-q","--quiet"],hasValue:!1},{flags:["--setup-hook"],hasValue:!1},{flags:["--remove-unused"],hasValue:!1},{flags:["--cache-dir"],hasValue:!0},{flags:["--cache-ttl"],hasValue:!0},{flags:["--no-cache"],hasValue:!1},{flags:["--refresh-cache"],hasValue:!1}],X=`
Pastoralist - A utility CLI to manage your dependency overrides
Usage: pastoralist [command] [options]
Commands:
init Initialize Pastoralist configuration interactively
Options:
-v, --version Print the installed Pastoralist version
--debug Enable debug mode
--dry-run Preview changes without writing to package.json
--outputFormat <format> Output format: text (default) or json
-p, --path <path> Specifies a path to a package.json (default: "package.json")
-d, --depPaths [paths...] Specifies glob paths to package.jsons
--ignore [paths...] Specifies glob paths to ignore
-r, --root <root> Specifies a root path
-t, --isTestingCLI Enable CLI testing (no scripts run)
--isTesting Enable testing mode (no scripts run)
--init Initialize Pastoralist configuration interactively
--checkSecurity Check for security vulnerabilities and generate overrides
--forceSecurityRefactor Automatically apply security overrides without prompting
--securityProvider <provider...> Security provider(s) to use (osv, github, snyk, npm, socket, spektion)
--securityProviderToken <token> Security provider token for API access
--interactive Run security checks in interactive mode
--hasWorkspaceSecurityChecks Include workspace packages in security scan
--promptForReasons Prompt for reasons when adding manual overrides
--strict Fail on any security check errors (network failures, API errors)
--summary Show summary metrics table after run
-q, --quiet Quiet mode for CI (exit 1 if vulnerabilities, 0 if clean)
--setup-hook Add postinstall script to run pastoralist automatically
--remove-unused Remove unused overrides from package.json
--cache-dir <path> Cache directory (default: node_modules/.cache/pastoralist/)
--cache-ttl <seconds> Override cache TTL in seconds
--no-cache Bypass cache reads and writes
--refresh-cache Bypass cache reads, force refresh (still writes)
`,Z=2;var ot=(e)=>j.find((t)=>t.flags.includes(e)),ee=(e)=>{return(e.flags.find((i)=>i.startsWith("--"))||e.flags[0]).replace(/^--?/,"").replace(/-([a-z])/g,(i,r)=>r.toUpperCase())},at=(e)=>{let t=e.indexOf("=");if(t>-1)return{flag:e.slice(0,t),value:e.slice(t+1)};return{flag:e}},U=(e)=>e.startsWith("-"),ut=(e,t)=>{let i=e.slice(t+1),r=i.findIndex(U);if(r===-1)return i;return i.slice(0,r)},ct=(e,t)=>{let i=ut(e,t);if(i.length>0)return{value:i,consumed:i.length};return{value:void 0,consumed:0}},lt=(e,t)=>{let i=e[t+1];if(i&&!U(i))return{value:i,consumed:1};return{value:!0,consumed:0}},dt=(e,t,i)=>i.isArray?ct(e,t):lt(e,t),ft=(e)=>j.reduce((t,i)=>{let r=ee(i);if(t[r]===void 0&&i.defaultValue!==void 0)return Object.assign({},t,{[r]:i.defaultValue});return t},e),b=(e,t,i=t.options,r=t.command)=>({nextIndex:e,options:i,command:r}),F=(e,t,i)=>Object.assign({},e.options,{[t]:i}),yt=(e,t,i)=>b(t+1,i,i.options,e),pt=(e,t,i,r)=>b(i+1,r,F(r,e,t)),mt=(e,t,i)=>b(t+1,i,F(i,e,!0)),vt=(e,t,i,r,n)=>{let{value:s,consumed:o}=dt(e,t,n),a=t+o+1;return b(a,i,F(i,r,s))},ht=(e,t,i)=>{let r=e[t];if(!U(r))return yt(r,t,i);let{flag:n,value:s}=at(r),o=ot(n);if(!o)throw Error(`Unknown option: ${n}`);let a=ee(o);if(s!==void 0)return pt(a,s,t,i);if(!o.hasValue)return mt(a,t,i);return vt(e,t,i,a,o)},te=(e,t,i)=>{if(t>=e.length)return i;let r=ht(e,t,i),n={options:r.options,command:r.command};return te(e,r.nextIndex,n)},ie=(e)=>{let t=e.slice(Z),r=te(t,0,{options:{},command:void 0}),n=ft(r.options);return{command:r.command,options:n}},w=()=>{console.log(X)};import{existsSync as Ot,writeFileSync as Ie}from"fs";import{resolve as xt}from"path";import*as ce from"readline";var H=[],$=0,W=!1,re=!1,k=[],Pt=()=>{W=!0;let e=k;k=[],e.forEach((t)=>t())},Rt=()=>{if(W)return Promise.resolve();return new Promise((e)=>{k=k.concat(e)})};function Ct(){if(re||process.stdin.isTTY)return;re=!0;let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",(i)=>{t+=i}),process.stdin.on("end",()=>{H=t.trim().split(`
`),Pt()})}function ne(){return!process.stdin.isTTY}async function bt(){if(!ne())return;Ct(),await Rt()}function kt(){if(!ne()||!W)return null;if($<H.length){let t=H[$];return $+=1,t}return""}async function S(e,t,i=(r)=>r.trim()){return await bt(),new Promise((r)=>{let n=kt();if(n!==null)console.log(`${t}${n}`),r(i(n));else e.question(t,(s)=>{r(i(s))})})}class le{rl;constructor(){this.rl=ce.createInterface({input:process.stdin,output:process.stdout})}close(){this.rl.close()}ensureCookedMode(){if(process.stdin.isTTY)process.stdin.setRawMode(!1)}async input(e,t){return this.ensureCookedMode(),S(this.rl,ue(e,t),(i)=>i.trim()||t||"")}async confirm(e,t=!0){return this.ensureCookedMode(),S(this.rl,se(e,t),(i)=>{let r=i.trim().toLowerCase();if(r==="")return t;if(r==="y")return!0;return r==="yes"})}async list(e,t){return console.log(oe(e,t)),this.ensureCookedMode(),S(this.rl,ae(),(i)=>{let r=parseInt(i.trim(),10),n=r<1,s=r>t.length;if(isNaN(r)||n||s)return console.log("Invalid choice. Please enter a number between 1 and "+t.length),t[0].value;return t[r-1].value})}async prompt(e){let{type:t="input",message:i}=e;switch(t){case"confirm":return this.confirm(i,e.default??!0);case"list":return this.list(i,e.choices);case"input":default:return this.input(i,e.default??"")}}async promptMany(e){return e.reduce(async(t,i,r)=>{let n=await t,s=`answer${r}`,o=i.type==="confirm",a=i.type==="list";if(o)n[s]=await this.prompt(i);else if(a)n[s]=await this.prompt(i);else n[s]=await this.prompt(i);return n},Promise.resolve({}))}}async function de(e){let t=new le;try{return await e(t)}finally{t.close()}}import{isAbsolute as St,resolve as gt}from"path";var p=(e,t)=>{if(t&&!St(e))return gt(t,e);return e};var fe=[{name:"In package.json (recommended for simple setups)",value:"package.json"},{name:"In a separate config file (recommended for complex setups)",value:"external"}],ye=[{name:".pastoralistrc.json (JSON format)",value:".pastoralistrc.json"},{name:"pastoralist.config.cjs (CommonJS module)",value:"pastoralist.config.cjs"},{name:"pastoralist.config.js (JavaScript module)",value:"pastoralist.config.js"},{name:"pastoralist.config.mjs (ESM module)",value:"pastoralist.config.mjs"}],pe=[{name:'Use "workspace" keyword (auto-detect from package.json)',value:"workspace"},{name:"Specify custom paths",value:"custom"}],me=[{name:"OSV (Open Source Vulnerabilities - free, recommended)",value:"osv"},{name:"GitHub Advisory Database",value:"github"},{name:"Snyk (requires token)",value:"snyk"},{name:"Socket.dev (requires token)",value:"socket"}],ve=[{name:"Low (all vulnerabilities)",value:"low"},{name:"Medium (medium and above)",value:"medium"},{name:"High (high and critical only)",value:"high"},{name:"Critical (critical only)",value:"critical"}],he="packages/*/package.json",g={default:"initialization wizard",security:"security configuration wizard",workspace:"workspace configuration wizard"},Pe={required:!1,optional:!1},Re={github:{required:!1,optional:!0,envVar:"GITHUB_TOKEN",createUrl:"https://github.com/settings/tokens/new?description=Pastoralist%20Security&scopes=repo",scopes:["repo"]},snyk:{required:!0,optional:!1,envVar:"SNYK_TOKEN",createUrl:"https://app.snyk.io/account"},socket:{required:!0,optional:!1,envVar:"SOCKET_SECURITY_API_KEY",createUrl:"https://socket.dev/dashboard/settings"}},u={welcome:"This wizard will help you set up your Pastoralist configuration.",skipInfo:"You can skip any step by selecting the skip option.",existingConfigWarning:"Existing Pastoralist configuration detected. Do you want to overwrite it?",existingFileWarning:(e)=>`${e} already exists. Overwrite?`,configNotSaved:"Configuration not saved. File preserved.",configSaved:(e)=>`Configuration saved to ${e}`,initCancelled:"Initialization cancelled. Your existing configuration is preserved.",initComplete:"▪▫▪ Pastoralist initialization complete! ▪▫▪",packageJsonNotFound:"Error: package.json not found",tokenEnvironmentInfo:(e)=>`Pastoralist reads this token from ${e} or --securityProviderToken. The init wizard will not write tokens to project config.`,tokenCreationInfo:(e,t)=>`To create a ${e} token, visit: ${t}`,tokenRequiredWarning:(e)=>`${e} requires a token to function. Security scanning will not work without it.`,workspacesDetected:(e)=>`Detected workspaces in package.json: ${e.join(", ")}`,noWorkspacesDetected:"No workspaces detected in package.json.",savingConfig:"Saving configuration...",nextSteps:"Next Steps:"},Ce={configLocation:"Step 1: Configuration Location",workspace:"Step 2: Workspace Configuration",security:"Step 3: Security Configuration"},l={configLocation:"Where would you like to store your Pastoralist configuration?",configFormat:"Choose a config file format:",setupWorkspaces:"Do you want to configure workspace dependencies?",workspaceType:"How would you like to configure workspace dependencies?",customWorkspacePaths:"Enter workspace paths (comma-separated glob patterns)",setupSecurity:"Do you want to enable security vulnerability scanning?",securityProvider:"Choose a security provider:",hasToken:(e)=>`Have you configured a ${e} API token in your environment?`,securityInteractive:"Enable interactive mode for security fixes? (allows you to review/approve each fix)",securityAutoFix:"Enable auto-fix mode? (automatically applies security overrides without prompting)",severityThreshold:"What severity level should trigger alerts?",hasWorkspaceSecurityChecks:"Scan workspace packages for vulnerabilities?"};function be(e){return e.split(",").map((t)=>t.trim()).filter((t)=>t.length>0)}function ke(e){let t={};if(e.setupWorkspaces){if(e.workspaceType==="workspace")t.depPaths="workspace";if(e.workspaceType==="custom"&&e.customWorkspacePaths?.length)t.depPaths=e.customWorkspacePaths}if(e.setupSecurity)t.checkSecurity=!0,t.security={enabled:!0,provider:e.securityProvider,interactive:e.securityInteractive,autoFix:e.securityAutoFix,severityThreshold:e.severityThreshold,hasWorkspaceSecurityChecks:e.hasWorkspaceSecurityChecks};return t}function Se(e,t){if(t.endsWith(".json"))return JSON.stringify(e,null,2)+`
`;if(t.endsWith(".js")||t.endsWith(".cjs"))return`module.exports = ${JSON.stringify(e,null,2)};
`;return`export default ${JSON.stringify(e,null,2)};
`}async function At(e,t,i){if(i.print(x(1,"Configuration Location")),t.configLocation=await e.list(l.configLocation,fe),t.configLocation==="external")t.configFormat=await e.list(l.configFormat,ye)}async function Dt(e,t){if(t.workspaceType!=="custom")return;t.customWorkspacePaths=await Ut(e)}async function Ne(e,t,i,r){if(r.print(x(2,"Workspace Configuration")),t.setupWorkspaces=await e.confirm(l.setupWorkspaces,!0),!t.setupWorkspaces)return;let n=Jt(i),s=n.length>0;Bt(s,r),t.workspaceType=await $t(e,s,n,r),await Dt(e,t)}async function Vt(e,t,i){if(i.print(x(3,"Security Configuration")),t.setupSecurity=await e.confirm(l.setupSecurity,!0),!t.setupSecurity)return;await Te(e,t,i,{askWorkspaceSecurity:t.setupWorkspaces,selectProvider:!0})}async function It(e,t,i){i.print(`
${Ce.security}`),t.setupSecurity=!0;let r=t.setupWorkspaces&&!t.hasWorkspaceSecurityChecks,n=!t.securityProvider;await Te(e,t,i,{askWorkspaceSecurity:r,selectProvider:n})}async function Te(e,t,i,r){await Nt(e,t,i,r.selectProvider),await Tt(e,t),t.severityThreshold=await wt(e),await jt(e,t,r.askWorkspaceSecurity)}async function Nt(e,t,i,r){if(r)t.securityProvider=await Ft(e);if(t.securityProvider)await Ht(e,t.securityProvider,i)}async function Tt(e,t){if(t.securityInteractive=await e.confirm(l.securityInteractive,!0),t.securityInteractive)return;t.securityAutoFix=await e.confirm(l.securityAutoFix,!1)}async function jt(e,t,i){if(!i)return;t.hasWorkspaceSecurityChecks=await e.confirm(l.hasWorkspaceSecurityChecks,!0)}async function Ut(e){let t=await e.input(l.customWorkspacePaths,he);return be(t)}async function Ft(e){return await e.list(l.securityProvider,me)}async function wt(e){return await e.list(l.severityThreshold,ve)}async function $t(e,t,i,r){if(!t)return"custom";return r.print(`
${u.workspacesDetected(i)}`),await e.list(l.workspaceType,pe)}async function Ht(e,t,i){let r=Lt(t);if(!r.required&&!r.optional)return;if(Wt(t,r,i),!await e.confirm(l.hasToken(t),!1)&&r.required)i.print(`
${u.tokenRequiredWarning(t)}`)}function Wt(e,t,i){if(t.createUrl)i.print(`
${u.tokenCreationInfo(e,t.createUrl)}`);if(t.envVar)i.print(`
${u.tokenEnvironmentInfo(t.envVar)}`)}function Lt(e){return Re[e]??Pe}function Jt(e){return De(e?.workspaces)}function Bt(e,t){if(e)return;t.print(xe(u.noWorkspacesDetected))}async function Et(e,t,i,r,n=!1){if(!i){r.print(u.packageJsonNotFound);return}if(i.pastoralist=e,!n)Ie(t,JSON.stringify(i,null,2)+`
`);r.print(u.configSaved(t))}async function qt(e,t,i,r,n,s=!1){let o=xt(i,t);if(!await Mt(t,o,r,n))return;zt(e,t,o,s),n.print(u.configSaved(o))}async function Mt(e,t,i,r){if(!Ot(t))return!0;let n=await i.confirm(u.existingFileWarning(e),!1);if(!n)r.print(`
${u.configNotSaved}`);return n}function zt(e,t,i,r){if(r)return;Ie(i,Se(e,t))}function Yt(e,t){let i=`Run ${m("pastoralist")} to check and update your dependencies`,r="Check the documentation for advanced configuration options",n=`Run ${m("pastoralist --checkSecurity")} to scan for security vulnerabilities`,s=e?[i,n,"Check the documentation for advanced configuration options"]:[i,"Check the documentation for advanced configuration options"],o="Pastoralist initialization complete!",a=Oe("Pastoralist initialization complete!",0)+` ${O}`;t.print(Ae("Pastoralist initialization complete!",s,a))}async function Kt(e,t,i){let r=await Ve(t,!1),n=P(i);if(!(r||n?.pastoralist))return!0;return e.confirm(u.existingConfigWarning,!1)}async function A(e={}){let t=y({file:"init/index.ts",isLogging:!0}),i=Zt(e);ri(i,t),await de(async(r)=>{await Gt(r,e,i,t)})}async function Gt(e,t,i,r){if(!await Kt(e,i.root,i.path)){r.print(`
${u.initCancelled}`);return}let s=P(i.path),o=ei(t,i);await _t(e,o,s,i,r),await Xt(e,t,i,o,s,r),Yt(o.setupSecurity,r)}async function _t(e,t,i,r,n){if(await At(e,t,n),!r.hasFocusedContext){await Ne(e,t,i,n),await Vt(e,t,n);return}await Qt(e,t,i,r,n)}async function Qt(e,t,i,r,n){if(r.hasWorkspaceContext)await Ne(e,t,i,n);if(r.hasSecurityContext)await It(e,t,n)}async function Xt(e,t,i,r,n,s){let o=ke(r);if(s.print(`
${u.savingConfig}
`),r.configLocation==="package.json")await Et(o,i.path,n,s,t.isTesting);if(r.configLocation==="external"){let c=r.configFormat;if(!c)return;await qt(o,c,i.root,e,s,t.isTesting)}}function Zt(e){let t=!!(e.checkSecurity||e.securityProvider),i=!!e.hasWorkspaceSecurityChecks,r=e.root||process.cwd(),n=p(e.path||"package.json",r);return{hasSecurityContext:t,hasWorkspaceContext:i,hasFocusedContext:t||i,root:r,path:n}}function ei(e,t){let i={configLocation:"package.json",setupSecurity:!1,setupWorkspaces:!1};return ti(i,e,t),ii(i,t),i}function ti(e,t,i){if(!i.hasSecurityContext)return;if(e.setupSecurity=!0,t.securityProvider)e.securityProvider=t.securityProvider}function ii(e,t){if(!t.hasWorkspaceContext)return;e.setupWorkspaces=!0,e.hasWorkspaceSecurityChecks=!0}function ri(e,t){let i=ni(e);if(t.print(`
${ge} ${i}
`),e.hasFocusedContext)return;t.print(`${u.welcome}
`),t.print(`${u.skipInfo}
`)}function ni(e){if(e.hasSecurityContext)return g.security;if(e.hasWorkspaceContext)return g.workspace;return g.default}import{dirname as si,resolve as oi}from"path";var ai=(e,t)=>{let i=t.resolveJSON(e);if(i)return i;throw Error(`Unable to load package.json at ${e}`)},ui=async(e,t,i,r)=>{let n=t.root||si(oi(e)),s=await(r.loadConfig??D)(n,i.pastoralist);return Object.assign({},i,s?{pastoralist:s}:void 0)},ci=(e)=>{let t=e.pastoralist??{},i=t.security;return{enabled:i?.enabled??t.checkSecurity,provider:i?.provider,autoFix:i?.autoFix,interactive:i?.interactive,securityProviderToken:i?.securityProviderToken,severityThreshold:i?.severityThreshold,excludePackages:i?.excludePackages,hasWorkspaceSecurityChecks:i?.hasWorkspaceSecurityChecks,strict:i?.strict,preferLatest:i?.preferLatest}},li=(e,t,i,r,n)=>{let s=ci(i),o=n.buildMergedOptions(e,t,s,s.provider),a=e.root?{root:e.root}:void 0;return Object.assign({},o,{config:i,path:r},a)},je=async(e,t,i)=>{let r=e.path||"package.json",n=p(r,e.root),s=ai(n,i),o=await ui(n,e,s,i),a=li(e,t,o,n,i);return{path:n,config:o,mergedOptions:a}};var Ue="osv",Fe=[{label:"Packages scanned",key:"total"},{label:"Appendix entries updated",key:"appendixEntriesUpdated"},{label:"Vulnerabilities blocked",key:"vulnerabilitiesBlocked"},{label:"Overrides added",key:"overridesAdded"},{label:"Overrides removed",key:"overridesRemoved"},{label:"By severity:",key:"severityHeader"},{label:" Critical",key:"severityCritical"},{label:" High",key:"severityHigh"},{label:" Medium",key:"severityMedium"},{label:" Low",key:"severityLow"},{label:"Write status",key:"writeStatus"}];var di=(e,t,i)=>({packageName:e,version:t,reason:i?.ledger?.reason,dependents:i?.dependents,patches:i?.patches,isSecurityFix:i?.ledger?.securityChecked,cves:i?.ledger?.cves,keep:i?.ledger?.keep,potentiallyFixedIn:i?.ledger?.potentiallyFixedIn}),fi=(e,t)=>{let i=t.finalOverrides[e];if(typeof i!=="string")return null;return{pkg:e,version:i}},yi=(e,t)=>{let i=`${e.pkg}@${e.version}`,r=t.finalAppendix[i];return di(e.pkg,e.version,r)},He=(e,t)=>{Object.keys(t.finalOverrides).map((i)=>fi(i,t)).filter((i)=>i!==null).map((i)=>yi(i,t)).forEach((i)=>e.override(i,!1))},R=(e)=>{if(e===1)return"";return"s"},pi=(e)=>{if(e===1)return"y";return"ies"},mi=(e)=>{let t=e.title||e.description||"Vulnerability";return{severity:e.severity||"unknown",packageName:e.packageName,currentVersion:e.currentVersion||"?",title:t,cves:e.cves,fixAvailable:e.fixAvailable,patchedVersion:e.patchedVersion,url:e.url}},vi=(e)=>({packageName:e.packageName,fromVersion:e.fromVersion||"?",toVersion:e.toVersion,cves:e.cves,severity:e.severity,reason:e.reason}),hi=(e,t)=>{if(e===0)return`No vulnerabilities in ${t} packages`;return`${e} vulnerabilit${pi(e)} found`},Pi=(e,t)=>e.length>0&&Boolean(t.forceSecurityRefactor||t.interactive),We=(e,t,i,r,n)=>{if(t.map(mi).forEach((s)=>{e.vulnerability(s,!1)}),e.endPhase(hi(t.length,n)),Pi(i,r))Ri(e,i)},Ri=(e,t)=>{e.startPhase("resolving","Fixes applied"),t.map(vi).forEach((r)=>{e.securityFix(r,!1)});let i=t.length;e.endPhase(`${i} override${R(i)} added`)},Ci=(e)=>{if(e===0)return"No overrides to update";return`${e} override${R(e)} applied`},bi=(e,t,i,r)=>{e.startPhase("writing","Updating overrides",r),He(e,{finalOverrides:t.finalOverrides??{},finalAppendix:t.finalAppendix??{}}),e.endPhase(Ci(i.overrideCount))},ki=(e,t)=>{if(t.length===0)return;e.startPhase("writing","Cleaned up stale overrides",!0),t.forEach((r)=>{e.removedOverride({packageName:r.packageName,version:r.version,reason:"Override no longer needed"},!1)});let i=t.length;e.endPhase(`${i} stale override${R(i)} removed`)},Si=(e,t,i,r)=>{let n=t.metrics;e.executiveSummary({vulnerabilitiesFixed:i.securityAlertCount||0,staleOverridesRemoved:n?.removedOverridePackages?.length??0,packagesProtected:r}),e.compactSummary({severityCritical:n?.severityCritical??0,severityHigh:n?.severityHigh??0,severityMedium:n?.severityMedium??0,severityLow:n?.severityLow??0,overridesTracked:n?.appendixEntriesUpdated??0,overridesRemoved:n?.overridesRemoved??0,packagesScanned:n?.packagesScanned??0}),e.complete("The herd is safe!",` ${we}`)},gi=(e,t)=>{if(t.updated)e.notice("Run an install to capture the updates!")},Oi=(e,t)=>{let i=t.skipRemovalKeys||[];if(i.length===0)return;let r=i.length;e.notice(`${r} override${R(r)} kept: still vulnerable at declared versions - ${i.join(", ")}`)},xi=(e,t,i)=>{let r=V(t.finalAppendix??{});if(!(r.length>0&&!i.removeUnused))return;let s=r.length;e.notice(`${s} unused override${R(s)} detected. Run with --remove-unused to clean up.`)},Ai=(e,t,i,r,n)=>{gi(e,i),Oi(e,r),xi(e,t,n)},Le=(e,t,i,r,n,s,o)=>{let a=t.metrics?.removedOverridePackages??[];bi(e,t,i,a.length===0),ki(e,a),Si(e,t,r,n),Ai(e,t,i,s,o)},Di=(e,t)=>{if(t==="total")return e.packagesScanned;if(t==="severityHeader")return"";if(t==="writeStatus"){if(e.writeSuccess)return"Success";return"Skipped"}let i=e[t];if(typeof i==="boolean")return i?1:0;return i},Vi=(e,t,i)=>{let n=(typeof t==="number"?t:0)>0;if(e==="severityCritical"&&n)return"red";if(e==="severityHigh"&&n)return"red";if(e==="severityMedium"&&n)return"yellow";if(e==="severityLow"&&n)return"gray";if(e==="vulnerabilitiesBlocked"&&n)return"green";if(e==="overridesAdded"&&n)return"cyan";if(e==="writeStatus"&&i.writeSuccess)return"green";if(e==="writeStatus")return"yellow";return},Ii=(e,t)=>{let i=Di(e,t.key),r=Vi(t.key,i,e);return{label:t.label,value:i,color:r}},L=(e)=>{let t=e.metrics;if(!t)return;let i=Fe.map((n)=>Ii(t,n)),r=$e(i,{title:`${O} Pastoralist Summary`});console.log(`
`+r)};var I=()=>({success:!0,hasSecurityIssues:!1,hasUnusedOverrides:!1,updated:!1,securityAlertCount:0,unusedOverrideCount:0,overrideCount:0,errors:[],securityAlerts:[],unusedOverrides:[],appliedOverrides:{}}),J=(e)=>{let t=e instanceof Error?e.message:String(e);return Object.assign({},I(),{success:!1,errors:[t]})},B=(e)=>({hasSecurityIssues:e.length>0,securityAlertCount:e.length,securityAlerts:e.map((t)=>({packageName:t.packageName,severity:t.severity||"unknown",cves:t.cves,description:t.description,patchedVersion:t.patchedVersion,fixAvailable:t.fixAvailable}))}),Ni=(e)=>Object.fromEntries(Object.keys(e).filter((t)=>typeof e[t]==="string").map((t)=>[t,e[t]])),Ti=(e,t)=>{let i=t?.pastoralist?.appendix||{},r=t?.overrides||t?.resolutions||t?.pnpm?.overrides||{},n=JSON.stringify(e.finalAppendix||{})!==JSON.stringify(i),s=JSON.stringify(e.finalOverrides||{})!==JSON.stringify(r);return n||s},E=(e,t,i)=>{let r=e.finalOverrides||{},n=Object.keys(r),o=Ti(e,t)&&!i;return{overrideCount:n.length,appliedOverrides:Ni(r),updated:o}},C=(e,t)=>{if(t)console.log(JSON.stringify(e))};var ji=(e)=>Object.assign({},e.dependencies,e.devDependencies,e.peerDependencies),Ui=(e,t)=>{let i=q(e);return Object.fromEntries(i.filter((r)=>Boolean(t[r])).map((r)=>[r,t[r]]))},Fi=(e,t)=>({name:e.name,version:e.version,dependencies:t}),M=async(e,t,i)=>{let r=e.pastoralist?.appendix||{},n=V(r);if(n.length===0)return[];let s=Ui(n,ji(e));if(Object.keys(s).length===0)return[];let o=Fi(e,s),{alerts:a}=await t.checkSecurity(o,{root:i.root||"./"}),c=new Set(a.map((d)=>d.packageName));return n.filter((d)=>{let[f]=q([d]);return c.has(f)})};var wi=y({file:"program.ts",isLogging:!1}),ze=(e)=>{if(e===void 0)return;let t=typeof e==="number",i=typeof e==="string"&&e.trim()!=="",r=t||i?Number(e):Number.NaN;if(Number.isFinite(r)&&r>=0)return r;throw Error("--cache-ttl must be a non-negative number of seconds")},z=(e,t,i,r)=>{let s=e.securityProvider??r??Ue,o=ze(e.cacheTtl??t.cacheTtl),a=e.checkSecurity??i.enabled,c=e.forceSecurityRefactor??i.autoFix,d=e.securityProviderToken??i.securityProviderToken,f=e.interactive??i.interactive,v=e.hasWorkspaceSecurityChecks??i.hasWorkspaceSecurityChecks,h=e.strict??i.strict;return Object.assign({},t,{checkSecurity:a,forceSecurityRefactor:c,securityProvider:s,securityProviderToken:d,interactive:f,hasWorkspaceSecurityChecks:v,strict:h,cacheTtl:o})},Ye=(e)=>{let i=[["cves",e.cves?.length?e.cves:void 0],["severity",e.severity],["description",e.description],["url",e.url],["vulnerableRange",e.vulnerableRange],["patchedVersion",e.patchedVersion],["sources",e.sources]].filter(([,r])=>r!==void 0).reduce((r,[n,s])=>Object.assign({},r,{[n]:s}),{});return Object.assign({},{packageName:e.packageName,reason:e.reason},i)},$i=(e,t,i)=>new i({provider:e.securityProvider,forceRefactor:e.forceSecurityRefactor,interactive:e.interactive,token:e.securityProviderToken,debug:t,strict:e.strict,cacheDir:e.cacheDir,cacheTtl:e.cacheTtl,noCache:e.noCache,refreshCache:e.refreshCache}),Hi=(e,t,i)=>new i({provider:e.securityProvider,forceRefactor:e.forceSecurityRefactor,interactive:e.interactive,token:e.securityProviderToken,debug:t,strict:e.strict,cacheTtl:e.cacheTtl}),Ke=(e,t,i=wi)=>{let r=e?.pastoralist?.depPaths,n=t.checkSecurity||e?.pastoralist?.checkSecurity||!1;if(Wi(r,n))return i.debug(`Using depPaths configuration for security checks: ${r.join(", ")}`,"determineSecurityScanPaths"),r;let s=Ee(e,t.root||"./",i);if(Li(r,s,n,t))return i.debug(`Using workspace configuration for security checks: ${s.join(", ")}`,"determineSecurityScanPaths"),s;return[]},Wi=(e,t)=>Array.isArray(e)&&t,Li=(e,t,i,r)=>Ji(e,t,i)||Bi(r,t.length>0),Ji=(e,t,i)=>{if(!(e==="workspace"||e==="workspaces"))return!1;if(t.length===0)return!1;return i},Bi=(e,t)=>{return(e.hasWorkspaceSecurityChecks||!1)&&t},Ei=(e)=>(t)=>{e.update(t.message)},qi=(e,t,i,r)=>Object.assign({},t,{depPaths:i,root:t.root||"./",onProgress:Ei(r),severityThreshold:e?.pastoralist?.security?.severityThreshold,excludePackages:e?.pastoralist?.security?.excludePackages}),Mi=(e,t,i)=>({spinner:e,securityChecker:t,alerts:i.alerts,securityOverrides:i.overrides,updates:i.updates,packagesScanned:i.packagesScanned,skipped:!1}),zi=async(e,t,i,r,n,s)=>{let o=$i(t,i,s.SecurityChecker),a=s.determineSecurityScanPaths(e,t,r),c=qi(e,t,a,n),d=await o.checkSecurity(e,c);return Mi(n,o,d)},Y=async(e,t,i,r,n={createSpinner:N,SecurityChecker:Me,determineSecurityScanPaths:Ke,green:m,yellow:Be})=>{let s=n.createSpinner(Je).start();try{return await zi(e,t,i,r,s,n)}catch(o){return Yi(o,s,t,i,n)}},Yi=(e,t,i,r,n)=>{if(e instanceof qe)return t.warn(`${n.yellow("pastoralist")} ${e.message}`),{spinner:t,securityChecker:Hi(i,r,n.SecurityChecker),alerts:[],securityOverrides:[],updates:[],packagesScanned:0,skipped:!0};let s=e instanceof Error?e.message:String(e);throw t.fail(`${n.yellow("pastoralist")} security check failed: ${s}`),e},Ki=(e)=>({packageName:e.packageName,fromVersion:e.currentOverride,toVersion:e.newerVersion,reason:e.reason,severity:"medium"}),Gi=(e,t)=>{return e.filter((i)=>{let r=t[i.packageName];if(typeof r!=="string")return!1;return r===i.toVersion})},K=(e,t,i,r,n,s=[])=>{let o=n.forceSecurityRefactor||n.interactive,a=e.length>0&&o,c=s.length>0&&o;if(!a&&!c)return r.stop(),{};let f=t.concat(s.map(Ki)),v=i.generatePackageOverrides(f),h=Gi(f,v),st=h.map(Ye);if(h.length>0&&!n.dryRun)i.applyAutoFix(h,n.path);return r.stop(),{securityOverrides:v,securityOverrideDetails:st}},_i=()=>({hasSecurityIssues:!1,securityAlertCount:0,securityAlerts:[]}),Qi=async(e,t,i)=>{if(!t.removeUnused)return t;let r=await M(e,i,t);if(r.length===0)return t;return Object.assign({},t,{skipRemovalKeys:r})},Xi=(e,t,i)=>{if(e.skipped)return t;let r=i.handleSecurityResults(e.alerts,e.securityOverrides,e.securityChecker,e.spinner,t,e.updates);return Object.assign({},t,r)},Zi=(e)=>({mergedOptions:e,securityResult:_i(),packagesScanned:0}),er=async(e,t,i,r)=>{let n=Object.assign({},t,{securityAlerts:i.alerts}),s=await Qi(e,n,i.securityChecker);return Xi(i,s,r)},tr=(e,t,i,r)=>{if(t.skipped||r)return;We(e,t.alerts,t.securityOverrides,i,t.packagesScanned)},ir=async(e,t,i,r,n,s,o)=>{if(!r)e.startPhase("scanning","Scanning packages");let a=await o.runSecurityCheck(t,i,n,s),c=B(a.alerts),d=await er(t,i,a,o);return tr(e,a,d,r),{mergedOptions:d,securityResult:c,packagesScanned:a.packagesScanned}},G=async(e,t,i,r,n,s,o)=>{if(!i.checkSecurity)return Zi(i);return ir(e,t,i,r,n,s,o)},rr=(e)=>{let t=`
Security Override Updates
`+"=".repeat(50)+`
`,i=`Found ${e.length} existing override(s) with newer patches available:
`,r=e.map(nr).join("");return[t,i,r].join("")},nr=(e)=>`[UPDATE] ${e.packageName}
Current override: ${e.currentOverride}
Newer patch: ${e.newerVersion}
${e.reason}
`;var it=(e,t,i)=>{if(!e)return!1;return t.debug("action:options:","action",{options:i}),!0},rt=async(e,t,i,r={initCommand:A})=>{if(!e)return!1;let n=Array.isArray(i.securityProvider)?i.securityProvider[0]:i.securityProvider;return await r.initCommand({path:t.path,root:t.root,checkSecurity:i.checkSecurity,securityProvider:n,hasWorkspaceSecurityChecks:i.hasWorkspaceSecurityChecks}),!0},sr=(e,t)=>{let i=Boolean(_e||e.debug),r=e.outputFormat==="json",n=e.quiet===!0,s=t.createLogger({file:"program.ts",isLogging:i}),o=t.createTerminalGraph({quiet:n}),a=I(),{isTestingCLI:c=!1,init:d=!1,...f}=e;return{emptyResult:a,graph:o,init:d,isJsonOutput:r,isLogging:i,isQuietMode:n,isTestingCLI:c,log:s,rest:f}},or=(e)=>{let t=Xe({cacheDir:e.cacheDir,root:e.root});Ze(t)},Ge=(e)=>{return C(e.emptyResult,e.isJsonOutput),e.emptyResult},ar=async(e,t,i)=>{if(t.handleTestMode(i.isTestingCLI,i.log,e))return Ge(i);if(await t.handleInitMode(i.init,e,i.rest))return Ge(i);return},ur=(e)=>{if(!e.isJsonOutput&&!e.isQuietMode)e.graph.banner()},cr=(e,t,i,r)=>G(r.graph,e.config,t,r.isJsonOutput,Boolean(r.isLogging),r.log,i),lr=async(e,t,i)=>{let r=await i.getOverrideGitDate(e);return Object.assign({},t,{addedDate:r})},dr=(e,t,i,r)=>{let n=r.update(t),s=E(n,e,i.dryRun||!1);return{updateContext:n,updateResultData:s}},fr=async(e,t,i)=>{let r=await je(e,i.rest,t),n=await cr(r,r.mergedOptions,t,i),s=await lr(r.path,n.mergedOptions,t),o=dr(r.config,s,e,t);return Object.assign({},r,{mergedOptions:s,securityPhase:n},o)},yr=(e,t)=>Object.assign({},e.emptyResult,t.securityPhase.securityResult,t.updateResultData,{metrics:t.updateContext.metrics}),pr=(e,t,i,r)=>{if(r.summary&&!i.isJsonOutput)L(e);if(C(e,i.isJsonOutput),i.isQuietMode&&e.hasSecurityIssues)t.processExit(1);return e},mr=(e,t,i)=>{if(t.isJsonOutput)return;Le(t.graph,e.updateContext,e.updateResultData,e.securityPhase.securityResult,e.securityPhase.packagesScanned,e.mergedOptions,i)},vr=async(e,t,i)=>{let r=await fr(e,t,i);return mr(r,i,e),pr(yr(i,r),t,i,e)},hr=(e,t,i)=>{i.graph.stop();let r=J(e);if(i.isJsonOutput)C(r,i.isJsonOutput);else i.log.error("action:fn","action",{error:e});return t.processExit(1),r},Pr={createLogger:y,handleTestMode:it,handleInitMode:rt,resolveJSON:P,buildMergedOptions:z,runSecurityCheck:Y,handleSecurityResults:K,createSpinner:N,green:m,update:tt,createTerminalGraph:Qe,getOverrideGitDate:et,loadConfig:D,processExit:(e)=>process.exit(e)};async function _(e={},t=Pr){or(e);let i=sr(e,t),r=await ar(e,t,i);if(r)return r;ur(i);try{return await vr(e,t,i)}catch(n){return hr(n,t,i)}}import*as T from"fs";import{resolve as Rr}from"path";var Cr={readFileSync:T.readFileSync,writeFileSync:T.writeFileSync,resolve:Rr},br=(e,t)=>t.resolve(p(e.path||"package.json",e.root)),kr=(e,t)=>JSON.parse(t.readFileSync(e,"utf8")),Sr=(e)=>{if(e)return`${e} && pastoralist`;return"pastoralist"},gr=(e)=>{let t=e.scripts||{},i=Object.assign({},t,{postinstall:Sr(t.postinstall||"")});return Object.assign({},e,{scripts:i})},Or=(e,t,i)=>{i.writeFileSync(e,JSON.stringify(t,null,2)+`
`)},Q=(e,t,i=Cr)=>{if(e.setupHook!==!0)return!1;try{let r=br(e,i),n=kr(r,i);if((n.scripts?.postinstall||"").includes("pastoralist"))return t.print("postinstall hook already configured"),!0;return Or(r,gr(n),i),t.print("added postinstall hook to package.json"),!0}catch(r){return t.error("Failed to setup hook","handleSetupHook",r),!1}};var Ir=(e)=>{try{return ie(e)}catch(t){let i=t instanceof Error?t.message:String(t);console.error(`Error: ${i}`),w(),process.exitCode=1;return}},Nr=(e,t)=>Boolean(t.help||e.includes("-h")||e.includes("--help")),Tr=(e,t)=>Boolean(t.version||e.includes("-v")||e.includes("--version")),jr=(e)=>{if(!xr(e))return;let t=JSON.parse(Ar(e,"utf8"));if(typeof t.version!=="string")return;return t.version},Ur=()=>{let e=Dr(Vr(import.meta.url)),i=[nt(e,"../package.json"),nt(e,"../../package.json")].map(jr).find((r)=>r!==void 0);if(!i)throw Error("Unable to read package version");return i},Fr=(e)=>{if(Array.isArray(e.securityProvider))return e.securityProvider[0];return e.securityProvider},wr=async(e,t)=>{let i=Object.assign({},e,{securityProvider:Fr(e)});await t.initCommand(i)},ls=async(e=process.argv,t={initCommand:A,action:_})=>{let i=Ir(e);if(!i)return;let r=i.options;if(Nr(e,r)){w();return}if(Tr(e,r)){console.log(Ur());return}let n=y({file:"program.ts",isLogging:!1});if(Q(r,n))return;if(i.command==="init"){await wr(r,t);return}await t.action(r)};export{G as runSecurityPhase,Y as runSecurityCheck,ls as run,p as resolvePathFromRoot,C as outputResult,ze as normalizeCacheTtl,it as handleTestMode,Q as handleSetupHook,K as handleSecurityResults,rt as handleInitMode,rr as formatUpdateReport,L as displaySummaryTable,He as displayOverrides,Ke as determineSecurityScanPaths,J as createErrorResult,I as createEmptyResult,M as checkRemovalSafety,E as buildUpdateResult,B as buildSecurityResult,Ye as buildSecurityOverrideDetail,z as buildMergedOptions,_ as action};