@netlify/agent-runner-cli 1.71.0 → 1.72.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 CHANGED
@@ -5,7 +5,7 @@ import L from"process";import Cr from"path";import Nr from"fs";import co 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 bn}from"child_process";import pr from"fs/promises";import Cn from"path";import re from"process";import{getTracer as Nn}from"@netlify/otel";import Te from"process";var ae=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},Rt=e=>e instanceof ae;var Ne=Te.env.NETLIFY_API_URL,Pe=Te.env.NETLIFY_API_TOKEN,K=_("api"),ke=()=>Te.env.NETLIFY_LOCAL_MODE==="true",xe=async(e,t={})=>{if(!Ne||!Pe)throw new Error("No API URL or token");let r=new URL(e,Ne),o={...t,headers:{...t.headers,Authorization:`Bearer ${Pe}`}};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),s=n.ok&&n.status<=299;if(Te.env.AGENT_RUNNERS_DEBUG==="true")K.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{K.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");K.log(`Request ID for ${r}: ${a||"N/A"}`)}if(s||K.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 ae(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new ae(`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},St=e=>{K.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Ne=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Pe=e.constants.NETLIFY_API_TOKEN)},vt=()=>({apiUrl:Ne,token:Pe}),Re=async(e,t)=>ke()?(K.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):xe(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),U=async(e,t,r)=>ke()?(K.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 At=async(e,t)=>ke()?(K.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`),bt=(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}),Ct=async(e,t)=>ke()?(K.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"}),Je=async(e,t)=>{K.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 le=_("ai_gateway"),Ve=null;var Nt=async()=>{if(Ve)return Ve;le.log("Fetching available AI gateway providers");let e=await fetch(`${vt().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 Ve=t,le.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},Mr=async(e,t)=>{let o=(await Nt()).providers[e];if(!o)return le.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return le.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Pt=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),le.log("Requesting AI gateway information");let c=await bt(i,t.id,t.sessionId);if({token:r,url:s}=c,o=c.expires_at?c.expires_at*1e3:void 0,le.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(),Nt()]),{get url(){return s},get token(){return r},isModelAvailableForProvider:Mr}};import V from"process";import Q from"path";import Oe from"fs";import{fileURLToPath as Hr}from"url";import{createRequire as Wr}from"module";import{execa as Kr,execaCommand as Bo}from"execa";import{Transform as Ur}from"stream";var Gr=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"]),jr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function Yr(){return Object.entries(process.env).filter(([e,t])=>!(!t||Gr.has(e)||jr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function Z(e){if(typeof e!="string")return e;let t=Yr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Br(o),"g");r=r.replace(n,"******")}),r}function Br(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ce=class extends Ur{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),s=Z(n);o(null,s)}};function kt(){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,Ot=e=>(Se&&Se.destroy(),Se=new te({totalAllowedTime:e}),Se),$t=()=>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,c)=>{s=setTimeout(()=>{c(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 Ft="netlify-agent-runner-context.md",ze="task-history",J=".netlify",ne="results.md",Xe="assets";var oe=1800*1e3,w={Environment:"environment",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"};var Lt={name:"@netlify/agent-runner-cli",type:"module",version:"1.71.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.37","@anthropic-ai/sdk":"0.72.1","@google/gemini-cli":"0.27.3","@netlify/otel":"^5.1.1","@openai/codex":"0.93.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.208.0",execa:"^9.6.1",kaddidlehopper:"^0.1.2",minimist:"^1.2.8",openai:"6.17.0"}};var Jr=Hr(import.meta.url),Vr=Q.dirname(Jr),zr=Wr(import.meta.url),ue=_("shell"),Ze=new Set,Xr={preferLocal:!0},R=(e,t,r)=>{let[o,n]=Zr(t,r),s={...Xr,...n},i=Kr(e,o,s);Qr(i,s),tn(i);let a=r?.idleTimeout;return a&&a>0&&en(i,a),i};var Zr=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},Qr=(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 ce).pipe(V.stdout),e.stdout?.pipe(new ce).pipe(V.stdout),e.stderr?.pipe(new ce).pipe(V.stderr);return}e.stdout?.pipe(V.stdout),e.stderr?.pipe(V.stderr)},Qe=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(V.kill(-e.pid,t),ue.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ue.error("Error killing process:",r),!1}},Dt=e=>Qe(e,"SIGKILL"),en=(e,t)=>{let r=null,o=()=>{ue.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),Qe(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ue.log(`Force killing idle process ${e.pid}`),Dt(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)},tn=e=>{Ze.add(e);let t=$t();if(t){let r=t.onTimesUp(()=>{ue.log(`Global timer expired, killing process ${e.pid}`),Qe(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ue.log(`Force killing process ${e.pid} after timeout`),Dt(e))},5e3)});e.on("exit",()=>{Ze.delete(e),r()}),e.on("error",()=>{Ze.delete(e),r()})}};function $e(e,t){return!!ee(e,t)}function ee(e,t){if(!V.env.NETLIFY_LOCAL_MODE)try{let n=zr.resolve(Lt.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(Oe.existsSync(a))return a;break}s=i}}catch(n){console.error("Could not resolve package.json",n)}if(V.env.NODE_PATH){let n=Q.join(V.env.NODE_PATH,".bin",t);if(Oe.existsSync(n))return n}let r=Q.join(e,"node_modules",".bin",t);if(Oe.existsSync(r))return r;let o=Q.join(Vr,"..","node_modules",".bin",t);if(Oe.existsSync(o))return o}var rn=_("utils"),nn=e=>new Promise(t=>{setTimeout(t,e)}),Mt=(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 c,u=new Promise(p=>{c=p});return s=(async()=>{await Promise.resolve();let p=await e(...a);for(c(p);;){if(await nn(t),!o)return r=!1,s=null,p;let d=o,m=n;o=null,n=[],p=await e(...d),m.forEach(y=>{y(p)})}})(),u};return i.flush=async()=>{if((r||o)&&s)return await s,i.flush()},i},de=(e,t,r=!1)=>{let o=null,n=null,s=null,i=function(...a){n=a,s=this;let c=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(s,n),n=null,s=null)},t),c&&(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,c=s;o=null,n=null,s=null,e.apply(c,a)}},i},Ut=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):rn.error("Could not parse JSON",o))}},Gt=(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 c=60-a.length;if(c<=0)return"";if(c>=s.length+6){let u=Math.min(c-s.length,e.length);return`${s}${e.slice(0,u)}`}return e.slice(0,c)};var on=50*1024,et=(e,t=on)=>{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 jt}from"buffer";import sn from"path";var Yt=_("repo"),qt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{Yt.info("Getting runner diffs");let o=await ln(r),{hasChanges:n}=o,{status:s}=o;if(!n)return{hasChanges:!1};if(!t){let I=un(s);await dn(I,r)}Yt.info("Changes after processing"),await rt(r);let i=await nt(s,r);if(await tt(i,r),n=await cn(r),!n)return{hasChanges:!1,ignored:i};process.env.NETLIFY_INTERNAL_GIT="1";try{await R("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},c=await R("git",["diff",e.runSha,"HEAD"],a),u=String(c.stdout??"");if(n=!!u,!n)return await Bt(r),{hasChanges:!1,ignored:i};let p=await R("git",["diff",e.runSha,"HEAD","--binary"],a),d=String(p.stdout??""),m,y;if(e.sha){let I=await R("git",["diff",e.sha,"HEAD"],a);m=String(I.stdout??"");let T=await R("git",["diff",e.sha,"HEAD","--binary"],a),E=String(T.stdout??"");m!==E&&(y=jt.from(E).toString("base64"))}await Bt(r);let h={hasChanges:!0,diff:u,resultDiff:m,ignored:i};return u!==d&&(h.diffBinary=jt.from(d).toString("base64")),y&&(h.resultDiffBinary=y),h},Bt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await R("git",["reset","--soft","HEAD~1"],{cwd:e})},tt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await R("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},rt=async(e=process.cwd())=>{let t=await R("git",["status","-s"],{cwd:e});return String(t.stdout??"")},Ht=/.. (.+)?\.log$/,an=[Ht],ln=async(e=process.cwd())=>{let t=await rt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
8
+ `);return s.length>e.length*.8?e:s}import{execSync as bn}from"child_process";import pr from"fs/promises";import Cn from"path";import re from"process";import{getTracer as Nn}from"@netlify/otel";import Te from"process";var ae=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},Rt=e=>e instanceof ae;var Ne=Te.env.NETLIFY_API_URL,Pe=Te.env.NETLIFY_API_TOKEN,K=_("api"),ke=()=>Te.env.NETLIFY_LOCAL_MODE==="true",xe=async(e,t={})=>{if(!Ne||!Pe)throw new Error("No API URL or token");let r=new URL(e,Ne),o={...t,headers:{...t.headers,Authorization:`Bearer ${Pe}`}};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),s=n.ok&&n.status<=299;if(Te.env.AGENT_RUNNERS_DEBUG==="true")K.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{K.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");K.log(`Request ID for ${r}: ${a||"N/A"}`)}if(s||K.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 ae(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new ae(`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},St=e=>{K.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Ne=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Pe=e.constants.NETLIFY_API_TOKEN)},vt=()=>({apiUrl:Ne,token:Pe}),Re=async(e,t)=>ke()?(K.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):xe(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),U=async(e,t,r)=>ke()?(K.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 At=async(e,t)=>ke()?(K.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):xe(`/api/v1/agent_runners/${e}/sessions/${t}`),bt=(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}),Ct=async(e,t)=>ke()?(K.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"}),Je=async(e,t)=>{K.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 le=_("ai_gateway"),Ve=null;var Nt=async()=>{if(Ve)return Ve;le.log("Fetching available AI gateway providers");let e=await fetch(`${vt().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 Ve=t,le.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},Mr=async(e,t)=>{let o=(await Nt()).providers[e];if(!o)return le.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return le.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Pt=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),le.log("Requesting AI gateway information");let c=await bt(i,t.id,t.sessionId);if({token:r,url:s}=c,o=c.expires_at?c.expires_at*1e3:void 0,le.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(),Nt()]),{get url(){return s},get token(){return r},isModelAvailableForProvider:Mr}};import V from"process";import Q from"path";import Oe from"fs";import{fileURLToPath as Hr}from"url";import{createRequire as Wr}from"module";import{execa as Kr,execaCommand as Bo}from"execa";import{Transform as Ur}from"stream";var Gr=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"]),jr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function Yr(){return Object.entries(process.env).filter(([e,t])=>!(!t||Gr.has(e)||jr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function Z(e){if(typeof e!="string")return e;let t=Yr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Br(o),"g");r=r.replace(n,"******")}),r}function Br(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ce=class extends Ur{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),s=Z(n);o(null,s)}};function kt(){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,Ot=e=>(Se&&Se.destroy(),Se=new te({totalAllowedTime:e}),Se),$t=()=>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,c)=>{s=setTimeout(()=>{c(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 Ft="netlify-agent-runner-context.md",ze="task-history",J=".netlify",ne="results.md",Xe="assets";var oe=1800*1e3,w={Environment:"environment",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"};var Lt={name:"@netlify/agent-runner-cli",type:"module",version:"1.72.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.45","@anthropic-ai/sdk":"0.72.1","@google/gemini-cli":"0.27.3","@netlify/otel":"^5.1.1","@openai/codex":"0.93.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.208.0",execa:"^9.6.1",kaddidlehopper:"^0.1.2",minimist:"^1.2.8",openai:"6.17.0"}};var Jr=Hr(import.meta.url),Vr=Q.dirname(Jr),zr=Wr(import.meta.url),ue=_("shell"),Ze=new Set,Xr={preferLocal:!0},R=(e,t,r)=>{let[o,n]=Zr(t,r),s={...Xr,...n},i=Kr(e,o,s);Qr(i,s),tn(i);let a=r?.idleTimeout;return a&&a>0&&en(i,a),i};var Zr=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},Qr=(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 ce).pipe(V.stdout),e.stdout?.pipe(new ce).pipe(V.stdout),e.stderr?.pipe(new ce).pipe(V.stderr);return}e.stdout?.pipe(V.stdout),e.stderr?.pipe(V.stderr)},Qe=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(V.kill(-e.pid,t),ue.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ue.error("Error killing process:",r),!1}},Dt=e=>Qe(e,"SIGKILL"),en=(e,t)=>{let r=null,o=()=>{ue.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),Qe(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ue.log(`Force killing idle process ${e.pid}`),Dt(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)},tn=e=>{Ze.add(e);let t=$t();if(t){let r=t.onTimesUp(()=>{ue.log(`Global timer expired, killing process ${e.pid}`),Qe(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ue.log(`Force killing process ${e.pid} after timeout`),Dt(e))},5e3)});e.on("exit",()=>{Ze.delete(e),r()}),e.on("error",()=>{Ze.delete(e),r()})}};function $e(e,t){return!!ee(e,t)}function ee(e,t){if(!V.env.NETLIFY_LOCAL_MODE)try{let n=zr.resolve(Lt.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(Oe.existsSync(a))return a;break}s=i}}catch(n){console.error("Could not resolve package.json",n)}if(V.env.NODE_PATH){let n=Q.join(V.env.NODE_PATH,".bin",t);if(Oe.existsSync(n))return n}let r=Q.join(e,"node_modules",".bin",t);if(Oe.existsSync(r))return r;let o=Q.join(Vr,"..","node_modules",".bin",t);if(Oe.existsSync(o))return o}var rn=_("utils"),nn=e=>new Promise(t=>{setTimeout(t,e)}),Mt=(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 c,u=new Promise(p=>{c=p});return s=(async()=>{await Promise.resolve();let p=await e(...a);for(c(p);;){if(await nn(t),!o)return r=!1,s=null,p;let d=o,m=n;o=null,n=[],p=await e(...d),m.forEach(y=>{y(p)})}})(),u};return i.flush=async()=>{if((r||o)&&s)return await s,i.flush()},i},de=(e,t,r=!1)=>{let o=null,n=null,s=null,i=function(...a){n=a,s=this;let c=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(s,n),n=null,s=null)},t),c&&(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,c=s;o=null,n=null,s=null,e.apply(c,a)}},i},Ut=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):rn.error("Could not parse JSON",o))}},Gt=(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 c=60-a.length;if(c<=0)return"";if(c>=s.length+6){let u=Math.min(c-s.length,e.length);return`${s}${e.slice(0,u)}`}return e.slice(0,c)};var on=50*1024,et=(e,t=on)=>{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 jt}from"buffer";import sn from"path";var Yt=_("repo"),qt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{Yt.info("Getting runner diffs");let o=await ln(r),{hasChanges:n}=o,{status:s}=o;if(!n)return{hasChanges:!1};if(!t){let I=un(s);await dn(I,r)}Yt.info("Changes after processing"),await rt(r);let i=await nt(s,r);if(await tt(i,r),n=await cn(r),!n)return{hasChanges:!1,ignored:i};process.env.NETLIFY_INTERNAL_GIT="1";try{await R("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},c=await R("git",["diff",e.runSha,"HEAD"],a),u=String(c.stdout??"");if(n=!!u,!n)return await Bt(r),{hasChanges:!1,ignored:i};let p=await R("git",["diff",e.runSha,"HEAD","--binary"],a),d=String(p.stdout??""),m,y;if(e.sha){let I=await R("git",["diff",e.sha,"HEAD"],a);m=String(I.stdout??"");let T=await R("git",["diff",e.sha,"HEAD","--binary"],a),E=String(T.stdout??"");m!==E&&(y=jt.from(E).toString("base64"))}await Bt(r);let h={hasChanges:!0,diff:u,resultDiff:m,ignored:i};return u!==d&&(h.diffBinary=jt.from(d).toString("base64")),y&&(h.resultDiffBinary=y),h},Bt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await R("git",["reset","--soft","HEAD~1"],{cwd:e})},tt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await R("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},rt=async(e=process.cwd())=>{let t=await R("git",["status","-s"],{cwd:e});return String(t.stdout??"")},Ht=/.. (.+)?\.log$/,an=[Ht],ln=async(e=process.cwd())=>{let t=await rt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
9
9
  `).filter(n=>an.some(i=>i instanceof RegExp?i.test(n):n===i)?!1:n[1]?.trim()!=="")).length!==0,status:t}},cn=async(e=process.cwd())=>{try{return await R("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},ve=async(e=process.cwd())=>{let{stdout:t}=await R("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},Wt=async(e=process.cwd())=>{let{stdout:t}=await R("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},nt=async(e,t=process.cwd())=>{e||=await rt(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build"],o=[];return e.split(`
10
10
  `).forEach(n=>{r.forEach(i=>{let a=n===`?? ${i}`,c=n.startsWith(`?? ${i}/`)||n.startsWith(`?? ${i}${sn.sep}`);(a||c)&&o.push(`:!${i}`)});let s=n.match(Ht)?.[1];s&&o.push(`:!${s}.log`)}),o},ot=async(e=process.cwd())=>{await R("git",["reset","--hard","HEAD"],{cwd:e})},un=e=>{let t=e.split(`
11
11
  `).reduce((r,o)=>{if(!o)return r;let[n,s,,...i]=o,a=i.join(""),c=n.trim(),u=s.trim();return r[a]?r[a].change=u:r[a]={filePath:a,stage:c,change:u},r},{});return Object.values(t)},dn=async(e,t=process.cwd())=>{let r=e.filter(o=>o.stage&&!o.change).map(o=>o.filePath);r.length!==0&&await R("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
package/dist/bin.js CHANGED
@@ -5,7 +5,7 @@ import wt from"process";import xo from"minimist";import{createRequire as mo}from
5
5
  ${i}
6
6
  </extracted_error_chunk>`).join(`
7
7
 
8
- `);return s.length>e.length*.8?e:s}import{execSync as Fn}from"child_process";import Er from"fs/promises";import Ln from"path";import ee from"process";import{getTracer as $n}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"}},vt=e=>e instanceof ie;var Ce=Te.env.NETLIFY_API_URL,be=Te.env.NETLIFY_API_TOKEN,q=_("api"),Ne=()=>Te.env.NETLIFY_LOCAL_MODE==="true",Re=async(e,t={})=>{if(!Ce||!be)throw new Error("No API URL or token");let r=new URL(e,Ce),o={...t,headers:{...t.headers,Authorization:`Bearer ${be}`}};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),s=n.ok&&n.status<=299;if(Te.env.AGENT_RUNNERS_DEBUG==="true")q.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{q.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");q.log(`Request ID for ${r}: ${a||"N/A"}`)}if(s||q.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 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 i},At=e=>{q.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Ce=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(be=e.constants.NETLIFY_API_TOKEN)},Ct=()=>({apiUrl:Ce,token:be}),xe=async(e,t)=>Ne()?(q.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):Re(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),D=async(e,t,r)=>Ne()?(q.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):Re(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var bt=async(e,t)=>Ne()?(q.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):Re(`/api/v1/agent_runners/${e}/sessions/${t}`),Nt=(e,t,r)=>Re(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),Pt=async(e,t)=>Ne()?(q.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"}}):Re(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),We=async(e,t)=>{q.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 se=_("ai_gateway"),Ke=null;var kt=async()=>{if(Ke)return Ke;se.log("Fetching available AI gateway providers");let e=await fetch(`${Ct().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 Ke=t,se.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},Hr=async(e,t)=>{let o=(await kt()).providers[e];if(!o)return se.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return se.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Ot=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),se.log("Requesting AI gateway information");let c=await Nt(i,t.id,t.sessionId);if({token:r,url:s}=c,o=c.expires_at?c.expires_at*1e3:void 0,se.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(),kt()]),{get url(){return s},get token(){return r},isModelAvailableForProvider:Hr}};import K from"process";import z from"path";import Pe from"fs";import{fileURLToPath as zr}from"url";import{createRequire as Zr}from"module";import{execa as Qr,execaCommand as ti}from"execa";import{Transform as qr}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 Vr(){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 X(e){if(typeof e!="string")return e;let t=Vr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Jr(o),"g");r=r.replace(n,"******")}),r}function Jr(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ae=class extends qr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),s=X(n);o(null,s)}};function Ft(){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"?X(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"?X(o):o;return typeof n=="function"?r(i,n):r(i,n,s)}}var Ie=null,Lt=e=>(Ie&&Ie.destroy(),Ie=new Z({totalAllowedTime:e}),Ie),$t=()=>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.`)}),s=null,i=null;o!==void 0&&(i=new Promise((a,c)=>{s=setTimeout(()=>{c(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 Dt="netlify-agent-runner-context.md",Ve="task-history",W=".netlify",te="results.md",Je="assets",Xe="other",ze="personal";var Ze="enterprise",Qe="free",Mt=[ze,"pro",Ze,Qe],Ut=["normal","redeploy","create","ask","dtn-prod-iteration","rebase"],Gt="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.",re=1800*1e3,w={Environment:"environment",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"};var jt={name:"@netlify/agent-runner-cli",type:"module",version:"1.71.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.37","@anthropic-ai/sdk":"0.72.1","@google/gemini-cli":"0.27.3","@netlify/otel":"^5.1.1","@openai/codex":"0.93.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.208.0",execa:"^9.6.1",kaddidlehopper:"^0.1.2",minimist:"^1.2.8",openai:"6.17.0"}};var en=zr(import.meta.url),tn=z.dirname(en),rn=Zr(import.meta.url),le=_("shell"),et=new Set,nn={preferLocal:!0},b=(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(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)},tt=(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}},Yt=e=>tt(e,"SIGKILL"),an=(e,t)=>{let r=null,o=()=>{le.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),tt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(le.log(`Force killing idle process ${e.pid}`),Yt(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=>{et.add(e);let t=$t();if(t){let r=t.onTimesUp(()=>{le.log(`Global timer expired, killing process ${e.pid}`),tt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(le.log(`Force killing process ${e.pid} after timeout`),Yt(e))},5e3)});e.on("exit",()=>{et.delete(e),r()}),e.on("error",()=>{et.delete(e),r()})}};function Q(e,t){if(!K.env.NETLIFY_LOCAL_MODE)try{let n=rn.resolve(jt.name),s=z.dirname(n);for(;s!==z.dirname(s);){let i=z.dirname(s);if(z.basename(i)==="node_modules"){let a=z.join(i,".bin",t);if(Pe.existsSync(a))return a;break}s=i}}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(Pe.existsSync(n))return n}let r=z.join(e,"node_modules",".bin",t);if(Pe.existsSync(r))return r;let o=z.join(tn,"..","node_modules",".bin",t);if(Pe.existsSync(o))return o}var Bt=_("utils"),cn=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(d=>{n.push(d)});r=!0;let c,u=new Promise(d=>{c=d});return s=(async()=>{await Promise.resolve();let d=await e(...a);for(c(d);;){if(await cn(t),!o)return r=!1,s=null,d;let p=o,m=n;o=null,n=[],d=await e(...p),m.forEach(y=>{y(d)})}})(),u};return i.flush=async()=>{if((r||o)&&s)return await s,i.flush()},i},ce=(e,t,r=!1)=>{let o=null,n=null,s=null,i=function(...a){n=a,s=this;let c=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(s,n),n=null,s=null)},t),c&&(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,c=s;o=null,n=null,s=null,e.apply(c,a)}},i},ke=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):Bt.error("Could not parse JSON",o))}},qt=(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 c=60-a.length;if(c<=0)return"";if(c>=s.length+6){let u=Math.min(c-s.length,e.length);return`${s}${e.slice(0,u)}`}return e.slice(0,c)},un=e=>!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).length===0?!1:!!Mt.some(t=>t in e),Wt=()=>{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 s=JSON.parse(o);un(s)&&(e[r]=s)}catch(s){let a=s instanceof SyntaxError?"Invalid JSON":s.message;Bt.error(`Could not parse ${r} model version override from ${n}: ${a}`)}}}),e},pn=50*1024,rt=(e,t=pn)=>{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 Kt}from"buffer";import dn from"path";var Vt=_("repo"),Xt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{Vt.info("Getting runner diffs");let o=await gn(r),{hasChanges:n}=o,{status:s}=o;if(!n)return{hasChanges:!1};if(!t){let T=hn(s);await yn(T,r)}Vt.info("Changes after processing"),await ot(r);let i=await st(s,r);if(await nt(i,r),n=await fn(r),!n)return{hasChanges:!1,ignored:i};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},c=await b("git",["diff",e.runSha,"HEAD"],a),u=String(c.stdout??"");if(n=!!u,!n)return await Jt(r),{hasChanges:!1,ignored:i};let d=await b("git",["diff",e.runSha,"HEAD","--binary"],a),p=String(d.stdout??""),m,y;if(e.sha){let T=await b("git",["diff",e.sha,"HEAD"],a);m=String(T.stdout??"");let R=await b("git",["diff",e.sha,"HEAD","--binary"],a),E=String(R.stdout??"");m!==E&&(y=Kt.from(E).toString("base64"))}await Jt(r);let h={hasChanges:!0,diff:u,resultDiff:m,ignored:i};return u!==p&&(h.diffBinary=Kt.from(p).toString("base64")),y&&(h.resultDiffBinary=y),h},Jt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await b("git",["reset","--soft","HEAD~1"],{cwd:e})},nt=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"}},ot=async(e=process.cwd())=>{let t=await b("git",["status","-s"],{cwd:e});return String(t.stdout??"")},zt=/.. (.+)?\.log$/,mn=[zt],gn=async(e=process.cwd())=>{let t=await ot(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
8
+ `);return s.length>e.length*.8?e:s}import{execSync as Fn}from"child_process";import Er from"fs/promises";import Ln from"path";import ee from"process";import{getTracer as $n}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"}},vt=e=>e instanceof ie;var Ce=Te.env.NETLIFY_API_URL,be=Te.env.NETLIFY_API_TOKEN,q=_("api"),Ne=()=>Te.env.NETLIFY_LOCAL_MODE==="true",Re=async(e,t={})=>{if(!Ce||!be)throw new Error("No API URL or token");let r=new URL(e,Ce),o={...t,headers:{...t.headers,Authorization:`Bearer ${be}`}};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),s=n.ok&&n.status<=299;if(Te.env.AGENT_RUNNERS_DEBUG==="true")q.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{q.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");q.log(`Request ID for ${r}: ${a||"N/A"}`)}if(s||q.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 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 i},At=e=>{q.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Ce=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(be=e.constants.NETLIFY_API_TOKEN)},Ct=()=>({apiUrl:Ce,token:be}),xe=async(e,t)=>Ne()?(q.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):Re(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),D=async(e,t,r)=>Ne()?(q.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):Re(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var bt=async(e,t)=>Ne()?(q.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):Re(`/api/v1/agent_runners/${e}/sessions/${t}`),Nt=(e,t,r)=>Re(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),Pt=async(e,t)=>Ne()?(q.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"}}):Re(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),We=async(e,t)=>{q.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 se=_("ai_gateway"),Ke=null;var kt=async()=>{if(Ke)return Ke;se.log("Fetching available AI gateway providers");let e=await fetch(`${Ct().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 Ke=t,se.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},Hr=async(e,t)=>{let o=(await kt()).providers[e];if(!o)return se.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return se.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Ot=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),se.log("Requesting AI gateway information");let c=await Nt(i,t.id,t.sessionId);if({token:r,url:s}=c,o=c.expires_at?c.expires_at*1e3:void 0,se.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(),kt()]),{get url(){return s},get token(){return r},isModelAvailableForProvider:Hr}};import K from"process";import z from"path";import Pe from"fs";import{fileURLToPath as zr}from"url";import{createRequire as Zr}from"module";import{execa as Qr,execaCommand as ti}from"execa";import{Transform as qr}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 Vr(){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 X(e){if(typeof e!="string")return e;let t=Vr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Jr(o),"g");r=r.replace(n,"******")}),r}function Jr(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ae=class extends qr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),s=X(n);o(null,s)}};function Ft(){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"?X(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"?X(o):o;return typeof n=="function"?r(i,n):r(i,n,s)}}var Ie=null,Lt=e=>(Ie&&Ie.destroy(),Ie=new Z({totalAllowedTime:e}),Ie),$t=()=>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.`)}),s=null,i=null;o!==void 0&&(i=new Promise((a,c)=>{s=setTimeout(()=>{c(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 Dt="netlify-agent-runner-context.md",Ve="task-history",W=".netlify",te="results.md",Je="assets",Xe="other",ze="personal";var Ze="enterprise",Qe="free",Mt=[ze,"pro",Ze,Qe],Ut=["normal","redeploy","create","ask","dtn-prod-iteration","rebase"],Gt="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.",re=1800*1e3,w={Environment:"environment",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"};var jt={name:"@netlify/agent-runner-cli",type:"module",version:"1.72.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.45","@anthropic-ai/sdk":"0.72.1","@google/gemini-cli":"0.27.3","@netlify/otel":"^5.1.1","@openai/codex":"0.93.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.208.0",execa:"^9.6.1",kaddidlehopper:"^0.1.2",minimist:"^1.2.8",openai:"6.17.0"}};var en=zr(import.meta.url),tn=z.dirname(en),rn=Zr(import.meta.url),le=_("shell"),et=new Set,nn={preferLocal:!0},b=(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(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)},tt=(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}},Yt=e=>tt(e,"SIGKILL"),an=(e,t)=>{let r=null,o=()=>{le.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),tt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(le.log(`Force killing idle process ${e.pid}`),Yt(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=>{et.add(e);let t=$t();if(t){let r=t.onTimesUp(()=>{le.log(`Global timer expired, killing process ${e.pid}`),tt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(le.log(`Force killing process ${e.pid} after timeout`),Yt(e))},5e3)});e.on("exit",()=>{et.delete(e),r()}),e.on("error",()=>{et.delete(e),r()})}};function Q(e,t){if(!K.env.NETLIFY_LOCAL_MODE)try{let n=rn.resolve(jt.name),s=z.dirname(n);for(;s!==z.dirname(s);){let i=z.dirname(s);if(z.basename(i)==="node_modules"){let a=z.join(i,".bin",t);if(Pe.existsSync(a))return a;break}s=i}}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(Pe.existsSync(n))return n}let r=z.join(e,"node_modules",".bin",t);if(Pe.existsSync(r))return r;let o=z.join(tn,"..","node_modules",".bin",t);if(Pe.existsSync(o))return o}var Bt=_("utils"),cn=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(d=>{n.push(d)});r=!0;let c,u=new Promise(d=>{c=d});return s=(async()=>{await Promise.resolve();let d=await e(...a);for(c(d);;){if(await cn(t),!o)return r=!1,s=null,d;let p=o,m=n;o=null,n=[],d=await e(...p),m.forEach(y=>{y(d)})}})(),u};return i.flush=async()=>{if((r||o)&&s)return await s,i.flush()},i},ce=(e,t,r=!1)=>{let o=null,n=null,s=null,i=function(...a){n=a,s=this;let c=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(s,n),n=null,s=null)},t),c&&(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,c=s;o=null,n=null,s=null,e.apply(c,a)}},i},ke=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):Bt.error("Could not parse JSON",o))}},qt=(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 c=60-a.length;if(c<=0)return"";if(c>=s.length+6){let u=Math.min(c-s.length,e.length);return`${s}${e.slice(0,u)}`}return e.slice(0,c)},un=e=>!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).length===0?!1:!!Mt.some(t=>t in e),Wt=()=>{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 s=JSON.parse(o);un(s)&&(e[r]=s)}catch(s){let a=s instanceof SyntaxError?"Invalid JSON":s.message;Bt.error(`Could not parse ${r} model version override from ${n}: ${a}`)}}}),e},pn=50*1024,rt=(e,t=pn)=>{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 Kt}from"buffer";import dn from"path";var Vt=_("repo"),Xt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{Vt.info("Getting runner diffs");let o=await gn(r),{hasChanges:n}=o,{status:s}=o;if(!n)return{hasChanges:!1};if(!t){let T=hn(s);await yn(T,r)}Vt.info("Changes after processing"),await ot(r);let i=await st(s,r);if(await nt(i,r),n=await fn(r),!n)return{hasChanges:!1,ignored:i};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},c=await b("git",["diff",e.runSha,"HEAD"],a),u=String(c.stdout??"");if(n=!!u,!n)return await Jt(r),{hasChanges:!1,ignored:i};let d=await b("git",["diff",e.runSha,"HEAD","--binary"],a),p=String(d.stdout??""),m,y;if(e.sha){let T=await b("git",["diff",e.sha,"HEAD"],a);m=String(T.stdout??"");let R=await b("git",["diff",e.sha,"HEAD","--binary"],a),E=String(R.stdout??"");m!==E&&(y=Kt.from(E).toString("base64"))}await Jt(r);let h={hasChanges:!0,diff:u,resultDiff:m,ignored:i};return u!==p&&(h.diffBinary=Kt.from(p).toString("base64")),y&&(h.resultDiffBinary=y),h},Jt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await b("git",["reset","--soft","HEAD~1"],{cwd:e})},nt=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"}},ot=async(e=process.cwd())=>{let t=await b("git",["status","-s"],{cwd:e});return String(t.stdout??"")},zt=/.. (.+)?\.log$/,mn=[zt],gn=async(e=process.cwd())=>{let t=await ot(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 b("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},it=async(e=process.cwd())=>{let{stdout:t}=await b("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},Zt=async(e=process.cwd())=>{let{stdout:t}=await b("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},st=async(e,t=process.cwd())=>{e||=await ot(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build"],o=[];return e.split(`
10
10
  `).forEach(n=>{r.forEach(i=>{let a=n===`?? ${i}`,c=n.startsWith(`?? ${i}/`)||n.startsWith(`?? ${i}${dn.sep}`);(a||c)&&o.push(`:!${i}`)});let s=n.match(zt)?.[1];s&&o.push(`:!${s}.log`)}),o},at=async(e=process.cwd())=>{await b("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(""),c=n.trim(),u=s.trim();return r[a]?r[a].change=u:r[a]={filePath:a,stage:c,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 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 zn}from"module";import{createTracerProvider as xr}from"@
4
4
  ${s}
5
5
  </extracted_error_chunk>`).join(`
6
6
 
7
- `);return i.length>e.length*.8?e:i}import{execSync as En}from"child_process";import ir from"fs/promises";import wn from"path";import Q from"process";import{getTracer as _n}from"@netlify/otel";import we from"process";var oe=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},Et=e=>e instanceof oe;var ve=we.env.NETLIFY_API_URL,Ae=we.env.NETLIFY_API_TOKEN,q=_("api"),be=()=>we.env.NETLIFY_LOCAL_MODE==="true",_e=async(e,t={})=>{if(!ve||!Ae)throw new Error("No API URL or token");let r=new URL(e,ve),o={...t,headers:{...t.headers,Authorization:`Bearer ${Ae}`}};we.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(we.env.AGENT_RUNNERS_DEBUG==="true")q.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{q.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");q.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||q.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 oe(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new oe(`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},wt=e=>{q.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(ve=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Ae=e.constants.NETLIFY_API_TOKEN)},_t=()=>({apiUrl:ve,token:Ae}),Te=async(e,t)=>be()?(q.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):_e(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),D=async(e,t,r)=>be()?(q.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):_e(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Tt=async(e,t)=>be()?(q.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):_e(`/api/v1/agent_runners/${e}/sessions/${t}`),xt=(e,t,r)=>_e(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),It=async(e,t)=>be()?(q.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"}}):_e(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Be=async(e,t)=>{q.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 se=_("ai_gateway"),qe=null;var Rt=async()=>{if(qe)return qe;se.log("Fetching available AI gateway providers");let e=await fetch(`${_t().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 qe=t,se.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},br=async(e,t)=>{let o=(await Rt()).providers[e];if(!o)return se.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return se.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},St=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),se.log("Requesting AI gateway information");let c=await xt(s,t.id,t.sessionId);if({token:r,url:i}=c,o=c.expires_at?c.expires_at*1e3:void 0,se.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(),Rt()]),{get url(){return i},get token(){return r},isModelAvailableForProvider:br}};import W from"process";import z from"path";import Ce from"fs";import{fileURLToPath as Fr}from"url";import{createRequire as Lr}from"module";import{execa as Dr,execaCommand as No}from"execa";import{Transform as Cr}from"stream";var Pr=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"]),Nr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function kr(){return Object.entries(process.env).filter(([e,t])=>!(!t||Pr.has(e)||Nr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function V(e){if(typeof e!="string")return e;let t=kr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Or(o),"g");r=r.replace(n,"******")}),r}function Or(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ie=class extends Cr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=V(n);o(null,i)}};function vt(){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,At=e=>(xe&&xe.destroy(),xe=new X({totalAllowedTime:e}),xe),bt=()=>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 Ct="netlify-agent-runner-context.md",He="task-history",H=".netlify",ee="results.md",We="assets";var te=1800*1e3,w={Environment:"environment",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"};var Pt={name:"@netlify/agent-runner-cli",type:"module",version:"1.71.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.37","@anthropic-ai/sdk":"0.72.1","@google/gemini-cli":"0.27.3","@netlify/otel":"^5.1.1","@openai/codex":"0.93.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.208.0",execa:"^9.6.1",kaddidlehopper:"^0.1.2",minimist:"^1.2.8",openai:"6.17.0"}};var Mr=Fr(import.meta.url),Ur=z.dirname(Mr),Gr=Lr(import.meta.url),ae=_("shell"),Ke=new Set,jr={preferLocal:!0},C=(e,t,r)=>{let[o,n]=Yr(t,r),i={...jr,...n},s=Dr(e,o,i);Br(s,i),Hr(s);let a=r?.idleTimeout;return a&&a>0&&qr(s,a),s};var Yr=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},Br=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(W.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new ie).pipe(W.stdout),e.stdout?.pipe(new ie).pipe(W.stdout),e.stderr?.pipe(new ie).pipe(W.stderr);return}e.stdout?.pipe(W.stdout),e.stderr?.pipe(W.stderr)},Je=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(W.kill(-e.pid,t),ae.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ae.error("Error killing process:",r),!1}},Nt=e=>Je(e,"SIGKILL"),qr=(e,t)=>{let r=null,o=()=>{ae.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),Je(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ae.log(`Force killing idle process ${e.pid}`),Nt(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)},Hr=e=>{Ke.add(e);let t=bt();if(t){let r=t.onTimesUp(()=>{ae.log(`Global timer expired, killing process ${e.pid}`),Je(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ae.log(`Force killing process ${e.pid} after timeout`),Nt(e))},5e3)});e.on("exit",()=>{Ke.delete(e),r()}),e.on("error",()=>{Ke.delete(e),r()})}};function Z(e,t){if(!W.env.NETLIFY_LOCAL_MODE)try{let n=Gr.resolve(Pt.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(Ce.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(W.env.NODE_PATH){let n=z.join(W.env.NODE_PATH,".bin",t);if(Ce.existsSync(n))return n}let r=z.join(e,"node_modules",".bin",t);if(Ce.existsSync(r))return r;let o=z.join(Ur,"..","node_modules",".bin",t);if(Ce.existsSync(o))return o}var Wr=_("utils"),Kr=e=>new Promise(t=>{setTimeout(t,e)}),kt=(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 c,u=new Promise(d=>{c=d});return i=(async()=>{await Promise.resolve();let d=await e(...a);for(c(d);;){if(await Kr(t),!o)return r=!1,i=null,d;let p=o,m=n;o=null,n=[],d=await e(...p),m.forEach(y=>{y(d)})}})(),u};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},le=(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},Ot=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):Wr.error("Could not parse JSON",o))}},$t=(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 Jr=50*1024,Ve=(e,t=Jr)=>{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 Ft}from"buffer";import Vr from"path";var Lt=_("repo"),Mt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{Lt.info("Getting runner diffs");let o=await Xr(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let T=Qr(i);await en(T,r)}Lt.info("Changes after processing"),await Xe(r);let s=await Qe(i,r);if(await ze(s,r),n=await Zr(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 Dt(r),{hasChanges:!1,ignored:s};let d=await C("git",["diff",e.runSha,"HEAD","--binary"],a),p=String(d.stdout??""),m,y;if(e.sha){let T=await C("git",["diff",e.sha,"HEAD"],a);m=String(T.stdout??"");let x=await C("git",["diff",e.sha,"HEAD","--binary"],a),E=String(x.stdout??"");m!==E&&(y=Ft.from(E).toString("base64"))}await Dt(r);let h={hasChanges:!0,diff:u,resultDiff:m,ignored:s};return u!==p&&(h.diffBinary=Ft.from(p).toString("base64")),y&&(h.resultDiffBinary=y),h},Dt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await C("git",["reset","--soft","HEAD~1"],{cwd:e})},ze=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"}},Xe=async(e=process.cwd())=>{let t=await C("git",["status","-s"],{cwd:e});return String(t.stdout??"")},Ut=/.. (.+)?\.log$/,zr=[Ut],Xr=async(e=process.cwd())=>{let t=await Xe(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
7
+ `);return i.length>e.length*.8?e:i}import{execSync as En}from"child_process";import ir from"fs/promises";import wn from"path";import Q from"process";import{getTracer as _n}from"@netlify/otel";import we from"process";var oe=class extends Error{constructor(r,o,n){super(r);this.statusCode=o;this.userMessage=n;this.name="GracefulShutdownError"}},Et=e=>e instanceof oe;var ve=we.env.NETLIFY_API_URL,Ae=we.env.NETLIFY_API_TOKEN,q=_("api"),be=()=>we.env.NETLIFY_LOCAL_MODE==="true",_e=async(e,t={})=>{if(!ve||!Ae)throw new Error("No API URL or token");let r=new URL(e,ve),o={...t,headers:{...t.headers,Authorization:`Bearer ${Ae}`}};we.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(we.env.AGENT_RUNNERS_DEBUG==="true")q.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{q.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");q.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||q.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 oe(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===403&&t.gracefulOn403?new oe(`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},wt=e=>{q.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(ve=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Ae=e.constants.NETLIFY_API_TOKEN)},_t=()=>({apiUrl:ve,token:Ae}),Te=async(e,t)=>be()?(q.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):_e(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),D=async(e,t,r)=>be()?(q.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):_e(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Tt=async(e,t)=>be()?(q.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):_e(`/api/v1/agent_runners/${e}/sessions/${t}`),xt=(e,t,r)=>_e(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn403:!0}),It=async(e,t)=>be()?(q.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"}}):_e(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Be=async(e,t)=>{q.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 se=_("ai_gateway"),qe=null;var Rt=async()=>{if(qe)return qe;se.log("Fetching available AI gateway providers");let e=await fetch(`${_t().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 qe=t,se.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},br=async(e,t)=>{let o=(await Rt()).providers[e];if(!o)return se.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return se.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},St=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),se.log("Requesting AI gateway information");let c=await xt(s,t.id,t.sessionId);if({token:r,url:i}=c,o=c.expires_at?c.expires_at*1e3:void 0,se.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(),Rt()]),{get url(){return i},get token(){return r},isModelAvailableForProvider:br}};import W from"process";import z from"path";import Ce from"fs";import{fileURLToPath as Fr}from"url";import{createRequire as Lr}from"module";import{execa as Dr,execaCommand as No}from"execa";import{Transform as Cr}from"stream";var Pr=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"]),Nr=new Set(["true","false","undefined","null","deploy","project","claude","gemini","codex",""]);function kr(){return Object.entries(process.env).filter(([e,t])=>!(!t||Pr.has(e)||Nr.has(t)||!isNaN(Number(t))||t.length<5)).map(([,e])=>e).filter(Boolean)}function V(e){if(typeof e!="string")return e;let t=kr();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(Or(o),"g");r=r.replace(n,"******")}),r}function Or(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ie=class extends Cr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=V(n);o(null,i)}};function vt(){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,At=e=>(xe&&xe.destroy(),xe=new X({totalAllowedTime:e}),xe),bt=()=>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 Ct="netlify-agent-runner-context.md",He="task-history",H=".netlify",ee="results.md",We="assets";var te=1800*1e3,w={Environment:"environment",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"};var Pt={name:"@netlify/agent-runner-cli",type:"module",version:"1.72.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.45","@anthropic-ai/sdk":"0.72.1","@google/gemini-cli":"0.27.3","@netlify/otel":"^5.1.1","@openai/codex":"0.93.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.208.0",execa:"^9.6.1",kaddidlehopper:"^0.1.2",minimist:"^1.2.8",openai:"6.17.0"}};var Mr=Fr(import.meta.url),Ur=z.dirname(Mr),Gr=Lr(import.meta.url),ae=_("shell"),Ke=new Set,jr={preferLocal:!0},C=(e,t,r)=>{let[o,n]=Yr(t,r),i={...jr,...n},s=Dr(e,o,i);Br(s,i),Hr(s);let a=r?.idleTimeout;return a&&a>0&&qr(s,a),s};var Yr=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},Br=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(W.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new ie).pipe(W.stdout),e.stdout?.pipe(new ie).pipe(W.stdout),e.stderr?.pipe(new ie).pipe(W.stderr);return}e.stdout?.pipe(W.stdout),e.stderr?.pipe(W.stderr)},Je=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(W.kill(-e.pid,t),ae.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ae.error("Error killing process:",r),!1}},Nt=e=>Je(e,"SIGKILL"),qr=(e,t)=>{let r=null,o=()=>{ae.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),Je(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ae.log(`Force killing idle process ${e.pid}`),Nt(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)},Hr=e=>{Ke.add(e);let t=bt();if(t){let r=t.onTimesUp(()=>{ae.log(`Global timer expired, killing process ${e.pid}`),Je(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ae.log(`Force killing process ${e.pid} after timeout`),Nt(e))},5e3)});e.on("exit",()=>{Ke.delete(e),r()}),e.on("error",()=>{Ke.delete(e),r()})}};function Z(e,t){if(!W.env.NETLIFY_LOCAL_MODE)try{let n=Gr.resolve(Pt.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(Ce.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(W.env.NODE_PATH){let n=z.join(W.env.NODE_PATH,".bin",t);if(Ce.existsSync(n))return n}let r=z.join(e,"node_modules",".bin",t);if(Ce.existsSync(r))return r;let o=z.join(Ur,"..","node_modules",".bin",t);if(Ce.existsSync(o))return o}var Wr=_("utils"),Kr=e=>new Promise(t=>{setTimeout(t,e)}),kt=(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 c,u=new Promise(d=>{c=d});return i=(async()=>{await Promise.resolve();let d=await e(...a);for(c(d);;){if(await Kr(t),!o)return r=!1,i=null,d;let p=o,m=n;o=null,n=[],d=await e(...p),m.forEach(y=>{y(d)})}})(),u};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},le=(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},Ot=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):Wr.error("Could not parse JSON",o))}},$t=(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 Jr=50*1024,Ve=(e,t=Jr)=>{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 Ft}from"buffer";import Vr from"path";var Lt=_("repo"),Mt=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{Lt.info("Getting runner diffs");let o=await Xr(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let T=Qr(i);await en(T,r)}Lt.info("Changes after processing"),await Xe(r);let s=await Qe(i,r);if(await ze(s,r),n=await Zr(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 Dt(r),{hasChanges:!1,ignored:s};let d=await C("git",["diff",e.runSha,"HEAD","--binary"],a),p=String(d.stdout??""),m,y;if(e.sha){let T=await C("git",["diff",e.sha,"HEAD"],a);m=String(T.stdout??"");let x=await C("git",["diff",e.sha,"HEAD","--binary"],a),E=String(x.stdout??"");m!==E&&(y=Ft.from(E).toString("base64"))}await Dt(r);let h={hasChanges:!0,diff:u,resultDiff:m,ignored:s};return u!==p&&(h.diffBinary=Ft.from(p).toString("base64")),y&&(h.resultDiffBinary=y),h},Dt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await C("git",["reset","--soft","HEAD~1"],{cwd:e})},ze=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"}},Xe=async(e=process.cwd())=>{let t=await C("git",["status","-s"],{cwd:e});return String(t.stdout??"")},Ut=/.. (.+)?\.log$/,zr=[Ut],Xr=async(e=process.cwd())=>{let t=await Xe(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
8
8
  `).filter(n=>zr.some(s=>s instanceof RegExp?s.test(n):n===s)?!1:n[1]?.trim()!=="")).length!==0,status:t}},Zr=async(e=process.cwd())=>{try{return await C("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},Ze=async(e=process.cwd())=>{let{stdout:t}=await C("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},Gt=async(e=process.cwd())=>{let{stdout:t}=await C("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},Qe=async(e,t=process.cwd())=>{e||=await Xe(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build"],o=[];return e.split(`
9
9
  `).forEach(n=>{r.forEach(s=>{let a=n===`?? ${s}`,c=n.startsWith(`?? ${s}/`)||n.startsWith(`?? ${s}${Vr.sep}`);(a||c)&&o.push(`:!${s}`)});let i=n.match(Ut)?.[1];i&&o.push(`:!${i}.log`)}),o},et=async(e=process.cwd())=>{await C("git",["reset","--hard","HEAD"],{cwd:e})},Qr=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)},en=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(`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@netlify/agent-runner-cli",
3
3
  "type": "module",
4
- "version": "1.71.0",
4
+ "version": "1.72.0",
5
5
  "description": "CLI tool for running Netlify agents",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -78,7 +78,7 @@
78
78
  "vitest": "^4.0.16"
79
79
  },
80
80
  "dependencies": {
81
- "@anthropic-ai/claude-code": "2.1.37",
81
+ "@anthropic-ai/claude-code": "2.1.45",
82
82
  "@anthropic-ai/sdk": "0.72.1",
83
83
  "@google/gemini-cli": "0.27.3",
84
84
  "@netlify/otel": "^5.1.1",