@netlify/agent-runner-cli 1.88.0-alpha.0 → 1.88.0-alpha.1
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 +2 -2
- package/dist/bin.js +2 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/dist/bin-local.js
CHANGED
|
@@ -5,7 +5,7 @@ import M from"process";import Jr from"path";import Kr from"fs";import Ci from"mi
|
|
|
5
5
|
${a}
|
|
6
6
|
</extracted_error_chunk>`).join(`
|
|
7
7
|
|
|
8
|
-
`);return o.length>e.length*.8?e:o}import{execSync as Vn}from"child_process";import Rr from"fs/promises";import zn from"path";import me from"process";import{getTracer as Xn}from"@netlify/otel";import Ae from"process";var z=class extends Error{constructor(r,i,n,o=!1){super(r);this.statusCode=i;this.userMessage=n;this.isCreditLimitExceeded=o;this.name="GracefulShutdownError"}},Ge=e=>e instanceof z;var je=Ae.env.NETLIFY_API_URL,Ye=Ae.env.NETLIFY_API_TOKEN,W=x("api"),he=()=>Ae.env.NETLIFY_LOCAL_MODE==="true",oe=async(e,t={})=>{if(!je||!Ye)throw new Error("No API URL or token");let r=new URL(e,je),i={...t,headers:{...t.headers,Authorization:`Bearer ${Ye}`}};Ae.env.AGENT_RUNNERS_DEBUG==="true"&&(i.headers["x-nf-debug-logging"]="true"),t.json&&(i.headers||={},i.headers["Content-Type"]="application/json",i.body=JSON.stringify(t.json));let n=await fetch(r,i),o=n.ok&&n.status<=299;if(Ae.env.AGENT_RUNNERS_DEBUG==="true")W.log(`Response headers for ${r}:`),n.headers.forEach((s,l)=>{W.log(` ${l}: ${s}`)});else{let s=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");W.log(`Request ID for ${r}: ${s||"N/A"}`)}if(o||W.error(`Got status ${n.status} for request ${r}`),t.raw){if(!o)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let a=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!o){let s=typeof a=="string"?a:JSON.stringify(a);throw n.status===404?new z(`API request failed: 404 - ${s}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&s.toLowerCase().includes("usage exceeded")?new z(`API request failed: 503 - ${s}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${s}`)}return a},Dt=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&&(Ye=e.constants.NETLIFY_API_TOKEN)},Mt=()=>({apiUrl:je,token:Ye}),Ce=async(e,t)=>he()?(W.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):oe(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),J=async(e,t,r)=>he()?(W.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):oe(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Ut=async e=>he()?(W.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):oe(`/api/v1/sites/${e}`),Gt=async(e,t)=>he()?(W.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):oe(`/api/v1/agent_runners/${e}/sessions/${t}`),jt=(e,t,r)=>oe(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Yt=(e,t,r)=>oe(`/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)=>he()?(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"}}):oe(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Bt=async(e,t)=>he()?(W.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):oe(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),at=async(e,t)=>{W.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ye=x("ai_gateway"),lt=null;var Ht=async()=>{if(lt)return lt;ye.log("Fetching available AI gateway providers");let e=await fetch(`${Mt().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 lt=t,ye.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},rn=async(e,t)=>{let i=(await Ht()).providers[e];if(!i)return ye.log(`Provider '${e}' not found`),!1;let n=i.models.includes(t);return ye.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Wt=async({config:e})=>{let t,r,i,n,o=!e.site?.published_deploy;if(!(o?e.accountId:e.siteId))throw new Error(`No entity id for ${o?"account":"site"}`);let s=async()=>{clearTimeout(i),ye.log("Requesting AI gateway information");let d=await(o?jt(e.accountId,e.id,e.sessionId):Yt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=d,r=d.expires_at?d.expires_at*1e3:void 0,ye.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let c=r-Date.now()-6e4;c>0&&(i=setTimeout(()=>{s()},c))}};return await Promise.all([s(),Ht()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:rn}};import Z from"process";import re from"path";import qe from"fs";import{fileURLToPath as un}from"url";import{createRequire as dn}from"module";import{execa as pn,execaCommand as lo}from"execa";import{Transform as nn}from"stream";function on(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function sn(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function an(){let t=on().map(r=>process.env[r]).filter(r=>!(!r||sn(r)));return[...new Set(t)].sort((r,i)=>i.length-r.length)}function te(e){if(typeof e!="string")return e;let t=an();if(t.length===0)return e;let r=e;return t.forEach(i=>{let n=new RegExp(ln(i),"g");r=r.replace(n,"******")}),r}function ln(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var we=class extends nn{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,i){let n=t.toString(),o=te(n);i(null,o)}};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(i,n,o){let a=typeof i=="string"?te(i):i;return typeof n=="function"?t(a,n):t(a,n,o)},process.stderr.write=function(i,n,o){let a=typeof i=="string"?te(i):i;return typeof n=="function"?r(a,n):r(a,n,o)}}var ke=null,Kt=e=>(ke&&ke.destroy(),ke=new se({totalAllowedTime:e}),ke),Vt=()=>ke;var se=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,i)=>{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.`)}),o=null,a=null;i!==void 0&&(a=new Promise((s,l)=>{o=setTimeout(()=>{l(new Error(`${t} stage exceeded its maximum duration of ${i}ms`))},i)}));try{return a?await Promise.race([r(),a]):await r()}finally{n(),o&&clearTimeout(o)}};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",ct="task-history",X=".netlify",ce="results.md",ut="assets";var Xt="free";var ue=1800*1e3,w={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 Zt={name:"@netlify/agent-runner-cli",type:"module",version:"1.88.0-alpha.0",description:"CLI tool for running Netlify agents",main:"./dist/index.js",types:"./dist/index.d.ts",exports:"./dist/index.js",bin:{"agent-runner-cli":"./dist/bin.js","agent-runner-cli-local":"./dist/bin-local.js"},files:["dist/**/*.js","dist/**/*.d.ts","dist/skills/**","patches","scripts"],scripts:{build:"tsup",dev:"tsup --watch",prepare:"husky install node_modules/@netlify/eslint-config-node/.husky/",prepublishOnly:"npm ci && npm test",prepack:"npm run build",test:"run-s build format test:dev",format:"run-s build format:check-fix:*","format:ci":"run-s build format:check:*","format:check-fix:lint":"run-e format:check:lint format:fix:lint","format:check:lint":"cross-env-shell eslint $npm_package_config_eslint","format:fix:lint":"cross-env-shell eslint --fix $npm_package_config_eslint","format:check-fix:prettier":"run-e format:check:prettier format:fix:prettier","format:check:prettier":"cross-env-shell prettier --check $npm_package_config_prettier","format:fix:prettier":"cross-env-shell prettier --write $npm_package_config_prettier","test:dev":"run-s build test:dev:*","test:ci":"run-s build test:ci:*","test:dev:vitest":"LOG=0 vitest --exclude '**/integration/**'","test:ci:vitest":"LOG=0 c8 -r lcovonly -r text -r json vitest --exclude '**/integration/**'","test:integration":"vitest run test/integration/","test:integration:codex":"vitest run test/integration/codex.test.ts","test:integration:claude":"vitest run test/integration/claude.test.ts","test:integration:gemini":"vitest run test/integration/gemini.test.ts","test:integration:create-stage":"vitest run test/integration/create.test.ts","test:integration:skill-invocation":"vitest run test/integration/skill-invocation.test.ts",postinstall:"node scripts/postinstall.js"},config:{eslint:'--cache --format=codeframe --max-warnings=0 "{src,scripts,test,.github}/**/*.{js,ts,md,html}"',prettier:'--ignore-path .gitignore --loglevel=warn "{src,scripts,test,.github}/**/*.{js,ts,md,yml,json,html}" "*.{js,ts,yml,json,html}" ".*.{js,ts,yml,json,html}" "!**/package-lock.json" "!package-lock.json" "!src/skills/**/*.md"'},keywords:[],license:"MIT",repository:"netlify/agent-runner-cli",bugs:{url:"https://github.com/netlify/agent-runner-cli/issues"},author:"Netlify Inc.",directories:{test:"test"},devDependencies:{"@commitlint/cli":"^20.0.0","@commitlint/config-conventional":"^20.0.0","@eslint/compat":"^2.0.0","@eslint/js":"^9.35.0","@netlify/eslint-config-node":"^7.0.1","@types/node":"^24.5.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/eslint-plugin":"^1.6.6",c8:"^10.0.0","eslint-config-prettier":"^10.1.8","eslint-plugin-n":"^17.0.0",husky:"^9.0.0","patch-package":"^8.0.0",tsup:"^8.5.0",typescript:"^5.0.0","typescript-eslint":"^8.44.0",vitest:"^4.0.16"},dependencies:{"@anthropic-ai/claude-code":"2.1.63","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.1","@openai/codex":"0.110.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.7.2",minimist:"^1.2.8",openai:"6.26.0"}};var mn=un(import.meta.url),gn=re.dirname(mn),fn=dn(import.meta.url),_e=x("shell"),dt=new Set,hn={preferLocal:!0},A=(e,t,r)=>{let[i,n]=yn(t,r),o={...hn,...n},a=pn(e,i,o);wn(a,o),En(a);let s=r?.idleTimeout;return s&&s>0&&_n(a,s),a};var yn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},wn=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(Z.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new we).pipe(Z.stdout),e.stdout?.pipe(new we).pipe(Z.stdout),e.stderr?.pipe(new we).pipe(Z.stderr);return}e.stdout?.pipe(Z.stdout),e.stderr?.pipe(Z.stderr)},pt=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(Z.kill(-e.pid,t),_e.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return _e.error("Error killing process:",r),!1}},Qt=e=>pt(e,"SIGKILL"),_n=(e,t)=>{let r=null,i=()=>{_e.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),pt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(_e.log(`Force killing idle process ${e.pid}`),Qt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(i,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let o=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",o),e.on("error",o)},En=e=>{dt.add(e);let t=Vt();if(t){let r=t.onTimesUp(()=>{_e.log(`Global timer expired, killing process ${e.pid}`),pt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(_e.log(`Force killing process ${e.pid} after timeout`),Qt(e))},5e3)});e.on("exit",()=>{dt.delete(e),r()}),e.on("error",()=>{dt.delete(e),r()})}};function Be(e,t){return!!ne(e,t)}function ne(e,t){if(!Z.env.NETLIFY_LOCAL_MODE)try{let n=fn.resolve(Zt.name),o=re.dirname(n);for(;o!==re.dirname(o);){let a=re.dirname(o);if(re.basename(a)==="node_modules"){let s=re.join(a,".bin",t);if(qe.existsSync(s))return s;break}o=a}}catch(n){console.error("Could not resolve package.json",n)}if(Z.env.NODE_PATH){let n=re.join(Z.env.NODE_PATH,".bin",t);if(qe.existsSync(n))return n}let r=re.join(e,"node_modules",".bin",t);if(qe.existsSync(r))return r;let i=re.join(gn,"..","node_modules",".bin",t);if(qe.existsSync(i))return i}var xn=x("utils"),Tn=e=>new Promise(t=>{setTimeout(t,e)}),He=(e,t=3e3)=>{let r=!1,i=null,n=[],o=null,a=(...s)=>{if(r)return i=s,new Promise(c=>{n.push(c)});r=!0;let l,d=new Promise(c=>{l=c});return o=(async()=>{await Promise.resolve();let c=await e(...s);for(l(c);;){if(await Tn(t),!i)return r=!1,o=null,c;let p=i,m=n;i=null,n=[],c=await e(...p),m.forEach(E=>{E(c)})}})(),d};return a.flush=async()=>{if((r||i)&&o)return await o,a.flush()},a},Ee=(e,t,r=!1)=>{let i=null,n=null,o=null,a=function(...s){n=s,o=this;let l=r&&!i;clearTimeout(i),i=setTimeout(()=>{i=null,r||(e.apply(o,n),n=null,o=null)},t),l&&(e.apply(o,n),n=null,o=null)};return a.cancel=()=>{clearTimeout(i),i=null,n=null,o=null},a.flush=()=>{if(i){clearTimeout(i);let s=n,l=o;i=null,n=null,o=null,e.apply(l,s)}},a},er=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(i){t&&(r?.error?r.error("Could not parse JSON",i):xn.error("Could not parse JSON",i))}},mt=e=>e.charAt(0).toUpperCase()+e.slice(1),ae=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():mt(t)).join(" ");function de(e,t){t&&e.log(`Skill invoked: ${t}`)}var tr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),rr=(e,t)=>{let n=".netlify.app",o="agent-";if(!t)return`${o}${e.slice(0,6)}`;let s=`--${t}${n}`;if(s.length>55)return"";let l=60-s.length;if(l<=0)return"";if(l>=o.length+6){let d=Math.min(l-o.length,e.length);return`${o}${e.slice(0,d)}`}return e.slice(0,l)};var In=50*1024,gt=(e,t=In)=>{if(!e||typeof e!="string"||e.length<=t)return e;let i=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+i};import{Buffer as nr}from"buffer";import Sn from"path";var ir=x("repo"),sr=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{ir.info("Getting runner diffs");let i=await Rn(r),{hasChanges:n}=i,{status:o}=i;if(!n)return{hasChanges:!1};if(!t){let h=An(o);await Cn(h,r)}ir.info("Changes after processing"),await ht(r);let a=await yt(o,r);if(await ft(a,r),n=await bn(r),!n)return{hasChanges:!1,ignored:a};process.env.NETLIFY_INTERNAL_GIT="1";try{await A("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let s={stdio:["ignore","pipe","pipe"],cwd:r},l=await A("git",["diff",e.runSha,"HEAD"],s),d=String(l.stdout??"");if(n=!!d,!n)return await or(r),{hasChanges:!1,ignored:a};let c=await A("git",["diff",e.runSha,"HEAD","--binary"],s),p=String(c.stdout??""),m,E;if(e.sha){let h=await A("git",["diff",e.sha,"HEAD"],s);m=String(h.stdout??"");let S=await A("git",["diff",e.sha,"HEAD","--binary"],s),y=String(S.stdout??"");m!==y&&(E=nr.from(y).toString("base64"))}await or(r);let f={hasChanges:!0,diff:d,resultDiff:m,ignored:a};return d!==p&&(f.diffBinary=nr.from(p).toString("base64")),E&&(f.resultDiffBinary=E),f},or=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await A("git",["reset","--soft","HEAD~1"],{cwd:e})},ft=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await A("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},ht=async(e=process.cwd())=>{let t=await A("git",["status","-s"],{cwd:e});return String(t.stdout??"")},ar=/.. (.+)?\.log$/,vn=[ar],Rn=async(e=process.cwd())=>{let t=await ht(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
8
|
+
`);return o.length>e.length*.8?e:o}import{execSync as Vn}from"child_process";import Rr from"fs/promises";import zn from"path";import me from"process";import{getTracer as Xn}from"@netlify/otel";import Ae from"process";var z=class extends Error{constructor(r,i,n,o=!1){super(r);this.statusCode=i;this.userMessage=n;this.isCreditLimitExceeded=o;this.name="GracefulShutdownError"}},Ge=e=>e instanceof z;var je=Ae.env.NETLIFY_API_URL,Ye=Ae.env.NETLIFY_API_TOKEN,W=x("api"),he=()=>Ae.env.NETLIFY_LOCAL_MODE==="true",oe=async(e,t={})=>{if(!je||!Ye)throw new Error("No API URL or token");let r=new URL(e,je),i={...t,headers:{...t.headers,Authorization:`Bearer ${Ye}`}};Ae.env.AGENT_RUNNERS_DEBUG==="true"&&(i.headers["x-nf-debug-logging"]="true"),t.json&&(i.headers||={},i.headers["Content-Type"]="application/json",i.body=JSON.stringify(t.json));let n=await fetch(r,i),o=n.ok&&n.status<=299;if(Ae.env.AGENT_RUNNERS_DEBUG==="true")W.log(`Response headers for ${r}:`),n.headers.forEach((s,l)=>{W.log(` ${l}: ${s}`)});else{let s=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");W.log(`Request ID for ${r}: ${s||"N/A"}`)}if(o||W.error(`Got status ${n.status} for request ${r}`),t.raw){if(!o)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let a=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!o){let s=typeof a=="string"?a:JSON.stringify(a);throw n.status===404?new z(`API request failed: 404 - ${s}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&s.toLowerCase().includes("usage exceeded")?new z(`API request failed: 503 - ${s}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${s}`)}return a},Dt=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&&(Ye=e.constants.NETLIFY_API_TOKEN)},Mt=()=>({apiUrl:je,token:Ye}),Ce=async(e,t)=>he()?(W.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):oe(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),J=async(e,t,r)=>he()?(W.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):oe(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Ut=async e=>he()?(W.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):oe(`/api/v1/sites/${e}`),Gt=async(e,t)=>he()?(W.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):oe(`/api/v1/agent_runners/${e}/sessions/${t}`),jt=(e,t,r)=>oe(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Yt=(e,t,r)=>oe(`/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)=>he()?(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"}}):oe(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Bt=async(e,t)=>he()?(W.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):oe(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),at=async(e,t)=>{W.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ye=x("ai_gateway"),lt=null;var Ht=async()=>{if(lt)return lt;ye.log("Fetching available AI gateway providers");let e=await fetch(`${Mt().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 lt=t,ye.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},rn=async(e,t)=>{let i=(await Ht()).providers[e];if(!i)return ye.log(`Provider '${e}' not found`),!1;let n=i.models.includes(t);return ye.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Wt=async({config:e})=>{let t,r,i,n,o=!e.site?.published_deploy;if(!(o?e.accountId:e.siteId))throw new Error(`No entity id for ${o?"account":"site"}`);let s=async()=>{clearTimeout(i),ye.log("Requesting AI gateway information");let d=await(o?jt(e.accountId,e.id,e.sessionId):Yt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=d,r=d.expires_at?d.expires_at*1e3:void 0,ye.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let c=r-Date.now()-6e4;c>0&&(i=setTimeout(()=>{s()},c))}};return await Promise.all([s(),Ht()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:rn}};import Z from"process";import re from"path";import qe from"fs";import{fileURLToPath as un}from"url";import{createRequire as dn}from"module";import{execa as pn,execaCommand as lo}from"execa";import{Transform as nn}from"stream";function on(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function sn(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function an(){let t=on().map(r=>process.env[r]).filter(r=>!(!r||sn(r)));return[...new Set(t)].sort((r,i)=>i.length-r.length)}function te(e){if(typeof e!="string")return e;let t=an();if(t.length===0)return e;let r=e;return t.forEach(i=>{let n=new RegExp(ln(i),"g");r=r.replace(n,"******")}),r}function ln(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var we=class extends nn{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,i){let n=t.toString(),o=te(n);i(null,o)}};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(i,n,o){let a=typeof i=="string"?te(i):i;return typeof n=="function"?t(a,n):t(a,n,o)},process.stderr.write=function(i,n,o){let a=typeof i=="string"?te(i):i;return typeof n=="function"?r(a,n):r(a,n,o)}}var ke=null,Kt=e=>(ke&&ke.destroy(),ke=new se({totalAllowedTime:e}),ke),Vt=()=>ke;var se=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,i)=>{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.`)}),o=null,a=null;i!==void 0&&(a=new Promise((s,l)=>{o=setTimeout(()=>{l(new Error(`${t} stage exceeded its maximum duration of ${i}ms`))},i)}));try{return a?await Promise.race([r(),a]):await r()}finally{n(),o&&clearTimeout(o)}};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",ct="task-history",X=".netlify",ce="results.md",ut="assets";var Xt="free";var ue=1800*1e3,w={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 Zt={name:"@netlify/agent-runner-cli",type:"module",version:"1.88.0-alpha.1",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",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.63","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.1","@openai/codex":"0.110.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.7.2",minimist:"^1.2.8",openai:"6.26.0"}};var mn=un(import.meta.url),gn=re.dirname(mn),fn=dn(import.meta.url),_e=x("shell"),dt=new Set,hn={preferLocal:!0},A=(e,t,r)=>{let[i,n]=yn(t,r),o={...hn,...n},a=pn(e,i,o);wn(a,o),En(a);let s=r?.idleTimeout;return s&&s>0&&_n(a,s),a};var yn=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},wn=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(Z.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new we).pipe(Z.stdout),e.stdout?.pipe(new we).pipe(Z.stdout),e.stderr?.pipe(new we).pipe(Z.stderr);return}e.stdout?.pipe(Z.stdout),e.stderr?.pipe(Z.stderr)},pt=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(Z.kill(-e.pid,t),_e.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return _e.error("Error killing process:",r),!1}},Qt=e=>pt(e,"SIGKILL"),_n=(e,t)=>{let r=null,i=()=>{_e.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),pt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(_e.log(`Force killing idle process ${e.pid}`),Qt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(i,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let o=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",o),e.on("error",o)},En=e=>{dt.add(e);let t=Vt();if(t){let r=t.onTimesUp(()=>{_e.log(`Global timer expired, killing process ${e.pid}`),pt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(_e.log(`Force killing process ${e.pid} after timeout`),Qt(e))},5e3)});e.on("exit",()=>{dt.delete(e),r()}),e.on("error",()=>{dt.delete(e),r()})}};function Be(e,t){return!!ne(e,t)}function ne(e,t){if(!Z.env.NETLIFY_LOCAL_MODE)try{let n=fn.resolve(Zt.name),o=re.dirname(n);for(;o!==re.dirname(o);){let a=re.dirname(o);if(re.basename(a)==="node_modules"){let s=re.join(a,".bin",t);if(qe.existsSync(s))return s;break}o=a}}catch(n){console.error("Could not resolve package.json",n)}if(Z.env.NODE_PATH){let n=re.join(Z.env.NODE_PATH,".bin",t);if(qe.existsSync(n))return n}let r=re.join(e,"node_modules",".bin",t);if(qe.existsSync(r))return r;let i=re.join(gn,"..","node_modules",".bin",t);if(qe.existsSync(i))return i}var xn=x("utils"),Tn=e=>new Promise(t=>{setTimeout(t,e)}),He=(e,t=3e3)=>{let r=!1,i=null,n=[],o=null,a=(...s)=>{if(r)return i=s,new Promise(c=>{n.push(c)});r=!0;let l,d=new Promise(c=>{l=c});return o=(async()=>{await Promise.resolve();let c=await e(...s);for(l(c);;){if(await Tn(t),!i)return r=!1,o=null,c;let p=i,m=n;i=null,n=[],c=await e(...p),m.forEach(E=>{E(c)})}})(),d};return a.flush=async()=>{if((r||i)&&o)return await o,a.flush()},a},Ee=(e,t,r=!1)=>{let i=null,n=null,o=null,a=function(...s){n=s,o=this;let l=r&&!i;clearTimeout(i),i=setTimeout(()=>{i=null,r||(e.apply(o,n),n=null,o=null)},t),l&&(e.apply(o,n),n=null,o=null)};return a.cancel=()=>{clearTimeout(i),i=null,n=null,o=null},a.flush=()=>{if(i){clearTimeout(i);let s=n,l=o;i=null,n=null,o=null,e.apply(l,s)}},a},er=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(i){t&&(r?.error?r.error("Could not parse JSON",i):xn.error("Could not parse JSON",i))}},mt=e=>e.charAt(0).toUpperCase()+e.slice(1),ae=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():mt(t)).join(" ");function de(e,t){t&&e.log(`Skill invoked: ${t}`)}var tr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),rr=(e,t)=>{let n=".netlify.app",o="agent-";if(!t)return`${o}${e.slice(0,6)}`;let s=`--${t}${n}`;if(s.length>55)return"";let l=60-s.length;if(l<=0)return"";if(l>=o.length+6){let d=Math.min(l-o.length,e.length);return`${o}${e.slice(0,d)}`}return e.slice(0,l)};var In=50*1024,gt=(e,t=In)=>{if(!e||typeof e!="string"||e.length<=t)return e;let i=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+i};import{Buffer as nr}from"buffer";import Sn from"path";var ir=x("repo"),sr=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{ir.info("Getting runner diffs");let i=await Rn(r),{hasChanges:n}=i,{status:o}=i;if(!n)return{hasChanges:!1};if(!t){let h=An(o);await Cn(h,r)}ir.info("Changes after processing"),await ht(r);let a=await yt(o,r);if(await ft(a,r),n=await bn(r),!n)return{hasChanges:!1,ignored:a};process.env.NETLIFY_INTERNAL_GIT="1";try{await A("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let s={stdio:["ignore","pipe","pipe"],cwd:r},l=await A("git",["diff",e.runSha,"HEAD"],s),d=String(l.stdout??"");if(n=!!d,!n)return await or(r),{hasChanges:!1,ignored:a};let c=await A("git",["diff",e.runSha,"HEAD","--binary"],s),p=String(c.stdout??""),m,E;if(e.sha){let h=await A("git",["diff",e.sha,"HEAD"],s);m=String(h.stdout??"");let S=await A("git",["diff",e.sha,"HEAD","--binary"],s),y=String(S.stdout??"");m!==y&&(E=nr.from(y).toString("base64"))}await or(r);let f={hasChanges:!0,diff:d,resultDiff:m,ignored:a};return d!==p&&(f.diffBinary=nr.from(p).toString("base64")),E&&(f.resultDiffBinary=E),f},or=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await A("git",["reset","--soft","HEAD~1"],{cwd:e})},ft=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await A("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},ht=async(e=process.cwd())=>{let t=await A("git",["status","-s"],{cwd:e});return String(t.stdout??"")},ar=/.. (.+)?\.log$/,vn=[ar],Rn=async(e=process.cwd())=>{let t=await ht(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
9
9
|
`).filter(n=>vn.some(a=>a instanceof RegExp?a.test(n):n===a)?!1:n[1]?.trim()!=="")).length!==0,status:t}},bn=async(e=process.cwd())=>{try{return await A("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},Pe=async(e=process.cwd())=>{let{stdout:t}=await A("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},lr=async(e=process.cwd())=>{let{stdout:t}=await A("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},yt=async(e,t=process.cwd())=>{e||=await ht(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"],i=[];return e.split(`
|
|
10
10
|
`).forEach(n=>{r.forEach(a=>{let s=n===`?? ${a}`,l=n.startsWith(`?? ${a}/`)||n.startsWith(`?? ${a}${Sn.sep}`);(s||l)&&i.push(`:!${a}`)});let o=n.match(ar)?.[1];o&&i.push(`:!${o}.log`)}),i},wt=async(e=process.cwd())=>{await A("git",["reset","--hard","HEAD"],{cwd:e})},An=e=>{let t=e.split(`
|
|
11
11
|
`).reduce((r,i)=>{if(!i)return r;let[n,o,,...a]=i,s=a.join(""),l=n.trim(),d=o.trim();return r[s]?r[s].change=d:r[s]={filePath:s,stage:l,change:d},r},{});return Object.values(t)},Cn=async(e,t=process.cwd())=>{let r=e.filter(i=>i.stage&&!i.change).map(i=>i.filePath);r.length!==0&&await A("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
|
|
@@ -167,7 +167,7 @@ Deploy failed failed. Here are the errors to review on the latest build:
|
|
|
167
167
|
Below are all of the logs with potential issues that we extracted. Some of them may be false positives, discern them carefully and ensure fixes are relevant.
|
|
168
168
|
|
|
169
169
|
${e.pop()}
|
|
170
|
-
`;import gi from"process";import{getTracer as bt}from"@netlify/otel";import{getTracer as pi}from"@netlify/otel";var Fe=x("deploy"),Nr=async e=>await k(pi(),"create-preview-deploy",async t=>mi(e,t)),mi=async({netlify:e,hasRepo:t,skipBuild:r,message:i="Agent Preview",deploySubdomain:n,cliPath:o,filter:a,prodDeploy:s,apiToken:l},d)=>{try{let c=["deploy","--message",`"${i}"`,"--json","--verbose",s?"--prod":"--draft"];t||(Fe.log("Deploy: Uploading source zip"),c.push("--upload-source-zip")),n&&c.push("--alias",n),a&&c.push("--filter",a),r?(Fe.log("Deploy: Skipping build"),c.push("--no-build")):c.push("--context",s?"production":"deploy-preview");let p=[...c];c.push("--auth",l);let m=o||"netlify";Fe.log(`Running: ${m} ${p.join(" ")}`),d?.setAttributes({cmd:m,args:c});let E=await e.utils.run(m,c,{stdio:["ignore","pipe","pipe"]}),f=JSON.parse(String(E.stdout??"").trim());d?.setAttributes({success:!0,deployId:f.deploy_id,deployUrl:f.deploy_url,siteId:f.site_id}),Fe.log(`
|
|
170
|
+
`;import gi from"process";import{getTracer as bt}from"@netlify/otel";import{getTracer as pi}from"@netlify/otel";var Fe=x("deploy"),Nr=async e=>await k(pi(),"create-preview-deploy",async t=>mi(e,t)),mi=async({netlify:e,hasRepo:t,skipBuild:r,message:i="Agent Preview",deploySubdomain:n,cliPath:o,filter:a,prodDeploy:s,apiToken:l},d)=>{try{let c=["deploy","--message",`"${i}"`,"--json","--verbose",s?"--prod":"--draft"];t||(Fe.log("Deploy: Uploading source zip"),c.push("--upload-source-zip")),n&&!s&&c.push("--alias",n),a&&c.push("--filter",a),r?(Fe.log("Deploy: Skipping build"),c.push("--no-build")):c.push("--context",s?"production":"deploy-preview");let p=[...c];c.push("--auth",l);let m=o||"netlify";Fe.log(`Running: ${m} ${p.join(" ")}`),d?.setAttributes({cmd:m,args:c});let E=await e.utils.run(m,c,{stdio:["ignore","pipe","pipe"]}),f=JSON.parse(String(E.stdout??"").trim());d?.setAttributes({success:!0,deployId:f.deploy_id,deployUrl:f.deploy_url,siteId:f.site_id}),Fe.log(`
|
|
171
171
|
Preview deploy created successfully:`,{deployId:f.deploy_id,deployUrl:f.deploy_url,siteId:f.site_id});let h={deployId:f.deploy_id,previewUrl:f.deploy_url,logsUrl:f.logs,siteId:f.site_id};return t||(h.sourceZipFilename=f.source_zip_filename),h}catch(c){throw Fe.error("Failed to create preview deploy via CLI:",c),d?.setAttributes({success:!1,error:c.message}),c}};var Or=e=>["dtn-prod-iteration","create"].includes(e);var Le=x("deploy_stage"),Qe=async e=>await k(bt(),"run-deploy-stage",async()=>fi(e)),fi=async({cliPath:e,config:t,context:r,result:i,filter:n,isRetry:o,apiToken:a})=>{let s=await k(bt(),"get-runner-diffs",async()=>await sr({config:t,isRetry:o}));if(Le.info("Resolved git",{hasChanges:s.hasChanges,ignored:s.ignored??[]}),!s.hasChanges&&t.mode!=="redeploy")return{diff:"",hasChanges:!1,previewInfo:null};let l=s.hasChanges?s.diff:"",d=s.hasChanges?s.resultDiff:void 0,c=s.hasChanges?s.diffBinary:void 0,p=s.hasChanges?s.resultDiffBinary:void 0,m=s.hasChanges||t.mode==="redeploy";Le.log("Deploy condition check:",{resultUndefined:i===void 0,resultType:typeof i,hasChanges:m,isRedeploy:t.mode==="redeploy",wouldCreateDeploy:i!==void 0&&(m||t.mode==="redeploy")});let E=null;if(i!==void 0&&(m||t.mode==="redeploy"))try{let f;try{let h=await k(bt(),"get-runner-session",async()=>await Gt(t.id,t.sessionId));h?.title&&(f=h.title)}catch(h){Le.warn("Failed to fetch session title, using fallback message:",h.message)}await J(t.id,t.sessionId,{steps:[{title:"Deploying the run preview",category:w.Deployment}]}),E=await Nr({cliPath:e,netlify:r,hasRepo:t.hasRepo,message:f,skipBuild:!1,deploySubdomain:rr(t.id,gi.env.SITE_NAME),filter:n,prodDeploy:Or(t.mode),apiToken:a})}catch(f){return Le.warn("Failed to create preview deploy (continuing with agent run):",f),{diff:l,resultDiff:d,hasChanges:m,previewInfo:null,diffBinary:c,resultDiffBinary:p,deployError:f instanceof Error?f.message:String(f)}}return Le.log("Git status",{hasDiff:!!l,hasChanges:m}),{diff:l,resultDiff:d,hasChanges:m,previewInfo:E,diffBinary:c,resultDiffBinary:p}};import{getTracer as rt}from"@netlify/otel";async function $r(e,t){let{maxRetries:r,baseDelay:i,onRetry:n}=t,o;for(let a=1;a<=r;a++)try{return await e()}catch(s){if(o=s,a===r)throw o;n&&n(a,o),await new Promise(l=>setTimeout(l,i*a))}throw o}var et=class{scanDiffForForms(t){let r=[],i=null,n=[],o=t.split(`
|
|
172
172
|
`);for(let a of o)if(a.startsWith("diff --git")){if(i&&n.length>0){let l=this.containsNetlifyForm(n,i);l&&r.push(l)}let s=a.split(" ");i=s[s.length-1].replace(/^b\//,""),n=[]}else a.startsWith("+")&&!a.startsWith("+++")&&n.push(a.slice(1));if(i&&n.length>0){let a=this.containsNetlifyForm(n,i);a&&r.push(a)}return{detected:r.length>0,matches:r}}containsNetlifyForm(t,r){let i=t.join(`
|
|
173
173
|
`),n=[{pattern:/<[\w-]*form[\s\S]*?(data-)?netlify/i,name:"standard form element"},{pattern:/<[A-Z][\w]*[\s\S]*?component\s*=\s*["']form["'][\s\S]*?(data-)?netlify/i,name:"component with form prop"}];for(let{pattern:o,name:a}of n){let s=i.match(o);if(s){let l=s.index||0,d=Math.max(0,l-20),c=Math.min(i.length,l+s[0].length+20),p=i.slice(d,c).trim();return p=p.replace(/\s+/g," "),p.length>100&&(p=p.slice(0,97)+"..."),{file:r,snippet:`[${a}] ${p}`}}}return null}};var tt=class{scanDiffForIdentity(t){let r=[],i=null,n=[],o=t.split(`
|
package/dist/bin.js
CHANGED
|
@@ -5,7 +5,7 @@ import $t from"process";import qo from"minimist";import{createRequire as No}from
|
|
|
5
5
|
${a}
|
|
6
6
|
</extracted_error_chunk>`).join(`
|
|
7
7
|
|
|
8
|
-
`);return i.length>e.length*.8?e:i}import{execSync as eo}from"child_process";import Nr from"fs/promises";import to from"path";import de from"process";import{getTracer as ro}from"@netlify/otel";import Ae from"process";var J=class extends Error{constructor(r,o,n,i=!1){super(r);this.statusCode=o;this.userMessage=n;this.isCreditLimitExceeded=i;this.name="GracefulShutdownError"}},Ue=e=>e instanceof J;var Ge=Ae.env.NETLIFY_API_URL,je=Ae.env.NETLIFY_API_TOKEN,H=x("api"),ge=()=>Ae.env.NETLIFY_LOCAL_MODE==="true",re=async(e,t={})=>{if(!Ge||!je)throw new Error("No API URL or token");let r=new URL(e,Ge),o={...t,headers:{...t.headers,Authorization:`Bearer ${je}`}};Ae.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(Ae.env.AGENT_RUNNERS_DEBUG==="true")H.log(`Response headers for ${r}:`),n.headers.forEach((s,c)=>{H.log(` ${c}: ${s}`)});else{let s=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");H.log(`Request ID for ${r}: ${s||"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 a=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let s=typeof a=="string"?a:JSON.stringify(a);throw n.status===404?new J(`API request failed: 404 - ${s}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&s.toLowerCase().includes("usage exceeded")?new J(`API request failed: 503 - ${s}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${s}`)}return a},Gt=e=>{H.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Ge=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(je=e.constants.NETLIFY_API_TOKEN)},jt=()=>({apiUrl:Ge,token:je}),Ce=async(e,t)=>ge()?(H.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):re(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),W=async(e,t,r)=>ge()?(H.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):re(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Yt=async e=>ge()?(H.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):re(`/api/v1/sites/${e}`),qt=async(e,t)=>ge()?(H.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):re(`/api/v1/agent_runners/${e}/sessions/${t}`),Bt=(e,t,r)=>re(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Ht=(e,t,r)=>re(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Wt=async(e,t)=>ge()?(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"}}):re(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Kt=async(e,t)=>ge()?(H.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):re(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),st=async(e,t)=>{H.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var fe=x("ai_gateway"),at=null;var Jt=async()=>{if(at)return at;fe.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 at=t,fe.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},ln=async(e,t)=>{let o=(await Jt()).providers[e];if(!o)return fe.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return fe.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Vt=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 s=async()=>{clearTimeout(o),fe.log("Requesting AI gateway information");let d=await(i?Bt(e.accountId,e.id,e.sessionId):Ht(e.siteId,e.id,e.sessionId));if({token:t,url:n}=d,r=d.expires_at?d.expires_at*1e3:void 0,fe.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let l=r-Date.now()-6e4;l>0&&(o=setTimeout(()=>{s()},l))}};return await Promise.all([s(),Jt()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:ln}};import z from"process";import ee from"path";import Ye from"fs";import{fileURLToPath as fn}from"url";import{createRequire as hn}from"module";import{execa as yn,execaCommand as xi}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 Q(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 he=class extends cn{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=Q(n);o(null,i)}};function zt(){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 a=typeof o=="string"?Q(o):o;return typeof n=="function"?t(a,n):t(a,n,i)},process.stderr.write=function(o,n,i){let a=typeof o=="string"?Q(o):o;return typeof n=="function"?r(a,n):r(a,n,i)}}var be=null,Xt=e=>(be&&be.destroy(),be=new ne({totalAllowedTime:e}),be),Zt=()=>be;var ne=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,a=null;o!==void 0&&(a=new Promise((s,c)=>{i=setTimeout(()=>{c(new Error(`${t} stage exceeded its maximum duration of ${o}ms`))},o)}));try{return a?await Promise.race([r(),a]):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 Qt="netlify-agent-runner-context.md",lt="task-history",V=".netlify",ae="results.md",ct="assets",ut="other",dt="personal";var pt="enterprise",Pe="free",er=[dt,"pro",pt,Pe],tr=["normal","redeploy","create","ask","dtn-prod-iteration","rebase"],rr="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.",le=1800*1e3,E={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var nr={name:"@netlify/agent-runner-cli",type:"module",version:"1.88.0-alpha.0",description:"CLI tool for running Netlify agents",main:"./dist/index.js",types:"./dist/index.d.ts",exports:"./dist/index.js",bin:{"agent-runner-cli":"./dist/bin.js","agent-runner-cli-local":"./dist/bin-local.js"},files:["dist/**/*.js","dist/**/*.d.ts","dist/skills/**","patches","scripts"],scripts:{build:"tsup",dev:"tsup --watch",prepare:"husky install node_modules/@netlify/eslint-config-node/.husky/",prepublishOnly:"npm ci && npm test",prepack:"npm run build",test:"run-s build format test:dev",format:"run-s build format:check-fix:*","format:ci":"run-s build format:check:*","format:check-fix:lint":"run-e format:check:lint format:fix:lint","format:check:lint":"cross-env-shell eslint $npm_package_config_eslint","format:fix:lint":"cross-env-shell eslint --fix $npm_package_config_eslint","format:check-fix:prettier":"run-e format:check:prettier format:fix:prettier","format:check:prettier":"cross-env-shell prettier --check $npm_package_config_prettier","format:fix:prettier":"cross-env-shell prettier --write $npm_package_config_prettier","test:dev":"run-s build test:dev:*","test:ci":"run-s build test:ci:*","test:dev:vitest":"LOG=0 vitest --exclude '**/integration/**'","test:ci:vitest":"LOG=0 c8 -r lcovonly -r text -r json vitest --exclude '**/integration/**'","test:integration":"vitest run test/integration/","test:integration:codex":"vitest run test/integration/codex.test.ts","test:integration:claude":"vitest run test/integration/claude.test.ts","test:integration:gemini":"vitest run test/integration/gemini.test.ts","test:integration:create-stage":"vitest run test/integration/create.test.ts","test:integration:skill-invocation":"vitest run test/integration/skill-invocation.test.ts",postinstall:"node scripts/postinstall.js"},config:{eslint:'--cache --format=codeframe --max-warnings=0 "{src,scripts,test,.github}/**/*.{js,ts,md,html}"',prettier:'--ignore-path .gitignore --loglevel=warn "{src,scripts,test,.github}/**/*.{js,ts,md,yml,json,html}" "*.{js,ts,yml,json,html}" ".*.{js,ts,yml,json,html}" "!**/package-lock.json" "!package-lock.json" "!src/skills/**/*.md"'},keywords:[],license:"MIT",repository:"netlify/agent-runner-cli",bugs:{url:"https://github.com/netlify/agent-runner-cli/issues"},author:"Netlify Inc.",directories:{test:"test"},devDependencies:{"@commitlint/cli":"^20.0.0","@commitlint/config-conventional":"^20.0.0","@eslint/compat":"^2.0.0","@eslint/js":"^9.35.0","@netlify/eslint-config-node":"^7.0.1","@types/node":"^24.5.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/eslint-plugin":"^1.6.6",c8:"^10.0.0","eslint-config-prettier":"^10.1.8","eslint-plugin-n":"^17.0.0",husky:"^9.0.0","patch-package":"^8.0.0",tsup:"^8.5.0",typescript:"^5.0.0","typescript-eslint":"^8.44.0",vitest:"^4.0.16"},dependencies:{"@anthropic-ai/claude-code":"2.1.63","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.1","@openai/codex":"0.110.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.7.2",minimist:"^1.2.8",openai:"6.26.0"}};var _n=fn(import.meta.url),En=ee.dirname(_n),wn=hn(import.meta.url),ye=x("shell"),mt=new Set,xn={preferLocal:!0},P=(e,t,r)=>{let[o,n]=Tn(t,r),i={...xn,...n},a=yn(e,o,i);In(a,i),Sn(a);let s=r?.idleTimeout;return s&&s>0&&vn(a,s),a};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(z.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new he).pipe(z.stdout),e.stdout?.pipe(new he).pipe(z.stdout),e.stderr?.pipe(new he).pipe(z.stderr);return}e.stdout?.pipe(z.stdout),e.stderr?.pipe(z.stderr)},gt=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(z.kill(-e.pid,t),ye.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ye.error("Error killing process:",r),!1}},or=e=>gt(e,"SIGKILL"),vn=(e,t)=>{let r=null,o=()=>{ye.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),gt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ye.log(`Force killing idle process ${e.pid}`),or(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)},Sn=e=>{mt.add(e);let t=Zt();if(t){let r=t.onTimesUp(()=>{ye.log(`Global timer expired, killing process ${e.pid}`),gt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ye.log(`Force killing process ${e.pid} after timeout`),or(e))},5e3)});e.on("exit",()=>{mt.delete(e),r()}),e.on("error",()=>{mt.delete(e),r()})}};function oe(e,t){if(!z.env.NETLIFY_LOCAL_MODE)try{let n=wn.resolve(nr.name),i=ee.dirname(n);for(;i!==ee.dirname(i);){let a=ee.dirname(i);if(ee.basename(a)==="node_modules"){let s=ee.join(a,".bin",t);if(Ye.existsSync(s))return s;break}i=a}}catch(n){console.error("Could not resolve package.json",n)}if(z.env.NODE_PATH){let n=ee.join(z.env.NODE_PATH,".bin",t);if(Ye.existsSync(n))return n}let r=ee.join(e,"node_modules",".bin",t);if(Ye.existsSync(r))return r;let o=ee.join(En,"..","node_modules",".bin",t);if(Ye.existsSync(o))return o}var ir=x("utils"),Rn=e=>new Promise(t=>{setTimeout(t,e)}),qe=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,a=(...s)=>{if(r)return o=s,new Promise(l=>{n.push(l)});r=!0;let c,d=new Promise(l=>{c=l});return i=(async()=>{await Promise.resolve();let l=await e(...s);for(c(l);;){if(await Rn(t),!o)return r=!1,i=null,l;let p=o,m=n;o=null,n=[],l=await e(...p),m.forEach(_=>{_(l)})}})(),d};return a.flush=async()=>{if((r||o)&&i)return await i,a.flush()},a},_e=(e,t,r=!1)=>{let o=null,n=null,i=null,a=function(...s){n=s,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 a.cancel=()=>{clearTimeout(o),o=null,n=null,i=null},a.flush=()=>{if(o){clearTimeout(o);let s=n,c=i;o=null,n=null,i=null,e.apply(c,s)}},a},Be=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):ir.error("Could not parse JSON",o))}},ft=e=>e.charAt(0).toUpperCase()+e.slice(1),ie=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():ft(t)).join(" ");function ce(e,t){t&&e.log(`Skill invoked: ${t}`)}var sr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),ar=(e,t)=>{let n=".netlify.app",i="agent-";if(!t)return`${i}${e.slice(0,6)}`;let s=`--${t}${n}`;if(s.length>55)return"";let c=60-s.length;if(c<=0)return"";if(c>=i.length+6){let d=Math.min(c-i.length,e.length);return`${i}${e.slice(0,d)}`}return e.slice(0,c)},An=e=>!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).length===0?!1:!!er.some(t=>t in e),lr=()=>{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);An(i)&&(e[r]=i)}catch(i){let s=i instanceof SyntaxError?"Invalid JSON":i.message;ir.error(`Could not parse ${r} model version override from ${n}: ${s}`)}}}),e},Cn=50*1024,ht=(e,t=Cn)=>{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 cr}from"buffer";import bn from"path";var ur=x("repo"),pr=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{ur.info("Getting runner diffs");let o=await kn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let h=On(i);await $n(h,r)}ur.info("Changes after processing"),await _t(r);let a=await wt(i,r);if(await yt(a,r),n=await Nn(r),!n)return{hasChanges:!1,ignored:a};process.env.NETLIFY_INTERNAL_GIT="1";try{await P("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let s={stdio:["ignore","pipe","pipe"],cwd:r},c=await P("git",["diff",e.runSha,"HEAD"],s),d=String(c.stdout??"");if(n=!!d,!n)return await dr(r),{hasChanges:!1,ignored:a};let l=await P("git",["diff",e.runSha,"HEAD","--binary"],s),p=String(l.stdout??""),m,_;if(e.sha){let h=await P("git",["diff",e.sha,"HEAD"],s);m=String(h.stdout??"");let v=await P("git",["diff",e.sha,"HEAD","--binary"],s),y=String(v.stdout??"");m!==y&&(_=cr.from(y).toString("base64"))}await dr(r);let f={hasChanges:!0,diff:d,resultDiff:m,ignored:a};return d!==p&&(f.diffBinary=cr.from(p).toString("base64")),_&&(f.resultDiffBinary=_),f},dr=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await P("git",["reset","--soft","HEAD~1"],{cwd:e})},yt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await P("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},_t=async(e=process.cwd())=>{let t=await P("git",["status","-s"],{cwd:e});return String(t.stdout??"")},mr=/.. (.+)?\.log$/,Pn=[mr],kn=async(e=process.cwd())=>{let t=await _t(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
8
|
+
`);return i.length>e.length*.8?e:i}import{execSync as eo}from"child_process";import Nr from"fs/promises";import to from"path";import de from"process";import{getTracer as ro}from"@netlify/otel";import Ae from"process";var J=class extends Error{constructor(r,o,n,i=!1){super(r);this.statusCode=o;this.userMessage=n;this.isCreditLimitExceeded=i;this.name="GracefulShutdownError"}},Ue=e=>e instanceof J;var Ge=Ae.env.NETLIFY_API_URL,je=Ae.env.NETLIFY_API_TOKEN,H=x("api"),ge=()=>Ae.env.NETLIFY_LOCAL_MODE==="true",re=async(e,t={})=>{if(!Ge||!je)throw new Error("No API URL or token");let r=new URL(e,Ge),o={...t,headers:{...t.headers,Authorization:`Bearer ${je}`}};Ae.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(Ae.env.AGENT_RUNNERS_DEBUG==="true")H.log(`Response headers for ${r}:`),n.headers.forEach((s,c)=>{H.log(` ${c}: ${s}`)});else{let s=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");H.log(`Request ID for ${r}: ${s||"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 a=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!i){let s=typeof a=="string"?a:JSON.stringify(a);throw n.status===404?new J(`API request failed: 404 - ${s}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&s.toLowerCase().includes("usage exceeded")?new J(`API request failed: 503 - ${s}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${s}`)}return a},Gt=e=>{H.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Ge=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(je=e.constants.NETLIFY_API_TOKEN)},jt=()=>({apiUrl:Ge,token:je}),Ce=async(e,t)=>ge()?(H.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):re(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),W=async(e,t,r)=>ge()?(H.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):re(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Yt=async e=>ge()?(H.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):re(`/api/v1/sites/${e}`),qt=async(e,t)=>ge()?(H.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):re(`/api/v1/agent_runners/${e}/sessions/${t}`),Bt=(e,t,r)=>re(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Ht=(e,t,r)=>re(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Wt=async(e,t)=>ge()?(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"}}):re(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Kt=async(e,t)=>ge()?(H.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):re(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),st=async(e,t)=>{H.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var fe=x("ai_gateway"),at=null;var Jt=async()=>{if(at)return at;fe.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 at=t,fe.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},ln=async(e,t)=>{let o=(await Jt()).providers[e];if(!o)return fe.log(`Provider '${e}' not found`),!1;let n=o.models.includes(t);return fe.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Vt=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 s=async()=>{clearTimeout(o),fe.log("Requesting AI gateway information");let d=await(i?Bt(e.accountId,e.id,e.sessionId):Ht(e.siteId,e.id,e.sessionId));if({token:t,url:n}=d,r=d.expires_at?d.expires_at*1e3:void 0,fe.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let l=r-Date.now()-6e4;l>0&&(o=setTimeout(()=>{s()},l))}};return await Promise.all([s(),Jt()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:ln}};import z from"process";import ee from"path";import Ye from"fs";import{fileURLToPath as fn}from"url";import{createRequire as hn}from"module";import{execa as yn,execaCommand as xi}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 Q(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 he=class extends cn{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,o){let n=t.toString(),i=Q(n);o(null,i)}};function zt(){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 a=typeof o=="string"?Q(o):o;return typeof n=="function"?t(a,n):t(a,n,i)},process.stderr.write=function(o,n,i){let a=typeof o=="string"?Q(o):o;return typeof n=="function"?r(a,n):r(a,n,i)}}var be=null,Xt=e=>(be&&be.destroy(),be=new ne({totalAllowedTime:e}),be),Zt=()=>be;var ne=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,a=null;o!==void 0&&(a=new Promise((s,c)=>{i=setTimeout(()=>{c(new Error(`${t} stage exceeded its maximum duration of ${o}ms`))},o)}));try{return a?await Promise.race([r(),a]):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 Qt="netlify-agent-runner-context.md",lt="task-history",V=".netlify",ae="results.md",ct="assets",ut="other",dt="personal";var pt="enterprise",Pe="free",er=[dt,"pro",pt,Pe],tr=["normal","redeploy","create","ask","dtn-prod-iteration","rebase"],rr="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.",le=1800*1e3,E={Environment:"environment",UserMessage:"user-message",AgentMessage:"agent-message",Task:"task",RunCommand:"run-command",Explore:"explore",Plan:"plan",FileRead:"file-read",FileWrite:"file-write",Notebook:"notebook",Web:"web",Todo:"todo",Reasoning:"reasoning",Skill:"skill",Memorize:"memorize",Deployment:"deployment",SiteGeneration:"site-generation"};var nr={name:"@netlify/agent-runner-cli",type:"module",version:"1.88.0-alpha.1",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",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.63","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.1","@openai/codex":"0.110.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.7.2",minimist:"^1.2.8",openai:"6.26.0"}};var _n=fn(import.meta.url),En=ee.dirname(_n),wn=hn(import.meta.url),ye=x("shell"),mt=new Set,xn={preferLocal:!0},P=(e,t,r)=>{let[o,n]=Tn(t,r),i={...xn,...n},a=yn(e,o,i);In(a,i),Sn(a);let s=r?.idleTimeout;return s&&s>0&&vn(a,s),a};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(z.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new he).pipe(z.stdout),e.stdout?.pipe(new he).pipe(z.stdout),e.stderr?.pipe(new he).pipe(z.stderr);return}e.stdout?.pipe(z.stdout),e.stderr?.pipe(z.stderr)},gt=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(z.kill(-e.pid,t),ye.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return ye.error("Error killing process:",r),!1}},or=e=>gt(e,"SIGKILL"),vn=(e,t)=>{let r=null,o=()=>{ye.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),gt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ye.log(`Force killing idle process ${e.pid}`),or(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)},Sn=e=>{mt.add(e);let t=Zt();if(t){let r=t.onTimesUp(()=>{ye.log(`Global timer expired, killing process ${e.pid}`),gt(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(ye.log(`Force killing process ${e.pid} after timeout`),or(e))},5e3)});e.on("exit",()=>{mt.delete(e),r()}),e.on("error",()=>{mt.delete(e),r()})}};function oe(e,t){if(!z.env.NETLIFY_LOCAL_MODE)try{let n=wn.resolve(nr.name),i=ee.dirname(n);for(;i!==ee.dirname(i);){let a=ee.dirname(i);if(ee.basename(a)==="node_modules"){let s=ee.join(a,".bin",t);if(Ye.existsSync(s))return s;break}i=a}}catch(n){console.error("Could not resolve package.json",n)}if(z.env.NODE_PATH){let n=ee.join(z.env.NODE_PATH,".bin",t);if(Ye.existsSync(n))return n}let r=ee.join(e,"node_modules",".bin",t);if(Ye.existsSync(r))return r;let o=ee.join(En,"..","node_modules",".bin",t);if(Ye.existsSync(o))return o}var ir=x("utils"),Rn=e=>new Promise(t=>{setTimeout(t,e)}),qe=(e,t=3e3)=>{let r=!1,o=null,n=[],i=null,a=(...s)=>{if(r)return o=s,new Promise(l=>{n.push(l)});r=!0;let c,d=new Promise(l=>{c=l});return i=(async()=>{await Promise.resolve();let l=await e(...s);for(c(l);;){if(await Rn(t),!o)return r=!1,i=null,l;let p=o,m=n;o=null,n=[],l=await e(...p),m.forEach(_=>{_(l)})}})(),d};return a.flush=async()=>{if((r||o)&&i)return await i,a.flush()},a},_e=(e,t,r=!1)=>{let o=null,n=null,i=null,a=function(...s){n=s,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 a.cancel=()=>{clearTimeout(o),o=null,n=null,i=null},a.flush=()=>{if(o){clearTimeout(o);let s=n,c=i;o=null,n=null,i=null,e.apply(c,s)}},a},Be=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(o){t&&(r?.error?r.error("Could not parse JSON",o):ir.error("Could not parse JSON",o))}},ft=e=>e.charAt(0).toUpperCase()+e.slice(1),ie=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():ft(t)).join(" ");function ce(e,t){t&&e.log(`Skill invoked: ${t}`)}var sr=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),ar=(e,t)=>{let n=".netlify.app",i="agent-";if(!t)return`${i}${e.slice(0,6)}`;let s=`--${t}${n}`;if(s.length>55)return"";let c=60-s.length;if(c<=0)return"";if(c>=i.length+6){let d=Math.min(c-i.length,e.length);return`${i}${e.slice(0,d)}`}return e.slice(0,c)},An=e=>!e||typeof e!="object"||Array.isArray(e)||Object.keys(e).length===0?!1:!!er.some(t=>t in e),lr=()=>{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);An(i)&&(e[r]=i)}catch(i){let s=i instanceof SyntaxError?"Invalid JSON":i.message;ir.error(`Could not parse ${r} model version override from ${n}: ${s}`)}}}),e},Cn=50*1024,ht=(e,t=Cn)=>{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 cr}from"buffer";import bn from"path";var ur=x("repo"),pr=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{ur.info("Getting runner diffs");let o=await kn(r),{hasChanges:n}=o,{status:i}=o;if(!n)return{hasChanges:!1};if(!t){let h=On(i);await $n(h,r)}ur.info("Changes after processing"),await _t(r);let a=await wt(i,r);if(await yt(a,r),n=await Nn(r),!n)return{hasChanges:!1,ignored:a};process.env.NETLIFY_INTERNAL_GIT="1";try{await P("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let s={stdio:["ignore","pipe","pipe"],cwd:r},c=await P("git",["diff",e.runSha,"HEAD"],s),d=String(c.stdout??"");if(n=!!d,!n)return await dr(r),{hasChanges:!1,ignored:a};let l=await P("git",["diff",e.runSha,"HEAD","--binary"],s),p=String(l.stdout??""),m,_;if(e.sha){let h=await P("git",["diff",e.sha,"HEAD"],s);m=String(h.stdout??"");let v=await P("git",["diff",e.sha,"HEAD","--binary"],s),y=String(v.stdout??"");m!==y&&(_=cr.from(y).toString("base64"))}await dr(r);let f={hasChanges:!0,diff:d,resultDiff:m,ignored:a};return d!==p&&(f.diffBinary=cr.from(p).toString("base64")),_&&(f.resultDiffBinary=_),f},dr=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await P("git",["reset","--soft","HEAD~1"],{cwd:e})},yt=async(e=[],t=process.cwd())=>{process.env.NETLIFY_INTERNAL_GIT="1";try{await P("git",["add",".",...e],{cwd:t})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}},_t=async(e=process.cwd())=>{let t=await P("git",["status","-s"],{cwd:e});return String(t.stdout??"")},mr=/.. (.+)?\.log$/,Pn=[mr],kn=async(e=process.cwd())=>{let t=await _t(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
9
9
|
`).filter(n=>Pn.some(a=>a instanceof RegExp?a.test(n):n===a)?!1:n[1]?.trim()!=="")).length!==0,status:t}},Nn=async(e=process.cwd())=>{try{return await P("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},Et=async(e=process.cwd())=>{let{stdout:t}=await P("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},gr=async(e=process.cwd())=>{let{stdout:t}=await P("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},wt=async(e,t=process.cwd())=>{e||=await _t(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(a=>{let s=n===`?? ${a}`,c=n.startsWith(`?? ${a}/`)||n.startsWith(`?? ${a}${bn.sep}`);(s||c)&&o.push(`:!${a}`)});let i=n.match(mr)?.[1];i&&o.push(`:!${i}.log`)}),o},xt=async(e=process.cwd())=>{await P("git",["reset","--hard","HEAD"],{cwd:e})},On=e=>{let t=e.split(`
|
|
11
11
|
`).reduce((r,o)=>{if(!o)return r;let[n,i,,...a]=o,s=a.join(""),c=n.trim(),d=i.trim();return r[s]?r[s].change=d:r[s]={filePath:s,stage:c,change:d},r},{});return Object.values(t)},$n=async(e,t=process.cwd())=>{let r=e.filter(o=>o.stage&&!o.change).map(o=>o.filePath);r.length!==0&&await P("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
|
|
@@ -167,7 +167,7 @@ Deploy failed failed. Here are the errors to review on the latest build:
|
|
|
167
167
|
Below are all of the logs with potential issues that we extracted. Some of them may be false positives, discern them carefully and ensure fixes are relevant.
|
|
168
168
|
|
|
169
169
|
${e.pop()}
|
|
170
|
-
`;import wo from"process";import{getTracer as Pt}from"@netlify/otel";import{getTracer as _o}from"@netlify/otel";var $e=x("deploy"),Mr=async e=>await b(_o(),"create-preview-deploy",async t=>Eo(e,t)),Eo=async({netlify:e,hasRepo:t,skipBuild:r,message:o="Agent Preview",deploySubdomain:n,cliPath:i,filter:a,prodDeploy:s,apiToken:c},d)=>{try{let l=["deploy","--message",`"${o}"`,"--json","--verbose",s?"--prod":"--draft"];t||($e.log("Deploy: Uploading source zip"),l.push("--upload-source-zip")),n&&l.push("--alias",n),a&&l.push("--filter",a),r?($e.log("Deploy: Skipping build"),l.push("--no-build")):l.push("--context",s?"production":"deploy-preview");let p=[...l];l.push("--auth",c);let m=i||"netlify";$e.log(`Running: ${m} ${p.join(" ")}`),d?.setAttributes({cmd:m,args:l});let _=await e.utils.run(m,l,{stdio:["ignore","pipe","pipe"]}),f=JSON.parse(String(_.stdout??"").trim());d?.setAttributes({success:!0,deployId:f.deploy_id,deployUrl:f.deploy_url,siteId:f.site_id}),$e.log(`
|
|
170
|
+
`;import wo from"process";import{getTracer as Pt}from"@netlify/otel";import{getTracer as _o}from"@netlify/otel";var $e=x("deploy"),Mr=async e=>await b(_o(),"create-preview-deploy",async t=>Eo(e,t)),Eo=async({netlify:e,hasRepo:t,skipBuild:r,message:o="Agent Preview",deploySubdomain:n,cliPath:i,filter:a,prodDeploy:s,apiToken:c},d)=>{try{let l=["deploy","--message",`"${o}"`,"--json","--verbose",s?"--prod":"--draft"];t||($e.log("Deploy: Uploading source zip"),l.push("--upload-source-zip")),n&&!s&&l.push("--alias",n),a&&l.push("--filter",a),r?($e.log("Deploy: Skipping build"),l.push("--no-build")):l.push("--context",s?"production":"deploy-preview");let p=[...l];l.push("--auth",c);let m=i||"netlify";$e.log(`Running: ${m} ${p.join(" ")}`),d?.setAttributes({cmd:m,args:l});let _=await e.utils.run(m,l,{stdio:["ignore","pipe","pipe"]}),f=JSON.parse(String(_.stdout??"").trim());d?.setAttributes({success:!0,deployId:f.deploy_id,deployUrl:f.deploy_url,siteId:f.site_id}),$e.log(`
|
|
171
171
|
Preview deploy created successfully:`,{deployId:f.deploy_id,deployUrl:f.deploy_url,siteId:f.site_id});let h={deployId:f.deploy_id,previewUrl:f.deploy_url,logsUrl:f.logs,siteId:f.site_id};return t||(h.sourceZipFilename=f.source_zip_filename),h}catch(l){throw $e.error("Failed to create preview deploy via CLI:",l),d?.setAttributes({success:!1,error:l.message}),l}};var Ur=e=>["dtn-prod-iteration","create"].includes(e);var Fe=x("deploy_stage"),Ze=async e=>await b(Pt(),"run-deploy-stage",async()=>xo(e)),xo=async({cliPath:e,config:t,context:r,result:o,filter:n,isRetry:i,apiToken:a})=>{let s=await b(Pt(),"get-runner-diffs",async()=>await pr({config:t,isRetry:i}));if(Fe.info("Resolved git",{hasChanges:s.hasChanges,ignored:s.ignored??[]}),!s.hasChanges&&t.mode!=="redeploy")return{diff:"",hasChanges:!1,previewInfo:null};let c=s.hasChanges?s.diff:"",d=s.hasChanges?s.resultDiff:void 0,l=s.hasChanges?s.diffBinary:void 0,p=s.hasChanges?s.resultDiffBinary:void 0,m=s.hasChanges||t.mode==="redeploy";Fe.log("Deploy condition check:",{resultUndefined:o===void 0,resultType:typeof o,hasChanges:m,isRedeploy:t.mode==="redeploy",wouldCreateDeploy:o!==void 0&&(m||t.mode==="redeploy")});let _=null;if(o!==void 0&&(m||t.mode==="redeploy"))try{let f;try{let h=await b(Pt(),"get-runner-session",async()=>await qt(t.id,t.sessionId));h?.title&&(f=h.title)}catch(h){Fe.warn("Failed to fetch session title, using fallback message:",h.message)}await W(t.id,t.sessionId,{steps:[{title:"Deploying the run preview",category:E.Deployment}]}),_=await Mr({cliPath:e,netlify:r,hasRepo:t.hasRepo,message:f,skipBuild:!1,deploySubdomain:ar(t.id,wo.env.SITE_NAME),filter:n,prodDeploy:Ur(t.mode),apiToken:a})}catch(f){return Fe.warn("Failed to create preview deploy (continuing with agent run):",f),{diff:c,resultDiff:d,hasChanges:m,previewInfo:null,diffBinary:l,resultDiffBinary:p,deployError:f instanceof Error?f.message:String(f)}}return Fe.log("Git status",{hasDiff:!!c,hasChanges:m}),{diff:c,resultDiff:d,hasChanges:m,previewInfo:_,diffBinary:l,resultDiffBinary:p}};import{getTracer as tt}from"@netlify/otel";async function Gr(e,t){let{maxRetries:r,baseDelay:o,onRetry:n}=t,i;for(let a=1;a<=r;a++)try{return await e()}catch(s){if(i=s,a===r)throw i;n&&n(a,i),await new Promise(c=>setTimeout(c,o*a))}throw i}var Qe=class{scanDiffForForms(t){let r=[],o=null,n=[],i=t.split(`
|
|
172
172
|
`);for(let a of i)if(a.startsWith("diff --git")){if(o&&n.length>0){let c=this.containsNetlifyForm(n,o);c&&r.push(c)}let s=a.split(" ");o=s[s.length-1].replace(/^b\//,""),n=[]}else a.startsWith("+")&&!a.startsWith("+++")&&n.push(a.slice(1));if(o&&n.length>0){let a=this.containsNetlifyForm(n,o);a&&r.push(a)}return{detected:r.length>0,matches:r}}containsNetlifyForm(t,r){let o=t.join(`
|
|
173
173
|
`),n=[{pattern:/<[\w-]*form[\s\S]*?(data-)?netlify/i,name:"standard form element"},{pattern:/<[A-Z][\w]*[\s\S]*?component\s*=\s*["']form["'][\s\S]*?(data-)?netlify/i,name:"component with form prop"}];for(let{pattern:i,name:a}of n){let s=o.match(i);if(s){let c=s.index||0,d=Math.max(0,c-20),l=Math.min(o.length,c+s[0].length+20),p=o.slice(d,l).trim();return p=p.replace(/\s+/g," "),p.length>100&&(p=p.slice(0,97)+"..."),{file:r,snippet:`[${a}] ${p}`}}}return null}};var et=class{scanDiffForIdentity(t){let r=[],o=null,n=[],i=t.split(`
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import{createRequire as hi}from"module";import{createTracerProvider as Gr}from"@
|
|
|
4
4
|
${a}
|
|
5
5
|
</extracted_error_chunk>`).join(`
|
|
6
6
|
|
|
7
|
-
`);return o.length>e.length*.8?e:o}import{execSync as Un}from"child_process";import Er from"fs/promises";import Gn from"path";import ue from"process";import{getTracer as jn}from"@netlify/otel";import Ie from"process";var K=class extends Error{constructor(r,i,n,o=!1){super(r);this.statusCode=i;this.userMessage=n;this.isCreditLimitExceeded=o;this.name="GracefulShutdownError"}},De=e=>e instanceof K;var Le=Ie.env.NETLIFY_API_URL,Me=Ie.env.NETLIFY_API_TOKEN,B=x("api"),me=()=>Ie.env.NETLIFY_LOCAL_MODE==="true",te=async(e,t={})=>{if(!Le||!Me)throw new Error("No API URL or token");let r=new URL(e,Le),i={...t,headers:{...t.headers,Authorization:`Bearer ${Me}`}};Ie.env.AGENT_RUNNERS_DEBUG==="true"&&(i.headers["x-nf-debug-logging"]="true"),t.json&&(i.headers||={},i.headers["Content-Type"]="application/json",i.body=JSON.stringify(t.json));let n=await fetch(r,i),o=n.ok&&n.status<=299;if(Ie.env.AGENT_RUNNERS_DEBUG==="true")B.log(`Response headers for ${r}:`),n.headers.forEach((s,c)=>{B.log(` ${c}: ${s}`)});else{let s=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");B.log(`Request ID for ${r}: ${s||"N/A"}`)}if(o||B.error(`Got status ${n.status} for request ${r}`),t.raw){if(!o)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let a=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!o){let s=typeof a=="string"?a:JSON.stringify(a);throw n.status===404?new K(`API request failed: 404 - ${s}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&s.toLowerCase().includes("usage exceeded")?new K(`API request failed: 503 - ${s}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${s}`)}return a},Pt=e=>{B.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Le=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Me=e.constants.NETLIFY_API_TOKEN)},Nt=()=>({apiUrl:Le,token:Me}),Re=async(e,t)=>me()?(B.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):te(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),W=async(e,t,r)=>me()?(B.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):te(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Ot=async e=>me()?(B.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):te(`/api/v1/sites/${e}`),$t=async(e,t)=>me()?(B.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):te(`/api/v1/agent_runners/${e}/sessions/${t}`),Ft=(e,t,r)=>te(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Dt=(e,t,r)=>te(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Lt=async(e,t)=>me()?(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"}}):te(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Mt=async(e,t)=>me()?(B.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):te(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),rt=async(e,t)=>{B.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ge=x("ai_gateway"),nt=null;var Ut=async()=>{if(nt)return nt;ge.log("Fetching available AI gateway providers");let e=await fetch(`${Nt().apiUrl}/api/v1/ai-gateway/providers`);if(!e.ok)throw new Error(`Failed to fetch AI gateway providers: ${e.statusText}`);let t=await e.json();return nt=t,ge.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},Hr=async(e,t)=>{let i=(await Ut()).providers[e];if(!i)return ge.log(`Provider '${e}' not found`),!1;let n=i.models.includes(t);return ge.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Gt=async({config:e})=>{let t,r,i,n,o=!e.site?.published_deploy;if(!(o?e.accountId:e.siteId))throw new Error(`No entity id for ${o?"account":"site"}`);let s=async()=>{clearTimeout(i),ge.log("Requesting AI gateway information");let d=await(o?Ft(e.accountId,e.id,e.sessionId):Dt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=d,r=d.expires_at?d.expires_at*1e3:void 0,ge.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let l=r-Date.now()-6e4;l>0&&(i=setTimeout(()=>{s()},l))}};return await Promise.all([s(),Ut()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:Hr}};import V from"process";import Q from"path";import Ue from"fs";import{fileURLToPath as Qr}from"url";import{createRequire as en}from"module";import{execa as tn,execaCommand as zi}from"execa";import{Transform as Kr}from"stream";function Jr(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function Vr(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function zr(){let t=Jr().map(r=>process.env[r]).filter(r=>!(!r||Vr(r)));return[...new Set(t)].sort((r,i)=>i.length-r.length)}function Z(e){if(typeof e!="string")return e;let t=zr();if(t.length===0)return e;let r=e;return t.forEach(i=>{let n=new RegExp(Xr(i),"g");r=r.replace(n,"******")}),r}function Xr(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var fe=class extends Kr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,i){let n=t.toString(),o=Z(n);i(null,o)}};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(i,n,o){let a=typeof i=="string"?Z(i):i;return typeof n=="function"?t(a,n):t(a,n,o)},process.stderr.write=function(i,n,o){let a=typeof i=="string"?Z(i):i;return typeof n=="function"?r(a,n):r(a,n,o)}}var be=null,Yt=e=>(be&&be.destroy(),be=new re({totalAllowedTime:e}),be),qt=()=>be;var re=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,i)=>{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.`)}),o=null,a=null;i!==void 0&&(a=new Promise((s,c)=>{o=setTimeout(()=>{c(new Error(`${t} stage exceeded its maximum duration of ${i}ms`))},i)}));try{return a?await Promise.race([r(),a]):await r()}finally{n(),o&&clearTimeout(o)}};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 Bt="netlify-agent-runner-context.md",it="task-history",J=".netlify",se="results.md",ot="assets";var Wt="free";var ae=1800*1e3,w={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 Ht={name:"@netlify/agent-runner-cli",type:"module",version:"1.88.0-alpha.0",description:"CLI tool for running Netlify agents",main:"./dist/index.js",types:"./dist/index.d.ts",exports:"./dist/index.js",bin:{"agent-runner-cli":"./dist/bin.js","agent-runner-cli-local":"./dist/bin-local.js"},files:["dist/**/*.js","dist/**/*.d.ts","dist/skills/**","patches","scripts"],scripts:{build:"tsup",dev:"tsup --watch",prepare:"husky install node_modules/@netlify/eslint-config-node/.husky/",prepublishOnly:"npm ci && npm test",prepack:"npm run build",test:"run-s build format test:dev",format:"run-s build format:check-fix:*","format:ci":"run-s build format:check:*","format:check-fix:lint":"run-e format:check:lint format:fix:lint","format:check:lint":"cross-env-shell eslint $npm_package_config_eslint","format:fix:lint":"cross-env-shell eslint --fix $npm_package_config_eslint","format:check-fix:prettier":"run-e format:check:prettier format:fix:prettier","format:check:prettier":"cross-env-shell prettier --check $npm_package_config_prettier","format:fix:prettier":"cross-env-shell prettier --write $npm_package_config_prettier","test:dev":"run-s build test:dev:*","test:ci":"run-s build test:ci:*","test:dev:vitest":"LOG=0 vitest --exclude '**/integration/**'","test:ci:vitest":"LOG=0 c8 -r lcovonly -r text -r json vitest --exclude '**/integration/**'","test:integration":"vitest run test/integration/","test:integration:codex":"vitest run test/integration/codex.test.ts","test:integration:claude":"vitest run test/integration/claude.test.ts","test:integration:gemini":"vitest run test/integration/gemini.test.ts","test:integration:create-stage":"vitest run test/integration/create.test.ts","test:integration:skill-invocation":"vitest run test/integration/skill-invocation.test.ts",postinstall:"node scripts/postinstall.js"},config:{eslint:'--cache --format=codeframe --max-warnings=0 "{src,scripts,test,.github}/**/*.{js,ts,md,html}"',prettier:'--ignore-path .gitignore --loglevel=warn "{src,scripts,test,.github}/**/*.{js,ts,md,yml,json,html}" "*.{js,ts,yml,json,html}" ".*.{js,ts,yml,json,html}" "!**/package-lock.json" "!package-lock.json" "!src/skills/**/*.md"'},keywords:[],license:"MIT",repository:"netlify/agent-runner-cli",bugs:{url:"https://github.com/netlify/agent-runner-cli/issues"},author:"Netlify Inc.",directories:{test:"test"},devDependencies:{"@commitlint/cli":"^20.0.0","@commitlint/config-conventional":"^20.0.0","@eslint/compat":"^2.0.0","@eslint/js":"^9.35.0","@netlify/eslint-config-node":"^7.0.1","@types/node":"^24.5.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","@vitest/eslint-plugin":"^1.6.6",c8:"^10.0.0","eslint-config-prettier":"^10.1.8","eslint-plugin-n":"^17.0.0",husky:"^9.0.0","patch-package":"^8.0.0",tsup:"^8.5.0",typescript:"^5.0.0","typescript-eslint":"^8.44.0",vitest:"^4.0.16"},dependencies:{"@anthropic-ai/claude-code":"2.1.63","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.1","@openai/codex":"0.110.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.7.2",minimist:"^1.2.8",openai:"6.26.0"}};var rn=Qr(import.meta.url),nn=Q.dirname(rn),on=en(import.meta.url),he=x("shell"),st=new Set,sn={preferLocal:!0},k=(e,t,r)=>{let[i,n]=an(t,r),o={...sn,...n},a=tn(e,i,o);ln(a,o),un(a);let s=r?.idleTimeout;return s&&s>0&&cn(a,s),a};var an=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},ln=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(V.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new fe).pipe(V.stdout),e.stdout?.pipe(new fe).pipe(V.stdout),e.stderr?.pipe(new fe).pipe(V.stderr);return}e.stdout?.pipe(V.stdout),e.stderr?.pipe(V.stderr)},at=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(V.kill(-e.pid,t),he.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return he.error("Error killing process:",r),!1}},Kt=e=>at(e,"SIGKILL"),cn=(e,t)=>{let r=null,i=()=>{he.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),at(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(he.log(`Force killing idle process ${e.pid}`),Kt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(i,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let o=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",o),e.on("error",o)},un=e=>{st.add(e);let t=qt();if(t){let r=t.onTimesUp(()=>{he.log(`Global timer expired, killing process ${e.pid}`),at(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(he.log(`Force killing process ${e.pid} after timeout`),Kt(e))},5e3)});e.on("exit",()=>{st.delete(e),r()}),e.on("error",()=>{st.delete(e),r()})}};function ne(e,t){if(!V.env.NETLIFY_LOCAL_MODE)try{let n=on.resolve(Ht.name),o=Q.dirname(n);for(;o!==Q.dirname(o);){let a=Q.dirname(o);if(Q.basename(a)==="node_modules"){let s=Q.join(a,".bin",t);if(Ue.existsSync(s))return s;break}o=a}}catch(n){console.error("Could not resolve package.json",n)}if(V.env.NODE_PATH){let n=Q.join(V.env.NODE_PATH,".bin",t);if(Ue.existsSync(n))return n}let r=Q.join(e,"node_modules",".bin",t);if(Ue.existsSync(r))return r;let i=Q.join(nn,"..","node_modules",".bin",t);if(Ue.existsSync(i))return i}var dn=x("utils"),pn=e=>new Promise(t=>{setTimeout(t,e)}),Ge=(e,t=3e3)=>{let r=!1,i=null,n=[],o=null,a=(...s)=>{if(r)return i=s,new Promise(l=>{n.push(l)});r=!0;let c,d=new Promise(l=>{c=l});return o=(async()=>{await Promise.resolve();let l=await e(...s);for(c(l);;){if(await pn(t),!i)return r=!1,o=null,l;let p=i,m=n;i=null,n=[],l=await e(...p),m.forEach(E=>{E(l)})}})(),d};return a.flush=async()=>{if((r||i)&&o)return await o,a.flush()},a},ye=(e,t,r=!1)=>{let i=null,n=null,o=null,a=function(...s){n=s,o=this;let c=r&&!i;clearTimeout(i),i=setTimeout(()=>{i=null,r||(e.apply(o,n),n=null,o=null)},t),c&&(e.apply(o,n),n=null,o=null)};return a.cancel=()=>{clearTimeout(i),i=null,n=null,o=null},a.flush=()=>{if(i){clearTimeout(i);let s=n,c=o;i=null,n=null,o=null,e.apply(c,s)}},a},Jt=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(i){t&&(r?.error?r.error("Could not parse JSON",i):dn.error("Could not parse JSON",i))}},lt=e=>e.charAt(0).toUpperCase()+e.slice(1),ie=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():lt(t)).join(" ");function le(e,t){t&&e.log(`Skill invoked: ${t}`)}var Vt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),zt=(e,t)=>{let n=".netlify.app",o="agent-";if(!t)return`${o}${e.slice(0,6)}`;let s=`--${t}${n}`;if(s.length>55)return"";let c=60-s.length;if(c<=0)return"";if(c>=o.length+6){let d=Math.min(c-o.length,e.length);return`${o}${e.slice(0,d)}`}return e.slice(0,c)};var mn=50*1024,ct=(e,t=mn)=>{if(!e||typeof e!="string"||e.length<=t)return e;let i=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+i};import{Buffer as Xt}from"buffer";import gn from"path";var Zt=x("repo"),er=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{Zt.info("Getting runner diffs");let i=await hn(r),{hasChanges:n}=i,{status:o}=i;if(!n)return{hasChanges:!1};if(!t){let h=wn(o);await _n(h,r)}Zt.info("Changes after processing"),await dt(r);let a=await mt(o,r);if(await ut(a,r),n=await yn(r),!n)return{hasChanges:!1,ignored:a};process.env.NETLIFY_INTERNAL_GIT="1";try{await k("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let s={stdio:["ignore","pipe","pipe"],cwd:r},c=await k("git",["diff",e.runSha,"HEAD"],s),d=String(c.stdout??"");if(n=!!d,!n)return await Qt(r),{hasChanges:!1,ignored:a};let l=await k("git",["diff",e.runSha,"HEAD","--binary"],s),p=String(l.stdout??""),m,E;if(e.sha){let h=await k("git",["diff",e.sha,"HEAD"],s);m=String(h.stdout??"");let v=await k("git",["diff",e.sha,"HEAD","--binary"],s),y=String(v.stdout??"");m!==y&&(E=Xt.from(y).toString("base64"))}await Qt(r);let f={hasChanges:!0,diff:d,resultDiff:m,ignored:a};return d!==p&&(f.diffBinary=Xt.from(p).toString("base64")),E&&(f.resultDiffBinary=E),f},Qt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await k("git",["reset","--soft","HEAD~1"],{cwd:e})},ut=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"}},dt=async(e=process.cwd())=>{let t=await k("git",["status","-s"],{cwd:e});return String(t.stdout??"")},tr=/.. (.+)?\.log$/,fn=[tr],hn=async(e=process.cwd())=>{let t=await dt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
7
|
+
`);return o.length>e.length*.8?e:o}import{execSync as Un}from"child_process";import Er from"fs/promises";import Gn from"path";import ue from"process";import{getTracer as jn}from"@netlify/otel";import Ie from"process";var K=class extends Error{constructor(r,i,n,o=!1){super(r);this.statusCode=i;this.userMessage=n;this.isCreditLimitExceeded=o;this.name="GracefulShutdownError"}},De=e=>e instanceof K;var Le=Ie.env.NETLIFY_API_URL,Me=Ie.env.NETLIFY_API_TOKEN,B=x("api"),me=()=>Ie.env.NETLIFY_LOCAL_MODE==="true",te=async(e,t={})=>{if(!Le||!Me)throw new Error("No API URL or token");let r=new URL(e,Le),i={...t,headers:{...t.headers,Authorization:`Bearer ${Me}`}};Ie.env.AGENT_RUNNERS_DEBUG==="true"&&(i.headers["x-nf-debug-logging"]="true"),t.json&&(i.headers||={},i.headers["Content-Type"]="application/json",i.body=JSON.stringify(t.json));let n=await fetch(r,i),o=n.ok&&n.status<=299;if(Ie.env.AGENT_RUNNERS_DEBUG==="true")B.log(`Response headers for ${r}:`),n.headers.forEach((s,c)=>{B.log(` ${c}: ${s}`)});else{let s=n.headers.get("x-request-id")||n.headers.get("x-nf-request-id");B.log(`Request ID for ${r}: ${s||"N/A"}`)}if(o||B.error(`Got status ${n.status} for request ${r}`),t.raw){if(!o)throw new Error(`API request failed: ${n.status} ${n.statusText}`);return n}let a=await(n.headers.get("content-type")?.includes("application/json")?n.json():n.text());if(!o){let s=typeof a=="string"?a:JSON.stringify(a);throw n.status===404?new K(`API request failed: 404 - ${s}`,404,"The site associated with this agent run no longer exists."):n.status===503&&t.gracefulOn503&&s.toLowerCase().includes("usage exceeded")?new K(`API request failed: 503 - ${s}`,503,"Credit limit reached. Please add more credits to continue using Agent Runners.",!0):new Error(`API request failed: ${n.status} - ${s}`)}return a},Pt=e=>{B.log("Setting details for api",{apiUrl:e?.constants?.NETLIFY_API_HOST,token:!!e?.constants?.NETLIFY_API_TOKEN}),e?.constants?.NETLIFY_API_HOST&&(Le=`https://${e.constants.NETLIFY_API_HOST}`),e?.constants?.NETLIFY_API_TOKEN&&(Me=e.constants.NETLIFY_API_TOKEN)},Nt=()=>({apiUrl:Le,token:Me}),Re=async(e,t)=>me()?(B.log("Mock API: updateRunner called",{runnerId:e,data:t}),{id:e,...t}):te(`/api/v1/agent_runners/${e}`,{method:"PUT",json:t}),W=async(e,t,r)=>me()?(B.log("Mock API: updateRunnerSession called",JSON.stringify({runnerId:e,sessionId:t,data:r},null,2)),{id:e,sessionId:t,...r}):te(`/api/v1/agent_runners/${e}/sessions/${t}`,{method:"PUT",json:r});var Ot=async e=>me()?(B.log("Mock API: getSite called",{siteId:e}),{id:e,published_deploy:{id:"id"}}):te(`/api/v1/sites/${e}`),$t=async(e,t)=>me()?(B.log("Mock API: getRunnerSession called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,state:"running"}):te(`/api/v1/agent_runners/${e}/sessions/${t}`),Ft=(e,t,r)=>te(`/api/v1/accounts/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Dt=(e,t,r)=>te(`/api/v1/sites/${e}/ai-gateway/token`,{headers:{"X-Nf-Agent-Runner-Id":t,"X-Nf-Agent-Runner-Session-Id":r},gracefulOn503:!0}),Lt=async(e,t)=>me()?(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"}}):te(`/api/v1/agent_runners/${e}/sessions/${t}/diff/upload_urls`,{method:"POST"}),Mt=async(e,t)=>me()?(B.log("Mock API: updateSessionUsage called",{runnerId:e,sessionId:t}),{id:t,runnerId:e,usage:0}):te(`/api/v1/agent_runners/${e}/sessions/${t}/update_usage`,{method:"POST"}),rt=async(e,t)=>{B.log(`Uploading diff to S3: ${e.substring(0,50)}...`);let r=await fetch(e,{method:"PUT",body:t,headers:{"Content-Type":"text/plain"}});if(!r.ok)throw new Error(`S3 upload failed with status ${r.status}`);return r};var ge=x("ai_gateway"),nt=null;var Ut=async()=>{if(nt)return nt;ge.log("Fetching available AI gateway providers");let e=await fetch(`${Nt().apiUrl}/api/v1/ai-gateway/providers`);if(!e.ok)throw new Error(`Failed to fetch AI gateway providers: ${e.statusText}`);let t=await e.json();return nt=t,ge.log("Cached AI gateway providers",{providerCount:Object.keys(t.providers).length}),t},Hr=async(e,t)=>{let i=(await Ut()).providers[e];if(!i)return ge.log(`Provider '${e}' not found`),!1;let n=i.models.includes(t);return ge.log(`Model validation for ${e}/${t}`,{isAvailable:n}),n},Gt=async({config:e})=>{let t,r,i,n,o=!e.site?.published_deploy;if(!(o?e.accountId:e.siteId))throw new Error(`No entity id for ${o?"account":"site"}`);let s=async()=>{clearTimeout(i),ge.log("Requesting AI gateway information");let d=await(o?Ft(e.accountId,e.id,e.sessionId):Dt(e.siteId,e.id,e.sessionId));if({token:t,url:n}=d,r=d.expires_at?d.expires_at*1e3:void 0,ge.log("Got AI gateway information",{token:!!t,expiresAt:r,url:n}),r){let l=r-Date.now()-6e4;l>0&&(i=setTimeout(()=>{s()},l))}};return await Promise.all([s(),Ut()]),{get url(){return n},get token(){return t},isModelAvailableForProvider:Hr}};import V from"process";import Q from"path";import Ue from"fs";import{fileURLToPath as Qr}from"url";import{createRequire as en}from"module";import{execa as tn,execaCommand as zi}from"execa";import{Transform as Kr}from"stream";function Jr(){let e=process.env.NETLIFY_SENSITIVE_ENV_KEYS;return e?e.split(",").map(t=>t.trim()).filter(Boolean):[]}function Vr(e){let t=e.toLowerCase();return t==="true"||t==="false"?!0:e.trim().length<4}function zr(){let t=Jr().map(r=>process.env[r]).filter(r=>!(!r||Vr(r)));return[...new Set(t)].sort((r,i)=>i.length-r.length)}function Z(e){if(typeof e!="string")return e;let t=zr();if(t.length===0)return e;let r=e;return t.forEach(i=>{let n=new RegExp(Xr(i),"g");r=r.replace(n,"******")}),r}function Xr(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var fe=class extends Kr{constructor(t={}){super({...t,objectMode:!1})}_transform(t,r,i){let n=t.toString(),o=Z(n);i(null,o)}};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(i,n,o){let a=typeof i=="string"?Z(i):i;return typeof n=="function"?t(a,n):t(a,n,o)},process.stderr.write=function(i,n,o){let a=typeof i=="string"?Z(i):i;return typeof n=="function"?r(a,n):r(a,n,o)}}var be=null,Yt=e=>(be&&be.destroy(),be=new re({totalAllowedTime:e}),be),qt=()=>be;var re=class{constructor({totalAllowedTime:t}){this.withStageTimer=async(t,r,i)=>{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.`)}),o=null,a=null;i!==void 0&&(a=new Promise((s,c)=>{o=setTimeout(()=>{c(new Error(`${t} stage exceeded its maximum duration of ${i}ms`))},i)}));try{return a?await Promise.race([r(),a]):await r()}finally{n(),o&&clearTimeout(o)}};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 Bt="netlify-agent-runner-context.md",it="task-history",J=".netlify",se="results.md",ot="assets";var Wt="free";var ae=1800*1e3,w={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 Ht={name:"@netlify/agent-runner-cli",type:"module",version:"1.88.0-alpha.1",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",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.63","@anthropic-ai/sdk":"0.78.0","@google/gemini-cli":"0.31.0","@netlify/otel":"^5.1.1","@openai/codex":"0.110.0","@opentelemetry/exporter-trace-otlp-grpc":"^0.212.0",execa:"^9.6.1",kaddidlehopper:"^0.7.2",minimist:"^1.2.8",openai:"6.26.0"}};var rn=Qr(import.meta.url),nn=Q.dirname(rn),on=en(import.meta.url),he=x("shell"),st=new Set,sn={preferLocal:!0},k=(e,t,r)=>{let[i,n]=an(t,r),o={...sn,...n},a=tn(e,i,o);ln(a,o),un(a);let s=r?.idleTimeout;return s&&s>0&&cn(a,s),a};var an=function(e,t){return Array.isArray(e)?[e,t]:typeof e=="object"&&e!==null?[[],e]:[[],void 0]},ln=(e,t)=>{if(t.stdio!==void 0||t.stdout!==void 0||t.stderr!==void 0)return;if(V.env.NETLIFY_MASK_LOGS!=="false"){e.all?.pipe(new fe).pipe(V.stdout),e.stdout?.pipe(new fe).pipe(V.stdout),e.stderr?.pipe(new fe).pipe(V.stderr);return}e.stdout?.pipe(V.stdout),e.stderr?.pipe(V.stderr)},at=(e,t="SIGTERM")=>{try{return e.pid&&!e.killed?(V.kill(-e.pid,t),he.log(`Killed process ${e.pid} with signal ${t}`),!0):!1}catch(r){return he.error("Error killing process:",r),!1}},Kt=e=>at(e,"SIGKILL"),cn=(e,t)=>{let r=null,i=()=>{he.log(`Process ${e.pid} killed due to idle timeout (no output for ${t}ms)`),at(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(he.log(`Force killing idle process ${e.pid}`),Kt(e))},5e3)},n=()=>{r&&clearTimeout(r),r=setTimeout(i,t)};n(),e.stdout?.on("data",n),e.stderr?.on("data",n);let o=()=>{r&&(clearTimeout(r),r=null)};e.on("exit",o),e.on("error",o)},un=e=>{st.add(e);let t=qt();if(t){let r=t.onTimesUp(()=>{he.log(`Global timer expired, killing process ${e.pid}`),at(e,"SIGTERM"),setTimeout(()=>{e.pid&&!e.killed&&(he.log(`Force killing process ${e.pid} after timeout`),Kt(e))},5e3)});e.on("exit",()=>{st.delete(e),r()}),e.on("error",()=>{st.delete(e),r()})}};function ne(e,t){if(!V.env.NETLIFY_LOCAL_MODE)try{let n=on.resolve(Ht.name),o=Q.dirname(n);for(;o!==Q.dirname(o);){let a=Q.dirname(o);if(Q.basename(a)==="node_modules"){let s=Q.join(a,".bin",t);if(Ue.existsSync(s))return s;break}o=a}}catch(n){console.error("Could not resolve package.json",n)}if(V.env.NODE_PATH){let n=Q.join(V.env.NODE_PATH,".bin",t);if(Ue.existsSync(n))return n}let r=Q.join(e,"node_modules",".bin",t);if(Ue.existsSync(r))return r;let i=Q.join(nn,"..","node_modules",".bin",t);if(Ue.existsSync(i))return i}var dn=x("utils"),pn=e=>new Promise(t=>{setTimeout(t,e)}),Ge=(e,t=3e3)=>{let r=!1,i=null,n=[],o=null,a=(...s)=>{if(r)return i=s,new Promise(l=>{n.push(l)});r=!0;let c,d=new Promise(l=>{c=l});return o=(async()=>{await Promise.resolve();let l=await e(...s);for(c(l);;){if(await pn(t),!i)return r=!1,o=null,l;let p=i,m=n;i=null,n=[],l=await e(...p),m.forEach(E=>{E(l)})}})(),d};return a.flush=async()=>{if((r||i)&&o)return await o,a.flush()},a},ye=(e,t,r=!1)=>{let i=null,n=null,o=null,a=function(...s){n=s,o=this;let c=r&&!i;clearTimeout(i),i=setTimeout(()=>{i=null,r||(e.apply(o,n),n=null,o=null)},t),c&&(e.apply(o,n),n=null,o=null)};return a.cancel=()=>{clearTimeout(i),i=null,n=null,o=null},a.flush=()=>{if(i){clearTimeout(i);let s=n,c=o;i=null,n=null,o=null,e.apply(c,s)}},a},Jt=(e,t=!0,r)=>{if(e)try{return JSON.parse(e)}catch(i){t&&(r?.error?r.error("Could not parse JSON",i):dn.error("Could not parse JSON",i))}},lt=e=>e.charAt(0).toUpperCase()+e.slice(1),ie=e=>e.split("-").map(t=>t.length===2?t.toUpperCase():lt(t)).join(" ");function le(e,t){t&&e.log(`Skill invoked: ${t}`)}var Vt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),zt=(e,t)=>{let n=".netlify.app",o="agent-";if(!t)return`${o}${e.slice(0,6)}`;let s=`--${t}${n}`;if(s.length>55)return"";let c=60-s.length;if(c<=0)return"";if(c>=o.length+6){let d=Math.min(c-o.length,e.length);return`${o}${e.slice(0,d)}`}return e.slice(0,c)};var mn=50*1024,ct=(e,t=mn)=>{if(!e||typeof e!="string"||e.length<=t)return e;let i=e.startsWith("```")?"\n... [truncated]\n```":"... [truncated]";return e.slice(0,t)+i};import{Buffer as Xt}from"buffer";import gn from"path";var Zt=x("repo"),er=async({config:e,isRetry:t,cwd:r=process.cwd()})=>{Zt.info("Getting runner diffs");let i=await hn(r),{hasChanges:n}=i,{status:o}=i;if(!n)return{hasChanges:!1};if(!t){let h=wn(o);await _n(h,r)}Zt.info("Changes after processing"),await dt(r);let a=await mt(o,r);if(await ut(a,r),n=await yn(r),!n)return{hasChanges:!1,ignored:a};process.env.NETLIFY_INTERNAL_GIT="1";try{await k("git",["commit","-m","Agent runner"],{cwd:r})}finally{process.env.NETLIFY_INTERNAL_GIT="0"}let s={stdio:["ignore","pipe","pipe"],cwd:r},c=await k("git",["diff",e.runSha,"HEAD"],s),d=String(c.stdout??"");if(n=!!d,!n)return await Qt(r),{hasChanges:!1,ignored:a};let l=await k("git",["diff",e.runSha,"HEAD","--binary"],s),p=String(l.stdout??""),m,E;if(e.sha){let h=await k("git",["diff",e.sha,"HEAD"],s);m=String(h.stdout??"");let v=await k("git",["diff",e.sha,"HEAD","--binary"],s),y=String(v.stdout??"");m!==y&&(E=Xt.from(y).toString("base64"))}await Qt(r);let f={hasChanges:!0,diff:d,resultDiff:m,ignored:a};return d!==p&&(f.diffBinary=Xt.from(p).toString("base64")),E&&(f.resultDiffBinary=E),f},Qt=async(e=process.cwd())=>{process.env.NETLIFY_LOCAL_MODE&&await k("git",["reset","--soft","HEAD~1"],{cwd:e})},ut=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"}},dt=async(e=process.cwd())=>{let t=await k("git",["status","-s"],{cwd:e});return String(t.stdout??"")},tr=/.. (.+)?\.log$/,fn=[tr],hn=async(e=process.cwd())=>{let t=await dt(e);return{hasChanges:(t.trim().length===0?[]:t.split(`
|
|
8
8
|
`).filter(n=>fn.some(a=>a instanceof RegExp?a.test(n):n===a)?!1:n[1]?.trim()!=="")).length!==0,status:t}},yn=async(e=process.cwd())=>{try{return await k("git",["diff","--staged","--quiet"],{cwd:e}),!1}catch{return!0}},pt=async(e=process.cwd())=>{let{stdout:t}=await k("git",["rev-parse","HEAD"],{cwd:e});return String(t??"").trim()},rr=async(e=process.cwd())=>{let{stdout:t}=await k("git",["rev-list","--max-parents=0","HEAD"],{cwd:e});return String(t??"").trim()},mt=async(e,t=process.cwd())=>{e||=await dt(t);let r=[".netlify","node_modules","dist",".next","out",".nuxt",".output",".cache",".turbo",".parcel-cache","coverage",".nyc_output","storybook-static","public/build","CLAUDE.local.md"],i=[];return e.split(`
|
|
9
9
|
`).forEach(n=>{r.forEach(a=>{let s=n===`?? ${a}`,c=n.startsWith(`?? ${a}/`)||n.startsWith(`?? ${a}${gn.sep}`);(s||c)&&i.push(`:!${a}`)});let o=n.match(tr)?.[1];o&&i.push(`:!${o}.log`)}),i},gt=async(e=process.cwd())=>{await k("git",["reset","--hard","HEAD"],{cwd:e})},wn=e=>{let t=e.split(`
|
|
10
10
|
`).reduce((r,i)=>{if(!i)return r;let[n,o,,...a]=i,s=a.join(""),c=n.trim(),d=o.trim();return r[s]?r[s].change=d:r[s]={filePath:s,stage:c,change:d},r},{});return Object.values(t)},_n=async(e,t=process.cwd())=>{let r=e.filter(i=>i.stage&&!i.change).map(i=>i.filePath);r.length!==0&&await k("git",["restore","--staged","--worktree","--pathspec-from-file=-"],{cwd:t,input:r.join(`
|
|
@@ -166,7 +166,7 @@ Deploy failed failed. Here are the errors to review on the latest build:
|
|
|
166
166
|
Below are all of the logs with potential issues that we extracted. Some of them may be false positives, discern them carefully and ensure fixes are relevant.
|
|
167
167
|
|
|
168
168
|
${e.pop()}
|
|
169
|
-
`;import ii from"process";import{getTracer as St}from"@netlify/otel";import{getTracer as ri}from"@netlify/otel";var Pe=x("deploy"),Rr=async e=>await C(ri(),"create-preview-deploy",async t=>ni(e,t)),ni=async({netlify:e,hasRepo:t,skipBuild:r,message:i="Agent Preview",deploySubdomain:n,cliPath:o,filter:a,prodDeploy:s,apiToken:c},d)=>{try{let l=["deploy","--message",`"${i}"`,"--json","--verbose",s?"--prod":"--draft"];t||(Pe.log("Deploy: Uploading source zip"),l.push("--upload-source-zip")),n&&l.push("--alias",n),a&&l.push("--filter",a),r?(Pe.log("Deploy: Skipping build"),l.push("--no-build")):l.push("--context",s?"production":"deploy-preview");let p=[...l];l.push("--auth",c);let m=o||"netlify";Pe.log(`Running: ${m} ${p.join(" ")}`),d?.setAttributes({cmd:m,args:l});let E=await e.utils.run(m,l,{stdio:["ignore","pipe","pipe"]}),f=JSON.parse(String(E.stdout??"").trim());d?.setAttributes({success:!0,deployId:f.deploy_id,deployUrl:f.deploy_url,siteId:f.site_id}),Pe.log(`
|
|
169
|
+
`;import ii from"process";import{getTracer as St}from"@netlify/otel";import{getTracer as ri}from"@netlify/otel";var Pe=x("deploy"),Rr=async e=>await C(ri(),"create-preview-deploy",async t=>ni(e,t)),ni=async({netlify:e,hasRepo:t,skipBuild:r,message:i="Agent Preview",deploySubdomain:n,cliPath:o,filter:a,prodDeploy:s,apiToken:c},d)=>{try{let l=["deploy","--message",`"${i}"`,"--json","--verbose",s?"--prod":"--draft"];t||(Pe.log("Deploy: Uploading source zip"),l.push("--upload-source-zip")),n&&!s&&l.push("--alias",n),a&&l.push("--filter",a),r?(Pe.log("Deploy: Skipping build"),l.push("--no-build")):l.push("--context",s?"production":"deploy-preview");let p=[...l];l.push("--auth",c);let m=o||"netlify";Pe.log(`Running: ${m} ${p.join(" ")}`),d?.setAttributes({cmd:m,args:l});let E=await e.utils.run(m,l,{stdio:["ignore","pipe","pipe"]}),f=JSON.parse(String(E.stdout??"").trim());d?.setAttributes({success:!0,deployId:f.deploy_id,deployUrl:f.deploy_url,siteId:f.site_id}),Pe.log(`
|
|
170
170
|
Preview deploy created successfully:`,{deployId:f.deploy_id,deployUrl:f.deploy_url,siteId:f.site_id});let h={deployId:f.deploy_id,previewUrl:f.deploy_url,logsUrl:f.logs,siteId:f.site_id};return t||(h.sourceZipFilename=f.source_zip_filename),h}catch(l){throw Pe.error("Failed to create preview deploy via CLI:",l),d?.setAttributes({success:!1,error:l.message}),l}};var br=e=>["dtn-prod-iteration","create"].includes(e);var Ne=x("deploy_stage"),Je=async e=>await C(St(),"run-deploy-stage",async()=>oi(e)),oi=async({cliPath:e,config:t,context:r,result:i,filter:n,isRetry:o,apiToken:a})=>{let s=await C(St(),"get-runner-diffs",async()=>await er({config:t,isRetry:o}));if(Ne.info("Resolved git",{hasChanges:s.hasChanges,ignored:s.ignored??[]}),!s.hasChanges&&t.mode!=="redeploy")return{diff:"",hasChanges:!1,previewInfo:null};let c=s.hasChanges?s.diff:"",d=s.hasChanges?s.resultDiff:void 0,l=s.hasChanges?s.diffBinary:void 0,p=s.hasChanges?s.resultDiffBinary:void 0,m=s.hasChanges||t.mode==="redeploy";Ne.log("Deploy condition check:",{resultUndefined:i===void 0,resultType:typeof i,hasChanges:m,isRedeploy:t.mode==="redeploy",wouldCreateDeploy:i!==void 0&&(m||t.mode==="redeploy")});let E=null;if(i!==void 0&&(m||t.mode==="redeploy"))try{let f;try{let h=await C(St(),"get-runner-session",async()=>await $t(t.id,t.sessionId));h?.title&&(f=h.title)}catch(h){Ne.warn("Failed to fetch session title, using fallback message:",h.message)}await W(t.id,t.sessionId,{steps:[{title:"Deploying the run preview",category:w.Deployment}]}),E=await Rr({cliPath:e,netlify:r,hasRepo:t.hasRepo,message:f,skipBuild:!1,deploySubdomain:zt(t.id,ii.env.SITE_NAME),filter:n,prodDeploy:br(t.mode),apiToken:a})}catch(f){return Ne.warn("Failed to create preview deploy (continuing with agent run):",f),{diff:c,resultDiff:d,hasChanges:m,previewInfo:null,diffBinary:l,resultDiffBinary:p,deployError:f instanceof Error?f.message:String(f)}}return Ne.log("Git status",{hasDiff:!!c,hasChanges:m}),{diff:c,resultDiff:d,hasChanges:m,previewInfo:E,diffBinary:l,resultDiffBinary:p}};import{getTracer as Xe}from"@netlify/otel";async function Ar(e,t){let{maxRetries:r,baseDelay:i,onRetry:n}=t,o;for(let a=1;a<=r;a++)try{return await e()}catch(s){if(o=s,a===r)throw o;n&&n(a,o),await new Promise(c=>setTimeout(c,i*a))}throw o}var Ve=class{scanDiffForForms(t){let r=[],i=null,n=[],o=t.split(`
|
|
171
171
|
`);for(let a of o)if(a.startsWith("diff --git")){if(i&&n.length>0){let c=this.containsNetlifyForm(n,i);c&&r.push(c)}let s=a.split(" ");i=s[s.length-1].replace(/^b\//,""),n=[]}else a.startsWith("+")&&!a.startsWith("+++")&&n.push(a.slice(1));if(i&&n.length>0){let a=this.containsNetlifyForm(n,i);a&&r.push(a)}return{detected:r.length>0,matches:r}}containsNetlifyForm(t,r){let i=t.join(`
|
|
172
172
|
`),n=[{pattern:/<[\w-]*form[\s\S]*?(data-)?netlify/i,name:"standard form element"},{pattern:/<[A-Z][\w]*[\s\S]*?component\s*=\s*["']form["'][\s\S]*?(data-)?netlify/i,name:"component with form prop"}];for(let{pattern:o,name:a}of n){let s=i.match(o);if(s){let c=s.index||0,d=Math.max(0,c-20),l=Math.min(i.length,c+s[0].length+20),p=i.slice(d,l).trim();return p=p.replace(/\s+/g," "),p.length>100&&(p=p.slice(0,97)+"..."),{file:r,snippet:`[${a}] ${p}`}}}return null}};var ze=class{scanDiffForIdentity(t){let r=[],i=null,n=[],o=t.split(`
|
package/package.json
CHANGED