From 28eba396d2d15a438110f4027459d5258f284061 Mon Sep 17 00:00:00 2001 From: "Marcus R. Brown" Date: Sat, 28 Mar 2026 19:10:10 -0700 Subject: [PATCH] feat(dedup): bypass dedup for synchronize and reopened PR actions (#398) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(dedup): bypass dedup for synchronize and reopened PR actions synchronize fires first on push and provides required status check results β€” if deduped, checks never pass. reopened is a meaningful state change (PR was closed, now open again) that warrants a fresh agent run regardless of recent execution. * feat(dedup): write job summary when execution is skipped by dedup When dedup skips execution, write a GitHub Actions job summary showing the current action, prior run link, prior action, time since prior run, and dedup window. Gives operators visibility into why a run was skipped. --- dist/main.js | 32 ++++++++++--------- src/harness/phases/dedup.test.ts | 54 ++++++++++++++++++++++++++++++- src/harness/phases/dedup.ts | 55 ++++++++++++++++++++++++++++---- 3 files changed, 119 insertions(+), 22 deletions(-) diff --git a/dist/main.js b/dist/main.js index 1b97587f..573c0b72 100644 --- a/dist/main.js +++ b/dist/main.js @@ -1,7 +1,7 @@ -import{A as e,B as t,C as n,D as r,E as i,F as a,G as o,H as s,J as c,K as l,L as u,M as d,N as f,O as p,P as m,R as h,S as g,T as _,U as v,V as y,W as b,X as x,Y as S,Z as C,_ as w,a as T,b as E,c as D,d as O,f as k,g as A,h as j,i as ee,j as M,k as N,l as te,m as ne,n as re,o as ie,p as P,q as ae,r as oe,s as se,t as ce,u as le,v as ue,w as de,x as fe,y as pe,z as F}from"./artifact-DZtNN4TE.js";import I from"node:process";import*as me from"os";import*as he from"crypto";import*as L from"fs";import*as R from"path";import{ok as ge}from"assert";import*as _e from"util";import{Buffer as ve}from"node:buffer";import*as ye from"node:crypto";import{createHash as be}from"node:crypto";import{pathToFileURL as xe}from"node:url";import*as z from"node:fs/promises";import Se from"node:fs/promises";import*as B from"node:path";import Ce,{join as we}from"node:path";import{spawn as Te}from"node:child_process";import*as Ee from"node:os";import De,{homedir as Oe}from"node:os";import*as ke from"stream";function Ae(e){switch(e){case`hit`:return`βœ… hit`;case`miss`:return`πŸ†• miss`;case`corrupted`:return`⚠️ corrupted (clean start)`}}function je(e){let t=Math.round(e/1e3);return t<60?`${t}s`:`${Math.floor(t/60)}m ${t%60}s`}async function Me(e,t){let{eventType:n,repo:r,ref:i,runId:a,runUrl:o,metrics:c,agent:l}=e;try{if(S.addHeading(`Fro Bot Agent Run`,2).addTable([[{data:`Field`,header:!0},{data:`Value`,header:!0}],[`Event`,n],[`Repository`,r],[`Ref`,i],[`Run ID`,`[${a}](${o})`],[`Agent`,l],[`Cache Status`,Ae(c.cacheStatus)],[`Duration`,c.duration==null?`N/A`:je(c.duration)]]),(c.sessionsUsed.length>0||c.sessionsCreated.length>0)&&(S.addHeading(`Sessions`,3),c.sessionsUsed.length>0&&S.addRaw(`**Used:** ${c.sessionsUsed.join(`, `)}\n`),c.sessionsCreated.length>0&&S.addRaw(`**Created:** ${c.sessionsCreated.join(`, `)}\n`)),c.tokenUsage!=null&&(S.addHeading(`Token Usage`,3),S.addTable([[{data:`Metric`,header:!0},{data:`Count`,header:!0}],[`Input`,c.tokenUsage.input.toLocaleString()],[`Output`,c.tokenUsage.output.toLocaleString()],[`Reasoning`,c.tokenUsage.reasoning.toLocaleString()],[`Cache Read`,c.tokenUsage.cache.read.toLocaleString()],[`Cache Write`,c.tokenUsage.cache.write.toLocaleString()]]),c.model!=null&&S.addRaw(`**Model:** ${c.model}\n`),c.cost!=null&&S.addRaw(`**Cost:** $${c.cost.toFixed(4)}\n`)),(c.prsCreated.length>0||c.commitsCreated.length>0||c.commentsPosted>0)&&(S.addHeading(`Created Artifacts`,3),c.prsCreated.length>0&&S.addList([...c.prsCreated]),c.commitsCreated.length>0&&S.addList(c.commitsCreated.map(e=>`Commit \`${e.slice(0,7)}\``)),c.commentsPosted>0&&S.addRaw(`**Comments Posted:** ${c.commentsPosted}\n`)),c.errors.length>0){S.addHeading(`Errors`,3);for(let e of c.errors){let t=e.recoverable?`πŸ”„ Recovered`:`❌ Failed`;S.addRaw(`- **${e.type}** (${t}): ${e.message}\n`)}}await S.write(),t.debug(`Wrote job summary`)}catch(e){let n=M(e);t.warning(`Failed to write job summary`,{error:n}),s(`Failed to write job summary: ${n}`)}}function Ne(){let e=0,t=null,n=`miss`,r=[],i=[],a=[],o=[],s=0,c=null,l=null,u=null,d=[];return{start(){e=Date.now()},end(){t=Date.now()},setCacheStatus(e){n=e},addSessionUsed(e){r.includes(e)||r.push(e)},addSessionCreated(e){i.includes(e)||i.push(e)},addPRCreated(e){a.includes(e)||a.push(e)},addCommitCreated(e){o.includes(e)||o.push(e)},incrementComments(){s++},setTokenUsage(e,t,n){c=e,l=t,u=n},recordError(e,t,n){d.push({timestamp:new Date().toISOString(),type:e,message:t,recoverable:n})},getMetrics(){let f=t==null?Date.now()-e:t-e;return Object.freeze({startTime:e,endTime:t,duration:f,cacheStatus:n,sessionsUsed:Object.freeze([...r]),sessionsCreated:Object.freeze([...i]),prsCreated:Object.freeze([...a]),commitsCreated:Object.freeze([...o]),commentsPosted:s,tokenUsage:c,model:l,cost:u,errors:Object.freeze([...d])})}}}function V(e){y(`session-id`,e.sessionId??``),y(`cache-status`,e.cacheStatus),y(`duration`,e.duration)}function H(e){let[t,n]=e.split(`/`);if(t==null||n==null||t.length===0||n.length===0)throw Error(`Invalid repository string: ${e}`);return{owner:t,repo:n}}async function Pe(e,t,n,r,i){try{let{owner:a,repo:o}=H(t),{data:s}=await e.rest.reactions.createForIssueComment({owner:a,repo:o,comment_id:n,content:r});return i.debug(`Created comment reaction`,{commentId:n,content:r,reactionId:s.id}),{id:s.id}}catch(e){return i.warning(`Failed to create comment reaction`,{commentId:n,content:r,error:M(e)}),null}}async function Fe(e,t,n,r){try{let{owner:r,repo:i}=H(t),{data:a}=await e.rest.reactions.listForIssueComment({owner:r,repo:i,comment_id:n,per_page:100});return a.map(e=>({id:e.id,content:e.content,userLogin:e.user?.login??null}))}catch(e){return r.warning(`Failed to list comment reactions`,{commentId:n,error:M(e)}),[]}}async function Ie(e,t,n,r,i){try{let{owner:a,repo:o}=H(t);return await e.rest.reactions.deleteForIssueComment({owner:a,repo:o,comment_id:n,reaction_id:r}),i.debug(`Deleted comment reaction`,{commentId:n,reactionId:r}),!0}catch(e){return i.warning(`Failed to delete comment reaction`,{commentId:n,reactionId:r,error:M(e)}),!1}}async function Le(e,t,n,r,i,a){let{owner:o,repo:s}=H(t);try{return await e.rest.issues.createLabel({owner:o,repo:s,name:n,color:r,description:i}),a.debug(`Created label`,{name:n,color:r}),!0}catch(e){return e instanceof Error&&`status`in e&&e.status===422?(a.debug(`Label already exists`,{name:n}),!0):(a.warning(`Failed to create label`,{name:n,error:M(e)}),!1)}}async function Re(e,t,n,r,i){try{let{owner:a,repo:o}=H(t);return await e.rest.issues.addLabels({owner:a,repo:o,issue_number:n,labels:[...r]}),i.debug(`Added labels to issue`,{issueNumber:n,labels:r}),!0}catch(e){return i.warning(`Failed to add labels to issue`,{issueNumber:n,labels:r,error:M(e)}),!1}}async function ze(e,t,n,r,i){try{let{owner:a,repo:o}=H(t);return await e.rest.issues.removeLabel({owner:a,repo:o,issue_number:n,name:r}),i.debug(`Removed label from issue`,{issueNumber:n,label:r}),!0}catch(e){return e instanceof Error&&`status`in e&&e.status===404?(i.debug(`Label was not present on issue`,{issueNumber:n,label:r}),!0):(i.warning(`Failed to remove label from issue`,{issueNumber:n,label:r,error:M(e)}),!1)}}async function Be(e,t,n){try{let{owner:n,repo:r}=H(t),{data:i}=await e.rest.repos.get({owner:n,repo:r});return i.default_branch}catch(e){return n.warning(`Failed to get default branch`,{repo:t,error:M(e)}),`main`}}const Ve={admin:`OWNER`,maintain:`MEMBER`,write:`COLLABORATOR`,triage:`COLLABORATOR`};async function He(e,t,n,r,i){try{let{data:a}=await e.rest.repos.getCollaboratorPermissionLevel({owner:t,repo:n,username:r}),o=Ve[a.permission]??null;return i.debug(`Resolved sender permission`,{username:r,permission:a.permission,association:o}),o}catch(e){return i.warning(`Failed to resolve sender permission`,{username:r,error:M(e)}),null}}async function Ue(e,t,n){try{let{data:n}=await e.rest.users.getByUsername({username:t});return{id:n.id,login:n.login}}catch(e){return n.debug(`Failed to get user by username`,{username:t,error:M(e)}),null}}const We={maxComments:50,maxCommits:100,maxFiles:100,maxReviews:100,maxBodyBytes:10*1024,maxTotalBytes:100*1024},Ge=`…[truncated]`;function Ke(e,t){if(e.length===0)return{text:``,truncated:!1};let n=new TextEncoder,r=n.encode(e);if(r.length<=t)return{text:e,truncated:!1};let i=t-n.encode(Ge).length;if(i<=0)return{text:Ge,truncated:!0};let a=r.slice(0,i),o=new TextDecoder(`utf-8`,{fatal:!1}).decode(a);for(;o.length>0&&o.charCodeAt(o.length-1)===65533;)a=a.slice(0,-1),o=new TextDecoder(`utf-8`,{fatal:!1}).decode(a);return{text:o+Ge,truncated:!0}}function qe(e){return e.length===0?``:`**Labels:** ${e.map(e=>`\`${e.name}\``).join(`, `)}\n`}function Je(e){return e.length===0?``:`**Assignees:** ${e.map(e=>`@${e.login}`).join(`, `)}\n`}function Ye(e){let t=[];t.push(`## Issue #${e.number}`),t.push(``),t.push(`**Title:** ${e.title}`),t.push(`**State:** ${e.state}`),t.push(`**Author:** ${e.author??`unknown`}`),t.push(`**Created:** ${e.createdAt}`);let n=qe(e.labels);n.length>0&&t.push(n.trimEnd());let r=Je(e.assignees);if(r.length>0&&t.push(r.trimEnd()),t.push(``),t.push(`### Body`),t.push(``),t.push(e.body),e.bodyTruncated&&(t.push(``),t.push(`*Note: Body was truncated due to size limits.*`)),e.comments.length>0){t.push(``),t.push(`### Comments (${e.comments.length}${e.commentsTruncated?` of ${e.totalComments}`:``})`),e.commentsTruncated&&(t.push(``),t.push(`*Note: Comments were truncated due to limits.*`)),t.push(``);for(let n of e.comments)t.push(`**${n.author??`unknown`}** (${n.createdAt}):`),t.push(n.body),t.push(``)}return t.join(` -`)}function Xe(e){let t=[];t.push(`## Pull Request #${e.number}`),t.push(``),t.push(`**Title:** ${e.title}`),t.push(`**State:** ${e.state}`),t.push(`**Author:** ${e.author??`unknown`}`),t.push(`**Created:** ${e.createdAt}`),t.push(`**Base:** ${e.baseBranch} ← **Head:** ${e.headBranch}`),e.isFork&&t.push(`**Fork:** Yes (external contributor)`);let n=qe(e.labels);n.length>0&&t.push(n.trimEnd());let r=Je(e.assignees);if(r.length>0&&t.push(r.trimEnd()),t.push(``),t.push(`### Description`),t.push(``),t.push(e.body),e.bodyTruncated&&(t.push(``),t.push(`*Note: Description was truncated due to size limits.*`)),e.files.length>0){t.push(``),t.push(`### Files Changed (${e.files.length}${e.filesTruncated?` of ${e.totalFiles}`:``})`),t.push(``),t.push(`| File | +/- |`),t.push(`|------|-----|`);for(let n of e.files)t.push(`| \`${n.path}\` | +${n.additions}/-${n.deletions} |`)}if(e.commits.length>0){t.push(``),t.push(`### Commits (${e.commits.length}${e.commitsTruncated?` of ${e.totalCommits}`:``})`),t.push(``);for(let n of e.commits){let e=n.oid.slice(0,7);t.push(`- \`${e}\` ${n.message.split(` +import{A as e,B as t,C as n,D as r,E as i,F as a,G as o,H as s,J as c,K as l,L as u,M as d,N as f,O as p,P as m,R as h,S as g,T as _,U as v,V as y,W as b,X as x,Y as S,Z as C,_ as ee,a as w,b as T,c as E,d as te,f as D,g as O,h as k,i as ne,j as A,k as j,l as re,m as ie,n as ae,o as oe,p as se,q as ce,r as le,s as ue,t as de,u as fe,v as pe,w as me,x as he,y as ge,z as M}from"./artifact-DZtNN4TE.js";import N from"node:process";import*as _e from"os";import*as ve from"crypto";import*as P from"fs";import*as F from"path";import{ok as ye}from"assert";import*as be from"util";import{Buffer as xe}from"node:buffer";import*as Se from"node:crypto";import{createHash as Ce}from"node:crypto";import{pathToFileURL as we}from"node:url";import*as I from"node:fs/promises";import Te from"node:fs/promises";import*as L from"node:path";import Ee,{join as R}from"node:path";import{spawn as De}from"node:child_process";import*as Oe from"node:os";import ke,{homedir as Ae}from"node:os";import*as je from"stream";function Me(e){switch(e){case`hit`:return`βœ… hit`;case`miss`:return`πŸ†• miss`;case`corrupted`:return`⚠️ corrupted (clean start)`}}function Ne(e){let t=Math.round(e/1e3);return t<60?`${t}s`:`${Math.floor(t/60)}m ${t%60}s`}async function Pe(e,t){let{eventType:n,repo:r,ref:i,runId:a,runUrl:o,metrics:c,agent:l}=e;try{if(S.addHeading(`Fro Bot Agent Run`,2).addTable([[{data:`Field`,header:!0},{data:`Value`,header:!0}],[`Event`,n],[`Repository`,r],[`Ref`,i],[`Run ID`,`[${a}](${o})`],[`Agent`,l],[`Cache Status`,Me(c.cacheStatus)],[`Duration`,c.duration==null?`N/A`:Ne(c.duration)]]),(c.sessionsUsed.length>0||c.sessionsCreated.length>0)&&(S.addHeading(`Sessions`,3),c.sessionsUsed.length>0&&S.addRaw(`**Used:** ${c.sessionsUsed.join(`, `)}\n`),c.sessionsCreated.length>0&&S.addRaw(`**Created:** ${c.sessionsCreated.join(`, `)}\n`)),c.tokenUsage!=null&&(S.addHeading(`Token Usage`,3),S.addTable([[{data:`Metric`,header:!0},{data:`Count`,header:!0}],[`Input`,c.tokenUsage.input.toLocaleString()],[`Output`,c.tokenUsage.output.toLocaleString()],[`Reasoning`,c.tokenUsage.reasoning.toLocaleString()],[`Cache Read`,c.tokenUsage.cache.read.toLocaleString()],[`Cache Write`,c.tokenUsage.cache.write.toLocaleString()]]),c.model!=null&&S.addRaw(`**Model:** ${c.model}\n`),c.cost!=null&&S.addRaw(`**Cost:** $${c.cost.toFixed(4)}\n`)),(c.prsCreated.length>0||c.commitsCreated.length>0||c.commentsPosted>0)&&(S.addHeading(`Created Artifacts`,3),c.prsCreated.length>0&&S.addList([...c.prsCreated]),c.commitsCreated.length>0&&S.addList(c.commitsCreated.map(e=>`Commit \`${e.slice(0,7)}\``)),c.commentsPosted>0&&S.addRaw(`**Comments Posted:** ${c.commentsPosted}\n`)),c.errors.length>0){S.addHeading(`Errors`,3);for(let e of c.errors){let t=e.recoverable?`πŸ”„ Recovered`:`❌ Failed`;S.addRaw(`- **${e.type}** (${t}): ${e.message}\n`)}}await S.write(),t.debug(`Wrote job summary`)}catch(e){let n=A(e);t.warning(`Failed to write job summary`,{error:n}),s(`Failed to write job summary: ${n}`)}}function Fe(){let e=0,t=null,n=`miss`,r=[],i=[],a=[],o=[],s=0,c=null,l=null,u=null,d=[];return{start(){e=Date.now()},end(){t=Date.now()},setCacheStatus(e){n=e},addSessionUsed(e){r.includes(e)||r.push(e)},addSessionCreated(e){i.includes(e)||i.push(e)},addPRCreated(e){a.includes(e)||a.push(e)},addCommitCreated(e){o.includes(e)||o.push(e)},incrementComments(){s++},setTokenUsage(e,t,n){c=e,l=t,u=n},recordError(e,t,n){d.push({timestamp:new Date().toISOString(),type:e,message:t,recoverable:n})},getMetrics(){let f=t==null?Date.now()-e:t-e;return Object.freeze({startTime:e,endTime:t,duration:f,cacheStatus:n,sessionsUsed:Object.freeze([...r]),sessionsCreated:Object.freeze([...i]),prsCreated:Object.freeze([...a]),commitsCreated:Object.freeze([...o]),commentsPosted:s,tokenUsage:c,model:l,cost:u,errors:Object.freeze([...d])})}}}function z(e){y(`session-id`,e.sessionId??``),y(`cache-status`,e.cacheStatus),y(`duration`,e.duration)}function B(e){let[t,n]=e.split(`/`);if(t==null||n==null||t.length===0||n.length===0)throw Error(`Invalid repository string: ${e}`);return{owner:t,repo:n}}async function Ie(e,t,n,r,i){try{let{owner:a,repo:o}=B(t),{data:s}=await e.rest.reactions.createForIssueComment({owner:a,repo:o,comment_id:n,content:r});return i.debug(`Created comment reaction`,{commentId:n,content:r,reactionId:s.id}),{id:s.id}}catch(e){return i.warning(`Failed to create comment reaction`,{commentId:n,content:r,error:A(e)}),null}}async function Le(e,t,n,r){try{let{owner:r,repo:i}=B(t),{data:a}=await e.rest.reactions.listForIssueComment({owner:r,repo:i,comment_id:n,per_page:100});return a.map(e=>({id:e.id,content:e.content,userLogin:e.user?.login??null}))}catch(e){return r.warning(`Failed to list comment reactions`,{commentId:n,error:A(e)}),[]}}async function Re(e,t,n,r,i){try{let{owner:a,repo:o}=B(t);return await e.rest.reactions.deleteForIssueComment({owner:a,repo:o,comment_id:n,reaction_id:r}),i.debug(`Deleted comment reaction`,{commentId:n,reactionId:r}),!0}catch(e){return i.warning(`Failed to delete comment reaction`,{commentId:n,reactionId:r,error:A(e)}),!1}}async function ze(e,t,n,r,i,a){let{owner:o,repo:s}=B(t);try{return await e.rest.issues.createLabel({owner:o,repo:s,name:n,color:r,description:i}),a.debug(`Created label`,{name:n,color:r}),!0}catch(e){return e instanceof Error&&`status`in e&&e.status===422?(a.debug(`Label already exists`,{name:n}),!0):(a.warning(`Failed to create label`,{name:n,error:A(e)}),!1)}}async function Be(e,t,n,r,i){try{let{owner:a,repo:o}=B(t);return await e.rest.issues.addLabels({owner:a,repo:o,issue_number:n,labels:[...r]}),i.debug(`Added labels to issue`,{issueNumber:n,labels:r}),!0}catch(e){return i.warning(`Failed to add labels to issue`,{issueNumber:n,labels:r,error:A(e)}),!1}}async function Ve(e,t,n,r,i){try{let{owner:a,repo:o}=B(t);return await e.rest.issues.removeLabel({owner:a,repo:o,issue_number:n,name:r}),i.debug(`Removed label from issue`,{issueNumber:n,label:r}),!0}catch(e){return e instanceof Error&&`status`in e&&e.status===404?(i.debug(`Label was not present on issue`,{issueNumber:n,label:r}),!0):(i.warning(`Failed to remove label from issue`,{issueNumber:n,label:r,error:A(e)}),!1)}}async function He(e,t,n){try{let{owner:n,repo:r}=B(t),{data:i}=await e.rest.repos.get({owner:n,repo:r});return i.default_branch}catch(e){return n.warning(`Failed to get default branch`,{repo:t,error:A(e)}),`main`}}const Ue={admin:`OWNER`,maintain:`MEMBER`,write:`COLLABORATOR`,triage:`COLLABORATOR`};async function We(e,t,n,r,i){try{let{data:a}=await e.rest.repos.getCollaboratorPermissionLevel({owner:t,repo:n,username:r}),o=Ue[a.permission]??null;return i.debug(`Resolved sender permission`,{username:r,permission:a.permission,association:o}),o}catch(e){return i.warning(`Failed to resolve sender permission`,{username:r,error:A(e)}),null}}async function Ge(e,t,n){try{let{data:n}=await e.rest.users.getByUsername({username:t});return{id:n.id,login:n.login}}catch(e){return n.debug(`Failed to get user by username`,{username:t,error:A(e)}),null}}const Ke={maxComments:50,maxCommits:100,maxFiles:100,maxReviews:100,maxBodyBytes:10*1024,maxTotalBytes:100*1024},qe=`…[truncated]`;function V(e,t){if(e.length===0)return{text:``,truncated:!1};let n=new TextEncoder,r=n.encode(e);if(r.length<=t)return{text:e,truncated:!1};let i=t-n.encode(qe).length;if(i<=0)return{text:qe,truncated:!0};let a=r.slice(0,i),o=new TextDecoder(`utf-8`,{fatal:!1}).decode(a);for(;o.length>0&&o.charCodeAt(o.length-1)===65533;)a=a.slice(0,-1),o=new TextDecoder(`utf-8`,{fatal:!1}).decode(a);return{text:o+qe,truncated:!0}}function Je(e){return e.length===0?``:`**Labels:** ${e.map(e=>`\`${e.name}\``).join(`, `)}\n`}function Ye(e){return e.length===0?``:`**Assignees:** ${e.map(e=>`@${e.login}`).join(`, `)}\n`}function Xe(e){let t=[];t.push(`## Issue #${e.number}`),t.push(``),t.push(`**Title:** ${e.title}`),t.push(`**State:** ${e.state}`),t.push(`**Author:** ${e.author??`unknown`}`),t.push(`**Created:** ${e.createdAt}`);let n=Je(e.labels);n.length>0&&t.push(n.trimEnd());let r=Ye(e.assignees);if(r.length>0&&t.push(r.trimEnd()),t.push(``),t.push(`### Body`),t.push(``),t.push(e.body),e.bodyTruncated&&(t.push(``),t.push(`*Note: Body was truncated due to size limits.*`)),e.comments.length>0){t.push(``),t.push(`### Comments (${e.comments.length}${e.commentsTruncated?` of ${e.totalComments}`:``})`),e.commentsTruncated&&(t.push(``),t.push(`*Note: Comments were truncated due to limits.*`)),t.push(``);for(let n of e.comments)t.push(`**${n.author??`unknown`}** (${n.createdAt}):`),t.push(n.body),t.push(``)}return t.join(` +`)}function Ze(e){let t=[];t.push(`## Pull Request #${e.number}`),t.push(``),t.push(`**Title:** ${e.title}`),t.push(`**State:** ${e.state}`),t.push(`**Author:** ${e.author??`unknown`}`),t.push(`**Created:** ${e.createdAt}`),t.push(`**Base:** ${e.baseBranch} ← **Head:** ${e.headBranch}`),e.isFork&&t.push(`**Fork:** Yes (external contributor)`);let n=Je(e.labels);n.length>0&&t.push(n.trimEnd());let r=Ye(e.assignees);if(r.length>0&&t.push(r.trimEnd()),t.push(``),t.push(`### Description`),t.push(``),t.push(e.body),e.bodyTruncated&&(t.push(``),t.push(`*Note: Description was truncated due to size limits.*`)),e.files.length>0){t.push(``),t.push(`### Files Changed (${e.files.length}${e.filesTruncated?` of ${e.totalFiles}`:``})`),t.push(``),t.push(`| File | +/- |`),t.push(`|------|-----|`);for(let n of e.files)t.push(`| \`${n.path}\` | +${n.additions}/-${n.deletions} |`)}if(e.commits.length>0){t.push(``),t.push(`### Commits (${e.commits.length}${e.commitsTruncated?` of ${e.totalCommits}`:``})`),t.push(``);for(let n of e.commits){let e=n.oid.slice(0,7);t.push(`- \`${e}\` ${n.message.split(` `)[0]}`)}}if(e.reviews.length>0){t.push(``),t.push(`### Reviews (${e.reviews.length}${e.reviewsTruncated?` of ${e.totalReviews}`:``})`),t.push(``);for(let n of e.reviews)t.push(`**${n.author??`unknown`}** - ${n.state}`),n.body.length>0&&t.push(n.body),t.push(``)}if(e.comments.length>0){t.push(``),t.push(`### Comments (${e.comments.length}${e.commentsTruncated?` of ${e.totalComments}`:``})`),t.push(``);for(let n of e.comments)t.push(`**${n.author??`unknown`}** (${n.createdAt}):`),t.push(n.body),t.push(``)}return t.join(` -`)}function Ze(e){return e.type===`issue`?Ye(e):Xe(e)}async function Qe(e,t,n,r,i,a){try{let[a,o]=await Promise.all([e.rest.issues.get({owner:t,repo:n,issue_number:r}),e.rest.issues.listComments({owner:t,repo:n,issue_number:r,per_page:i.maxComments})]),s=a.data,c=Ke(s.body??``,i.maxBodyBytes),l=o.data.slice(0,i.maxComments).map(e=>({id:e.node_id??String(e.id),author:e.user?.login??null,body:e.body??``,createdAt:e.created_at,authorAssociation:e.author_association,isMinimized:!1})),u=(s.labels??[]).filter(e=>typeof e==`object`&&!!e&&`name`in e).map(e=>({name:e.name??``,color:e.color})),d=(s.assignees??[]).map(e=>({login:e?.login??``}));return{type:`issue`,number:s.number,title:s.title,body:c.text,bodyTruncated:c.truncated,state:s.state,author:s.user?.login??null,createdAt:s.created_at,labels:u,assignees:d,comments:l,commentsTruncated:o.data.length>=i.maxComments,totalComments:o.data.length}}catch(e){return a.warning(`REST issue fallback failed`,{owner:t,repo:n,number:r,error:M(e)}),null}}async function $e(e,t,n,r,i,a){try{let[o,s,c,l,u]=await Promise.all([e.rest.pulls.get({owner:t,repo:n,pull_number:r}),e.rest.pulls.listCommits({owner:t,repo:n,pull_number:r,per_page:i.maxCommits}),e.rest.pulls.listFiles({owner:t,repo:n,pull_number:r,per_page:i.maxFiles}),e.rest.pulls.listReviews({owner:t,repo:n,pull_number:r,per_page:i.maxReviews}),e.rest.issues.listComments({owner:t,repo:n,issue_number:r,per_page:i.maxComments})]),d=await e.rest.pulls.listRequestedReviewers({owner:t,repo:n,pull_number:r}).catch(e=>(a.warning(`Failed to fetch requested reviewers, defaulting to empty`,{owner:t,repo:n,number:r,error:M(e)}),{data:{users:[],teams:[]}})),f=o.data,p=Ke(f.body??``,i.maxBodyBytes),m=f.base.repo?.owner.login,h=f.head.repo?.owner.login,g=h==null||m!==h,_=u.data.slice(0,i.maxComments).map(e=>({id:e.node_id??String(e.id),author:e.user?.login??null,body:e.body??``,createdAt:e.created_at,authorAssociation:e.author_association,isMinimized:!1})),v=s.data.slice(0,i.maxCommits).map(e=>({oid:e.sha,message:e.commit.message,author:e.commit.author?.name??null})),y=c.data.slice(0,i.maxFiles).map(e=>({path:e.filename,additions:e.additions,deletions:e.deletions,status:e.status})),b=l.data.slice(0,i.maxReviews).map(e=>({author:e.user?.login??null,state:e.state,body:e.body??``,createdAt:e.submitted_at??``,comments:[]})),x=(f.labels??[]).map(e=>({name:e.name??``,color:e.color})),S=(f.assignees??[]).map(e=>({login:e?.login??``})),C=(d.data.users??[]).map(e=>e.login),w=(d.data.teams??[]).map(e=>e.name);return{type:`pull_request`,number:f.number,title:f.title,body:p.text,bodyTruncated:p.truncated,state:f.state,author:f.user?.login??null,createdAt:f.created_at,baseBranch:f.base.ref,headBranch:f.head.ref,isFork:g,labels:x,assignees:S,comments:_,commentsTruncated:u.data.length>=i.maxComments,totalComments:u.data.length,commits:v,commitsTruncated:s.data.length>=i.maxCommits,totalCommits:s.data.length,files:y,filesTruncated:c.data.length>=i.maxFiles,totalFiles:c.data.length,reviews:b,reviewsTruncated:l.data.length>=i.maxReviews,totalReviews:l.data.length,authorAssociation:f.author_association,requestedReviewers:C,requestedReviewerTeams:w}}catch(e){return a.warning(`REST pull request fallback failed`,{owner:t,repo:n,number:r,error:M(e)}),null}}async function et(e,t,n,r,i,a){try{return await e.graphql(` +`)}function Qe(e){return e.type===`issue`?Xe(e):Ze(e)}async function $e(e,t,n,r,i,a){try{let[a,o]=await Promise.all([e.rest.issues.get({owner:t,repo:n,issue_number:r}),e.rest.issues.listComments({owner:t,repo:n,issue_number:r,per_page:i.maxComments})]),s=a.data,c=V(s.body??``,i.maxBodyBytes),l=o.data.slice(0,i.maxComments).map(e=>({id:e.node_id??String(e.id),author:e.user?.login??null,body:e.body??``,createdAt:e.created_at,authorAssociation:e.author_association,isMinimized:!1})),u=(s.labels??[]).filter(e=>typeof e==`object`&&!!e&&`name`in e).map(e=>({name:e.name??``,color:e.color})),d=(s.assignees??[]).map(e=>({login:e?.login??``}));return{type:`issue`,number:s.number,title:s.title,body:c.text,bodyTruncated:c.truncated,state:s.state,author:s.user?.login??null,createdAt:s.created_at,labels:u,assignees:d,comments:l,commentsTruncated:o.data.length>=i.maxComments,totalComments:o.data.length}}catch(e){return a.warning(`REST issue fallback failed`,{owner:t,repo:n,number:r,error:A(e)}),null}}async function et(e,t,n,r,i,a){try{let[o,s,c,l,u]=await Promise.all([e.rest.pulls.get({owner:t,repo:n,pull_number:r}),e.rest.pulls.listCommits({owner:t,repo:n,pull_number:r,per_page:i.maxCommits}),e.rest.pulls.listFiles({owner:t,repo:n,pull_number:r,per_page:i.maxFiles}),e.rest.pulls.listReviews({owner:t,repo:n,pull_number:r,per_page:i.maxReviews}),e.rest.issues.listComments({owner:t,repo:n,issue_number:r,per_page:i.maxComments})]),d=await e.rest.pulls.listRequestedReviewers({owner:t,repo:n,pull_number:r}).catch(e=>(a.warning(`Failed to fetch requested reviewers, defaulting to empty`,{owner:t,repo:n,number:r,error:A(e)}),{data:{users:[],teams:[]}})),f=o.data,p=V(f.body??``,i.maxBodyBytes),m=f.base.repo?.owner.login,h=f.head.repo?.owner.login,g=h==null||m!==h,_=u.data.slice(0,i.maxComments).map(e=>({id:e.node_id??String(e.id),author:e.user?.login??null,body:e.body??``,createdAt:e.created_at,authorAssociation:e.author_association,isMinimized:!1})),v=s.data.slice(0,i.maxCommits).map(e=>({oid:e.sha,message:e.commit.message,author:e.commit.author?.name??null})),y=c.data.slice(0,i.maxFiles).map(e=>({path:e.filename,additions:e.additions,deletions:e.deletions,status:e.status})),b=l.data.slice(0,i.maxReviews).map(e=>({author:e.user?.login??null,state:e.state,body:e.body??``,createdAt:e.submitted_at??``,comments:[]})),x=(f.labels??[]).map(e=>({name:e.name??``,color:e.color})),S=(f.assignees??[]).map(e=>({login:e?.login??``})),C=(d.data.users??[]).map(e=>e.login),ee=(d.data.teams??[]).map(e=>e.name);return{type:`pull_request`,number:f.number,title:f.title,body:p.text,bodyTruncated:p.truncated,state:f.state,author:f.user?.login??null,createdAt:f.created_at,baseBranch:f.base.ref,headBranch:f.head.ref,isFork:g,labels:x,assignees:S,comments:_,commentsTruncated:u.data.length>=i.maxComments,totalComments:u.data.length,commits:v,commitsTruncated:s.data.length>=i.maxCommits,totalCommits:s.data.length,files:y,filesTruncated:c.data.length>=i.maxFiles,totalFiles:c.data.length,reviews:b,reviewsTruncated:l.data.length>=i.maxReviews,totalReviews:l.data.length,authorAssociation:f.author_association,requestedReviewers:C,requestedReviewerTeams:ee}}catch(e){return a.warning(`REST pull request fallback failed`,{owner:t,repo:n,number:r,error:A(e)}),null}}async function tt(e,t,n,r,i,a){try{return await e.graphql(` query GetIssue($owner: String!, $repo: String!, $number: Int!, $maxComments: Int!) { repository(owner: $owner, name: $repo) { issue(number: $number) { @@ -31,7 +31,7 @@ import{A as e,B as t,C as n,D as r,E as i,F as a,G as o,H as s,J as c,K as l,L a } } } -`,{owner:t,repo:n,number:r,maxComments:i})}catch(e){return a.warning(`GraphQL issue query failed`,{owner:t,repo:n,number:r,error:M(e)}),null}}async function tt(e,t,n,r,i,a,o,s,c){try{return await e.graphql(` +`,{owner:t,repo:n,number:r,maxComments:i})}catch(e){return a.warning(`GraphQL issue query failed`,{owner:t,repo:n,number:r,error:A(e)}),null}}async function nt(e,t,n,r,i,a,o,s,c){try{return await e.graphql(` query GetPullRequest( $owner: String!, $repo: String!, @@ -119,13 +119,13 @@ import{A as e,B as t,C as n,D as r,E as i,F as a,G as o,H as s,J as c,K as l,L a } } } -`,{owner:t,repo:n,number:r,maxComments:i,maxCommits:a,maxFiles:o,maxReviews:s})}catch(e){return c.warning(`GraphQL pull request query failed`,{owner:t,repo:n,number:r,error:M(e)}),null}}async function nt(e,t,n,r,i,a){let o=await et(e,t,n,r,i.maxComments,a);if(o==null)return null;let s=o.repository.issue;if(s==null)return a.debug(`Issue not found`,{owner:t,repo:n,number:r}),null;let c=Ke(s.body??``,i.maxBodyBytes),l=s.comments.nodes.slice(0,i.maxComments),u=s.comments.totalCount>l.length,d=l.map(e=>({id:e.id,author:e.author?.login??null,body:e.body,createdAt:e.createdAt,authorAssociation:e.authorAssociation,isMinimized:e.isMinimized})),f=s.labels.nodes.map(e=>({name:e.name,color:e.color})),p=s.assignees.nodes.map(e=>({login:e.login}));return{type:`issue`,number:s.number,title:s.title,body:c.text,bodyTruncated:c.truncated,state:s.state,author:s.author?.login??null,createdAt:s.createdAt,labels:f,assignees:p,comments:d,commentsTruncated:u,totalComments:s.comments.totalCount}}async function rt(e,t,n,r,i,a){let o=await tt(e,t,n,r,i.maxComments,i.maxCommits,i.maxFiles,i.maxReviews,a);if(o==null)return null;let s=o.repository.pullRequest;if(s==null)return a.debug(`Pull request not found`,{owner:t,repo:n,number:r}),null;let c=Ke(s.body??``,i.maxBodyBytes),l=s.baseRepository?.owner.login,u=s.headRepository?.owner.login,d=u==null||l!==u,f=s.comments.nodes.slice(0,i.maxComments),p=s.comments.totalCount>f.length,m=f.map(e=>({id:e.id,author:e.author?.login??null,body:e.body,createdAt:e.createdAt,authorAssociation:e.authorAssociation,isMinimized:e.isMinimized})),h=s.commits.nodes.slice(0,i.maxCommits),g=s.commits.totalCount>h.length,_=h.map(e=>({oid:e.commit.oid,message:e.commit.message,author:e.commit.author?.name??null})),v=s.files.nodes.slice(0,i.maxFiles),y=s.files.totalCount>v.length,b=v.map(e=>({path:e.path,additions:e.additions,deletions:e.deletions})),x=s.reviews.nodes.slice(0,i.maxReviews),S=s.reviews.totalCount>x.length,C=x.map(e=>({author:e.author?.login??null,state:e.state,body:e.body,createdAt:e.createdAt,comments:e.comments.nodes.map(e=>({id:e.id,author:e.author?.login??null,body:e.body,path:e.path,line:e.line,createdAt:e.createdAt}))})),w=s.labels.nodes.map(e=>({name:e.name,color:e.color})),T=s.assignees.nodes.map(e=>({login:e.login})),E=s.reviewRequests.nodes.map(e=>`login`in e.requestedReviewer?e.requestedReviewer.login:null).filter(e=>e!=null),D=s.reviewRequests.nodes.map(e=>`name`in e.requestedReviewer?e.requestedReviewer.name:null).filter(e=>e!=null);return{type:`pull_request`,number:s.number,title:s.title,body:c.text,bodyTruncated:c.truncated,state:s.state,author:s.author?.login??null,createdAt:s.createdAt,baseBranch:s.baseRefName,headBranch:s.headRefName,isFork:d,labels:w,assignees:T,comments:m,commentsTruncated:p,totalComments:s.comments.totalCount,commits:_,commitsTruncated:g,totalCommits:s.commits.totalCount,files:b,filesTruncated:y,totalFiles:s.files.totalCount,reviews:C,reviewsTruncated:S,totalReviews:s.reviews.totalCount,authorAssociation:s.authorAssociation,requestedReviewers:E,requestedReviewerTeams:D}}const U={PER_PAGE:100,MAX_PAGES:50};async function it(e,t,n,r,i){i.debug(`Fetching PR diff`,{prNumber:r});let a=[],o=1,s=!1;for(;o<=U.MAX_PAGES;){let{data:c}=await e.rest.pulls.listFiles({owner:t,repo:n,pull_number:r,per_page:U.PER_PAGE,page:o}),l=c.map(e=>({filename:e.filename,status:e.status,additions:e.additions,deletions:e.deletions,patch:e.patch??null,previousFilename:e.previous_filename??null}));if(a.push(...l),c.lengthU.MAX_PAGES&&(s=!0,i.warning(`PR diff pagination limit reached`,{filesLoaded:a.length,maxPages:U.MAX_PAGES}))}let c=a.reduce((e,t)=>({additions:e.additions+t.additions,deletions:e.deletions+t.deletions}),{additions:0,deletions:0});return i.debug(`Fetched diff`,{files:a.length,additions:c.additions,deletions:c.deletions,truncated:s}),{files:a,additions:c.additions,deletions:c.deletions,changedFiles:a.length,truncated:s}}async function at(e,t,n,r){if(e.eventType!==`pull_request`)return null;let i=e.target?.number;if(i==null)return r.debug(`No PR number in trigger context, skipping diff collection`),null;let[a,o]=n.split(`/`);if(a==null||o==null)return r.warning(`Invalid repo format, skipping diff collection`,{repo:n}),null;try{let e=await it(t,a,o,i,r),n={changedFiles:e.changedFiles,additions:e.additions,deletions:e.deletions,truncated:e.truncated,files:e.files.slice(0,50).map(e=>({filename:e.filename,status:e.status,additions:e.additions,deletions:e.deletions}))};return r.debug(`Collected diff context`,{files:n.changedFiles,additions:n.additions,deletions:n.deletions,truncated:n.truncated}),n}catch(e){return r.warning(`Failed to fetch PR diff`,{error:M(e)}),null}}async function ot(e){let{logger:t,octokit:n,triggerContext:r,botLogin:i}=e,{repo:a,ref:o,actor:s,runId:c,target:l,author:u,commentBody:d,commentId:f}=r,p=`${a.owner}/${a.repo}`,m=l?.kind===`issue`||l?.kind===`pr`?l.kind:null,h=l?.number??null,g=l?.title??null,_=u?.login??null,v=await at(r,n,p,t),y=await st(n,a.owner,a.repo,h,m,t),b=y?.type===`pull_request`?y:null,x=b?.authorAssociation??null,S=i!=null&&b!=null?b.requestedReviewers.includes(i):!1;return t.info(`Collected agent context`,{eventName:r.eventName,repo:p,issueNumber:h,issueType:m,hasComment:d!=null,hasDiffContext:v!=null,hasHydratedContext:y!=null}),{eventName:r.eventName,repo:p,ref:o,actor:s,runId:String(c),issueNumber:h,issueTitle:g,issueType:m,commentBody:d,commentAuthor:_,commentId:f,defaultBranch:await Be(n,p,t),diffContext:v,hydratedContext:y,authorAssociation:x,isRequestedReviewer:S}}async function st(e,t,n,r,i,a){if(r==null||i==null)return null;let o=We;return i===`issue`?await nt(e,t,n,r,o,a)??Qe(e,t,n,r,o,a):await rt(e,t,n,r,o,a)??$e(e,t,n,r,o,a)}const ct=({onSseError:e,onSseEvent:t,responseTransformer:n,responseValidator:r,sseDefaultRetryDelay:i,sseMaxRetryAttempts:a,sseMaxRetryDelay:o,sseSleepFn:s,url:c,...l})=>{let u,d=s??(e=>new Promise(t=>setTimeout(t,e)));return{stream:async function*(){let s=i??3e3,f=0,p=l.signal??new AbortController().signal;for(;!p.aborted;){f++;let i=l.headers instanceof Headers?l.headers:new Headers(l.headers);u!==void 0&&i.set(`Last-Event-ID`,u);try{let e=await fetch(c,{...l,headers:i,signal:p});if(!e.ok)throw Error(`SSE failed: ${e.status} ${e.statusText}`);if(!e.body)throw Error(`No body in SSE response`);let a=e.body.pipeThrough(new TextDecoderStream).getReader(),o=``,d=()=>{try{a.cancel()}catch{}};p.addEventListener(`abort`,d);try{for(;;){let{done:e,value:i}=await a.read();if(e)break;o+=i;let c=o.split(` +`,{owner:t,repo:n,number:r,maxComments:i,maxCommits:a,maxFiles:o,maxReviews:s})}catch(e){return c.warning(`GraphQL pull request query failed`,{owner:t,repo:n,number:r,error:A(e)}),null}}async function rt(e,t,n,r,i,a){let o=await tt(e,t,n,r,i.maxComments,a);if(o==null)return null;let s=o.repository.issue;if(s==null)return a.debug(`Issue not found`,{owner:t,repo:n,number:r}),null;let c=V(s.body??``,i.maxBodyBytes),l=s.comments.nodes.slice(0,i.maxComments),u=s.comments.totalCount>l.length,d=l.map(e=>({id:e.id,author:e.author?.login??null,body:e.body,createdAt:e.createdAt,authorAssociation:e.authorAssociation,isMinimized:e.isMinimized})),f=s.labels.nodes.map(e=>({name:e.name,color:e.color})),p=s.assignees.nodes.map(e=>({login:e.login}));return{type:`issue`,number:s.number,title:s.title,body:c.text,bodyTruncated:c.truncated,state:s.state,author:s.author?.login??null,createdAt:s.createdAt,labels:f,assignees:p,comments:d,commentsTruncated:u,totalComments:s.comments.totalCount}}async function it(e,t,n,r,i,a){let o=await nt(e,t,n,r,i.maxComments,i.maxCommits,i.maxFiles,i.maxReviews,a);if(o==null)return null;let s=o.repository.pullRequest;if(s==null)return a.debug(`Pull request not found`,{owner:t,repo:n,number:r}),null;let c=V(s.body??``,i.maxBodyBytes),l=s.baseRepository?.owner.login,u=s.headRepository?.owner.login,d=u==null||l!==u,f=s.comments.nodes.slice(0,i.maxComments),p=s.comments.totalCount>f.length,m=f.map(e=>({id:e.id,author:e.author?.login??null,body:e.body,createdAt:e.createdAt,authorAssociation:e.authorAssociation,isMinimized:e.isMinimized})),h=s.commits.nodes.slice(0,i.maxCommits),g=s.commits.totalCount>h.length,_=h.map(e=>({oid:e.commit.oid,message:e.commit.message,author:e.commit.author?.name??null})),v=s.files.nodes.slice(0,i.maxFiles),y=s.files.totalCount>v.length,b=v.map(e=>({path:e.path,additions:e.additions,deletions:e.deletions})),x=s.reviews.nodes.slice(0,i.maxReviews),S=s.reviews.totalCount>x.length,C=x.map(e=>({author:e.author?.login??null,state:e.state,body:e.body,createdAt:e.createdAt,comments:e.comments.nodes.map(e=>({id:e.id,author:e.author?.login??null,body:e.body,path:e.path,line:e.line,createdAt:e.createdAt}))})),ee=s.labels.nodes.map(e=>({name:e.name,color:e.color})),w=s.assignees.nodes.map(e=>({login:e.login})),T=s.reviewRequests.nodes.map(e=>`login`in e.requestedReviewer?e.requestedReviewer.login:null).filter(e=>e!=null),E=s.reviewRequests.nodes.map(e=>`name`in e.requestedReviewer?e.requestedReviewer.name:null).filter(e=>e!=null);return{type:`pull_request`,number:s.number,title:s.title,body:c.text,bodyTruncated:c.truncated,state:s.state,author:s.author?.login??null,createdAt:s.createdAt,baseBranch:s.baseRefName,headBranch:s.headRefName,isFork:d,labels:ee,assignees:w,comments:m,commentsTruncated:p,totalComments:s.comments.totalCount,commits:_,commitsTruncated:g,totalCommits:s.commits.totalCount,files:b,filesTruncated:y,totalFiles:s.files.totalCount,reviews:C,reviewsTruncated:S,totalReviews:s.reviews.totalCount,authorAssociation:s.authorAssociation,requestedReviewers:T,requestedReviewerTeams:E}}const H={PER_PAGE:100,MAX_PAGES:50};async function at(e,t,n,r,i){i.debug(`Fetching PR diff`,{prNumber:r});let a=[],o=1,s=!1;for(;o<=H.MAX_PAGES;){let{data:c}=await e.rest.pulls.listFiles({owner:t,repo:n,pull_number:r,per_page:H.PER_PAGE,page:o}),l=c.map(e=>({filename:e.filename,status:e.status,additions:e.additions,deletions:e.deletions,patch:e.patch??null,previousFilename:e.previous_filename??null}));if(a.push(...l),c.lengthH.MAX_PAGES&&(s=!0,i.warning(`PR diff pagination limit reached`,{filesLoaded:a.length,maxPages:H.MAX_PAGES}))}let c=a.reduce((e,t)=>({additions:e.additions+t.additions,deletions:e.deletions+t.deletions}),{additions:0,deletions:0});return i.debug(`Fetched diff`,{files:a.length,additions:c.additions,deletions:c.deletions,truncated:s}),{files:a,additions:c.additions,deletions:c.deletions,changedFiles:a.length,truncated:s}}async function ot(e,t,n,r){if(e.eventType!==`pull_request`)return null;let i=e.target?.number;if(i==null)return r.debug(`No PR number in trigger context, skipping diff collection`),null;let[a,o]=n.split(`/`);if(a==null||o==null)return r.warning(`Invalid repo format, skipping diff collection`,{repo:n}),null;try{let e=await at(t,a,o,i,r),n={changedFiles:e.changedFiles,additions:e.additions,deletions:e.deletions,truncated:e.truncated,files:e.files.slice(0,50).map(e=>({filename:e.filename,status:e.status,additions:e.additions,deletions:e.deletions}))};return r.debug(`Collected diff context`,{files:n.changedFiles,additions:n.additions,deletions:n.deletions,truncated:n.truncated}),n}catch(e){return r.warning(`Failed to fetch PR diff`,{error:A(e)}),null}}async function st(e){let{logger:t,octokit:n,triggerContext:r,botLogin:i}=e,{repo:a,ref:o,actor:s,runId:c,target:l,author:u,commentBody:d,commentId:f}=r,p=`${a.owner}/${a.repo}`,m=l?.kind===`issue`||l?.kind===`pr`?l.kind:null,h=l?.number??null,g=l?.title??null,_=u?.login??null,v=await ot(r,n,p,t),y=await ct(n,a.owner,a.repo,h,m,t),b=y?.type===`pull_request`?y:null,x=b?.authorAssociation??null,S=i!=null&&b!=null?b.requestedReviewers.includes(i):!1;return t.info(`Collected agent context`,{eventName:r.eventName,repo:p,issueNumber:h,issueType:m,hasComment:d!=null,hasDiffContext:v!=null,hasHydratedContext:y!=null}),{eventName:r.eventName,repo:p,ref:o,actor:s,runId:String(c),issueNumber:h,issueTitle:g,issueType:m,commentBody:d,commentAuthor:_,commentId:f,defaultBranch:await He(n,p,t),diffContext:v,hydratedContext:y,authorAssociation:x,isRequestedReviewer:S}}async function ct(e,t,n,r,i,a){if(r==null||i==null)return null;let o=Ke;return i===`issue`?await rt(e,t,n,r,o,a)??$e(e,t,n,r,o,a):await it(e,t,n,r,o,a)??et(e,t,n,r,o,a)}const lt=({onSseError:e,onSseEvent:t,responseTransformer:n,responseValidator:r,sseDefaultRetryDelay:i,sseMaxRetryAttempts:a,sseMaxRetryDelay:o,sseSleepFn:s,url:c,...l})=>{let u,d=s??(e=>new Promise(t=>setTimeout(t,e)));return{stream:async function*(){let s=i??3e3,f=0,p=l.signal??new AbortController().signal;for(;!p.aborted;){f++;let i=l.headers instanceof Headers?l.headers:new Headers(l.headers);u!==void 0&&i.set(`Last-Event-ID`,u);try{let e=await fetch(c,{...l,headers:i,signal:p});if(!e.ok)throw Error(`SSE failed: ${e.status} ${e.statusText}`);if(!e.body)throw Error(`No body in SSE response`);let a=e.body.pipeThrough(new TextDecoderStream).getReader(),o=``,d=()=>{try{a.cancel()}catch{}};p.addEventListener(`abort`,d);try{for(;;){let{done:e,value:i}=await a.read();if(e)break;o+=i;let c=o.split(` `);o=c.pop()??``;for(let e of c){let i=e.split(` `),a=[],o;for(let e of i)if(e.startsWith(`data:`))a.push(e.replace(/^data:\s*/,``));else if(e.startsWith(`event:`))o=e.replace(/^event:\s*/,``);else if(e.startsWith(`id:`))u=e.replace(/^id:\s*/,``);else if(e.startsWith(`retry:`)){let t=Number.parseInt(e.replace(/^retry:\s*/,``),10);Number.isNaN(t)||(s=t)}let c,l=!1;if(a.length){let e=a.join(` -`);try{c=JSON.parse(e),l=!0}catch{c=e}}l&&(r&&await r(c),n&&(c=await n(c))),t?.({data:c,event:o,id:u,retry:s}),a.length&&(yield c)}}}finally{p.removeEventListener(`abort`,d),a.releaseLock()}break}catch(t){if(e?.(t),a!==void 0&&f>=a)break;await d(Math.min(s*2**(f-1),o??3e4))}}}()}},lt=async(e,t)=>{let n=typeof t==`function`?await t(e):t;if(n)return e.scheme===`bearer`?`Bearer ${n}`:e.scheme===`basic`?`Basic ${btoa(n)}`:n},ut={bodySerializer:e=>JSON.stringify(e,(e,t)=>typeof t==`bigint`?t.toString():t)},dt=e=>{switch(e){case`label`:return`.`;case`matrix`:return`;`;case`simple`:return`,`;default:return`&`}},ft=e=>{switch(e){case`form`:return`,`;case`pipeDelimited`:return`|`;case`spaceDelimited`:return`%20`;default:return`,`}},pt=e=>{switch(e){case`label`:return`.`;case`matrix`:return`;`;case`simple`:return`,`;default:return`&`}},mt=({allowReserved:e,explode:t,name:n,style:r,value:i})=>{if(!t){let t=(e?i:i.map(e=>encodeURIComponent(e))).join(ft(r));switch(r){case`label`:return`.${t}`;case`matrix`:return`;${n}=${t}`;case`simple`:return t;default:return`${n}=${t}`}}let a=dt(r),o=i.map(t=>r===`label`||r===`simple`?e?t:encodeURIComponent(t):ht({allowReserved:e,name:n,value:t})).join(a);return r===`label`||r===`matrix`?a+o:o},ht=({allowReserved:e,name:t,value:n})=>{if(n==null)return``;if(typeof n==`object`)throw Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");return`${t}=${e?n:encodeURIComponent(n)}`},gt=({allowReserved:e,explode:t,name:n,style:r,value:i,valueOnly:a})=>{if(i instanceof Date)return a?i.toISOString():`${n}=${i.toISOString()}`;if(r!==`deepObject`&&!t){let t=[];Object.entries(i).forEach(([n,r])=>{t=[...t,n,e?r:encodeURIComponent(r)]});let a=t.join(`,`);switch(r){case`form`:return`${n}=${a}`;case`label`:return`.${a}`;case`matrix`:return`;${n}=${a}`;default:return a}}let o=pt(r),s=Object.entries(i).map(([t,i])=>ht({allowReserved:e,name:r===`deepObject`?`${n}[${t}]`:t,value:i})).join(o);return r===`label`||r===`matrix`?o+s:s},_t=/\{[^{}]+\}/g,vt=({path:e,url:t})=>{let n=t,r=t.match(_t);if(r)for(let t of r){let r=!1,i=t.substring(1,t.length-1),a=`simple`;i.endsWith(`*`)&&(r=!0,i=i.substring(0,i.length-1)),i.startsWith(`.`)?(i=i.substring(1),a=`label`):i.startsWith(`;`)&&(i=i.substring(1),a=`matrix`);let o=e[i];if(o==null)continue;if(Array.isArray(o)){n=n.replace(t,mt({explode:r,name:i,style:a,value:o}));continue}if(typeof o==`object`){n=n.replace(t,gt({explode:r,name:i,style:a,value:o,valueOnly:!0}));continue}if(a===`matrix`){n=n.replace(t,`;${ht({name:i,value:o})}`);continue}let s=encodeURIComponent(a===`label`?`.${o}`:o);n=n.replace(t,s)}return n},yt=({baseUrl:e,path:t,query:n,querySerializer:r,url:i})=>{let a=i.startsWith(`/`)?i:`/${i}`,o=(e??``)+a;t&&(o=vt({path:t,url:o}));let s=n?r(n):``;return s.startsWith(`?`)&&(s=s.substring(1)),s&&(o+=`?${s}`),o},bt=({allowReserved:e,array:t,object:n}={})=>r=>{let i=[];if(r&&typeof r==`object`)for(let a in r){let o=r[a];if(o!=null)if(Array.isArray(o)){let n=mt({allowReserved:e,explode:!0,name:a,style:`form`,value:o,...t});n&&i.push(n)}else if(typeof o==`object`){let t=gt({allowReserved:e,explode:!0,name:a,style:`deepObject`,value:o,...n});t&&i.push(t)}else{let t=ht({allowReserved:e,name:a,value:o});t&&i.push(t)}}return i.join(`&`)},xt=e=>{if(!e)return`stream`;let t=e.split(`;`)[0]?.trim();if(t){if(t.startsWith(`application/json`)||t.endsWith(`+json`))return`json`;if(t===`multipart/form-data`)return`formData`;if([`application/`,`audio/`,`image/`,`video/`].some(e=>t.startsWith(e)))return`blob`;if(t.startsWith(`text/`))return`text`}},St=(e,t)=>t?!!(e.headers.has(t)||e.query?.[t]||e.headers.get(`Cookie`)?.includes(`${t}=`)):!1,Ct=async({security:e,...t})=>{for(let n of e){if(St(t,n.name))continue;let e=await lt(n,t.auth);if(!e)continue;let r=n.name??`Authorization`;switch(n.in){case`query`:t.query||={},t.query[r]=e;break;case`cookie`:t.headers.append(`Cookie`,`${r}=${e}`);break;default:t.headers.set(r,e);break}}},wt=e=>yt({baseUrl:e.baseUrl,path:e.path,query:e.query,querySerializer:typeof e.querySerializer==`function`?e.querySerializer:bt(e.querySerializer),url:e.url}),Tt=(e,t)=>{let n={...e,...t};return n.baseUrl?.endsWith(`/`)&&(n.baseUrl=n.baseUrl.substring(0,n.baseUrl.length-1)),n.headers=Et(e.headers,t.headers),n},Et=(...e)=>{let t=new Headers;for(let n of e){if(!n||typeof n!=`object`)continue;let e=n instanceof Headers?n.entries():Object.entries(n);for(let[n,r]of e)if(r===null)t.delete(n);else if(Array.isArray(r))for(let e of r)t.append(n,e);else r!==void 0&&t.set(n,typeof r==`object`?JSON.stringify(r):r)}return t};var Dt=class{_fns;constructor(){this._fns=[]}clear(){this._fns=[]}getInterceptorIndex(e){return typeof e==`number`?this._fns[e]?e:-1:this._fns.indexOf(e)}exists(e){let t=this.getInterceptorIndex(e);return!!this._fns[t]}eject(e){let t=this.getInterceptorIndex(e);this._fns[t]&&(this._fns[t]=null)}update(e,t){let n=this.getInterceptorIndex(e);return this._fns[n]?(this._fns[n]=t,e):!1}use(e){return this._fns=[...this._fns,e],this._fns.length-1}};const Ot=()=>({error:new Dt,request:new Dt,response:new Dt}),kt=bt({allowReserved:!1,array:{explode:!0,style:`form`},object:{explode:!0,style:`deepObject`}}),At={"Content-Type":`application/json`},jt=(e={})=>({...ut,headers:At,parseAs:`auto`,querySerializer:kt,...e}),Mt=(e={})=>{let t=Tt(jt(),e),n=()=>({...t}),r=e=>(t=Tt(t,e),n()),i=Ot(),a=async e=>{let n={...t,...e,fetch:e.fetch??t.fetch??globalThis.fetch,headers:Et(t.headers,e.headers),serializedBody:void 0};return n.security&&await Ct({...n,security:n.security}),n.requestValidator&&await n.requestValidator(n),n.body&&n.bodySerializer&&(n.serializedBody=n.bodySerializer(n.body)),(n.serializedBody===void 0||n.serializedBody===``)&&n.headers.delete(`Content-Type`),{opts:n,url:wt(n)}},o=async e=>{let{opts:t,url:n}=await a(e),r={redirect:`follow`,...t,body:t.serializedBody},o=new Request(n,r);for(let e of i.request._fns)e&&(o=await e(o,t));let s=t.fetch,c=await s(o);for(let e of i.response._fns)e&&(c=await e(c,o,t));let l={request:o,response:c};if(c.ok){if(c.status===204||c.headers.get(`Content-Length`)===`0`)return t.responseStyle===`data`?{}:{data:{},...l};let e=(t.parseAs===`auto`?xt(c.headers.get(`Content-Type`)):t.parseAs)??`json`,n;switch(e){case`arrayBuffer`:case`blob`:case`formData`:case`json`:case`text`:n=await c[e]();break;case`stream`:return t.responseStyle===`data`?c.body:{data:c.body,...l}}return e===`json`&&(t.responseValidator&&await t.responseValidator(n),t.responseTransformer&&(n=await t.responseTransformer(n))),t.responseStyle===`data`?n:{data:n,...l}}let u=await c.text(),d;try{d=JSON.parse(u)}catch{}let f=d??u,p=f;for(let e of i.error._fns)e&&(p=await e(f,c,o,t));if(p||={},t.throwOnError)throw p;return t.responseStyle===`data`?void 0:{error:p,...l}},s=e=>{let t=t=>o({...t,method:e});return t.sse=async t=>{let{opts:n,url:r}=await a(t);return ct({...n,body:n.body,headers:n.headers,method:e,url:r})},t};return{buildUrl:wt,connect:s(`CONNECT`),delete:s(`DELETE`),get:s(`GET`),getConfig:n,head:s(`HEAD`),interceptors:i,options:s(`OPTIONS`),patch:s(`PATCH`),post:s(`POST`),put:s(`PUT`),request:o,setConfig:r,trace:s(`TRACE`)}};Object.entries({$body_:`body`,$headers_:`headers`,$path_:`path`,$query_:`query`});const Nt=Mt(jt({baseUrl:`http://localhost:4096`}));var W=class{_client=Nt;constructor(e){e?.client&&(this._client=e.client)}},Pt=class extends W{event(e){return(e?.client??this._client).get.sse({url:`/global/event`,...e})}},Ft=class extends W{list(e){return(e?.client??this._client).get({url:`/project`,...e})}current(e){return(e?.client??this._client).get({url:`/project/current`,...e})}},It=class extends W{list(e){return(e?.client??this._client).get({url:`/pty`,...e})}create(e){return(e?.client??this._client).post({url:`/pty`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}remove(e){return(e.client??this._client).delete({url:`/pty/{id}`,...e})}get(e){return(e.client??this._client).get({url:`/pty/{id}`,...e})}update(e){return(e.client??this._client).put({url:`/pty/{id}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}connect(e){return(e.client??this._client).get({url:`/pty/{id}/connect`,...e})}},Lt=class extends W{get(e){return(e?.client??this._client).get({url:`/config`,...e})}update(e){return(e?.client??this._client).patch({url:`/config`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}providers(e){return(e?.client??this._client).get({url:`/config/providers`,...e})}},Rt=class extends W{ids(e){return(e?.client??this._client).get({url:`/experimental/tool/ids`,...e})}list(e){return(e.client??this._client).get({url:`/experimental/tool`,...e})}},zt=class extends W{dispose(e){return(e?.client??this._client).post({url:`/instance/dispose`,...e})}},Bt=class extends W{get(e){return(e?.client??this._client).get({url:`/path`,...e})}},Vt=class extends W{get(e){return(e?.client??this._client).get({url:`/vcs`,...e})}},Ht=class extends W{list(e){return(e?.client??this._client).get({url:`/session`,...e})}create(e){return(e?.client??this._client).post({url:`/session`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}status(e){return(e?.client??this._client).get({url:`/session/status`,...e})}delete(e){return(e.client??this._client).delete({url:`/session/{id}`,...e})}get(e){return(e.client??this._client).get({url:`/session/{id}`,...e})}update(e){return(e.client??this._client).patch({url:`/session/{id}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}children(e){return(e.client??this._client).get({url:`/session/{id}/children`,...e})}todo(e){return(e.client??this._client).get({url:`/session/{id}/todo`,...e})}init(e){return(e.client??this._client).post({url:`/session/{id}/init`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}fork(e){return(e.client??this._client).post({url:`/session/{id}/fork`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}abort(e){return(e.client??this._client).post({url:`/session/{id}/abort`,...e})}unshare(e){return(e.client??this._client).delete({url:`/session/{id}/share`,...e})}share(e){return(e.client??this._client).post({url:`/session/{id}/share`,...e})}diff(e){return(e.client??this._client).get({url:`/session/{id}/diff`,...e})}summarize(e){return(e.client??this._client).post({url:`/session/{id}/summarize`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}messages(e){return(e.client??this._client).get({url:`/session/{id}/message`,...e})}prompt(e){return(e.client??this._client).post({url:`/session/{id}/message`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}message(e){return(e.client??this._client).get({url:`/session/{id}/message/{messageID}`,...e})}promptAsync(e){return(e.client??this._client).post({url:`/session/{id}/prompt_async`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}command(e){return(e.client??this._client).post({url:`/session/{id}/command`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}shell(e){return(e.client??this._client).post({url:`/session/{id}/shell`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}revert(e){return(e.client??this._client).post({url:`/session/{id}/revert`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}unrevert(e){return(e.client??this._client).post({url:`/session/{id}/unrevert`,...e})}},Ut=class extends W{list(e){return(e?.client??this._client).get({url:`/command`,...e})}},Wt=class extends W{authorize(e){return(e.client??this._client).post({url:`/provider/{id}/oauth/authorize`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}callback(e){return(e.client??this._client).post({url:`/provider/{id}/oauth/callback`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}},Gt=class extends W{list(e){return(e?.client??this._client).get({url:`/provider`,...e})}auth(e){return(e?.client??this._client).get({url:`/provider/auth`,...e})}oauth=new Wt({client:this._client})},Kt=class extends W{text(e){return(e.client??this._client).get({url:`/find`,...e})}files(e){return(e.client??this._client).get({url:`/find/file`,...e})}symbols(e){return(e.client??this._client).get({url:`/find/symbol`,...e})}},qt=class extends W{list(e){return(e.client??this._client).get({url:`/file`,...e})}read(e){return(e.client??this._client).get({url:`/file/content`,...e})}status(e){return(e?.client??this._client).get({url:`/file/status`,...e})}},Jt=class extends W{log(e){return(e?.client??this._client).post({url:`/log`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}agents(e){return(e?.client??this._client).get({url:`/agent`,...e})}},Yt=class extends W{remove(e){return(e.client??this._client).delete({url:`/mcp/{name}/auth`,...e})}start(e){return(e.client??this._client).post({url:`/mcp/{name}/auth`,...e})}callback(e){return(e.client??this._client).post({url:`/mcp/{name}/auth/callback`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}authenticate(e){return(e.client??this._client).post({url:`/mcp/{name}/auth/authenticate`,...e})}set(e){return(e.client??this._client).put({url:`/auth/{id}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}},Xt=class extends W{status(e){return(e?.client??this._client).get({url:`/mcp`,...e})}add(e){return(e?.client??this._client).post({url:`/mcp`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}connect(e){return(e.client??this._client).post({url:`/mcp/{name}/connect`,...e})}disconnect(e){return(e.client??this._client).post({url:`/mcp/{name}/disconnect`,...e})}auth=new Yt({client:this._client})},Zt=class extends W{status(e){return(e?.client??this._client).get({url:`/lsp`,...e})}},Qt=class extends W{status(e){return(e?.client??this._client).get({url:`/formatter`,...e})}},$t=class extends W{next(e){return(e?.client??this._client).get({url:`/tui/control/next`,...e})}response(e){return(e?.client??this._client).post({url:`/tui/control/response`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}},en=class extends W{appendPrompt(e){return(e?.client??this._client).post({url:`/tui/append-prompt`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}openHelp(e){return(e?.client??this._client).post({url:`/tui/open-help`,...e})}openSessions(e){return(e?.client??this._client).post({url:`/tui/open-sessions`,...e})}openThemes(e){return(e?.client??this._client).post({url:`/tui/open-themes`,...e})}openModels(e){return(e?.client??this._client).post({url:`/tui/open-models`,...e})}submitPrompt(e){return(e?.client??this._client).post({url:`/tui/submit-prompt`,...e})}clearPrompt(e){return(e?.client??this._client).post({url:`/tui/clear-prompt`,...e})}executeCommand(e){return(e?.client??this._client).post({url:`/tui/execute-command`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}showToast(e){return(e?.client??this._client).post({url:`/tui/show-toast`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}publish(e){return(e?.client??this._client).post({url:`/tui/publish`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}control=new $t({client:this._client})},tn=class extends W{subscribe(e){return(e?.client??this._client).get.sse({url:`/event`,...e})}},nn=class extends W{postSessionIdPermissionsPermissionId(e){return(e.client??this._client).post({url:`/session/{id}/permissions/{permissionID}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}global=new Pt({client:this._client});project=new Ft({client:this._client});pty=new It({client:this._client});config=new Lt({client:this._client});tool=new Rt({client:this._client});instance=new zt({client:this._client});path=new Bt({client:this._client});vcs=new Vt({client:this._client});session=new Ht({client:this._client});command=new Ut({client:this._client});provider=new Gt({client:this._client});find=new Kt({client:this._client});file=new qt({client:this._client});app=new Jt({client:this._client});mcp=new Xt({client:this._client});lsp=new Zt({client:this._client});formatter=new Qt({client:this._client});tui=new en({client:this._client});auth=new Yt({client:this._client});event=new tn({client:this._client})};function rn(e){if(!e?.fetch){let t=e=>(e.timeout=!1,fetch(e));e={...e,fetch:t}}return e?.directory&&(e.headers={...e.headers,"x-opencode-directory":encodeURIComponent(e.directory)}),new nn({client:Mt(e)})}async function an(e){e=Object.assign({hostname:`127.0.0.1`,port:4096,timeout:5e3},e??{});let t=[`serve`,`--hostname=${e.hostname}`,`--port=${e.port}`];e.config?.logLevel&&t.push(`--log-level=${e.config.logLevel}`);let n=Te(`opencode`,t,{signal:e.signal,env:{...process.env,OPENCODE_CONFIG_CONTENT:JSON.stringify(e.config??{})}});return{url:await new Promise((t,r)=>{let i=setTimeout(()=>{r(Error(`Timeout waiting for server to start after ${e.timeout}ms`))},e.timeout),a=``;n.stdout?.on(`data`,e=>{a+=e.toString();let n=a.split(` +`);try{c=JSON.parse(e),l=!0}catch{c=e}}l&&(r&&await r(c),n&&(c=await n(c))),t?.({data:c,event:o,id:u,retry:s}),a.length&&(yield c)}}}finally{p.removeEventListener(`abort`,d),a.releaseLock()}break}catch(t){if(e?.(t),a!==void 0&&f>=a)break;await d(Math.min(s*2**(f-1),o??3e4))}}}()}},ut=async(e,t)=>{let n=typeof t==`function`?await t(e):t;if(n)return e.scheme===`bearer`?`Bearer ${n}`:e.scheme===`basic`?`Basic ${btoa(n)}`:n},dt={bodySerializer:e=>JSON.stringify(e,(e,t)=>typeof t==`bigint`?t.toString():t)},ft=e=>{switch(e){case`label`:return`.`;case`matrix`:return`;`;case`simple`:return`,`;default:return`&`}},pt=e=>{switch(e){case`form`:return`,`;case`pipeDelimited`:return`|`;case`spaceDelimited`:return`%20`;default:return`,`}},mt=e=>{switch(e){case`label`:return`.`;case`matrix`:return`;`;case`simple`:return`,`;default:return`&`}},ht=({allowReserved:e,explode:t,name:n,style:r,value:i})=>{if(!t){let t=(e?i:i.map(e=>encodeURIComponent(e))).join(pt(r));switch(r){case`label`:return`.${t}`;case`matrix`:return`;${n}=${t}`;case`simple`:return t;default:return`${n}=${t}`}}let a=ft(r),o=i.map(t=>r===`label`||r===`simple`?e?t:encodeURIComponent(t):U({allowReserved:e,name:n,value:t})).join(a);return r===`label`||r===`matrix`?a+o:o},U=({allowReserved:e,name:t,value:n})=>{if(n==null)return``;if(typeof n==`object`)throw Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");return`${t}=${e?n:encodeURIComponent(n)}`},gt=({allowReserved:e,explode:t,name:n,style:r,value:i,valueOnly:a})=>{if(i instanceof Date)return a?i.toISOString():`${n}=${i.toISOString()}`;if(r!==`deepObject`&&!t){let t=[];Object.entries(i).forEach(([n,r])=>{t=[...t,n,e?r:encodeURIComponent(r)]});let a=t.join(`,`);switch(r){case`form`:return`${n}=${a}`;case`label`:return`.${a}`;case`matrix`:return`;${n}=${a}`;default:return a}}let o=mt(r),s=Object.entries(i).map(([t,i])=>U({allowReserved:e,name:r===`deepObject`?`${n}[${t}]`:t,value:i})).join(o);return r===`label`||r===`matrix`?o+s:s},_t=/\{[^{}]+\}/g,vt=({path:e,url:t})=>{let n=t,r=t.match(_t);if(r)for(let t of r){let r=!1,i=t.substring(1,t.length-1),a=`simple`;i.endsWith(`*`)&&(r=!0,i=i.substring(0,i.length-1)),i.startsWith(`.`)?(i=i.substring(1),a=`label`):i.startsWith(`;`)&&(i=i.substring(1),a=`matrix`);let o=e[i];if(o==null)continue;if(Array.isArray(o)){n=n.replace(t,ht({explode:r,name:i,style:a,value:o}));continue}if(typeof o==`object`){n=n.replace(t,gt({explode:r,name:i,style:a,value:o,valueOnly:!0}));continue}if(a===`matrix`){n=n.replace(t,`;${U({name:i,value:o})}`);continue}let s=encodeURIComponent(a===`label`?`.${o}`:o);n=n.replace(t,s)}return n},yt=({baseUrl:e,path:t,query:n,querySerializer:r,url:i})=>{let a=i.startsWith(`/`)?i:`/${i}`,o=(e??``)+a;t&&(o=vt({path:t,url:o}));let s=n?r(n):``;return s.startsWith(`?`)&&(s=s.substring(1)),s&&(o+=`?${s}`),o},bt=({allowReserved:e,array:t,object:n}={})=>r=>{let i=[];if(r&&typeof r==`object`)for(let a in r){let o=r[a];if(o!=null)if(Array.isArray(o)){let n=ht({allowReserved:e,explode:!0,name:a,style:`form`,value:o,...t});n&&i.push(n)}else if(typeof o==`object`){let t=gt({allowReserved:e,explode:!0,name:a,style:`deepObject`,value:o,...n});t&&i.push(t)}else{let t=U({allowReserved:e,name:a,value:o});t&&i.push(t)}}return i.join(`&`)},xt=e=>{if(!e)return`stream`;let t=e.split(`;`)[0]?.trim();if(t){if(t.startsWith(`application/json`)||t.endsWith(`+json`))return`json`;if(t===`multipart/form-data`)return`formData`;if([`application/`,`audio/`,`image/`,`video/`].some(e=>t.startsWith(e)))return`blob`;if(t.startsWith(`text/`))return`text`}},St=(e,t)=>t?!!(e.headers.has(t)||e.query?.[t]||e.headers.get(`Cookie`)?.includes(`${t}=`)):!1,Ct=async({security:e,...t})=>{for(let n of e){if(St(t,n.name))continue;let e=await ut(n,t.auth);if(!e)continue;let r=n.name??`Authorization`;switch(n.in){case`query`:t.query||={},t.query[r]=e;break;case`cookie`:t.headers.append(`Cookie`,`${r}=${e}`);break;default:t.headers.set(r,e);break}}},wt=e=>yt({baseUrl:e.baseUrl,path:e.path,query:e.query,querySerializer:typeof e.querySerializer==`function`?e.querySerializer:bt(e.querySerializer),url:e.url}),Tt=(e,t)=>{let n={...e,...t};return n.baseUrl?.endsWith(`/`)&&(n.baseUrl=n.baseUrl.substring(0,n.baseUrl.length-1)),n.headers=Et(e.headers,t.headers),n},Et=(...e)=>{let t=new Headers;for(let n of e){if(!n||typeof n!=`object`)continue;let e=n instanceof Headers?n.entries():Object.entries(n);for(let[n,r]of e)if(r===null)t.delete(n);else if(Array.isArray(r))for(let e of r)t.append(n,e);else r!==void 0&&t.set(n,typeof r==`object`?JSON.stringify(r):r)}return t};var Dt=class{_fns;constructor(){this._fns=[]}clear(){this._fns=[]}getInterceptorIndex(e){return typeof e==`number`?this._fns[e]?e:-1:this._fns.indexOf(e)}exists(e){let t=this.getInterceptorIndex(e);return!!this._fns[t]}eject(e){let t=this.getInterceptorIndex(e);this._fns[t]&&(this._fns[t]=null)}update(e,t){let n=this.getInterceptorIndex(e);return this._fns[n]?(this._fns[n]=t,e):!1}use(e){return this._fns=[...this._fns,e],this._fns.length-1}};const Ot=()=>({error:new Dt,request:new Dt,response:new Dt}),kt=bt({allowReserved:!1,array:{explode:!0,style:`form`},object:{explode:!0,style:`deepObject`}}),At={"Content-Type":`application/json`},jt=(e={})=>({...dt,headers:At,parseAs:`auto`,querySerializer:kt,...e}),Mt=(e={})=>{let t=Tt(jt(),e),n=()=>({...t}),r=e=>(t=Tt(t,e),n()),i=Ot(),a=async e=>{let n={...t,...e,fetch:e.fetch??t.fetch??globalThis.fetch,headers:Et(t.headers,e.headers),serializedBody:void 0};return n.security&&await Ct({...n,security:n.security}),n.requestValidator&&await n.requestValidator(n),n.body&&n.bodySerializer&&(n.serializedBody=n.bodySerializer(n.body)),(n.serializedBody===void 0||n.serializedBody===``)&&n.headers.delete(`Content-Type`),{opts:n,url:wt(n)}},o=async e=>{let{opts:t,url:n}=await a(e),r={redirect:`follow`,...t,body:t.serializedBody},o=new Request(n,r);for(let e of i.request._fns)e&&(o=await e(o,t));let s=t.fetch,c=await s(o);for(let e of i.response._fns)e&&(c=await e(c,o,t));let l={request:o,response:c};if(c.ok){if(c.status===204||c.headers.get(`Content-Length`)===`0`)return t.responseStyle===`data`?{}:{data:{},...l};let e=(t.parseAs===`auto`?xt(c.headers.get(`Content-Type`)):t.parseAs)??`json`,n;switch(e){case`arrayBuffer`:case`blob`:case`formData`:case`json`:case`text`:n=await c[e]();break;case`stream`:return t.responseStyle===`data`?c.body:{data:c.body,...l}}return e===`json`&&(t.responseValidator&&await t.responseValidator(n),t.responseTransformer&&(n=await t.responseTransformer(n))),t.responseStyle===`data`?n:{data:n,...l}}let u=await c.text(),d;try{d=JSON.parse(u)}catch{}let f=d??u,p=f;for(let e of i.error._fns)e&&(p=await e(f,c,o,t));if(p||={},t.throwOnError)throw p;return t.responseStyle===`data`?void 0:{error:p,...l}},s=e=>{let t=t=>o({...t,method:e});return t.sse=async t=>{let{opts:n,url:r}=await a(t);return lt({...n,body:n.body,headers:n.headers,method:e,url:r})},t};return{buildUrl:wt,connect:s(`CONNECT`),delete:s(`DELETE`),get:s(`GET`),getConfig:n,head:s(`HEAD`),interceptors:i,options:s(`OPTIONS`),patch:s(`PATCH`),post:s(`POST`),put:s(`PUT`),request:o,setConfig:r,trace:s(`TRACE`)}};Object.entries({$body_:`body`,$headers_:`headers`,$path_:`path`,$query_:`query`});const Nt=Mt(jt({baseUrl:`http://localhost:4096`}));var W=class{_client=Nt;constructor(e){e?.client&&(this._client=e.client)}},Pt=class extends W{event(e){return(e?.client??this._client).get.sse({url:`/global/event`,...e})}},Ft=class extends W{list(e){return(e?.client??this._client).get({url:`/project`,...e})}current(e){return(e?.client??this._client).get({url:`/project/current`,...e})}},It=class extends W{list(e){return(e?.client??this._client).get({url:`/pty`,...e})}create(e){return(e?.client??this._client).post({url:`/pty`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}remove(e){return(e.client??this._client).delete({url:`/pty/{id}`,...e})}get(e){return(e.client??this._client).get({url:`/pty/{id}`,...e})}update(e){return(e.client??this._client).put({url:`/pty/{id}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}connect(e){return(e.client??this._client).get({url:`/pty/{id}/connect`,...e})}},Lt=class extends W{get(e){return(e?.client??this._client).get({url:`/config`,...e})}update(e){return(e?.client??this._client).patch({url:`/config`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}providers(e){return(e?.client??this._client).get({url:`/config/providers`,...e})}},Rt=class extends W{ids(e){return(e?.client??this._client).get({url:`/experimental/tool/ids`,...e})}list(e){return(e.client??this._client).get({url:`/experimental/tool`,...e})}},zt=class extends W{dispose(e){return(e?.client??this._client).post({url:`/instance/dispose`,...e})}},Bt=class extends W{get(e){return(e?.client??this._client).get({url:`/path`,...e})}},Vt=class extends W{get(e){return(e?.client??this._client).get({url:`/vcs`,...e})}},Ht=class extends W{list(e){return(e?.client??this._client).get({url:`/session`,...e})}create(e){return(e?.client??this._client).post({url:`/session`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}status(e){return(e?.client??this._client).get({url:`/session/status`,...e})}delete(e){return(e.client??this._client).delete({url:`/session/{id}`,...e})}get(e){return(e.client??this._client).get({url:`/session/{id}`,...e})}update(e){return(e.client??this._client).patch({url:`/session/{id}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}children(e){return(e.client??this._client).get({url:`/session/{id}/children`,...e})}todo(e){return(e.client??this._client).get({url:`/session/{id}/todo`,...e})}init(e){return(e.client??this._client).post({url:`/session/{id}/init`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}fork(e){return(e.client??this._client).post({url:`/session/{id}/fork`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}abort(e){return(e.client??this._client).post({url:`/session/{id}/abort`,...e})}unshare(e){return(e.client??this._client).delete({url:`/session/{id}/share`,...e})}share(e){return(e.client??this._client).post({url:`/session/{id}/share`,...e})}diff(e){return(e.client??this._client).get({url:`/session/{id}/diff`,...e})}summarize(e){return(e.client??this._client).post({url:`/session/{id}/summarize`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}messages(e){return(e.client??this._client).get({url:`/session/{id}/message`,...e})}prompt(e){return(e.client??this._client).post({url:`/session/{id}/message`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}message(e){return(e.client??this._client).get({url:`/session/{id}/message/{messageID}`,...e})}promptAsync(e){return(e.client??this._client).post({url:`/session/{id}/prompt_async`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}command(e){return(e.client??this._client).post({url:`/session/{id}/command`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}shell(e){return(e.client??this._client).post({url:`/session/{id}/shell`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}revert(e){return(e.client??this._client).post({url:`/session/{id}/revert`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}unrevert(e){return(e.client??this._client).post({url:`/session/{id}/unrevert`,...e})}},Ut=class extends W{list(e){return(e?.client??this._client).get({url:`/command`,...e})}},Wt=class extends W{authorize(e){return(e.client??this._client).post({url:`/provider/{id}/oauth/authorize`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}callback(e){return(e.client??this._client).post({url:`/provider/{id}/oauth/callback`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}},Gt=class extends W{list(e){return(e?.client??this._client).get({url:`/provider`,...e})}auth(e){return(e?.client??this._client).get({url:`/provider/auth`,...e})}oauth=new Wt({client:this._client})},Kt=class extends W{text(e){return(e.client??this._client).get({url:`/find`,...e})}files(e){return(e.client??this._client).get({url:`/find/file`,...e})}symbols(e){return(e.client??this._client).get({url:`/find/symbol`,...e})}},qt=class extends W{list(e){return(e.client??this._client).get({url:`/file`,...e})}read(e){return(e.client??this._client).get({url:`/file/content`,...e})}status(e){return(e?.client??this._client).get({url:`/file/status`,...e})}},Jt=class extends W{log(e){return(e?.client??this._client).post({url:`/log`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}agents(e){return(e?.client??this._client).get({url:`/agent`,...e})}},Yt=class extends W{remove(e){return(e.client??this._client).delete({url:`/mcp/{name}/auth`,...e})}start(e){return(e.client??this._client).post({url:`/mcp/{name}/auth`,...e})}callback(e){return(e.client??this._client).post({url:`/mcp/{name}/auth/callback`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}authenticate(e){return(e.client??this._client).post({url:`/mcp/{name}/auth/authenticate`,...e})}set(e){return(e.client??this._client).put({url:`/auth/{id}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}},Xt=class extends W{status(e){return(e?.client??this._client).get({url:`/mcp`,...e})}add(e){return(e?.client??this._client).post({url:`/mcp`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}connect(e){return(e.client??this._client).post({url:`/mcp/{name}/connect`,...e})}disconnect(e){return(e.client??this._client).post({url:`/mcp/{name}/disconnect`,...e})}auth=new Yt({client:this._client})},Zt=class extends W{status(e){return(e?.client??this._client).get({url:`/lsp`,...e})}},Qt=class extends W{status(e){return(e?.client??this._client).get({url:`/formatter`,...e})}},$t=class extends W{next(e){return(e?.client??this._client).get({url:`/tui/control/next`,...e})}response(e){return(e?.client??this._client).post({url:`/tui/control/response`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}},en=class extends W{appendPrompt(e){return(e?.client??this._client).post({url:`/tui/append-prompt`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}openHelp(e){return(e?.client??this._client).post({url:`/tui/open-help`,...e})}openSessions(e){return(e?.client??this._client).post({url:`/tui/open-sessions`,...e})}openThemes(e){return(e?.client??this._client).post({url:`/tui/open-themes`,...e})}openModels(e){return(e?.client??this._client).post({url:`/tui/open-models`,...e})}submitPrompt(e){return(e?.client??this._client).post({url:`/tui/submit-prompt`,...e})}clearPrompt(e){return(e?.client??this._client).post({url:`/tui/clear-prompt`,...e})}executeCommand(e){return(e?.client??this._client).post({url:`/tui/execute-command`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}showToast(e){return(e?.client??this._client).post({url:`/tui/show-toast`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}publish(e){return(e?.client??this._client).post({url:`/tui/publish`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}control=new $t({client:this._client})},tn=class extends W{subscribe(e){return(e?.client??this._client).get.sse({url:`/event`,...e})}},nn=class extends W{postSessionIdPermissionsPermissionId(e){return(e.client??this._client).post({url:`/session/{id}/permissions/{permissionID}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}global=new Pt({client:this._client});project=new Ft({client:this._client});pty=new It({client:this._client});config=new Lt({client:this._client});tool=new Rt({client:this._client});instance=new zt({client:this._client});path=new Bt({client:this._client});vcs=new Vt({client:this._client});session=new Ht({client:this._client});command=new Ut({client:this._client});provider=new Gt({client:this._client});find=new Kt({client:this._client});file=new qt({client:this._client});app=new Jt({client:this._client});mcp=new Xt({client:this._client});lsp=new Zt({client:this._client});formatter=new Qt({client:this._client});tui=new en({client:this._client});auth=new Yt({client:this._client});event=new tn({client:this._client})};function rn(e){if(!e?.fetch){let t=e=>(e.timeout=!1,fetch(e));e={...e,fetch:t}}return e?.directory&&(e.headers={...e.headers,"x-opencode-directory":encodeURIComponent(e.directory)}),new nn({client:Mt(e)})}async function an(e){e=Object.assign({hostname:`127.0.0.1`,port:4096,timeout:5e3},e??{});let t=[`serve`,`--hostname=${e.hostname}`,`--port=${e.port}`];e.config?.logLevel&&t.push(`--log-level=${e.config.logLevel}`);let n=De(`opencode`,t,{signal:e.signal,env:{...process.env,OPENCODE_CONFIG_CONTENT:JSON.stringify(e.config??{})}});return{url:await new Promise((t,r)=>{let i=setTimeout(()=>{r(Error(`Timeout waiting for server to start after ${e.timeout}ms`))},e.timeout),a=``;n.stdout?.on(`data`,e=>{a+=e.toString();let n=a.split(` `);for(let e of n)if(e.startsWith(`opencode server listening`)){let n=e.match(/on\s+(https?:\/\/[^\s]+)/);if(!n)throw Error(`Failed to parse server url from output: ${e}`);clearTimeout(i),t(n[1]);return}}),n.stderr?.on(`data`,e=>{a+=e.toString()}),n.on(`exit`,e=>{clearTimeout(i);let t=`Server exited with code ${e}`;a.trim()&&(t+=`\nServer output: ${a}`),r(Error(t))}),n.on(`error`,e=>{clearTimeout(i),r(e)}),e.signal&&e.signal.addEventListener(`abort`,()=>{clearTimeout(i),r(Error(`Aborted`))})}),close(){n.kill()}}}async function on(e){let t=await an({...e});return{client:rn({baseUrl:t.url}),server:t}}async function sn(e,t,n,r){if(n!=null)try{let i=await e.session.update({path:{id:t},body:{title:n}});i.error!=null&&r.warning(`Best-effort session title re-assertion failed`,{sessionId:t,sessionTitle:n,error:String(i.error)})}catch(e){r.warning(`Best-effort session title re-assertion failed`,{sessionId:t,sessionTitle:n,error:e instanceof Error?e.message:String(e)})}}async function cn(e){if(e<0||!Number.isFinite(e))throw Error(`Invalid sleep duration: ${e}`);return new Promise(t=>setTimeout(t,e))}const ln={api_error:`API Error`,configuration:`Configuration Error`,internal:`Internal Error`,llm_fetch_error:`LLM Fetch Error`,llm_timeout:`LLM Timeout`,permission:`Permission Error`,rate_limit:`Rate Limit`,validation:`Validation Error`};function un(e){return e.type===`rate_limit`?`:warning:`:e.type===`llm_timeout`?`:hourglass:`:e.type===`llm_fetch_error`||e.retryable?`:warning:`:`:x:`}function dn(e){let t=un(e),n=ln[e.type],r=[];return r.push(`${t} **${n}**`),r.push(``),r.push(e.message),e.details!=null&&(r.push(``),r.push(`> ${e.details}`)),e.suggestedAction!=null&&(r.push(``),r.push(`**Suggested action:** ${e.suggestedAction}`)),e.retryable&&(r.push(``),r.push(`_This error is retryable._`)),e.resetTime!=null&&(r.push(``),r.push(`_Rate limit resets at: ${e.resetTime.toISOString()}_`)),r.join(` -`)}function fn(e,t,n,r){return{type:e,message:t,retryable:n,details:r?.details,suggestedAction:r?.suggestedAction,resetTime:r?.resetTime}}const pn=[/fetch failed/i,/connect\s*timeout/i,/connecttimeouterror/i,/timed?\s*out/i,/econnrefused/i,/econnreset/i,/etimedout/i,/network error/i];function mn(e){if(e==null)return!1;let t=``;if(typeof e==`string`)t=e;else if(e instanceof Error)t=e.message,`cause`in e&&typeof e.cause==`string`&&(t+=` ${e.cause}`);else if(typeof e==`object`){let n=e;typeof n.message==`string`&&(t=n.message),typeof n.cause==`string`&&(t+=` ${n.cause}`)}return pn.some(e=>e.test(t))}function hn(e,t){return fn(`llm_fetch_error`,`LLM request failed: ${e}`,!0,{details:t==null?void 0:`Model: ${t}`,suggestedAction:`This is a transient network error. The request may succeed on retry, or try a different model.`})}function gn(e,t){return fn(`configuration`,`Agent error: ${e}`,!1,{details:t==null?void 0:`Requested agent: ${t}`,suggestedAction:`Verify the agent name is correct and the required plugins (e.g., oMo) are installed.`})}async function _n(e,t,n,i,a,o=r,s){let c=Date.now(),l=0;for(;!i.aborted;){if(await cn(500),i.aborted)return{completed:!1,error:`Aborted`};if(s?.sessionError==null)l=0;else{if(l++,l>=3)return a.error(`Session error persisted through grace period`,{sessionId:t,error:s.sessionError,graceCycles:l}),{completed:!1,error:`Session error: ${s.sessionError}`};continue}if(s?.sessionIdle===!0)return a.debug(`Session idle detected via event stream`,{sessionId:t}),{completed:!0,error:null};let r=Date.now()-c;if(o>0&&r>=o)return a.warning(`Poll timeout reached`,{elapsedMs:r,maxPollTimeMs:o}),{completed:!1,error:`Poll timeout after ${r}ms`};try{let r=((await e.session.status({query:{directory:n}})).data??{})[t];if(r==null)a.debug(`Session status not found in poll response`,{sessionId:t});else if(r.type===`idle`)return a.debug(`Session idle detected via polling`,{sessionId:t}),{completed:!0,error:null};else a.debug(`Session status`,{sessionId:t,type:r.type});if(s!=null&&!s.firstMeaningfulEventReceived){let e=Date.now()-c;if(e>=9e4)return a.error(`No agent activity detected β€” server may have crashed during prompt processing`,{elapsedMs:e,sessionId:t}),{completed:!1,error:`No agent activity detected after ${e}ms β€” server may have crashed during prompt processing`}}}catch(e){a.debug(`Poll request failed`,{error:M(e)})}}return{completed:!1,error:`Aborted`}}async function vn(e,t=2e3){await Promise.race([e,new Promise(e=>{setTimeout(e,t)})])}function yn(e){try{let t=new URL(e);return t.hostname===`github.com`||t.hostname===`api.github.com`}catch{return!1}}function bn(e){try{let t=new URL(e);return t.hostname===`github.com`&&(t.pathname.startsWith(`/user-attachments/assets/`)||t.pathname.startsWith(`/user-attachments/files/`))}catch{return!1}}function xn(e){let t=e.match(/https:\/\/github\.com\/[a-zA-Z0-9-]+\/[\w.-]+\/(?:pull|issues)\/\d+(?:#issuecomment-\d+)?/g)??[];return[...new Set(t)].filter(yn)}function Sn(e){let t=/\[[\w-]+\s+([a-f0-9]{7,40})\]/g,n=[];for(let r of e.matchAll(t))r[1]!=null&&n.push(r[1]);return[...new Set(n)]}const Cn={todowrite:[`Todo`,`\x1B[33m\x1B[1m`],todoread:[`Todo`,`\x1B[33m\x1B[1m`],bash:[`Bash`,`\x1B[31m\x1B[1m`],edit:[`Edit`,`\x1B[32m\x1B[1m`],glob:[`Glob`,`\x1B[34m\x1B[1m`],grep:[`Grep`,`\x1B[34m\x1B[1m`],list:[`List`,`\x1B[34m\x1B[1m`],read:[`Read`,`\x1B[35m\x1B[1m`],write:[`Write`,`\x1B[32m\x1B[1m`],websearch:[`Search`,`\x1B[2m\x1B[1m`]},wn=`\x1B[0m`;function Tn(){return I.env.NO_COLOR==null}function En(e,t){let[n,r]=Cn[e.toLowerCase()]??[e,`\x1B[36m\x1B[1m`],i=n.padEnd(10,` `);Tn()?I.stdout.write(`\n${r}|${wn} ${i} ${wn}${t}\n`):I.stdout.write(`\n| ${i} ${t}\n`)}function Dn(e){I.stdout.write(`\n${e}\n`)}function On(e,t){t.debug(`Server event`,{eventType:e.type,properties:e.properties})}function kn(e,t,n,r,i){let a=xn(t);if(e.includes(`gh pr create`)){let e=a.filter(e=>e.includes(`/pull/`)&&!e.includes(`#`));for(let t of e)n.includes(t)||n.push(t)}if(e.includes(`git commit`)){let e=Sn(t);for(let t of e)r.includes(t)||r.push(t)}(e.includes(`gh issue comment`)||e.includes(`gh pr comment`))&&a.some(e=>e.includes(`#issuecomment`))&&i()}async function An(e,t,n,r,i){let a=``,o=null,s=null,c=null,l=[],u=[],d=0,f=null;for await(let p of e){if(n.aborted)break;if(On(p,r),p.type===`message.part.updated`){let e=p.properties.part;if(e.sessionID!==t)continue;if(i!=null&&(i.firstMeaningfulEventReceived=!0),e.type===`text`&&`text`in e&&typeof e.text==`string`){a=e.text;let t=`time`in e?e.time?.end:void 0;t!=null&&Number.isFinite(t)&&(Dn(a),a=``)}else if(e.type===`tool`){let t=e.state;t.status===`completed`&&(En(e.tool,t.title),e.tool.toLowerCase()===`bash`&&kn(String(t.input.command??t.input.cmd??``),String(t.output),l,u,()=>{d++}))}}else if(p.type===`message.updated`){let e=p.properties.info;e.sessionID===t&&e.role===`assistant`&&e.tokens!=null&&(i!=null&&(i.firstMeaningfulEventReceived=!0),o={input:e.tokens.input??0,output:e.tokens.output??0,reasoning:e.tokens.reasoning??0,cache:{read:e.tokens.cache?.read??0,write:e.tokens.cache?.write??0}},s=e.modelID??null,c=e.cost??null,r.debug(`Token usage received`,{tokens:o,model:s,cost:c}))}else if(p.type===`session.error`){if(p.properties.sessionID===t){let e=p.properties.error,t=typeof e==`string`?e:String(e);r.error(`Session error`,{error:e}),f=mn(e)?hn(t,s??void 0):gn(t),i!=null&&(i.sessionError=t)}}else p.type===`session.idle`&&p.properties.sessionID===t&&(i!=null&&(i.sessionIdle=!0),a.length>0&&(Dn(a),a=``))}return a.length>0&&Dn(a),{tokens:o,model:s,cost:c,prsCreated:l,commitsCreated:u,commentsPosted:d,llmError:f}}const jn=5e3;async function Mn(e,t,n,r,i){let a=new AbortController,o={firstMeaningfulEventReceived:!1,sessionIdle:!1,sessionError:null},s=await e.event.subscribe(),c={tokens:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:null},l=An(s.stream,t,a.signal,i,o).then(e=>{c=e}).catch(e=>{e instanceof Error&&e.name!==`AbortError`&&i.debug(`Event stream error`,{error:e.message})}),u=async()=>{a.abort(),await vn(l)};try{let s=await _n(e,t,n,a.signal,i,r,o);if(await u(),!s.completed){let e=s.error??`Session did not reach idle state`;return i.error(`Session completion polling failed`,{error:e,sessionId:t}),{success:!1,error:e,llmError:c.llmError,shouldRetry:c.llmError!=null,eventStreamResult:c}}return{success:!0,error:null,llmError:null,shouldRetry:!1,eventStreamResult:c}}finally{a.abort(),await vn(l)}}const Nn=e=>{if(e?.model!=null)return{providerID:e.model.providerID,modelID:e.model.modelID};if(!(e!=null&&Object.values(e.omoProviders).some(e=>e!==`no`)))return{providerID:de.providerID,modelID:de.modelID}};async function Pn(e,t,n,r,i,a,o){let s={parts:[{type:`text`,text:n},...r??[]]},c=Nn(a);c!=null&&(s.model=c);let l=a?.agent??`sisyphus`;l!==`sisyphus`&&(s.agent=l);let u=await e.session.promptAsync({path:{id:t},body:s,query:{directory:i}});if(u.error!=null){let e=String(u.error),t=mn(u.error)?hn(e):null;return{success:!1,error:e,llmError:t,shouldRetry:t!=null,eventStreamResult:{tokens:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:t}}}return Mn(e,t,i,a?.timeoutMs??18e5,o)}function Fn(){return[`## Critical Rules (NON-NEGOTIABLE)`,`- You are a NON-INTERACTIVE CI agent. Do NOT ask questions. Make decisions autonomously.`,`- Post EXACTLY ONE comment or review per invocation. Never multiple.`,`- Include the Run Summary marker block in your comment.`,"- Use `gh` CLI for all GitHub operations. Do not use the GitHub API directly.",`- Mark your comment with the bot identification marker.`].join(` +`)}function fn(e,t,n,r){return{type:e,message:t,retryable:n,details:r?.details,suggestedAction:r?.suggestedAction,resetTime:r?.resetTime}}const pn=[/fetch failed/i,/connect\s*timeout/i,/connecttimeouterror/i,/timed?\s*out/i,/econnrefused/i,/econnreset/i,/etimedout/i,/network error/i];function mn(e){if(e==null)return!1;let t=``;if(typeof e==`string`)t=e;else if(e instanceof Error)t=e.message,`cause`in e&&typeof e.cause==`string`&&(t+=` ${e.cause}`);else if(typeof e==`object`){let n=e;typeof n.message==`string`&&(t=n.message),typeof n.cause==`string`&&(t+=` ${n.cause}`)}return pn.some(e=>e.test(t))}function hn(e,t){return fn(`llm_fetch_error`,`LLM request failed: ${e}`,!0,{details:t==null?void 0:`Model: ${t}`,suggestedAction:`This is a transient network error. The request may succeed on retry, or try a different model.`})}function gn(e,t){return fn(`configuration`,`Agent error: ${e}`,!1,{details:t==null?void 0:`Requested agent: ${t}`,suggestedAction:`Verify the agent name is correct and the required plugins (e.g., oMo) are installed.`})}async function _n(e,t,n,i,a,o=r,s){let c=Date.now(),l=0;for(;!i.aborted;){if(await cn(500),i.aborted)return{completed:!1,error:`Aborted`};if(s?.sessionError==null)l=0;else{if(l++,l>=3)return a.error(`Session error persisted through grace period`,{sessionId:t,error:s.sessionError,graceCycles:l}),{completed:!1,error:`Session error: ${s.sessionError}`};continue}if(s?.sessionIdle===!0)return a.debug(`Session idle detected via event stream`,{sessionId:t}),{completed:!0,error:null};let r=Date.now()-c;if(o>0&&r>=o)return a.warning(`Poll timeout reached`,{elapsedMs:r,maxPollTimeMs:o}),{completed:!1,error:`Poll timeout after ${r}ms`};try{let r=((await e.session.status({query:{directory:n}})).data??{})[t];if(r==null)a.debug(`Session status not found in poll response`,{sessionId:t});else if(r.type===`idle`)return a.debug(`Session idle detected via polling`,{sessionId:t}),{completed:!0,error:null};else a.debug(`Session status`,{sessionId:t,type:r.type});if(s!=null&&!s.firstMeaningfulEventReceived){let e=Date.now()-c;if(e>=9e4)return a.error(`No agent activity detected β€” server may have crashed during prompt processing`,{elapsedMs:e,sessionId:t}),{completed:!1,error:`No agent activity detected after ${e}ms β€” server may have crashed during prompt processing`}}}catch(e){a.debug(`Poll request failed`,{error:A(e)})}}return{completed:!1,error:`Aborted`}}async function vn(e,t=2e3){await Promise.race([e,new Promise(e=>{setTimeout(e,t)})])}function yn(e){try{let t=new URL(e);return t.hostname===`github.com`||t.hostname===`api.github.com`}catch{return!1}}function bn(e){try{let t=new URL(e);return t.hostname===`github.com`&&(t.pathname.startsWith(`/user-attachments/assets/`)||t.pathname.startsWith(`/user-attachments/files/`))}catch{return!1}}function xn(e){let t=e.match(/https:\/\/github\.com\/[a-zA-Z0-9-]+\/[\w.-]+\/(?:pull|issues)\/\d+(?:#issuecomment-\d+)?/g)??[];return[...new Set(t)].filter(yn)}function Sn(e){let t=/\[[\w-]+\s+([a-f0-9]{7,40})\]/g,n=[];for(let r of e.matchAll(t))r[1]!=null&&n.push(r[1]);return[...new Set(n)]}const Cn={todowrite:[`Todo`,`\x1B[33m\x1B[1m`],todoread:[`Todo`,`\x1B[33m\x1B[1m`],bash:[`Bash`,`\x1B[31m\x1B[1m`],edit:[`Edit`,`\x1B[32m\x1B[1m`],glob:[`Glob`,`\x1B[34m\x1B[1m`],grep:[`Grep`,`\x1B[34m\x1B[1m`],list:[`List`,`\x1B[34m\x1B[1m`],read:[`Read`,`\x1B[35m\x1B[1m`],write:[`Write`,`\x1B[32m\x1B[1m`],websearch:[`Search`,`\x1B[2m\x1B[1m`]},wn=`\x1B[0m`;function Tn(){return N.env.NO_COLOR==null}function En(e,t){let[n,r]=Cn[e.toLowerCase()]??[e,`\x1B[36m\x1B[1m`],i=n.padEnd(10,` `);Tn()?N.stdout.write(`\n${r}|${wn} ${i} ${wn}${t}\n`):N.stdout.write(`\n| ${i} ${t}\n`)}function Dn(e){N.stdout.write(`\n${e}\n`)}function On(e,t){t.debug(`Server event`,{eventType:e.type,properties:e.properties})}function kn(e,t,n,r,i){let a=xn(t);if(e.includes(`gh pr create`)){let e=a.filter(e=>e.includes(`/pull/`)&&!e.includes(`#`));for(let t of e)n.includes(t)||n.push(t)}if(e.includes(`git commit`)){let e=Sn(t);for(let t of e)r.includes(t)||r.push(t)}(e.includes(`gh issue comment`)||e.includes(`gh pr comment`))&&a.some(e=>e.includes(`#issuecomment`))&&i()}async function An(e,t,n,r,i){let a=``,o=null,s=null,c=null,l=[],u=[],d=0,f=null;for await(let p of e){if(n.aborted)break;if(On(p,r),p.type===`message.part.updated`){let e=p.properties.part;if(e.sessionID!==t)continue;if(i!=null&&(i.firstMeaningfulEventReceived=!0),e.type===`text`&&`text`in e&&typeof e.text==`string`){a=e.text;let t=`time`in e?e.time?.end:void 0;t!=null&&Number.isFinite(t)&&(Dn(a),a=``)}else if(e.type===`tool`){let t=e.state;t.status===`completed`&&(En(e.tool,t.title),e.tool.toLowerCase()===`bash`&&kn(String(t.input.command??t.input.cmd??``),String(t.output),l,u,()=>{d++}))}}else if(p.type===`message.updated`){let e=p.properties.info;e.sessionID===t&&e.role===`assistant`&&e.tokens!=null&&(i!=null&&(i.firstMeaningfulEventReceived=!0),o={input:e.tokens.input??0,output:e.tokens.output??0,reasoning:e.tokens.reasoning??0,cache:{read:e.tokens.cache?.read??0,write:e.tokens.cache?.write??0}},s=e.modelID??null,c=e.cost??null,r.debug(`Token usage received`,{tokens:o,model:s,cost:c}))}else if(p.type===`session.error`){if(p.properties.sessionID===t){let e=p.properties.error,t=typeof e==`string`?e:String(e);r.error(`Session error`,{error:e}),f=mn(e)?hn(t,s??void 0):gn(t),i!=null&&(i.sessionError=t)}}else p.type===`session.idle`&&p.properties.sessionID===t&&(i!=null&&(i.sessionIdle=!0),a.length>0&&(Dn(a),a=``))}return a.length>0&&Dn(a),{tokens:o,model:s,cost:c,prsCreated:l,commitsCreated:u,commentsPosted:d,llmError:f}}const jn=5e3;async function Mn(e,t,n,r,i){let a=new AbortController,o={firstMeaningfulEventReceived:!1,sessionIdle:!1,sessionError:null},s=await e.event.subscribe(),c={tokens:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:null},l=An(s.stream,t,a.signal,i,o).then(e=>{c=e}).catch(e=>{e instanceof Error&&e.name!==`AbortError`&&i.debug(`Event stream error`,{error:e.message})}),u=async()=>{a.abort(),await vn(l)};try{let s=await _n(e,t,n,a.signal,i,r,o);if(await u(),!s.completed){let e=s.error??`Session did not reach idle state`;return i.error(`Session completion polling failed`,{error:e,sessionId:t}),{success:!1,error:e,llmError:c.llmError,shouldRetry:c.llmError!=null,eventStreamResult:c}}return{success:!0,error:null,llmError:null,shouldRetry:!1,eventStreamResult:c}}finally{a.abort(),await vn(l)}}const Nn=e=>{if(e?.model!=null)return{providerID:e.model.providerID,modelID:e.model.modelID};if(!(e!=null&&Object.values(e.omoProviders).some(e=>e!==`no`)))return{providerID:me.providerID,modelID:me.modelID}};async function Pn(e,t,n,r,i,a,o){let s={parts:[{type:`text`,text:n},...r??[]]},c=Nn(a);c!=null&&(s.model=c);let l=a?.agent??`sisyphus`;l!==`sisyphus`&&(s.agent=l);let u=await e.session.promptAsync({path:{id:t},body:s,query:{directory:i}});if(u.error!=null){let e=String(u.error),t=mn(u.error)?hn(e):null;return{success:!1,error:e,llmError:t,shouldRetry:t!=null,eventStreamResult:{tokens:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:t}}}return Mn(e,t,i,a?.timeoutMs??18e5,o)}function Fn(){return[`## Critical Rules (NON-NEGOTIABLE)`,`- You are a NON-INTERACTIVE CI agent. Do NOT ask questions. Make decisions autonomously.`,`- Post EXACTLY ONE comment or review per invocation. Never multiple.`,`- Include the Run Summary marker block in your comment.`,"- Use `gh` CLI for all GitHub operations. Do not use the GitHub API directly.",`- Mark your comment with the bot identification marker.`].join(` `)}function In(e,t,n){if(e==null)return``;let r=[`## Thread Identity`];return r.push(`**Logical Thread**: \`${e.key}\` (${e.entityType} #${e.entityId})`),t?(r.push(`**Status**: Continuing previous conversation thread.`),n!=null&&n.length>0&&(r.push(``),r.push(`**Thread Summary**:`),r.push(n))):r.push(`**Status**: Fresh conversation β€” no prior thread found for this entity.`),r.join(` `)}function Ln(e){return e==null||e.length===0?``:[`## Current Thread Context`,`This is work from your PREVIOUS runs on this same entity:`,``,e].join(` `)}function Rn(){return[`## Reminder: Critical Rules`,"- ONE comment/review only. Include Run Summary marker. Use `gh` CLI only."].join(` @@ -159,7 +159,7 @@ ${r.trim()} - **Number:** #${n.issueNumber} - **Title:** ${n.issueTitle??`N/A`} - **Type:** ${n.issueType??`unknown`} -`)}if(n.diffContext!=null&&l.push(qn(n.diffContext)),n.hydratedContext!=null&&l.push(Ze(n.hydratedContext)),a!=null){let e=Kn(a,u,c,f!=null);e!=null&&l.push(e)}l.push(`# Agent Context +`)}if(n.diffContext!=null&&l.push(qn(n.diffContext)),n.hydratedContext!=null&&l.push(Qe(n.hydratedContext)),a!=null){let e=Kn(a,u,c,f!=null);e!=null&&l.push(e)}l.push(`# Agent Context You are the Fro Bot Agent running in a non-interactive CI environment (GitHub Actions). @@ -257,11 +257,13 @@ Every response you post β€” regardless of channel (issue, PR, discussion, review `)}function Gn(e,t){let n=e.filter(e=>e.sessionId===t);if(n.length===0)return null;let r=[];for(let e of n.slice(0,1)){r.push(`**Session ${e.sessionId}:**`),r.push("```markdown");for(let t of e.matches.slice(0,3))r.push(`- ${t.excerpt}`);r.push("```")}return r.join(` `)}function Kn(e,t,n,r){if(t&&n!=null){let t=e.priorWorkContext.filter(e=>e.sessionId!==n);return e.recentSessions.length===0&&t.length===0?null:Wn(e,`## Related Historical Context`,t)}return e.recentSessions.length===0&&e.priorWorkContext.length===0&&r?null:Wn(e,`## Prior Session Context`,e.priorWorkContext)}function qn(e){let t=[`## Pull Request Diff Summary`];if(t.push(``),t.push(`- **Changed Files:** ${e.changedFiles}`),t.push(`- **Additions:** +${e.additions}`),t.push(`- **Deletions:** -${e.deletions}`),e.truncated&&t.push(`- **Note:** Diff was truncated due to size limits`),e.files.length>0){t.push(``),t.push(`### Changed Files`),t.push(`| File | Status | +/- |`),t.push(`|------|--------|-----|`);for(let n of e.files.slice(0,20))t.push(`| \`${n.filename}\` | ${n.status} | +${n.additions}/-${n.deletions} |`);e.files.length>20&&t.push(`| ... | | +${e.files.length-20} more files |`)}return t.push(``),t.join(` `)}function Jn(e){let t=[`## Output Contract`,``];return t.push(`- Review action: approve/request-changes if confident; otherwise comment-only`),t.push(`- Requested reviewer: ${e.isRequestedReviewer?`yes`:`no`}`),e.authorAssociation!=null&&t.push(`- Author association: ${e.authorAssociation}`),t.push(``),t.join(` -`)}async function Yn(e,t,n,r){let i=Date.now(),a=new AbortController,o=n?.timeoutMs??18e5,s=null,c=!1,l=r==null,u=null;o>0&&(s=setTimeout(()=>{c=!0,t.warning(`Execution timeout reached`,{timeoutMs:o}),a.abort()},o)),t.info(`Executing OpenCode agent (SDK mode)`,{agent:n?.agent??`sisyphus`,hasModelOverride:n?.model!=null,timeoutMs:o});try{let s;if(r==null){let e=await on({signal:a.signal});s=e.client,u=e.server}else s=r.client;let l;if(n?.continueSessionId==null){let e=n?.sessionTitle==null?void 0:{body:{title:n.sessionTitle}},r=e==null?await s.session.create():await s.session.create(e);if(r.data==null||r.error!=null)throw Error(`Failed to create session: ${r.error==null?`No data returned`:String(r.error)}`);l=r.data.id,t.info(`Created new OpenCode session`,{sessionId:l,sessionTitle:n?.sessionTitle??null})}else l=n.continueSessionId,t.info(`Continuing existing OpenCode session`,{sessionId:l});let d=Hn({...e,sessionId:l},t),f=P();if(pe()){let e=j(),n=ye.createHash(`sha256`).update(d).digest(`hex`),r=B.join(e,`prompt-${l}-${n.slice(0,8)}.txt`);try{await z.mkdir(e,{recursive:!0}),await z.writeFile(r,d,`utf8`),t.info(`Prompt artifact written`,{hash:n,path:r})}catch(e){t.warning(`Failed to write prompt artifact`,{error:e instanceof Error?e.message:String(e),path:r})}}let p={tokens:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:null},m=null,h=null;for(let r=1;r<=3;r++){if(c)return{success:!1,exitCode:130,duration:Date.now()-i,sessionId:l,error:`Execution timed out after ${o}ms`,tokenUsage:p.tokens,model:p.model,cost:p.cost,prsCreated:p.prsCreated,commitsCreated:p.commitsCreated,commentsPosted:p.commentsPosted,llmError:h};if(o>0&&o-(Date.now()-i)<=5e3&&r>1)break;let a=r===1?d:`The previous request was interrupted by a network error (fetch failed). +`)}async function Yn(e,t,n,r){let i=Date.now(),a=new AbortController,o=n?.timeoutMs??18e5,s=null,c=!1,l=r==null,u=null;o>0&&(s=setTimeout(()=>{c=!0,t.warning(`Execution timeout reached`,{timeoutMs:o}),a.abort()},o)),t.info(`Executing OpenCode agent (SDK mode)`,{agent:n?.agent??`sisyphus`,hasModelOverride:n?.model!=null,timeoutMs:o});try{let s;if(r==null){let e=await on({signal:a.signal});s=e.client,u=e.server}else s=r.client;let l;if(n?.continueSessionId==null){let e=n?.sessionTitle==null?void 0:{body:{title:n.sessionTitle}},r=e==null?await s.session.create():await s.session.create(e);if(r.data==null||r.error!=null)throw Error(`Failed to create session: ${r.error==null?`No data returned`:String(r.error)}`);l=r.data.id,t.info(`Created new OpenCode session`,{sessionId:l,sessionTitle:n?.sessionTitle??null})}else l=n.continueSessionId,t.info(`Continuing existing OpenCode session`,{sessionId:l});let d=Hn({...e,sessionId:l},t),f=se();if(ge()){let e=k(),n=Se.createHash(`sha256`).update(d).digest(`hex`),r=L.join(e,`prompt-${l}-${n.slice(0,8)}.txt`);try{await I.mkdir(e,{recursive:!0}),await I.writeFile(r,d,`utf8`),t.info(`Prompt artifact written`,{hash:n,path:r})}catch(e){t.warning(`Failed to write prompt artifact`,{error:e instanceof Error?e.message:String(e),path:r})}}let p={tokens:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:null},m=null,h=null;for(let r=1;r<=3;r++){if(c)return{success:!1,exitCode:130,duration:Date.now()-i,sessionId:l,error:`Execution timed out after ${o}ms`,tokenUsage:p.tokens,model:p.model,cost:p.cost,prsCreated:p.prsCreated,commitsCreated:p.commitsCreated,commentsPosted:p.commentsPosted,llmError:h};if(o>0&&o-(Date.now()-i)<=5e3&&r>1)break;let a=r===1?d:`The previous request was interrupted by a network error (fetch failed). Please continue where you left off. If you were in the middle of a task, resume it. -If you had completed the task, confirm the completion.`,u=r===1?e.fileParts:void 0,g=await(async()=>{try{return await Pn(s,l,a,u,f,n,t)}finally{await sn(s,l,n?.sessionTitle,t)}})();if(g.success)return p=g.eventStreamResult,{success:!0,exitCode:0,duration:Date.now()-i,sessionId:l,error:null,tokenUsage:p.tokens,model:p.model,cost:p.cost,prsCreated:p.prsCreated,commitsCreated:p.commitsCreated,commentsPosted:p.commentsPosted,llmError:null};if(m=g.error,h=g.llmError,!g.shouldRetry||r>=3)break;t.warning(`LLM fetch error detected, retrying with continuation prompt`,{attempt:r,maxAttempts:3,error:g.error,delayMs:jn,sessionId:l}),await cn(jn)}return{success:!1,exitCode:1,duration:Date.now()-i,sessionId:l,error:m??`Unknown error`,tokenUsage:p.tokens,model:p.model,cost:p.cost,prsCreated:p.prsCreated,commitsCreated:p.commitsCreated,commentsPosted:p.commentsPosted,llmError:h}}catch(e){let n=Date.now()-i,r=M(e);return t.error(`OpenCode execution failed`,{error:r,durationMs:n}),{success:!1,exitCode:1,duration:n,sessionId:null,error:r,tokenUsage:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:mn(e)?hn(r):null}}finally{s!=null&&clearTimeout(s),a.abort(),l&&u?.close()}}async function Xn(e,t,n){return t.commentId==null?(n.debug(`No comment ID, skipping eyes reaction`),!1):await Pe(e,t.repo,t.commentId,`eyes`,n)==null?!1:(n.info(`Added eyes reaction`,{commentId:t.commentId}),!0)}async function Zn(e,t,n){return t.issueNumber==null?(n.debug(`No issue number, skipping working label`),!1):await Le(e,t.repo,`agent: working`,`fcf2e1`,`Agent is currently working on this`,n)&&await Re(e,t.repo,t.issueNumber,[`agent: working`],n)?(n.info(`Added working label`,{issueNumber:t.issueNumber}),!0):!1}async function Qn(e,t,n){await Promise.all([Xn(e,t,n),Zn(e,t,n)])}async function $n(e,t,n){if(t.commentId==null||t.botLogin==null)return;let r=(await Fe(e,t.repo,t.commentId,n)).find(e=>e.content===`eyes`&&e.userLogin===t.botLogin);r!=null&&await Ie(e,t.repo,t.commentId,r.id,n)}async function er(e,t,n,r){t.commentId!=null&&await Pe(e,t.repo,t.commentId,n,r)}async function tr(e,t,n){if(t.commentId==null||t.botLogin==null){n.debug(`Missing comment ID or bot login, skipping reaction update`);return}try{await $n(e,t,n),await er(e,t,`hooray`,n),n.info(`Updated reaction to success indicator`,{commentId:t.commentId,reaction:`hooray`})}catch(e){n.warning(`Failed to update reaction (non-fatal)`,{error:M(e)})}}async function nr(e,t,n){if(t.commentId==null||t.botLogin==null){n.debug(`Missing comment ID or bot login, skipping reaction update`);return}try{await $n(e,t,n),await er(e,t,`confused`,n),n.info(`Updated reaction to confused`,{commentId:t.commentId})}catch(e){n.warning(`Failed to update failure reaction (non-fatal)`,{error:M(e)})}}async function rr(e,t,n){if(t.issueNumber==null){n.debug(`No issue number, skipping label removal`);return}await ze(e,t.repo,t.issueNumber,`agent: working`,n)&&n.info(`Removed working label`,{issueNumber:t.issueNumber})}async function ir(e,t,n,r){n?await tr(e,t,r):await nr(e,t,r),await rr(e,t,r)}var G=C(D(),1),ar=function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},or=class{constructor(e,t,n){if(e<1)throw Error(`max attempts should be greater than or equal to 1`);if(this.maxAttempts=e,this.minSeconds=Math.floor(t),this.maxSeconds=Math.floor(n),this.minSeconds>this.maxSeconds)throw Error(`min seconds should be less than or equal to max seconds`)}execute(e,t){return ar(this,void 0,void 0,function*(){let n=1;for(;nsetTimeout(t,e*1e3))})}},K=function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},sr=class extends Error{constructor(e){super(`Unexpected HTTP response: ${e}`),this.httpStatusCode=e,Object.setPrototypeOf(this,new.target.prototype)}};const cr=process.platform===`win32`;process.platform;function lr(e,t,n,r){return K(this,void 0,void 0,function*(){return t||=R.join(Cr(),he.randomUUID()),yield l(R.dirname(t)),f(`Downloading ${e}`),f(`Destination ${t}`),yield new or(3,wr(`TEST_DOWNLOAD_TOOL_RETRY_MIN_SECONDS`,10),wr(`TEST_DOWNLOAD_TOOL_RETRY_MAX_SECONDS`,20)).execute(()=>K(this,void 0,void 0,function*(){return yield ur(e,t||``,n,r)}),e=>!(e instanceof sr&&e.httpStatusCode&&e.httpStatusCode<500&&e.httpStatusCode!==408&&e.httpStatusCode!==429))})}function ur(e,t,n,r){return K(this,void 0,void 0,function*(){if(L.existsSync(t))throw Error(`Destination file path ${t} already exists`);let i=new x(`actions/tool-cache`,[],{allowRetries:!1});n&&(f(`set auth`),r===void 0&&(r={}),r.authorization=n);let a=yield i.get(e,r);if(a.message.statusCode!==200){let t=new sr(a.message.statusCode);throw f(`Failed to download from "${e}". Code(${a.message.statusCode}) Message(${a.message.statusMessage})`),t}let o=_e.promisify(ke.pipeline),s=wr(`TEST_DOWNLOAD_TOOL_RESPONSE_MESSAGE_FACTORY`,()=>a.message)(),c=!1;try{return yield o(s,L.createWriteStream(t)),f(`download complete`),c=!0,t}finally{if(!c){f(`download failed`);try{yield ae(t)}catch(e){f(`Failed to delete '${t}'. ${e.message}`)}}}})}function dr(e,t){return K(this,arguments,void 0,function*(e,t,n=`xz`){if(!e)throw Error(`parameter 'file' is required`);t=yield vr(t),f(`Checking tar --version`);let r=``;yield v(`tar --version`,[],{ignoreReturnCode:!0,silent:!0,listeners:{stdout:e=>r+=e.toString(),stderr:e=>r+=e.toString()}}),f(r.trim());let i=r.toUpperCase().includes(`GNU TAR`),a;a=n instanceof Array?n:[n],h()&&!n.includes(`v`)&&a.push(`-v`);let o=t,s=e;return cr&&i&&(a.push(`--force-local`),o=t.replace(/\\/g,`/`),s=e.replace(/\\/g,`/`)),i&&(a.push(`--warning=no-unknown-keyword`),a.push(`--overwrite`)),a.push(`-C`,o,`-f`,s),yield v(`tar`,a),t})}function fr(e,t){return K(this,void 0,void 0,function*(){if(!e)throw Error(`parameter 'file' is required`);return t=yield vr(t),cr?yield pr(e,t):yield mr(e,t),t})}function pr(e,t){return K(this,void 0,void 0,function*(){let n=e.replace(/'/g,`''`).replace(/"|\n|\r/g,``),r=t.replace(/'/g,`''`).replace(/"|\n|\r/g,``),i=yield c(`pwsh`,!1);if(i){let e=[`-NoLogo`,`-NoProfile`,`-NonInteractive`,`-ExecutionPolicy`,`Unrestricted`,`-Command`,[`$ErrorActionPreference = 'Stop' ;`,`try { Add-Type -AssemblyName System.IO.Compression.ZipFile } catch { } ;`,`try { [System.IO.Compression.ZipFile]::ExtractToDirectory('${n}', '${r}', $true) }`,`catch { if (($_.Exception.GetType().FullName -eq 'System.Management.Automation.MethodException') -or ($_.Exception.GetType().FullName -eq 'System.Management.Automation.RuntimeException') ){ Expand-Archive -LiteralPath '${n}' -DestinationPath '${r}' -Force } else { throw $_ } } ;`].join(` `)];f(`Using pwsh at path: ${i}`),yield v(`"${i}"`,e)}else{let e=[`-NoLogo`,`-Sta`,`-NoProfile`,`-NonInteractive`,`-ExecutionPolicy`,`Unrestricted`,`-Command`,[`$ErrorActionPreference = 'Stop' ;`,`try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ;`,`if ((Get-Command -Name Expand-Archive -Module Microsoft.PowerShell.Archive -ErrorAction Ignore)) { Expand-Archive -LiteralPath '${n}' -DestinationPath '${r}' -Force }`,`else {[System.IO.Compression.ZipFile]::ExtractToDirectory('${n}', '${r}', $true) }`].join(` `)],t=yield c(`powershell`,!0);f(`Using powershell at path: ${t}`),yield v(`"${t}"`,e)}})}function mr(e,t){return K(this,void 0,void 0,function*(){let n=yield c(`unzip`,!0),r=[e];h()||r.unshift(`-q`),r.unshift(`-o`),yield v(`"${n}"`,r,{cwd:t})})}function hr(e,t,n,r){return K(this,void 0,void 0,function*(){if(n=G.clean(n)||n,r||=me.arch(),f(`Caching tool ${t} ${n} ${r}`),f(`source dir: ${e}`),!L.statSync(e).isDirectory())throw Error(`sourceDir is not a directory`);let i=yield yr(t,n,r);for(let t of L.readdirSync(e))yield o(R.join(e,t),i,{recursive:!0});return br(t,n,r),i})}function gr(e,t,n){if(!e)throw Error(`toolName parameter is required`);if(!t)throw Error(`versionSpec parameter is required`);n||=me.arch(),xr(t)||(t=Sr(_r(e,n),t));let r=``;if(t){t=G.clean(t)||``;let i=R.join(q(),e,t,n);f(`checking cache: ${i}`),L.existsSync(i)&&L.existsSync(`${i}.complete`)?(f(`Found tool in cache ${e} ${t} ${n}`),r=i):f(`not found`)}return r}function _r(e,t){let n=[];t||=me.arch();let r=R.join(q(),e);if(L.existsSync(r)){let e=L.readdirSync(r);for(let i of e)if(xr(i)){let e=R.join(r,i,t||``);L.existsSync(e)&&L.existsSync(`${e}.complete`)&&n.push(i)}}return n}function vr(e){return K(this,void 0,void 0,function*(){return e||=R.join(Cr(),he.randomUUID()),yield l(e),e})}function yr(e,t,n){return K(this,void 0,void 0,function*(){let r=R.join(q(),e,G.clean(t)||t,n||``);f(`destination ${r}`);let i=`${r}.complete`;return yield ae(r),yield ae(i),yield l(r),r})}function br(e,t,n){let r=`${R.join(q(),e,G.clean(t)||t,n||``)}.complete`;L.writeFileSync(r,``),f(`finished caching tool`)}function xr(e){let t=G.clean(e)||``;f(`isExplicit: ${t}`);let n=G.valid(t)!=null;return f(`explicit? ${n}`),n}function Sr(e,t){let n=``;f(`evaluating ${e.length} versions`),e=e.sort((e,t)=>G.gt(e,t)?1:-1);for(let r=e.length-1;r>=0;r--){let i=e[r];if(G.satisfies(i,t)){n=i;break}}return f(n?`matched: ${n}`:`match not found`),n}function q(){let e=process.env.RUNNER_TOOL_CACHE||``;return ge(e,`Expected RUNNER_TOOL_CACHE to be defined`),e}function Cr(){let e=process.env.RUNNER_TEMP||``;return ge(e,`Expected RUNNER_TEMP to be defined`),e}function wr(e,t){let n=global[e];return n===void 0?t:n}function Tr(e){let t;try{t=JSON.parse(e)}catch(e){throw e instanceof SyntaxError?Error(`Invalid auth-json format: ${e.message}`):e}if(typeof t!=`object`||!t||Array.isArray(t))throw Error(`auth-json must be a JSON object`);return t}async function Er(e,t,n){let r=B.join(t,`auth.json`);await z.mkdir(t,{recursive:!0});let i=JSON.stringify(e,null,2);return await z.writeFile(r,i,{mode:384}),n.info(`Populated auth.json`,{path:r,providers:Object.keys(e).length}),r}function Dr(){let e=I.platform,t=I.arch;return{os:{darwin:`darwin`,linux:`linux`,win32:`windows`}[e]??`linux`,arch:{arm64:`aarch64`,x64:`x64`}[t]??`x64`,ext:`.zip`}}function Or(e,t){return`https://github.com/oven-sh/bun/releases/download/bun-${e.startsWith(`v`)?e:`v${e}`}/${`bun-${t.os}-${t.arch}${t.ext}`}`}async function kr(e,t,n,r,i=g){let a=Dr(),o=t.find(`bun`,i,a.arch);if(o.length>0)return e.info(`Bun found in cache`,{version:i,path:o}),r(o),await jr(o),{path:o,version:i,cached:!0};e.info(`Downloading Bun`,{version:i});let s=Or(i,a);try{let o=await t.downloadTool(s);if(I.platform!==`win32`&&!await Mr(o,e,n))throw Error(`Downloaded Bun archive appears corrupted`);e.info(`Extracting Bun`);let c=await Ar(await t.extractZip(o),t),l=Ce.dirname(c);e.info(`Caching Bun`);let u=await t.cacheDir(l,`bun`,i,a.arch);return r(u),await jr(u),e.info(`Bun installed`,{version:i,path:u}),{path:u,version:i,cached:!1}}catch(e){let t=M(e);throw Error(`Failed to install Bun ${i}: ${t}`)}}async function Ar(e,t){for(let n of await Se.readdir(e,{withFileTypes:!0})){let{name:r}=n,i=Ce.join(e,r);if(n.isFile()){if(r===`bun`||r===`bun.exe`)return i;if(/^bun.*\.zip/.test(r))return Ar(await t.extractZip(i),t)}if(r.startsWith(`bun`)&&n.isDirectory())return Ar(i,t)}throw Error(`Could not find executable: bun`)}async function jr(e){let t=e=>I.platform===`win32`?`${e}.exe`:e,n=Ce.join(e,t(`bun`));try{await Se.symlink(n,Ce.join(e,t(`bunx`)))}catch(e){let t=typeof e==`object`?e.code:void 0;if(t!==`EEXIST`&&t!==`EPERM`&&t!==`EACCES`)throw e}}async function Mr(e,t,n){try{let{stdout:r}=await n.getExecOutput(`file`,[e],{silent:!0}),i=r.includes(`Zip archive`)||r.includes(`ZIP`);return i||t.warning(`Bun download validation failed`,{output:r.trim()}),i}catch{return t.debug(`Could not validate Bun download (file command unavailable)`),!0}}function Nr(e){return{debug:t=>e.debug(t),info:t=>e.info(t),warn:t=>e.warning(t),error:t=>e.error(t)}}function Pr(e){let{token:t,logger:n}=e;return n.debug(`Creating GitHub client with token`),le(t,{log:Nr(n)})}async function Fr(e,t){try{let{data:n}=await e.rest.users.getAuthenticated();return t.debug(`Authenticated as`,{login:n.login,type:n.type}),n.login}catch{return t.debug(`Failed to get authenticated user, may be app token`),`fro-bot[bot]`}}async function Ir(e,t,n,r){let i=t??n,a=t==null?n.length>0?`github-token`:`none`:`app-token`;if(i.length===0)return r.warning(`No GitHub token available`),{authenticated:!1,method:`none`,botLogin:null};I.env.GH_TOKEN=i,r.info(`Configured authentication`,{method:a});let o=null;return e!=null&&(o=await Fr(e,r)),{authenticated:!0,method:a,botLogin:o}}async function Lr(e,t){let n=await t.getExecOutput(`git`,[`config`,e],{ignoreReturnCode:!0,silent:!0});return n.exitCode===0&&n.stdout.trim().length>0?n.stdout.trim():null}async function Rr(e,t,n,r){let i=await Lr(`user.name`,r),a=await Lr(`user.email`,r);if(i!=null&&a!=null){n.info(`Git identity already configured`,{name:i,email:a});return}if(t==null)throw Error(`Cannot configure Git identity: no authenticated GitHub user`);let o=null;if(a==null){let r=await Ue(e,t,n);if(r==null)throw Error(`Cannot configure Git identity: failed to look up user ID for '${t}'`);o=String(r.id)}i??await r.exec(`git`,[`config`,`--global`,`user.name`,t],void 0);let s=`${o}+${t}@users.noreply.github.com`;a??await r.exec(`git`,[`config`,`--global`,`user.email`,s],void 0),n.info(`Configured git identity`,{name:i??t,email:a??s})}const zr=new Set([`__proto__`,`prototype`,`constructor`]);function Br(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Vr(e,t){let n=Object.create(null);for(let[t,r]of Object.entries(e))zr.has(t)||(n[t]=r);for(let[e,r]of Object.entries(t)){if(zr.has(e))continue;let t=n[e];Br(r)&&Br(t)?n[e]=Vr(t,r):n[e]=r}return n}async function Hr(e,t,n){let r=JSON.parse(e);if(!Br(r))throw Error(`omo-config must be a JSON object (non-null, non-array)`);let i=r;await z.mkdir(t,{recursive:!0});let a=B.join(t,`oh-my-opencode.json`),o={};try{let e=await z.readFile(a,`utf8`),t=JSON.parse(e);typeof t==`object`&&t&&!Array.isArray(t)&&(o=t)}catch(e){n.debug(`Using empty base oMo config`,{path:a,error:String(e)})}let s=Vr(o,i);await z.writeFile(a,JSON.stringify(s,null,2)),n.info(`Wrote oMo config`,{path:a,keyCount:Object.keys(i).length})}async function Ur(e,t,n={}){let{logger:r,execAdapter:i}=t,{claude:a=`no`,copilot:o=`no`,gemini:s=`no`,openai:c=`no`,opencodeZen:l=`no`,zaiCodingPlan:u=`no`,kimiForCoding:d=`no`}=n;r.info(`Installing Oh My OpenAgent plugin`,{version:e,claude:a,copilot:o,gemini:s,openai:c,opencodeZen:l,zaiCodingPlan:u,kimiForCoding:d});let f=``,p=[`oh-my-openagent@${e}`,`install`,`--no-tui`,`--skip-auth`,`--claude=${a}`,`--copilot=${o}`,`--gemini=${s}`,`--openai=${c}`,`--opencode-zen=${l}`,`--zai-coding-plan=${u}`,`--kimi-for-coding=${d}`];try{let t=await i.exec(`bunx`,p,{listeners:{stdout:e=>{f+=e.toString()},stderr:e=>{f+=e.toString()}},ignoreReturnCode:!0});if(t!==0){let e=`bunx oh-my-openagent install returned exit code ${t}`;return r.error(e,{output:f.slice(0,1e3)}),{installed:!1,version:null,error:`${e}\n${f.slice(0,500)}`}}let n=/oh-my-opencode@(\d+\.\d+\.\d+)/i.exec(f),a=n!=null&&n[1]!=null?n[1]:e;return r.info(`oMo plugin installed`,{version:a}),{installed:!0,version:a,error:null}}catch(e){let t=M(e),n=f.length>0?`${t}\nOutput: ${f.slice(0,500)}`:t;return r.error(`Failed to run oMo installer`,{error:t,output:f.slice(0,500)}),{installed:!1,version:null,error:`bunx oh-my-openagent install failed: ${n}`}}}const Wr=`opencode`,Gr=i;function Kr(){let e=De.platform(),t=De.arch(),n={darwin:`darwin`,linux:`linux`,win32:`windows`},r={x64:`x64`,arm64:`arm64`},i=e===`win32`||e===`darwin`?`.zip`:`.tar.gz`;return{os:n[e]??`linux`,arch:r[t]??`x64`,ext:i}}function qr(e,t){return`https://github.com/anomalyco/opencode/releases/download/${e.startsWith(`v`)?e:`v${e}`}/${`opencode-${t.os}-${t.arch}${t.ext}`}`}async function Jr(e,t,n,r){if(I.platform===`win32`)return!0;try{let{stdout:i}=await r.getExecOutput(`file`,[e],{silent:!0}),a=(t===`.zip`?[`Zip archive`,`ZIP`]:[`gzip`,`tar`,`compressed`]).some(e=>i.includes(e));return a||n.warning(`Download validation failed`,{output:i.trim()}),a}catch{return n.debug(`Could not validate download (file command unavailable)`),!0}}async function Yr(e,t,n,r,i=Gr){let a=Kr(),o=n.find(Wr,e,a.arch);if(o.length>0)return t.info(`OpenCode found in cache`,{version:e,path:o}),{path:o,version:e,cached:!0};try{return await Xr(e,a,t,n,r)}catch(n){t.warning(`Primary version install failed, trying fallback`,{requestedVersion:e,fallbackVersion:i,error:M(n)})}if(e!==i)try{let e=await Xr(i,a,t,n,r);return t.info(`Installed fallback version`,{version:i}),e}catch(t){throw Error(`Failed to install OpenCode (tried ${e} and ${i}): ${M(t)}`)}throw Error(`Failed to install OpenCode version ${e}`)}async function Xr(e,t,n,r,i){n.info(`Downloading OpenCode`,{version:e});let a=qr(e,t),o=await r.downloadTool(a);if(!await Jr(o,t.ext,n,i))throw Error(`Downloaded archive appears corrupted`);n.info(`Extracting OpenCode`);let s=t.ext===`.zip`?await r.extractZip(o):await r.extractTar(o);n.info(`Caching OpenCode`);let c=await r.cacheDir(s,Wr,e,t.arch);return n.info(`OpenCode installed`,{version:e,path:c}),{path:c,version:e,cached:!1}}async function Zr(e){let t=await fetch(`https://api.github.com/repos/anomalyco/opencode/releases/latest`);if(!t.ok)throw Error(`Failed to fetch latest OpenCode version: ${t.statusText}`);let n=(await t.json()).tag_name.replace(/^v/,``);return e.info(`Latest OpenCode version`,{version:n}),n}const Qr={restoreCache:async(e,t,n)=>ie(e,t,n),saveCache:async(e,t)=>se(e,t)};function $r(e){let{os:t,opencodeVersion:n,omoVersion:r}=e;return`${p}-${t}-oc-${n}-omo-${r}`}function ei(e){let{os:t,opencodeVersion:n,omoVersion:r}=e;return[`${p}-${t}-oc-${n}-omo-${r}-`]}async function ti(e){let{logger:t,os:n,opencodeVersion:r,omoVersion:i,toolCachePath:a,bunCachePath:o,omoConfigPath:s,cacheAdapter:c=Qr}=e,l=$r({os:n,opencodeVersion:r,omoVersion:i}),u=ei({os:n,opencodeVersion:r,omoVersion:i}),d=[a,o,s];t.info(`Restoring tools cache`,{primaryKey:l,restoreKeys:[...u],paths:d});try{let e=await c.restoreCache(d,l,[...u]);return e==null?(t.info(`Tools cache miss - will install tools`),{hit:!1,restoredKey:null}):(t.info(`Tools cache restored`,{restoredKey:e}),{hit:!0,restoredKey:e})}catch(e){return t.warning(`Tools cache restore failed`,{error:M(e)}),{hit:!1,restoredKey:null}}}async function ni(e){let{logger:t,os:n,opencodeVersion:r,omoVersion:i,toolCachePath:a,bunCachePath:o,omoConfigPath:s,cacheAdapter:c=Qr}=e,l=$r({os:n,opencodeVersion:r,omoVersion:i}),u=[a,o,s];t.info(`Saving tools cache`,{saveKey:l,paths:u});try{return await c.saveCache(u,l),t.info(`Tools cache saved`,{saveKey:l}),!0}catch(e){return e instanceof Error&&e.message.includes(`already exists`)?(t.info(`Tools cache key already exists, skipping save`),!0):(t.warning(`Tools cache save failed`,{error:M(e)}),!1)}}function ri(){return{find:gr,downloadTool:lr,extractTar:dr,extractZip:fr,cacheDir:hr}}function ii(){return{exec:v,getExecOutput:b}}async function ai(n,r){let i=Date.now(),a=e({component:`setup`}),o=ri(),s=ii();try{a.info(`Starting setup`,{version:n.opencodeVersion});let e;try{e=Tr(n.authJson)}catch(e){return t(`Invalid auth-json: ${M(e)}`),null}let c=n.opencodeVersion;if(c===`latest`)try{c=await Zr(a)}catch(e){a.warning(`Failed to get latest version, using fallback`,{error:M(e)}),c=Gr}let l=n.omoVersion,u=I.env.RUNNER_TOOL_CACHE??`/opt/hostedtoolcache`,f=we(u,`opencode`),p=we(u,`bun`),h=we(Oe(),`.config`,`opencode`),_=w(),v=await ti({logger:a,os:_,opencodeVersion:c,omoVersion:l,toolCachePath:f,bunCachePath:p,omoConfigPath:h}),b=v.hit?`hit`:`miss`,x,S=!1,C=null;if(v.hit){let e=o.find(`opencode`,c);e.length>0?(x={path:e,version:c,cached:!0},a.info(`Tools cache hit, using cached OpenCode CLI`,{version:c,omoVersion:l})):a.warning(`Tools cache hit but binary not found in tool-cache, falling through to install`,{requestedVersion:c,restoredKey:v.restoredKey})}if(x==null)try{x=await Yr(c,a,o,s)}catch(e){return t(`Failed to install OpenCode: ${M(e)}`),null}let T=!1;try{await kr(a,o,s,d,g),T=!0}catch(e){a.warning(`Bun installation failed, oMo will be unavailable`,{error:M(e)})}if(T){if(n.omoConfig!=null)try{await Hr(n.omoConfig,h,a)}catch(e){a.warning(`Failed to write omo-config, continuing without custom config`,{error:M(e)})}let e=await Ur(l,{logger:a,execAdapter:s},n.omoProviders);e.installed?(a.info(`oMo installed`,{version:e.version}),S=!0):a.warning(`oMo installation failed, continuing without oMo`,{error:e.error??`unknown error`}),C=e.error}let E={autoupdate:!1};if(n.opencodeConfig!=null){let e;try{e=JSON.parse(n.opencodeConfig)}catch{return t(`opencode-config must be valid JSON`),null}if(typeof e!=`object`||!e||Array.isArray(e))return t(`opencode-config must be a JSON object`),null;Object.assign(E,e)}m(`OPENCODE_CONFIG_CONTENT`,JSON.stringify(E)),v.hit||await ni({logger:a,os:_,opencodeVersion:c,omoVersion:l,toolCachePath:f,bunCachePath:p,omoConfigPath:h}),d(x.path),y(`opencode-path`,x.path),y(`opencode-version`,x.version),a.info(`OpenCode ready`,{version:x.version,cached:x.cached});let D=le(r),O=await Ir(D,null,r,a);m(`GH_TOKEN`,r),a.info(`GitHub CLI configured`),await Rr(D,O.botLogin,a,s);let k=we(ue(),`opencode`),A=await Er(e,k,a);y(`auth-json-path`,A),a.info(`auth.json populated`,{path:A});let j=Date.now()-i,ee={opencodePath:x.path,opencodeVersion:x.version,ghAuthenticated:O.authenticated,omoInstalled:S,omoError:C,toolsCacheStatus:b,duration:j};return a.info(`Setup complete`,{duration:j}),ee}catch(e){let n=M(e);return a.error(`Setup failed`,{error:n}),t(n),null}}function oi(e){return{success:!0,data:e}}function si(e){return{success:!1,error:e}}const ci=[`OWNER`,`MEMBER`,`COLLABORATOR`];async function li(e,t){try{let{client:n,server:r}=await on({signal:e});return t.debug(`OpenCode server bootstrapped`,{url:r.url}),oi({client:n,server:r,shutdown:()=>{r.close()}})}catch(e){let n=e instanceof Error?e.message:String(e);return t.warning(`Failed to bootstrap OpenCode server`,{error:n}),si(Error(`Server bootstrap failed: ${n}`))}}async function ui(e,t){let n=e??`opencode`;try{let e=``;await v(n,[`--version`],{listeners:{stdout:t=>{e+=t.toString()}},silent:!0});let r=/(\d+\.\d+\.\d+)/.exec(e)?.[1]??null;return t.debug(`OpenCode version verified`,{version:r}),{available:!0,version:r}}catch{return t.debug(`OpenCode not available, will attempt auto-setup`),{available:!1,version:null}}}async function di(e){let{logger:t,opencodeVersion:n}=e,r=I.env.OPENCODE_PATH??null,i=await ui(r,t);if(i.available&&i.version!=null)return t.info(`OpenCode already available`,{version:i.version}),{path:r??`opencode`,version:i.version,didSetup:!1};t.info(`OpenCode not found, running auto-setup`,{requestedVersion:n});let a=await ai({opencodeVersion:n,authJson:e.authJson,appId:null,privateKey:null,opencodeConfig:e.opencodeConfig,omoConfig:null,omoVersion:e.omoVersion,omoProviders:e.omoProviders},e.githubToken);if(a==null)throw Error(`Auto-setup failed: runSetup returned null`);return d(a.opencodePath),I.env.OPENCODE_PATH=a.opencodePath,t.info(`Auto-setup completed`,{version:a.opencodeVersion,path:a.opencodePath}),{path:a.opencodePath,version:a.opencodeVersion,didSetup:!0}}async function fi(t,n){let r={repo:t.agentContext.repo,commentId:t.agentContext.commentId,issueNumber:t.agentContext.issueNumber,issueType:t.agentContext.issueType,botLogin:t.botLogin},i=e({phase:`acknowledgment`});return await Qn(t.githubClient,r,i),n.debug(`Acknowledgment phase completed`),r}function pi(e,t){try{JSON.parse(e)}catch{throw Error(`${t} must be valid JSON`)}}function mi(e,t){let n=e.trim();if(!/^\d+$/.test(n))throw Error(`${t} must be a positive integer, received: ${e}`);let r=Number.parseInt(n,10);if(r===0)throw Error(`${t} must be a positive integer, received: ${e}`);return r}function hi(e){let t=e.trim(),n=t.indexOf(`/`);if(n===-1)throw Error(`Invalid model format: "${e}". Expected "provider/model" (e.g., "anthropic/claude-sonnet-4-20250514")`);let r=t.slice(0,n).trim(),i=t.slice(n+1).trim();if(r.length===0)throw Error(`Invalid model format: "${e}". Provider cannot be empty.`);if(i.length===0)throw Error(`Invalid model format: "${e}". Model ID cannot be empty.`);return{providerID:r,modelID:i}}function gi(e,t=`timeout`){let n=e.trim();if(!/^\d+$/.test(n))throw Error(`${t} must be a non-negative integer, received: ${e}`);let r=Number.parseInt(n,10);if(Number.isNaN(r)||r<0)throw Error(`${t} must be a non-negative integer, received: ${e}`);return r}const _i=[`claude`,`claude-max20`,`copilot`,`gemini`,`openai`,`opencode-zen`,`zai-coding-plan`,`kimi-for-coding`];function vi(e){let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0),n=`no`,r=`no`,i=`no`,a=`no`,o=`no`,s=`no`,c=`no`;for(let e of t){if(!_i.includes(e))throw Error(`Invalid omo-providers value: "${e}". Valid values: ${_i.join(`, `)}`);switch(e){case`claude`:n=`yes`;break;case`claude-max20`:n=`max20`;break;case`copilot`:r=`yes`;break;case`gemini`:i=`yes`;break;case`openai`:a=`yes`;break;case`opencode-zen`:o=`yes`;break;case`zai-coding-plan`:s=`yes`;break;case`kimi-for-coding`:c=`yes`;break}}return{claude:n,copilot:r,gemini:i,openai:a,opencodeZen:o,zaiCodingPlan:s,kimiForCoding:c}}function yi(){try{let e=a(`github-token`,{required:!0}).trim();if(e.length===0)return si(Error(`github-token is required but was not provided`));let t=a(`auth-json`,{required:!0}).trim();if(t.length===0)return si(Error(`auth-json is required but was not provided`));pi(t,`auth-json`);let o=a(`prompt`).trim(),s=o.length>0?o:null,c=a(`session-retention`).trim(),l=c.length>0?mi(c,`session-retention`):50,u=a(`s3-backup`).trim().toLowerCase()===`true`,d=a(`s3-bucket`).trim(),f=d.length>0?d:null,p=a(`aws-region`).trim(),m=p.length>0?p:null,h=a(`agent`).trim(),g=h.length>0?h:fe,v=a(`model`).trim(),y=v.length>0?hi(v):null,b=a(`timeout`).trim(),x=b.length>0?gi(b):r,S=a(`opencode-version`).trim(),C=S.length>0?S:i,w=a(`skip-cache`).trim().toLowerCase()===`true`,T=a(`omo-version`).trim(),E=T.length>0?T:_,D=a(`omo-providers`).trim(),O=vi(D.length>0?D:``),k=a(`opencode-config`).trim(),A=k.length>0?k:null,j=a(`dedup-window`).trim(),ee=j.length>0?gi(j,`dedup-window`):n;if(A!=null){pi(A,`opencode-config`);let e=JSON.parse(A);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Input 'opencode-config' must be a JSON object`)}return oi({githubToken:e,authJson:t,prompt:s,sessionRetention:l,s3Backup:u,s3Bucket:f,awsRegion:m,agent:g,model:y,timeoutMs:x,opencodeVersion:C,skipCache:w,omoVersion:E,omoProviders:O,opencodeConfig:A,dedupWindow:ee})}catch(e){return si(e instanceof Error?e:Error(String(e)))}}async function bi(n){let r=yi();if(!r.success)return t(`Invalid inputs: ${r.error.message}`),null;let i=r.data,a=e({phase:`main`});a.info(`Action inputs parsed`,{sessionRetention:i.sessionRetention,s3Backup:i.s3Backup,hasGithubToken:i.githubToken.length>0,hasPrompt:i.prompt!=null,agent:i.agent,hasModelOverride:i.model!=null,timeoutMs:i.timeoutMs});let o=await di({logger:a,opencodeVersion:i.opencodeVersion,githubToken:i.githubToken,authJson:i.authJson,omoVersion:i.omoVersion,omoProviders:i.omoProviders,opencodeConfig:i.opencodeConfig});return o.didSetup?a.info(`OpenCode auto-setup completed`,{version:o.version}):a.info(`OpenCode already available`,{version:o.version}),F(N.OPENCODE_VERSION,o.version),n.debug(`Bootstrap phase completed`,{opencodeVersion:o.version}),{inputs:i,logger:a,opencodeResult:o}}const xi=/^[0-9a-f]{40}$/i;function Si(){return{exec:v,getExecOutput:b}}async function Ci(e){let{workspacePath:t,logger:n,execAdapter:r=Si()}=e,i=B.join(t,`.git`),a=B.join(i,`opencode`);try{let e=(await z.readFile(a,`utf8`)).trim();if(e.length>0){if(xi.test(e))return n.debug(`Project ID loaded from cache`,{projectId:e}),{projectId:e,source:`cached`};n.warning(`Invalid cached project ID format, regenerating`,{cachedId:e})}}catch(e){n.debug(`No cached project ID found`,{error:M(e)})}try{let e=await z.readFile(i,`utf8`),n=/^gitdir: (.+)$/m.exec(e);if(n==null)return{projectId:null,source:`error`,error:`Invalid .git file format`};i=B.resolve(t,n[1]),a=B.join(i,`opencode`)}catch(e){if((typeof e==`object`?e.code:void 0)!==`EISDIR`)return{projectId:null,source:`error`,error:`Not a git repository`}}try{let{stdout:e,exitCode:i}=await r.getExecOutput(`git`,[`rev-list`,`--max-parents=0`,`--all`],{cwd:t,silent:!0});if(i!==0||e.trim().length===0)return{projectId:null,source:`error`,error:`No commits found in repository`};let o=e.trim().split(` -`).map(e=>e.trim()).filter(e=>e.length>0).sort();if(o.length===0)return{projectId:null,source:`error`,error:`No root commits found`};let s=o[0];try{await z.writeFile(a,s,{encoding:`utf8`,flag:`wx`}),n.info(`Project ID generated and cached`,{projectId:s,source:`generated`})}catch(e){(typeof e==`object`?e.code:void 0)===`EEXIST`?n.debug(`Project ID file already written by concurrent process, skipping`,{projectId:s}):n.warning(`Failed to cache project ID (continuing)`,{error:M(e)})}return{projectId:s,source:`generated`}}catch(e){return{projectId:null,source:`error`,error:M(e)}}}async function wi(n){let r=T(),i=e({phase:`cache`}),a=P(),o=B.join(a,`.git`,`opencode`),s=await oe({components:r,logger:i,storagePath:A(),authPath:ne(),projectIdPath:o,opencodeVersion:n.opencodeResult.version}),c=s.corrupted?`corrupted`:s.hit?`hit`:`miss`;n.logger.info(`Cache restore completed`,{cacheStatus:c,key:s.key});let l=await Ci({workspacePath:a,logger:i});l.source===`error`?i.warning(`Failed to generate project ID (continuing)`,{error:l.error}):i.debug(`Project ID ready`,{projectId:l.projectId,source:l.source});let u=e({phase:`server-bootstrap`}),d=await li(new AbortController().signal,u);if(!d.success)return t(`OpenCode server bootstrap failed: ${d.error.message}`),null;let f=d.data;return u.info(`SDK server bootstrapped successfully`),{cacheResult:s,cacheStatus:c,serverHandle:f}}const Ti={markdownImage:/!\[([^\]]*)\]\((https:\/\/github\.com\/user-attachments\/assets\/[^)]+)\)/gi,markdownLink:/\[([^\]]+)\]\((https:\/\/github\.com\/user-attachments\/files\/[^)]+)\)/gi,htmlImage:/]*src=["'](https:\/\/github\.com\/user-attachments\/assets\/[^"']+)["'][^>]*>/gi};function Ei(e,t,n){e.lastIndex=0;let r=e.exec(t);for(;r!=null;)n(r),r=e.exec(t);e.lastIndex=0}function Di(e){let t=[],n=new Set;return Ei(Ti.markdownImage,e,e=>{let r=e[2],i=e[1],a=e[0];r!=null&&i!=null&&!n.has(r)&&bn(r)&&(n.add(r),t.push({url:r,originalMarkdown:a,altText:i,type:`image`}))}),Ei(Ti.markdownLink,e,e=>{let r=e[2],i=e[1],a=e[0];r!=null&&i!=null&&!n.has(r)&&bn(r)&&(n.add(r),t.push({url:r,originalMarkdown:a,altText:i,type:`file`}))}),Ei(Ti.htmlImage,e,e=>{let r=e[1],i=e[0];if(r!=null&&!n.has(r)&&bn(r)){n.add(r);let e=/alt=["']([^"']*)["']/i.exec(i);t.push({url:r,originalMarkdown:i,altText:e?.[1]??``,type:`image`})}}),Ti.htmlImage.lastIndex=0,t}function Oi(e,t,n){try{let r=new URL(e).pathname.split(`/`).at(-1);if(r!=null&&/\.[a-z0-9]+$/i.test(r))return r;if(t.trim().length>0){let e=t.replaceAll(/[^\w.-]/g,`_`).slice(0,50);return e.trim().length>0?e:`attachment_${n+1}`}return`attachment_${n+1}`}catch{return`attachment_${n+1}`}}const ki={maxFiles:5,maxFileSizeBytes:5*1024*1024,maxTotalSizeBytes:15*1024*1024,allowedMimeTypes:[`image/png`,`image/jpeg`,`image/gif`,`image/webp`,`image/svg+xml`,`text/plain`,`text/markdown`,`text/csv`,`application/json`,`application/pdf`]},Ai=[`github.com`,`githubusercontent.com`];async function ji(e,t,n,r,i){i.debug(`Downloading attachment`,{url:e.url});try{let a=await fetch(e.url,{headers:{Authorization:`Bearer ${n}`,Accept:`*/*`,"User-Agent":`fro-bot-agent`},redirect:`manual`}),o=a;if(a.status>=300&&a.status<400){let t=a.headers.get(`location`);if(t==null)return i.warning(`Redirect without location`,{url:e.url}),null;let n=new URL(t);if(!Ai.some(e=>n.hostname===e||n.hostname.endsWith(`.${e}`)))return i.warning(`Redirect to non-GitHub host blocked`,{url:e.url,redirectTo:n.hostname}),null;o=await fetch(t,{headers:{Accept:`*/*`,"User-Agent":`fro-bot-agent`},redirect:`follow`})}if(!o.ok)return i.warning(`Attachment download failed`,{url:e.url,status:o.status}),null;let s=o.headers.get(`content-length`);if(s!=null){let t=Number.parseInt(s,10);if(t>r.maxFileSizeBytes)return i.warning(`Attachment exceeds size limit (Content-Length)`,{url:e.url,size:t,limit:r.maxFileSizeBytes}),null}let c=ve.from(await o.arrayBuffer());if(c.length>r.maxFileSizeBytes)return i.warning(`Attachment exceeds size limit`,{url:e.url,size:c.length,limit:r.maxFileSizeBytes}),null;let l=o.headers.get(`content-type`)??`application/octet-stream`,u=Oi(e.url,e.altText,t),d=l.split(`;`)[0],f=d==null?`application/octet-stream`:d.trim(),p=await z.mkdtemp(B.join(Ee.tmpdir(),`fro-bot-attachments-`)),m=u.trim().length>0?u:`attachment_${t+1}`,h=B.join(p,m);return await z.writeFile(h,c),i.debug(`Attachment downloaded`,{filename:u,mime:f,sizeBytes:c.length,tempPath:h}),{url:e.url,filename:u,mime:f,sizeBytes:c.length,tempPath:h}}catch(t){return i.warning(`Attachment download error`,{url:e.url,error:M(t)}),null}}async function Mi(e,t,n=ki,r){return Promise.all(e.map(async(e,i)=>ji(e,i,t,n,r)))}async function Ni(e,t){for(let n of e)try{await z.unlink(n);let e=B.dirname(n);await z.rmdir(e).catch(()=>{})}catch(e){t.debug(`Failed to cleanup temp file`,{path:n,error:M(e)})}}function Pi(e){return e.map(e=>({type:`file`,mime:e.mime,url:xe(e.tempPath).toString(),filename:e.filename}))}function Fi(e,t,n){let r=e,i=new Set(n.map(e=>e.filename));for(let e of t){let t=n.find(e=>i.has(e.filename));t!=null&&(r=r.replace(e.originalMarkdown,`@${t.filename}`))}return r}function Ii(e,t,n,r){return{processed:n,skipped:r,modifiedBody:Fi(e,t,n),fileParts:Pi(n),tempFiles:n.map(e=>e.tempPath)}}function Li(e){if(e<0||!Number.isFinite(e))throw Error(`Invalid bytes value: ${e}`);return e<1024?`${e}B`:e<1024*1024?`${(e/1024).toFixed(1)}KB`:`${(e/(1024*1024)).toFixed(1)}MB`}function Ri(e,t=ki,n){let r=[],i=[],a=0;for(let o of e)if(o!=null){if(r.length>=t.maxFiles){i.push({url:o.url,reason:`Exceeds max file count (${t.maxFiles})`}),n.debug(`Attachment skipped: max count`,{url:o.url});continue}if(o.sizeBytes>t.maxFileSizeBytes){i.push({url:o.url,reason:`File too large (${Li(o.sizeBytes)} > ${Li(t.maxFileSizeBytes)})`}),n.debug(`Attachment skipped: too large`,{url:o.url,size:o.sizeBytes});continue}if(a+o.sizeBytes>t.maxTotalSizeBytes){i.push({url:o.url,reason:`Would exceed total size limit (${Li(t.maxTotalSizeBytes)})`}),n.debug(`Attachment skipped: total size exceeded`,{url:o.url});continue}if(!zi(o.mime,t.allowedMimeTypes)){i.push({url:o.url,reason:`MIME type not allowed: ${o.mime}`}),n.debug(`Attachment skipped: MIME type`,{url:o.url,mime:o.mime});continue}a+=o.sizeBytes,r.push({filename:o.filename,mime:o.mime,sizeBytes:o.sizeBytes,tempPath:o.tempPath}),n.info(`Attachment validated`,{filename:o.filename,mime:o.mime,sizeBytes:o.sizeBytes})}return{validated:r,skipped:i}}function zi(e,t){let[n]=e.split(`/`);for(let r of t)if(r===e||r.endsWith(`/*`)&&n!=null&&n===r.slice(0,-2))return!0;return!1}function J(e){let t=B.resolve(e);return t.endsWith(B.sep)&&t.length>1?t.slice(0,-1):t}const Bi=e=>typeof e==`object`&&!!e,Y=e=>typeof e==`string`?e:null,Vi=e=>typeof e==`number`?e:null;function Hi(e){if(Array.isArray(e))return e.filter(Bi).map(e=>({file:Y(e.file)??``,additions:Vi(e.additions)??0,deletions:Vi(e.deletions)??0}))}function Ui(e){return{id:e.id,version:e.version,projectID:e.projectID,directory:e.directory,parentID:e.parentID,title:e.title,time:{created:e.time.created,updated:e.time.updated,compacting:e.time.compacting,archived:e.time.archived},summary:e.summary==null?void 0:{additions:e.summary.additions,deletions:e.summary.deletions,files:e.summary.files,diffs:Hi(e.summary.diffs)},share:e.share?.url==null?void 0:{url:e.share.url},permission:e.permission==null?void 0:{rules:e.permission.rules},revert:e.revert==null?void 0:{messageID:e.revert.messageID,partID:e.revert.partID,snapshot:e.revert.snapshot,diff:e.revert.diff}}}async function Wi(e,t){let n=await e.project.list();if(n.error!=null||n.data==null)return t.warning(`SDK project list failed`,{error:String(n.error)}),[];if(!Array.isArray(n.data))return[];let r=[];for(let e of n.data){if(!Bi(e))continue;let t=Y(e.id),n=Y(e.worktree),i=Y(e.path);t==null||n==null||i==null||r.push({id:t,worktree:n,path:i,vcs:`git`,time:{created:0,updated:0}})}return r}async function Gi(e,t,n){let r=J(t),i=await Wi(e,n);for(let e of i){if(J(e.worktree)===r)return e;let t=Y(e.path);if(t!=null&&J(t)===r)return e}return null}function Ki(e){return e.status===`running`?{status:`running`,input:e.input,time:{start:e.time.start}}:e.status===`error`?{status:`error`,input:e.input,error:e.error,time:{start:e.time.start,end:e.time.end}}:e.status===`pending`?{status:`pending`}:{status:`completed`,input:e.input,output:e.output,title:e.title,metadata:e.metadata,time:{start:e.time.start,end:e.time.end,compacted:e.time.compacted},attachments:void 0}}function qi(e){let t={id:e.id,sessionID:e.sessionID,messageID:e.messageID};if(e.type===`text`)return{...t,type:`text`,text:e.text,synthetic:e.synthetic,ignored:e.ignored,time:e.time,metadata:e.metadata};if(e.type===`reasoning`)return{...t,type:`reasoning`,reasoning:e.reasoning??e.text,time:e.time};if(e.type===`tool`)return{...t,type:`tool`,callID:e.callID,tool:e.tool,state:Ki(e.state),metadata:e.metadata};if(e.type!==`step-finish`)return{...t,type:`text`,text:`text`in e?e.text:``};let n=e;return{...t,type:`step-finish`,reason:n.reason,snapshot:n.snapshot,cost:n.cost,tokens:{input:n.tokens.input,output:n.tokens.output,reasoning:n.tokens.reasoning,cache:{read:n.tokens.cache.read,write:n.tokens.cache.write}}}}function Ji(e){if(e.role===`user`){let t=e;return{id:t.id,sessionID:t.sessionID,role:`user`,time:{created:t.time.created},summary:t.summary==null?void 0:{title:t.summary.title,body:t.summary.body,diffs:Hi(t.summary.diffs)??[]},agent:t.agent,model:{providerID:t.model.providerID,modelID:t.model.modelID},system:t.system,tools:t.tools,variant:t.variant}}let t=e;return{id:t.id,sessionID:t.sessionID,role:`assistant`,time:{created:t.time.created,completed:t.time.completed},parentID:t.parentID,modelID:t.modelID,providerID:t.providerID,mode:t.mode,agent:t.agent??``,path:{cwd:t.path.cwd,root:t.path.root},summary:t.summary,cost:t.cost,tokens:{input:t.tokens.input,output:t.tokens.output,reasoning:t.tokens.reasoning,cache:{read:t.tokens.cache.read,write:t.tokens.cache.write}},finish:t.finish,error:t.error?{name:t.error.name,message:Y(t.error.data.message)??``}:void 0}}function Yi(e){return[...e.map(e=>{let t=Ji(`info`in e?e.info:e),n=`parts`in e?e.parts.map(qi):void 0;return n==null||n.length===0?t:{...t,parts:n}})].sort((e,t)=>e.time.created-t.time.created)}async function Xi(e,t,n){let r=await e.session.list({query:{directory:t}});return r.error==null&&r.data!=null?Array.isArray(r.data)?r.data.map(Ui):[]:(n.warning(`SDK session list failed`,{error:String(r.error)}),[])}async function Zi(e,t,n){let r=await e.session.messages({path:{id:t}});return r.error==null&&r.data!=null?Yi(r.data):(n.warning(`SDK session messages failed`,{error:String(r.error)}),[])}async function Qi(e,t,n,r){let i=await e.session.list({query:{directory:t,start:n,roots:!0,limit:10}});if(i.error!=null||i.data==null)return r.warning(`SDK session list failed`,{error:String(i.error)}),null;if(!Array.isArray(i.data)||i.data.length===0)return null;let a=i.data.map(Ui);if(a.length===0)return null;let o=a.reduce((e,t)=>t.time.created>e.time.created?t:e);return{projectID:o.projectID,session:o}}async function $i(e,t,n){let r=await e.session.delete({path:{id:t}});if(r.error!=null){n.warning(`SDK session delete failed`,{sessionID:t,error:String(r.error)});return}n.debug(`Deleted session via SDK`,{sessionID:t})}const ea={maxSessions:50,maxAgeDays:30};async function ta(e,t,n,r){let{maxSessions:i,maxAgeDays:a}=n;if(r.info(`Starting session pruning`,{workspacePath:t,maxSessions:i,maxAgeDays:a}),await Gi(e,t,r)==null)return r.debug(`No project found for pruning`,{workspacePath:t}),{prunedCount:0,prunedSessionIds:[],remainingCount:0,freedBytes:0};let o=await Xi(e,t,r),s=o.filter(e=>e.parentID==null);if(s.length===0)return{prunedCount:0,prunedSessionIds:[],remainingCount:0,freedBytes:0};let c=[...s].sort((e,t)=>t.time.updated-e.time.updated),l=new Date;l.setDate(l.getDate()-a);let u=l.getTime(),d=new Set;for(let e of c)e.time.updated>=u&&d.add(e.id);for(let e=0;e!d.has(e.id)),p=new Set;for(let e of f){p.add(e.id);for(let t of o)t.parentID===e.id&&p.add(t.id)}if(p.size===0)return r.info(`No sessions to prune`),{prunedCount:0,prunedSessionIds:[],remainingCount:s.length,freedBytes:0};let m=[];for(let t of p)try{await $i(e,t,r),m.push(t),r.debug(`Pruned session`,{sessionId:t})}catch(e){r.warning(`Failed to prune session`,{sessionId:t,error:M(e)})}let h=s.length-f.length;return r.info(`Session pruning complete`,{prunedCount:m.length,remainingCount:h}),{prunedCount:m.length,prunedSessionIds:m,remainingCount:h,freedBytes:0}}async function na(e,t,n,r){let{limit:i,fromDate:a,toDate:o}=n;r.debug(`Listing sessions`,{directory:t,limit:i});let s=[...(await Xi(e,t,r)).filter(e=>!(e.parentID!=null||a!=null&&e.time.createdo.getTime()))].sort((e,t)=>t.time.updated-e.time.updated),c=[],l=i==null?s:s.slice(0,i);for(let t of l){let n=await Zi(e,t.id,r),i=ra(n);c.push({id:t.id,projectID:t.projectID,directory:t.directory,title:t.title,createdAt:t.time.created,updatedAt:t.time.updated,messageCount:n.length,agents:i,isChild:!1})}return r.info(`Listed sessions`,{count:c.length,directory:t}),c}function ra(e){let t=new Set;for(let n of e)n.agent!=null&&t.add(n.agent);return[...t]}async function ia(e,t,n,r,i){let{limit:a=20,caseSensitive:o=!1,sessionId:s}=r;i.debug(`Searching sessions`,{query:e,directory:n,limit:a,caseSensitive:o});let c=o?e:e.toLowerCase(),l=[],u=0;if(s!=null){let e=await aa(t,s,c,o,i);return e.length>0&&l.push({sessionId:s,matches:e.slice(0,a)}),l}let d=await na(t,n,{},i);for(let e of d){if(u>=a)break;let n=await aa(t,e.id,c,o,i);if(n.length>0){let t=a-u;l.push({sessionId:e.id,matches:n.slice(0,t)}),u+=Math.min(n.length,t)}}return i.info(`Session search complete`,{query:e,resultCount:l.length,totalMatches:u}),l}async function aa(e,t,n,r,i){let a=await Zi(e,t,i),o=[];for(let e of a){let t=e.parts??[];for(let i of t){let t=oa(i);if(t==null)continue;let a=r?t:t.toLowerCase();if(a.includes(n)){let r=a.indexOf(n),s=Math.max(0,r-50),c=Math.min(t.length,r+n.length+50),l=t.slice(s,c);o.push({messageId:e.id,partId:i.id,excerpt:`...${l}...`,role:e.role,agent:e.agent})}}}return o}function oa(e){switch(e.type){case`text`:return e.text;case`reasoning`:return e.reasoning;case`tool`:return e.state.status===`completed`?`${e.tool}: ${e.state.output}`:null;case`step-finish`:return null}}function sa(e){let t=[`--- Fro Bot Run Summary ---`,`Event: ${e.eventType}`,`Repo: ${e.repo}`,`Ref: ${e.ref}`,`Run ID: ${e.runId}`,`Cache: ${e.cacheStatus}`,`Duration: ${e.duration}s`];return e.sessionIds.length>0&&t.push(`Sessions used: ${e.sessionIds.join(`, `)}`),e.logicalKey!=null&&t.push(`Logical Thread: ${e.logicalKey}`),e.createdPRs.length>0&&t.push(`PRs created: ${e.createdPRs.join(`, `)}`),e.createdCommits.length>0&&t.push(`Commits: ${e.createdCommits.join(`, `)}`),e.tokenUsage!=null&&t.push(`Tokens: ${e.tokenUsage.input} in / ${e.tokenUsage.output} out`),t.join(` -`)}async function ca(e,t,n,r){let i=sa(t);try{let t=await n.session.prompt({path:{id:e},body:{noReply:!0,parts:[{type:`text`,text:i}]}});if(t.error!=null){r.warning(`SDK prompt writeback failed`,{sessionId:e,error:String(t.error)});return}r.info(`Session summary written via SDK`,{sessionId:e})}catch(t){r.warning(`SDK prompt writeback failed`,{sessionId:e,error:M(t)})}}async function la(t){let{bootstrapLogger:n,reactionCtx:r,githubClient:i,agentSuccess:a,attachmentResult:o,serverHandle:s,detectedOpencodeVersion:c}=t;try{if(o!=null){let t=e({phase:`attachment-cleanup`});await Ni(o.tempFiles,t)}r!=null&&i!=null&&await ir(i,r,a,e({phase:`cleanup`}));let t=e({phase:`prune`}),n=P();if(s!=null){let e=J(n),r=await ta(s.client,e,ea,t);r.prunedCount>0&&t.info(`Pruned old sessions`,{pruned:r.prunedCount,remaining:r.remainingCount})}let l=T(),u=e({phase:`cache-save`}),d=B.join(n,`.git`,`opencode`);if(await re({components:l,runId:k(),logger:u,storagePath:A(),authPath:ne(),projectIdPath:d,opencodeVersion:c})&&F(N.CACHE_SAVED,`true`),pe()){let t=e({phase:`artifact-upload`});await ce({logPath:j(),runId:k(),runAttempt:O(),logger:t})&&F(N.ARTIFACT_UPLOADED,`true`)}}catch(e){n.warning(`Cleanup failed (non-fatal)`,{error:e instanceof Error?e.message:String(e)})}finally{if(s!=null)try{s.shutdown()}catch(e){n.warning(`Server shutdown failed (non-fatal)`,{error:e instanceof Error?e.message:String(e)})}}}const ua=B.join(De.homedir(),`.cache`,`fro-bot-dedup`);function da(e){return e.replaceAll(`/`,`-`)}function fa(e,t){let n=da(e);return B.join(ua,`${n}-${t.entityType}-${t.entityNumber}`)}function pa(e,t){return`${E}-${da(e)}-${t.entityType}-${t.entityNumber}-`}function ma(e,t,n){return`${pa(e,t)}${n}`}async function ha(e,t,n,r=ee){let i=fa(e,t),a=B.join(i,`sentinel.json`),o=pa(e,t);try{if(await z.rm(i,{recursive:!0,force:!0}),await z.mkdir(i,{recursive:!0}),await r.restoreCache([i],o,[])==null)return null;let e=await z.readFile(a,`utf8`);return JSON.parse(e)}catch(e){return n.debug(`Dedup marker restore failed; proceeding without marker`,{error:M(e),entityType:t.entityType,entityNumber:t.entityNumber}),null}}async function ga(e,t,n,r,i=ee){let a=fa(e,t),o=B.join(a,`sentinel.json`),s=ma(e,t,n.runId);try{return await z.mkdir(a,{recursive:!0}),await z.writeFile(o,JSON.stringify(n),`utf8`),await i.saveCache([a],s),!0}catch(e){return M(e).toLowerCase().includes(`already exists`)?!0:(r.debug(`Dedup marker save failed`,{error:M(e),entityType:t.entityType,entityNumber:t.entityNumber,saveKey:s}),!1)}}const _a=new Set([`pull_request`,`issues`]);function va(e){return e.target==null||!_a.has(e.eventType)?null:e.eventType===`pull_request`&&e.target.kind===`pr`?{entityType:`pr`,entityNumber:e.target.number}:e.eventType===`issues`&&e.target.kind===`issue`?{entityType:`issue`,entityNumber:e.target.number}:null}async function ya(t,n,r,i,a=e({phase:`dedup`}),o){let s=va(n);if(t===0)return{shouldProceed:!0,entity:s};if(s==null)return{shouldProceed:!0,entity:null};let c=await ha(r,s,a,o);if(c==null||c.runId===n.runId)return{shouldProceed:!0,entity:s};let l=new Date(c.timestamp).getTime();if(Number.isNaN(l))return a.warning(`Dedup marker timestamp is invalid; proceeding without dedup`,{markerTimestamp:c.timestamp}),{shouldProceed:!0,entity:s};let u=Date.now()-l;return u<-6e4?(a.warning(`Dedup marker timestamp is too far in the future; proceeding without dedup`,{markerTimestamp:c.timestamp,markerAge:u}),{shouldProceed:!0,entity:s}):Math.max(0,u)>t?{shouldProceed:!0,entity:s}:(a.info(`Skipping duplicate trigger within dedup window`,{eventType:n.eventType,action:n.action,runId:n.runId,markerRunId:c.runId,markerTimestamp:c.timestamp,dedupWindow:t,entityType:s.entityType,entityNumber:s.entityNumber}),V({sessionId:null,cacheStatus:`miss`,duration:Date.now()-i}),{shouldProceed:!1,entity:s})}async function ba(t,n,r,i=e({phase:`dedup`}),a){await ga(r,n,{timestamp:new Date().toISOString(),runId:t.runId,action:t.action??`unknown`,eventType:t.eventType,entityType:n.entityType,entityNumber:n.entityNumber},i,a)}async function xa(t,n,r,i,a,o){let s={context:n.agentContext,customPrompt:t.inputs.prompt,cacheStatus:r.cacheStatus,sessionContext:{recentSessions:i.recentSessions,priorWorkContext:i.priorWorkContext},logicalKey:i.logicalKey??null,isContinuation:i.isContinuation,currentThreadSessionId:i.continueSessionId??null,triggerContext:n.triggerResult.context,fileParts:i.attachmentResult?.fileParts},c=I.env.SKIP_AGENT_EXECUTION===`true`,l=Date.now(),u;if(c)t.logger.info(`Skipping agent execution (SKIP_AGENT_EXECUTION=true)`),u={success:!0,exitCode:0,sessionId:null,error:null,tokenUsage:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:null};else{let n=e({phase:`execution`});n.info(`Starting OpenCode execution`,{logicalKey:i.logicalKey?.key??null,continueSessionId:i.continueSessionId});let a=await Yn(s,n,{agent:t.inputs.agent,model:t.inputs.model,timeoutMs:t.inputs.timeoutMs,omoProviders:t.inputs.omoProviders,continueSessionId:i.continueSessionId??void 0,sessionTitle:i.sessionTitle??void 0},r.serverHandle),o=a.sessionId;if(o==null){let t=e({phase:`session`}),n=await Qi(r.serverHandle.client,i.normalizedWorkspace,l,t);n!=null&&(o=n.session.id,t.debug(`Identified session from execution`,{sessionId:o}))}u={...a,sessionId:o},n.info(`Completed OpenCode execution`,{success:u.success,sessionId:u.sessionId,logicalKey:i.logicalKey?.key??null})}u.sessionId!=null&&(F(N.SESSION_ID,u.sessionId),a.addSessionCreated(u.sessionId)),u.tokenUsage!=null&&a.setTokenUsage(u.tokenUsage,u.model,u.cost);for(let e of u.prsCreated)a.addPRCreated(e);for(let e of u.commitsCreated)a.addCommitCreated(e);for(let e=0;e`)}async function wa(e,t,n){try{if(t.type===`pr`){let{data:n}=await e.rest.pulls.get({owner:t.owner,repo:t.repo,pull_number:t.number});return{title:n.title,body:n.body??``,author:n.user?.login??`unknown`}}let{data:n}=await e.rest.issues.get({owner:t.owner,repo:t.repo,issue_number:t.number});return{title:n.title,body:n.body??``,author:n.user?.login??`unknown`}}catch(e){return n.warning(`Failed to fetch issue/PR`,{target:t,error:M(e)}),null}}async function Ta(e,t,n,r){let i=[],a=1;for(;a<=50;)try{let{data:r}=await e.rest.issues.listComments({owner:t.owner,repo:t.repo,issue_number:t.number,per_page:100,page:a});if(r.length===0)break;for(let e of r){let t=e.user?.login??`unknown`;i.push({id:e.id,body:e.body??``,author:t,authorAssociation:e.author_association??`NONE`,createdAt:e.created_at,updatedAt:e.updated_at,isBot:Ca(t,e.body??``,n)})}if(r.length<100)break;a++}catch(e){r.warning(`Failed to fetch comments page`,{target:t,page:a,error:M(e)});break}return i}async function Ea(e,t,n,r){try{let i=[],a=null,o=null,s=``,c=``,l=`unknown`,u=0;for(;u<50;){let d=(await e.graphql(` +If you had completed the task, confirm the completion.`,u=r===1?e.fileParts:void 0,g=await(async()=>{try{return await Pn(s,l,a,u,f,n,t)}finally{await sn(s,l,n?.sessionTitle,t)}})();if(g.success)return p=g.eventStreamResult,{success:!0,exitCode:0,duration:Date.now()-i,sessionId:l,error:null,tokenUsage:p.tokens,model:p.model,cost:p.cost,prsCreated:p.prsCreated,commitsCreated:p.commitsCreated,commentsPosted:p.commentsPosted,llmError:null};if(m=g.error,h=g.llmError,!g.shouldRetry||r>=3)break;t.warning(`LLM fetch error detected, retrying with continuation prompt`,{attempt:r,maxAttempts:3,error:g.error,delayMs:jn,sessionId:l}),await cn(jn)}return{success:!1,exitCode:1,duration:Date.now()-i,sessionId:l,error:m??`Unknown error`,tokenUsage:p.tokens,model:p.model,cost:p.cost,prsCreated:p.prsCreated,commitsCreated:p.commitsCreated,commentsPosted:p.commentsPosted,llmError:h}}catch(e){let n=Date.now()-i,r=A(e);return t.error(`OpenCode execution failed`,{error:r,durationMs:n}),{success:!1,exitCode:1,duration:n,sessionId:null,error:r,tokenUsage:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:mn(e)?hn(r):null}}finally{s!=null&&clearTimeout(s),a.abort(),l&&u?.close()}}async function Xn(e,t,n){return t.commentId==null?(n.debug(`No comment ID, skipping eyes reaction`),!1):await Ie(e,t.repo,t.commentId,`eyes`,n)==null?!1:(n.info(`Added eyes reaction`,{commentId:t.commentId}),!0)}async function Zn(e,t,n){return t.issueNumber==null?(n.debug(`No issue number, skipping working label`),!1):await ze(e,t.repo,`agent: working`,`fcf2e1`,`Agent is currently working on this`,n)&&await Be(e,t.repo,t.issueNumber,[`agent: working`],n)?(n.info(`Added working label`,{issueNumber:t.issueNumber}),!0):!1}async function Qn(e,t,n){await Promise.all([Xn(e,t,n),Zn(e,t,n)])}async function $n(e,t,n){if(t.commentId==null||t.botLogin==null)return;let r=(await Le(e,t.repo,t.commentId,n)).find(e=>e.content===`eyes`&&e.userLogin===t.botLogin);r!=null&&await Re(e,t.repo,t.commentId,r.id,n)}async function er(e,t,n,r){t.commentId!=null&&await Ie(e,t.repo,t.commentId,n,r)}async function tr(e,t,n){if(t.commentId==null||t.botLogin==null){n.debug(`Missing comment ID or bot login, skipping reaction update`);return}try{await $n(e,t,n),await er(e,t,`hooray`,n),n.info(`Updated reaction to success indicator`,{commentId:t.commentId,reaction:`hooray`})}catch(e){n.warning(`Failed to update reaction (non-fatal)`,{error:A(e)})}}async function nr(e,t,n){if(t.commentId==null||t.botLogin==null){n.debug(`Missing comment ID or bot login, skipping reaction update`);return}try{await $n(e,t,n),await er(e,t,`confused`,n),n.info(`Updated reaction to confused`,{commentId:t.commentId})}catch(e){n.warning(`Failed to update failure reaction (non-fatal)`,{error:A(e)})}}async function rr(e,t,n){if(t.issueNumber==null){n.debug(`No issue number, skipping label removal`);return}await Ve(e,t.repo,t.issueNumber,`agent: working`,n)&&n.info(`Removed working label`,{issueNumber:t.issueNumber})}async function ir(e,t,n,r){n?await tr(e,t,r):await nr(e,t,r),await rr(e,t,r)}var G=C(E(),1),ar=function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},or=class{constructor(e,t,n){if(e<1)throw Error(`max attempts should be greater than or equal to 1`);if(this.maxAttempts=e,this.minSeconds=Math.floor(t),this.maxSeconds=Math.floor(n),this.minSeconds>this.maxSeconds)throw Error(`min seconds should be less than or equal to max seconds`)}execute(e,t){return ar(this,void 0,void 0,function*(){let n=1;for(;nsetTimeout(t,e*1e3))})}},K=function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},sr=class extends Error{constructor(e){super(`Unexpected HTTP response: ${e}`),this.httpStatusCode=e,Object.setPrototypeOf(this,new.target.prototype)}};const cr=process.platform===`win32`;process.platform;function lr(e,t,n,r){return K(this,void 0,void 0,function*(){return t||=F.join(wr(),ve.randomUUID()),yield l(F.dirname(t)),f(`Downloading ${e}`),f(`Destination ${t}`),yield new or(3,Tr(`TEST_DOWNLOAD_TOOL_RETRY_MIN_SECONDS`,10),Tr(`TEST_DOWNLOAD_TOOL_RETRY_MAX_SECONDS`,20)).execute(()=>K(this,void 0,void 0,function*(){return yield ur(e,t||``,n,r)}),e=>!(e instanceof sr&&e.httpStatusCode&&e.httpStatusCode<500&&e.httpStatusCode!==408&&e.httpStatusCode!==429))})}function ur(e,t,n,r){return K(this,void 0,void 0,function*(){if(P.existsSync(t))throw Error(`Destination file path ${t} already exists`);let i=new x(`actions/tool-cache`,[],{allowRetries:!1});n&&(f(`set auth`),r===void 0&&(r={}),r.authorization=n);let a=yield i.get(e,r);if(a.message.statusCode!==200){let t=new sr(a.message.statusCode);throw f(`Failed to download from "${e}". Code(${a.message.statusCode}) Message(${a.message.statusMessage})`),t}let o=be.promisify(je.pipeline),s=Tr(`TEST_DOWNLOAD_TOOL_RESPONSE_MESSAGE_FACTORY`,()=>a.message)(),c=!1;try{return yield o(s,P.createWriteStream(t)),f(`download complete`),c=!0,t}finally{if(!c){f(`download failed`);try{yield ce(t)}catch(e){f(`Failed to delete '${t}'. ${e.message}`)}}}})}function dr(e,t){return K(this,arguments,void 0,function*(e,t,n=`xz`){if(!e)throw Error(`parameter 'file' is required`);t=yield vr(t),f(`Checking tar --version`);let r=``;yield v(`tar --version`,[],{ignoreReturnCode:!0,silent:!0,listeners:{stdout:e=>r+=e.toString(),stderr:e=>r+=e.toString()}}),f(r.trim());let i=r.toUpperCase().includes(`GNU TAR`),a;a=n instanceof Array?n:[n],h()&&!n.includes(`v`)&&a.push(`-v`);let o=t,s=e;return cr&&i&&(a.push(`--force-local`),o=t.replace(/\\/g,`/`),s=e.replace(/\\/g,`/`)),i&&(a.push(`--warning=no-unknown-keyword`),a.push(`--overwrite`)),a.push(`-C`,o,`-f`,s),yield v(`tar`,a),t})}function fr(e,t){return K(this,void 0,void 0,function*(){if(!e)throw Error(`parameter 'file' is required`);return t=yield vr(t),cr?yield pr(e,t):yield mr(e,t),t})}function pr(e,t){return K(this,void 0,void 0,function*(){let n=e.replace(/'/g,`''`).replace(/"|\n|\r/g,``),r=t.replace(/'/g,`''`).replace(/"|\n|\r/g,``),i=yield c(`pwsh`,!1);if(i){let e=[`-NoLogo`,`-NoProfile`,`-NonInteractive`,`-ExecutionPolicy`,`Unrestricted`,`-Command`,[`$ErrorActionPreference = 'Stop' ;`,`try { Add-Type -AssemblyName System.IO.Compression.ZipFile } catch { } ;`,`try { [System.IO.Compression.ZipFile]::ExtractToDirectory('${n}', '${r}', $true) }`,`catch { if (($_.Exception.GetType().FullName -eq 'System.Management.Automation.MethodException') -or ($_.Exception.GetType().FullName -eq 'System.Management.Automation.RuntimeException') ){ Expand-Archive -LiteralPath '${n}' -DestinationPath '${r}' -Force } else { throw $_ } } ;`].join(` `)];f(`Using pwsh at path: ${i}`),yield v(`"${i}"`,e)}else{let e=[`-NoLogo`,`-Sta`,`-NoProfile`,`-NonInteractive`,`-ExecutionPolicy`,`Unrestricted`,`-Command`,[`$ErrorActionPreference = 'Stop' ;`,`try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ;`,`if ((Get-Command -Name Expand-Archive -Module Microsoft.PowerShell.Archive -ErrorAction Ignore)) { Expand-Archive -LiteralPath '${n}' -DestinationPath '${r}' -Force }`,`else {[System.IO.Compression.ZipFile]::ExtractToDirectory('${n}', '${r}', $true) }`].join(` `)],t=yield c(`powershell`,!0);f(`Using powershell at path: ${t}`),yield v(`"${t}"`,e)}})}function mr(e,t){return K(this,void 0,void 0,function*(){let n=yield c(`unzip`,!0),r=[e];h()||r.unshift(`-q`),r.unshift(`-o`),yield v(`"${n}"`,r,{cwd:t})})}function hr(e,t,n,r){return K(this,void 0,void 0,function*(){if(n=G.clean(n)||n,r||=_e.arch(),f(`Caching tool ${t} ${n} ${r}`),f(`source dir: ${e}`),!P.statSync(e).isDirectory())throw Error(`sourceDir is not a directory`);let i=yield yr(t,n,r);for(let t of P.readdirSync(e))yield o(F.join(e,t),i,{recursive:!0});return br(t,n,r),i})}function gr(e,t,n){if(!e)throw Error(`toolName parameter is required`);if(!t)throw Error(`versionSpec parameter is required`);n||=_e.arch(),xr(t)||(t=Sr(_r(e,n),t));let r=``;if(t){t=G.clean(t)||``;let i=F.join(Cr(),e,t,n);f(`checking cache: ${i}`),P.existsSync(i)&&P.existsSync(`${i}.complete`)?(f(`Found tool in cache ${e} ${t} ${n}`),r=i):f(`not found`)}return r}function _r(e,t){let n=[];t||=_e.arch();let r=F.join(Cr(),e);if(P.existsSync(r)){let e=P.readdirSync(r);for(let i of e)if(xr(i)){let e=F.join(r,i,t||``);P.existsSync(e)&&P.existsSync(`${e}.complete`)&&n.push(i)}}return n}function vr(e){return K(this,void 0,void 0,function*(){return e||=F.join(wr(),ve.randomUUID()),yield l(e),e})}function yr(e,t,n){return K(this,void 0,void 0,function*(){let r=F.join(Cr(),e,G.clean(t)||t,n||``);f(`destination ${r}`);let i=`${r}.complete`;return yield ce(r),yield ce(i),yield l(r),r})}function br(e,t,n){let r=`${F.join(Cr(),e,G.clean(t)||t,n||``)}.complete`;P.writeFileSync(r,``),f(`finished caching tool`)}function xr(e){let t=G.clean(e)||``;f(`isExplicit: ${t}`);let n=G.valid(t)!=null;return f(`explicit? ${n}`),n}function Sr(e,t){let n=``;f(`evaluating ${e.length} versions`),e=e.sort((e,t)=>G.gt(e,t)?1:-1);for(let r=e.length-1;r>=0;r--){let i=e[r];if(G.satisfies(i,t)){n=i;break}}return f(n?`matched: ${n}`:`match not found`),n}function Cr(){let e=process.env.RUNNER_TOOL_CACHE||``;return ye(e,`Expected RUNNER_TOOL_CACHE to be defined`),e}function wr(){let e=process.env.RUNNER_TEMP||``;return ye(e,`Expected RUNNER_TEMP to be defined`),e}function Tr(e,t){let n=global[e];return n===void 0?t:n}function Er(e){let t;try{t=JSON.parse(e)}catch(e){throw e instanceof SyntaxError?Error(`Invalid auth-json format: ${e.message}`):e}if(typeof t!=`object`||!t||Array.isArray(t))throw Error(`auth-json must be a JSON object`);return t}async function Dr(e,t,n){let r=L.join(t,`auth.json`);await I.mkdir(t,{recursive:!0});let i=JSON.stringify(e,null,2);return await I.writeFile(r,i,{mode:384}),n.info(`Populated auth.json`,{path:r,providers:Object.keys(e).length}),r}function Or(){let e=N.platform,t=N.arch;return{os:{darwin:`darwin`,linux:`linux`,win32:`windows`}[e]??`linux`,arch:{arm64:`aarch64`,x64:`x64`}[t]??`x64`,ext:`.zip`}}function kr(e,t){return`https://github.com/oven-sh/bun/releases/download/bun-${e.startsWith(`v`)?e:`v${e}`}/${`bun-${t.os}-${t.arch}${t.ext}`}`}async function Ar(e,t,n,r,i=g){let a=Or(),o=t.find(`bun`,i,a.arch);if(o.length>0)return e.info(`Bun found in cache`,{version:i,path:o}),r(o),await Mr(o),{path:o,version:i,cached:!0};e.info(`Downloading Bun`,{version:i});let s=kr(i,a);try{let o=await t.downloadTool(s);if(N.platform!==`win32`&&!await Nr(o,e,n))throw Error(`Downloaded Bun archive appears corrupted`);e.info(`Extracting Bun`);let c=await jr(await t.extractZip(o),t),l=Ee.dirname(c);e.info(`Caching Bun`);let u=await t.cacheDir(l,`bun`,i,a.arch);return r(u),await Mr(u),e.info(`Bun installed`,{version:i,path:u}),{path:u,version:i,cached:!1}}catch(e){let t=A(e);throw Error(`Failed to install Bun ${i}: ${t}`)}}async function jr(e,t){for(let n of await Te.readdir(e,{withFileTypes:!0})){let{name:r}=n,i=Ee.join(e,r);if(n.isFile()){if(r===`bun`||r===`bun.exe`)return i;if(/^bun.*\.zip/.test(r))return jr(await t.extractZip(i),t)}if(r.startsWith(`bun`)&&n.isDirectory())return jr(i,t)}throw Error(`Could not find executable: bun`)}async function Mr(e){let t=e=>N.platform===`win32`?`${e}.exe`:e,n=Ee.join(e,t(`bun`));try{await Te.symlink(n,Ee.join(e,t(`bunx`)))}catch(e){let t=typeof e==`object`?e.code:void 0;if(t!==`EEXIST`&&t!==`EPERM`&&t!==`EACCES`)throw e}}async function Nr(e,t,n){try{let{stdout:r}=await n.getExecOutput(`file`,[e],{silent:!0}),i=r.includes(`Zip archive`)||r.includes(`ZIP`);return i||t.warning(`Bun download validation failed`,{output:r.trim()}),i}catch{return t.debug(`Could not validate Bun download (file command unavailable)`),!0}}function Pr(e){return{debug:t=>e.debug(t),info:t=>e.info(t),warn:t=>e.warning(t),error:t=>e.error(t)}}function Fr(e){let{token:t,logger:n}=e;return n.debug(`Creating GitHub client with token`),fe(t,{log:Pr(n)})}async function Ir(e,t){try{let{data:n}=await e.rest.users.getAuthenticated();return t.debug(`Authenticated as`,{login:n.login,type:n.type}),n.login}catch{return t.debug(`Failed to get authenticated user, may be app token`),`fro-bot[bot]`}}async function Lr(e,t,n,r){let i=t??n,a=t==null?n.length>0?`github-token`:`none`:`app-token`;if(i.length===0)return r.warning(`No GitHub token available`),{authenticated:!1,method:`none`,botLogin:null};N.env.GH_TOKEN=i,r.info(`Configured authentication`,{method:a});let o=null;return e!=null&&(o=await Ir(e,r)),{authenticated:!0,method:a,botLogin:o}}async function Rr(e,t){let n=await t.getExecOutput(`git`,[`config`,e],{ignoreReturnCode:!0,silent:!0});return n.exitCode===0&&n.stdout.trim().length>0?n.stdout.trim():null}async function zr(e,t,n,r){let i=await Rr(`user.name`,r),a=await Rr(`user.email`,r);if(i!=null&&a!=null){n.info(`Git identity already configured`,{name:i,email:a});return}if(t==null)throw Error(`Cannot configure Git identity: no authenticated GitHub user`);let o=null;if(a==null){let r=await Ge(e,t,n);if(r==null)throw Error(`Cannot configure Git identity: failed to look up user ID for '${t}'`);o=String(r.id)}i??await r.exec(`git`,[`config`,`--global`,`user.name`,t],void 0);let s=`${o}+${t}@users.noreply.github.com`;a??await r.exec(`git`,[`config`,`--global`,`user.email`,s],void 0),n.info(`Configured git identity`,{name:i??t,email:a??s})}const Br=new Set([`__proto__`,`prototype`,`constructor`]);function Vr(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Hr(e,t){let n=Object.create(null);for(let[t,r]of Object.entries(e))Br.has(t)||(n[t]=r);for(let[e,r]of Object.entries(t)){if(Br.has(e))continue;let t=n[e];Vr(r)&&Vr(t)?n[e]=Hr(t,r):n[e]=r}return n}async function Ur(e,t,n){let r=JSON.parse(e);if(!Vr(r))throw Error(`omo-config must be a JSON object (non-null, non-array)`);let i=r;await I.mkdir(t,{recursive:!0});let a=L.join(t,`oh-my-opencode.json`),o={};try{let e=await I.readFile(a,`utf8`),t=JSON.parse(e);typeof t==`object`&&t&&!Array.isArray(t)&&(o=t)}catch(e){n.debug(`Using empty base oMo config`,{path:a,error:String(e)})}let s=Hr(o,i);await I.writeFile(a,JSON.stringify(s,null,2)),n.info(`Wrote oMo config`,{path:a,keyCount:Object.keys(i).length})}async function Wr(e,t,n={}){let{logger:r,execAdapter:i}=t,{claude:a=`no`,copilot:o=`no`,gemini:s=`no`,openai:c=`no`,opencodeZen:l=`no`,zaiCodingPlan:u=`no`,kimiForCoding:d=`no`}=n;r.info(`Installing Oh My OpenAgent plugin`,{version:e,claude:a,copilot:o,gemini:s,openai:c,opencodeZen:l,zaiCodingPlan:u,kimiForCoding:d});let f=``,p=[`oh-my-openagent@${e}`,`install`,`--no-tui`,`--skip-auth`,`--claude=${a}`,`--copilot=${o}`,`--gemini=${s}`,`--openai=${c}`,`--opencode-zen=${l}`,`--zai-coding-plan=${u}`,`--kimi-for-coding=${d}`];try{let t=await i.exec(`bunx`,p,{listeners:{stdout:e=>{f+=e.toString()},stderr:e=>{f+=e.toString()}},ignoreReturnCode:!0});if(t!==0){let e=`bunx oh-my-openagent install returned exit code ${t}`;return r.error(e,{output:f.slice(0,1e3)}),{installed:!1,version:null,error:`${e}\n${f.slice(0,500)}`}}let n=/oh-my-opencode@(\d+\.\d+\.\d+)/i.exec(f),a=n!=null&&n[1]!=null?n[1]:e;return r.info(`oMo plugin installed`,{version:a}),{installed:!0,version:a,error:null}}catch(e){let t=A(e),n=f.length>0?`${t}\nOutput: ${f.slice(0,500)}`:t;return r.error(`Failed to run oMo installer`,{error:t,output:f.slice(0,500)}),{installed:!1,version:null,error:`bunx oh-my-openagent install failed: ${n}`}}}const Gr=`opencode`,Kr=i;function qr(){let e=ke.platform(),t=ke.arch(),n={darwin:`darwin`,linux:`linux`,win32:`windows`},r={x64:`x64`,arm64:`arm64`},i=e===`win32`||e===`darwin`?`.zip`:`.tar.gz`;return{os:n[e]??`linux`,arch:r[t]??`x64`,ext:i}}function Jr(e,t){return`https://github.com/anomalyco/opencode/releases/download/${e.startsWith(`v`)?e:`v${e}`}/${`opencode-${t.os}-${t.arch}${t.ext}`}`}async function Yr(e,t,n,r){if(N.platform===`win32`)return!0;try{let{stdout:i}=await r.getExecOutput(`file`,[e],{silent:!0}),a=(t===`.zip`?[`Zip archive`,`ZIP`]:[`gzip`,`tar`,`compressed`]).some(e=>i.includes(e));return a||n.warning(`Download validation failed`,{output:i.trim()}),a}catch{return n.debug(`Could not validate download (file command unavailable)`),!0}}async function Xr(e,t,n,r,i=Kr){let a=qr(),o=n.find(Gr,e,a.arch);if(o.length>0)return t.info(`OpenCode found in cache`,{version:e,path:o}),{path:o,version:e,cached:!0};try{return await Zr(e,a,t,n,r)}catch(n){t.warning(`Primary version install failed, trying fallback`,{requestedVersion:e,fallbackVersion:i,error:A(n)})}if(e!==i)try{let e=await Zr(i,a,t,n,r);return t.info(`Installed fallback version`,{version:i}),e}catch(t){throw Error(`Failed to install OpenCode (tried ${e} and ${i}): ${A(t)}`)}throw Error(`Failed to install OpenCode version ${e}`)}async function Zr(e,t,n,r,i){n.info(`Downloading OpenCode`,{version:e});let a=Jr(e,t),o=await r.downloadTool(a);if(!await Yr(o,t.ext,n,i))throw Error(`Downloaded archive appears corrupted`);n.info(`Extracting OpenCode`);let s=t.ext===`.zip`?await r.extractZip(o):await r.extractTar(o);n.info(`Caching OpenCode`);let c=await r.cacheDir(s,Gr,e,t.arch);return n.info(`OpenCode installed`,{version:e,path:c}),{path:c,version:e,cached:!1}}async function Qr(e){let t=await fetch(`https://api.github.com/repos/anomalyco/opencode/releases/latest`);if(!t.ok)throw Error(`Failed to fetch latest OpenCode version: ${t.statusText}`);let n=(await t.json()).tag_name.replace(/^v/,``);return e.info(`Latest OpenCode version`,{version:n}),n}const $r={restoreCache:async(e,t,n)=>oe(e,t,n),saveCache:async(e,t)=>ue(e,t)};function ei(e){let{os:t,opencodeVersion:n,omoVersion:r}=e;return`${p}-${t}-oc-${n}-omo-${r}`}function ti(e){let{os:t,opencodeVersion:n,omoVersion:r}=e;return[`${p}-${t}-oc-${n}-omo-${r}-`]}async function ni(e){let{logger:t,os:n,opencodeVersion:r,omoVersion:i,toolCachePath:a,bunCachePath:o,omoConfigPath:s,cacheAdapter:c=$r}=e,l=ei({os:n,opencodeVersion:r,omoVersion:i}),u=ti({os:n,opencodeVersion:r,omoVersion:i}),d=[a,o,s];t.info(`Restoring tools cache`,{primaryKey:l,restoreKeys:[...u],paths:d});try{let e=await c.restoreCache(d,l,[...u]);return e==null?(t.info(`Tools cache miss - will install tools`),{hit:!1,restoredKey:null}):(t.info(`Tools cache restored`,{restoredKey:e}),{hit:!0,restoredKey:e})}catch(e){return t.warning(`Tools cache restore failed`,{error:A(e)}),{hit:!1,restoredKey:null}}}async function ri(e){let{logger:t,os:n,opencodeVersion:r,omoVersion:i,toolCachePath:a,bunCachePath:o,omoConfigPath:s,cacheAdapter:c=$r}=e,l=ei({os:n,opencodeVersion:r,omoVersion:i}),u=[a,o,s];t.info(`Saving tools cache`,{saveKey:l,paths:u});try{return await c.saveCache(u,l),t.info(`Tools cache saved`,{saveKey:l}),!0}catch(e){return e instanceof Error&&e.message.includes(`already exists`)?(t.info(`Tools cache key already exists, skipping save`),!0):(t.warning(`Tools cache save failed`,{error:A(e)}),!1)}}function ii(){return{find:gr,downloadTool:lr,extractTar:dr,extractZip:fr,cacheDir:hr}}function ai(){return{exec:v,getExecOutput:b}}async function oi(n,r){let i=Date.now(),a=e({component:`setup`}),o=ii(),s=ai();try{a.info(`Starting setup`,{version:n.opencodeVersion});let e;try{e=Er(n.authJson)}catch(e){return t(`Invalid auth-json: ${A(e)}`),null}let c=n.opencodeVersion;if(c===`latest`)try{c=await Qr(a)}catch(e){a.warning(`Failed to get latest version, using fallback`,{error:A(e)}),c=Kr}let l=n.omoVersion,u=N.env.RUNNER_TOOL_CACHE??`/opt/hostedtoolcache`,f=R(u,`opencode`),p=R(u,`bun`),h=R(Ae(),`.config`,`opencode`),_=ee(),v=await ni({logger:a,os:_,opencodeVersion:c,omoVersion:l,toolCachePath:f,bunCachePath:p,omoConfigPath:h}),b=v.hit?`hit`:`miss`,x,S=!1,C=null;if(v.hit){let e=o.find(`opencode`,c);e.length>0?(x={path:e,version:c,cached:!0},a.info(`Tools cache hit, using cached OpenCode CLI`,{version:c,omoVersion:l})):a.warning(`Tools cache hit but binary not found in tool-cache, falling through to install`,{requestedVersion:c,restoredKey:v.restoredKey})}if(x==null)try{x=await Xr(c,a,o,s)}catch(e){return t(`Failed to install OpenCode: ${A(e)}`),null}let w=!1;try{await Ar(a,o,s,d,g),w=!0}catch(e){a.warning(`Bun installation failed, oMo will be unavailable`,{error:A(e)})}if(w){if(n.omoConfig!=null)try{await Ur(n.omoConfig,h,a)}catch(e){a.warning(`Failed to write omo-config, continuing without custom config`,{error:A(e)})}let e=await Wr(l,{logger:a,execAdapter:s},n.omoProviders);e.installed?(a.info(`oMo installed`,{version:e.version}),S=!0):a.warning(`oMo installation failed, continuing without oMo`,{error:e.error??`unknown error`}),C=e.error}let T={autoupdate:!1};if(n.opencodeConfig!=null){let e;try{e=JSON.parse(n.opencodeConfig)}catch{return t(`opencode-config must be valid JSON`),null}if(typeof e!=`object`||!e||Array.isArray(e))return t(`opencode-config must be a JSON object`),null;Object.assign(T,e)}m(`OPENCODE_CONFIG_CONTENT`,JSON.stringify(T)),v.hit||await ri({logger:a,os:_,opencodeVersion:c,omoVersion:l,toolCachePath:f,bunCachePath:p,omoConfigPath:h}),d(x.path),y(`opencode-path`,x.path),y(`opencode-version`,x.version),a.info(`OpenCode ready`,{version:x.version,cached:x.cached});let E=fe(r),te=await Lr(E,null,r,a);m(`GH_TOKEN`,r),a.info(`GitHub CLI configured`),await zr(E,te.botLogin,a,s);let D=R(pe(),`opencode`),O=await Dr(e,D,a);y(`auth-json-path`,O),a.info(`auth.json populated`,{path:O});let k=Date.now()-i,ne={opencodePath:x.path,opencodeVersion:x.version,ghAuthenticated:te.authenticated,omoInstalled:S,omoError:C,toolsCacheStatus:b,duration:k};return a.info(`Setup complete`,{duration:k}),ne}catch(e){let n=A(e);return a.error(`Setup failed`,{error:n}),t(n),null}}function si(e){return{success:!0,data:e}}function ci(e){return{success:!1,error:e}}const li=[`OWNER`,`MEMBER`,`COLLABORATOR`];async function ui(e,t){try{let{client:n,server:r}=await on({signal:e});return t.debug(`OpenCode server bootstrapped`,{url:r.url}),si({client:n,server:r,shutdown:()=>{r.close()}})}catch(e){let n=e instanceof Error?e.message:String(e);return t.warning(`Failed to bootstrap OpenCode server`,{error:n}),ci(Error(`Server bootstrap failed: ${n}`))}}async function di(e,t){let n=e??`opencode`;try{let e=``;await v(n,[`--version`],{listeners:{stdout:t=>{e+=t.toString()}},silent:!0});let r=/(\d+\.\d+\.\d+)/.exec(e)?.[1]??null;return t.debug(`OpenCode version verified`,{version:r}),{available:!0,version:r}}catch{return t.debug(`OpenCode not available, will attempt auto-setup`),{available:!1,version:null}}}async function fi(e){let{logger:t,opencodeVersion:n}=e,r=N.env.OPENCODE_PATH??null,i=await di(r,t);if(i.available&&i.version!=null)return t.info(`OpenCode already available`,{version:i.version}),{path:r??`opencode`,version:i.version,didSetup:!1};t.info(`OpenCode not found, running auto-setup`,{requestedVersion:n});let a=await oi({opencodeVersion:n,authJson:e.authJson,appId:null,privateKey:null,opencodeConfig:e.opencodeConfig,omoConfig:null,omoVersion:e.omoVersion,omoProviders:e.omoProviders},e.githubToken);if(a==null)throw Error(`Auto-setup failed: runSetup returned null`);return d(a.opencodePath),N.env.OPENCODE_PATH=a.opencodePath,t.info(`Auto-setup completed`,{version:a.opencodeVersion,path:a.opencodePath}),{path:a.opencodePath,version:a.opencodeVersion,didSetup:!0}}async function pi(t,n){let r={repo:t.agentContext.repo,commentId:t.agentContext.commentId,issueNumber:t.agentContext.issueNumber,issueType:t.agentContext.issueType,botLogin:t.botLogin},i=e({phase:`acknowledgment`});return await Qn(t.githubClient,r,i),n.debug(`Acknowledgment phase completed`),r}function mi(e,t){try{JSON.parse(e)}catch{throw Error(`${t} must be valid JSON`)}}function hi(e,t){let n=e.trim();if(!/^\d+$/.test(n))throw Error(`${t} must be a positive integer, received: ${e}`);let r=Number.parseInt(n,10);if(r===0)throw Error(`${t} must be a positive integer, received: ${e}`);return r}function gi(e){let t=e.trim(),n=t.indexOf(`/`);if(n===-1)throw Error(`Invalid model format: "${e}". Expected "provider/model" (e.g., "anthropic/claude-sonnet-4-20250514")`);let r=t.slice(0,n).trim(),i=t.slice(n+1).trim();if(r.length===0)throw Error(`Invalid model format: "${e}". Provider cannot be empty.`);if(i.length===0)throw Error(`Invalid model format: "${e}". Model ID cannot be empty.`);return{providerID:r,modelID:i}}function _i(e,t=`timeout`){let n=e.trim();if(!/^\d+$/.test(n))throw Error(`${t} must be a non-negative integer, received: ${e}`);let r=Number.parseInt(n,10);if(Number.isNaN(r)||r<0)throw Error(`${t} must be a non-negative integer, received: ${e}`);return r}const vi=[`claude`,`claude-max20`,`copilot`,`gemini`,`openai`,`opencode-zen`,`zai-coding-plan`,`kimi-for-coding`];function yi(e){let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0),n=`no`,r=`no`,i=`no`,a=`no`,o=`no`,s=`no`,c=`no`;for(let e of t){if(!vi.includes(e))throw Error(`Invalid omo-providers value: "${e}". Valid values: ${vi.join(`, `)}`);switch(e){case`claude`:n=`yes`;break;case`claude-max20`:n=`max20`;break;case`copilot`:r=`yes`;break;case`gemini`:i=`yes`;break;case`openai`:a=`yes`;break;case`opencode-zen`:o=`yes`;break;case`zai-coding-plan`:s=`yes`;break;case`kimi-for-coding`:c=`yes`;break}}return{claude:n,copilot:r,gemini:i,openai:a,opencodeZen:o,zaiCodingPlan:s,kimiForCoding:c}}function bi(){try{let e=a(`github-token`,{required:!0}).trim();if(e.length===0)return ci(Error(`github-token is required but was not provided`));let t=a(`auth-json`,{required:!0}).trim();if(t.length===0)return ci(Error(`auth-json is required but was not provided`));mi(t,`auth-json`);let o=a(`prompt`).trim(),s=o.length>0?o:null,c=a(`session-retention`).trim(),l=c.length>0?hi(c,`session-retention`):50,u=a(`s3-backup`).trim().toLowerCase()===`true`,d=a(`s3-bucket`).trim(),f=d.length>0?d:null,p=a(`aws-region`).trim(),m=p.length>0?p:null,h=a(`agent`).trim(),g=h.length>0?h:he,v=a(`model`).trim(),y=v.length>0?gi(v):null,b=a(`timeout`).trim(),x=b.length>0?_i(b):r,S=a(`opencode-version`).trim(),C=S.length>0?S:i,ee=a(`skip-cache`).trim().toLowerCase()===`true`,w=a(`omo-version`).trim(),T=w.length>0?w:_,E=a(`omo-providers`).trim(),te=yi(E.length>0?E:``),D=a(`opencode-config`).trim(),O=D.length>0?D:null,k=a(`dedup-window`).trim(),ne=k.length>0?_i(k,`dedup-window`):n;if(O!=null){mi(O,`opencode-config`);let e=JSON.parse(O);if(typeof e!=`object`||!e||Array.isArray(e))throw Error(`Input 'opencode-config' must be a JSON object`)}return si({githubToken:e,authJson:t,prompt:s,sessionRetention:l,s3Backup:u,s3Bucket:f,awsRegion:m,agent:g,model:y,timeoutMs:x,opencodeVersion:C,skipCache:ee,omoVersion:T,omoProviders:te,opencodeConfig:O,dedupWindow:ne})}catch(e){return ci(e instanceof Error?e:Error(String(e)))}}async function xi(n){let r=bi();if(!r.success)return t(`Invalid inputs: ${r.error.message}`),null;let i=r.data,a=e({phase:`main`});a.info(`Action inputs parsed`,{sessionRetention:i.sessionRetention,s3Backup:i.s3Backup,hasGithubToken:i.githubToken.length>0,hasPrompt:i.prompt!=null,agent:i.agent,hasModelOverride:i.model!=null,timeoutMs:i.timeoutMs});let o=await fi({logger:a,opencodeVersion:i.opencodeVersion,githubToken:i.githubToken,authJson:i.authJson,omoVersion:i.omoVersion,omoProviders:i.omoProviders,opencodeConfig:i.opencodeConfig});return o.didSetup?a.info(`OpenCode auto-setup completed`,{version:o.version}):a.info(`OpenCode already available`,{version:o.version}),M(j.OPENCODE_VERSION,o.version),n.debug(`Bootstrap phase completed`,{opencodeVersion:o.version}),{inputs:i,logger:a,opencodeResult:o}}const Si=/^[0-9a-f]{40}$/i;function Ci(){return{exec:v,getExecOutput:b}}async function wi(e){let{workspacePath:t,logger:n,execAdapter:r=Ci()}=e,i=L.join(t,`.git`),a=L.join(i,`opencode`);try{let e=(await I.readFile(a,`utf8`)).trim();if(e.length>0){if(Si.test(e))return n.debug(`Project ID loaded from cache`,{projectId:e}),{projectId:e,source:`cached`};n.warning(`Invalid cached project ID format, regenerating`,{cachedId:e})}}catch(e){n.debug(`No cached project ID found`,{error:A(e)})}try{let e=await I.readFile(i,`utf8`),n=/^gitdir: (.+)$/m.exec(e);if(n==null)return{projectId:null,source:`error`,error:`Invalid .git file format`};i=L.resolve(t,n[1]),a=L.join(i,`opencode`)}catch(e){if((typeof e==`object`?e.code:void 0)!==`EISDIR`)return{projectId:null,source:`error`,error:`Not a git repository`}}try{let{stdout:e,exitCode:i}=await r.getExecOutput(`git`,[`rev-list`,`--max-parents=0`,`--all`],{cwd:t,silent:!0});if(i!==0||e.trim().length===0)return{projectId:null,source:`error`,error:`No commits found in repository`};let o=e.trim().split(` +`).map(e=>e.trim()).filter(e=>e.length>0).sort();if(o.length===0)return{projectId:null,source:`error`,error:`No root commits found`};let s=o[0];try{await I.writeFile(a,s,{encoding:`utf8`,flag:`wx`}),n.info(`Project ID generated and cached`,{projectId:s,source:`generated`})}catch(e){(typeof e==`object`?e.code:void 0)===`EEXIST`?n.debug(`Project ID file already written by concurrent process, skipping`,{projectId:s}):n.warning(`Failed to cache project ID (continuing)`,{error:A(e)})}return{projectId:s,source:`generated`}}catch(e){return{projectId:null,source:`error`,error:A(e)}}}async function Ti(n){let r=w(),i=e({phase:`cache`}),a=se(),o=L.join(a,`.git`,`opencode`),s=await le({components:r,logger:i,storagePath:O(),authPath:ie(),projectIdPath:o,opencodeVersion:n.opencodeResult.version}),c=s.corrupted?`corrupted`:s.hit?`hit`:`miss`;n.logger.info(`Cache restore completed`,{cacheStatus:c,key:s.key});let l=await wi({workspacePath:a,logger:i});l.source===`error`?i.warning(`Failed to generate project ID (continuing)`,{error:l.error}):i.debug(`Project ID ready`,{projectId:l.projectId,source:l.source});let u=e({phase:`server-bootstrap`}),d=await ui(new AbortController().signal,u);if(!d.success)return t(`OpenCode server bootstrap failed: ${d.error.message}`),null;let f=d.data;return u.info(`SDK server bootstrapped successfully`),{cacheResult:s,cacheStatus:c,serverHandle:f}}const Ei={markdownImage:/!\[([^\]]*)\]\((https:\/\/github\.com\/user-attachments\/assets\/[^)]+)\)/gi,markdownLink:/\[([^\]]+)\]\((https:\/\/github\.com\/user-attachments\/files\/[^)]+)\)/gi,htmlImage:/]*src=["'](https:\/\/github\.com\/user-attachments\/assets\/[^"']+)["'][^>]*>/gi};function Di(e,t,n){e.lastIndex=0;let r=e.exec(t);for(;r!=null;)n(r),r=e.exec(t);e.lastIndex=0}function Oi(e){let t=[],n=new Set;return Di(Ei.markdownImage,e,e=>{let r=e[2],i=e[1],a=e[0];r!=null&&i!=null&&!n.has(r)&&bn(r)&&(n.add(r),t.push({url:r,originalMarkdown:a,altText:i,type:`image`}))}),Di(Ei.markdownLink,e,e=>{let r=e[2],i=e[1],a=e[0];r!=null&&i!=null&&!n.has(r)&&bn(r)&&(n.add(r),t.push({url:r,originalMarkdown:a,altText:i,type:`file`}))}),Di(Ei.htmlImage,e,e=>{let r=e[1],i=e[0];if(r!=null&&!n.has(r)&&bn(r)){n.add(r);let e=/alt=["']([^"']*)["']/i.exec(i);t.push({url:r,originalMarkdown:i,altText:e?.[1]??``,type:`image`})}}),Ei.htmlImage.lastIndex=0,t}function ki(e,t,n){try{let r=new URL(e).pathname.split(`/`).at(-1);if(r!=null&&/\.[a-z0-9]+$/i.test(r))return r;if(t.trim().length>0){let e=t.replaceAll(/[^\w.-]/g,`_`).slice(0,50);return e.trim().length>0?e:`attachment_${n+1}`}return`attachment_${n+1}`}catch{return`attachment_${n+1}`}}const Ai={maxFiles:5,maxFileSizeBytes:5*1024*1024,maxTotalSizeBytes:15*1024*1024,allowedMimeTypes:[`image/png`,`image/jpeg`,`image/gif`,`image/webp`,`image/svg+xml`,`text/plain`,`text/markdown`,`text/csv`,`application/json`,`application/pdf`]},ji=[`github.com`,`githubusercontent.com`];async function Mi(e,t,n,r,i){i.debug(`Downloading attachment`,{url:e.url});try{let a=await fetch(e.url,{headers:{Authorization:`Bearer ${n}`,Accept:`*/*`,"User-Agent":`fro-bot-agent`},redirect:`manual`}),o=a;if(a.status>=300&&a.status<400){let t=a.headers.get(`location`);if(t==null)return i.warning(`Redirect without location`,{url:e.url}),null;let n=new URL(t);if(!ji.some(e=>n.hostname===e||n.hostname.endsWith(`.${e}`)))return i.warning(`Redirect to non-GitHub host blocked`,{url:e.url,redirectTo:n.hostname}),null;o=await fetch(t,{headers:{Accept:`*/*`,"User-Agent":`fro-bot-agent`},redirect:`follow`})}if(!o.ok)return i.warning(`Attachment download failed`,{url:e.url,status:o.status}),null;let s=o.headers.get(`content-length`);if(s!=null){let t=Number.parseInt(s,10);if(t>r.maxFileSizeBytes)return i.warning(`Attachment exceeds size limit (Content-Length)`,{url:e.url,size:t,limit:r.maxFileSizeBytes}),null}let c=xe.from(await o.arrayBuffer());if(c.length>r.maxFileSizeBytes)return i.warning(`Attachment exceeds size limit`,{url:e.url,size:c.length,limit:r.maxFileSizeBytes}),null;let l=o.headers.get(`content-type`)??`application/octet-stream`,u=ki(e.url,e.altText,t),d=l.split(`;`)[0],f=d==null?`application/octet-stream`:d.trim(),p=await I.mkdtemp(L.join(Oe.tmpdir(),`fro-bot-attachments-`)),m=u.trim().length>0?u:`attachment_${t+1}`,h=L.join(p,m);return await I.writeFile(h,c),i.debug(`Attachment downloaded`,{filename:u,mime:f,sizeBytes:c.length,tempPath:h}),{url:e.url,filename:u,mime:f,sizeBytes:c.length,tempPath:h}}catch(t){return i.warning(`Attachment download error`,{url:e.url,error:A(t)}),null}}async function Ni(e,t,n=Ai,r){return Promise.all(e.map(async(e,i)=>Mi(e,i,t,n,r)))}async function Pi(e,t){for(let n of e)try{await I.unlink(n);let e=L.dirname(n);await I.rmdir(e).catch(()=>{})}catch(e){t.debug(`Failed to cleanup temp file`,{path:n,error:A(e)})}}function Fi(e){return e.map(e=>({type:`file`,mime:e.mime,url:we(e.tempPath).toString(),filename:e.filename}))}function Ii(e,t,n){let r=e,i=new Set(n.map(e=>e.filename));for(let e of t){let t=n.find(e=>i.has(e.filename));t!=null&&(r=r.replace(e.originalMarkdown,`@${t.filename}`))}return r}function Li(e,t,n,r){return{processed:n,skipped:r,modifiedBody:Ii(e,t,n),fileParts:Fi(n),tempFiles:n.map(e=>e.tempPath)}}function Ri(e){if(e<0||!Number.isFinite(e))throw Error(`Invalid bytes value: ${e}`);return e<1024?`${e}B`:e<1024*1024?`${(e/1024).toFixed(1)}KB`:`${(e/(1024*1024)).toFixed(1)}MB`}function zi(e,t=Ai,n){let r=[],i=[],a=0;for(let o of e)if(o!=null){if(r.length>=t.maxFiles){i.push({url:o.url,reason:`Exceeds max file count (${t.maxFiles})`}),n.debug(`Attachment skipped: max count`,{url:o.url});continue}if(o.sizeBytes>t.maxFileSizeBytes){i.push({url:o.url,reason:`File too large (${Ri(o.sizeBytes)} > ${Ri(t.maxFileSizeBytes)})`}),n.debug(`Attachment skipped: too large`,{url:o.url,size:o.sizeBytes});continue}if(a+o.sizeBytes>t.maxTotalSizeBytes){i.push({url:o.url,reason:`Would exceed total size limit (${Ri(t.maxTotalSizeBytes)})`}),n.debug(`Attachment skipped: total size exceeded`,{url:o.url});continue}if(!Bi(o.mime,t.allowedMimeTypes)){i.push({url:o.url,reason:`MIME type not allowed: ${o.mime}`}),n.debug(`Attachment skipped: MIME type`,{url:o.url,mime:o.mime});continue}a+=o.sizeBytes,r.push({filename:o.filename,mime:o.mime,sizeBytes:o.sizeBytes,tempPath:o.tempPath}),n.info(`Attachment validated`,{filename:o.filename,mime:o.mime,sizeBytes:o.sizeBytes})}return{validated:r,skipped:i}}function Bi(e,t){let[n]=e.split(`/`);for(let r of t)if(r===e||r.endsWith(`/*`)&&n!=null&&n===r.slice(0,-2))return!0;return!1}function q(e){let t=L.resolve(e);return t.endsWith(L.sep)&&t.length>1?t.slice(0,-1):t}const Vi=e=>typeof e==`object`&&!!e,J=e=>typeof e==`string`?e:null,Hi=e=>typeof e==`number`?e:null;function Ui(e){if(Array.isArray(e))return e.filter(Vi).map(e=>({file:J(e.file)??``,additions:Hi(e.additions)??0,deletions:Hi(e.deletions)??0}))}function Wi(e){return{id:e.id,version:e.version,projectID:e.projectID,directory:e.directory,parentID:e.parentID,title:e.title,time:{created:e.time.created,updated:e.time.updated,compacting:e.time.compacting,archived:e.time.archived},summary:e.summary==null?void 0:{additions:e.summary.additions,deletions:e.summary.deletions,files:e.summary.files,diffs:Ui(e.summary.diffs)},share:e.share?.url==null?void 0:{url:e.share.url},permission:e.permission==null?void 0:{rules:e.permission.rules},revert:e.revert==null?void 0:{messageID:e.revert.messageID,partID:e.revert.partID,snapshot:e.revert.snapshot,diff:e.revert.diff}}}async function Gi(e,t){let n=await e.project.list();if(n.error!=null||n.data==null)return t.warning(`SDK project list failed`,{error:String(n.error)}),[];if(!Array.isArray(n.data))return[];let r=[];for(let e of n.data){if(!Vi(e))continue;let t=J(e.id),n=J(e.worktree),i=J(e.path);t==null||n==null||i==null||r.push({id:t,worktree:n,path:i,vcs:`git`,time:{created:0,updated:0}})}return r}async function Ki(e,t,n){let r=q(t),i=await Gi(e,n);for(let e of i){if(q(e.worktree)===r)return e;let t=J(e.path);if(t!=null&&q(t)===r)return e}return null}function qi(e){return e.status===`running`?{status:`running`,input:e.input,time:{start:e.time.start}}:e.status===`error`?{status:`error`,input:e.input,error:e.error,time:{start:e.time.start,end:e.time.end}}:e.status===`pending`?{status:`pending`}:{status:`completed`,input:e.input,output:e.output,title:e.title,metadata:e.metadata,time:{start:e.time.start,end:e.time.end,compacted:e.time.compacted},attachments:void 0}}function Ji(e){let t={id:e.id,sessionID:e.sessionID,messageID:e.messageID};if(e.type===`text`)return{...t,type:`text`,text:e.text,synthetic:e.synthetic,ignored:e.ignored,time:e.time,metadata:e.metadata};if(e.type===`reasoning`)return{...t,type:`reasoning`,reasoning:e.reasoning??e.text,time:e.time};if(e.type===`tool`)return{...t,type:`tool`,callID:e.callID,tool:e.tool,state:qi(e.state),metadata:e.metadata};if(e.type!==`step-finish`)return{...t,type:`text`,text:`text`in e?e.text:``};let n=e;return{...t,type:`step-finish`,reason:n.reason,snapshot:n.snapshot,cost:n.cost,tokens:{input:n.tokens.input,output:n.tokens.output,reasoning:n.tokens.reasoning,cache:{read:n.tokens.cache.read,write:n.tokens.cache.write}}}}function Yi(e){if(e.role===`user`){let t=e;return{id:t.id,sessionID:t.sessionID,role:`user`,time:{created:t.time.created},summary:t.summary==null?void 0:{title:t.summary.title,body:t.summary.body,diffs:Ui(t.summary.diffs)??[]},agent:t.agent,model:{providerID:t.model.providerID,modelID:t.model.modelID},system:t.system,tools:t.tools,variant:t.variant}}let t=e;return{id:t.id,sessionID:t.sessionID,role:`assistant`,time:{created:t.time.created,completed:t.time.completed},parentID:t.parentID,modelID:t.modelID,providerID:t.providerID,mode:t.mode,agent:t.agent??``,path:{cwd:t.path.cwd,root:t.path.root},summary:t.summary,cost:t.cost,tokens:{input:t.tokens.input,output:t.tokens.output,reasoning:t.tokens.reasoning,cache:{read:t.tokens.cache.read,write:t.tokens.cache.write}},finish:t.finish,error:t.error?{name:t.error.name,message:J(t.error.data.message)??``}:void 0}}function Xi(e){return[...e.map(e=>{let t=Yi(`info`in e?e.info:e),n=`parts`in e?e.parts.map(Ji):void 0;return n==null||n.length===0?t:{...t,parts:n}})].sort((e,t)=>e.time.created-t.time.created)}async function Zi(e,t,n){let r=await e.session.list({query:{directory:t}});return r.error==null&&r.data!=null?Array.isArray(r.data)?r.data.map(Wi):[]:(n.warning(`SDK session list failed`,{error:String(r.error)}),[])}async function Qi(e,t,n){let r=await e.session.messages({path:{id:t}});return r.error==null&&r.data!=null?Xi(r.data):(n.warning(`SDK session messages failed`,{error:String(r.error)}),[])}async function $i(e,t,n,r){let i=await e.session.list({query:{directory:t,start:n,roots:!0,limit:10}});if(i.error!=null||i.data==null)return r.warning(`SDK session list failed`,{error:String(i.error)}),null;if(!Array.isArray(i.data)||i.data.length===0)return null;let a=i.data.map(Wi);if(a.length===0)return null;let o=a.reduce((e,t)=>t.time.created>e.time.created?t:e);return{projectID:o.projectID,session:o}}async function ea(e,t,n){let r=await e.session.delete({path:{id:t}});if(r.error!=null){n.warning(`SDK session delete failed`,{sessionID:t,error:String(r.error)});return}n.debug(`Deleted session via SDK`,{sessionID:t})}const ta={maxSessions:50,maxAgeDays:30};async function na(e,t,n,r){let{maxSessions:i,maxAgeDays:a}=n;if(r.info(`Starting session pruning`,{workspacePath:t,maxSessions:i,maxAgeDays:a}),await Ki(e,t,r)==null)return r.debug(`No project found for pruning`,{workspacePath:t}),{prunedCount:0,prunedSessionIds:[],remainingCount:0,freedBytes:0};let o=await Zi(e,t,r),s=o.filter(e=>e.parentID==null);if(s.length===0)return{prunedCount:0,prunedSessionIds:[],remainingCount:0,freedBytes:0};let c=[...s].sort((e,t)=>t.time.updated-e.time.updated),l=new Date;l.setDate(l.getDate()-a);let u=l.getTime(),d=new Set;for(let e of c)e.time.updated>=u&&d.add(e.id);for(let e=0;e!d.has(e.id)),p=new Set;for(let e of f){p.add(e.id);for(let t of o)t.parentID===e.id&&p.add(t.id)}if(p.size===0)return r.info(`No sessions to prune`),{prunedCount:0,prunedSessionIds:[],remainingCount:s.length,freedBytes:0};let m=[];for(let t of p)try{await ea(e,t,r),m.push(t),r.debug(`Pruned session`,{sessionId:t})}catch(e){r.warning(`Failed to prune session`,{sessionId:t,error:A(e)})}let h=s.length-f.length;return r.info(`Session pruning complete`,{prunedCount:m.length,remainingCount:h}),{prunedCount:m.length,prunedSessionIds:m,remainingCount:h,freedBytes:0}}async function ra(e,t,n,r){let{limit:i,fromDate:a,toDate:o}=n;r.debug(`Listing sessions`,{directory:t,limit:i});let s=[...(await Zi(e,t,r)).filter(e=>!(e.parentID!=null||a!=null&&e.time.createdo.getTime()))].sort((e,t)=>t.time.updated-e.time.updated),c=[],l=i==null?s:s.slice(0,i);for(let t of l){let n=await Qi(e,t.id,r),i=ia(n);c.push({id:t.id,projectID:t.projectID,directory:t.directory,title:t.title,createdAt:t.time.created,updatedAt:t.time.updated,messageCount:n.length,agents:i,isChild:!1})}return r.info(`Listed sessions`,{count:c.length,directory:t}),c}function ia(e){let t=new Set;for(let n of e)n.agent!=null&&t.add(n.agent);return[...t]}async function aa(e,t,n,r,i){let{limit:a=20,caseSensitive:o=!1,sessionId:s}=r;i.debug(`Searching sessions`,{query:e,directory:n,limit:a,caseSensitive:o});let c=o?e:e.toLowerCase(),l=[],u=0;if(s!=null){let e=await oa(t,s,c,o,i);return e.length>0&&l.push({sessionId:s,matches:e.slice(0,a)}),l}let d=await ra(t,n,{},i);for(let e of d){if(u>=a)break;let n=await oa(t,e.id,c,o,i);if(n.length>0){let t=a-u;l.push({sessionId:e.id,matches:n.slice(0,t)}),u+=Math.min(n.length,t)}}return i.info(`Session search complete`,{query:e,resultCount:l.length,totalMatches:u}),l}async function oa(e,t,n,r,i){let a=await Qi(e,t,i),o=[];for(let e of a){let t=e.parts??[];for(let i of t){let t=sa(i);if(t==null)continue;let a=r?t:t.toLowerCase();if(a.includes(n)){let r=a.indexOf(n),s=Math.max(0,r-50),c=Math.min(t.length,r+n.length+50),l=t.slice(s,c);o.push({messageId:e.id,partId:i.id,excerpt:`...${l}...`,role:e.role,agent:e.agent})}}}return o}function sa(e){switch(e.type){case`text`:return e.text;case`reasoning`:return e.reasoning;case`tool`:return e.state.status===`completed`?`${e.tool}: ${e.state.output}`:null;case`step-finish`:return null}}function ca(e){let t=[`--- Fro Bot Run Summary ---`,`Event: ${e.eventType}`,`Repo: ${e.repo}`,`Ref: ${e.ref}`,`Run ID: ${e.runId}`,`Cache: ${e.cacheStatus}`,`Duration: ${e.duration}s`];return e.sessionIds.length>0&&t.push(`Sessions used: ${e.sessionIds.join(`, `)}`),e.logicalKey!=null&&t.push(`Logical Thread: ${e.logicalKey}`),e.createdPRs.length>0&&t.push(`PRs created: ${e.createdPRs.join(`, `)}`),e.createdCommits.length>0&&t.push(`Commits: ${e.createdCommits.join(`, `)}`),e.tokenUsage!=null&&t.push(`Tokens: ${e.tokenUsage.input} in / ${e.tokenUsage.output} out`),t.join(` +`)}async function la(e,t,n,r){let i=ca(t);try{let t=await n.session.prompt({path:{id:e},body:{noReply:!0,parts:[{type:`text`,text:i}]}});if(t.error!=null){r.warning(`SDK prompt writeback failed`,{sessionId:e,error:String(t.error)});return}r.info(`Session summary written via SDK`,{sessionId:e})}catch(t){r.warning(`SDK prompt writeback failed`,{sessionId:e,error:A(t)})}}async function ua(t){let{bootstrapLogger:n,reactionCtx:r,githubClient:i,agentSuccess:a,attachmentResult:o,serverHandle:s,detectedOpencodeVersion:c}=t;try{if(o!=null){let t=e({phase:`attachment-cleanup`});await Pi(o.tempFiles,t)}r!=null&&i!=null&&await ir(i,r,a,e({phase:`cleanup`}));let t=e({phase:`prune`}),n=se();if(s!=null){let e=q(n),r=await na(s.client,e,ta,t);r.prunedCount>0&&t.info(`Pruned old sessions`,{pruned:r.prunedCount,remaining:r.remainingCount})}let l=w(),u=e({phase:`cache-save`}),d=L.join(n,`.git`,`opencode`);if(await ae({components:l,runId:D(),logger:u,storagePath:O(),authPath:ie(),projectIdPath:d,opencodeVersion:c})&&M(j.CACHE_SAVED,`true`),ge()){let t=e({phase:`artifact-upload`});await de({logPath:k(),runId:D(),runAttempt:te(),logger:t})&&M(j.ARTIFACT_UPLOADED,`true`)}}catch(e){n.warning(`Cleanup failed (non-fatal)`,{error:e instanceof Error?e.message:String(e)})}finally{if(s!=null)try{s.shutdown()}catch(e){n.warning(`Server shutdown failed (non-fatal)`,{error:e instanceof Error?e.message:String(e)})}}}const da=L.join(ke.homedir(),`.cache`,`fro-bot-dedup`);function fa(e){return e.replaceAll(`/`,`-`)}function pa(e,t){let n=fa(e);return L.join(da,`${n}-${t.entityType}-${t.entityNumber}`)}function ma(e,t){return`${T}-${fa(e)}-${t.entityType}-${t.entityNumber}-`}function ha(e,t,n){return`${ma(e,t)}${n}`}async function ga(e,t,n,r=ne){let i=pa(e,t),a=L.join(i,`sentinel.json`),o=ma(e,t);try{if(await I.rm(i,{recursive:!0,force:!0}),await I.mkdir(i,{recursive:!0}),await r.restoreCache([i],o,[])==null)return null;let e=await I.readFile(a,`utf8`);return JSON.parse(e)}catch(e){return n.debug(`Dedup marker restore failed; proceeding without marker`,{error:A(e),entityType:t.entityType,entityNumber:t.entityNumber}),null}}async function _a(e,t,n,r,i=ne){let a=pa(e,t),o=L.join(a,`sentinel.json`),s=ha(e,t,n.runId);try{return await I.mkdir(a,{recursive:!0}),await I.writeFile(o,JSON.stringify(n),`utf8`),await i.saveCache([a],s),!0}catch(e){return A(e).toLowerCase().includes(`already exists`)?!0:(r.debug(`Dedup marker save failed`,{error:A(e),entityType:t.entityType,entityNumber:t.entityNumber,saveKey:s}),!1)}}const va=new Set([`pull_request`,`issues`]),ya=new Set([`synchronize`,`reopened`]);function ba(e){return e.target==null||!va.has(e.eventType)?null:e.eventType===`pull_request`&&e.target.kind===`pr`?{entityType:`pr`,entityNumber:e.target.number}:e.eventType===`issues`&&e.target.kind===`issue`?{entityType:`issue`,entityNumber:e.target.number}:null}async function xa(t,n,r,i,a=e({phase:`dedup`}),o){let s=ba(n);if(t===0)return{shouldProceed:!0,entity:s};if(s==null)return{shouldProceed:!0,entity:null};if(n.action!=null&&ya.has(n.action))return a.debug(`Dedup bypassed for action`,{action:n.action}),{shouldProceed:!0,entity:s};let c=await ga(r,s,a,o);if(c==null||c.runId===n.runId)return{shouldProceed:!0,entity:s};let l=new Date(c.timestamp).getTime();if(Number.isNaN(l))return a.warning(`Dedup marker timestamp is invalid; proceeding without dedup`,{markerTimestamp:c.timestamp}),{shouldProceed:!0,entity:s};let u=Date.now()-l;if(u<-6e4)return a.warning(`Dedup marker timestamp is too far in the future; proceeding without dedup`,{markerTimestamp:c.timestamp,markerAge:u}),{shouldProceed:!0,entity:s};let d=Math.max(0,u);return d>t?{shouldProceed:!0,entity:s}:(a.info(`Skipping duplicate trigger within dedup window`,{eventType:n.eventType,action:n.action,runId:n.runId,markerRunId:c.runId,markerTimestamp:c.timestamp,dedupWindow:t,entityType:s.entityType,entityNumber:s.entityNumber}),z({sessionId:null,cacheStatus:`miss`,duration:Date.now()-i}),await Ca(n,s,c,d,t,a),{shouldProceed:!1,entity:s})}async function Sa(t,n,r,i=e({phase:`dedup`}),a){await _a(r,n,{timestamp:new Date().toISOString(),runId:t.runId,action:t.action??`unknown`,eventType:t.eventType,entityType:n.entityType,entityNumber:n.entityNumber},i,a)}async function Ca(e,t,n,r,i,a){try{let a=Math.round(r/1e3),o=Math.round(i/1e3),s=`${t.entityType} #${t.entityNumber}`,c=`https://github.com/${e.repo.owner}/${e.repo.repo}/actions/runs/${n.runId}`;S.addHeading(`Fro Bot Agent Run β€” Skipped (Dedup)`,2).addRaw(`Execution skipped because the agent already ran for **${s}** recently.\n\n`).addTable([[{data:`Detail`,header:!0},{data:`Value`,header:!0}],[`Current action`,`\`${e.eventType}.${e.action??`unknown`}\``],[`Prior run`,`[${n.runId}](${c})`],[`Prior action`,`\`${n.eventType}.${n.action}\``],[`Time since prior run`,`${a}s`],[`Dedup window`,`${o}s`]]).addRaw(` +> Dedup is best-effort suppression. Use workflow concurrency groups to prevent overlapping runs. +`),await S.write()}catch(e){a.warning(`Failed to write dedup skip summary`,{error:A(e)})}}async function wa(t,n,r,i,a,o){let s={context:n.agentContext,customPrompt:t.inputs.prompt,cacheStatus:r.cacheStatus,sessionContext:{recentSessions:i.recentSessions,priorWorkContext:i.priorWorkContext},logicalKey:i.logicalKey??null,isContinuation:i.isContinuation,currentThreadSessionId:i.continueSessionId??null,triggerContext:n.triggerResult.context,fileParts:i.attachmentResult?.fileParts},c=N.env.SKIP_AGENT_EXECUTION===`true`,l=Date.now(),u;if(c)t.logger.info(`Skipping agent execution (SKIP_AGENT_EXECUTION=true)`),u={success:!0,exitCode:0,sessionId:null,error:null,tokenUsage:null,model:null,cost:null,prsCreated:[],commitsCreated:[],commentsPosted:0,llmError:null};else{let n=e({phase:`execution`});n.info(`Starting OpenCode execution`,{logicalKey:i.logicalKey?.key??null,continueSessionId:i.continueSessionId});let a=await Yn(s,n,{agent:t.inputs.agent,model:t.inputs.model,timeoutMs:t.inputs.timeoutMs,omoProviders:t.inputs.omoProviders,continueSessionId:i.continueSessionId??void 0,sessionTitle:i.sessionTitle??void 0},r.serverHandle),o=a.sessionId;if(o==null){let t=e({phase:`session`}),n=await $i(r.serverHandle.client,i.normalizedWorkspace,l,t);n!=null&&(o=n.session.id,t.debug(`Identified session from execution`,{sessionId:o}))}u={...a,sessionId:o},n.info(`Completed OpenCode execution`,{success:u.success,sessionId:u.sessionId,logicalKey:i.logicalKey?.key??null})}u.sessionId!=null&&(M(j.SESSION_ID,u.sessionId),a.addSessionCreated(u.sessionId)),u.tokenUsage!=null&&a.setTokenUsage(u.tokenUsage,u.model,u.cost);for(let e of u.prsCreated)a.addPRCreated(e);for(let e of u.commitsCreated)a.addCommitCreated(e);for(let e=0;e`)}async function Da(e,t,n){try{if(t.type===`pr`){let{data:n}=await e.rest.pulls.get({owner:t.owner,repo:t.repo,pull_number:t.number});return{title:n.title,body:n.body??``,author:n.user?.login??`unknown`}}let{data:n}=await e.rest.issues.get({owner:t.owner,repo:t.repo,issue_number:t.number});return{title:n.title,body:n.body??``,author:n.user?.login??`unknown`}}catch(e){return n.warning(`Failed to fetch issue/PR`,{target:t,error:A(e)}),null}}async function Oa(e,t,n,r){let i=[],a=1;for(;a<=50;)try{let{data:r}=await e.rest.issues.listComments({owner:t.owner,repo:t.repo,issue_number:t.number,per_page:100,page:a});if(r.length===0)break;for(let e of r){let t=e.user?.login??`unknown`;i.push({id:e.id,body:e.body??``,author:t,authorAssociation:e.author_association??`NONE`,createdAt:e.created_at,updatedAt:e.updated_at,isBot:Ea(t,e.body??``,n)})}if(r.length<100)break;a++}catch(e){r.warning(`Failed to fetch comments page`,{target:t,page:a,error:A(e)});break}return i}async function ka(e,t,n,r){try{let i=[],a=null,o=null,s=``,c=``,l=`unknown`,u=0;for(;u<50;){let d=(await e.graphql(` query GetDiscussion($owner: String!, $repo: String!, $number: Int!, $after: String) { repository(owner: $owner, name: $repo) { discussion(number: $number) { @@ -285,7 +287,7 @@ If you had completed the task, confirm the completion.`,u=r===1?e.fileParts:void } } } -`,{owner:t.owner,repo:t.repo,number:t.number,after:a})).repository.discussion;if(d==null)return r.debug(`Discussion not found`,{target:t}),null;u===0&&(o=d.id,s=d.title,c=d.body,l=d.author?.login??`unknown`);for(let e of d.comments.nodes){let t=e.author?.login??`unknown`;i.push({id:e.id,body:e.body,author:t,authorAssociation:`NONE`,createdAt:e.createdAt,updatedAt:e.updatedAt,isBot:Ca(t,e.body,n)})}if(!d.comments.pageInfo.hasNextPage)break;a=d.comments.pageInfo.endCursor,u++}return{type:`discussion`,number:t.number,title:s,body:c,author:l,comments:i,discussionId:o??void 0}}catch(e){return r.warning(`Failed to fetch discussion`,{target:t,error:M(e)}),null}}async function Da(e,t,n,r){if(t.type===`discussion`)return Ea(e,t,n,r);let i=await wa(e,t,r);if(i==null)return null;let a=await Ta(e,t,n,r);return{type:t.type,number:t.number,title:i.title,body:i.body,author:i.author,comments:a}}function Oa(e,t){let n=e.comments.filter(e=>Sa(e.author,t)&&e.body.includes(``));return n.length===0?null:n.at(-1)??null}async function ka(e,t,n,r){try{let{data:i}=await e.rest.issues.createComment({owner:t.owner,repo:t.repo,issue_number:t.number,body:n});return r.debug(`Created issue comment`,{commentId:i.id,target:t}),{commentId:i.id,created:!0,updated:!1,url:i.html_url}}catch(e){return r.warning(`Failed to create issue comment`,{target:t,error:M(e)}),null}}async function Aa(e,t,n,r,i){try{let{data:a}=await e.rest.issues.updateComment({owner:t.owner,repo:t.repo,comment_id:n,body:r});return i.debug(`Updated issue comment`,{commentId:a.id,target:t}),{commentId:a.id,created:!1,updated:!0,url:a.html_url}}catch(e){return i.warning(`Failed to update issue comment`,{target:t,commentId:n,error:M(e)}),null}}async function ja(e,t,n,r){try{let i=(await e.graphql(` +`,{owner:t.owner,repo:t.repo,number:t.number,after:a})).repository.discussion;if(d==null)return r.debug(`Discussion not found`,{target:t}),null;u===0&&(o=d.id,s=d.title,c=d.body,l=d.author?.login??`unknown`);for(let e of d.comments.nodes){let t=e.author?.login??`unknown`;i.push({id:e.id,body:e.body,author:t,authorAssociation:`NONE`,createdAt:e.createdAt,updatedAt:e.updatedAt,isBot:Ea(t,e.body,n)})}if(!d.comments.pageInfo.hasNextPage)break;a=d.comments.pageInfo.endCursor,u++}return{type:`discussion`,number:t.number,title:s,body:c,author:l,comments:i,discussionId:o??void 0}}catch(e){return r.warning(`Failed to fetch discussion`,{target:t,error:A(e)}),null}}async function Aa(e,t,n,r){if(t.type===`discussion`)return ka(e,t,n,r);let i=await Da(e,t,r);if(i==null)return null;let a=await Oa(e,t,n,r);return{type:t.type,number:t.number,title:i.title,body:i.body,author:i.author,comments:a}}function ja(e,t){let n=e.comments.filter(e=>Ta(e.author,t)&&e.body.includes(``));return n.length===0?null:n.at(-1)??null}async function Ma(e,t,n,r){try{let{data:i}=await e.rest.issues.createComment({owner:t.owner,repo:t.repo,issue_number:t.number,body:n});return r.debug(`Created issue comment`,{commentId:i.id,target:t}),{commentId:i.id,created:!0,updated:!1,url:i.html_url}}catch(e){return r.warning(`Failed to create issue comment`,{target:t,error:A(e)}),null}}async function Na(e,t,n,r,i){try{let{data:a}=await e.rest.issues.updateComment({owner:t.owner,repo:t.repo,comment_id:n,body:r});return i.debug(`Updated issue comment`,{commentId:a.id,target:t}),{commentId:a.id,created:!1,updated:!0,url:a.html_url}}catch(e){return i.warning(`Failed to update issue comment`,{target:t,commentId:n,error:A(e)}),null}}async function Pa(e,t,n,r){try{let i=(await e.graphql(` query GetDiscussionId($owner: String!, $repo: String!, $number: Int!) { repository(owner: $owner, name: $repo) { discussion(number: $number) { @@ -306,7 +308,7 @@ If you had completed the task, confirm the completion.`,u=r===1?e.fileParts:void } } } -`,{owner:t.owner,repo:t.repo,number:t.number})).repository.discussion;if(i==null)return r.warning(`Discussion not found`,{target:t}),null;if(n.updateExisting===!0&&n.botLogin!=null){let i=await Da(e,t,n.botLogin,r);if(i!=null){let t=Oa(i,n.botLogin);if(t!=null&&typeof t.id==`string`){let i=await e.graphql(` +`,{owner:t.owner,repo:t.repo,number:t.number})).repository.discussion;if(i==null)return r.warning(`Discussion not found`,{target:t}),null;if(n.updateExisting===!0&&n.botLogin!=null){let i=await Aa(e,t,n.botLogin,r);if(i!=null){let t=ja(i,n.botLogin);if(t!=null&&typeof t.id==`string`){let i=await e.graphql(` mutation UpdateDiscussionComment($commentId: ID!, $body: String!) { updateDiscussionComment(input: {commentId: $commentId, body: $body}) { comment { id url } @@ -318,4 +320,4 @@ If you had completed the task, confirm the completion.`,u=r===1?e.fileParts:void comment { id url } } } -`,{discussionId:i.id,body:n.body});return r.debug(`Created discussion comment`,{discussionId:i.id}),{commentId:a.addDiscussionComment.comment.id,created:!0,updated:!1,url:a.addDiscussionComment.comment.url}}catch(e){return r.warning(`Failed to post discussion comment`,{target:t,error:M(e)}),null}}async function Ma(e,t,n,r){if(t.type===`discussion`)return ja(e,t,n,r);if(n.updateExisting===!0&&n.botLogin!=null){let i=await Da(e,t,n.botLogin,r);if(i!=null){let a=Oa(i,n.botLogin);if(a!=null&&typeof a.id==`number`)return Aa(e,t,a.id,n.body,r)}}return ka(e,t,n.body,r)}async function Na(n,r,i,a,o,s,c){let l=Date.now()-s;if(V({sessionId:a.sessionId,cacheStatus:i.cacheStatus,duration:l}),await Me({eventType:r.agentContext.eventName,repo:r.agentContext.repo,ref:r.agentContext.ref,runId:Number(r.agentContext.runId),runUrl:`https://github.com/${r.agentContext.repo}/actions/runs/${r.agentContext.runId}`,metrics:o.getMetrics(),agent:n.inputs.agent},c),a.success)return c.info(`Agent run completed successfully`,{durationMs:l}),0;if(a.llmError==null)return t(`Agent execution failed with exit code ${a.exitCode}`),a.exitCode;c.info(`Agent failed with recoverable LLM error`,{error:a.llmError.message,type:a.llmError.type,durationMs:l});let[u,d]=r.agentContext.repo.split(`/`),f={type:r.triggerResult.context.eventType===`discussion_comment`?`discussion`:r.agentContext.issueType===`pr`?`pr`:`issue`,number:r.agentContext.issueNumber??0,owner:u??``,repo:d??``};if(f.number>0&&f.owner.length>0&&f.repo.length>0){let t=dn(a.llmError),n=e({phase:`error-comment`}),i=await Ma(r.githubClient,f,{body:t},n);i==null?n.warning(`Failed to post LLM error comment`):(n.info(`Posted LLM error comment`,{commentUrl:i.url}),o.incrementComments())}else c.warning(`Cannot post error comment: missing target context`);return 0}function Pa(e){switch(e){case`issue_comment`:return`issue_comment`;case`discussion`:case`discussion_comment`:return`discussion_comment`;case`workflow_dispatch`:return`workflow_dispatch`;case`issues`:return`issues`;case`pull_request`:return`pull_request`;case`pull_request_review_comment`:return`pull_request_review_comment`;case`schedule`:return`schedule`;default:return`unsupported`}}function Fa(e,t){switch(e){case`issue_comment`:{let e=t;return{type:`issue_comment`,action:e.action,issue:{number:e.issue.number,title:e.issue.title,body:e.issue.body??null,locked:e.issue.locked??!1,isPullRequest:e.issue.pull_request!=null},comment:{id:e.comment.id,body:e.comment.body,author:e.comment.user.login,authorAssociation:e.comment.author_association??`NONE`}}}case`discussion_comment`:{let e=t;return{type:`discussion_comment`,action:e.action,discussion:{number:e.discussion.number,title:e.discussion.title,body:e.discussion.body??null,locked:e.discussion.locked??!1},comment:{id:e.comment.id,body:e.comment.body??null,author:e.comment.user.login,authorAssociation:e.comment.author_association??`NONE`}}}case`issues`:{let e=t;return{type:`issues`,action:e.action,issue:{number:e.issue.number,title:e.issue.title,body:e.issue.body??null,locked:e.issue.locked??!1,authorAssociation:e.issue.author_association??`NONE`},sender:{login:e.sender.login}}}case`pull_request`:{let e=t,n=e.pull_request.requested_reviewers??[],r=`requested_reviewer`in e&&e.requested_reviewer!=null?{login:e.requested_reviewer.login,type:e.requested_reviewer.type}:null,i=`requested_team`in e&&e.requested_team!=null?{name:e.requested_team.name,slug:e.requested_team.slug}:null,a=n.flatMap(e=>`login`in e&&`type`in e?[{login:e.login,type:e.type}]:[]);return{type:`pull_request`,action:e.action,requestedReviewer:r,requestedTeam:i,pullRequest:{number:e.pull_request.number,title:e.pull_request.title,body:e.pull_request.body??null,locked:e.pull_request.locked??!1,draft:e.pull_request.draft??!1,authorAssociation:e.pull_request.author_association??`NONE`,requestedReviewers:a},sender:{login:e.sender.login}}}case`pull_request_review_comment`:{let e=t;return{type:`pull_request_review_comment`,action:e.action,pullRequest:{number:e.pull_request.number,title:e.pull_request.title,locked:e.pull_request.locked??!1},comment:{id:e.comment.id,body:e.comment.body,author:e.comment.user.login,authorAssociation:e.comment.author_association,path:e.comment.path,line:e.comment.line??null,diffHunk:e.comment.diff_hunk,commitId:e.comment.commit_id}}}case`workflow_dispatch`:return{type:`workflow_dispatch`,inputs:{prompt:t.inputs?.prompt??void 0}};case`schedule`:return{type:`schedule`,schedule:t.schedule??void 0};case`unsupported`:return{type:`unsupported`}}}function Ia(e){let t=te,n=Pa(t.eventName),r=Fa(n,t.payload);return e.debug(`Parsed GitHub context`,{eventName:t.eventName,eventType:n,repo:`${t.repo.owner}/${t.repo.repo}`}),{eventName:t.eventName,eventType:n,repo:t.repo,ref:t.ref,sha:t.sha,runId:t.runId,actor:t.actor,payload:t.payload,event:r}}function La(e,t){return t.includes(e)}function X(e){return e.endsWith(`[bot]`)}function Ra(e,t){if(t.length===0)return!1;let n=t.replace(/\[bot\]$/i,``);return n.length===0?!1:new RegExp(String.raw`@${za(n)}(?:\[bot\])?(?:$|[^\w])`,`i`).test(e)}function za(e){return e.replaceAll(/[.*+?^${}()|[\]\\]/g,String.raw`\$&`)}function Ba(e,t){if(t.length===0)return null;let n=t.replace(/\[bot\]$/i,``);if(n.length===0)return null;let r=new RegExp(String.raw`@${za(n)}(?:\[bot\])?\s*(.*)`,`is`).exec(e)?.[1];if(r==null)return null;let i=r.trim();if(i.length===0)return{raw:``,action:null,args:``};let a=i.split(/\s+/),o=a[0]??``;return{raw:i,action:o===``?null:o,args:a.slice(1).join(` `)}}function Z(e,t){if(t==null||t===``||e==null)return{hasMention:!1,command:null};let n=Ra(e,t);return{hasMention:n,command:n?Ba(e,t):null}}function Va(e,t){if(e.type!==`issue_comment`)throw Error(`Event type must be issue_comment`);let n={login:e.comment.author,association:e.comment.authorAssociation,isBot:X(e.comment.author)},r={kind:e.issue.isPullRequest?`pr`:`issue`,number:e.issue.number,title:e.issue.title,body:e.comment.body??null,locked:e.issue.locked},{hasMention:i,command:a}=Z(e.comment.body,t);return{action:e.action,author:n,target:r,commentBody:e.comment.body,commentId:e.comment.id,hasMention:i,command:a,isBotReviewRequested:!1}}function Ha(e,t){if(e.type!==`discussion_comment`)throw Error(`Event type must be discussion_comment`);let n={login:e.comment.author,association:e.comment.authorAssociation,isBot:X(e.comment.author)},r=e.comment.body??null,i={kind:`discussion`,number:e.discussion.number,title:e.discussion.title,body:r??e.discussion.body??null,locked:e.discussion.locked},{hasMention:a,command:o}=Z(r,t);return{action:e.action,author:n,target:i,commentBody:r,commentId:e.comment.id,hasMention:a,command:o,isBotReviewRequested:!1}}function Ua(e,t){if(e.type!==`pull_request_review_comment`)throw Error(`Event type must be pull_request_review_comment`);let n={login:e.comment.author,association:e.comment.authorAssociation,isBot:X(e.comment.author)},r={kind:`pr`,number:e.pullRequest.number,title:e.pullRequest.title,body:e.comment.body,locked:e.pullRequest.locked,path:e.comment.path,line:e.comment.line??void 0,diffHunk:e.comment.diffHunk,commitId:e.comment.commitId},{hasMention:i,command:a}=Z(e.comment.body,t);return{action:e.action,author:n,target:r,commentBody:e.comment.body,commentId:e.comment.id,hasMention:i,command:a,isBotReviewRequested:!1}}function Wa(e,t,n){if(e.type!==`workflow_dispatch`)throw Error(`Event type must be workflow_dispatch`);let r=(n??e.inputs?.prompt??``).trim();return{action:null,author:{login:t,association:`OWNER`,isBot:!1},target:{kind:`manual`,number:0,title:`Manual workflow dispatch`,body:r===``?null:r,locked:!1},commentBody:r===``?null:r,commentId:null,hasMention:!1,command:null,isBotReviewRequested:!1}}function Ga(e,t,n){let r=n?.trim()??``;return{action:null,author:{login:t,association:`OWNER`,isBot:!1},target:{kind:`manual`,number:0,title:`Scheduled workflow`,body:r===``?null:r,locked:!1},commentBody:r===``?null:r,commentId:null,hasMention:!1,command:null,isBotReviewRequested:!1}}function Ka(e){return e.toLowerCase().replace(/\[bot\]$/i,``)}function qa(e,t){if(e.type!==`pull_request`||t==null||t===``)return!1;let n=Ka(t);if(n===``)return!1;if(e.action===`review_requested`){let t=e.requestedReviewer?.login;return t!=null&&Ka(t)===n}return e.action===`ready_for_review`?e.pullRequest.requestedReviewers.some(e=>Ka(e.login)===n):!1}function Ja(e,t){if(e.type!==`issues`)throw Error(`Event type must be issues`);let n={login:e.sender.login,association:e.issue.authorAssociation,isBot:X(e.sender.login)},r={kind:`issue`,number:e.issue.number,title:e.issue.title,body:e.issue.body,locked:e.issue.locked},{hasMention:i,command:a}=Z(e.issue.body??``,t);return{action:e.action,author:n,target:r,commentBody:e.issue.body,commentId:null,hasMention:i,command:a,isBotReviewRequested:!1}}function Ya(e,t){if(e.type!==`pull_request`)throw Error(`Event type must be pull_request`);let n={login:e.sender.login,association:e.pullRequest.authorAssociation,isBot:X(e.sender.login)},r={kind:`pr`,number:e.pullRequest.number,title:e.pullRequest.title,body:e.pullRequest.body,locked:e.pullRequest.locked,isDraft:e.pullRequest.draft,requestedReviewerLogin:e.requestedReviewer?.login,requestedTeamSlug:e.requestedTeam?.slug,requestedReviewerLogins:e.pullRequest.requestedReviewers.map(e=>e.login)},{hasMention:i,command:a}=Z(e.pullRequest.body??``,t);return{action:e.action,author:n,target:r,commentBody:e.pullRequest.body,commentId:null,hasMention:i,command:a,isBotReviewRequested:qa(e,t)}}function Q(e,t){return{...e,action:t.action,author:t.author,target:t.target,commentBody:t.commentBody,commentId:t.commentId,hasMention:t.hasMention,command:t.command,isBotReviewRequested:t.isBotReviewRequested}}function Xa(e,t,n){let r={eventType:e.eventType,eventName:e.eventName,repo:e.repo,ref:e.ref,sha:e.sha,runId:e.runId,actor:e.actor,raw:e};switch(e.eventType){case`issue_comment`:return Q(r,Va(e.event,t));case`discussion_comment`:return Q(r,Ha(e.event,t));case`workflow_dispatch`:return Q(r,Wa(e.event,e.actor,n));case`issues`:return Q(r,Ja(e.event,t));case`pull_request`:return Q(r,Ya(e.event,t));case`pull_request_review_comment`:return Q(r,Ua(e.event,t));case`schedule`:return Q(r,Ga(e.event,e.actor,n));case`unsupported`:return{...r,action:null,author:null,target:null,commentBody:null,commentId:null,hasMention:!1,command:null,isBotReviewRequested:!1}}}function Za(e,t,n){let{targetLabel:r,actionLabel:i}=n;return e.action===`created`?e.target?.locked===!0?{shouldSkip:!0,reason:`issue_locked`,message:`${r} is locked`}:e.author!=null&&e.author.isBot?{shouldSkip:!0,reason:`self_comment`,message:`Comments from bots (${e.author.login}) are not processed`}:e.author!=null&&!La(e.author.association,t.allowedAssociations)?{shouldSkip:!0,reason:`unauthorized_author`,message:`Author association '${e.author.association}' is not authorized`}:t.requireMention&&!e.hasMention?{shouldSkip:!0,reason:`no_mention`,message:`Comment does not mention the bot`}:{shouldSkip:!1}:{shouldSkip:!0,reason:`action_not_created`,message:`${i} action is '${e.action}', not 'created'`}}function Qa(e,t){return Za(e,t,{targetLabel:`Issue or PR`,actionLabel:`Comment`})}function $a(e,t){return Za(e,t,{targetLabel:`Discussion`,actionLabel:`Discussion comment`})}const eo=[`opened`,`edited`];function to(e){return eo.includes(e)}function no(e,t){let n=e.action;return n==null||!to(n)?{shouldSkip:!0,reason:`action_not_supported`,message:`Issues action '${n}' is not supported (only 'opened' and 'edited')`}:e.author!=null&&e.author.isBot?{shouldSkip:!0,reason:`self_comment`,message:`Issues from bots (${e.author.login}) are not processed`}:e.author!=null&&!La(e.author.association,t.allowedAssociations)?{shouldSkip:!0,reason:`unauthorized_author`,message:`Author association '${e.author.association}' is not authorized`}:n===`edited`&&!e.hasMention?{shouldSkip:!0,reason:`no_mention`,message:`Issue edit does not mention the bot`}:e.target?.locked===!0?{shouldSkip:!0,reason:`issue_locked`,message:`Issue is locked`}:{shouldSkip:!1}}function ro(e){return(e.promptInput?.trim()??``)===``?{shouldSkip:!0,reason:`prompt_required`,message:`Schedule trigger requires prompt input`}:{shouldSkip:!1}}function io(e){return(e.commentBody?.trim()??``)===``?{shouldSkip:!0,reason:`prompt_required`,message:`Workflow dispatch requires prompt input`}:{shouldSkip:!1}}const ao=[`opened`,`synchronize`,`reopened`,`ready_for_review`,`review_requested`];function oo(e){return ao.includes(e)}function so(e,t){let n=e.action;return n==null||!oo(n)?{shouldSkip:!0,reason:`action_not_supported`,message:`Pull request action '${n}' is not supported`}:e.action!==`review_requested`&&e.action!==`ready_for_review`&&e.author!=null&&e.author.isBot?{shouldSkip:!0,reason:`self_comment`,message:`Pull requests from bots (${e.author.login}) are not processed`}:e.author!=null&&!La(e.author.association,t.allowedAssociations)?{shouldSkip:!0,reason:`unauthorized_author`,message:`Author association '${e.author.association}' is not authorized`}:t.skipDraftPRs&&e.target?.isDraft===!0?{shouldSkip:!0,reason:`draft_pr`,message:`Pull request is a draft`}:e.target?.locked===!0?{shouldSkip:!0,reason:`issue_locked`,message:`Pull request is locked`}:t.botLogin!=null&&t.botLogin!==``&&(e.action===`ready_for_review`||e.action===`review_requested`)&&e.isBotReviewRequested!==!0?{shouldSkip:!0,reason:`bot_not_requested`,message:`Pull request action '${e.action}' did not request review from the bot`}:{shouldSkip:!1}}function co(e,t){let n=e.action;return n===`created`?e.target?.locked===!0?{shouldSkip:!0,reason:`issue_locked`,message:`Pull request is locked`}:e.author!=null&&e.author.isBot?{shouldSkip:!0,reason:`self_comment`,message:`Review comments from bots (${e.author.login}) are not processed`}:e.author!=null&&!La(e.author.association,t.allowedAssociations)?{shouldSkip:!0,reason:`unauthorized_author`,message:`Author association '${e.author.association}' is not authorized`}:t.requireMention&&!e.hasMention?{shouldSkip:!0,reason:`no_mention`,message:`Review comment does not mention the bot`}:{shouldSkip:!1}:{shouldSkip:!0,reason:`action_not_created`,message:`Review comment action '${n}' is not supported (only 'created')`}}function lo(e){return{shouldSkip:!0,reason:`unsupported_event`,message:`Unsupported event type: ${e}`}}function uo(e,t,n){if(e.eventType===`unsupported`)return n.debug(`Skipping unsupported event`,{eventName:e.eventName}),lo(e.eventName);switch(e.eventType){case`issue_comment`:return Qa(e,t);case`discussion_comment`:return $a(e,t);case`issues`:return no(e,t);case`pull_request`:return so(e,t);case`pull_request_review_comment`:return co(e,t);case`schedule`:return ro(t);case`workflow_dispatch`:return io(e);default:return{shouldSkip:!1}}}const fo={botLogin:null,requireMention:!0,allowedAssociations:ci,skipDraftPRs:!0,promptInput:null,senderAssociation:null};function po(e,t,n={}){let r={...fo,...n},i=Xa(e,r.botLogin,r.promptInput);r.senderAssociation!=null&&(i.action===`review_requested`||i.action===`ready_for_review`)&&i.author!=null&&(i={...i,author:{...i.author,association:r.senderAssociation}}),t.debug(`Routing event`,{eventName:e.eventName,eventType:e.eventType,hasMention:i.hasMention});let a=uo(i,r,t);return a.shouldSkip?{shouldProcess:!1,skipReason:a.reason,skipMessage:a.message,context:i}:{shouldProcess:!0,context:i}}async function mo(t,n){let r=e({phase:`context`}),i=Ia(r),a=Pr({token:t.inputs.githubToken,logger:r}),o=await Fr(a,r),s=null;if(i.event.type===`pull_request`&&(i.event.action===`review_requested`||i.event.action===`ready_for_review`)){let{owner:e,repo:t}=i.repo;s=await He(a,e,t,i.event.sender.login,r)}let c=e({phase:`trigger`}),l=po(i,c,{botLogin:o,requireMention:!0,promptInput:t.inputs.prompt,senderAssociation:s});return l.shouldProcess?(c.info(`Event routed for processing`,{eventType:l.context.eventType,hasMention:l.context.hasMention,command:l.context.command?.action??null}),F(N.SHOULD_SAVE_CACHE,`true`),{githubClient:a,triggerResult:l,agentContext:await ot({logger:r,octokit:a,triggerContext:l.context,botLogin:o}),botLogin:o}):(c.info(`Skipping event`,{reason:l.skipReason,message:l.skipMessage}),V({sessionId:null,cacheStatus:`miss`,duration:Date.now()-n}),null)}function $(e,t){return{key:`${e}-${t}`,entityType:e,entityId:t}}function ho(e){return be(`sha256`).update(e).digest(`hex`).slice(0,8)}function go(e){if(e.eventType===`unsupported`)return null;if(e.eventType===`schedule`){let t=e.raw.event.type===`schedule`?e.raw.event.schedule:void 0;return $(`schedule`,ho((t!=null&&t.trim().length>0?t:e.action)??`default`))}return e.eventType===`workflow_dispatch`?$(`dispatch`,String(e.runId)):e.target==null?null:e.eventType===`issue_comment`?e.target.kind===`issue`?$(`issue`,String(e.target.number)):e.target.kind===`pr`?$(`pr`,String(e.target.number)):null:e.eventType===`discussion_comment`?e.target.kind===`discussion`?$(`discussion`,String(e.target.number)):null:e.eventType===`issues`?e.target.kind===`issue`?$(`issue`,String(e.target.number)):null:(e.eventType===`pull_request`||e.eventType===`pull_request_review_comment`)&&e.target.kind===`pr`?$(`pr`,String(e.target.number)):null}function _o(e){return`fro-bot: ${e.key}`}function vo(e,t){let n=e.filter(e=>e.title===t);return n.length===0?null:n.reduce((e,t)=>t.time.updated>e.time.updated?t:e)}async function yo(e,t,n,r){try{let i=vo(await Xi(e,t,r),_o(n));return i==null||i.time.archived!=null||i.time.compacting!=null?{status:`not-found`}:{status:`found`,session:i}}catch(e){return{status:`error`,error:e instanceof Error?e.message:String(e)}}}async function bo(t,n,r,i){let a=e({phase:`session`}),o=J(P()),s=await na(r.serverHandle.client,o,{limit:10},a);a.debug(`Listed recent sessions`,{count:s.length});let c=go(n.triggerResult.context),l=c==null?null:_o(c),u=null,d=!1;if(c!=null){let e=await yo(r.serverHandle.client,o,c,a);e.status===`found`?(u=e.session.id,d=!0,a.info(`Session continuity: found existing session`,{logicalKey:c.key,sessionId:u})):e.status===`error`?a.warning(`Session continuity: lookup error, will create new`,{logicalKey:c.key,error:e.error}):a.info(`Session continuity: no existing session found`,{logicalKey:c.key})}let f=c?.key??n.agentContext.issueTitle??n.agentContext.repo,p=await ia(f,r.serverHandle.client,o,{limit:5},a);a.debug(`Searched prior sessions`,{query:f,resultCount:p.length});for(let e of p)i.addSessionUsed(e.sessionId);let m=e({phase:`attachments`}),h=n.agentContext.commentBody??``,g=Di(h),_=null;if(g.length>0){m.info(`Processing attachments`,{count:g.length});let{validated:e,skipped:n}=Ri(await Mi(g,t.inputs.githubToken,void 0,m),void 0,m);(e.length>0||n.length>0)&&(_=Ii(h,g,e,n),m.info(`Attachments processed`,{processed:e.length,skipped:n.length}))}return{recentSessions:s,priorWorkContext:p,attachmentResult:_,normalizedWorkspace:o,logicalKey:c,continueSessionId:u,isContinuation:d,sessionTitle:l}}async function xo(){let n=Date.now(),r=e({phase:`bootstrap`}),i=Ne();i.start();let a=null,o=!1,s=0,c=null,l=null,u=null,d=null;F(N.SHOULD_SAVE_CACHE,`false`),F(N.CACHE_SAVED,`false`);try{r.info(`Starting Fro Bot Agent`);let e=await bi(r);if(e==null)return 1;u=e.opencodeResult.version;let t=await mo(e,n);if(t==null)return 0;c=t.githubClient;let f=`${t.triggerResult.context.repo.owner}/${t.triggerResult.context.repo.repo}`,p=await ya(e.inputs.dedupWindow,t.triggerResult.context,f,n);if(!p.shouldProceed)return 0;a=await fi(t,e.logger);let m=await wi(e);if(m==null)return 1;d=m.serverHandle,i.setCacheStatus(m.cacheStatus);let h=await bo(e,t,m,i);l=h.attachmentResult;let g=await xa(e,t,m,h,i,n);o=g.success,o&&p.entity!=null&&await ba(t.triggerResult.context,p.entity,f),i.end(),s=await Na(e,t,m,g,i,n,e.logger)}catch(e){s=1;let a=Date.now()-n,o=e instanceof Error?e.name:`UnknownError`,c=e instanceof Error?e.message:String(e);i.recordError(o,c,!1),i.end(),V({sessionId:null,cacheStatus:`miss`,duration:a}),e instanceof Error?(r.error(`Agent failed`,{error:e.message}),t(e.message)):(r.error(`Agent failed with unknown error`),t(`An unknown error occurred`))}finally{await la({bootstrapLogger:r,reactionCtx:a,githubClient:c,agentSuccess:o,attachmentResult:l,serverHandle:d,detectedOpencodeVersion:u})}return s}await xo().then(e=>{I.exit(e)});export{}; \ No newline at end of file +`,{discussionId:i.id,body:n.body});return r.debug(`Created discussion comment`,{discussionId:i.id}),{commentId:a.addDiscussionComment.comment.id,created:!0,updated:!1,url:a.addDiscussionComment.comment.url}}catch(e){return r.warning(`Failed to post discussion comment`,{target:t,error:A(e)}),null}}async function Fa(e,t,n,r){if(t.type===`discussion`)return Pa(e,t,n,r);if(n.updateExisting===!0&&n.botLogin!=null){let i=await Aa(e,t,n.botLogin,r);if(i!=null){let a=ja(i,n.botLogin);if(a!=null&&typeof a.id==`number`)return Na(e,t,a.id,n.body,r)}}return Ma(e,t,n.body,r)}async function Ia(n,r,i,a,o,s,c){let l=Date.now()-s;if(z({sessionId:a.sessionId,cacheStatus:i.cacheStatus,duration:l}),await Pe({eventType:r.agentContext.eventName,repo:r.agentContext.repo,ref:r.agentContext.ref,runId:Number(r.agentContext.runId),runUrl:`https://github.com/${r.agentContext.repo}/actions/runs/${r.agentContext.runId}`,metrics:o.getMetrics(),agent:n.inputs.agent},c),a.success)return c.info(`Agent run completed successfully`,{durationMs:l}),0;if(a.llmError==null)return t(`Agent execution failed with exit code ${a.exitCode}`),a.exitCode;c.info(`Agent failed with recoverable LLM error`,{error:a.llmError.message,type:a.llmError.type,durationMs:l});let[u,d]=r.agentContext.repo.split(`/`),f={type:r.triggerResult.context.eventType===`discussion_comment`?`discussion`:r.agentContext.issueType===`pr`?`pr`:`issue`,number:r.agentContext.issueNumber??0,owner:u??``,repo:d??``};if(f.number>0&&f.owner.length>0&&f.repo.length>0){let t=dn(a.llmError),n=e({phase:`error-comment`}),i=await Fa(r.githubClient,f,{body:t},n);i==null?n.warning(`Failed to post LLM error comment`):(n.info(`Posted LLM error comment`,{commentUrl:i.url}),o.incrementComments())}else c.warning(`Cannot post error comment: missing target context`);return 0}function La(e){switch(e){case`issue_comment`:return`issue_comment`;case`discussion`:case`discussion_comment`:return`discussion_comment`;case`workflow_dispatch`:return`workflow_dispatch`;case`issues`:return`issues`;case`pull_request`:return`pull_request`;case`pull_request_review_comment`:return`pull_request_review_comment`;case`schedule`:return`schedule`;default:return`unsupported`}}function Ra(e,t){switch(e){case`issue_comment`:{let e=t;return{type:`issue_comment`,action:e.action,issue:{number:e.issue.number,title:e.issue.title,body:e.issue.body??null,locked:e.issue.locked??!1,isPullRequest:e.issue.pull_request!=null},comment:{id:e.comment.id,body:e.comment.body,author:e.comment.user.login,authorAssociation:e.comment.author_association??`NONE`}}}case`discussion_comment`:{let e=t;return{type:`discussion_comment`,action:e.action,discussion:{number:e.discussion.number,title:e.discussion.title,body:e.discussion.body??null,locked:e.discussion.locked??!1},comment:{id:e.comment.id,body:e.comment.body??null,author:e.comment.user.login,authorAssociation:e.comment.author_association??`NONE`}}}case`issues`:{let e=t;return{type:`issues`,action:e.action,issue:{number:e.issue.number,title:e.issue.title,body:e.issue.body??null,locked:e.issue.locked??!1,authorAssociation:e.issue.author_association??`NONE`},sender:{login:e.sender.login}}}case`pull_request`:{let e=t,n=e.pull_request.requested_reviewers??[],r=`requested_reviewer`in e&&e.requested_reviewer!=null?{login:e.requested_reviewer.login,type:e.requested_reviewer.type}:null,i=`requested_team`in e&&e.requested_team!=null?{name:e.requested_team.name,slug:e.requested_team.slug}:null,a=n.flatMap(e=>`login`in e&&`type`in e?[{login:e.login,type:e.type}]:[]);return{type:`pull_request`,action:e.action,requestedReviewer:r,requestedTeam:i,pullRequest:{number:e.pull_request.number,title:e.pull_request.title,body:e.pull_request.body??null,locked:e.pull_request.locked??!1,draft:e.pull_request.draft??!1,authorAssociation:e.pull_request.author_association??`NONE`,requestedReviewers:a},sender:{login:e.sender.login}}}case`pull_request_review_comment`:{let e=t;return{type:`pull_request_review_comment`,action:e.action,pullRequest:{number:e.pull_request.number,title:e.pull_request.title,locked:e.pull_request.locked??!1},comment:{id:e.comment.id,body:e.comment.body,author:e.comment.user.login,authorAssociation:e.comment.author_association,path:e.comment.path,line:e.comment.line??null,diffHunk:e.comment.diff_hunk,commitId:e.comment.commit_id}}}case`workflow_dispatch`:return{type:`workflow_dispatch`,inputs:{prompt:t.inputs?.prompt??void 0}};case`schedule`:return{type:`schedule`,schedule:t.schedule??void 0};case`unsupported`:return{type:`unsupported`}}}function za(e){let t=re,n=La(t.eventName),r=Ra(n,t.payload);return e.debug(`Parsed GitHub context`,{eventName:t.eventName,eventType:n,repo:`${t.repo.owner}/${t.repo.repo}`}),{eventName:t.eventName,eventType:n,repo:t.repo,ref:t.ref,sha:t.sha,runId:t.runId,actor:t.actor,payload:t.payload,event:r}}function Y(e,t){return t.includes(e)}function X(e){return e.endsWith(`[bot]`)}function Ba(e,t){if(t.length===0)return!1;let n=t.replace(/\[bot\]$/i,``);return n.length===0?!1:new RegExp(String.raw`@${Va(n)}(?:\[bot\])?(?:$|[^\w])`,`i`).test(e)}function Va(e){return e.replaceAll(/[.*+?^${}()|[\]\\]/g,String.raw`\$&`)}function Ha(e,t){if(t.length===0)return null;let n=t.replace(/\[bot\]$/i,``);if(n.length===0)return null;let r=new RegExp(String.raw`@${Va(n)}(?:\[bot\])?\s*(.*)`,`is`).exec(e)?.[1];if(r==null)return null;let i=r.trim();if(i.length===0)return{raw:``,action:null,args:``};let a=i.split(/\s+/),o=a[0]??``;return{raw:i,action:o===``?null:o,args:a.slice(1).join(` `)}}function Z(e,t){if(t==null||t===``||e==null)return{hasMention:!1,command:null};let n=Ba(e,t);return{hasMention:n,command:n?Ha(e,t):null}}function Ua(e,t){if(e.type!==`issue_comment`)throw Error(`Event type must be issue_comment`);let n={login:e.comment.author,association:e.comment.authorAssociation,isBot:X(e.comment.author)},r={kind:e.issue.isPullRequest?`pr`:`issue`,number:e.issue.number,title:e.issue.title,body:e.comment.body??null,locked:e.issue.locked},{hasMention:i,command:a}=Z(e.comment.body,t);return{action:e.action,author:n,target:r,commentBody:e.comment.body,commentId:e.comment.id,hasMention:i,command:a,isBotReviewRequested:!1}}function Wa(e,t){if(e.type!==`discussion_comment`)throw Error(`Event type must be discussion_comment`);let n={login:e.comment.author,association:e.comment.authorAssociation,isBot:X(e.comment.author)},r=e.comment.body??null,i={kind:`discussion`,number:e.discussion.number,title:e.discussion.title,body:r??e.discussion.body??null,locked:e.discussion.locked},{hasMention:a,command:o}=Z(r,t);return{action:e.action,author:n,target:i,commentBody:r,commentId:e.comment.id,hasMention:a,command:o,isBotReviewRequested:!1}}function Ga(e,t){if(e.type!==`pull_request_review_comment`)throw Error(`Event type must be pull_request_review_comment`);let n={login:e.comment.author,association:e.comment.authorAssociation,isBot:X(e.comment.author)},r={kind:`pr`,number:e.pullRequest.number,title:e.pullRequest.title,body:e.comment.body,locked:e.pullRequest.locked,path:e.comment.path,line:e.comment.line??void 0,diffHunk:e.comment.diffHunk,commitId:e.comment.commitId},{hasMention:i,command:a}=Z(e.comment.body,t);return{action:e.action,author:n,target:r,commentBody:e.comment.body,commentId:e.comment.id,hasMention:i,command:a,isBotReviewRequested:!1}}function Ka(e,t,n){if(e.type!==`workflow_dispatch`)throw Error(`Event type must be workflow_dispatch`);let r=(n??e.inputs?.prompt??``).trim();return{action:null,author:{login:t,association:`OWNER`,isBot:!1},target:{kind:`manual`,number:0,title:`Manual workflow dispatch`,body:r===``?null:r,locked:!1},commentBody:r===``?null:r,commentId:null,hasMention:!1,command:null,isBotReviewRequested:!1}}function qa(e,t,n){let r=n?.trim()??``;return{action:null,author:{login:t,association:`OWNER`,isBot:!1},target:{kind:`manual`,number:0,title:`Scheduled workflow`,body:r===``?null:r,locked:!1},commentBody:r===``?null:r,commentId:null,hasMention:!1,command:null,isBotReviewRequested:!1}}function Ja(e){return e.toLowerCase().replace(/\[bot\]$/i,``)}function Ya(e,t){if(e.type!==`pull_request`||t==null||t===``)return!1;let n=Ja(t);if(n===``)return!1;if(e.action===`review_requested`){let t=e.requestedReviewer?.login;return t!=null&&Ja(t)===n}return e.action===`ready_for_review`?e.pullRequest.requestedReviewers.some(e=>Ja(e.login)===n):!1}function Xa(e,t){if(e.type!==`issues`)throw Error(`Event type must be issues`);let n={login:e.sender.login,association:e.issue.authorAssociation,isBot:X(e.sender.login)},r={kind:`issue`,number:e.issue.number,title:e.issue.title,body:e.issue.body,locked:e.issue.locked},{hasMention:i,command:a}=Z(e.issue.body??``,t);return{action:e.action,author:n,target:r,commentBody:e.issue.body,commentId:null,hasMention:i,command:a,isBotReviewRequested:!1}}function Za(e,t){if(e.type!==`pull_request`)throw Error(`Event type must be pull_request`);let n={login:e.sender.login,association:e.pullRequest.authorAssociation,isBot:X(e.sender.login)},r={kind:`pr`,number:e.pullRequest.number,title:e.pullRequest.title,body:e.pullRequest.body,locked:e.pullRequest.locked,isDraft:e.pullRequest.draft,requestedReviewerLogin:e.requestedReviewer?.login,requestedTeamSlug:e.requestedTeam?.slug,requestedReviewerLogins:e.pullRequest.requestedReviewers.map(e=>e.login)},{hasMention:i,command:a}=Z(e.pullRequest.body??``,t);return{action:e.action,author:n,target:r,commentBody:e.pullRequest.body,commentId:null,hasMention:i,command:a,isBotReviewRequested:Ya(e,t)}}function Q(e,t){return{...e,action:t.action,author:t.author,target:t.target,commentBody:t.commentBody,commentId:t.commentId,hasMention:t.hasMention,command:t.command,isBotReviewRequested:t.isBotReviewRequested}}function Qa(e,t,n){let r={eventType:e.eventType,eventName:e.eventName,repo:e.repo,ref:e.ref,sha:e.sha,runId:e.runId,actor:e.actor,raw:e};switch(e.eventType){case`issue_comment`:return Q(r,Ua(e.event,t));case`discussion_comment`:return Q(r,Wa(e.event,t));case`workflow_dispatch`:return Q(r,Ka(e.event,e.actor,n));case`issues`:return Q(r,Xa(e.event,t));case`pull_request`:return Q(r,Za(e.event,t));case`pull_request_review_comment`:return Q(r,Ga(e.event,t));case`schedule`:return Q(r,qa(e.event,e.actor,n));case`unsupported`:return{...r,action:null,author:null,target:null,commentBody:null,commentId:null,hasMention:!1,command:null,isBotReviewRequested:!1}}}function $a(e,t,n){let{targetLabel:r,actionLabel:i}=n;return e.action===`created`?e.target?.locked===!0?{shouldSkip:!0,reason:`issue_locked`,message:`${r} is locked`}:e.author!=null&&e.author.isBot?{shouldSkip:!0,reason:`self_comment`,message:`Comments from bots (${e.author.login}) are not processed`}:e.author!=null&&!Y(e.author.association,t.allowedAssociations)?{shouldSkip:!0,reason:`unauthorized_author`,message:`Author association '${e.author.association}' is not authorized`}:t.requireMention&&!e.hasMention?{shouldSkip:!0,reason:`no_mention`,message:`Comment does not mention the bot`}:{shouldSkip:!1}:{shouldSkip:!0,reason:`action_not_created`,message:`${i} action is '${e.action}', not 'created'`}}function eo(e,t){return $a(e,t,{targetLabel:`Issue or PR`,actionLabel:`Comment`})}function to(e,t){return $a(e,t,{targetLabel:`Discussion`,actionLabel:`Discussion comment`})}const no=[`opened`,`edited`];function ro(e){return no.includes(e)}function io(e,t){let n=e.action;return n==null||!ro(n)?{shouldSkip:!0,reason:`action_not_supported`,message:`Issues action '${n}' is not supported (only 'opened' and 'edited')`}:e.author!=null&&e.author.isBot?{shouldSkip:!0,reason:`self_comment`,message:`Issues from bots (${e.author.login}) are not processed`}:e.author!=null&&!Y(e.author.association,t.allowedAssociations)?{shouldSkip:!0,reason:`unauthorized_author`,message:`Author association '${e.author.association}' is not authorized`}:n===`edited`&&!e.hasMention?{shouldSkip:!0,reason:`no_mention`,message:`Issue edit does not mention the bot`}:e.target?.locked===!0?{shouldSkip:!0,reason:`issue_locked`,message:`Issue is locked`}:{shouldSkip:!1}}function ao(e){return(e.promptInput?.trim()??``)===``?{shouldSkip:!0,reason:`prompt_required`,message:`Schedule trigger requires prompt input`}:{shouldSkip:!1}}function oo(e){return(e.commentBody?.trim()??``)===``?{shouldSkip:!0,reason:`prompt_required`,message:`Workflow dispatch requires prompt input`}:{shouldSkip:!1}}const so=[`opened`,`synchronize`,`reopened`,`ready_for_review`,`review_requested`];function co(e){return so.includes(e)}function lo(e,t){let n=e.action;return n==null||!co(n)?{shouldSkip:!0,reason:`action_not_supported`,message:`Pull request action '${n}' is not supported`}:e.action!==`review_requested`&&e.action!==`ready_for_review`&&e.author!=null&&e.author.isBot?{shouldSkip:!0,reason:`self_comment`,message:`Pull requests from bots (${e.author.login}) are not processed`}:e.author!=null&&!Y(e.author.association,t.allowedAssociations)?{shouldSkip:!0,reason:`unauthorized_author`,message:`Author association '${e.author.association}' is not authorized`}:t.skipDraftPRs&&e.target?.isDraft===!0?{shouldSkip:!0,reason:`draft_pr`,message:`Pull request is a draft`}:e.target?.locked===!0?{shouldSkip:!0,reason:`issue_locked`,message:`Pull request is locked`}:t.botLogin!=null&&t.botLogin!==``&&(e.action===`ready_for_review`||e.action===`review_requested`)&&e.isBotReviewRequested!==!0?{shouldSkip:!0,reason:`bot_not_requested`,message:`Pull request action '${e.action}' did not request review from the bot`}:{shouldSkip:!1}}function uo(e,t){let n=e.action;return n===`created`?e.target?.locked===!0?{shouldSkip:!0,reason:`issue_locked`,message:`Pull request is locked`}:e.author!=null&&e.author.isBot?{shouldSkip:!0,reason:`self_comment`,message:`Review comments from bots (${e.author.login}) are not processed`}:e.author!=null&&!Y(e.author.association,t.allowedAssociations)?{shouldSkip:!0,reason:`unauthorized_author`,message:`Author association '${e.author.association}' is not authorized`}:t.requireMention&&!e.hasMention?{shouldSkip:!0,reason:`no_mention`,message:`Review comment does not mention the bot`}:{shouldSkip:!1}:{shouldSkip:!0,reason:`action_not_created`,message:`Review comment action '${n}' is not supported (only 'created')`}}function fo(e){return{shouldSkip:!0,reason:`unsupported_event`,message:`Unsupported event type: ${e}`}}function po(e,t,n){if(e.eventType===`unsupported`)return n.debug(`Skipping unsupported event`,{eventName:e.eventName}),fo(e.eventName);switch(e.eventType){case`issue_comment`:return eo(e,t);case`discussion_comment`:return to(e,t);case`issues`:return io(e,t);case`pull_request`:return lo(e,t);case`pull_request_review_comment`:return uo(e,t);case`schedule`:return ao(t);case`workflow_dispatch`:return oo(e);default:return{shouldSkip:!1}}}const mo={botLogin:null,requireMention:!0,allowedAssociations:li,skipDraftPRs:!0,promptInput:null,senderAssociation:null};function ho(e,t,n={}){let r={...mo,...n},i=Qa(e,r.botLogin,r.promptInput);r.senderAssociation!=null&&(i.action===`review_requested`||i.action===`ready_for_review`)&&i.author!=null&&(i={...i,author:{...i.author,association:r.senderAssociation}}),t.debug(`Routing event`,{eventName:e.eventName,eventType:e.eventType,hasMention:i.hasMention});let a=po(i,r,t);return a.shouldSkip?{shouldProcess:!1,skipReason:a.reason,skipMessage:a.message,context:i}:{shouldProcess:!0,context:i}}async function go(t,n){let r=e({phase:`context`}),i=za(r),a=Fr({token:t.inputs.githubToken,logger:r}),o=await Ir(a,r),s=null;if(i.event.type===`pull_request`&&(i.event.action===`review_requested`||i.event.action===`ready_for_review`)){let{owner:e,repo:t}=i.repo;s=await We(a,e,t,i.event.sender.login,r)}let c=e({phase:`trigger`}),l=ho(i,c,{botLogin:o,requireMention:!0,promptInput:t.inputs.prompt,senderAssociation:s});return l.shouldProcess?(c.info(`Event routed for processing`,{eventType:l.context.eventType,hasMention:l.context.hasMention,command:l.context.command?.action??null}),M(j.SHOULD_SAVE_CACHE,`true`),{githubClient:a,triggerResult:l,agentContext:await st({logger:r,octokit:a,triggerContext:l.context,botLogin:o}),botLogin:o}):(c.info(`Skipping event`,{reason:l.skipReason,message:l.skipMessage}),z({sessionId:null,cacheStatus:`miss`,duration:Date.now()-n}),null)}function $(e,t){return{key:`${e}-${t}`,entityType:e,entityId:t}}function _o(e){return Ce(`sha256`).update(e).digest(`hex`).slice(0,8)}function vo(e){if(e.eventType===`unsupported`)return null;if(e.eventType===`schedule`){let t=e.raw.event.type===`schedule`?e.raw.event.schedule:void 0;return $(`schedule`,_o((t!=null&&t.trim().length>0?t:e.action)??`default`))}return e.eventType===`workflow_dispatch`?$(`dispatch`,String(e.runId)):e.target==null?null:e.eventType===`issue_comment`?e.target.kind===`issue`?$(`issue`,String(e.target.number)):e.target.kind===`pr`?$(`pr`,String(e.target.number)):null:e.eventType===`discussion_comment`?e.target.kind===`discussion`?$(`discussion`,String(e.target.number)):null:e.eventType===`issues`?e.target.kind===`issue`?$(`issue`,String(e.target.number)):null:(e.eventType===`pull_request`||e.eventType===`pull_request_review_comment`)&&e.target.kind===`pr`?$(`pr`,String(e.target.number)):null}function yo(e){return`fro-bot: ${e.key}`}function bo(e,t){let n=e.filter(e=>e.title===t);return n.length===0?null:n.reduce((e,t)=>t.time.updated>e.time.updated?t:e)}async function xo(e,t,n,r){try{let i=bo(await Zi(e,t,r),yo(n));return i==null||i.time.archived!=null||i.time.compacting!=null?{status:`not-found`}:{status:`found`,session:i}}catch(e){return{status:`error`,error:e instanceof Error?e.message:String(e)}}}async function So(t,n,r,i){let a=e({phase:`session`}),o=q(se()),s=await ra(r.serverHandle.client,o,{limit:10},a);a.debug(`Listed recent sessions`,{count:s.length});let c=vo(n.triggerResult.context),l=c==null?null:yo(c),u=null,d=!1;if(c!=null){let e=await xo(r.serverHandle.client,o,c,a);e.status===`found`?(u=e.session.id,d=!0,a.info(`Session continuity: found existing session`,{logicalKey:c.key,sessionId:u})):e.status===`error`?a.warning(`Session continuity: lookup error, will create new`,{logicalKey:c.key,error:e.error}):a.info(`Session continuity: no existing session found`,{logicalKey:c.key})}let f=c?.key??n.agentContext.issueTitle??n.agentContext.repo,p=await aa(f,r.serverHandle.client,o,{limit:5},a);a.debug(`Searched prior sessions`,{query:f,resultCount:p.length});for(let e of p)i.addSessionUsed(e.sessionId);let m=e({phase:`attachments`}),h=n.agentContext.commentBody??``,g=Oi(h),_=null;if(g.length>0){m.info(`Processing attachments`,{count:g.length});let{validated:e,skipped:n}=zi(await Ni(g,t.inputs.githubToken,void 0,m),void 0,m);(e.length>0||n.length>0)&&(_=Li(h,g,e,n),m.info(`Attachments processed`,{processed:e.length,skipped:n.length}))}return{recentSessions:s,priorWorkContext:p,attachmentResult:_,normalizedWorkspace:o,logicalKey:c,continueSessionId:u,isContinuation:d,sessionTitle:l}}async function Co(){let n=Date.now(),r=e({phase:`bootstrap`}),i=Fe();i.start();let a=null,o=!1,s=0,c=null,l=null,u=null,d=null;M(j.SHOULD_SAVE_CACHE,`false`),M(j.CACHE_SAVED,`false`);try{r.info(`Starting Fro Bot Agent`);let e=await xi(r);if(e==null)return 1;u=e.opencodeResult.version;let t=await go(e,n);if(t==null)return 0;c=t.githubClient;let f=`${t.triggerResult.context.repo.owner}/${t.triggerResult.context.repo.repo}`,p=await xa(e.inputs.dedupWindow,t.triggerResult.context,f,n);if(!p.shouldProceed)return 0;a=await pi(t,e.logger);let m=await Ti(e);if(m==null)return 1;d=m.serverHandle,i.setCacheStatus(m.cacheStatus);let h=await So(e,t,m,i);l=h.attachmentResult;let g=await wa(e,t,m,h,i,n);o=g.success,o&&p.entity!=null&&await Sa(t.triggerResult.context,p.entity,f),i.end(),s=await Ia(e,t,m,g,i,n,e.logger)}catch(e){s=1;let a=Date.now()-n,o=e instanceof Error?e.name:`UnknownError`,c=e instanceof Error?e.message:String(e);i.recordError(o,c,!1),i.end(),z({sessionId:null,cacheStatus:`miss`,duration:a}),e instanceof Error?(r.error(`Agent failed`,{error:e.message}),t(e.message)):(r.error(`Agent failed with unknown error`),t(`An unknown error occurred`))}finally{await ua({bootstrapLogger:r,reactionCtx:a,githubClient:c,agentSuccess:o,attachmentResult:l,serverHandle:d,detectedOpencodeVersion:u})}return s}await Co().then(e=>{N.exit(e)});export{}; \ No newline at end of file diff --git a/src/harness/phases/dedup.test.ts b/src/harness/phases/dedup.test.ts index c54f3a79..ac774f7f 100644 --- a/src/harness/phases/dedup.test.ts +++ b/src/harness/phases/dedup.test.ts @@ -1,12 +1,30 @@ import type {TriggerContext, TriggerTarget} from '../../features/triggers/types.js' import type {DeduplicationMarker} from '../../services/cache/dedup.js' import type {EventType, GitHubContext} from '../../services/github/types.js' +import * as core from '@actions/core' import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest' import {restoreDeduplicationMarker, saveDeduplicationMarker} from '../../services/cache/dedup.js' import {createMockLogger} from '../../shared/test-helpers.js' import {setActionOutputs} from '../config/outputs.js' import {extractDedupEntity, runDedup, saveDedupMarker} from './dedup.js' +vi.mock('@actions/core', () => ({ + summary: { + addHeading: vi.fn().mockReturnThis(), + addTable: vi.fn().mockReturnThis(), + addRaw: vi.fn().mockReturnThis(), + write: vi.fn().mockResolvedValue(undefined), + }, + warning: vi.fn(), + info: vi.fn(), + debug: vi.fn(), + setOutput: vi.fn(), + getInput: vi.fn().mockReturnValue(''), + saveState: vi.fn(), + getState: vi.fn().mockReturnValue(''), + setFailed: vi.fn(), +})) + vi.mock('../../services/cache/dedup.js', () => ({ restoreDeduplicationMarker: vi.fn(), saveDeduplicationMarker: vi.fn(), @@ -178,6 +196,38 @@ describe('runDedup', () => { expect(vi.mocked(restoreDeduplicationMarker)).not.toHaveBeenCalled() }) + it('bypasses dedup for synchronize action', async () => { + // #given synchronize action on a PR (fires first, needed for required status checks) + const context = createTriggerContext({ + eventType: 'pull_request', + action: 'synchronize', + target: createTarget('pr', 42), + }) + + // #when running dedup phase + const result = await runDedup(600_000, context, 'fro-bot/agent', 1, createMockLogger()) + + // #then dedup is bypassed β€” no cache lookup occurs + expect(result).toEqual({shouldProceed: true, entity: {entityType: 'pr', entityNumber: 42}}) + expect(vi.mocked(restoreDeduplicationMarker)).not.toHaveBeenCalled() + }) + + it('bypasses dedup for reopened action', async () => { + // #given reopened PR (meaningful state change, breaks dedup lock) + const context = createTriggerContext({ + eventType: 'pull_request', + action: 'reopened', + target: createTarget('pr', 42), + }) + + // #when running dedup phase + const result = await runDedup(600_000, context, 'fro-bot/agent', 1, createMockLogger()) + + // #then dedup is bypassed + expect(result).toEqual({shouldProceed: true, entity: {entityType: 'pr', entityNumber: 42}}) + expect(vi.mocked(restoreDeduplicationMarker)).not.toHaveBeenCalled() + }) + it('returns shouldProceed true when no sentinel is found', async () => { // #given cache miss for dedup marker vi.mocked(restoreDeduplicationMarker).mockResolvedValueOnce(null) @@ -292,7 +342,7 @@ describe('runDedup', () => { // #when running dedup phase const result = await runDedup(10_000, context, 'fro-bot/agent', 5_000, createMockLogger()) - // #then processing is skipped and outputs are set + // #then processing is skipped, outputs set, and job summary written expect(result).toEqual({ shouldProceed: false, entity: {entityType: 'pr', entityNumber: 42}, @@ -302,6 +352,8 @@ describe('runDedup', () => { cacheStatus: 'miss', duration: 25_000, }) + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(core.summary.write).toHaveBeenCalled() }) }) diff --git a/src/harness/phases/dedup.ts b/src/harness/phases/dedup.ts index 0613c398..108dcf35 100644 --- a/src/harness/phases/dedup.ts +++ b/src/harness/phases/dedup.ts @@ -1,17 +1,17 @@ import type {TriggerContext} from '../../features/triggers/types.js' +import type {DeduplicationEntity, DeduplicationMarker} from '../../services/cache/dedup.js' import type {CacheAdapter} from '../../services/cache/types.js' import type {Logger} from '../../shared/logger.js' -import { - restoreDeduplicationMarker, - saveDeduplicationMarker, - type DeduplicationEntity, - type DeduplicationMarker, -} from '../../services/cache/dedup.js' +import * as core from '@actions/core' +import {restoreDeduplicationMarker, saveDeduplicationMarker} from '../../services/cache/dedup.js' +import {toErrorMessage} from '../../shared/errors.js' import {createLogger} from '../../shared/logger.js' import {setActionOutputs} from '../config/outputs.js' const DEDUP_EVENT_TYPES = new Set(['pull_request', 'issues']) +const DEDUP_BYPASS_ACTIONS = new Set(['synchronize', 'reopened']) + export interface DedupCheckResult { readonly shouldProceed: boolean readonly entity: DeduplicationEntity | null @@ -55,6 +55,11 @@ export async function runDedup( return {shouldProceed: true, entity: null} } + if (triggerContext.action != null && DEDUP_BYPASS_ACTIONS.has(triggerContext.action)) { + logger.debug('Dedup bypassed for action', {action: triggerContext.action}) + return {shouldProceed: true, entity} + } + const marker = await restoreDeduplicationMarker(repo, entity, logger, cacheAdapter) if (marker == null) { return {shouldProceed: true, entity} @@ -104,6 +109,8 @@ export async function runDedup( duration: Date.now() - startTime, }) + await writeDedupSkipSummary(triggerContext, entity, marker, effectiveAge, dedupWindow, logger) + return {shouldProceed: false, entity} } @@ -125,3 +132,39 @@ export async function saveDedupMarker( await saveDeduplicationMarker(repo, entity, marker, logger, cacheAdapter) } + +async function writeDedupSkipSummary( + triggerContext: TriggerContext, + entity: DeduplicationEntity, + marker: DeduplicationMarker, + ageMs: number, + dedupWindow: number, + logger: Logger, +): Promise { + try { + const ageSeconds = Math.round(ageMs / 1000) + const windowSeconds = Math.round(dedupWindow / 1000) + const entityLabel = `${entity.entityType} #${entity.entityNumber}` + const priorRunUrl = `https://github.com/${triggerContext.repo.owner}/${triggerContext.repo.repo}/actions/runs/${marker.runId}` + + core.summary + .addHeading('Fro Bot Agent Run β€” Skipped (Dedup)', 2) + .addRaw(`Execution skipped because the agent already ran for **${entityLabel}** recently.\n\n`) + .addTable([ + [ + {data: 'Detail', header: true}, + {data: 'Value', header: true}, + ], + ['Current action', `\`${triggerContext.eventType}.${triggerContext.action ?? 'unknown'}\``], + ['Prior run', `[${marker.runId}](${priorRunUrl})`], + ['Prior action', `\`${marker.eventType}.${marker.action}\``], + ['Time since prior run', `${ageSeconds}s`], + ['Dedup window', `${windowSeconds}s`], + ]) + .addRaw('\n> Dedup is best-effort suppression. Use workflow concurrency groups to prevent overlapping runs.\n') + + await core.summary.write() + } catch (error) { + logger.warning('Failed to write dedup skip summary', {error: toErrorMessage(error)}) + } +}