@oss-autopilot/core 1.16.1 → 1.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -92,7 +92,7 @@ Capacity: ${e.hasCapacity?"\u2705 Ready for new work":"\u26A0\uFE0F Focus on ex
92
92
  `),n=[],o=[],r="Uncategorized",i=null,s=!1;for(let a of e){let c=a.match(/^#{1,3}\s+(.+)/);if(c){r=c[1].trim(),i=null;continue}if(!a.trim()||!/^\s*[-*+]|\s*\d+\.|\s*\[[ xX]\]/.test(a))continue;let u=Ik(a);if(!u){if(i&&/^\s{2,}/.test(a)){let p=Ak(a);if(p!==void 0&&(i.score=p),s&&(Dk(a)||_O(a))){let g=n.indexOf(i);g!==-1&&(n.splice(g,1),o.push(i),s=!1)}}continue}let l=yO(a),d={repo:u.repo,number:u.number,title:l||`#${u.number}`,tier:r,url:u.url};Ok(a)?(o.push(d),s=!1):(n.push(d),s=!0),i=d}return{available:n,completed:o,availableCount:n.length,completedCount:o.length}}function mh(t,e=6){let n=t.split(`
93
93
  `),o=[],r=0,i=!1;for(let c=0;c<n.length;c++){let u=n[c];if(/^#{1,3}\s+/.test(u)){i=!1,o.push(u);continue}if(i&&/^\s{2,}/.test(u))continue;if(i=!1,/^\s*[-*+]\s/.test(u)&&Ok(u)){r++,i=!0;continue}if(Ik(u)){let p=!1,g=c+1;for(;g<n.length&&/^\s{2,}/.test(n[g]);){Dk(n[g])&&(p=!0);let y=Ak(n[g]);y!==void 0&&y<e&&(p=!0),g++}if(p){r++,i=!0;continue}}/^\s*skip\s*\(\d+\s*issues?\)/i.test(u.replace(/[#*]/g,"").trim())||/^---\s*$/.test(u)||/^\s*(###?\s*)?(Removed|Previously dropped)/i.test(u)||/^>\s/.test(u)||o.push(u)}let s=[];for(let c=0;c<o.length;c++){if(/^#{1,3}\s+/.test(o[c])){let l=c+1;for(;l<o.length&&o[l].trim()==="";)l++;if(l>=o.length||/^#{1,3}\s+/.test(o[l]))continue}s.push(o[c])}let a=[];for(let c of s)c.trim()===""&&a.length>0&&a[a.length-1].trim()===""||a.push(c);for(;a.length>0&&a[a.length-1].trim()==="";)a.pop();return{pruned:a.join(`
94
94
  `)+`
95
- `,removedCount:r}}async function gh(t){let e=Ck.resolve(t.filePath);if(!Lc.existsSync(e))throw new Error(`File not found: ${e}`);let n;try{n=Lc.readFileSync(e,"utf-8")}catch(o){let r=D(o);throw new Error(`Failed to read file: ${r}`,{cause:o})}return ko(n)}var Lc,Ck,Hi=h(()=>{"use strict";Lc=X(require("fs"),1),Ck=X(require("path"),1);$e()});function Vi(){return Gk.join(yt(),"dashboard-server.pid")}function Mc(t){Ro.writeFileSync(Vi(),JSON.stringify(t),{mode:384})}function To(){try{let t=Ro.readFileSync(Vi(),"utf-8"),e=JSON.parse(t);return typeof e!="object"||e===null||typeof e.pid!="number"||!Number.isInteger(e.pid)||e.pid<=0||typeof e.port!="number"||typeof e.startedAt!="string"?(b(Nc,"PID file has invalid structure, ignoring"),null):e}catch(t){return t.code!=="ENOENT"&&b(Nc,`Failed to read PID file: ${t.message}`),null}}function Or(){try{Ro.unlinkSync(Vi())}catch(t){t.code!=="ENOENT"&&b(Nc,`Failed to remove PID file: ${t.message}`)}}function qi(t){return new Promise(e=>{let n=Fk.get(`http://127.0.0.1:${t}/api/data`,{timeout:2e3},o=>{o.resume(),e(o.statusCode===200)});n.on("error",()=>e(!1)),n.on("timeout",()=>{n.destroy(),e(!1)})})}async function Zc(){let t=To();if(!t)return null;try{process.kill(t.pid,0)}catch(e){let n=e.code;return n!=="ESRCH"&&n!=="EPERM"&&b(Nc,`Unexpected error checking PID ${t.pid}: ${e.message}`),Or(),null}return await qi(t.port)?{port:t.port,url:`http://oss.localhost:${t.port}`}:(Or(),null)}var Fk,Ro,Gk,Nc,Hc=h(()=>{"use strict";Fk=X(require("http"),1),Ro=X(require("fs"),1),Gk=X(require("path"),1);ye();Se();Nc="dashboard-server"});var xo,zk=h(()=>{"use strict";xo=class{maxRequests;windowMs;timestamps=[];constructor(e){this.maxRequests=e.maxRequests,this.windowMs=e.windowMs}check(){let e=Date.now(),n=e-this.windowMs;if(this.timestamps=this.timestamps.filter(o=>o>n),this.timestamps.length>=this.maxRequests){let r=this.timestamps[0]+this.windowMs-e;return{allowed:!1,retryAfterSeconds:Math.ceil(r/1e3)}}return this.timestamps.push(e),{allowed:!0}}}});var ln={};ie(ln,{VALID_TARGETS:()=>fh,runMove:()=>SO});async function SO(t){Ae(t.prUrl),He(t.prUrl,ar,"PR");let e=t.target;if(!fh.includes(e))throw new Error(`Invalid target "${t.target}". Must be one of: ${fh.join(", ")}`);let n=L();switch(e){case"attention":case"waiting":{let o=e==="attention"?"needs_addressing":"waiting_on_maintainer",r=e==="attention"?"Need Attention":"Waiting on Maintainer",i=new Date().toISOString();return n.batch(()=>{n.setStatusOverride(t.prUrl,o,i),n.unshelvePR(t.prUrl)}),{url:t.prUrl,target:e,description:`Moved to ${r}`}}case"shelved":return n.batch(()=>{n.shelvePR(t.prUrl),n.clearStatusOverride(t.prUrl)}),{url:t.prUrl,target:e,description:"Shelved \u2014 excluded from capacity and actionable items"};case"auto":return n.batch(()=>{n.clearStatusOverride(t.prUrl),n.unshelvePR(t.prUrl)}),{url:t.prUrl,target:e,description:"Reset to computed status"};default:{let o=e;throw new Error(`Unhandled move target: ${o}`)}}}var fh,dn=h(()=>{"use strict";ye();Ot();fh=["attention","waiting","shelved","auto"]});var Zk={};ie(Zk,{buildDashboardJson:()=>Eo,findRunningDashboardServer:()=>Zc,getDashboardPidPath:()=>Vi,isDashboardServerRunning:()=>qi,readDashboardServerInfo:()=>To,removeDashboardServerInfo:()=>Or,startDashboardServer:()=>xO,writeDashboardServerInfo:()=>Mc});function RO(){try{let t=pn();if(!t)return null;let e=Po.readFileSync(t.path,"utf-8");return ko(e)}catch(t){return b(Je,`Failed to read vetted issue list: ${D(t)}`),null}}function Bi(){try{let t=pn();return t?Po.statSync(t.path).mtimeMs:null}catch{return null}}function Eo(t,e,n,o,r){let i=gk(t,e),s=fk(i),{monthlyMerged:a,monthlyOpened:c,monthlyClosed:u}=hk(e),l=o??ih(L().getMergedPRs()),d=r??sh(L().getClosedPRs()),p=e.config.minStars??50,g=e.repoScores||{},y=F=>!Zt(g[F.repo]?.stargazersCount,p),S=l.filter(y),U=d.filter(y),k=pk(t,e,S.length,U.length),E=e.config.dismissedIssues||{},P=n.filter(F=>F.status==="new_response"&&!(F.url in E)),M={};for(let[F,z]of Object.entries(g))(z.stargazersCount!==void 0||z.language!==void 0)&&(M[F]={stars:z.stargazersCount,language:z.language});let N=RO();return N&&(k.availableIssues=N.availableCount),{stats:k,prsByRepo:i,topRepos:s.map(([F,z])=>({repo:F,...z})),monthlyMerged:a,monthlyOpened:c,monthlyClosed:u,activePRs:Tr(t.openPRs||[],e),shelvedPRUrls:(t.shelvedPRs||[]).map(F=>F.url),recentlyMergedPRs:t.recentlyMergedPRs||[],recentlyClosedPRs:t.recentlyClosedPRs||[],autoUnshelvedPRs:t.autoUnshelvedPRs||[],commentedIssues:n,issueResponses:P,allMergedPRs:S,allClosedPRs:U,repoMetadata:M,vettedIssues:N}}function TO(t,e=wO){return new Promise((n,o)=>{let r=[],i=0,s=!1;t.on("data",a=>{if(!s){if(i+=a.length,i>e){s=!0,t.destroy(),o(new Error("Body too large"));return}r.push(a)}}),t.on("end",()=>{s||n(Buffer.concat(r).toString("utf-8"))}),t.on("error",a=>{s||o(a)})})}function Mk(t){t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("X-Frame-Options","DENY"),t.setHeader("Content-Security-Policy","default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'"),t.setHeader("Referrer-Policy","strict-origin-when-cross-origin")}function Lk(t,e){let n=t.headers.origin;return n?[`http://localhost:${e}`,`http://127.0.0.1:${e}`,`http://oss.localhost:${e}`].includes(n):!0}function Vc(t,e,n){Mk(t),t.setHeader("Cache-Control","no-store");let o=JSON.stringify(n);t.writeHead(e,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(o)}),t.end(o)}function Te(t,e,n){Vc(t,e,{error:n})}async function xO(t){let{port:e,assetsDir:n,token:o,open:r}=t,i=L(),s=Wt.resolve(n),a=i.getState().lastDigest,c=[];if(!a)throw new Error("No dashboard data available. Run the daily check first: GITHUB_TOKEN=$(gh auth token) npm start -- daily");let u,l=Bi();try{u=Eo(a,i.getState(),c)}catch(F){throw new Error(`Failed to build dashboard data: ${D(F)}. State data may be corrupted \u2014 try running: daily --json`,{cause:F})}let d=new xo({maxRequests:30,windowMs:6e4}),p=new xo({maxRequests:10,windowMs:6e4}),g=new xo({maxRequests:6,windowMs:6e4}),y=Nk.createServer(async(F,z)=>{let Z=F.method||"GET",te=F.url||"/";try{if(te==="/api/data"&&Z==="GET"){let B=d.check();if(!B.allowed){z.setHeader("Retry-After",String(B.retryAfterSeconds)),Te(z,429,"Too many requests");return}let _e=!1;i.isGistMode()?_e=await i.refreshFromGist():_e=i.reloadIfChanged();let Ee=Bi();if(_e||Ee!==l)try{u=Eo(a,i.getState(),c),l=Ee}catch(Ke){b(Je,`Failed to rebuild dashboard data after state reload: ${D(Ke)}`),z.setHeader("X-Dashboard-Stale","1")}Vc(z,200,u);return}if(te==="/api/action"&&Z==="POST"){if(!Lk(F,P)){Te(z,403,"Invalid origin");return}let B=p.check();if(!B.allowed){z.setHeader("Retry-After",String(B.retryAfterSeconds)),Te(z,429,"Too many requests");return}await S(F,z);return}if(te==="/api/refresh"&&Z==="POST"){if(!Lk(F,P)){Te(z,403,"Invalid origin");return}let B=g.check();if(!B.allowed){z.setHeader("Retry-After",String(B.retryAfterSeconds)),Te(z,429,"Too many requests");return}await U(F,z);return}if(Z==="GET"){k(te,z);return}Te(z,405,"Method not allowed")}catch(B){b(Je,`Unhandled request error: ${Z} ${te} ${D(B)}`),z.headersSent||Te(z,500,"Internal server error")}});y.requestTimeout=$O;async function S(F,z){i.isGistMode()?await i.refreshFromGist():i.reloadIfChanged();let Z;try{let B=await TO(F);Z=JSON.parse(B)}catch(B){let _e=B instanceof Error&&B.message==="Body too large";Te(z,_e?413:400,_e?"Request body too large":"Invalid JSON body");return}if(!Z.action||!jk.has(Z.action)){Te(z,400,`Invalid action. Must be one of: ${[...jk].join(", ")}`);return}if(!Z.url||typeof Z.url!="string"){Te(z,400,'Missing or invalid "url" field');return}let te=Z.action==="dismiss_issue_response";try{Ae(Z.url),He(Z.url,te?cr:ar,te?"issue":"PR")}catch(B){B instanceof we?Te(z,400,B.message):(b(Je,`Unexpected error during URL validation: ${D(B)}`),Te(z,400,"Invalid URL"));return}try{if(Z.action==="move"){let{VALID_TARGETS:B,runMove:_e}=await Promise.resolve().then(()=>(dn(),ln));if(!Z.target||!B.includes(Z.target)){Te(z,400,`move requires a valid "target" field (${B.join(", ")})`);return}await _e({prUrl:Z.url,target:Z.target})}else i.dismissIssue(Z.url,new Date().toISOString())}catch(B){b(Je,`Action failed: ${Z.action} ${Z.url} ${D(B)}`),Te(z,500,"Action failed");return}u=Eo(a,i.getState(),c),l=Bi(),Vc(z,200,u)}async function U(F,z){let Z=o||Mt();if(!Z){Te(z,401,"No GitHub token available. Cannot refresh data.");return}try{i.isGistMode()?await i.refreshFromGist():i.reloadIfChanged(),b(Je,"Refreshing dashboard data from GitHub...");let te=await oh(Z);a=te.digest,c=te.commentedIssues,u=Eo(a,i.getState(),c,te.allMergedPRs,te.allClosedPRs),l=Bi(),Vc(z,200,u)}catch(te){b(Je,`Dashboard refresh failed: ${D(te)}`),Te(z,500,"Refresh failed")}}function k(F,z){let Z;try{Z=decodeURIComponent(F.split("?")[0])}catch{b(Je,`Malformed URL received: ${F}`),Te(z,400,"Malformed URL");return}if(Z.includes("..")){Te(z,403,"Forbidden");return}let te=Z==="/"?"index.html":Z.replace(/^\/+/,""),B=Wt.join(s,te);if(!B.startsWith(s+Wt.sep)&&B!==s){Te(z,403,"Forbidden");return}try{Po.statSync(B).isDirectory()&&(B=Wt.join(s,"index.html"))}catch(ue){if(ue.code==="ENOENT")B=Wt.join(s,"index.html");else{b(Je,`Failed to stat file: ${B}`),Te(z,500,"Internal server error");return}}let _e=Wt.extname(B).toLowerCase(),Ee=kO[_e]||"application/octet-stream";try{let ue=Po.readFileSync(B);Mk(z),z.writeHead(200,{"Content-Type":Ee,"Content-Length":ue.length,"Cache-Control":"public, max-age=3600"}),z.end(ue)}catch(ue){ue.code==="ENOENT"?Te(z,404,"Not found"):(b(Je,`Failed to serve static file: ${B}`),Te(z,500,"Failed to read file"))}}let E=10,P=e;for(let F=0;F<E;F++)try{await new Promise((z,Z)=>{y.once("error",Z),y.listen(P,"127.0.0.1",()=>z())});break}catch(z){let Z=z;if(Z.code==="EADDRINUSE"&&F<E-1){b(Je,`Port ${P} is in use, trying ${P+1}...`),P++;continue}throw new Error(`Failed to start server: ${Z.message}`,{cause:z})}Mc({pid:process.pid,port:P,startedAt:new Date().toISOString(),version:Et()});let M=`http://oss.localhost:${P}`;b(Je,`Dashboard server running at ${M} (also: http://localhost:${P})`),o&&oh(o).then(async F=>{i.isGistMode()?await i.refreshFromGist():i.reloadIfChanged(),a=F.digest,c=F.commentedIssues,u=Eo(a,i.getState(),c,F.allMergedPRs,F.allClosedPRs),l=Bi(),b(Je,"Background data refresh complete")}).catch(F=>{b(Je,`Background data refresh failed (serving cached data): ${D(F)}`)}),r&&qc(M);let N=()=>{b(Je,"Shutting down dashboard server..."),Or(),y.close(()=>{process.exit(0)}),setTimeout(()=>process.exit(0),3e3).unref()};process.on("SIGINT",N),process.on("SIGTERM",N)}var Nk,Po,Wt,jk,Je,wO,$O,kO,Hk=h(()=>{"use strict";Nk=X(require("http"),1),Po=X(require("fs"),1),Wt=X(require("path"),1);ye();$e();Se();Ot();ah();Bc();Hi();Hc();zk();Sr();Hc();jk=new Set(["move","dismiss_issue_response"]),Je="dashboard-server",wO=10240,$O=3e4,kO={".html":"text/html",".js":"application/javascript",".css":"text/css",".svg":"image/svg+xml",".json":"application/json",".png":"image/png",".ico":"image/x-icon"}});var Vk={};ie(Vk,{resolveAssetsDir:()=>Jc,serveDashboard:()=>EO});function Jc(){let t=At.resolve(__dirname,"../../dashboard/dist");if(Wc.existsSync(At.join(t,"index.html")))return t;let e=At.resolve(At.dirname(process.argv[1]),"../../dashboard/dist");if(Wc.existsSync(At.join(e,"index.html")))return e;try{let n=require.resolve("@oss-autopilot/dashboard/package.json"),o=At.join(At.dirname(n),"dist");if(Wc.existsSync(At.join(o,"index.html")))return o}catch(n){n.code!=="MODULE_NOT_FOUND"&&console.error("Error resolving dashboard package:",n)}return null}async function EO(t){let e=Jc();e||(console.error("Could not find dashboard SPA assets."),console.error("Make sure packages/dashboard has been built:"),console.error(" cd packages/dashboard && pnpm run build"),process.exit(1));let n=Mt(),{startDashboardServer:o}=await Promise.resolve().then(()=>(Hk(),Zk));await o({port:t.port,assetsDir:e,token:n,open:t.open})}var Wc,At,hh=h(()=>{"use strict";Wc=X(require("fs"),1),At=X(require("path"),1);ye()});function OO(t){return new Promise(e=>setTimeout(e,t))}async function Bk(t){if(!Jc())return null;let n=await Zc();if(n){let c=To(),u=Et();if(c)if(c.version&&u!=="0.0.0"&&c.version!==u){console.error(`[STARTUP] Dashboard server version mismatch (running: ${c.version}, current: ${u}). Restarting...`);let l=!1;try{process.kill(c.pid,"SIGTERM"),l=!0}catch(d){d.code==="ESRCH"?l=!0:console.error(`[STARTUP] Could not kill outdated dashboard (PID ${c.pid}): ${d.message}`)}if(l)Or();else return{url:n.url,port:n.port,alreadyRunning:!0}}else return{url:n.url,port:n.port,alreadyRunning:!0}}let o=t?.port??PO,r=process.argv[1],i=(0,qk.spawn)("node",[r,"dashboard","serve","--port",String(o),"--no-open"],{detached:!0,stdio:"ignore"}),s=!1,a=!1;i.on("error",c=>{s=!0,console.error(`[STARTUP] Failed to spawn dashboard server: ${c.message}`)}),i.on("exit",c=>{a=!0,c!==0&&c!==null&&console.error(`[STARTUP] Dashboard server exited prematurely (code ${c})`)}),i.unref();for(let c=0;c<IO;c++){if(await OO(CO),s||a)return null;let u=To();if(u&&await qi(u.port))return{url:`http://oss.localhost:${u.port}`,port:u.port,alreadyRunning:!1}}if(console.error("[STARTUP] Dashboard server failed to start within 5 seconds"),i.pid)try{process.kill(i.pid,"SIGTERM")}catch(c){c.code!=="ESRCH"&&console.error(`[STARTUP] Failed to kill orphan dashboard process (PID ${i.pid}): ${c.message}`)}return null}var qk,PO,CO,IO,Wk=h(()=>{"use strict";qk=require("child_process");Hc();hh();ye();PO=3e3,CO=200,IO=25});var Yk={};ie(Yk,{countIssueListItems:()=>Xk,detectIssueList:()=>pn,openInBrowser:()=>qc,parseIssueListPathFromConfig:()=>Kk,runStartup:()=>DO});function Kk(t){let e=t.match(/^---\n([\s\S]*?)\n---/);if(!e)return;let o=e[1].match(/issueListPath:\s*["']?([^"'\n]+)["']?/);return o?o[1].trim():void 0}function Xk(t){let{availableCount:e,completedCount:n}=ko(t);return{availableCount:e,completedCount:n}}function pn(){let t="",e="auto-detected";try{let s=L().getState().config.issueListPath;s&&Jt.existsSync(s)&&(t=s,e="configured")}catch(i){b("startup",`Could not read issueListPath from state: ${D(i)}`)}if(!t){let i=".claude/oss-autopilot/config.md";if(Jt.existsSync(i))try{let s=Jt.readFileSync(i,"utf-8"),a=Kk(s);a&&Jt.existsSync(a)&&(t=a,e="configured")}catch(s){console.error("[STARTUP] Failed to read config:",D(s))}}if(!t){let i=["open-source/potential-issue-list.md","oss/issue-list.md","issues.md"];for(let s of i)if(Jt.existsSync(s)){t=s,e="auto-detected";break}}if(!t)return;let n=0,o=0;try{let i=Jt.readFileSync(t,"utf-8");({availableCount:n,completedCount:o}=Xk(i))}catch(i){console.error(`[STARTUP] Failed to read issue list at ${t}:`,D(i))}let r;try{let s=L().getState().config.skippedIssuesPath;s&&Jt.existsSync(s)&&(r=s)}catch(i){b("startup",`Could not read skippedIssuesPath from state: ${D(i)}`)}if(!r&&t){let i=Kc.join(Kc.dirname(t),"skipped-issues.md");Jt.existsSync(i)&&(r=i)}return{path:t,source:e,availableCount:n,completedCount:o,skippedIssuesPath:r}}function qc(t){let e,n;switch(process.platform){case"darwin":e="open",n=[t];break;case"win32":e="cmd",n=["/c","start","",t];break;default:e="xdg-open",n=[t];break}(0,Jk.execFile)(e,n,o=>{o&&console.error(`[STARTUP] Failed to open dashboard in browser: ${o.message}`)})}async function AO(t){try{let e=await fetch(`http://127.0.0.1:${t}/api/refresh`,{method:"POST",headers:{Origin:`http://oss.localhost:${t}`},signal:AbortSignal.timeout(5e3)});if(!e.ok){let n=await e.text().catch(()=>"");return console.error(`[STARTUP] Dashboard refresh returned ${e.status}: ${n}`),!1}return await e.text().catch(()=>{}),!0}catch(e){return console.error(`[STARTUP] Could not trigger dashboard refresh: ${D(e)}`),!1}}async function DO(){let t=Et(),e=L(),n=!1;if(!e.isSetupComplete()){let c=await ki();if(c)try{e.initializeWithDefaults(c),n=!0}catch(u){return console.error(`[STARTUP] Auto-detected username "${c}" but failed to save config:`,D(u)),{version:t,setupComplete:!1}}else return{version:t,setupComplete:!1}}let o=Mt();if(!o)return{version:t,setupComplete:!0,authError:'GitHub authentication required. Install GitHub CLI (https://cli.github.com/) and run "gh auth login", or set GITHUB_TOKEN.'};let r=await Uc(o),i,s;if(r.digest.summary.totalActivePRs>0)try{let c=await Bk();c?(i=c.url,c.alreadyRunning?s=await AO(c.port)?"refreshed":"running":(qc(c.url),s="opened")):console.error("[STARTUP] Dashboard SPA assets not found. Build with: cd packages/dashboard && pnpm run build")}catch(c){console.error("[STARTUP] SPA dashboard launch failed:",D(c))}s==="opened"?r.briefSummary+=" | Dashboard opened in browser":s==="refreshed"?r.briefSummary+=" | Dashboard refreshed":s==="running"&&(r.briefSummary+=" | Dashboard running");let a=pn();return{version:t,setupComplete:!0,autoDetected:n,daily:r,dashboardUrl:i,issueList:a}}var Jt,Kc,Jk,Bc=h(()=>{"use strict";Jt=X(require("fs"),1),Kc=X(require("path"),1),Jk=require("child_process");ye();$e();Se();Zi();Wk();Hi()});var eR={};ie(eR,{classifyListStatus:()=>Qk,runVetList:()=>FO});function Qk(t){let e=t.reasonsToSkip.map(n=>n.toLowerCase());return e.some(n=>n.includes("closed"))?"closed":e.some(n=>n.includes("claimed")||n.includes("assigned"))?"claimed":e.some(n=>n.includes("existing pr")||n.includes("linked pr")||n.includes("pull request"))?"has_pr":(t.recommendation==="approve"||t.recommendation==="needs_review","still_available")}async function FO(t={}){let e=t.concurrency??5,n=t.issueListPath;if(!n){let p=pn();if(!p)throw new Error("No issue list found. Provide a path with --path or configure issueListPath in settings.");n=p.path}let o=await gh({filePath:n});if(o.available.length===0)return{results:[],summary:{total:0,stillAvailable:0,claimed:0,closed:0,hasPR:0,errors:0}};let r=await Cr(),i=[],s=o.available,a=0;async function c(){for(;a<s.length;){let p=s[a++];try{let g=await r.vetIssue(p.url),y=jc({repo:g.issue.repo,projectHealth:g.projectHealth,getRepoScore:U=>L().getRepoScore(U)}),S={issue:{repo:g.issue.repo,number:g.issue.number,title:g.issue.title,url:g.issue.url,labels:g.issue.labels},recommendation:g.recommendation,reasonsToApprove:g.reasonsToApprove,reasonsToSkip:g.reasonsToSkip,projectHealth:g.projectHealth,vettingResult:g.vettingResult,grade:y};i.push({...S,listStatus:Qk(S)})}catch(g){i.push({issue:{repo:p.repo,number:p.number,title:p.title,url:p.url,labels:[]},recommendation:"skip",reasonsToApprove:[],reasonsToSkip:[`Error: ${g instanceof Error?g.message:String(g)}`],projectHealth:{},vettingResult:{},grade:UO,listStatus:"error",errorMessage:g instanceof Error?g.message:String(g)})}}}let u=Array.from({length:Math.min(e,s.length)},()=>c());await Promise.all(u);let l={total:i.length,stillAvailable:i.filter(p=>p.listStatus==="still_available").length,claimed:i.filter(p=>p.listStatus==="claimed").length,closed:i.filter(p=>p.listStatus==="closed").length,hasPR:i.filter(p=>p.listStatus==="has_pr").length,errors:i.filter(p=>p.listStatus==="error").length},d;if(t.prune&&n)try{let p=Xc.readFileSync(n,"utf-8"),{pruned:g,removedCount:y}=mh(p);g!==p&&Xc.writeFileSync(n,g,"utf-8"),d={removedCount:y}}catch(p){let g=p instanceof Error?p.message:String(p);console.error(`Warning: Failed to prune ${n}: ${g}`)}return{results:i,summary:l,pruneResult:d}}var Xc,UO,tR=h(()=>{"use strict";Xc=X(require("fs"),1);Mi();Hi();Bc();ph();ye();UO=dh({avgResponseDays:null,mergeRate:null,daysSinceLastCommit:null})});var rR={};ie(rR,{runSkipAdd:()=>LO});function jO(t){return t.toISOString().slice(0,10)}function LO(t){let e=t.skipFilePath??L().getState().config.skippedIssuesPath;if(!e)throw new Error("No skipped-issues path configured. Set one via `oss-autopilot config --set skippedIssuesPath=<path>` or pass --path.");if(!GO.test(t.issueUrl))throw new Error(`Invalid GitHub issue or PR URL: ${t.issueUrl}`);if(Ac(e).some(r=>r.url===t.issueUrl))return{added:!1,alreadyPresent:!0,url:t.issueUrl,path:e};Co.existsSync(e)||Co.writeFileSync(e,zO);let o=jO(t.now??new Date);return Co.appendFileSync(e,`${o} ${t.issueUrl}
95
+ `,removedCount:r}}async function gh(t){let e=Ck.resolve(t.filePath);if(!Lc.existsSync(e))throw new Error(`File not found: ${e}`);let n;try{n=Lc.readFileSync(e,"utf-8")}catch(o){let r=D(o);throw new Error(`Failed to read file: ${r}`,{cause:o})}return ko(n)}var Lc,Ck,Hi=h(()=>{"use strict";Lc=X(require("fs"),1),Ck=X(require("path"),1);$e()});function Vi(){return Gk.join(yt(),"dashboard-server.pid")}function Mc(t){Ro.writeFileSync(Vi(),JSON.stringify(t),{mode:384})}function To(){try{let t=Ro.readFileSync(Vi(),"utf-8"),e=JSON.parse(t);return typeof e!="object"||e===null||typeof e.pid!="number"||!Number.isInteger(e.pid)||e.pid<=0||typeof e.port!="number"||typeof e.startedAt!="string"?(b(Nc,"PID file has invalid structure, ignoring"),null):e}catch(t){return t.code!=="ENOENT"&&b(Nc,`Failed to read PID file: ${t.message}`),null}}function Or(){try{Ro.unlinkSync(Vi())}catch(t){t.code!=="ENOENT"&&b(Nc,`Failed to remove PID file: ${t.message}`)}}function qi(t){return new Promise(e=>{let n=Fk.get(`http://127.0.0.1:${t}/api/data`,{timeout:2e3},o=>{o.resume(),e(o.statusCode===200)});n.on("error",()=>e(!1)),n.on("timeout",()=>{n.destroy(),e(!1)})})}async function Zc(){let t=To();if(!t)return null;try{process.kill(t.pid,0)}catch(e){let n=e.code;return n!=="ESRCH"&&n!=="EPERM"&&b(Nc,`Unexpected error checking PID ${t.pid}: ${e.message}`),Or(),null}return await qi(t.port)?{port:t.port,url:`http://oss.localhost:${t.port}`}:(Or(),null)}var Fk,Ro,Gk,Nc,Hc=h(()=>{"use strict";Fk=X(require("http"),1),Ro=X(require("fs"),1),Gk=X(require("path"),1);ye();Se();Nc="dashboard-server"});var xo,zk=h(()=>{"use strict";xo=class{maxRequests;windowMs;timestamps=[];constructor(e){this.maxRequests=e.maxRequests,this.windowMs=e.windowMs}check(){let e=Date.now(),n=e-this.windowMs;if(this.timestamps=this.timestamps.filter(o=>o>n),this.timestamps.length>=this.maxRequests){let r=this.timestamps[0]+this.windowMs-e;return{allowed:!1,retryAfterSeconds:Math.ceil(r/1e3)}}return this.timestamps.push(e),{allowed:!0}}}});var ln={};ie(ln,{VALID_TARGETS:()=>fh,runMove:()=>SO});async function SO(t){Ae(t.prUrl),He(t.prUrl,ar,"PR");let e=t.target;if(!fh.includes(e))throw new Error(`Invalid target "${t.target}". Must be one of: ${fh.join(", ")}`);let n=L();switch(e){case"attention":case"waiting":{let o=e==="attention"?"needs_addressing":"waiting_on_maintainer",r=e==="attention"?"Need Attention":"Waiting on Maintainer",i=new Date().toISOString();return n.batch(()=>{n.setStatusOverride(t.prUrl,o,i),n.unshelvePR(t.prUrl)}),{url:t.prUrl,target:e,description:`Moved to ${r}`}}case"shelved":return n.batch(()=>{n.shelvePR(t.prUrl),n.clearStatusOverride(t.prUrl)}),{url:t.prUrl,target:e,description:"Shelved \u2014 excluded from capacity and actionable items"};case"auto":return n.batch(()=>{n.clearStatusOverride(t.prUrl),n.unshelvePR(t.prUrl)}),{url:t.prUrl,target:e,description:"Reset to computed status"};default:{let o=e;throw new Error(`Unhandled move target: ${o}`)}}}var fh,dn=h(()=>{"use strict";ye();Ot();fh=["attention","waiting","shelved","auto"]});var Zk={};ie(Zk,{buildDashboardJson:()=>Eo,findRunningDashboardServer:()=>Zc,getDashboardPidPath:()=>Vi,isDashboardServerRunning:()=>qi,readDashboardServerInfo:()=>To,removeDashboardServerInfo:()=>Or,startDashboardServer:()=>xO,writeDashboardServerInfo:()=>Mc});function RO(){try{let t=pn();if(!t)return null;let e=Po.readFileSync(t.path,"utf-8");return ko(e)}catch(t){return b(Je,`Failed to read vetted issue list: ${D(t)}`),null}}function Bi(){try{let t=pn();return t?Po.statSync(t.path).mtimeMs:null}catch{return null}}function Eo(t,e,n,o,r){let i=gk(t,e),s=fk(i),{monthlyMerged:a,monthlyOpened:c,monthlyClosed:u}=hk(e),l=o??ih(L().getMergedPRs()),d=r??sh(L().getClosedPRs()),p=e.config.minStars??50,g=e.repoScores||{},y=F=>!Zt(g[F.repo]?.stargazersCount,p),S=l.filter(y),U=d.filter(y),k=pk(t,e,S.length,U.length),E=e.config.dismissedIssues||{},P=n.filter(F=>F.status==="new_response"&&!(F.url in E)),M={};for(let[F,z]of Object.entries(g))(z.stargazersCount!==void 0||z.language!==void 0)&&(M[F]={stars:z.stargazersCount,language:z.language});let N=RO();return N&&(k.availableIssues=N.availableCount),{stats:k,prsByRepo:i,topRepos:s.map(([F,z])=>({repo:F,...z})),monthlyMerged:a,monthlyOpened:c,monthlyClosed:u,activePRs:Tr(t.openPRs||[],e),shelvedPRUrls:(t.shelvedPRs||[]).map(F=>F.url),recentlyMergedPRs:t.recentlyMergedPRs||[],recentlyClosedPRs:t.recentlyClosedPRs||[],autoUnshelvedPRs:t.autoUnshelvedPRs||[],commentedIssues:n,issueResponses:P,allMergedPRs:S,allClosedPRs:U,repoMetadata:M,vettedIssues:N}}function TO(t,e=wO){return new Promise((n,o)=>{let r=[],i=0,s=!1;t.on("data",a=>{if(!s){if(i+=a.length,i>e){s=!0,t.destroy(),o(new Error("Body too large"));return}r.push(a)}}),t.on("end",()=>{s||n(Buffer.concat(r).toString("utf-8"))}),t.on("error",a=>{s||o(a)})})}function Mk(t){t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("X-Frame-Options","DENY"),t.setHeader("Content-Security-Policy","default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'; worker-src 'self' blob:"),t.setHeader("Referrer-Policy","strict-origin-when-cross-origin")}function Lk(t,e){let n=t.headers.origin;return n?[`http://localhost:${e}`,`http://127.0.0.1:${e}`,`http://oss.localhost:${e}`].includes(n):!0}function Vc(t,e,n){Mk(t),t.setHeader("Cache-Control","no-store");let o=JSON.stringify(n);t.writeHead(e,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(o)}),t.end(o)}function Te(t,e,n){Vc(t,e,{error:n})}async function xO(t){let{port:e,assetsDir:n,token:o,open:r}=t,i=L(),s=Wt.resolve(n),a=i.getState().lastDigest,c=[];if(!a)throw new Error("No dashboard data available. Run the daily check first: GITHUB_TOKEN=$(gh auth token) npm start -- daily");let u,l=Bi();try{u=Eo(a,i.getState(),c)}catch(F){throw new Error(`Failed to build dashboard data: ${D(F)}. State data may be corrupted \u2014 try running: daily --json`,{cause:F})}let d=new xo({maxRequests:30,windowMs:6e4}),p=new xo({maxRequests:10,windowMs:6e4}),g=new xo({maxRequests:6,windowMs:6e4}),y=Nk.createServer(async(F,z)=>{let Z=F.method||"GET",te=F.url||"/";try{if(te==="/api/data"&&Z==="GET"){let B=d.check();if(!B.allowed){z.setHeader("Retry-After",String(B.retryAfterSeconds)),Te(z,429,"Too many requests");return}let _e=!1;i.isGistMode()?_e=await i.refreshFromGist():_e=i.reloadIfChanged();let Ee=Bi();if(_e||Ee!==l)try{u=Eo(a,i.getState(),c),l=Ee}catch(Ke){b(Je,`Failed to rebuild dashboard data after state reload: ${D(Ke)}`),z.setHeader("X-Dashboard-Stale","1")}Vc(z,200,u);return}if(te==="/api/action"&&Z==="POST"){if(!Lk(F,P)){Te(z,403,"Invalid origin");return}let B=p.check();if(!B.allowed){z.setHeader("Retry-After",String(B.retryAfterSeconds)),Te(z,429,"Too many requests");return}await S(F,z);return}if(te==="/api/refresh"&&Z==="POST"){if(!Lk(F,P)){Te(z,403,"Invalid origin");return}let B=g.check();if(!B.allowed){z.setHeader("Retry-After",String(B.retryAfterSeconds)),Te(z,429,"Too many requests");return}await U(F,z);return}if(Z==="GET"){k(te,z);return}Te(z,405,"Method not allowed")}catch(B){b(Je,`Unhandled request error: ${Z} ${te} ${D(B)}`),z.headersSent||Te(z,500,"Internal server error")}});y.requestTimeout=$O;async function S(F,z){i.isGistMode()?await i.refreshFromGist():i.reloadIfChanged();let Z;try{let B=await TO(F);Z=JSON.parse(B)}catch(B){let _e=B instanceof Error&&B.message==="Body too large";Te(z,_e?413:400,_e?"Request body too large":"Invalid JSON body");return}if(!Z.action||!jk.has(Z.action)){Te(z,400,`Invalid action. Must be one of: ${[...jk].join(", ")}`);return}if(!Z.url||typeof Z.url!="string"){Te(z,400,'Missing or invalid "url" field');return}let te=Z.action==="dismiss_issue_response";try{Ae(Z.url),He(Z.url,te?cr:ar,te?"issue":"PR")}catch(B){B instanceof we?Te(z,400,B.message):(b(Je,`Unexpected error during URL validation: ${D(B)}`),Te(z,400,"Invalid URL"));return}try{if(Z.action==="move"){let{VALID_TARGETS:B,runMove:_e}=await Promise.resolve().then(()=>(dn(),ln));if(!Z.target||!B.includes(Z.target)){Te(z,400,`move requires a valid "target" field (${B.join(", ")})`);return}await _e({prUrl:Z.url,target:Z.target})}else i.dismissIssue(Z.url,new Date().toISOString())}catch(B){b(Je,`Action failed: ${Z.action} ${Z.url} ${D(B)}`),Te(z,500,"Action failed");return}u=Eo(a,i.getState(),c),l=Bi(),Vc(z,200,u)}async function U(F,z){let Z=o||Mt();if(!Z){Te(z,401,"No GitHub token available. Cannot refresh data.");return}try{i.isGistMode()?await i.refreshFromGist():i.reloadIfChanged(),b(Je,"Refreshing dashboard data from GitHub...");let te=await oh(Z);a=te.digest,c=te.commentedIssues,u=Eo(a,i.getState(),c,te.allMergedPRs,te.allClosedPRs),l=Bi(),Vc(z,200,u)}catch(te){b(Je,`Dashboard refresh failed: ${D(te)}`),Te(z,500,"Refresh failed")}}function k(F,z){let Z;try{Z=decodeURIComponent(F.split("?")[0])}catch{b(Je,`Malformed URL received: ${F}`),Te(z,400,"Malformed URL");return}if(Z.includes("..")){Te(z,403,"Forbidden");return}let te=Z==="/"?"index.html":Z.replace(/^\/+/,""),B=Wt.join(s,te);if(!B.startsWith(s+Wt.sep)&&B!==s){Te(z,403,"Forbidden");return}try{Po.statSync(B).isDirectory()&&(B=Wt.join(s,"index.html"))}catch(ue){if(ue.code==="ENOENT")B=Wt.join(s,"index.html");else{b(Je,`Failed to stat file: ${B}`),Te(z,500,"Internal server error");return}}let _e=Wt.extname(B).toLowerCase(),Ee=kO[_e]||"application/octet-stream";try{let ue=Po.readFileSync(B);Mk(z),z.writeHead(200,{"Content-Type":Ee,"Content-Length":ue.length,"Cache-Control":"public, max-age=3600"}),z.end(ue)}catch(ue){ue.code==="ENOENT"?Te(z,404,"Not found"):(b(Je,`Failed to serve static file: ${B}`),Te(z,500,"Failed to read file"))}}let E=10,P=e;for(let F=0;F<E;F++)try{await new Promise((z,Z)=>{y.once("error",Z),y.listen(P,"127.0.0.1",()=>z())});break}catch(z){let Z=z;if(Z.code==="EADDRINUSE"&&F<E-1){b(Je,`Port ${P} is in use, trying ${P+1}...`),P++;continue}throw new Error(`Failed to start server: ${Z.message}`,{cause:z})}Mc({pid:process.pid,port:P,startedAt:new Date().toISOString(),version:Et()});let M=`http://oss.localhost:${P}`;b(Je,`Dashboard server running at ${M} (also: http://localhost:${P})`),o&&oh(o).then(async F=>{i.isGistMode()?await i.refreshFromGist():i.reloadIfChanged(),a=F.digest,c=F.commentedIssues,u=Eo(a,i.getState(),c,F.allMergedPRs,F.allClosedPRs),l=Bi(),b(Je,"Background data refresh complete")}).catch(F=>{b(Je,`Background data refresh failed (serving cached data): ${D(F)}`)}),r&&qc(M);let N=()=>{b(Je,"Shutting down dashboard server..."),Or(),y.close(()=>{process.exit(0)}),setTimeout(()=>process.exit(0),3e3).unref()};process.on("SIGINT",N),process.on("SIGTERM",N)}var Nk,Po,Wt,jk,Je,wO,$O,kO,Hk=h(()=>{"use strict";Nk=X(require("http"),1),Po=X(require("fs"),1),Wt=X(require("path"),1);ye();$e();Se();Ot();ah();Bc();Hi();Hc();zk();Sr();Hc();jk=new Set(["move","dismiss_issue_response"]),Je="dashboard-server",wO=10240,$O=3e4,kO={".html":"text/html",".js":"application/javascript",".css":"text/css",".svg":"image/svg+xml",".json":"application/json",".png":"image/png",".ico":"image/x-icon"}});var Vk={};ie(Vk,{resolveAssetsDir:()=>Jc,serveDashboard:()=>EO});function Jc(){let t=At.resolve(__dirname,"../../dashboard/dist");if(Wc.existsSync(At.join(t,"index.html")))return t;let e=At.resolve(At.dirname(process.argv[1]),"../../dashboard/dist");if(Wc.existsSync(At.join(e,"index.html")))return e;try{let n=require.resolve("@oss-autopilot/dashboard/package.json"),o=At.join(At.dirname(n),"dist");if(Wc.existsSync(At.join(o,"index.html")))return o}catch(n){n.code!=="MODULE_NOT_FOUND"&&console.error("Error resolving dashboard package:",n)}return null}async function EO(t){let e=Jc();e||(console.error("Could not find dashboard SPA assets."),console.error("Make sure packages/dashboard has been built:"),console.error(" cd packages/dashboard && pnpm run build"),process.exit(1));let n=Mt(),{startDashboardServer:o}=await Promise.resolve().then(()=>(Hk(),Zk));await o({port:t.port,assetsDir:e,token:n,open:t.open})}var Wc,At,hh=h(()=>{"use strict";Wc=X(require("fs"),1),At=X(require("path"),1);ye()});function OO(t){return new Promise(e=>setTimeout(e,t))}async function Bk(t){if(!Jc())return null;let n=await Zc();if(n){let c=To(),u=Et();if(c)if(c.version&&u!=="0.0.0"&&c.version!==u){console.error(`[STARTUP] Dashboard server version mismatch (running: ${c.version}, current: ${u}). Restarting...`);let l=!1;try{process.kill(c.pid,"SIGTERM"),l=!0}catch(d){d.code==="ESRCH"?l=!0:console.error(`[STARTUP] Could not kill outdated dashboard (PID ${c.pid}): ${d.message}`)}if(l)Or();else return{url:n.url,port:n.port,alreadyRunning:!0}}else return{url:n.url,port:n.port,alreadyRunning:!0}}let o=t?.port??PO,r=process.argv[1],i=(0,qk.spawn)("node",[r,"dashboard","serve","--port",String(o),"--no-open"],{detached:!0,stdio:"ignore"}),s=!1,a=!1;i.on("error",c=>{s=!0,console.error(`[STARTUP] Failed to spawn dashboard server: ${c.message}`)}),i.on("exit",c=>{a=!0,c!==0&&c!==null&&console.error(`[STARTUP] Dashboard server exited prematurely (code ${c})`)}),i.unref();for(let c=0;c<IO;c++){if(await OO(CO),s||a)return null;let u=To();if(u&&await qi(u.port))return{url:`http://oss.localhost:${u.port}`,port:u.port,alreadyRunning:!1}}if(console.error("[STARTUP] Dashboard server failed to start within 5 seconds"),i.pid)try{process.kill(i.pid,"SIGTERM")}catch(c){c.code!=="ESRCH"&&console.error(`[STARTUP] Failed to kill orphan dashboard process (PID ${i.pid}): ${c.message}`)}return null}var qk,PO,CO,IO,Wk=h(()=>{"use strict";qk=require("child_process");Hc();hh();ye();PO=3e3,CO=200,IO=25});var Yk={};ie(Yk,{countIssueListItems:()=>Xk,detectIssueList:()=>pn,openInBrowser:()=>qc,parseIssueListPathFromConfig:()=>Kk,runStartup:()=>DO});function Kk(t){let e=t.match(/^---\n([\s\S]*?)\n---/);if(!e)return;let o=e[1].match(/issueListPath:\s*["']?([^"'\n]+)["']?/);return o?o[1].trim():void 0}function Xk(t){let{availableCount:e,completedCount:n}=ko(t);return{availableCount:e,completedCount:n}}function pn(){let t="",e="auto-detected";try{let s=L().getState().config.issueListPath;s&&Jt.existsSync(s)&&(t=s,e="configured")}catch(i){b("startup",`Could not read issueListPath from state: ${D(i)}`)}if(!t){let i=".claude/oss-autopilot/config.md";if(Jt.existsSync(i))try{let s=Jt.readFileSync(i,"utf-8"),a=Kk(s);a&&Jt.existsSync(a)&&(t=a,e="configured")}catch(s){console.error("[STARTUP] Failed to read config:",D(s))}}if(!t){let i=["open-source/potential-issue-list.md","oss/issue-list.md","issues.md"];for(let s of i)if(Jt.existsSync(s)){t=s,e="auto-detected";break}}if(!t)return;let n=0,o=0;try{let i=Jt.readFileSync(t,"utf-8");({availableCount:n,completedCount:o}=Xk(i))}catch(i){console.error(`[STARTUP] Failed to read issue list at ${t}:`,D(i))}let r;try{let s=L().getState().config.skippedIssuesPath;s&&Jt.existsSync(s)&&(r=s)}catch(i){b("startup",`Could not read skippedIssuesPath from state: ${D(i)}`)}if(!r&&t){let i=Kc.join(Kc.dirname(t),"skipped-issues.md");Jt.existsSync(i)&&(r=i)}return{path:t,source:e,availableCount:n,completedCount:o,skippedIssuesPath:r}}function qc(t){let e,n;switch(process.platform){case"darwin":e="open",n=[t];break;case"win32":e="cmd",n=["/c","start","",t];break;default:e="xdg-open",n=[t];break}(0,Jk.execFile)(e,n,o=>{o&&console.error(`[STARTUP] Failed to open dashboard in browser: ${o.message}`)})}async function AO(t){try{let e=await fetch(`http://127.0.0.1:${t}/api/refresh`,{method:"POST",headers:{Origin:`http://oss.localhost:${t}`},signal:AbortSignal.timeout(5e3)});if(!e.ok){let n=await e.text().catch(()=>"");return console.error(`[STARTUP] Dashboard refresh returned ${e.status}: ${n}`),!1}return await e.text().catch(()=>{}),!0}catch(e){return console.error(`[STARTUP] Could not trigger dashboard refresh: ${D(e)}`),!1}}async function DO(){let t=Et(),e=L(),n=!1;if(!e.isSetupComplete()){let c=await ki();if(c)try{e.initializeWithDefaults(c),n=!0}catch(u){return console.error(`[STARTUP] Auto-detected username "${c}" but failed to save config:`,D(u)),{version:t,setupComplete:!1}}else return{version:t,setupComplete:!1}}let o=Mt();if(!o)return{version:t,setupComplete:!0,authError:'GitHub authentication required. Install GitHub CLI (https://cli.github.com/) and run "gh auth login", or set GITHUB_TOKEN.'};let r=await Uc(o),i,s;if(r.digest.summary.totalActivePRs>0)try{let c=await Bk();c?(i=c.url,c.alreadyRunning?s=await AO(c.port)?"refreshed":"running":(qc(c.url),s="opened")):console.error("[STARTUP] Dashboard SPA assets not found. Build with: cd packages/dashboard && pnpm run build")}catch(c){console.error("[STARTUP] SPA dashboard launch failed:",D(c))}s==="opened"?r.briefSummary+=" | Dashboard opened in browser":s==="refreshed"?r.briefSummary+=" | Dashboard refreshed":s==="running"&&(r.briefSummary+=" | Dashboard running");let a=pn();return{version:t,setupComplete:!0,autoDetected:n,daily:r,dashboardUrl:i,issueList:a}}var Jt,Kc,Jk,Bc=h(()=>{"use strict";Jt=X(require("fs"),1),Kc=X(require("path"),1),Jk=require("child_process");ye();$e();Se();Zi();Wk();Hi()});var eR={};ie(eR,{classifyListStatus:()=>Qk,runVetList:()=>FO});function Qk(t){let e=t.reasonsToSkip.map(n=>n.toLowerCase());return e.some(n=>n.includes("closed"))?"closed":e.some(n=>n.includes("claimed")||n.includes("assigned"))?"claimed":e.some(n=>n.includes("existing pr")||n.includes("linked pr")||n.includes("pull request"))?"has_pr":(t.recommendation==="approve"||t.recommendation==="needs_review","still_available")}async function FO(t={}){let e=t.concurrency??5,n=t.issueListPath;if(!n){let p=pn();if(!p)throw new Error("No issue list found. Provide a path with --path or configure issueListPath in settings.");n=p.path}let o=await gh({filePath:n});if(o.available.length===0)return{results:[],summary:{total:0,stillAvailable:0,claimed:0,closed:0,hasPR:0,errors:0}};let r=await Cr(),i=[],s=o.available,a=0;async function c(){for(;a<s.length;){let p=s[a++];try{let g=await r.vetIssue(p.url),y=jc({repo:g.issue.repo,projectHealth:g.projectHealth,getRepoScore:U=>L().getRepoScore(U)}),S={issue:{repo:g.issue.repo,number:g.issue.number,title:g.issue.title,url:g.issue.url,labels:g.issue.labels},recommendation:g.recommendation,reasonsToApprove:g.reasonsToApprove,reasonsToSkip:g.reasonsToSkip,projectHealth:g.projectHealth,vettingResult:g.vettingResult,grade:y};i.push({...S,listStatus:Qk(S)})}catch(g){i.push({issue:{repo:p.repo,number:p.number,title:p.title,url:p.url,labels:[]},recommendation:"skip",reasonsToApprove:[],reasonsToSkip:[`Error: ${g instanceof Error?g.message:String(g)}`],projectHealth:{},vettingResult:{},grade:UO,listStatus:"error",errorMessage:g instanceof Error?g.message:String(g)})}}}let u=Array.from({length:Math.min(e,s.length)},()=>c());await Promise.all(u);let l={total:i.length,stillAvailable:i.filter(p=>p.listStatus==="still_available").length,claimed:i.filter(p=>p.listStatus==="claimed").length,closed:i.filter(p=>p.listStatus==="closed").length,hasPR:i.filter(p=>p.listStatus==="has_pr").length,errors:i.filter(p=>p.listStatus==="error").length},d;if(t.prune&&n)try{let p=Xc.readFileSync(n,"utf-8"),{pruned:g,removedCount:y}=mh(p);g!==p&&Xc.writeFileSync(n,g,"utf-8"),d={removedCount:y}}catch(p){let g=p instanceof Error?p.message:String(p);console.error(`Warning: Failed to prune ${n}: ${g}`)}return{results:i,summary:l,pruneResult:d}}var Xc,UO,tR=h(()=>{"use strict";Xc=X(require("fs"),1);Mi();Hi();Bc();ph();ye();UO=dh({avgResponseDays:null,mergeRate:null,daysSinceLastCommit:null})});var rR={};ie(rR,{runSkipAdd:()=>LO});function jO(t){return t.toISOString().slice(0,10)}function LO(t){let e=t.skipFilePath??L().getState().config.skippedIssuesPath;if(!e)throw new Error("No skipped-issues path configured. Set one via `oss-autopilot config --set skippedIssuesPath=<path>` or pass --path.");if(!GO.test(t.issueUrl))throw new Error(`Invalid GitHub issue or PR URL: ${t.issueUrl}`);if(Ac(e).some(r=>r.url===t.issueUrl))return{added:!1,alreadyPresent:!0,url:t.issueUrl,path:e};Co.existsSync(e)||Co.writeFileSync(e,zO);let o=jO(t.now??new Date);return Co.appendFileSync(e,`${o} ${t.issueUrl}
96
96
  `),{added:!0,alreadyPresent:!1,url:t.issueUrl,path:e,date:o}}var Co,GO,zO,nR=h(()=>{"use strict";Co=X(require("fs"),1);th();ye();GO=/^https:\/\/github\.com\/([^/]+\/[^/]+)\/(?:issues|pull)\/(\d+)(?:[/?#].*)?$/,zO=`# Skipped Issues \u2014 auto-culled after 90 days
97
97
  # Format: YYYY-MM-DD URL
98
98
 
@@ -160,7 +160,11 @@ function readBody(req, maxBytes = MAX_BODY_BYTES) {
160
160
  function setSecurityHeaders(res) {
161
161
  res.setHeader('X-Content-Type-Options', 'nosniff');
162
162
  res.setHeader('X-Frame-Options', 'DENY');
163
- res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'");
163
+ // worker-src: canvas-confetti generates its animation worker as a Blob and
164
+ // loads it via a blob: URL. Without this directive the browser falls back
165
+ // to script-src, which doesn't list blob:, and the celebrate button fails
166
+ // silently. Scoped to workers only — safer than widening script-src.
167
+ res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'; worker-src 'self' blob:");
164
168
  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
165
169
  }
166
170
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "1.16.1",
3
+ "version": "1.16.2",
4
4
  "description": "CLI and core library for managing open source contributions",
5
5
  "type": "module",
6
6
  "bin": {