@netlify/agent-runner-cli 1.93.3 → 1.93.4
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 G from"process";import Zr from"path";import Qr from"fs";import Oo from"mi
|
|
|
5
5
|
${s}
|
|
6
6
|
</extracted_error_chunk>`).join(`
|
|
7
7
|
|
|
8
|
-
`);return i.length>e.length*.8?e:i}import{execSync as Qn}from"child_process";import Cr from"fs/promises";import eo from"path";import _e from"process";import{getTracer as to}from"@netlify/otel";import Oe from"process";var re=class extends Error{constructor(r,o,n,i=!1){super(r);this.statusCode=o;this.userMessage=n;this.isCreditLimitExceeded=i;this.name="GracefulShutdownError"}},We=e=>e instanceof re;var Je=Oe.env.NETLIFY_API_URL,Ke=Oe.env.NETLIFY_API_TOKEN,W=I("api"),Te=()=>Oe.env.NETLIFY_LOCAL_MODE==="true",ue=async(e,t={})=>{if(!Je||!Ke)throw new Error("No API URL or token");let r=new URL(e,Je),o={...t,headers:{...t.headers,Authorization:`Bearer ${Ke}`}};Oe.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(Oe.env.AGENT_RUNNERS_DEBUG==="true")W.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{W.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");W.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||W.error(`Got status ${n.status} for request ${r}`),t.raw){if(!i)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let s=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let a=typeof s=="string"?s:JSON.stringify(s);throw n.status===404?new re(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&a.toLowerCase().includes("usage exceeded")?new re(`API request failed: 503 - ${a}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${a}`)}return s},Bt=e=>{W.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Je=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Ke=e.constants.NETLIFY_API_TOKEN)},Ht=()=>({apiUrl:Je,token:Ke}),Fe=async(e,t)=>Te()?(W.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):ue(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),J=async(e,t,r)=>Te()?(W.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):ue(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Wt=async e=>Te()?(W.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):ue(`/api/v1/sites/${e}`),Jt=async(e,t)=>Te()?(W.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):ue(`/api/v1/agent_runners/${e}/sessions/${t}`),Kt=(e,t,r)=>ue(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Vt=(e,t,r)=>ue(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),zt=async(e,t)=>Te()?(W.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):ue(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Xt=async(e,t)=>Te()?(W.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):ue(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),ct=async(e,t,{maxRetries:r=3,baseDelayMs:o=500}={})=>{W.log(`Uploading diff to S3: ${e.substring(0,50)}...`);for(let n=1;n<=r;n++)try{let i=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!i.ok)throw new Error(`S3 upload failed with status ${i.status}`);return i}catch(i){if(n===r)throw i;let s=o*2**(n-1);W.warn(`S3 upload attempt ${n}/${r} failed: ${i.message}. Retrying in ${s}ms...`),await new Promise(a=>setTimeout(a,s))}};var Ie=I("ai_gateway"),ut=null;var Ve=async()=>{if(ut)return ut;Ie.log("Fetching available AI gateway providers");let e=await fetch(`${Ht().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 ut=t,Ie.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},ln=async(e,t)=>{let o=(await Ve()).providers[e];if(!o)return Ie.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return Ie.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Zt=async({config:e})=>{let t,r,o,n,i=!e.site?.published_deploy;if(!(i?e.accountId:e.siteId))throw new Error(`No entity id for ${i?"account":"site"}`);let a=async()=>{clearTimeout(o),Ie.log("Requesting AI gateway information");let l=await(i?Kt(e.accountId,e.id,e.sessionId):Vt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=l,r=l.expires_at?l.expires_at*1e3:void 0,Ie.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let u=r-Date.now()-6e4;u>0&&(o=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Ve()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:ln}};import ne from"process";import se from"path";import ze from"fs";import{fileURLToPath as fn}from"url";import{createRequire as hn}from"module";import{execa as yn,execaCommand as mi}from"execa";import{Transform as cn}from"stream";function un(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function dn(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function pn(){let t=un().map(r=>process.env[r]).filter(r=>!(!r||dn(r)));return[...new Set(t)].sort((r,o)=>o.length-r.length)}function ie(e){if(typeof e!="string")return e;let t=pn();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(mn(o),"g");r=r.replace(n,"******")}),r}function mn(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var Se=class extends cn{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=ie(n);o(null,i)}};function Qt(){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"?ie(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"?ie(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var Le=null,er=e=>(Le&&Le.destroy(),Le=new de({totalAllowedTime:e}),Le),tr=()=>Le;var de=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 rr="netlify-agent-runner-context.md",dt="task-history",V=".netlify",fe="results.md",pt="assets",nr="features";var or="free";var he=1800*1e3,f={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var ir={name:"@netlify/agent-runner-cli",type:"module",version:"1.93.3",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","test:integration:skill-invocation":"vitest run test/integration/skill-invocation.test.ts","test:integration:feature-enablement":"vitest run test/integration/feature-enablement.test.ts","check:types":"tsc --noEmit",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.81","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.5","@netlify/ts-cli":"^1.0.4","@openai/codex":"0.115.0","@opentelemetry/exporter-trace-otlp-grpc":"0.57.2",execa:"^9.6.1",minimist:"^1.2.8",openai:"6.26.0"}};var wn=fn(import.meta.url),_n=se.dirname(wn),En=hn(import.meta.url),ve=I("shell"),mt=new Set,xn={preferLocal:!0},k=(e,t,r)=>{let[o,n]=Tn(t,r),i={...xn,...n},s=yn(e,o,i);In(s,i),vn(s);let a=r?.idleTimeout;return a&&a>0&&Sn(s,a),s};var Tn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},In=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(ne.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new Se).pipe(ne.stdout),e.stdout?.pipe(new Se).pipe(ne.stdout),e.stderr?.pipe(new Se).pipe(ne.stderr);return}e.stdout?.pipe(ne.stdout),e.stderr?.pipe(ne.stderr)},gt=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(ne.kill(-e.pid,t),ve.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ve.error("Error killing process:",r),!1}},sr=e=>gt(e,"SIGKILL"),Sn=(e,t)=>{let r=null,o=()=>{ve.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),gt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ve.log(`Force killing idle process ${e.pid}`),sr(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)},vn=e=>{mt.add(e);let t=tr();if(t){let r=t.onTimesUp(()=>{ve.log(`Global timer expired, killing process ${e.pid}`),gt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ve.log(`Force killing process ${e.pid} after timeout`),sr(e))},5e3)});e.on("exit",()=>{mt.delete(e),r()}),e.on("error",()=>{mt.delete(e),r()})}};function Xe(e,t){return!!ae(e,t)}function ae(e,t){if(!ne.env.NETLIFY_LOCAL_MODE)try{let n=En.resolve(ir.name),i=se.dirname(n);for(;i!==se.dirname(i);){let s=se.dirname(i);if(se.basename(s)==="node_modules"){let a=se.join(s,".bin",t);if(ze.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(ne.env.NODE_PATH){let n=se.join(ne.env.NODE_PATH,".bin",t);if(ze.existsSync(n))return n}let r=se.join(e,"node_modules",".bin",t);if(ze.existsSync(r))return r;let o=se.join(_n,"..","node_modules",".bin",t);if(ze.existsSync(o))return o}var bn=I("utils"),Rn=e=>new Promise(t=>{setTimeout(t,e)}),Ze=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(u=>{n.push(u)});r=!0;let c,l=new Promise(u=>{c=u});return i=(async()=>{await Promise.resolve();let u=await e(...a);for(c(u);;){if(await Rn(t),!o)return r=!1,i=null,u;let m=o,p=n;o=null,n=[],u=await e(...m),p.forEach(g=>{g(u)})}})(),l};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},be=(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},ar=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):bn.error("Could not parse JSON",o))}},ft=e=>e.charAt(0).toUpperCase()+e.slice(1),pe=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():ft(t)).join(" ");function ye(e,t){t&&e.log(`Skill invoked: ${t}`)}var lr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),cr=(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 l=Math.min(c-i.length,e.length);return`${i}${e.slice(0,l)}`}return e.slice(0,c)};var An=1e4,ht=(e,t=An)=>{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 ur}from"buffer";import Cn from"path";var dr=I("repo"),mr=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{dr.info("Getting runner diffs");let o=await Pn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let _=$n(i);await On(_,r)}dr.info("Changes after processing"),await wt(r);let s=await _t(i,r);if(await yt(s,r),n=await Nn(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await k("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},c=await k("git",["diff",e.runSha,"HEAD"],a),l=String(c.stdout??"");if(n=!!l,!n)return await pr(r),{hasChanges:!1,ignored:s};let u=await k("git",["diff",e.runSha,"HEAD","--binary"],a),m=String(u.stdout??""),p,g;if(e.sha){let _=await k("git",["diff",e.sha,"HEAD"],a);p=String(_.stdout??"");let x=await k("git",["diff",e.sha,"HEAD","--binary"],a),y=String(x.stdout??"");p!==y&&(g=ur.from(y).toString("base64"))}await pr(r);let T={hasChanges:!0,diff:l,resultDiff:p,ignored:s};return l!==m&&(T.diffBinary=ur.from(m).toString("base64")),g&&(T.resultDiffBinary=g),T},pr=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await k("git",["reset","--soft","HEAD~1"],{cwd:e})},yt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await k("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},wt=async(e=process.cwd())=>{let t=await k("git",["status","-s"],{cwd:e});return String(t.stdout??"")},gr=/.. (.+)?\.log$/,kn=[gr],Pn=async(e=process.cwd())=>{let t=await wt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
8
|
+
`);return i.length>e.length*.8?e:i}import{execSync as Qn}from"child_process";import Cr from"fs/promises";import eo from"path";import _e from"process";import{getTracer as to}from"@netlify/otel";import Oe from"process";var re=class extends Error{constructor(r,o,n,i=!1){super(r);this.statusCode=o;this.userMessage=n;this.isCreditLimitExceeded=i;this.name="GracefulShutdownError"}},We=e=>e instanceof re;var Je=Oe.env.NETLIFY_API_URL,Ke=Oe.env.NETLIFY_API_TOKEN,W=I("api"),Te=()=>Oe.env.NETLIFY_LOCAL_MODE==="true",ue=async(e,t={})=>{if(!Je||!Ke)throw new Error("No API URL or token");let r=new URL(e,Je),o={...t,headers:{...t.headers,Authorization:`Bearer ${Ke}`}};Oe.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(Oe.env.AGENT_RUNNERS_DEBUG==="true")W.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{W.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");W.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||W.error(`Got status ${n.status} for request ${r}`),t.raw){if(!i)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let s=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let a=typeof s=="string"?s:JSON.stringify(s);throw n.status===404?new re(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&a.toLowerCase().includes("usage exceeded")?new re(`API request failed: 503 - ${a}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${a}`)}return s},Bt=e=>{W.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Je=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Ke=e.constants.NETLIFY_API_TOKEN)},Ht=()=>({apiUrl:Je,token:Ke}),Fe=async(e,t)=>Te()?(W.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):ue(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),J=async(e,t,r)=>Te()?(W.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):ue(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Wt=async e=>Te()?(W.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):ue(`/api/v1/sites/${e}`),Jt=async(e,t)=>Te()?(W.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):ue(`/api/v1/agent_runners/${e}/sessions/${t}`),Kt=(e,t,r)=>ue(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Vt=(e,t,r)=>ue(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),zt=async(e,t)=>Te()?(W.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):ue(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Xt=async(e,t)=>Te()?(W.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):ue(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),ct=async(e,t,{maxRetries:r=3,baseDelayMs:o=500}={})=>{W.log(`Uploading diff to S3: ${e.substring(0,50)}...`);for(let n=1;n<=r;n++)try{let i=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!i.ok)throw new Error(`S3 upload failed with status ${i.status}`);return i}catch(i){if(n===r)throw i;let s=o*2**(n-1);W.warn(`S3 upload attempt ${n}/${r} failed: ${i.message}. Retrying in ${s}ms...`),await new Promise(a=>setTimeout(a,s))}};var Ie=I("ai_gateway"),ut=null;var Ve=async()=>{if(ut)return ut;Ie.log("Fetching available AI gateway providers");let e=await fetch(`${Ht().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 ut=t,Ie.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},ln=async(e,t)=>{let o=(await Ve()).providers[e];if(!o)return Ie.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return Ie.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Zt=async({config:e})=>{let t,r,o,n,i=!e.site?.published_deploy;if(!(i?e.accountId:e.siteId))throw new Error(`No entity id for ${i?"account":"site"}`);let a=async()=>{clearTimeout(o),Ie.log("Requesting AI gateway information");let l=await(i?Kt(e.accountId,e.id,e.sessionId):Vt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=l,r=l.expires_at?l.expires_at*1e3:void 0,Ie.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let u=r-Date.now()-6e4;u>0&&(o=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Ve()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:ln}};import ne from"process";import se from"path";import ze from"fs";import{fileURLToPath as fn}from"url";import{createRequire as hn}from"module";import{execa as yn,execaCommand as mi}from"execa";import{Transform as cn}from"stream";function un(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function dn(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function pn(){let t=un().map(r=>process.env[r]).filter(r=>!(!r||dn(r)));return[...new Set(t)].sort((r,o)=>o.length-r.length)}function ie(e){if(typeof e!="string")return e;let t=pn();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(mn(o),"g");r=r.replace(n,"******")}),r}function mn(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var Se=class extends cn{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=ie(n);o(null,i)}};function Qt(){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"?ie(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"?ie(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var Le=null,er=e=>(Le&&Le.destroy(),Le=new de({totalAllowedTime:e}),Le),tr=()=>Le;var de=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 rr="netlify-agent-runner-context.md",dt="task-history",V=".netlify",fe="results.md",pt="assets",nr="features";var or="free";var he=1800*1e3,f={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var ir={name:"@netlify/agent-runner-cli",type:"module",version:"1.93.4",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","test:integration:skill-invocation":"vitest run test/integration/skill-invocation.test.ts","test:integration:feature-enablement":"vitest run test/integration/feature-enablement.test.ts","check:types":"tsc --noEmit",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.81","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.5","@netlify/ts-cli":"^1.0.4","@openai/codex":"0.115.0","@opentelemetry/exporter-trace-otlp-grpc":"0.57.2",execa:"^9.6.1",minimist:"^1.2.8",openai:"6.26.0"}};var wn=fn(import.meta.url),_n=se.dirname(wn),En=hn(import.meta.url),ve=I("shell"),mt=new Set,xn={preferLocal:!0},k=(e,t,r)=>{let[o,n]=Tn(t,r),i={...xn,...n},s=yn(e,o,i);In(s,i),vn(s);let a=r?.idleTimeout;return a&&a>0&&Sn(s,a),s};var Tn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},In=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(ne.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new Se).pipe(ne.stdout),e.stdout?.pipe(new Se).pipe(ne.stdout),e.stderr?.pipe(new Se).pipe(ne.stderr);return}e.stdout?.pipe(ne.stdout),e.stderr?.pipe(ne.stderr)},gt=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(ne.kill(-e.pid,t),ve.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ve.error("Error killing process:",r),!1}},sr=e=>gt(e,"SIGKILL"),Sn=(e,t)=>{let r=null,o=()=>{ve.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),gt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ve.log(`Force killing idle process ${e.pid}`),sr(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)},vn=e=>{mt.add(e);let t=tr();if(t){let r=t.onTimesUp(()=>{ve.log(`Global timer expired, killing process ${e.pid}`),gt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ve.log(`Force killing process ${e.pid} after timeout`),sr(e))},5e3)});e.on("exit",()=>{mt.delete(e),r()}),e.on("error",()=>{mt.delete(e),r()})}};function Xe(e,t){return!!ae(e,t)}function ae(e,t){if(!ne.env.NETLIFY_LOCAL_MODE)try{let n=En.resolve(ir.name),i=se.dirname(n);for(;i!==se.dirname(i);){let s=se.dirname(i);if(se.basename(s)==="node_modules"){let a=se.join(s,".bin",t);if(ze.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(ne.env.NODE_PATH){let n=se.join(ne.env.NODE_PATH,".bin",t);if(ze.existsSync(n))return n}let r=se.join(e,"node_modules",".bin",t);if(ze.existsSync(r))return r;let o=se.join(_n,"..","node_modules",".bin",t);if(ze.existsSync(o))return o}var bn=I("utils"),Rn=e=>new Promise(t=>{setTimeout(t,e)}),Ze=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(u=>{n.push(u)});r=!0;let c,l=new Promise(u=>{c=u});return i=(async()=>{await Promise.resolve();let u=await e(...a);for(c(u);;){if(await Rn(t),!o)return r=!1,i=null,u;let m=o,p=n;o=null,n=[],u=await e(...m),p.forEach(g=>{g(u)})}})(),l};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},be=(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},ar=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):bn.error("Could not parse JSON",o))}},ft=e=>e.charAt(0).toUpperCase()+e.slice(1),pe=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():ft(t)).join(" ");function ye(e,t){t&&e.log(`Skill invoked: ${t}`)}var lr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),cr=(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 l=Math.min(c-i.length,e.length);return`${i}${e.slice(0,l)}`}return e.slice(0,c)};var An=1e4,ht=(e,t=An)=>{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 ur}from"buffer";import Cn from"path";var dr=I("repo"),mr=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{dr.info("Getting runner diffs");let o=await Pn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let _=$n(i);await On(_,r)}dr.info("Changes after processing"),await wt(r);let s=await _t(i,r);if(await yt(s,r),n=await Nn(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await k("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},c=await k("git",["diff",e.runSha,"HEAD"],a),l=String(c.stdout??"");if(n=!!l,!n)return await pr(r),{hasChanges:!1,ignored:s};let u=await k("git",["diff",e.runSha,"HEAD","--binary"],a),m=String(u.stdout??""),p,g;if(e.sha){let _=await k("git",["diff",e.sha,"HEAD"],a);p=String(_.stdout??"");let x=await k("git",["diff",e.sha,"HEAD","--binary"],a),y=String(x.stdout??"");p!==y&&(g=ur.from(y).toString("base64"))}await pr(r);let T={hasChanges:!0,diff:l,resultDiff:p,ignored:s};return l!==m&&(T.diffBinary=ur.from(m).toString("base64")),g&&(T.resultDiffBinary=g),T},pr=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await k("git",["reset","--soft","HEAD~1"],{cwd:e})},yt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await k("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},wt=async(e=process.cwd())=>{let t=await k("git",["status","-s"],{cwd:e});return String(t.stdout??"")},gr=/.. (.+)?\.log$/,kn=[gr],Pn=async(e=process.cwd())=>{let t=await wt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
9
9
|
`).filter(n=>kn.some(s=>s instanceof RegExp?s.test(n):n===s)?!1:n[1]?.trim()!=="")).length!==0,status:t}},Nn=async(e=process.cwd())=>{try{return await k("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},De=async(e=process.cwd())=>{let{stdout:t}=await k("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},fr=async(e=process.cwd())=>{let{stdout:t}=await k("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},_t=async(e,t=process.cwd())=>{e||=await wt(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build","CLAUDE.local.md"],o=[];return e.split(`
|
|
10
10
|
`).forEach(n=>{r.forEach(s=>{let a=n===`?? ${s}`,c=n.startsWith(`?? ${s}/`)||n.startsWith(`?? ${s}${Cn.sep}`);(a||c)&&o.push(`:!${s}`)});let i=n.match(gr)?.[1];i&&o.push(`:!${i}.log`)}),o},Et=async(e=process.cwd())=>{await k("git",["reset","--hard","HEAD"],{cwd:e})},$n=e=>{let t=e.split(`
|
|
11
11
|
`).reduce((r,o)=>{if(!o)return r;let[n,i,,...s]=o,a=s.join(""),c=n.trim(),l=i.trim();return r[a]?r[a].change=l:r[a]={filePath:a,stage:c,change:l},r},{});return Object.values(t)},On=async(e,t=process.cwd())=>{let r=e.filter(o=>o.stage&&!o.change).map(o=>o.filePath);r.length!==0&&await k("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
|
package/dist/bin.js
CHANGED
|
@@ -5,7 +5,7 @@ import jt from"process";import Vo from"minimist";import{createRequire as Lo}from
|
|
|
5
5
|
${s}
|
|
6
6
|
</extracted_error_chunk>`).join(`
|
|
7
7
|
|
|
8
|
-
`);return i.length>e.length*.8?e:i}import{execSync as oo}from"child_process";import Fr from"fs/promises";import io from"path";import ye from"process";import{getTracer as so}from"@netlify/otel";import Oe from"process";var ee=class extends Error{constructor(r,o,n,i=!1){super(r);this.statusCode=o;this.userMessage=n;this.isCreditLimitExceeded=i;this.name="GracefulShutdownError"}},He=e=>e instanceof ee;var We=Oe.env.NETLIFY_API_URL,Ve=Oe.env.NETLIFY_API_TOKEN,H=I("api"),we=()=>Oe.env.NETLIFY_LOCAL_MODE==="true",ae=async(e,t={})=>{if(!We||!Ve)throw new Error("No API URL or token");let r=new URL(e,We),o={...t,headers:{...t.headers,Authorization:`Bearer ${Ve}`}};Oe.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(Oe.env.AGENT_RUNNERS_DEBUG==="true")H.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{H.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");H.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||H.error(`Got status ${n.status} for request ${r}`),t.raw){if(!i)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let s=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let a=typeof s=="string"?s:JSON.stringify(s);throw n.status===404?new ee(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&a.toLowerCase().includes("usage exceeded")?new ee(`API request failed: 503 - ${a}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${a}`)}return s},Vt=e=>{H.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(We=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Ve=e.constants.NETLIFY_API_TOKEN)},Jt=()=>({apiUrl:We,token:Ve}),$e=async(e,t)=>we()?(H.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):ae(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),W=async(e,t,r)=>we()?(H.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):ae(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Kt=async e=>we()?(H.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):ae(`/api/v1/sites/${e}`),zt=async(e,t)=>we()?(H.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):ae(`/api/v1/agent_runners/${e}/sessions/${t}`),Xt=(e,t,r)=>ae(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Zt=(e,t,r)=>ae(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Qt=async(e,t)=>we()?(H.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):ae(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),er=async(e,t)=>we()?(H.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):ae(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),lt=async(e,t,{maxRetries:r=3,baseDelayMs:o=500}={})=>{H.log(`Uploading diff to S3: ${e.substring(0,50)}...`);for(let n=1;n<=r;n++)try{let i=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!i.ok)throw new Error(`S3 upload failed with status ${i.status}`);return i}catch(i){if(n===r)throw i;let s=o*2**(n-1);H.warn(`S3 upload attempt ${n}/${r} failed: ${i.message}. Retrying in ${s}ms...`),await new Promise(a=>setTimeout(a,s))}};var Te=I("ai_gateway"),ct=null;var Je=async()=>{if(ct)return ct;Te.log("Fetching available AI gateway providers");let e=await fetch(`${Jt().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 ct=t,Te.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},mn=async(e,t)=>{let o=(await Je()).providers[e];if(!o)return Te.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return Te.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},tr=async({config:e})=>{let t,r,o,n,i=!e.site?.published_deploy;if(!(i?e.accountId:e.siteId))throw new Error(`No entity id for ${i?"account":"site"}`);let a=async()=>{clearTimeout(o),Te.log("Requesting AI gateway information");let l=await(i?Xt(e.accountId,e.id,e.sessionId):Zt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=l,r=l.expires_at?l.expires_at*1e3:void 0,Te.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let u=r-Date.now()-6e4;u>0&&(o=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Je()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:mn}};import te from"process";import oe from"path";import Ke from"fs";import{fileURLToPath as wn}from"url";import{createRequire as Tn}from"module";import{execa as xn,execaCommand as Si}from"execa";import{Transform as gn}from"stream";function fn(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function hn(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function yn(){let t=fn().map(r=>process.env[r]).filter(r=>!(!r||hn(r)));return[...new Set(t)].sort((r,o)=>o.length-r.length)}function ne(e){if(typeof e!="string")return e;let t=yn();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(_n(o),"g");r=r.replace(n,"******")}),r}function _n(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var xe=class extends gn{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=ne(n);o(null,i)}};function rr(){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"?ne(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"?ne(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var Fe=null,nr=e=>(Fe&&Fe.destroy(),Fe=new le({totalAllowedTime:e}),Fe),or=()=>Fe;var le=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 ir="netlify-agent-runner-context.md",ut="task-history",J=".netlify",me="results.md",dt="assets",sr="features",pt="other",mt="personal";var gt="enterprise",Le="free",ar=[mt,"pro",gt,Le],lr=["normal","redeploy","create","ask","dtn-prod-iteration","rebase"],cr="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.",ge=1800*1e3,f={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var ur={name:"@netlify/agent-runner-cli",type:"module",version:"1.93.3",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","test:integration:skill-invocation":"vitest run test/integration/skill-invocation.test.ts","test:integration:feature-enablement":"vitest run test/integration/feature-enablement.test.ts","check:types":"tsc --noEmit",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.81","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.5","@netlify/ts-cli":"^1.0.4","@openai/codex":"0.115.0","@opentelemetry/exporter-trace-otlp-grpc":"0.57.2",execa:"^9.6.1",minimist:"^1.2.8",openai:"6.26.0"}};var In=wn(import.meta.url),vn=oe.dirname(In),Sn=Tn(import.meta.url),Ie=I("shell"),ft=new Set,Rn={preferLocal:!0},N=(e,t,r)=>{let[o,n]=bn(t,r),i={...Rn,...n},s=xn(e,o,i);An(s,i),Pn(s);let a=r?.idleTimeout;return a&&a>0&&Cn(s,a),s};var bn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},An=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(te.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new xe).pipe(te.stdout),e.stdout?.pipe(new xe).pipe(te.stdout),e.stderr?.pipe(new xe).pipe(te.stderr);return}e.stdout?.pipe(te.stdout),e.stderr?.pipe(te.stderr)},ht=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(te.kill(-e.pid,t),Ie.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return Ie.error("Error killing process:",r),!1}},dr=e=>ht(e,"SIGKILL"),Cn=(e,t)=>{let r=null,o=()=>{Ie.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),ht(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(Ie.log(`Force killing idle process ${e.pid}`),dr(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)},Pn=e=>{ft.add(e);let t=or();if(t){let r=t.onTimesUp(()=>{Ie.log(`Global timer expired, killing process ${e.pid}`),ht(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(Ie.log(`Force killing process ${e.pid} after timeout`),dr(e))},5e3)});e.on("exit",()=>{ft.delete(e),r()}),e.on("error",()=>{ft.delete(e),r()})}};function ce(e,t){if(!te.env.NETLIFY_LOCAL_MODE)try{let n=Sn.resolve(ur.name),i=oe.dirname(n);for(;i!==oe.dirname(i);){let s=oe.dirname(i);if(oe.basename(s)==="node_modules"){let a=oe.join(s,".bin",t);if(Ke.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(te.env.NODE_PATH){let n=oe.join(te.env.NODE_PATH,".bin",t);if(Ke.existsSync(n))return n}let r=oe.join(e,"node_modules",".bin",t);if(Ke.existsSync(r))return r;let o=oe.join(vn,"..","node_modules",".bin",t);if(Ke.existsSync(o))return o}var pr=I("utils"),kn=e=>new Promise(t=>{setTimeout(t,e)}),ze=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(u=>{n.push(u)});r=!0;let c,l=new Promise(u=>{c=u});return i=(async()=>{await Promise.resolve();let u=await e(...a);for(c(u);;){if(await kn(t),!o)return r=!1,i=null,u;let m=o,d=n;o=null,n=[],u=await e(...m),d.forEach(g=>{g(u)})}})(),l};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},ve=(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},Xe=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):pr.error("Could not parse JSON",o))}},yt=e=>e.charAt(0).toUpperCase()+e.slice(1),ue=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():yt(t)).join(" ");function fe(e,t){t&&e.log(`Skill invoked: ${t}`)}var mr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),gr=(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 l=Math.min(c-i.length,e.length);return`${i}${e.slice(0,l)}`}return e.slice(0,c)},Nn=e=>!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).length===0?!1:!!ar.some(t=>t in e),fr=()=>{let e={},t={codex:process.env.NETLIFY_FF_AGENT_RUNNER_CODEX_VERSION,claude:process.env.NETLIFY_FF_AGENT_RUNNER_CLAUDE_VERSION,gemini:process.env.NETLIFY_FF_AGENT_RUNNER_GEMINI_VERSION};return Object.entries(t).forEach(([r,o])=>{if(o){let n=`NETLIFY_FF_AGENT_RUNNER_${r.toUpperCase()}_VERSION`;try{let i=JSON.parse(o);Nn(i)&&(e[r]=i)}catch(i){let a=i instanceof SyntaxError?"Invalid JSON":i.message;pr.error(`Could not parse ${r} model version override from ${n}: ${a}`)}}}),e},On=1e4,_t=(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 hr}from"buffer";import $n from"path";var yr=I("repo"),Er=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{yr.info("Getting runner diffs");let o=await Ln(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let E=Mn(i);await Un(E,r)}yr.info("Changes after processing"),await wt(r);let s=await xt(i,r);if(await Et(s,r),n=await Dn(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await N("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},c=await N("git",["diff",e.runSha,"HEAD"],a),l=String(c.stdout??"");if(n=!!l,!n)return await _r(r),{hasChanges:!1,ignored:s};let u=await N("git",["diff",e.runSha,"HEAD","--binary"],a),m=String(u.stdout??""),d,g;if(e.sha){let E=await N("git",["diff",e.sha,"HEAD"],a);d=String(E.stdout??"");let T=await N("git",["diff",e.sha,"HEAD","--binary"],a),y=String(T.stdout??"");d!==y&&(g=hr.from(y).toString("base64"))}await _r(r);let x={hasChanges:!0,diff:l,resultDiff:d,ignored:s};return l!==m&&(x.diffBinary=hr.from(m).toString("base64")),g&&(x.resultDiffBinary=g),x},_r=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await N("git",["reset","--soft","HEAD~1"],{cwd:e})},Et=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await N("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},wt=async(e=process.cwd())=>{let t=await N("git",["status","-s"],{cwd:e});return String(t.stdout??"")},wr=/.. (.+)?\.log$/,Fn=[wr],Ln=async(e=process.cwd())=>{let t=await wt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
8
|
+
`);return i.length>e.length*.8?e:i}import{execSync as oo}from"child_process";import Fr from"fs/promises";import io from"path";import ye from"process";import{getTracer as so}from"@netlify/otel";import Oe from"process";var ee=class extends Error{constructor(r,o,n,i=!1){super(r);this.statusCode=o;this.userMessage=n;this.isCreditLimitExceeded=i;this.name="GracefulShutdownError"}},He=e=>e instanceof ee;var We=Oe.env.NETLIFY_API_URL,Ve=Oe.env.NETLIFY_API_TOKEN,H=I("api"),we=()=>Oe.env.NETLIFY_LOCAL_MODE==="true",ae=async(e,t={})=>{if(!We||!Ve)throw new Error("No API URL or token");let r=new URL(e,We),o={...t,headers:{...t.headers,Authorization:`Bearer ${Ve}`}};Oe.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(Oe.env.AGENT_RUNNERS_DEBUG==="true")H.log(`Response headers for ${r}:`),n.headers.forEach((a,c)=>{H.log(` ${c}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");H.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||H.error(`Got status ${n.status} for request ${r}`),t.raw){if(!i)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let s=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let a=typeof s=="string"?s:JSON.stringify(s);throw n.status===404?new ee(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&a.toLowerCase().includes("usage exceeded")?new ee(`API request failed: 503 - ${a}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${a}`)}return s},Vt=e=>{H.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(We=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Ve=e.constants.NETLIFY_API_TOKEN)},Jt=()=>({apiUrl:We,token:Ve}),$e=async(e,t)=>we()?(H.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):ae(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),W=async(e,t,r)=>we()?(H.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):ae(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Kt=async e=>we()?(H.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):ae(`/api/v1/sites/${e}`),zt=async(e,t)=>we()?(H.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):ae(`/api/v1/agent_runners/${e}/sessions/${t}`),Xt=(e,t,r)=>ae(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Zt=(e,t,r)=>ae(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Qt=async(e,t)=>we()?(H.log("Mock API: getDiffUploadUrls called",{runnerId:e,sessionId:t}),{result:{upload_url:"https://s3.mock.com/mock-upload-url-result",s3_key:"mock-s3-key-result"},cumulative:{upload_url:"https://s3.mock.com/mock-upload-url-cumulative",s3_key:"mock-s3-key-cumulative"}}):ae(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),er=async(e,t)=>we()?(H.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):ae(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),lt=async(e,t,{maxRetries:r=3,baseDelayMs:o=500}={})=>{H.log(`Uploading diff to S3: ${e.substring(0,50)}...`);for(let n=1;n<=r;n++)try{let i=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!i.ok)throw new Error(`S3 upload failed with status ${i.status}`);return i}catch(i){if(n===r)throw i;let s=o*2**(n-1);H.warn(`S3 upload attempt ${n}/${r} failed: ${i.message}. Retrying in ${s}ms...`),await new Promise(a=>setTimeout(a,s))}};var Te=I("ai_gateway"),ct=null;var Je=async()=>{if(ct)return ct;Te.log("Fetching available AI gateway providers");let e=await fetch(`${Jt().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 ct=t,Te.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},mn=async(e,t)=>{let o=(await Je()).providers[e];if(!o)return Te.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return Te.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},tr=async({config:e})=>{let t,r,o,n,i=!e.site?.published_deploy;if(!(i?e.accountId:e.siteId))throw new Error(`No entity id for ${i?"account":"site"}`);let a=async()=>{clearTimeout(o),Te.log("Requesting AI gateway information");let l=await(i?Xt(e.accountId,e.id,e.sessionId):Zt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=l,r=l.expires_at?l.expires_at*1e3:void 0,Te.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let u=r-Date.now()-6e4;u>0&&(o=setTimeout(()=>{a()},u))}};return await Promise.all([a(),Je()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:mn}};import te from"process";import oe from"path";import Ke from"fs";import{fileURLToPath as wn}from"url";import{createRequire as Tn}from"module";import{execa as xn,execaCommand as Si}from"execa";import{Transform as gn}from"stream";function fn(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function hn(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function yn(){let t=fn().map(r=>process.env[r]).filter(r=>!(!r||hn(r)));return[...new Set(t)].sort((r,o)=>o.length-r.length)}function ne(e){if(typeof e!="string")return e;let t=yn();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(_n(o),"g");r=r.replace(n,"******")}),r}function _n(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var xe=class extends gn{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=ne(n);o(null,i)}};function rr(){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"?ne(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"?ne(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var Fe=null,nr=e=>(Fe&&Fe.destroy(),Fe=new le({totalAllowedTime:e}),Fe),or=()=>Fe;var le=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 ir="netlify-agent-runner-context.md",ut="task-history",J=".netlify",me="results.md",dt="assets",sr="features",pt="other",mt="personal";var gt="enterprise",Le="free",ar=[mt,"pro",gt,Le],lr=["normal","redeploy","create","ask","dtn-prod-iteration","rebase"],cr="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.",ge=1800*1e3,f={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var ur={name:"@netlify/agent-runner-cli",type:"module",version:"1.93.4",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","test:integration:skill-invocation":"vitest run test/integration/skill-invocation.test.ts","test:integration:feature-enablement":"vitest run test/integration/feature-enablement.test.ts","check:types":"tsc --noEmit",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.81","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.5","@netlify/ts-cli":"^1.0.4","@openai/codex":"0.115.0","@opentelemetry/exporter-trace-otlp-grpc":"0.57.2",execa:"^9.6.1",minimist:"^1.2.8",openai:"6.26.0"}};var In=wn(import.meta.url),vn=oe.dirname(In),Sn=Tn(import.meta.url),Ie=I("shell"),ft=new Set,Rn={preferLocal:!0},N=(e,t,r)=>{let[o,n]=bn(t,r),i={...Rn,...n},s=xn(e,o,i);An(s,i),Pn(s);let a=r?.idleTimeout;return a&&a>0&&Cn(s,a),s};var bn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},An=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(te.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new xe).pipe(te.stdout),e.stdout?.pipe(new xe).pipe(te.stdout),e.stderr?.pipe(new xe).pipe(te.stderr);return}e.stdout?.pipe(te.stdout),e.stderr?.pipe(te.stderr)},ht=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(te.kill(-e.pid,t),Ie.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return Ie.error("Error killing process:",r),!1}},dr=e=>ht(e,"SIGKILL"),Cn=(e,t)=>{let r=null,o=()=>{Ie.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),ht(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(Ie.log(`Force killing idle process ${e.pid}`),dr(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)},Pn=e=>{ft.add(e);let t=or();if(t){let r=t.onTimesUp(()=>{Ie.log(`Global timer expired, killing process ${e.pid}`),ht(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(Ie.log(`Force killing process ${e.pid} after timeout`),dr(e))},5e3)});e.on("exit",()=>{ft.delete(e),r()}),e.on("error",()=>{ft.delete(e),r()})}};function ce(e,t){if(!te.env.NETLIFY_LOCAL_MODE)try{let n=Sn.resolve(ur.name),i=oe.dirname(n);for(;i!==oe.dirname(i);){let s=oe.dirname(i);if(oe.basename(s)==="node_modules"){let a=oe.join(s,".bin",t);if(Ke.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(te.env.NODE_PATH){let n=oe.join(te.env.NODE_PATH,".bin",t);if(Ke.existsSync(n))return n}let r=oe.join(e,"node_modules",".bin",t);if(Ke.existsSync(r))return r;let o=oe.join(vn,"..","node_modules",".bin",t);if(Ke.existsSync(o))return o}var pr=I("utils"),kn=e=>new Promise(t=>{setTimeout(t,e)}),ze=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(u=>{n.push(u)});r=!0;let c,l=new Promise(u=>{c=u});return i=(async()=>{await Promise.resolve();let u=await e(...a);for(c(u);;){if(await kn(t),!o)return r=!1,i=null,u;let m=o,d=n;o=null,n=[],u=await e(...m),d.forEach(g=>{g(u)})}})(),l};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},ve=(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},Xe=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):pr.error("Could not parse JSON",o))}},yt=e=>e.charAt(0).toUpperCase()+e.slice(1),ue=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():yt(t)).join(" ");function fe(e,t){t&&e.log(`Skill invoked: ${t}`)}var mr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),gr=(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 l=Math.min(c-i.length,e.length);return`${i}${e.slice(0,l)}`}return e.slice(0,c)},Nn=e=>!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).length===0?!1:!!ar.some(t=>t in e),fr=()=>{let e={},t={codex:process.env.NETLIFY_FF_AGENT_RUNNER_CODEX_VERSION,claude:process.env.NETLIFY_FF_AGENT_RUNNER_CLAUDE_VERSION,gemini:process.env.NETLIFY_FF_AGENT_RUNNER_GEMINI_VERSION};return Object.entries(t).forEach(([r,o])=>{if(o){let n=`NETLIFY_FF_AGENT_RUNNER_${r.toUpperCase()}_VERSION`;try{let i=JSON.parse(o);Nn(i)&&(e[r]=i)}catch(i){let a=i instanceof SyntaxError?"Invalid JSON":i.message;pr.error(`Could not parse ${r} model version override from ${n}: ${a}`)}}}),e},On=1e4,_t=(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 hr}from"buffer";import $n from"path";var yr=I("repo"),Er=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{yr.info("Getting runner diffs");let o=await Ln(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let E=Mn(i);await Un(E,r)}yr.info("Changes after processing"),await wt(r);let s=await xt(i,r);if(await Et(s,r),n=await Dn(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await N("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},c=await N("git",["diff",e.runSha,"HEAD"],a),l=String(c.stdout??"");if(n=!!l,!n)return await _r(r),{hasChanges:!1,ignored:s};let u=await N("git",["diff",e.runSha,"HEAD","--binary"],a),m=String(u.stdout??""),d,g;if(e.sha){let E=await N("git",["diff",e.sha,"HEAD"],a);d=String(E.stdout??"");let T=await N("git",["diff",e.sha,"HEAD","--binary"],a),y=String(T.stdout??"");d!==y&&(g=hr.from(y).toString("base64"))}await _r(r);let x={hasChanges:!0,diff:l,resultDiff:d,ignored:s};return l!==m&&(x.diffBinary=hr.from(m).toString("base64")),g&&(x.resultDiffBinary=g),x},_r=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await N("git",["reset","--soft","HEAD~1"],{cwd:e})},Et=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await N("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},wt=async(e=process.cwd())=>{let t=await N("git",["status","-s"],{cwd:e});return String(t.stdout??"")},wr=/.. (.+)?\.log$/,Fn=[wr],Ln=async(e=process.cwd())=>{let t=await wt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
9
9
|
`).filter(n=>Fn.some(s=>s instanceof RegExp?s.test(n):n===s)?!1:n[1]?.trim()!=="")).length!==0,status:t}},Dn=async(e=process.cwd())=>{try{return await N("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},Tt=async(e=process.cwd())=>{let{stdout:t}=await N("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},Tr=async(e=process.cwd())=>{let{stdout:t}=await N("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},xt=async(e,t=process.cwd())=>{e||=await wt(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build","CLAUDE.local.md"],o=[];return e.split(`
|
|
10
10
|
`).forEach(n=>{r.forEach(s=>{let a=n===`?? ${s}`,c=n.startsWith(`?? ${s}/`)||n.startsWith(`?? ${s}${$n.sep}`);(a||c)&&o.push(`:!${s}`)});let i=n.match(wr)?.[1];i&&o.push(`:!${i}.log`)}),o},It=async(e=process.cwd())=>{await N("git",["reset","--hard","HEAD"],{cwd:e})},Mn=e=>{let t=e.split(`
|
|
11
11
|
`).reduce((r,o)=>{if(!o)return r;let[n,i,,...s]=o,a=s.join(""),c=n.trim(),l=i.trim();return r[a]?r[a].change=l:r[a]={filePath:a,stage:c,change:l},r},{});return Object.values(t)},Un=async(e,t=process.cwd())=>{let r=e.filter(o=>o.stage&&!o.change).map(o=>o.filePath);r.length!==0&&await N("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import{createRequire as xo}from"module";import{createTracerProvider as Hr}from"@
|
|
|
4
4
|
${s}
|
|
5
5
|
</extracted_error_chunk>`).join(`
|
|
6
6
|
|
|
7
|
-
`);return i.length>e.length*.8?e:i}import{execSync as qn}from"child_process";import Sr from"fs/promises";import Bn from"path";import he from"process";import{getTracer as Hn}from"@netlify/otel";import Pe from"process";var Q=class extends Error{constructor(r,o,n,i=!1){super(r);this.statusCode=o;this.userMessage=n;this.isCreditLimitExceeded=i;this.name="GracefulShutdownError"}},Ye=e=>e instanceof Q;var qe=Pe.env.NETLIFY_API_URL,Be=Pe.env.NETLIFY_API_TOKEN,B=v("api"),_e=()=>Pe.env.NETLIFY_LOCAL_MODE==="true",se=async(e,t={})=>{if(!qe||!Be)throw new Error("No API URL or token");let r=new URL(e,qe),o={...t,headers:{...t.headers,Authorization:`Bearer ${Be}`}};Pe.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(Pe.env.AGENT_RUNNERS_DEBUG==="true")B.log(`Response headers for ${r}:`),n.headers.forEach((a,u)=>{B.log(` ${u}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");B.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||B.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 Q(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&a.toLowerCase().includes("usage exceeded")?new Q(`API request failed: 503 - ${a}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${a}`)}return s},Mt=e=>{B.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(qe=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Be=e.constants.NETLIFY_API_TOKEN)},Ut=()=>({apiUrl:qe,token:Be}),Ne=async(e,t)=>_e()?(B.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):se(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),H=async(e,t,r)=>_e()?(B.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):se(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Gt=async e=>_e()?(B.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):se(`/api/v1/sites/${e}`),jt=async(e,t)=>_e()?(B.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):se(`/api/v1/agent_runners/${e}/sessions/${t}`),Yt=(e,t,r)=>se(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),qt=(e,t,r)=>se(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Bt=async(e,t)=>_e()?(B.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"}}):se(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Ht=async(e,t)=>_e()?(B.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):se(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),ot=async(e,t,{maxRetries:r=3,baseDelayMs:o=500}={})=>{B.log(`Uploading diff to S3: ${e.substring(0,50)}...`);for(let n=1;n<=r;n++)try{let i=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!i.ok)throw new Error(`S3 upload failed with status ${i.status}`);return i}catch(i){if(n===r)throw i;let s=o*2**(n-1);B.warn(`S3 upload attempt ${n}/${r} failed: ${i.message}. Retrying in ${s}ms...`),await new Promise(a=>setTimeout(a,s))}};var Ee=v("ai_gateway"),it=null;var He=async()=>{if(it)return it;Ee.log("Fetching available AI gateway providers");let e=await fetch(`${Ut().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 it=t,Ee.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},Xr=async(e,t)=>{let o=(await He()).providers[e];if(!o)return Ee.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return Ee.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Wt=async({config:e})=>{let t,r,o,n,i=!e.site?.published_deploy;if(!(i?e.accountId:e.siteId))throw new Error(`No entity id for ${i?"account":"site"}`);let a=async()=>{clearTimeout(o),Ee.log("Requesting AI gateway information");let l=await(i?Yt(e.accountId,e.id,e.sessionId):qt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=l,r=l.expires_at?l.expires_at*1e3:void 0,Ee.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let c=r-Date.now()-6e4;c>0&&(o=setTimeout(()=>{a()},c))}};return await Promise.all([a(),He()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:Xr}};import ee from"process";import ne from"path";import We from"fs";import{fileURLToPath as on}from"url";import{createRequire as sn}from"module";import{execa as an,execaCommand as ti}from"execa";import{Transform as Zr}from"stream";function Qr(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function en(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function tn(){let t=Qr().map(r=>process.env[r]).filter(r=>!(!r||en(r)));return[...new Set(t)].sort((r,o)=>o.length-r.length)}function re(e){if(typeof e!="string")return e;let t=tn();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(rn(o),"g");r=r.replace(n,"******")}),r}function rn(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var xe=class extends Zr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=re(n);o(null,i)}};function Jt(){if(!(process.env.NETLIFY_MASK_LOGS!=="false"))return;let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr);process.stdout.write=function(o,n,i){let s=typeof o=="string"?re(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"?re(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var $e=null,Kt=e=>($e&&$e.destroy(),$e=new ae({totalAllowedTime:e}),$e),Vt=()=>$e;var ae=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,u)=>{i=setTimeout(()=>{u(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 zt="netlify-agent-runner-context.md",st="task-history",J=".netlify",pe="results.md",at="assets",Xt="features";var Zt="free";var me=1800*1e3,f={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var Qt={name:"@netlify/agent-runner-cli",type:"module",version:"1.93.3",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","test:integration:skill-invocation":"vitest run test/integration/skill-invocation.test.ts","test:integration:feature-enablement":"vitest run test/integration/feature-enablement.test.ts","check:types":"tsc --noEmit",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.81","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.5","@netlify/ts-cli":"^1.0.4","@openai/codex":"0.115.0","@opentelemetry/exporter-trace-otlp-grpc":"0.57.2",execa:"^9.6.1",minimist:"^1.2.8",openai:"6.26.0"}};var ln=on(import.meta.url),un=ne.dirname(ln),cn=sn(import.meta.url),Te=v("shell"),lt=new Set,dn={preferLocal:!0},N=(e,t,r)=>{let[o,n]=pn(t,r),i={...dn,...n},s=an(e,o,i);mn(s,i),fn(s);let a=r?.idleTimeout;return a&&a>0&&gn(s,a),s};var pn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},mn=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(ee.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new xe).pipe(ee.stdout),e.stdout?.pipe(new xe).pipe(ee.stdout),e.stderr?.pipe(new xe).pipe(ee.stderr);return}e.stdout?.pipe(ee.stdout),e.stderr?.pipe(ee.stderr)},ut=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(ee.kill(-e.pid,t),Te.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return Te.error("Error killing process:",r),!1}},er=e=>ut(e,"SIGKILL"),gn=(e,t)=>{let r=null,o=()=>{Te.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),ut(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(Te.log(`Force killing idle process ${e.pid}`),er(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)},fn=e=>{lt.add(e);let t=Vt();if(t){let r=t.onTimesUp(()=>{Te.log(`Global timer expired, killing process ${e.pid}`),ut(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(Te.log(`Force killing process ${e.pid} after timeout`),er(e))},5e3)});e.on("exit",()=>{lt.delete(e),r()}),e.on("error",()=>{lt.delete(e),r()})}};function le(e,t){if(!ee.env.NETLIFY_LOCAL_MODE)try{let n=cn.resolve(Qt.name),i=ne.dirname(n);for(;i!==ne.dirname(i);){let s=ne.dirname(i);if(ne.basename(s)==="node_modules"){let a=ne.join(s,".bin",t);if(We.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(ee.env.NODE_PATH){let n=ne.join(ee.env.NODE_PATH,".bin",t);if(We.existsSync(n))return n}let r=ne.join(e,"node_modules",".bin",t);if(We.existsSync(r))return r;let o=ne.join(un,"..","node_modules",".bin",t);if(We.existsSync(o))return o}var hn=v("utils"),yn=e=>new Promise(t=>{setTimeout(t,e)}),Je=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(c=>{n.push(c)});r=!0;let u,l=new Promise(c=>{u=c});return i=(async()=>{await Promise.resolve();let c=await e(...a);for(u(c);;){if(await yn(t),!o)return r=!1,i=null,c;let m=o,p=n;o=null,n=[],c=await e(...m),p.forEach(g=>{g(c)})}})(),l};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},Se=(e,t,r=!1)=>{let o=null,n=null,i=null,s=function(...a){n=a,i=this;let u=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(i,n),n=null,i=null)},t),u&&(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,u=i;o=null,n=null,i=null,e.apply(u,a)}},s},tr=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):hn.error("Could not parse JSON",o))}},ct=e=>e.charAt(0).toUpperCase()+e.slice(1),ue=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():ct(t)).join(" ");function ge(e,t){t&&e.log(`Skill invoked: ${t}`)}var rr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),nr=(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 u=60-a.length;if(u<=0)return"";if(u>=i.length+6){let l=Math.min(u-i.length,e.length);return`${i}${e.slice(0,l)}`}return e.slice(0,u)};var wn=1e4,dt=(e,t=wn)=>{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 or}from"buffer";import _n from"path";var ir=v("repo"),ar=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{ir.info("Getting runner diffs");let o=await xn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let _=Sn(i);await vn(_,r)}ir.info("Changes after processing"),await mt(r);let s=await ft(i,r);if(await pt(s,r),n=await Tn(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await N("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},u=await N("git",["diff",e.runSha,"HEAD"],a),l=String(u.stdout??"");if(n=!!l,!n)return await sr(r),{hasChanges:!1,ignored:s};let c=await N("git",["diff",e.runSha,"HEAD","--binary"],a),m=String(c.stdout??""),p,g;if(e.sha){let _=await N("git",["diff",e.sha,"HEAD"],a);p=String(_.stdout??"");let x=await N("git",["diff",e.sha,"HEAD","--binary"],a),y=String(x.stdout??"");p!==y&&(g=or.from(y).toString("base64"))}await sr(r);let T={hasChanges:!0,diff:l,resultDiff:p,ignored:s};return l!==m&&(T.diffBinary=or.from(m).toString("base64")),g&&(T.resultDiffBinary=g),T},sr=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await N("git",["reset","--soft","HEAD~1"],{cwd:e})},pt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await N("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},mt=async(e=process.cwd())=>{let t=await N("git",["status","-s"],{cwd:e});return String(t.stdout??"")},lr=/.. (.+)?\.log$/,En=[lr],xn=async(e=process.cwd())=>{let t=await mt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
7
|
+
`);return i.length>e.length*.8?e:i}import{execSync as qn}from"child_process";import Sr from"fs/promises";import Bn from"path";import he from"process";import{getTracer as Hn}from"@netlify/otel";import Pe from"process";var Q=class extends Error{constructor(r,o,n,i=!1){super(r);this.statusCode=o;this.userMessage=n;this.isCreditLimitExceeded=i;this.name="GracefulShutdownError"}},Ye=e=>e instanceof Q;var qe=Pe.env.NETLIFY_API_URL,Be=Pe.env.NETLIFY_API_TOKEN,B=v("api"),_e=()=>Pe.env.NETLIFY_LOCAL_MODE==="true",se=async(e,t={})=>{if(!qe||!Be)throw new Error("No API URL or token");let r=new URL(e,qe),o={...t,headers:{...t.headers,Authorization:`Bearer ${Be}`}};Pe.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(Pe.env.AGENT_RUNNERS_DEBUG==="true")B.log(`Response headers for ${r}:`),n.headers.forEach((a,u)=>{B.log(` ${u}: ${a}`)});else{let a=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");B.log(`Request ID for ${r}: ${a||"N/A"}`)}if(i||B.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 Q(`API request failed: 404 - ${a}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&a.toLowerCase().includes("usage exceeded")?new Q(`API request failed: 503 - ${a}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${a}`)}return s},Mt=e=>{B.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(qe=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Be=e.constants.NETLIFY_API_TOKEN)},Ut=()=>({apiUrl:qe,token:Be}),Ne=async(e,t)=>_e()?(B.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):se(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),H=async(e,t,r)=>_e()?(B.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):se(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Gt=async e=>_e()?(B.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):se(`/api/v1/sites/${e}`),jt=async(e,t)=>_e()?(B.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):se(`/api/v1/agent_runners/${e}/sessions/${t}`),Yt=(e,t,r)=>se(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),qt=(e,t,r)=>se(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Bt=async(e,t)=>_e()?(B.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"}}):se(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Ht=async(e,t)=>_e()?(B.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):se(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),ot=async(e,t,{maxRetries:r=3,baseDelayMs:o=500}={})=>{B.log(`Uploading diff to S3: ${e.substring(0,50)}...`);for(let n=1;n<=r;n++)try{let i=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!i.ok)throw new Error(`S3 upload failed with status ${i.status}`);return i}catch(i){if(n===r)throw i;let s=o*2**(n-1);B.warn(`S3 upload attempt ${n}/${r} failed: ${i.message}. Retrying in ${s}ms...`),await new Promise(a=>setTimeout(a,s))}};var Ee=v("ai_gateway"),it=null;var He=async()=>{if(it)return it;Ee.log("Fetching available AI gateway providers");let e=await fetch(`${Ut().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 it=t,Ee.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},Xr=async(e,t)=>{let o=(await He()).providers[e];if(!o)return Ee.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return Ee.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Wt=async({config:e})=>{let t,r,o,n,i=!e.site?.published_deploy;if(!(i?e.accountId:e.siteId))throw new Error(`No entity id for ${i?"account":"site"}`);let a=async()=>{clearTimeout(o),Ee.log("Requesting AI gateway information");let l=await(i?Yt(e.accountId,e.id,e.sessionId):qt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=l,r=l.expires_at?l.expires_at*1e3:void 0,Ee.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let c=r-Date.now()-6e4;c>0&&(o=setTimeout(()=>{a()},c))}};return await Promise.all([a(),He()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:Xr}};import ee from"process";import ne from"path";import We from"fs";import{fileURLToPath as on}from"url";import{createRequire as sn}from"module";import{execa as an,execaCommand as ti}from"execa";import{Transform as Zr}from"stream";function Qr(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function en(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function tn(){let t=Qr().map(r=>process.env[r]).filter(r=>!(!r||en(r)));return[...new Set(t)].sort((r,o)=>o.length-r.length)}function re(e){if(typeof e!="string")return e;let t=tn();if(t.length===0)return e;let r=e;return t.forEach(o=>{let n=new RegExp(rn(o),"g");r=r.replace(n,"******")}),r}function rn(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var xe=class extends Zr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=re(n);o(null,i)}};function Jt(){if(!(process.env.NETLIFY_MASK_LOGS!=="false"))return;let t=process.stdout.write.bind(process.stdout),r=process.stderr.write.bind(process.stderr);process.stdout.write=function(o,n,i){let s=typeof o=="string"?re(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"?re(o):o;return typeof n=="function"?r(s,n):r(s,n,i)}}var $e=null,Kt=e=>($e&&$e.destroy(),$e=new ae({totalAllowedTime:e}),$e),Vt=()=>$e;var ae=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,u)=>{i=setTimeout(()=>{u(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 zt="netlify-agent-runner-context.md",st="task-history",J=".netlify",pe="results.md",at="assets",Xt="features";var Zt="free";var me=1800*1e3,f={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var Qt={name:"@netlify/agent-runner-cli",type:"module",version:"1.93.4",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","test:integration:skill-invocation":"vitest run test/integration/skill-invocation.test.ts","test:integration:feature-enablement":"vitest run test/integration/feature-enablement.test.ts","check:types":"tsc --noEmit",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.81","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.5","@netlify/ts-cli":"^1.0.4","@openai/codex":"0.115.0","@opentelemetry/exporter-trace-otlp-grpc":"0.57.2",execa:"^9.6.1",minimist:"^1.2.8",openai:"6.26.0"}};var ln=on(import.meta.url),un=ne.dirname(ln),cn=sn(import.meta.url),Te=v("shell"),lt=new Set,dn={preferLocal:!0},N=(e,t,r)=>{let[o,n]=pn(t,r),i={...dn,...n},s=an(e,o,i);mn(s,i),fn(s);let a=r?.idleTimeout;return a&&a>0&&gn(s,a),s};var pn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},mn=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(ee.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new xe).pipe(ee.stdout),e.stdout?.pipe(new xe).pipe(ee.stdout),e.stderr?.pipe(new xe).pipe(ee.stderr);return}e.stdout?.pipe(ee.stdout),e.stderr?.pipe(ee.stderr)},ut=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(ee.kill(-e.pid,t),Te.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return Te.error("Error killing process:",r),!1}},er=e=>ut(e,"SIGKILL"),gn=(e,t)=>{let r=null,o=()=>{Te.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),ut(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(Te.log(`Force killing idle process ${e.pid}`),er(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)},fn=e=>{lt.add(e);let t=Vt();if(t){let r=t.onTimesUp(()=>{Te.log(`Global timer expired, killing process ${e.pid}`),ut(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(Te.log(`Force killing process ${e.pid} after timeout`),er(e))},5e3)});e.on("exit",()=>{lt.delete(e),r()}),e.on("error",()=>{lt.delete(e),r()})}};function le(e,t){if(!ee.env.NETLIFY_LOCAL_MODE)try{let n=cn.resolve(Qt.name),i=ne.dirname(n);for(;i!==ne.dirname(i);){let s=ne.dirname(i);if(ne.basename(s)==="node_modules"){let a=ne.join(s,".bin",t);if(We.existsSync(a))return a;break}i=s}}catch(n){console.error("Could not resolve package.json",n)}if(ee.env.NODE_PATH){let n=ne.join(ee.env.NODE_PATH,".bin",t);if(We.existsSync(n))return n}let r=ne.join(e,"node_modules",".bin",t);if(We.existsSync(r))return r;let o=ne.join(un,"..","node_modules",".bin",t);if(We.existsSync(o))return o}var hn=v("utils"),yn=e=>new Promise(t=>{setTimeout(t,e)}),Je=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,s=(...a)=>{if(r)return o=a,new Promise(c=>{n.push(c)});r=!0;let u,l=new Promise(c=>{u=c});return i=(async()=>{await Promise.resolve();let c=await e(...a);for(u(c);;){if(await yn(t),!o)return r=!1,i=null,c;let m=o,p=n;o=null,n=[],c=await e(...m),p.forEach(g=>{g(c)})}})(),l};return s.flush=async()=>{if((r||o)&&i)return await i,s.flush()},s},Se=(e,t,r=!1)=>{let o=null,n=null,i=null,s=function(...a){n=a,i=this;let u=r&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,r||(e.apply(i,n),n=null,i=null)},t),u&&(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,u=i;o=null,n=null,i=null,e.apply(u,a)}},s},tr=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):hn.error("Could not parse JSON",o))}},ct=e=>e.charAt(0).toUpperCase()+e.slice(1),ue=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():ct(t)).join(" ");function ge(e,t){t&&e.log(`Skill invoked: ${t}`)}var rr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),nr=(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 u=60-a.length;if(u<=0)return"";if(u>=i.length+6){let l=Math.min(u-i.length,e.length);return`${i}${e.slice(0,l)}`}return e.slice(0,u)};var wn=1e4,dt=(e,t=wn)=>{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 or}from"buffer";import _n from"path";var ir=v("repo"),ar=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{ir.info("Getting runner diffs");let o=await xn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let _=Sn(i);await vn(_,r)}ir.info("Changes after processing"),await mt(r);let s=await ft(i,r);if(await pt(s,r),n=await Tn(r),!n)return{hasChanges:!1,ignored:s};process.env.NETLIFY_INTERNAL_GIT="1";try{await N("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let a={stdio:["ignore","pipe","pipe"],cwd:r},u=await N("git",["diff",e.runSha,"HEAD"],a),l=String(u.stdout??"");if(n=!!l,!n)return await sr(r),{hasChanges:!1,ignored:s};let c=await N("git",["diff",e.runSha,"HEAD","--binary"],a),m=String(c.stdout??""),p,g;if(e.sha){let _=await N("git",["diff",e.sha,"HEAD"],a);p=String(_.stdout??"");let x=await N("git",["diff",e.sha,"HEAD","--binary"],a),y=String(x.stdout??"");p!==y&&(g=or.from(y).toString("base64"))}await sr(r);let T={hasChanges:!0,diff:l,resultDiff:p,ignored:s};return l!==m&&(T.diffBinary=or.from(m).toString("base64")),g&&(T.resultDiffBinary=g),T},sr=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await N("git",["reset","--soft","HEAD~1"],{cwd:e})},pt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await N("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},mt=async(e=process.cwd())=>{let t=await N("git",["status","-s"],{cwd:e});return String(t.stdout??"")},lr=/.. (.+)?\.log$/,En=[lr],xn=async(e=process.cwd())=>{let t=await mt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
8
8
|
`).filter(n=>En.some(s=>s instanceof RegExp?s.test(n):n===s)?!1:n[1]?.trim()!=="")).length!==0,status:t}},Tn=async(e=process.cwd())=>{try{return await N("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},gt=async(e=process.cwd())=>{let{stdout:t}=await N("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},ur=async(e=process.cwd())=>{let{stdout:t}=await N("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},ft=async(e,t=process.cwd())=>{e||=await mt(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build","CLAUDE.local.md"],o=[];return e.split(`
|
|
9
9
|
`).forEach(n=>{r.forEach(s=>{let a=n===`?? ${s}`,u=n.startsWith(`?? ${s}/`)||n.startsWith(`?? ${s}${_n.sep}`);(a||u)&&o.push(`:!${s}`)});let i=n.match(lr)?.[1];i&&o.push(`:!${i}.log`)}),o},ht=async(e=process.cwd())=>{await N("git",["reset","--hard","HEAD"],{cwd:e})},Sn=e=>{let t=e.split(`
|
|
10
10
|
`).reduce((r,o)=>{if(!o)return r;let[n,i,,...s]=o,a=s.join(""),u=n.trim(),l=i.trim();return r[a]?r[a].change=l:r[a]={filePath:a,stage:u,change:l},r},{});return Object.values(t)},vn=async(e,t=process.cwd())=>{let r=e.filter(o=>o.stage&&!o.change).map(o=>o.filePath);r.length!==0&&await N("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: netlify-forms
|
|
3
|
-
description: Build and configure Netlify Forms for serverless form handling. Use when implementing contact forms, feedback forms, file uploads, or any form that collects user submissions without backend code.
|
|
3
|
+
description: Build and configure Netlify Forms for serverless form handling. Use when implementing contact forms, feedback forms, file uploads, or any form that collects user submissions without backend code. Make sure to always run `node scripts/enable.cjs` located in this skill's directory after implementing Netlify Forms.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Netlify Forms
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: netlify-identity
|
|
3
|
-
description: Use whenever the task involves authentication, signups, logins, password recovery, user accounts, role-based access control, OAuth providers, protected routes, protecting Netlify Functions, server-side auth in SSR frameworks, or Netlify Identity. Always use `@netlify/identity`. Never use `netlify-identity-widget` or `gotrue-js` as they are deprecated.
|
|
3
|
+
description: Use whenever the task involves authentication, signups, logins, password recovery, user accounts, role-based access control, OAuth providers, protected routes, protecting Netlify Functions, server-side auth in SSR frameworks, or Netlify Identity. Always use `@netlify/identity`. Never use `netlify-identity-widget` or `gotrue-js` as they are deprecated. Make sure to always run `node scripts/enable.cjs` located in this skill's directory after implementing Netlify Identity.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Netlify Identity
|