@netlify/agent-runner-cli 1.75.0-alpha.0 → 1.75.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin-local.js +1 -1
- package/dist/bin.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/bin-local.js
CHANGED
|
@@ -5,7 +5,7 @@ import L from"process";import Fr from"path";import Lr from"fs";import ho from"mi
|
|
|
5
5
|
${i}
|
|
6
6
|
</extracted_error_chunk>`).join(`
|
|
7
7
|
|
|
8
|
-
`);return s.length>e.length*.8?e:s}import{execSync as $n}from"child_process";import Er from"fs/promises";import Fn from"path";import ne from"process";import{getTracer as Ln}from"@netlify/otel";import Ie from"process";var le=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},Pt=e=>e instanceof le;var Fe=Ie.env.NETLIFY_API_URL,Le=Ie.env.NETLIFY_API_TOKEN,J=T("api"),De=()=>Ie.env.NETLIFY_LOCAL_MODE==="true",xe=async(e,t={})=>{if(!Fe||!Le)throw new Error("No API URL or token");let r=new URL(e,Fe),o={...t,headers:{...t.headers,Authorization:`Bearer ${Le}`}};Ie.env.AGENT_RUNNERS_DEBUG==="true"&&(o.headers["x-nf-debug-logging"]="true"),t.json&&(o.headers||={},o.headers["Content-Type"]="application/json",o.body=JSON.stringify(t.json));let n=await fetch(r,o),s=n.ok&&n.status<=299;if(Ie.env.AGENT_RUNNERS_DEBUG==="true")J.log(`Response headers for ${r}:`),n.headers.forEach((a,l)=>{J.log(` ${l}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");J.log(`Request ID for ${r}: ${a||"N/A"}`)}if(s||J.error(`Got status ${n.status} for request ${r}`),t.raw){if(!s)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let i=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!s){let a=typeof i=="string"?i:JSON.stringify(i);throw n.status===404?new le(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new le(`API request failed: 403 - ${a}`,403,"Credit limit reached. Please add more credits to continue using Agent Runners."):new Error(`API request failed: ${n.status} - ${a}`)}return i},kt=e=>{J.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Fe=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Le=e.constants.NETLIFY_API_TOKEN)},Ot=()=>({apiUrl:Fe,token:Le}),Re=async(e,t)=>De()?(J.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):xe(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),B=async(e,t,r)=>De()?(J.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var $t=async(e,t)=>De()?(J.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`),Ft=(e,t,r)=>xe(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),Lt=async(e,t)=>De()?(J.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):xe(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),rt=async(e,t)=>{J.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ce=T("ai_gateway"),nt=null;var Dt=async()=>{if(nt)return nt;ce.log("Fetching available AI gateway providers");let e=await fetch(`${Ot().apiUrl}/api/v1/ai-gateway/providers`);if(!e.ok)throw new Error(`Failed to fetch AI gateway providers: ${e.statusText}`);let t=await e.json();return nt=t,ce.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},qr=async(e,t)=>{let o=(await Dt()).providers[e];if(!o)return ce.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return ce.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Mt=async({netlify:e,config:t})=>{let r,o,n,s,i=e.constants?.SITE_ID;if(!i)throw new Error("No site id");let a=async()=>{clearTimeout(n),ce.log("Requesting AI gateway information");let l=await Ft(i,t.id,t.sessionId);if({token:r,url:s}=l,o=l.expires_at?l.expires_at*1e3:void 0,ce.log("Got AI gateway information",{token:!!r,expiresAt:o,url:s}),o){let u=o-Date.now()-6e4;u>0&&(n=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Dt()]),{get url(){return s},get token(){return r},isModelAvailableForProvider:qr}};import z from"process";import Q from"path";import Me from"fs";import{fileURLToPath as Xr}from"url";import{createRequire as Zr}from"module";import{execa as Qr,execaCommand as Vo}from"execa";import{Transform as Hr}from"stream";var Wr=new Set(["NODE_ENV","PATH","HOME","USER","USERNAME","SHELL","PWD","OLDPWD","TMPDIR","TMP","TEMP","LANG","TERM","EDITOR","PAGER","OS","PROCESSOR_ARCHITECTURE","PROCESSOR_IDENTIFIER","SYSTEMROOT","WINDIR","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","APPDATA","LOCALAPPDATA","NODE_OPTIONS","NODE_PATH","NODE_DEBUG","NODE_NO_WARNINGS","npm_config_registry","npm_config_cache","npm_execpath","npm_node_execpath","CI","GITHUB_ACTIONS","GITHUB_WORKSPACE","GITHUB_REPOSITORY","GITHUB_REF","BUILDKITE","BUILDKITE_BRANCH","BUILDKITE_COMMIT","BUILDKITE_BUILD_NUMBER","JENKINS_URL","TRAVIS","CIRCLECI","DISPLAY","COLORTERM","TERM_PROGRAM","TERM_PROGRAM_VERSION","COLUMNS","LINES","HISTSIZE","HISTFILE","NETLIFY_AGENT_RUNNER_ID","NETLIFY_AGENT_RUNNER_SESSION_ID","NETLIFY_AGENT_RUNNER_PROMPT","NETLIFY_AGENT_RUNNER_AGENT","NETLIFY_AGENT_RUNNER_MODEL","NETLIFY_AGENT_RUNNER_CONTEXT","NETLIFY_AGENT_RUNNER_HAS_REPO","NETLIFY_FF_AGENT_RUNNER_BYOK_ENABLED","NETLIFY_AGENT_RUNNER_SHA","NETLIFY_TEAM_TYPE","AGENT_RUNNERS_DEBUG","NETLIFY_TEAM_ID","NETLIFY_AGENT_RUNNER_USER_ID","SITE_NAME"]),Kr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function Jr(){return Object.entries(process.env).filter(([e,t])=>!(!t||Wr.has(e)||Kr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function Z(e){if(typeof e!="string")return e;let t=Jr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Vr(o),"g");r=r.replace(n,"******")}),r}function Vr(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ue=class extends Hr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),s=Z(n);o(null,s)}};function Ut(){if(!(process.env.NETLIFY_MASK_LOGS!=="false"))return;let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr);process.stdout.write=function(o,n,s){let i=typeof o=="string"?Z(o):o;return typeof n=="function"?t(i,n):t(i,n,s)},process.stderr.write=function(o,n,s){let i=typeof o=="string"?Z(o):o;return typeof n=="function"?r(i,n):r(i,n,s)}}var Se=null,Gt=e=>(Se&&Se.destroy(),Se=new te({totalAllowedTime:e}),Se),jt=()=>Se;var te=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,o)=>{if(this.isTimeExpired())throw new Error(`${t} stage did not complete in the allowed time. Time has already expired.`);let n=this.onTimesUp(()=>{throw new Error(`${t} stage did not complete in the allowed time.`)}),s=null,i=null;o!==void 0&&(i=new Promise((a,l)=>{s=setTimeout(()=>{l(new Error(`${t} stage exceeded its maximum duration of ${o}ms`))},o)}));try{return i?await Promise.race([r(),i]):await r()}finally{n(),s&&clearTimeout(s)}};this.startTime=Date.now(),this.totalAllowedTime=t,this.globalTimeoutId=null,this.subscribers=[],this.hasTimedOut=!1,this.setupGlobalTimeout()}getElapsedTime(){return Date.now()-this.startTime}getRemainingTime(){let t=this.getElapsedTime(),r=this.totalAllowedTime-t;return Math.max(0,r)}isTimeExpired(){return this.getRemainingTime()===0||this.hasTimedOut}setupGlobalTimeout(){this.globalTimeoutId&&clearTimeout(this.globalTimeoutId),this.globalTimeoutId=setTimeout(()=>{this.notifyTimeUp()},this.totalAllowedTime)}notifyTimeUp(){this.hasTimedOut=!0;for(let t=this.subscribers.length-1;t>=0;t--)try{this.subscribers[t]()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}}onTimesUp(t){if(this.subscribers.push(t),this.hasTimedOut)try{t()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}return()=>{let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}}off(t){let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}clearSubscribers(){this.subscribers.length=0}getSubscriberCount(){return this.subscribers.length}destroy(){this.globalTimeoutId&&(clearTimeout(this.globalTimeoutId),this.globalTimeoutId=null),this.clearSubscribers()}static{this.timeUnits={seconds:t=>t*1e3,minutes:t=>t*60*1e3,hours:t=>t*60*60*1e3}}};var Yt="netlify-agent-runner-context.md",ot="task-history",V=".netlify",oe="results.md",it="assets";var ie=1800*1e3,E={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var Bt={name:"@netlify/agent-runner-cli",type:"module",version:"1.75.0-alpha.0",description:"CLI tool for running Netlify agents",main:"./dist/index.js",types:"./dist/index.d.ts",exports:"./dist/index.js",bin:{"agent-runner-cli":"./dist/bin.js","agent-runner-cli-local":"./dist/bin-local.js"},files:["dist/**/*.js","dist/**/*.d.ts","dist/skills/**","patches","scripts"],scripts:{build:"tsup",dev:"tsup --watch",prepare:"husky install node_modules/@netlify/eslint-config-node/.husky/",prepublishOnly:"npm ci && npm test",prepack:"npm run build",test:"run-s build format test:dev",format:"run-s build format:check-fix:*","format:ci":"run-s build format:check:*","format:check-fix:lint":"run-e format:check:lint format:fix:lint","format:check:lint":"cross-env-shell eslint $npm_package_config_eslint","format:fix:lint":"cross-env-shell eslint --fix $npm_package_config_eslint","format:check-fix:prettier":"run-e format:check:prettier format:fix:prettier","format:check:prettier":"cross-env-shell prettier --check $npm_package_config_prettier","format:fix:prettier":"cross-env-shell prettier --write $npm_package_config_prettier","test:dev":"run-s build test:dev:*","test:ci":"run-s build test:ci:*","test:dev:vitest":"LOG=0 vitest --exclude '**/integration/**'","test:ci:vitest":"LOG=0 c8 -r lcovonly -r text -r json vitest --exclude '**/integration/**'","test:integration":"vitest run test/integration/","test:integration:codex":"vitest run test/integration/codex.test.ts","test:integration:claude":"vitest run test/integration/claude.test.ts","test:integration:gemini":"vitest run test/integration/gemini.test.ts","test:integration:create-stage":"vitest run test/integration/create.test.ts",postinstall:"node scripts/postinstall.js"},config:{eslint:'--cache --format=codeframe --max-warnings=0 "{src,scripts,test,.github}/**/*.{js,ts,md,html}"',prettier:'--ignore-path .gitignore --loglevel=warn "{src,scripts,test,.github}/**/*.{js,ts,md,yml,json,html}" "*.{js,ts,yml,json,html}" ".*.{js,ts,yml,json,html}" "!**/package-lock.json" "!package-lock.json" "!src/skills/**/*.md"'},keywords:[],license:"MIT",repository:"netlify/agent-runner-cli",bugs:{url:"https://github.com/netlify/agent-runner-cli/issues"},author:"Netlify Inc.",directories:{test:"test"},devDependencies:{"@commitlint/cli":"^20.0.0","@commitlint/config-conventional":"^20.0.0","@eslint/compat":"^2.0.0","@eslint/js":"^9.35.0","@netlify/eslint-config-node":"^7.0.1","@types/node":"^24.5.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/eslint-plugin":"^1.6.6",c8:"^10.0.0","eslint-config-prettier":"^10.1.8","eslint-plugin-n":"^17.0.0",husky:"^9.0.0","patch-package":"^8.0.0",tsup:"^8.5.0",typescript:"^5.0.0","typescript-eslint":"^8.44.0",vitest:"^4.0.16"},dependencies:{"@anthropic-ai/claude-code":"2.1.47","@anthropic-ai/sdk":"0.77.0","@google/gemini-cli":"0.29.3","@netlify/otel":"^5.1.1","@openai/codex":"0.104.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.5.0",minimist:"^1.2.8",openai:"6.22.0"}};var en=Xr(import.meta.url),tn=Q.dirname(en),rn=Zr(import.meta.url),de=T("shell"),st=new Set,nn={preferLocal:!0},S=(e,t,r)=>{let[o,n]=on(t,r),s={...nn,...n},i=Qr(e,o,s);sn(i,s),ln(i);let a=r?.idleTimeout;return a&&a>0&&an(i,a),i};var on=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},sn=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(z.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new ue).pipe(z.stdout),e.stdout?.pipe(new ue).pipe(z.stdout),e.stderr?.pipe(new ue).pipe(z.stderr);return}e.stdout?.pipe(z.stdout),e.stderr?.pipe(z.stderr)},at=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(z.kill(-e.pid,t),de.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return de.error("Error killing process:",r),!1}},qt=e=>at(e,"SIGKILL"),an=(e,t)=>{let r=null,o=()=>{de.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),at(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(de.log(`Force killing idle process ${e.pid}`),qt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(o,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let s=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",s),e.on("error",s)},ln=e=>{st.add(e);let t=jt();if(t){let r=t.onTimesUp(()=>{de.log(`Global timer expired, killing process ${e.pid}`),at(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(de.log(`Force killing process ${e.pid} after timeout`),qt(e))},5e3)});e.on("exit",()=>{st.delete(e),r()}),e.on("error",()=>{st.delete(e),r()})}};function Ue(e,t){return!!ee(e,t)}function ee(e,t){if(!z.env.NETLIFY_LOCAL_MODE)try{let n=rn.resolve(Bt.name),s=Q.dirname(n);for(;s!==Q.dirname(s);){let i=Q.dirname(s);if(Q.basename(i)==="node_modules"){let a=Q.join(i,".bin",t);if(Me.existsSync(a))return a;break}s=i}}catch(n){console.error("Could not resolve package.json",n)}if(z.env.NODE_PATH){let n=Q.join(z.env.NODE_PATH,".bin",t);if(Me.existsSync(n))return n}let r=Q.join(e,"node_modules",".bin",t);if(Me.existsSync(r))return r;let o=Q.join(tn,"..","node_modules",".bin",t);if(Me.existsSync(o))return o}var cn=T("utils"),un=e=>new Promise(t=>{setTimeout(t,e)}),Ht=(e,t=3e3)=>{let r=!1,o=null,n=[],s=null,i=(...a)=>{if(r)return o=a,new Promise(p=>{n.push(p)});r=!0;let l,u=new Promise(p=>{l=p});return s=(async()=>{await Promise.resolve();let p=await e(...a);for(l(p);;){if(await un(t),!o)return r=!1,s=null,p;let d=o,m=n;o=null,n=[],p=await e(...d),m.forEach(h=>{h(p)})}})(),u};return i.flush=async()=>{if((r||o)&&s)return await s,i.flush()},i},pe=(e,t,r=!1)=>{let o=null,n=null,s=null,i=function(...a){n=a,s=this;let l=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(s,n),n=null,s=null)},t),l&&(e.apply(s,n),n=null,s=null)};return i.cancel=()=>{clearTimeout(o),o=null,n=null,s=null},i.flush=()=>{if(o){clearTimeout(o);let a=n,l=s;o=null,n=null,s=null,e.apply(l,a)}},i},Wt=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):cn.error("Could not parse JSON",o))}},Ge=e=>e.charAt(0).toUpperCase()+e.slice(1),Kt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),Jt=(e,t)=>{let n=".netlify.app",s="agent-";if(!t)return`${s}${e.slice(0,6)}`;let a=`--${t}${n}`;if(a.length>55)return"";let l=60-a.length;if(l<=0)return"";if(l>=s.length+6){let u=Math.min(l-s.length,e.length);return`${s}${e.slice(0,u)}`}return e.slice(0,l)};var dn=50*1024,lt=(e,t=dn)=>{if(!e||typeof e!="string"||e.length<=t)return e;let o=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+o};import{Buffer as Vt}from"buffer";import pn from"path";var zt=T("repo"),Zt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{zt.info("Getting runner diffs");let o=await gn(r),{hasChanges:n}=o,{status:s}=o;if(!n)return{hasChanges:!1};if(!t){let _=hn(s);await yn(_,r)}zt.info("Changes after processing"),await ut(r);let i=await dt(s,r);if(await ct(i,r),n=await fn(r),!n)return{hasChanges:!1,ignored:i};process.env.NETLIFY_INTERNAL_GIT="1";try{await S("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},l=await S("git",["diff",e.runSha,"HEAD"],a),u=String(l.stdout??"");if(n=!!u,!n)return await Xt(r),{hasChanges:!1,ignored:i};let p=await S("git",["diff",e.runSha,"HEAD","--binary"],a),d=String(p.stdout??""),m,h;if(e.sha){let _=await S("git",["diff",e.sha,"HEAD"],a);m=String(_.stdout??"");let I=await S("git",["diff",e.sha,"HEAD","--binary"],a),w=String(I.stdout??"");m!==w&&(h=Vt.from(w).toString("base64"))}await Xt(r);let y={hasChanges:!0,diff:u,resultDiff:m,ignored:i};return u!==d&&(y.diffBinary=Vt.from(d).toString("base64")),h&&(y.resultDiffBinary=h),y},Xt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await S("git",["reset","--soft","HEAD~1"],{cwd:e})},ct=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await S("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},ut=async(e=process.cwd())=>{let t=await S("git",["status","-s"],{cwd:e});return String(t.stdout??"")},Qt=/.. (.+)?\.log$/,mn=[Qt],gn=async(e=process.cwd())=>{let t=await ut(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
8
|
+
`);return s.length>e.length*.8?e:s}import{execSync as $n}from"child_process";import Er from"fs/promises";import Fn from"path";import ne from"process";import{getTracer as Ln}from"@netlify/otel";import Ie from"process";var le=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},Pt=e=>e instanceof le;var Fe=Ie.env.NETLIFY_API_URL,Le=Ie.env.NETLIFY_API_TOKEN,J=T("api"),De=()=>Ie.env.NETLIFY_LOCAL_MODE==="true",xe=async(e,t={})=>{if(!Fe||!Le)throw new Error("No API URL or token");let r=new URL(e,Fe),o={...t,headers:{...t.headers,Authorization:`Bearer ${Le}`}};Ie.env.AGENT_RUNNERS_DEBUG==="true"&&(o.headers["x-nf-debug-logging"]="true"),t.json&&(o.headers||={},o.headers["Content-Type"]="application/json",o.body=JSON.stringify(t.json));let n=await fetch(r,o),s=n.ok&&n.status<=299;if(Ie.env.AGENT_RUNNERS_DEBUG==="true")J.log(`Response headers for ${r}:`),n.headers.forEach((a,l)=>{J.log(` ${l}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");J.log(`Request ID for ${r}: ${a||"N/A"}`)}if(s||J.error(`Got status ${n.status} for request ${r}`),t.raw){if(!s)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let i=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!s){let a=typeof i=="string"?i:JSON.stringify(i);throw n.status===404?new le(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new le(`API request failed: 403 - ${a}`,403,"Credit limit reached. Please add more credits to continue using Agent Runners."):new Error(`API request failed: ${n.status} - ${a}`)}return i},kt=e=>{J.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Fe=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Le=e.constants.NETLIFY_API_TOKEN)},Ot=()=>({apiUrl:Fe,token:Le}),Re=async(e,t)=>De()?(J.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):xe(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),B=async(e,t,r)=>De()?(J.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var $t=async(e,t)=>De()?(J.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`),Ft=(e,t,r)=>xe(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),Lt=async(e,t)=>De()?(J.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):xe(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),rt=async(e,t)=>{J.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ce=T("ai_gateway"),nt=null;var Dt=async()=>{if(nt)return nt;ce.log("Fetching available AI gateway providers");let e=await fetch(`${Ot().apiUrl}/api/v1/ai-gateway/providers`);if(!e.ok)throw new Error(`Failed to fetch AI gateway providers: ${e.statusText}`);let t=await e.json();return nt=t,ce.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},qr=async(e,t)=>{let o=(await Dt()).providers[e];if(!o)return ce.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return ce.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Mt=async({netlify:e,config:t})=>{let r,o,n,s,i=e.constants?.SITE_ID;if(!i)throw new Error("No site id");let a=async()=>{clearTimeout(n),ce.log("Requesting AI gateway information");let l=await Ft(i,t.id,t.sessionId);if({token:r,url:s}=l,o=l.expires_at?l.expires_at*1e3:void 0,ce.log("Got AI gateway information",{token:!!r,expiresAt:o,url:s}),o){let u=o-Date.now()-6e4;u>0&&(n=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Dt()]),{get url(){return s},get token(){return r},isModelAvailableForProvider:qr}};import z from"process";import Q from"path";import Me from"fs";import{fileURLToPath as Xr}from"url";import{createRequire as Zr}from"module";import{execa as Qr,execaCommand as Vo}from"execa";import{Transform as Hr}from"stream";var Wr=new Set(["NODE_ENV","PATH","HOME","USER","USERNAME","SHELL","PWD","OLDPWD","TMPDIR","TMP","TEMP","LANG","TERM","EDITOR","PAGER","OS","PROCESSOR_ARCHITECTURE","PROCESSOR_IDENTIFIER","SYSTEMROOT","WINDIR","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","APPDATA","LOCALAPPDATA","NODE_OPTIONS","NODE_PATH","NODE_DEBUG","NODE_NO_WARNINGS","npm_config_registry","npm_config_cache","npm_execpath","npm_node_execpath","CI","GITHUB_ACTIONS","GITHUB_WORKSPACE","GITHUB_REPOSITORY","GITHUB_REF","BUILDKITE","BUILDKITE_BRANCH","BUILDKITE_COMMIT","BUILDKITE_BUILD_NUMBER","JENKINS_URL","TRAVIS","CIRCLECI","DISPLAY","COLORTERM","TERM_PROGRAM","TERM_PROGRAM_VERSION","COLUMNS","LINES","HISTSIZE","HISTFILE","NETLIFY_AGENT_RUNNER_ID","NETLIFY_AGENT_RUNNER_SESSION_ID","NETLIFY_AGENT_RUNNER_PROMPT","NETLIFY_AGENT_RUNNER_AGENT","NETLIFY_AGENT_RUNNER_MODEL","NETLIFY_AGENT_RUNNER_CONTEXT","NETLIFY_AGENT_RUNNER_HAS_REPO","NETLIFY_FF_AGENT_RUNNER_BYOK_ENABLED","NETLIFY_AGENT_RUNNER_SHA","NETLIFY_TEAM_TYPE","AGENT_RUNNERS_DEBUG","NETLIFY_TEAM_ID","NETLIFY_AGENT_RUNNER_USER_ID","SITE_NAME"]),Kr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function Jr(){return Object.entries(process.env).filter(([e,t])=>!(!t||Wr.has(e)||Kr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function Z(e){if(typeof e!="string")return e;let t=Jr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Vr(o),"g");r=r.replace(n,"******")}),r}function Vr(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ue=class extends Hr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),s=Z(n);o(null,s)}};function Ut(){if(!(process.env.NETLIFY_MASK_LOGS!=="false"))return;let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr);process.stdout.write=function(o,n,s){let i=typeof o=="string"?Z(o):o;return typeof n=="function"?t(i,n):t(i,n,s)},process.stderr.write=function(o,n,s){let i=typeof o=="string"?Z(o):o;return typeof n=="function"?r(i,n):r(i,n,s)}}var Se=null,Gt=e=>(Se&&Se.destroy(),Se=new te({totalAllowedTime:e}),Se),jt=()=>Se;var te=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,o)=>{if(this.isTimeExpired())throw new Error(`${t} stage did not complete in the allowed time. Time has already expired.`);let n=this.onTimesUp(()=>{throw new Error(`${t} stage did not complete in the allowed time.`)}),s=null,i=null;o!==void 0&&(i=new Promise((a,l)=>{s=setTimeout(()=>{l(new Error(`${t} stage exceeded its maximum duration of ${o}ms`))},o)}));try{return i?await Promise.race([r(),i]):await r()}finally{n(),s&&clearTimeout(s)}};this.startTime=Date.now(),this.totalAllowedTime=t,this.globalTimeoutId=null,this.subscribers=[],this.hasTimedOut=!1,this.setupGlobalTimeout()}getElapsedTime(){return Date.now()-this.startTime}getRemainingTime(){let t=this.getElapsedTime(),r=this.totalAllowedTime-t;return Math.max(0,r)}isTimeExpired(){return this.getRemainingTime()===0||this.hasTimedOut}setupGlobalTimeout(){this.globalTimeoutId&&clearTimeout(this.globalTimeoutId),this.globalTimeoutId=setTimeout(()=>{this.notifyTimeUp()},this.totalAllowedTime)}notifyTimeUp(){this.hasTimedOut=!0;for(let t=this.subscribers.length-1;t>=0;t--)try{this.subscribers[t]()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}}onTimesUp(t){if(this.subscribers.push(t),this.hasTimedOut)try{t()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}return()=>{let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}}off(t){let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}clearSubscribers(){this.subscribers.length=0}getSubscriberCount(){return this.subscribers.length}destroy(){this.globalTimeoutId&&(clearTimeout(this.globalTimeoutId),this.globalTimeoutId=null),this.clearSubscribers()}static{this.timeUnits={seconds:t=>t*1e3,minutes:t=>t*60*1e3,hours:t=>t*60*60*1e3}}};var Yt="netlify-agent-runner-context.md",ot="task-history",V=".netlify",oe="results.md",it="assets";var ie=1800*1e3,E={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var Bt={name:"@netlify/agent-runner-cli",type:"module",version:"1.75.0",description:"CLI tool for running Netlify agents",main:"./dist/index.js",types:"./dist/index.d.ts",exports:"./dist/index.js",bin:{"agent-runner-cli":"./dist/bin.js","agent-runner-cli-local":"./dist/bin-local.js"},files:["dist/**/*.js","dist/**/*.d.ts","dist/skills/**","patches","scripts"],scripts:{build:"tsup",dev:"tsup --watch",prepare:"husky install node_modules/@netlify/eslint-config-node/.husky/",prepublishOnly:"npm ci && npm test",prepack:"npm run build",test:"run-s build format test:dev",format:"run-s build format:check-fix:*","format:ci":"run-s build format:check:*","format:check-fix:lint":"run-e format:check:lint format:fix:lint","format:check:lint":"cross-env-shell eslint $npm_package_config_eslint","format:fix:lint":"cross-env-shell eslint --fix $npm_package_config_eslint","format:check-fix:prettier":"run-e format:check:prettier format:fix:prettier","format:check:prettier":"cross-env-shell prettier --check $npm_package_config_prettier","format:fix:prettier":"cross-env-shell prettier --write $npm_package_config_prettier","test:dev":"run-s build test:dev:*","test:ci":"run-s build test:ci:*","test:dev:vitest":"LOG=0 vitest --exclude '**/integration/**'","test:ci:vitest":"LOG=0 c8 -r lcovonly -r text -r json vitest --exclude '**/integration/**'","test:integration":"vitest run test/integration/","test:integration:codex":"vitest run test/integration/codex.test.ts","test:integration:claude":"vitest run test/integration/claude.test.ts","test:integration:gemini":"vitest run test/integration/gemini.test.ts","test:integration:create-stage":"vitest run test/integration/create.test.ts",postinstall:"node scripts/postinstall.js"},config:{eslint:'--cache --format=codeframe --max-warnings=0 "{src,scripts,test,.github}/**/*.{js,ts,md,html}"',prettier:'--ignore-path .gitignore --loglevel=warn "{src,scripts,test,.github}/**/*.{js,ts,md,yml,json,html}" "*.{js,ts,yml,json,html}" ".*.{js,ts,yml,json,html}" "!**/package-lock.json" "!package-lock.json" "!src/skills/**/*.md"'},keywords:[],license:"MIT",repository:"netlify/agent-runner-cli",bugs:{url:"https://github.com/netlify/agent-runner-cli/issues"},author:"Netlify Inc.",directories:{test:"test"},devDependencies:{"@commitlint/cli":"^20.0.0","@commitlint/config-conventional":"^20.0.0","@eslint/compat":"^2.0.0","@eslint/js":"^9.35.0","@netlify/eslint-config-node":"^7.0.1","@types/node":"^24.5.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/eslint-plugin":"^1.6.6",c8:"^10.0.0","eslint-config-prettier":"^10.1.8","eslint-plugin-n":"^17.0.0",husky:"^9.0.0","patch-package":"^8.0.0",tsup:"^8.5.0",typescript:"^5.0.0","typescript-eslint":"^8.44.0",vitest:"^4.0.16"},dependencies:{"@anthropic-ai/claude-code":"2.1.47","@anthropic-ai/sdk":"0.77.0","@google/gemini-cli":"0.29.3","@netlify/otel":"^5.1.1","@openai/codex":"0.104.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.5.0",minimist:"^1.2.8",openai:"6.22.0"}};var en=Xr(import.meta.url),tn=Q.dirname(en),rn=Zr(import.meta.url),de=T("shell"),st=new Set,nn={preferLocal:!0},S=(e,t,r)=>{let[o,n]=on(t,r),s={...nn,...n},i=Qr(e,o,s);sn(i,s),ln(i);let a=r?.idleTimeout;return a&&a>0&&an(i,a),i};var on=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},sn=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(z.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new ue).pipe(z.stdout),e.stdout?.pipe(new ue).pipe(z.stdout),e.stderr?.pipe(new ue).pipe(z.stderr);return}e.stdout?.pipe(z.stdout),e.stderr?.pipe(z.stderr)},at=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(z.kill(-e.pid,t),de.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return de.error("Error killing process:",r),!1}},qt=e=>at(e,"SIGKILL"),an=(e,t)=>{let r=null,o=()=>{de.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),at(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(de.log(`Force killing idle process ${e.pid}`),qt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(o,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let s=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",s),e.on("error",s)},ln=e=>{st.add(e);let t=jt();if(t){let r=t.onTimesUp(()=>{de.log(`Global timer expired, killing process ${e.pid}`),at(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(de.log(`Force killing process ${e.pid} after timeout`),qt(e))},5e3)});e.on("exit",()=>{st.delete(e),r()}),e.on("error",()=>{st.delete(e),r()})}};function Ue(e,t){return!!ee(e,t)}function ee(e,t){if(!z.env.NETLIFY_LOCAL_MODE)try{let n=rn.resolve(Bt.name),s=Q.dirname(n);for(;s!==Q.dirname(s);){let i=Q.dirname(s);if(Q.basename(i)==="node_modules"){let a=Q.join(i,".bin",t);if(Me.existsSync(a))return a;break}s=i}}catch(n){console.error("Could not resolve package.json",n)}if(z.env.NODE_PATH){let n=Q.join(z.env.NODE_PATH,".bin",t);if(Me.existsSync(n))return n}let r=Q.join(e,"node_modules",".bin",t);if(Me.existsSync(r))return r;let o=Q.join(tn,"..","node_modules",".bin",t);if(Me.existsSync(o))return o}var cn=T("utils"),un=e=>new Promise(t=>{setTimeout(t,e)}),Ht=(e,t=3e3)=>{let r=!1,o=null,n=[],s=null,i=(...a)=>{if(r)return o=a,new Promise(p=>{n.push(p)});r=!0;let l,u=new Promise(p=>{l=p});return s=(async()=>{await Promise.resolve();let p=await e(...a);for(l(p);;){if(await un(t),!o)return r=!1,s=null,p;let d=o,m=n;o=null,n=[],p=await e(...d),m.forEach(h=>{h(p)})}})(),u};return i.flush=async()=>{if((r||o)&&s)return await s,i.flush()},i},pe=(e,t,r=!1)=>{let o=null,n=null,s=null,i=function(...a){n=a,s=this;let l=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(s,n),n=null,s=null)},t),l&&(e.apply(s,n),n=null,s=null)};return i.cancel=()=>{clearTimeout(o),o=null,n=null,s=null},i.flush=()=>{if(o){clearTimeout(o);let a=n,l=s;o=null,n=null,s=null,e.apply(l,a)}},i},Wt=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):cn.error("Could not parse JSON",o))}},Ge=e=>e.charAt(0).toUpperCase()+e.slice(1),Kt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),Jt=(e,t)=>{let n=".netlify.app",s="agent-";if(!t)return`${s}${e.slice(0,6)}`;let a=`--${t}${n}`;if(a.length>55)return"";let l=60-a.length;if(l<=0)return"";if(l>=s.length+6){let u=Math.min(l-s.length,e.length);return`${s}${e.slice(0,u)}`}return e.slice(0,l)};var dn=50*1024,lt=(e,t=dn)=>{if(!e||typeof e!="string"||e.length<=t)return e;let o=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+o};import{Buffer as Vt}from"buffer";import pn from"path";var zt=T("repo"),Zt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{zt.info("Getting runner diffs");let o=await gn(r),{hasChanges:n}=o,{status:s}=o;if(!n)return{hasChanges:!1};if(!t){let _=hn(s);await yn(_,r)}zt.info("Changes after processing"),await ut(r);let i=await dt(s,r);if(await ct(i,r),n=await fn(r),!n)return{hasChanges:!1,ignored:i};process.env.NETLIFY_INTERNAL_GIT="1";try{await S("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},l=await S("git",["diff",e.runSha,"HEAD"],a),u=String(l.stdout??"");if(n=!!u,!n)return await Xt(r),{hasChanges:!1,ignored:i};let p=await S("git",["diff",e.runSha,"HEAD","--binary"],a),d=String(p.stdout??""),m,h;if(e.sha){let _=await S("git",["diff",e.sha,"HEAD"],a);m=String(_.stdout??"");let I=await S("git",["diff",e.sha,"HEAD","--binary"],a),w=String(I.stdout??"");m!==w&&(h=Vt.from(w).toString("base64"))}await Xt(r);let y={hasChanges:!0,diff:u,resultDiff:m,ignored:i};return u!==d&&(y.diffBinary=Vt.from(d).toString("base64")),h&&(y.resultDiffBinary=h),y},Xt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await S("git",["reset","--soft","HEAD~1"],{cwd:e})},ct=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await S("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},ut=async(e=process.cwd())=>{let t=await S("git",["status","-s"],{cwd:e});return String(t.stdout??"")},Qt=/.. (.+)?\.log$/,mn=[Qt],gn=async(e=process.cwd())=>{let t=await ut(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
9
9
|
`).filter(n=>mn.some(i=>i instanceof RegExp?i.test(n):n===i)?!1:n[1]?.trim()!=="")).length!==0,status:t}},fn=async(e=process.cwd())=>{try{return await S("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},ve=async(e=process.cwd())=>{let{stdout:t}=await S("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},er=async(e=process.cwd())=>{let{stdout:t}=await S("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},dt=async(e,t=process.cwd())=>{e||=await ut(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build","CLAUDE.local.md"],o=[];return e.split(`
|
|
10
10
|
`).forEach(n=>{r.forEach(i=>{let a=n===`?? ${i}`,l=n.startsWith(`?? ${i}/`)||n.startsWith(`?? ${i}${pn.sep}`);(a||l)&&o.push(`:!${i}`)});let s=n.match(Qt)?.[1];s&&o.push(`:!${s}.log`)}),o},pt=async(e=process.cwd())=>{await S("git",["reset","--hard","HEAD"],{cwd:e})},hn=e=>{let t=e.split(`
|
|
11
11
|
`).reduce((r,o)=>{if(!o)return r;let[n,s,,...i]=o,a=i.join(""),l=n.trim(),u=s.trim();return r[a]?r[a].change=u:r[a]={filePath:a,stage:l,change:u},r},{});return Object.values(t)},yn=async(e,t=process.cwd())=>{let r=e.filter(o=>o.stage&&!o.change).map(o=>o.filePath);r.length!==0&&await S("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
|
package/dist/bin.js
CHANGED
|
@@ -5,7 +5,7 @@ import vt from"process";import bo from"minimist";import{createRequire as _o}from
|
|
|
5
5
|
${s}
|
|
6
6
|
</extracted_error_chunk>`).join(`
|
|
7
7
|
|
|
8
|
-
`);return i.length>e.length*.8?e:i}import{execSync as Gn}from"child_process";import Ir from"fs/promises";import jn from"path";import te from"process";import{getTracer as Yn}from"@netlify/otel";import Te from"process";var ie=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},Ot=e=>e instanceof ie;var Oe=Te.env.NETLIFY_API_URL,Fe=Te.env.NETLIFY_API_TOKEN,W=T("api"),Le=()=>Te.env.NETLIFY_LOCAL_MODE==="true",xe=async(e,t={})=>{if(!Oe||!Fe)throw new Error("No API URL or token");let r=new URL(e,Oe),o={...t,headers:{...t.headers,Authorization:`Bearer ${Fe}`}};Te.env.AGENT_RUNNERS_DEBUG==="true"&&(o.headers["x-nf-debug-logging"]="true"),t.json&&(o.headers||={},o.headers["Content-Type"]="application/json",o.body=JSON.stringify(t.json));let n=await fetch(r,o),i=n.ok&&n.status<=299;if(Te.env.AGENT_RUNNERS_DEBUG==="true")W.log(`Response headers for ${r}:`),n.headers.forEach((a,l)=>{W.log(` ${l}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");W.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||W.error(`Got status ${n.status} for request ${r}`),t.raw){if(!i)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let s=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let a=typeof s=="string"?s:JSON.stringify(s);throw n.status===404?new ie(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new ie(`API request failed: 403 - ${a}`,403,"Credit limit reached. Please add more credits to continue using Agent Runners."):new Error(`API request failed: ${n.status} - ${a}`)}return s},Ft=e=>{W.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Oe=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Fe=e.constants.NETLIFY_API_TOKEN)},Lt=()=>({apiUrl:Oe,token:Fe}),Re=async(e,t)=>Le()?(W.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):xe(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),j=async(e,t,r)=>Le()?(W.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var $t=async(e,t)=>Le()?(W.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`),Dt=(e,t,r)=>xe(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),Mt=async(e,t)=>Le()?(W.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):xe(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),et=async(e,t)=>{W.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ae=T("ai_gateway"),tt=null;var Ut=async()=>{if(tt)return tt;ae.log("Fetching available AI gateway providers");let e=await fetch(`${Lt().apiUrl}/api/v1/ai-gateway/providers`);if(!e.ok)throw new Error(`Failed to fetch AI gateway providers: ${e.statusText}`);let t=await e.json();return tt=t,ae.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},zr=async(e,t)=>{let o=(await Ut()).providers[e];if(!o)return ae.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return ae.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Gt=async({netlify:e,config:t})=>{let r,o,n,i,s=e.constants?.SITE_ID;if(!s)throw new Error("No site id");let a=async()=>{clearTimeout(n),ae.log("Requesting AI gateway information");let l=await Dt(s,t.id,t.sessionId);if({token:r,url:i}=l,o=l.expires_at?l.expires_at*1e3:void 0,ae.log("Got AI gateway information",{token:!!r,expiresAt:o,url:i}),o){let u=o-Date.now()-6e4;u>0&&(n=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Ut()]),{get url(){return i},get token(){return r},isModelAvailableForProvider:zr}};import V from"process";import X from"path";import $e from"fs";import{fileURLToPath as nn}from"url";import{createRequire as on}from"module";import{execa as sn,execaCommand as as}from"execa";import{Transform as Xr}from"stream";var Zr=new Set(["NODE_ENV","PATH","HOME","USER","USERNAME","SHELL","PWD","OLDPWD","TMPDIR","TMP","TEMP","LANG","TERM","EDITOR","PAGER","OS","PROCESSOR_ARCHITECTURE","PROCESSOR_IDENTIFIER","SYSTEMROOT","WINDIR","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","APPDATA","LOCALAPPDATA","NODE_OPTIONS","NODE_PATH","NODE_DEBUG","NODE_NO_WARNINGS","npm_config_registry","npm_config_cache","npm_execpath","npm_node_execpath","CI","GITHUB_ACTIONS","GITHUB_WORKSPACE","GITHUB_REPOSITORY","GITHUB_REF","BUILDKITE","BUILDKITE_BRANCH","BUILDKITE_COMMIT","BUILDKITE_BUILD_NUMBER","JENKINS_URL","TRAVIS","CIRCLECI","DISPLAY","COLORTERM","TERM_PROGRAM","TERM_PROGRAM_VERSION","COLUMNS","LINES","HISTSIZE","HISTFILE","NETLIFY_AGENT_RUNNER_ID","NETLIFY_AGENT_RUNNER_SESSION_ID","NETLIFY_AGENT_RUNNER_PROMPT","NETLIFY_AGENT_RUNNER_AGENT","NETLIFY_AGENT_RUNNER_MODEL","NETLIFY_AGENT_RUNNER_CONTEXT","NETLIFY_AGENT_RUNNER_HAS_REPO","NETLIFY_FF_AGENT_RUNNER_BYOK_ENABLED","NETLIFY_AGENT_RUNNER_SHA","NETLIFY_TEAM_TYPE","AGENT_RUNNERS_DEBUG","NETLIFY_TEAM_ID","NETLIFY_AGENT_RUNNER_USER_ID","SITE_NAME"]),Qr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function en(){return Object.entries(process.env).filter(([e,t])=>!(!t||Zr.has(e)||Qr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function z(e){if(typeof e!="string")return e;let t=en();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(tn(o),"g");r=r.replace(n,"******")}),r}function tn(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var le=class extends Xr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=z(n);o(null,i)}};function jt(){if(!(process.env.NETLIFY_MASK_LOGS!=="false"))return;let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr);process.stdout.write=function(o,n,i){let s=typeof o=="string"?z(o):o;return typeof n=="function"?t(s,n):t(s,n,i)},process.stderr.write=function(o,n,i){let s=typeof o=="string"?z(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var Ie=null,Yt=e=>(Ie&&Ie.destroy(),Ie=new Z({totalAllowedTime:e}),Ie),Bt=()=>Ie;var Z=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,o)=>{if(this.isTimeExpired())throw new Error(`${t} stage did not complete in the allowed time. Time has already expired.`);let n=this.onTimesUp(()=>{throw new Error(`${t} stage did not complete in the allowed time.`)}),i=null,s=null;o!==void 0&&(s=new Promise((a,l)=>{i=setTimeout(()=>{l(new Error(`${t} stage exceeded its maximum duration of ${o}ms`))},o)}));try{return s?await Promise.race([r(),s]):await r()}finally{n(),i&&clearTimeout(i)}};this.startTime=Date.now(),this.totalAllowedTime=t,this.globalTimeoutId=null,this.subscribers=[],this.hasTimedOut=!1,this.setupGlobalTimeout()}getElapsedTime(){return Date.now()-this.startTime}getRemainingTime(){let t=this.getElapsedTime(),r=this.totalAllowedTime-t;return Math.max(0,r)}isTimeExpired(){return this.getRemainingTime()===0||this.hasTimedOut}setupGlobalTimeout(){this.globalTimeoutId&&clearTimeout(this.globalTimeoutId),this.globalTimeoutId=setTimeout(()=>{this.notifyTimeUp()},this.totalAllowedTime)}notifyTimeUp(){this.hasTimedOut=!0;for(let t=this.subscribers.length-1;t>=0;t--)try{this.subscribers[t]()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}}onTimesUp(t){if(this.subscribers.push(t),this.hasTimedOut)try{t()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}return()=>{let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}}off(t){let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}clearSubscribers(){this.subscribers.length=0}getSubscriberCount(){return this.subscribers.length}destroy(){this.globalTimeoutId&&(clearTimeout(this.globalTimeoutId),this.globalTimeoutId=null),this.clearSubscribers()}static{this.timeUnits={seconds:t=>t*1e3,minutes:t=>t*60*1e3,hours:t=>t*60*60*1e3}}};var Ht="netlify-agent-runner-context.md",rt="task-history",K=".netlify",re="results.md",nt="assets",ot="other",st="personal";var it="enterprise",at="free",qt=[st,"pro",it,at],Wt=["normal","redeploy","create","ask","dtn-prod-iteration","rebase"],Kt="The production deploy has changed since you started working. Please reapply the changes to the current codebase, resolving any conflicts that arise. Use the attached diff file if present, otherwise review the previous session context to reproduce the changes.",ne=1800*1e3,E={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var Vt={name:"@netlify/agent-runner-cli",type:"module",version:"1.75.0-alpha.0",description:"CLI tool for running Netlify agents",main:"./dist/index.js",types:"./dist/index.d.ts",exports:"./dist/index.js",bin:{"agent-runner-cli":"./dist/bin.js","agent-runner-cli-local":"./dist/bin-local.js"},files:["dist/**/*.js","dist/**/*.d.ts","dist/skills/**","patches","scripts"],scripts:{build:"tsup",dev:"tsup --watch",prepare:"husky install node_modules/@netlify/eslint-config-node/.husky/",prepublishOnly:"npm ci && npm test",prepack:"npm run build",test:"run-s build format test:dev",format:"run-s build format:check-fix:*","format:ci":"run-s build format:check:*","format:check-fix:lint":"run-e format:check:lint format:fix:lint","format:check:lint":"cross-env-shell eslint $npm_package_config_eslint","format:fix:lint":"cross-env-shell eslint --fix $npm_package_config_eslint","format:check-fix:prettier":"run-e format:check:prettier format:fix:prettier","format:check:prettier":"cross-env-shell prettier --check $npm_package_config_prettier","format:fix:prettier":"cross-env-shell prettier --write $npm_package_config_prettier","test:dev":"run-s build test:dev:*","test:ci":"run-s build test:ci:*","test:dev:vitest":"LOG=0 vitest --exclude '**/integration/**'","test:ci:vitest":"LOG=0 c8 -r lcovonly -r text -r json vitest --exclude '**/integration/**'","test:integration":"vitest run test/integration/","test:integration:codex":"vitest run test/integration/codex.test.ts","test:integration:claude":"vitest run test/integration/claude.test.ts","test:integration:gemini":"vitest run test/integration/gemini.test.ts","test:integration:create-stage":"vitest run test/integration/create.test.ts",postinstall:"node scripts/postinstall.js"},config:{eslint:'--cache --format=codeframe --max-warnings=0 "{src,scripts,test,.github}/**/*.{js,ts,md,html}"',prettier:'--ignore-path .gitignore --loglevel=warn "{src,scripts,test,.github}/**/*.{js,ts,md,yml,json,html}" "*.{js,ts,yml,json,html}" ".*.{js,ts,yml,json,html}" "!**/package-lock.json" "!package-lock.json" "!src/skills/**/*.md"'},keywords:[],license:"MIT",repository:"netlify/agent-runner-cli",bugs:{url:"https://github.com/netlify/agent-runner-cli/issues"},author:"Netlify Inc.",directories:{test:"test"},devDependencies:{"@commitlint/cli":"^20.0.0","@commitlint/config-conventional":"^20.0.0","@eslint/compat":"^2.0.0","@eslint/js":"^9.35.0","@netlify/eslint-config-node":"^7.0.1","@types/node":"^24.5.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/eslint-plugin":"^1.6.6",c8:"^10.0.0","eslint-config-prettier":"^10.1.8","eslint-plugin-n":"^17.0.0",husky:"^9.0.0","patch-package":"^8.0.0",tsup:"^8.5.0",typescript:"^5.0.0","typescript-eslint":"^8.44.0",vitest:"^4.0.16"},dependencies:{"@anthropic-ai/claude-code":"2.1.47","@anthropic-ai/sdk":"0.77.0","@google/gemini-cli":"0.29.3","@netlify/otel":"^5.1.1","@openai/codex":"0.104.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.5.0",minimist:"^1.2.8",openai:"6.22.0"}};var an=nn(import.meta.url),ln=X.dirname(an),cn=on(import.meta.url),ce=T("shell"),lt=new Set,un={preferLocal:!0},b=(e,t,r)=>{let[o,n]=pn(t,r),i={...un,...n},s=sn(e,o,i);dn(s,i),gn(s);let a=r?.idleTimeout;return a&&a>0&&mn(s,a),s};var pn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},dn=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(V.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new le).pipe(V.stdout),e.stdout?.pipe(new le).pipe(V.stdout),e.stderr?.pipe(new le).pipe(V.stderr);return}e.stdout?.pipe(V.stdout),e.stderr?.pipe(V.stderr)},ct=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(V.kill(-e.pid,t),ce.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ce.error("Error killing process:",r),!1}},Jt=e=>ct(e,"SIGKILL"),mn=(e,t)=>{let r=null,o=()=>{ce.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),ct(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ce.log(`Force killing idle process ${e.pid}`),Jt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(o,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let i=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",i),e.on("error",i)},gn=e=>{lt.add(e);let t=Bt();if(t){let r=t.onTimesUp(()=>{ce.log(`Global timer expired, killing process ${e.pid}`),ct(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ce.log(`Force killing process ${e.pid} after timeout`),Jt(e))},5e3)});e.on("exit",()=>{lt.delete(e),r()}),e.on("error",()=>{lt.delete(e),r()})}};function Q(e,t){if(!V.env.NETLIFY_LOCAL_MODE)try{let n=cn.resolve(Vt.name),i=X.dirname(n);for(;i!==X.dirname(i);){let s=X.dirname(i);if(X.basename(s)==="node_modules"){let a=X.join(s,".bin",t);if($e.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(V.env.NODE_PATH){let n=X.join(V.env.NODE_PATH,".bin",t);if($e.existsSync(n))return n}let r=X.join(e,"node_modules",".bin",t);if($e.existsSync(r))return r;let o=X.join(ln,"..","node_modules",".bin",t);if($e.existsSync(o))return o}var zt=T("utils"),fn=e=>new Promise(t=>{setTimeout(t,e)}),Xt=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(d=>{n.push(d)});r=!0;let l,u=new Promise(d=>{l=d});return i=(async()=>{await Promise.resolve();let d=await e(...a);for(l(d);;){if(await fn(t),!o)return r=!1,i=null,d;let p=o,m=n;o=null,n=[],d=await e(...p),m.forEach(h=>{h(d)})}})(),u};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},ue=(e,t,r=!1)=>{let o=null,n=null,i=null,s=function(...a){n=a,i=this;let l=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(i,n),n=null,i=null)},t),l&&(e.apply(i,n),n=null,i=null)};return s.cancel=()=>{clearTimeout(o),o=null,n=null,i=null},s.flush=()=>{if(o){clearTimeout(o);let a=n,l=i;o=null,n=null,i=null,e.apply(l,a)}},s},De=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):zt.error("Could not parse JSON",o))}},Me=e=>e.charAt(0).toUpperCase()+e.slice(1),Zt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),Qt=(e,t)=>{let n=".netlify.app",i="agent-";if(!t)return`${i}${e.slice(0,6)}`;let a=`--${t}${n}`;if(a.length>55)return"";let l=60-a.length;if(l<=0)return"";if(l>=i.length+6){let u=Math.min(l-i.length,e.length);return`${i}${e.slice(0,u)}`}return e.slice(0,l)},hn=e=>!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).length===0?!1:!!qt.some(t=>t in e),er=()=>{let e={},t={codex:process.env.NETLIFY_FF_AGENT_RUNNER_CODEX_VERSION,claude:process.env.NETLIFY_FF_AGENT_RUNNER_CLAUDE_VERSION,gemini:process.env.NETLIFY_FF_AGENT_RUNNER_GEMINI_VERSION};return Object.entries(t).forEach(([r,o])=>{if(o){let n=`NETLIFY_FF_AGENT_RUNNER_${r.toUpperCase()}_VERSION`;try{let i=JSON.parse(o);hn(i)&&(e[r]=i)}catch(i){let a=i instanceof SyntaxError?"Invalid JSON":i.message;zt.error(`Could not parse ${r} model version override from ${n}: ${a}`)}}}),e},yn=50*1024,ut=(e,t=yn)=>{if(!e||typeof e!="string"||e.length<=t)return e;let o=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+o};import{Buffer as tr}from"buffer";import En from"path";var rr=T("repo"),or=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{rr.info("Getting runner diffs");let o=await wn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let _=xn(i);await Rn(_,r)}rr.info("Changes after processing"),await dt(r);let s=await gt(i,r);if(await pt(s,r),n=await Tn(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await b("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},l=await b("git",["diff",e.runSha,"HEAD"],a),u=String(l.stdout??"");if(n=!!u,!n)return await nr(r),{hasChanges:!1,ignored:s};let d=await b("git",["diff",e.runSha,"HEAD","--binary"],a),p=String(d.stdout??""),m,h;if(e.sha){let _=await b("git",["diff",e.sha,"HEAD"],a);m=String(_.stdout??"");let x=await b("git",["diff",e.sha,"HEAD","--binary"],a),w=String(x.stdout??"");m!==w&&(h=tr.from(w).toString("base64"))}await nr(r);let y={hasChanges:!0,diff:u,resultDiff:m,ignored:s};return u!==p&&(y.diffBinary=tr.from(p).toString("base64")),h&&(y.resultDiffBinary=h),y},nr=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await b("git",["reset","--soft","HEAD~1"],{cwd:e})},pt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await b("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},dt=async(e=process.cwd())=>{let t=await b("git",["status","-s"],{cwd:e});return String(t.stdout??"")},sr=/.. (.+)?\.log$/,_n=[sr],wn=async(e=process.cwd())=>{let t=await dt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
8
|
+
`);return i.length>e.length*.8?e:i}import{execSync as Gn}from"child_process";import Ir from"fs/promises";import jn from"path";import te from"process";import{getTracer as Yn}from"@netlify/otel";import Te from"process";var ie=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},Ot=e=>e instanceof ie;var Oe=Te.env.NETLIFY_API_URL,Fe=Te.env.NETLIFY_API_TOKEN,W=T("api"),Le=()=>Te.env.NETLIFY_LOCAL_MODE==="true",xe=async(e,t={})=>{if(!Oe||!Fe)throw new Error("No API URL or token");let r=new URL(e,Oe),o={...t,headers:{...t.headers,Authorization:`Bearer ${Fe}`}};Te.env.AGENT_RUNNERS_DEBUG==="true"&&(o.headers["x-nf-debug-logging"]="true"),t.json&&(o.headers||={},o.headers["Content-Type"]="application/json",o.body=JSON.stringify(t.json));let n=await fetch(r,o),i=n.ok&&n.status<=299;if(Te.env.AGENT_RUNNERS_DEBUG==="true")W.log(`Response headers for ${r}:`),n.headers.forEach((a,l)=>{W.log(` ${l}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");W.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||W.error(`Got status ${n.status} for request ${r}`),t.raw){if(!i)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let s=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let a=typeof s=="string"?s:JSON.stringify(s);throw n.status===404?new ie(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new ie(`API request failed: 403 - ${a}`,403,"Credit limit reached. Please add more credits to continue using Agent Runners."):new Error(`API request failed: ${n.status} - ${a}`)}return s},Ft=e=>{W.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Oe=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Fe=e.constants.NETLIFY_API_TOKEN)},Lt=()=>({apiUrl:Oe,token:Fe}),Re=async(e,t)=>Le()?(W.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):xe(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),j=async(e,t,r)=>Le()?(W.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var $t=async(e,t)=>Le()?(W.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`),Dt=(e,t,r)=>xe(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),Mt=async(e,t)=>Le()?(W.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):xe(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),et=async(e,t)=>{W.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ae=T("ai_gateway"),tt=null;var Ut=async()=>{if(tt)return tt;ae.log("Fetching available AI gateway providers");let e=await fetch(`${Lt().apiUrl}/api/v1/ai-gateway/providers`);if(!e.ok)throw new Error(`Failed to fetch AI gateway providers: ${e.statusText}`);let t=await e.json();return tt=t,ae.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},zr=async(e,t)=>{let o=(await Ut()).providers[e];if(!o)return ae.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return ae.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Gt=async({netlify:e,config:t})=>{let r,o,n,i,s=e.constants?.SITE_ID;if(!s)throw new Error("No site id");let a=async()=>{clearTimeout(n),ae.log("Requesting AI gateway information");let l=await Dt(s,t.id,t.sessionId);if({token:r,url:i}=l,o=l.expires_at?l.expires_at*1e3:void 0,ae.log("Got AI gateway information",{token:!!r,expiresAt:o,url:i}),o){let u=o-Date.now()-6e4;u>0&&(n=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Ut()]),{get url(){return i},get token(){return r},isModelAvailableForProvider:zr}};import V from"process";import X from"path";import $e from"fs";import{fileURLToPath as nn}from"url";import{createRequire as on}from"module";import{execa as sn,execaCommand as as}from"execa";import{Transform as Xr}from"stream";var Zr=new Set(["NODE_ENV","PATH","HOME","USER","USERNAME","SHELL","PWD","OLDPWD","TMPDIR","TMP","TEMP","LANG","TERM","EDITOR","PAGER","OS","PROCESSOR_ARCHITECTURE","PROCESSOR_IDENTIFIER","SYSTEMROOT","WINDIR","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","APPDATA","LOCALAPPDATA","NODE_OPTIONS","NODE_PATH","NODE_DEBUG","NODE_NO_WARNINGS","npm_config_registry","npm_config_cache","npm_execpath","npm_node_execpath","CI","GITHUB_ACTIONS","GITHUB_WORKSPACE","GITHUB_REPOSITORY","GITHUB_REF","BUILDKITE","BUILDKITE_BRANCH","BUILDKITE_COMMIT","BUILDKITE_BUILD_NUMBER","JENKINS_URL","TRAVIS","CIRCLECI","DISPLAY","COLORTERM","TERM_PROGRAM","TERM_PROGRAM_VERSION","COLUMNS","LINES","HISTSIZE","HISTFILE","NETLIFY_AGENT_RUNNER_ID","NETLIFY_AGENT_RUNNER_SESSION_ID","NETLIFY_AGENT_RUNNER_PROMPT","NETLIFY_AGENT_RUNNER_AGENT","NETLIFY_AGENT_RUNNER_MODEL","NETLIFY_AGENT_RUNNER_CONTEXT","NETLIFY_AGENT_RUNNER_HAS_REPO","NETLIFY_FF_AGENT_RUNNER_BYOK_ENABLED","NETLIFY_AGENT_RUNNER_SHA","NETLIFY_TEAM_TYPE","AGENT_RUNNERS_DEBUG","NETLIFY_TEAM_ID","NETLIFY_AGENT_RUNNER_USER_ID","SITE_NAME"]),Qr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function en(){return Object.entries(process.env).filter(([e,t])=>!(!t||Zr.has(e)||Qr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function z(e){if(typeof e!="string")return e;let t=en();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(tn(o),"g");r=r.replace(n,"******")}),r}function tn(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var le=class extends Xr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=z(n);o(null,i)}};function jt(){if(!(process.env.NETLIFY_MASK_LOGS!=="false"))return;let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr);process.stdout.write=function(o,n,i){let s=typeof o=="string"?z(o):o;return typeof n=="function"?t(s,n):t(s,n,i)},process.stderr.write=function(o,n,i){let s=typeof o=="string"?z(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var Ie=null,Yt=e=>(Ie&&Ie.destroy(),Ie=new Z({totalAllowedTime:e}),Ie),Bt=()=>Ie;var Z=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,o)=>{if(this.isTimeExpired())throw new Error(`${t} stage did not complete in the allowed time. Time has already expired.`);let n=this.onTimesUp(()=>{throw new Error(`${t} stage did not complete in the allowed time.`)}),i=null,s=null;o!==void 0&&(s=new Promise((a,l)=>{i=setTimeout(()=>{l(new Error(`${t} stage exceeded its maximum duration of ${o}ms`))},o)}));try{return s?await Promise.race([r(),s]):await r()}finally{n(),i&&clearTimeout(i)}};this.startTime=Date.now(),this.totalAllowedTime=t,this.globalTimeoutId=null,this.subscribers=[],this.hasTimedOut=!1,this.setupGlobalTimeout()}getElapsedTime(){return Date.now()-this.startTime}getRemainingTime(){let t=this.getElapsedTime(),r=this.totalAllowedTime-t;return Math.max(0,r)}isTimeExpired(){return this.getRemainingTime()===0||this.hasTimedOut}setupGlobalTimeout(){this.globalTimeoutId&&clearTimeout(this.globalTimeoutId),this.globalTimeoutId=setTimeout(()=>{this.notifyTimeUp()},this.totalAllowedTime)}notifyTimeUp(){this.hasTimedOut=!0;for(let t=this.subscribers.length-1;t>=0;t--)try{this.subscribers[t]()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}}onTimesUp(t){if(this.subscribers.push(t),this.hasTimedOut)try{t()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}return()=>{let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}}off(t){let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}clearSubscribers(){this.subscribers.length=0}getSubscriberCount(){return this.subscribers.length}destroy(){this.globalTimeoutId&&(clearTimeout(this.globalTimeoutId),this.globalTimeoutId=null),this.clearSubscribers()}static{this.timeUnits={seconds:t=>t*1e3,minutes:t=>t*60*1e3,hours:t=>t*60*60*1e3}}};var Ht="netlify-agent-runner-context.md",rt="task-history",K=".netlify",re="results.md",nt="assets",ot="other",st="personal";var it="enterprise",at="free",qt=[st,"pro",it,at],Wt=["normal","redeploy","create","ask","dtn-prod-iteration","rebase"],Kt="The production deploy has changed since you started working. Please reapply the changes to the current codebase, resolving any conflicts that arise. Use the attached diff file if present, otherwise review the previous session context to reproduce the changes.",ne=1800*1e3,E={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var Vt={name:"@netlify/agent-runner-cli",type:"module",version:"1.75.0",description:"CLI tool for running Netlify agents",main:"./dist/index.js",types:"./dist/index.d.ts",exports:"./dist/index.js",bin:{"agent-runner-cli":"./dist/bin.js","agent-runner-cli-local":"./dist/bin-local.js"},files:["dist/**/*.js","dist/**/*.d.ts","dist/skills/**","patches","scripts"],scripts:{build:"tsup",dev:"tsup --watch",prepare:"husky install node_modules/@netlify/eslint-config-node/.husky/",prepublishOnly:"npm ci && npm test",prepack:"npm run build",test:"run-s build format test:dev",format:"run-s build format:check-fix:*","format:ci":"run-s build format:check:*","format:check-fix:lint":"run-e format:check:lint format:fix:lint","format:check:lint":"cross-env-shell eslint $npm_package_config_eslint","format:fix:lint":"cross-env-shell eslint --fix $npm_package_config_eslint","format:check-fix:prettier":"run-e format:check:prettier format:fix:prettier","format:check:prettier":"cross-env-shell prettier --check $npm_package_config_prettier","format:fix:prettier":"cross-env-shell prettier --write $npm_package_config_prettier","test:dev":"run-s build test:dev:*","test:ci":"run-s build test:ci:*","test:dev:vitest":"LOG=0 vitest --exclude '**/integration/**'","test:ci:vitest":"LOG=0 c8 -r lcovonly -r text -r json vitest --exclude '**/integration/**'","test:integration":"vitest run test/integration/","test:integration:codex":"vitest run test/integration/codex.test.ts","test:integration:claude":"vitest run test/integration/claude.test.ts","test:integration:gemini":"vitest run test/integration/gemini.test.ts","test:integration:create-stage":"vitest run test/integration/create.test.ts",postinstall:"node scripts/postinstall.js"},config:{eslint:'--cache --format=codeframe --max-warnings=0 "{src,scripts,test,.github}/**/*.{js,ts,md,html}"',prettier:'--ignore-path .gitignore --loglevel=warn "{src,scripts,test,.github}/**/*.{js,ts,md,yml,json,html}" "*.{js,ts,yml,json,html}" ".*.{js,ts,yml,json,html}" "!**/package-lock.json" "!package-lock.json" "!src/skills/**/*.md"'},keywords:[],license:"MIT",repository:"netlify/agent-runner-cli",bugs:{url:"https://github.com/netlify/agent-runner-cli/issues"},author:"Netlify Inc.",directories:{test:"test"},devDependencies:{"@commitlint/cli":"^20.0.0","@commitlint/config-conventional":"^20.0.0","@eslint/compat":"^2.0.0","@eslint/js":"^9.35.0","@netlify/eslint-config-node":"^7.0.1","@types/node":"^24.5.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/eslint-plugin":"^1.6.6",c8:"^10.0.0","eslint-config-prettier":"^10.1.8","eslint-plugin-n":"^17.0.0",husky:"^9.0.0","patch-package":"^8.0.0",tsup:"^8.5.0",typescript:"^5.0.0","typescript-eslint":"^8.44.0",vitest:"^4.0.16"},dependencies:{"@anthropic-ai/claude-code":"2.1.47","@anthropic-ai/sdk":"0.77.0","@google/gemini-cli":"0.29.3","@netlify/otel":"^5.1.1","@openai/codex":"0.104.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.5.0",minimist:"^1.2.8",openai:"6.22.0"}};var an=nn(import.meta.url),ln=X.dirname(an),cn=on(import.meta.url),ce=T("shell"),lt=new Set,un={preferLocal:!0},b=(e,t,r)=>{let[o,n]=pn(t,r),i={...un,...n},s=sn(e,o,i);dn(s,i),gn(s);let a=r?.idleTimeout;return a&&a>0&&mn(s,a),s};var pn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},dn=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(V.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new le).pipe(V.stdout),e.stdout?.pipe(new le).pipe(V.stdout),e.stderr?.pipe(new le).pipe(V.stderr);return}e.stdout?.pipe(V.stdout),e.stderr?.pipe(V.stderr)},ct=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(V.kill(-e.pid,t),ce.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ce.error("Error killing process:",r),!1}},Jt=e=>ct(e,"SIGKILL"),mn=(e,t)=>{let r=null,o=()=>{ce.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),ct(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ce.log(`Force killing idle process ${e.pid}`),Jt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(o,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let i=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",i),e.on("error",i)},gn=e=>{lt.add(e);let t=Bt();if(t){let r=t.onTimesUp(()=>{ce.log(`Global timer expired, killing process ${e.pid}`),ct(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ce.log(`Force killing process ${e.pid} after timeout`),Jt(e))},5e3)});e.on("exit",()=>{lt.delete(e),r()}),e.on("error",()=>{lt.delete(e),r()})}};function Q(e,t){if(!V.env.NETLIFY_LOCAL_MODE)try{let n=cn.resolve(Vt.name),i=X.dirname(n);for(;i!==X.dirname(i);){let s=X.dirname(i);if(X.basename(s)==="node_modules"){let a=X.join(s,".bin",t);if($e.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(V.env.NODE_PATH){let n=X.join(V.env.NODE_PATH,".bin",t);if($e.existsSync(n))return n}let r=X.join(e,"node_modules",".bin",t);if($e.existsSync(r))return r;let o=X.join(ln,"..","node_modules",".bin",t);if($e.existsSync(o))return o}var zt=T("utils"),fn=e=>new Promise(t=>{setTimeout(t,e)}),Xt=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(d=>{n.push(d)});r=!0;let l,u=new Promise(d=>{l=d});return i=(async()=>{await Promise.resolve();let d=await e(...a);for(l(d);;){if(await fn(t),!o)return r=!1,i=null,d;let p=o,m=n;o=null,n=[],d=await e(...p),m.forEach(h=>{h(d)})}})(),u};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},ue=(e,t,r=!1)=>{let o=null,n=null,i=null,s=function(...a){n=a,i=this;let l=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(i,n),n=null,i=null)},t),l&&(e.apply(i,n),n=null,i=null)};return s.cancel=()=>{clearTimeout(o),o=null,n=null,i=null},s.flush=()=>{if(o){clearTimeout(o);let a=n,l=i;o=null,n=null,i=null,e.apply(l,a)}},s},De=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):zt.error("Could not parse JSON",o))}},Me=e=>e.charAt(0).toUpperCase()+e.slice(1),Zt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),Qt=(e,t)=>{let n=".netlify.app",i="agent-";if(!t)return`${i}${e.slice(0,6)}`;let a=`--${t}${n}`;if(a.length>55)return"";let l=60-a.length;if(l<=0)return"";if(l>=i.length+6){let u=Math.min(l-i.length,e.length);return`${i}${e.slice(0,u)}`}return e.slice(0,l)},hn=e=>!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).length===0?!1:!!qt.some(t=>t in e),er=()=>{let e={},t={codex:process.env.NETLIFY_FF_AGENT_RUNNER_CODEX_VERSION,claude:process.env.NETLIFY_FF_AGENT_RUNNER_CLAUDE_VERSION,gemini:process.env.NETLIFY_FF_AGENT_RUNNER_GEMINI_VERSION};return Object.entries(t).forEach(([r,o])=>{if(o){let n=`NETLIFY_FF_AGENT_RUNNER_${r.toUpperCase()}_VERSION`;try{let i=JSON.parse(o);hn(i)&&(e[r]=i)}catch(i){let a=i instanceof SyntaxError?"Invalid JSON":i.message;zt.error(`Could not parse ${r} model version override from ${n}: ${a}`)}}}),e},yn=50*1024,ut=(e,t=yn)=>{if(!e||typeof e!="string"||e.length<=t)return e;let o=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+o};import{Buffer as tr}from"buffer";import En from"path";var rr=T("repo"),or=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{rr.info("Getting runner diffs");let o=await wn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let _=xn(i);await Rn(_,r)}rr.info("Changes after processing"),await dt(r);let s=await gt(i,r);if(await pt(s,r),n=await Tn(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await b("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},l=await b("git",["diff",e.runSha,"HEAD"],a),u=String(l.stdout??"");if(n=!!u,!n)return await nr(r),{hasChanges:!1,ignored:s};let d=await b("git",["diff",e.runSha,"HEAD","--binary"],a),p=String(d.stdout??""),m,h;if(e.sha){let _=await b("git",["diff",e.sha,"HEAD"],a);m=String(_.stdout??"");let x=await b("git",["diff",e.sha,"HEAD","--binary"],a),w=String(x.stdout??"");m!==w&&(h=tr.from(w).toString("base64"))}await nr(r);let y={hasChanges:!0,diff:u,resultDiff:m,ignored:s};return u!==p&&(y.diffBinary=tr.from(p).toString("base64")),h&&(y.resultDiffBinary=h),y},nr=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await b("git",["reset","--soft","HEAD~1"],{cwd:e})},pt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await b("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},dt=async(e=process.cwd())=>{let t=await b("git",["status","-s"],{cwd:e});return String(t.stdout??"")},sr=/.. (.+)?\.log$/,_n=[sr],wn=async(e=process.cwd())=>{let t=await dt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
9
9
|
`).filter(n=>_n.some(s=>s instanceof RegExp?s.test(n):n===s)?!1:n[1]?.trim()!=="")).length!==0,status:t}},Tn=async(e=process.cwd())=>{try{return await b("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},mt=async(e=process.cwd())=>{let{stdout:t}=await b("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},ir=async(e=process.cwd())=>{let{stdout:t}=await b("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},gt=async(e,t=process.cwd())=>{e||=await dt(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build","CLAUDE.local.md"],o=[];return e.split(`
|
|
10
10
|
`).forEach(n=>{r.forEach(s=>{let a=n===`?? ${s}`,l=n.startsWith(`?? ${s}/`)||n.startsWith(`?? ${s}${En.sep}`);(a||l)&&o.push(`:!${s}`)});let i=n.match(sr)?.[1];i&&o.push(`:!${i}.log`)}),o},ft=async(e=process.cwd())=>{await b("git",["reset","--hard","HEAD"],{cwd:e})},xn=e=>{let t=e.split(`
|
|
11
11
|
`).reduce((r,o)=>{if(!o)return r;let[n,i,,...s]=o,a=s.join(""),l=n.trim(),u=i.trim();return r[a]?r[a].change=u:r[a]={filePath:a,stage:l,change:u},r},{});return Object.values(t)},Rn=async(e,t=process.cwd())=>{let r=e.filter(o=>o.stage&&!o.change).map(o=>o.filePath);r.length!==0&&await b("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import{createRequire as ro}from"module";import{createTracerProvider as br}from"@
|
|
|
4
4
|
${s}
|
|
5
5
|
</extracted_error_chunk>`).join(`
|
|
6
6
|
|
|
7
|
-
`);return i.length>e.length*.8?e:i}import{execSync as Rn}from"child_process";import pr from"fs/promises";import Sn from"path";import ee from"process";import{getTracer as vn}from"@netlify/otel";import Ee from"process";var se=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},St=e=>e instanceof se;var Pe=Ee.env.NETLIFY_API_URL,ke=Ee.env.NETLIFY_API_TOKEN,H=T("api"),Oe=()=>Ee.env.NETLIFY_LOCAL_MODE==="true",we=async(e,t={})=>{if(!Pe||!ke)throw new Error("No API URL or token");let r=new URL(e,Pe),o={...t,headers:{...t.headers,Authorization:`Bearer ${ke}`}};Ee.env.AGENT_RUNNERS_DEBUG==="true"&&(o.headers["x-nf-debug-logging"]="true"),t.json&&(o.headers||={},o.headers["Content-Type"]="application/json",o.body=JSON.stringify(t.json));let n=await fetch(r,o),i=n.ok&&n.status<=299;if(Ee.env.AGENT_RUNNERS_DEBUG==="true")H.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{H.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");H.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||H.error(`Got status ${n.status} for request ${r}`),t.raw){if(!i)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let s=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let a=typeof s=="string"?s:JSON.stringify(s);throw n.status===404?new se(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new se(`API request failed: 403 - ${a}`,403,"Credit limit reached. Please add more credits to continue using Agent Runners."):new Error(`API request failed: ${n.status} - ${a}`)}return s},vt=e=>{H.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Pe=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(ke=e.constants.NETLIFY_API_TOKEN)},At=()=>({apiUrl:Pe,token:ke}),Te=async(e,t)=>Oe()?(H.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):we(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),j=async(e,t,r)=>Oe()?(H.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):we(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var bt=async(e,t)=>Oe()?(H.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):we(`/api/v1/agent_runners/${e}/sessions/${t}`),Ct=(e,t,r)=>we(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),Nt=async(e,t)=>Oe()?(H.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):we(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Xe=async(e,t)=>{H.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ie=T("ai_gateway"),Ze=null;var Pt=async()=>{if(Ze)return Ze;ie.log("Fetching available AI gateway providers");let e=await fetch(`${At().apiUrl}/api/v1/ai-gateway/providers`);if(!e.ok)throw new Error(`Failed to fetch AI gateway providers: ${e.statusText}`);let t=await e.json();return Ze=t,ie.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},$r=async(e,t)=>{let o=(await Pt()).providers[e];if(!o)return ie.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return ie.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},kt=async({netlify:e,config:t})=>{let r,o,n,i,s=e.constants?.SITE_ID;if(!s)throw new Error("No site id");let a=async()=>{clearTimeout(n),ie.log("Requesting AI gateway information");let c=await Ct(s,t.id,t.sessionId);if({token:r,url:i}=c,o=c.expires_at?c.expires_at*1e3:void 0,ie.log("Got AI gateway information",{token:!!r,expiresAt:o,url:i}),o){let u=o-Date.now()-6e4;u>0&&(n=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Pt()]),{get url(){return i},get token(){return r},isModelAvailableForProvider:$r}};import K from"process";import z from"path";import $e from"fs";import{fileURLToPath as jr}from"url";import{createRequire as Yr}from"module";import{execa as Br,execaCommand as Do}from"execa";import{Transform as Fr}from"stream";var Lr=new Set(["NODE_ENV","PATH","HOME","USER","USERNAME","SHELL","PWD","OLDPWD","TMPDIR","TMP","TEMP","LANG","TERM","EDITOR","PAGER","OS","PROCESSOR_ARCHITECTURE","PROCESSOR_IDENTIFIER","SYSTEMROOT","WINDIR","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","APPDATA","LOCALAPPDATA","NODE_OPTIONS","NODE_PATH","NODE_DEBUG","NODE_NO_WARNINGS","npm_config_registry","npm_config_cache","npm_execpath","npm_node_execpath","CI","GITHUB_ACTIONS","GITHUB_WORKSPACE","GITHUB_REPOSITORY","GITHUB_REF","BUILDKITE","BUILDKITE_BRANCH","BUILDKITE_COMMIT","BUILDKITE_BUILD_NUMBER","JENKINS_URL","TRAVIS","CIRCLECI","DISPLAY","COLORTERM","TERM_PROGRAM","TERM_PROGRAM_VERSION","COLUMNS","LINES","HISTSIZE","HISTFILE","NETLIFY_AGENT_RUNNER_ID","NETLIFY_AGENT_RUNNER_SESSION_ID","NETLIFY_AGENT_RUNNER_PROMPT","NETLIFY_AGENT_RUNNER_AGENT","NETLIFY_AGENT_RUNNER_MODEL","NETLIFY_AGENT_RUNNER_CONTEXT","NETLIFY_AGENT_RUNNER_HAS_REPO","NETLIFY_FF_AGENT_RUNNER_BYOK_ENABLED","NETLIFY_AGENT_RUNNER_SHA","NETLIFY_TEAM_TYPE","AGENT_RUNNERS_DEBUG","NETLIFY_TEAM_ID","NETLIFY_AGENT_RUNNER_USER_ID","SITE_NAME"]),Dr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function Mr(){return Object.entries(process.env).filter(([e,t])=>!(!t||Lr.has(e)||Dr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function V(e){if(typeof e!="string")return e;let t=Mr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Ur(o),"g");r=r.replace(n,"******")}),r}function Ur(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ae=class extends Fr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=V(n);o(null,i)}};function Ot(){if(!(process.env.NETLIFY_MASK_LOGS!=="false"))return;let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr);process.stdout.write=function(o,n,i){let s=typeof o=="string"?V(o):o;return typeof n=="function"?t(s,n):t(s,n,i)},process.stderr.write=function(o,n,i){let s=typeof o=="string"?V(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var xe=null,$t=e=>(xe&&xe.destroy(),xe=new X({totalAllowedTime:e}),xe),Ft=()=>xe;var X=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,o)=>{if(this.isTimeExpired())throw new Error(`${t} stage did not complete in the allowed time. Time has already expired.`);let n=this.onTimesUp(()=>{throw new Error(`${t} stage did not complete in the allowed time.`)}),i=null,s=null;o!==void 0&&(s=new Promise((a,c)=>{i=setTimeout(()=>{c(new Error(`${t} stage exceeded its maximum duration of ${o}ms`))},o)}));try{return s?await Promise.race([r(),s]):await r()}finally{n(),i&&clearTimeout(i)}};this.startTime=Date.now(),this.totalAllowedTime=t,this.globalTimeoutId=null,this.subscribers=[],this.hasTimedOut=!1,this.setupGlobalTimeout()}getElapsedTime(){return Date.now()-this.startTime}getRemainingTime(){let t=this.getElapsedTime(),r=this.totalAllowedTime-t;return Math.max(0,r)}isTimeExpired(){return this.getRemainingTime()===0||this.hasTimedOut}setupGlobalTimeout(){this.globalTimeoutId&&clearTimeout(this.globalTimeoutId),this.globalTimeoutId=setTimeout(()=>{this.notifyTimeUp()},this.totalAllowedTime)}notifyTimeUp(){this.hasTimedOut=!0;for(let t=this.subscribers.length-1;t>=0;t--)try{this.subscribers[t]()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}}onTimesUp(t){if(this.subscribers.push(t),this.hasTimedOut)try{t()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}return()=>{let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}}off(t){let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}clearSubscribers(){this.subscribers.length=0}getSubscriberCount(){return this.subscribers.length}destroy(){this.globalTimeoutId&&(clearTimeout(this.globalTimeoutId),this.globalTimeoutId=null),this.clearSubscribers()}static{this.timeUnits={seconds:t=>t*1e3,minutes:t=>t*60*1e3,hours:t=>t*60*60*1e3}}};var Lt="netlify-agent-runner-context.md",Qe="task-history",W=".netlify",te="results.md",et="assets";var re=1800*1e3,_={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var Dt={name:"@netlify/agent-runner-cli",type:"module",version:"1.75.0-alpha.0",description:"CLI tool for running Netlify agents",main:"./dist/index.js",types:"./dist/index.d.ts",exports:"./dist/index.js",bin:{"agent-runner-cli":"./dist/bin.js","agent-runner-cli-local":"./dist/bin-local.js"},files:["dist/**/*.js","dist/**/*.d.ts","dist/skills/**","patches","scripts"],scripts:{build:"tsup",dev:"tsup --watch",prepare:"husky install node_modules/@netlify/eslint-config-node/.husky/",prepublishOnly:"npm ci && npm test",prepack:"npm run build",test:"run-s build format test:dev",format:"run-s build format:check-fix:*","format:ci":"run-s build format:check:*","format:check-fix:lint":"run-e format:check:lint format:fix:lint","format:check:lint":"cross-env-shell eslint $npm_package_config_eslint","format:fix:lint":"cross-env-shell eslint --fix $npm_package_config_eslint","format:check-fix:prettier":"run-e format:check:prettier format:fix:prettier","format:check:prettier":"cross-env-shell prettier --check $npm_package_config_prettier","format:fix:prettier":"cross-env-shell prettier --write $npm_package_config_prettier","test:dev":"run-s build test:dev:*","test:ci":"run-s build test:ci:*","test:dev:vitest":"LOG=0 vitest --exclude '**/integration/**'","test:ci:vitest":"LOG=0 c8 -r lcovonly -r text -r json vitest --exclude '**/integration/**'","test:integration":"vitest run test/integration/","test:integration:codex":"vitest run test/integration/codex.test.ts","test:integration:claude":"vitest run test/integration/claude.test.ts","test:integration:gemini":"vitest run test/integration/gemini.test.ts","test:integration:create-stage":"vitest run test/integration/create.test.ts",postinstall:"node scripts/postinstall.js"},config:{eslint:'--cache --format=codeframe --max-warnings=0 "{src,scripts,test,.github}/**/*.{js,ts,md,html}"',prettier:'--ignore-path .gitignore --loglevel=warn "{src,scripts,test,.github}/**/*.{js,ts,md,yml,json,html}" "*.{js,ts,yml,json,html}" ".*.{js,ts,yml,json,html}" "!**/package-lock.json" "!package-lock.json" "!src/skills/**/*.md"'},keywords:[],license:"MIT",repository:"netlify/agent-runner-cli",bugs:{url:"https://github.com/netlify/agent-runner-cli/issues"},author:"Netlify Inc.",directories:{test:"test"},devDependencies:{"@commitlint/cli":"^20.0.0","@commitlint/config-conventional":"^20.0.0","@eslint/compat":"^2.0.0","@eslint/js":"^9.35.0","@netlify/eslint-config-node":"^7.0.1","@types/node":"^24.5.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/eslint-plugin":"^1.6.6",c8:"^10.0.0","eslint-config-prettier":"^10.1.8","eslint-plugin-n":"^17.0.0",husky:"^9.0.0","patch-package":"^8.0.0",tsup:"^8.5.0",typescript:"^5.0.0","typescript-eslint":"^8.44.0",vitest:"^4.0.16"},dependencies:{"@anthropic-ai/claude-code":"2.1.47","@anthropic-ai/sdk":"0.77.0","@google/gemini-cli":"0.29.3","@netlify/otel":"^5.1.1","@openai/codex":"0.104.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.5.0",minimist:"^1.2.8",openai:"6.22.0"}};var qr=jr(import.meta.url),Hr=z.dirname(qr),Wr=Yr(import.meta.url),le=T("shell"),tt=new Set,Kr={preferLocal:!0},C=(e,t,r)=>{let[o,n]=Jr(t,r),i={...Kr,...n},s=Br(e,o,i);Vr(s,i),Xr(s);let a=r?.idleTimeout;return a&&a>0&&zr(s,a),s};var Jr=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},Vr=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(K.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new ae).pipe(K.stdout),e.stdout?.pipe(new ae).pipe(K.stdout),e.stderr?.pipe(new ae).pipe(K.stderr);return}e.stdout?.pipe(K.stdout),e.stderr?.pipe(K.stderr)},rt=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(K.kill(-e.pid,t),le.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return le.error("Error killing process:",r),!1}},Mt=e=>rt(e,"SIGKILL"),zr=(e,t)=>{let r=null,o=()=>{le.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),rt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(le.log(`Force killing idle process ${e.pid}`),Mt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(o,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let i=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",i),e.on("error",i)},Xr=e=>{tt.add(e);let t=Ft();if(t){let r=t.onTimesUp(()=>{le.log(`Global timer expired, killing process ${e.pid}`),rt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(le.log(`Force killing process ${e.pid} after timeout`),Mt(e))},5e3)});e.on("exit",()=>{tt.delete(e),r()}),e.on("error",()=>{tt.delete(e),r()})}};function Z(e,t){if(!K.env.NETLIFY_LOCAL_MODE)try{let n=Wr.resolve(Dt.name),i=z.dirname(n);for(;i!==z.dirname(i);){let s=z.dirname(i);if(z.basename(s)==="node_modules"){let a=z.join(s,".bin",t);if($e.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(K.env.NODE_PATH){let n=z.join(K.env.NODE_PATH,".bin",t);if($e.existsSync(n))return n}let r=z.join(e,"node_modules",".bin",t);if($e.existsSync(r))return r;let o=z.join(Hr,"..","node_modules",".bin",t);if($e.existsSync(o))return o}var Zr=T("utils"),Qr=e=>new Promise(t=>{setTimeout(t,e)}),Ut=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(p=>{n.push(p)});r=!0;let c,u=new Promise(p=>{c=p});return i=(async()=>{await Promise.resolve();let p=await e(...a);for(c(p);;){if(await Qr(t),!o)return r=!1,i=null,p;let d=o,m=n;o=null,n=[],p=await e(...d),m.forEach(h=>{h(p)})}})(),u};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},ce=(e,t,r=!1)=>{let o=null,n=null,i=null,s=function(...a){n=a,i=this;let c=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(i,n),n=null,i=null)},t),c&&(e.apply(i,n),n=null,i=null)};return s.cancel=()=>{clearTimeout(o),o=null,n=null,i=null},s.flush=()=>{if(o){clearTimeout(o);let a=n,c=i;o=null,n=null,i=null,e.apply(c,a)}},s},Gt=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):Zr.error("Could not parse JSON",o))}},Fe=e=>e.charAt(0).toUpperCase()+e.slice(1),jt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),Yt=(e,t)=>{let n=".netlify.app",i="agent-";if(!t)return`${i}${e.slice(0,6)}`;let a=`--${t}${n}`;if(a.length>55)return"";let c=60-a.length;if(c<=0)return"";if(c>=i.length+6){let u=Math.min(c-i.length,e.length);return`${i}${e.slice(0,u)}`}return e.slice(0,c)};var en=50*1024,nt=(e,t=en)=>{if(!e||typeof e!="string"||e.length<=t)return e;let o=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+o};import{Buffer as Bt}from"buffer";import tn from"path";var qt=T("repo"),Wt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{qt.info("Getting runner diffs");let o=await nn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let E=sn(i);await an(E,r)}qt.info("Changes after processing"),await st(r);let s=await at(i,r);if(await ot(s,r),n=await on(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await C("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},c=await C("git",["diff",e.runSha,"HEAD"],a),u=String(c.stdout??"");if(n=!!u,!n)return await Ht(r),{hasChanges:!1,ignored:s};let p=await C("git",["diff",e.runSha,"HEAD","--binary"],a),d=String(p.stdout??""),m,h;if(e.sha){let E=await C("git",["diff",e.sha,"HEAD"],a);m=String(E.stdout??"");let x=await C("git",["diff",e.sha,"HEAD","--binary"],a),w=String(x.stdout??"");m!==w&&(h=Bt.from(w).toString("base64"))}await Ht(r);let y={hasChanges:!0,diff:u,resultDiff:m,ignored:s};return u!==d&&(y.diffBinary=Bt.from(d).toString("base64")),h&&(y.resultDiffBinary=h),y},Ht=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await C("git",["reset","--soft","HEAD~1"],{cwd:e})},ot=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await C("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},st=async(e=process.cwd())=>{let t=await C("git",["status","-s"],{cwd:e});return String(t.stdout??"")},Kt=/.. (.+)?\.log$/,rn=[Kt],nn=async(e=process.cwd())=>{let t=await st(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
7
|
+
`);return i.length>e.length*.8?e:i}import{execSync as Rn}from"child_process";import pr from"fs/promises";import Sn from"path";import ee from"process";import{getTracer as vn}from"@netlify/otel";import Ee from"process";var se=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},St=e=>e instanceof se;var Pe=Ee.env.NETLIFY_API_URL,ke=Ee.env.NETLIFY_API_TOKEN,H=T("api"),Oe=()=>Ee.env.NETLIFY_LOCAL_MODE==="true",we=async(e,t={})=>{if(!Pe||!ke)throw new Error("No API URL or token");let r=new URL(e,Pe),o={...t,headers:{...t.headers,Authorization:`Bearer ${ke}`}};Ee.env.AGENT_RUNNERS_DEBUG==="true"&&(o.headers["x-nf-debug-logging"]="true"),t.json&&(o.headers||={},o.headers["Content-Type"]="application/json",o.body=JSON.stringify(t.json));let n=await fetch(r,o),i=n.ok&&n.status<=299;if(Ee.env.AGENT_RUNNERS_DEBUG==="true")H.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{H.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");H.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||H.error(`Got status ${n.status} for request ${r}`),t.raw){if(!i)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let s=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let a=typeof s=="string"?s:JSON.stringify(s);throw n.status===404?new se(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new se(`API request failed: 403 - ${a}`,403,"Credit limit reached. Please add more credits to continue using Agent Runners."):new Error(`API request failed: ${n.status} - ${a}`)}return s},vt=e=>{H.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Pe=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(ke=e.constants.NETLIFY_API_TOKEN)},At=()=>({apiUrl:Pe,token:ke}),Te=async(e,t)=>Oe()?(H.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):we(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),j=async(e,t,r)=>Oe()?(H.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):we(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var bt=async(e,t)=>Oe()?(H.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):we(`/api/v1/agent_runners/${e}/sessions/${t}`),Ct=(e,t,r)=>we(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),Nt=async(e,t)=>Oe()?(H.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):we(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Xe=async(e,t)=>{H.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ie=T("ai_gateway"),Ze=null;var Pt=async()=>{if(Ze)return Ze;ie.log("Fetching available AI gateway providers");let e=await fetch(`${At().apiUrl}/api/v1/ai-gateway/providers`);if(!e.ok)throw new Error(`Failed to fetch AI gateway providers: ${e.statusText}`);let t=await e.json();return Ze=t,ie.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},$r=async(e,t)=>{let o=(await Pt()).providers[e];if(!o)return ie.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return ie.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},kt=async({netlify:e,config:t})=>{let r,o,n,i,s=e.constants?.SITE_ID;if(!s)throw new Error("No site id");let a=async()=>{clearTimeout(n),ie.log("Requesting AI gateway information");let c=await Ct(s,t.id,t.sessionId);if({token:r,url:i}=c,o=c.expires_at?c.expires_at*1e3:void 0,ie.log("Got AI gateway information",{token:!!r,expiresAt:o,url:i}),o){let u=o-Date.now()-6e4;u>0&&(n=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Pt()]),{get url(){return i},get token(){return r},isModelAvailableForProvider:$r}};import K from"process";import z from"path";import $e from"fs";import{fileURLToPath as jr}from"url";import{createRequire as Yr}from"module";import{execa as Br,execaCommand as Do}from"execa";import{Transform as Fr}from"stream";var Lr=new Set(["NODE_ENV","PATH","HOME","USER","USERNAME","SHELL","PWD","OLDPWD","TMPDIR","TMP","TEMP","LANG","TERM","EDITOR","PAGER","OS","PROCESSOR_ARCHITECTURE","PROCESSOR_IDENTIFIER","SYSTEMROOT","WINDIR","PROGRAMFILES","PROGRAMFILES(X86)","PROGRAMDATA","APPDATA","LOCALAPPDATA","NODE_OPTIONS","NODE_PATH","NODE_DEBUG","NODE_NO_WARNINGS","npm_config_registry","npm_config_cache","npm_execpath","npm_node_execpath","CI","GITHUB_ACTIONS","GITHUB_WORKSPACE","GITHUB_REPOSITORY","GITHUB_REF","BUILDKITE","BUILDKITE_BRANCH","BUILDKITE_COMMIT","BUILDKITE_BUILD_NUMBER","JENKINS_URL","TRAVIS","CIRCLECI","DISPLAY","COLORTERM","TERM_PROGRAM","TERM_PROGRAM_VERSION","COLUMNS","LINES","HISTSIZE","HISTFILE","NETLIFY_AGENT_RUNNER_ID","NETLIFY_AGENT_RUNNER_SESSION_ID","NETLIFY_AGENT_RUNNER_PROMPT","NETLIFY_AGENT_RUNNER_AGENT","NETLIFY_AGENT_RUNNER_MODEL","NETLIFY_AGENT_RUNNER_CONTEXT","NETLIFY_AGENT_RUNNER_HAS_REPO","NETLIFY_FF_AGENT_RUNNER_BYOK_ENABLED","NETLIFY_AGENT_RUNNER_SHA","NETLIFY_TEAM_TYPE","AGENT_RUNNERS_DEBUG","NETLIFY_TEAM_ID","NETLIFY_AGENT_RUNNER_USER_ID","SITE_NAME"]),Dr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function Mr(){return Object.entries(process.env).filter(([e,t])=>!(!t||Lr.has(e)||Dr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function V(e){if(typeof e!="string")return e;let t=Mr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Ur(o),"g");r=r.replace(n,"******")}),r}function Ur(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ae=class extends Fr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=V(n);o(null,i)}};function Ot(){if(!(process.env.NETLIFY_MASK_LOGS!=="false"))return;let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr);process.stdout.write=function(o,n,i){let s=typeof o=="string"?V(o):o;return typeof n=="function"?t(s,n):t(s,n,i)},process.stderr.write=function(o,n,i){let s=typeof o=="string"?V(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var xe=null,$t=e=>(xe&&xe.destroy(),xe=new X({totalAllowedTime:e}),xe),Ft=()=>xe;var X=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,o)=>{if(this.isTimeExpired())throw new Error(`${t} stage did not complete in the allowed time. Time has already expired.`);let n=this.onTimesUp(()=>{throw new Error(`${t} stage did not complete in the allowed time.`)}),i=null,s=null;o!==void 0&&(s=new Promise((a,c)=>{i=setTimeout(()=>{c(new Error(`${t} stage exceeded its maximum duration of ${o}ms`))},o)}));try{return s?await Promise.race([r(),s]):await r()}finally{n(),i&&clearTimeout(i)}};this.startTime=Date.now(),this.totalAllowedTime=t,this.globalTimeoutId=null,this.subscribers=[],this.hasTimedOut=!1,this.setupGlobalTimeout()}getElapsedTime(){return Date.now()-this.startTime}getRemainingTime(){let t=this.getElapsedTime(),r=this.totalAllowedTime-t;return Math.max(0,r)}isTimeExpired(){return this.getRemainingTime()===0||this.hasTimedOut}setupGlobalTimeout(){this.globalTimeoutId&&clearTimeout(this.globalTimeoutId),this.globalTimeoutId=setTimeout(()=>{this.notifyTimeUp()},this.totalAllowedTime)}notifyTimeUp(){this.hasTimedOut=!0;for(let t=this.subscribers.length-1;t>=0;t--)try{this.subscribers[t]()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}}onTimesUp(t){if(this.subscribers.push(t),this.hasTimedOut)try{t()}catch(r){console.error("TimeKeeper: Error in time up callback:",r)}return()=>{let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}}off(t){let r=this.subscribers.indexOf(t);r>-1&&this.subscribers.splice(r,1)}clearSubscribers(){this.subscribers.length=0}getSubscriberCount(){return this.subscribers.length}destroy(){this.globalTimeoutId&&(clearTimeout(this.globalTimeoutId),this.globalTimeoutId=null),this.clearSubscribers()}static{this.timeUnits={seconds:t=>t*1e3,minutes:t=>t*60*1e3,hours:t=>t*60*60*1e3}}};var Lt="netlify-agent-runner-context.md",Qe="task-history",W=".netlify",te="results.md",et="assets";var re=1800*1e3,_={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var Dt={name:"@netlify/agent-runner-cli",type:"module",version:"1.75.0",description:"CLI tool for running Netlify agents",main:"./dist/index.js",types:"./dist/index.d.ts",exports:"./dist/index.js",bin:{"agent-runner-cli":"./dist/bin.js","agent-runner-cli-local":"./dist/bin-local.js"},files:["dist/**/*.js","dist/**/*.d.ts","dist/skills/**","patches","scripts"],scripts:{build:"tsup",dev:"tsup --watch",prepare:"husky install node_modules/@netlify/eslint-config-node/.husky/",prepublishOnly:"npm ci && npm test",prepack:"npm run build",test:"run-s build format test:dev",format:"run-s build format:check-fix:*","format:ci":"run-s build format:check:*","format:check-fix:lint":"run-e format:check:lint format:fix:lint","format:check:lint":"cross-env-shell eslint $npm_package_config_eslint","format:fix:lint":"cross-env-shell eslint --fix $npm_package_config_eslint","format:check-fix:prettier":"run-e format:check:prettier format:fix:prettier","format:check:prettier":"cross-env-shell prettier --check $npm_package_config_prettier","format:fix:prettier":"cross-env-shell prettier --write $npm_package_config_prettier","test:dev":"run-s build test:dev:*","test:ci":"run-s build test:ci:*","test:dev:vitest":"LOG=0 vitest --exclude '**/integration/**'","test:ci:vitest":"LOG=0 c8 -r lcovonly -r text -r json vitest --exclude '**/integration/**'","test:integration":"vitest run test/integration/","test:integration:codex":"vitest run test/integration/codex.test.ts","test:integration:claude":"vitest run test/integration/claude.test.ts","test:integration:gemini":"vitest run test/integration/gemini.test.ts","test:integration:create-stage":"vitest run test/integration/create.test.ts",postinstall:"node scripts/postinstall.js"},config:{eslint:'--cache --format=codeframe --max-warnings=0 "{src,scripts,test,.github}/**/*.{js,ts,md,html}"',prettier:'--ignore-path .gitignore --loglevel=warn "{src,scripts,test,.github}/**/*.{js,ts,md,yml,json,html}" "*.{js,ts,yml,json,html}" ".*.{js,ts,yml,json,html}" "!**/package-lock.json" "!package-lock.json" "!src/skills/**/*.md"'},keywords:[],license:"MIT",repository:"netlify/agent-runner-cli",bugs:{url:"https://github.com/netlify/agent-runner-cli/issues"},author:"Netlify Inc.",directories:{test:"test"},devDependencies:{"@commitlint/cli":"^20.0.0","@commitlint/config-conventional":"^20.0.0","@eslint/compat":"^2.0.0","@eslint/js":"^9.35.0","@netlify/eslint-config-node":"^7.0.1","@types/node":"^24.5.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/eslint-plugin":"^1.6.6",c8:"^10.0.0","eslint-config-prettier":"^10.1.8","eslint-plugin-n":"^17.0.0",husky:"^9.0.0","patch-package":"^8.0.0",tsup:"^8.5.0",typescript:"^5.0.0","typescript-eslint":"^8.44.0",vitest:"^4.0.16"},dependencies:{"@anthropic-ai/claude-code":"2.1.47","@anthropic-ai/sdk":"0.77.0","@google/gemini-cli":"0.29.3","@netlify/otel":"^5.1.1","@openai/codex":"0.104.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.5.0",minimist:"^1.2.8",openai:"6.22.0"}};var qr=jr(import.meta.url),Hr=z.dirname(qr),Wr=Yr(import.meta.url),le=T("shell"),tt=new Set,Kr={preferLocal:!0},C=(e,t,r)=>{let[o,n]=Jr(t,r),i={...Kr,...n},s=Br(e,o,i);Vr(s,i),Xr(s);let a=r?.idleTimeout;return a&&a>0&&zr(s,a),s};var Jr=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},Vr=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(K.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new ae).pipe(K.stdout),e.stdout?.pipe(new ae).pipe(K.stdout),e.stderr?.pipe(new ae).pipe(K.stderr);return}e.stdout?.pipe(K.stdout),e.stderr?.pipe(K.stderr)},rt=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(K.kill(-e.pid,t),le.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return le.error("Error killing process:",r),!1}},Mt=e=>rt(e,"SIGKILL"),zr=(e,t)=>{let r=null,o=()=>{le.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),rt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(le.log(`Force killing idle process ${e.pid}`),Mt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(o,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let i=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",i),e.on("error",i)},Xr=e=>{tt.add(e);let t=Ft();if(t){let r=t.onTimesUp(()=>{le.log(`Global timer expired, killing process ${e.pid}`),rt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(le.log(`Force killing process ${e.pid} after timeout`),Mt(e))},5e3)});e.on("exit",()=>{tt.delete(e),r()}),e.on("error",()=>{tt.delete(e),r()})}};function Z(e,t){if(!K.env.NETLIFY_LOCAL_MODE)try{let n=Wr.resolve(Dt.name),i=z.dirname(n);for(;i!==z.dirname(i);){let s=z.dirname(i);if(z.basename(s)==="node_modules"){let a=z.join(s,".bin",t);if($e.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(K.env.NODE_PATH){let n=z.join(K.env.NODE_PATH,".bin",t);if($e.existsSync(n))return n}let r=z.join(e,"node_modules",".bin",t);if($e.existsSync(r))return r;let o=z.join(Hr,"..","node_modules",".bin",t);if($e.existsSync(o))return o}var Zr=T("utils"),Qr=e=>new Promise(t=>{setTimeout(t,e)}),Ut=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(p=>{n.push(p)});r=!0;let c,u=new Promise(p=>{c=p});return i=(async()=>{await Promise.resolve();let p=await e(...a);for(c(p);;){if(await Qr(t),!o)return r=!1,i=null,p;let d=o,m=n;o=null,n=[],p=await e(...d),m.forEach(h=>{h(p)})}})(),u};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},ce=(e,t,r=!1)=>{let o=null,n=null,i=null,s=function(...a){n=a,i=this;let c=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(i,n),n=null,i=null)},t),c&&(e.apply(i,n),n=null,i=null)};return s.cancel=()=>{clearTimeout(o),o=null,n=null,i=null},s.flush=()=>{if(o){clearTimeout(o);let a=n,c=i;o=null,n=null,i=null,e.apply(c,a)}},s},Gt=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):Zr.error("Could not parse JSON",o))}},Fe=e=>e.charAt(0).toUpperCase()+e.slice(1),jt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),Yt=(e,t)=>{let n=".netlify.app",i="agent-";if(!t)return`${i}${e.slice(0,6)}`;let a=`--${t}${n}`;if(a.length>55)return"";let c=60-a.length;if(c<=0)return"";if(c>=i.length+6){let u=Math.min(c-i.length,e.length);return`${i}${e.slice(0,u)}`}return e.slice(0,c)};var en=50*1024,nt=(e,t=en)=>{if(!e||typeof e!="string"||e.length<=t)return e;let o=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+o};import{Buffer as Bt}from"buffer";import tn from"path";var qt=T("repo"),Wt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{qt.info("Getting runner diffs");let o=await nn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let E=sn(i);await an(E,r)}qt.info("Changes after processing"),await st(r);let s=await at(i,r);if(await ot(s,r),n=await on(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await C("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},c=await C("git",["diff",e.runSha,"HEAD"],a),u=String(c.stdout??"");if(n=!!u,!n)return await Ht(r),{hasChanges:!1,ignored:s};let p=await C("git",["diff",e.runSha,"HEAD","--binary"],a),d=String(p.stdout??""),m,h;if(e.sha){let E=await C("git",["diff",e.sha,"HEAD"],a);m=String(E.stdout??"");let x=await C("git",["diff",e.sha,"HEAD","--binary"],a),w=String(x.stdout??"");m!==w&&(h=Bt.from(w).toString("base64"))}await Ht(r);let y={hasChanges:!0,diff:u,resultDiff:m,ignored:s};return u!==d&&(y.diffBinary=Bt.from(d).toString("base64")),h&&(y.resultDiffBinary=h),y},Ht=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await C("git",["reset","--soft","HEAD~1"],{cwd:e})},ot=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await C("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},st=async(e=process.cwd())=>{let t=await C("git",["status","-s"],{cwd:e});return String(t.stdout??"")},Kt=/.. (.+)?\.log$/,rn=[Kt],nn=async(e=process.cwd())=>{let t=await st(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
8
8
|
`).filter(n=>rn.some(s=>s instanceof RegExp?s.test(n):n===s)?!1:n[1]?.trim()!=="")).length!==0,status:t}},on=async(e=process.cwd())=>{try{return await C("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},it=async(e=process.cwd())=>{let{stdout:t}=await C("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},Jt=async(e=process.cwd())=>{let{stdout:t}=await C("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},at=async(e,t=process.cwd())=>{e||=await st(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build","CLAUDE.local.md"],o=[];return e.split(`
|
|
9
9
|
`).forEach(n=>{r.forEach(s=>{let a=n===`?? ${s}`,c=n.startsWith(`?? ${s}/`)||n.startsWith(`?? ${s}${tn.sep}`);(a||c)&&o.push(`:!${s}`)});let i=n.match(Kt)?.[1];i&&o.push(`:!${i}.log`)}),o},lt=async(e=process.cwd())=>{await C("git",["reset","--hard","HEAD"],{cwd:e})},sn=e=>{let t=e.split(`
|
|
10
10
|
`).reduce((r,o)=>{if(!o)return r;let[n,i,,...s]=o,a=s.join(""),c=n.trim(),u=i.trim();return r[a]?r[a].change=u:r[a]={filePath:a,stage:c,change:u},r},{});return Object.values(t)},an=async(e,t=process.cwd())=>{let r=e.filter(o=>o.stage&&!o.change).map(o=>o.filePath);r.length!==0&&await C("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
|