@workermill/agent 0.9.0 → 0.9.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.
Files changed (3) hide show
  1. package/dist/cli.js +21 -20
  2. package/dist/index.js +14 -13
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,24 +1,25 @@
1
1
  #!/usr/bin/env node
2
- var $t=Object.defineProperty;var wt=(e,o)=>()=>(e&&(o=e(e=0)),o);var yt=(e,o)=>{for(var n in o)$t(e,n,{get:o[n],enumerable:!0})};var Ao={};yt(Ao,{checkPrerequisites:()=>no,findClaudePath:()=>ie,getConfigDir:()=>Tt,getConfigFile:()=>ee,getLogFile:()=>_e,getPidFile:()=>ce,getSystemInfo:()=>Ue,loadConfig:()=>yo,loadConfigFromFile:()=>he,saveConfigToFile:()=>to,validatePrerequisites:()=>Io});import{existsSync as Ne,readFileSync as It,mkdirSync as At,writeFileSync as kt,chmodSync as bt}from"fs";import{execSync as fe}from"child_process";import{hostname as wo,homedir as Se}from"os";import{join as Z}from"path";function Tt(){return Ce}function ee(){return Te}function ce(){return Et}function _e(){return St}function he(){Ne(Te)||(console.error("No config found. Run 'workermill-agent setup' first."),process.exit(1));let e;try{e=It(Te,"utf-8")}catch{console.error("Failed to read config file:",Te),process.exit(1)}let o;try{o=JSON.parse(e)}catch{console.error("Config file is corrupted. Re-run 'workermill-agent setup'."),process.exit(1)}(!o.apiUrl||!o.apiKey)&&(console.error("Config file is missing required fields (apiUrl, apiKey). Re-run 'workermill-agent setup'."),process.exit(1));let n=o.workerImage||"workermill-worker:local";return{apiUrl:o.apiUrl,apiKey:o.apiKey,agentId:o.agentId,maxWorkers:o.maxWorkers||4,pollIntervalMs:o.pollIntervalMs||5e3,heartbeatIntervalMs:o.heartbeatIntervalMs||3e4,githubToken:o.tokens?.github||"",bitbucketToken:o.tokens?.bitbucket||"",gitlabToken:o.tokens?.gitlab||"",workerImage:n}}function to(e){Ne(Ce)||At(Ce,{recursive:!0}),kt(Te,JSON.stringify(e,null,2),"utf-8");try{bt(Te,384)}catch{}}function yo(){let e=process.env.WORKERMILL_API_URL,o=process.env.WORKERMILL_API_KEY;return e||(console.error("WORKERMILL_API_URL is required in .env.remote"),process.exit(1)),o||(console.error("WORKERMILL_API_KEY is required in .env.remote"),console.error("Get your API key from Settings > Integrations on the WorkerMill dashboard."),process.exit(1)),{apiUrl:e.replace(/\/$/,""),apiKey:o,agentId:process.env.AGENT_ID||`agent-${wo()}`,maxWorkers:parseInt(process.env.MAX_WORKERS||"4",10),pollIntervalMs:parseInt(process.env.POLL_INTERVAL_MS||"5000",10),heartbeatIntervalMs:parseInt(process.env.HEARTBEAT_INTERVAL_MS||"30000",10),githubToken:process.env.GITHUB_TOKEN||"",bitbucketToken:process.env.BITBUCKET_TOKEN||"",gitlabToken:process.env.GITLAB_TOKEN||"",workerImage:process.env.WORKER_IMAGE||"workermill-worker:local"}}function ie(){let e=process.platform==="win32",o=e?"where":"which";try{return fe(`${o} claude`,{stdio:"ignore",timeout:1e4}),"claude"}catch{}let n=[];e?n.push(Z(process.env.ProgramFiles||"C:\\Program Files","ClaudeCode","claude.exe"),Z(process.env.LOCALAPPDATA||"","Programs","ClaudeCode","claude.exe"),Z(Se(),"AppData","Local","Programs","ClaudeCode","claude.exe"),Z(Se(),".local","bin","claude.exe")):n.push(Z(Se(),".local","bin","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude");for(let t of n)if(t&&Ne(t))return t;return null}function no(e){let o=[],n=e||"workermill-worker:local";try{let c=fe("docker version --format {{.Server.Version}}",{encoding:"utf-8",timeout:1e4}).trim();o.push({name:"Docker",ok:!0,detail:c})}catch{o.push({name:"Docker",ok:!1,detail:"Not running or not installed"})}let t=ie();if(t)try{let c=fe(`"${t}" --version`,{encoding:"utf-8",timeout:1e4}).trim();o.push({name:"Claude CLI",ok:!0,detail:c})}catch{o.push({name:"Claude CLI",ok:!0,detail:t})}else o.push({name:"Claude CLI",ok:!1,detail:"Not installed"});let r=Se(),i=Z(r,".claude",".credentials.json");Ne(i)?o.push({name:"Claude auth",ok:!0,detail:"Credentials found"}):o.push({name:"Claude auth",ok:!1,detail:"Run 'claude' and complete sign-in"});let s=process.version;parseInt(s.slice(1).split(".")[0],10)>=20?o.push({name:"Node.js",ok:!0,detail:s}):o.push({name:"Node.js",ok:!1,detail:`${s} (need >= 20)`});try{fe(`docker image inspect ${n}`,{stdio:"ignore",timeout:1e4}),o.push({name:"Worker image",ok:!0,detail:n})}catch{o.push({name:"Worker image",ok:!1,detail:`'${n}' not found`})}return o}function Io(){try{fe("docker version",{stdio:"ignore"})}catch{console.error("Docker is not available. Please install Docker and ensure it's running."),process.exit(1)}let e=process.env.WORKER_IMAGE||"workermill-worker:local";try{fe(`docker image inspect ${e}`,{stdio:"ignore"})}catch{console.error(`Worker image '${e}' not found.`),console.error(e==="workermill-worker:local"?"Build it with: ./bin/local-workermill build-worker":`Pull it with: docker pull ${e}`),process.exit(1)}ie()||(console.error("Claude CLI is not installed."),console.error("Install it: curl -fsSL https://claude.ai/install.sh | bash"),process.exit(1));let o=Se(),n=Z(o,".claude",".credentials.json");Ne(n)||(console.error("Claude credentials not found."),console.error("Run 'claude' and complete the sign-in flow to authenticate."),process.exit(1))}function Ue(){let e="unknown";try{e=fe("docker version --format {{.Server.Version}}",{encoding:"utf-8",timeout:1e4}).trim()}catch{}let o="unknown",n=ie();if(n)try{o=fe(`"${n}" --version`,{encoding:"utf-8",timeout:1e4}).trim()}catch{}return{hostname:wo(),platform:process.platform,nodeVersion:process.version,dockerVersion:e,claudeVersion:o}}var Ce,Te,Et,St,oe=wt(()=>{"use strict";Ce=Z(Se(),".workermill"),Te=Z(Ce,"config.json"),Et=Z(Ce,"agent.pid"),St=Z(Ce,"agent.log")});import{existsSync as Gn}from"fs";import{Command as jn}from"commander";oe();import u from"chalk";import Re from"ora";import ro from"inquirer";import{execSync as de,spawnSync as ko}from"child_process";import{existsSync as Ke}from"fs";import{hostname as Ct,homedir as Eo,totalmem as _t,cpus as Rt}from"os";import{join as We}from"path";import Pt from"axios";var Ae=process.platform==="win32";function so(e){try{return de(`${Ae?"where":"which"} ${e}`,{stdio:"ignore",timeout:1e4}),!0}catch{return!1}}function io(e){try{return de(`"${e}" --version`,{encoding:"utf-8",timeout:1e4}).trim()}catch{return null}}function bo(){if(!Ae)return null;if(so("git"))try{let o=de("where git",{encoding:"utf-8",timeout:1e4}).trim().split(`
3
- `)[0],n=We(o,"..","..","bin","bash.exe");if(Ke(n))return n}catch{}let e=[We(process.env.ProgramFiles||"C:\\Program Files","Git","bin","bash.exe"),"C:\\Program Files\\Git\\bin\\bash.exe","C:\\Program Files (x86)\\Git\\bin\\bash.exe",We(Eo(),"scoop","apps","git","current","bin","bash.exe")];for(let o of e)if(Ke(o))return o;return null}function xt(){if(Ae)try{return de("winget install Anthropic.ClaudeCode --accept-package-agreements --accept-source-agreements",{stdio:"inherit",timeout:18e4}),!0}catch{return!1}else{if(process.platform==="darwin")try{return de("brew install --cask claude-code",{stdio:"inherit",timeout:18e4}),!0}catch{}try{return de("curl -fsSL https://claude.ai/install.sh | bash",{stdio:"inherit",timeout:12e4}),!0}catch{return!1}}}async function ao(){console.log(),console.log(u.bold.cyan(" WorkerMill Remote Agent Setup")),console.log(u.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),console.log(" Run AI workers locally with your Claude Max subscription."),console.log(" Workers execute on your machine, logs stream to the cloud dashboard."),console.log();let e=Math.round(_t()/(1024*1024*1024)),o=Rt().length;console.log(u.dim(" System")),console.log(` ${u.dim("RAM:")} ${e} GB ${u.dim("CPUs:")} ${o}`),e<8?(console.log(),console.log(u.red(" \u2717 Insufficient RAM")),console.log(u.yellow(" WorkerMill requires at least 8 GB of RAM (16 GB recommended).")),console.log(u.yellow(` Your system has ${e} GB.`)),console.log(),process.exit(1)):e<16?(console.log(u.yellow(` \u26A0 ${e} GB RAM is below the recommended 16 GB.`)),console.log(u.yellow(" Workers may run slowly or be killed by the OS under memory pressure."))):console.log(u.green(" \u2713 System meets requirements")),console.log();let n=Re("Checking Docker...").start();if(so("docker")){let l=io("docker");try{let b=de("docker info --format {{.OSType}}",{encoding:"utf-8",timeout:15e3}).trim();Ae&&b==="windows"&&(n.fail("Docker is running in Windows containers mode"),console.log(),console.log(u.yellow(" WorkerMill workers require Linux containers.")),console.log(u.yellow(" Right-click the Docker Desktop icon in the system tray \u2192")),console.log(u.yellow(" 'Switch to Linux containers...'")),console.log(),console.log(" Then re-run: workermill-agent"),process.exit(1))}catch{n.fail("Docker is installed but the daemon is not running"),console.log(),console.log(u.yellow(" Start Docker Desktop, wait for it to fully initialize,")),console.log(u.yellow(" then re-run: workermill-agent")),process.exit(1)}n.succeed(`Docker ${u.dim(l?`(${l})`:"")}`)}else n.fail("Docker is not installed"),console.log(),console.log(u.yellow(" Docker Desktop is required but must be installed manually:")),console.log(` ${u.cyan("https://docs.docker.com/get-docker/")}`),console.log(),console.log(" Install Docker, start it, then re-run: workermill-agent"),process.exit(1);if(Ae){let l=Re("Checking Git for Windows...").start(),b=bo();b?(l.succeed(`Git for Windows ${u.dim(`(${b})`)}`),process.env.CLAUDE_CODE_GIT_BASH_PATH=b):(l.fail("Git for Windows is not installed"),console.log(),console.log(u.yellow(" Claude Code on Windows requires Git for Windows (Git Bash):")),console.log(` ${u.cyan("https://git-scm.com/downloads/win")}`),console.log(),console.log(" Install Git for Windows, then re-run: workermill-agent"),process.exit(1))}let t=Re("Checking Claude CLI...").start(),r=ie();if(r){let l=io(r);t.succeed(`Claude CLI ${u.dim(l?`(${l})`:"")}`)}else if(t.warn("Claude CLI not found \u2014 installing..."),console.log(),xt()&&(r=ie()),r){let b=io(r);console.log(),console.log(u.green(` \u2713 Claude CLI installed ${u.dim(b?`(${b})`:"")}`))}else console.log(),console.log(u.red(" Claude CLI was installed but could not be found.")),console.log(),Ae?(console.log(u.yellow(" Winget updated your PATH but this shell doesn't have it yet.")),console.log(u.yellow(" Close this terminal, open a new one, and re-run: workermill-agent"))):(console.log(" Try manually:"),console.log(u.cyan(" curl -fsSL https://claude.ai/install.sh | bash")),console.log(" Then re-run: workermill-agent")),process.exit(1);let i=Re("Checking Claude authentication...").start(),s=We(Eo(),".claude",".credentials.json");if(Ke(s))i.succeed("Claude authenticated");else{i.warn("Not authenticated \u2014 launching Claude..."),console.log(),console.log(u.dim(" Claude will open and prompt you to authenticate.")),console.log(u.dim(" Sign in with your Claude Max account, then exit Claude (Ctrl+C).")),console.log();let l={...process.env};if(Ae){let b=bo();b&&(l.CLAUDE_CODE_GIT_BASH_PATH=b)}ko(r,[],{stdio:"inherit",timeout:3e5,env:l}),Ke(s)?(console.log(),console.log(u.green(" \u2713 Claude authenticated"))):(console.log(),console.log(u.red(" Authentication failed or was cancelled.")),console.log(" Try manually: open a new terminal and run 'claude'"),console.log(" Then re-run: workermill-agent"),process.exit(1))}console.log(u.green(" \u2713")+` Node.js ${u.dim(`(${process.version})`)}`),console.log(),console.log(u.bold("Configuration")),console.log();let{apiUrl:a}=await ro.prompt([{type:"input",name:"apiUrl",message:"WorkerMill API URL:",default:"https://workermill.com",validate:l=>l.startsWith("http://")||l.startsWith("https://")?!0:"Must be a valid URL"}]),{apiKey:c}=await ro.prompt([{type:"password",name:"apiKey",message:"API Key (from Settings > Integrations):",mask:"*",validate:l=>l.length>0?!0:"API key is required"}]),h=Re("Validating API key...").start(),w="github",m="",g="";try{let l=await Pt.get(`${a.replace(/\/$/,"")}/api/agent/config`,{headers:{"x-api-key":c},timeout:15e3});w=l.data.scmProvider||"github",m=l.data.workerImageUrl||"",g=l.data.ecrRegistry||"",h.succeed(`Connected! SCM provider: ${w}`)}catch(l){l.response?.status===401?h.fail("Invalid API key. Check Settings > Integrations on the dashboard."):h.fail("Failed to connect to WorkerMill API. Check the URL and try again."),process.exit(1)}console.log(u.dim(" SCM tokens are managed via Settings > Integrations on the dashboard.")),console.log();let{agentId:P}=await ro.prompt([{type:"input",name:"agentId",message:"Agent name:",default:`agent-${Ct()}`}]);console.log();let d=m||"workermill-worker:local",$=g.length>0,v=Re("Checking AWS CLI...").start();if(so("aws"))try{de("aws sts get-caller-identity",{stdio:"pipe",timeout:15e3}),v.succeed("AWS CLI configured")}catch{v.warn("AWS CLI found but credentials not configured"),console.log(),console.log(u.yellow(" Configure AWS credentials for private ECR image access:")),console.log(u.cyan(" aws configure")),console.log(u.dim(" Contact your WorkerMill admin for AWS access key / secret key.")),console.log(u.dim(" Setup will continue \u2014 you can configure AWS later before starting."))}else v.warn("AWS CLI not found"),console.log(),console.log(u.yellow(" AWS CLI is required for pulling worker images from private ECR.")),console.log(u.cyan(" Install: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html")),console.log(u.dim(" Setup will continue \u2014 install AWS CLI before starting the agent."));let A=!1;if($){console.log(),console.log(u.dim(" Authenticating with private ECR..."));let l=g.match(/\.ecr\.([a-z0-9-]+)\.amazonaws\.com/),b=l?l[1]:"us-east-1";try{de(`aws ecr get-login-password --region ${b} | docker login --username AWS --password-stdin ${g}`,{stdio:"pipe",timeout:3e4}),console.log(u.green(" \u2713 ECR authenticated")),A=!0}catch{console.log(u.yellow(" \u26A0 ECR authentication failed (AWS credentials may not be configured yet)")),console.log(u.dim(" Worker image pull will be skipped \u2014 authenticate later with:")),console.log(u.dim(` aws ecr get-login-password --region ${b} | docker login --username AWS --password-stdin ${g}`))}}if(A||!$){console.log(),console.log(u.dim(` Pulling worker image: ${d}`)),console.log(u.dim(" This may take a few minutes on first run (~1.1 GB)...")),console.log();let l=ko("docker",["pull",d],{stdio:"inherit",timeout:6e5});l.status===0?(console.log(),console.log(u.green(" \u2713 Worker image pulled"))):(console.log(),console.log(u.red(" \u2717 Failed to pull worker image.")),l.error&&console.log(u.yellow(` Error: ${l.error.message}`)),console.log(u.dim(" Setup will continue \u2014 you can pull the image later before starting.")))}let B={apiUrl:a.replace(/\/$/,""),apiKey:c,agentId:P,maxWorkers:1,pollIntervalMs:5e3,heartbeatIntervalMs:3e4,tokens:{github:"",bitbucket:"",gitlab:""},workerImage:d,setupCompletedAt:new Date().toISOString()};to(B),console.log(),console.log(u.green.bold(" Setup complete!")),console.log(),console.log(` Config saved to: ${u.dim(ee())}`),console.log(),console.log(` Start the agent with: ${u.cyan("workermill-agent start")}`),console.log()}import U from"chalk";import{totalmem as An}from"os";import{spawn as kn}from"child_process";import{writeFileSync as ct,existsSync as bn,unlinkSync as En,openSync as Sn,createWriteStream as Tn}from"fs";import{createRequire as vt}from"module";var Mt=vt(import.meta.url),Nt=Mt("../package.json"),z=Nt.version;oe();import K from"chalk";import Ot from"axios";var lo=null;function Ge(e,o){lo=Ot.create({baseURL:e,headers:{"Content-Type":"application/json","x-api-key":o},timeout:3e4})}var N=new Proxy({},{get(e,o){if(!lo)throw new Error("API client not initialized. Call initApi() first.");return lo[o]}});import S from"chalk";oe();import p from"chalk";import{spawn as nn,execSync as po}from"child_process";import{spawn as Gt}from"child_process";import we from"chalk";import je from"axios";var Lt=16384,Ft=6e5;async function So(e,o,n,t,r){let i=r?.maxTokens??Lt,s=r?.temperature??.7,a=r?.timeoutMs??Ft;switch(e){case"anthropic":return Dt(o,n,t,i,s,a);case"openai":return Ut(o,n,t,i,s,a);case"google":return Wt(o,n,t,i,s,a);case"ollama":return Kt(o,n,t,i,s,a);default:throw new Error(`Unsupported AI provider: ${e}`)}}async function Dt(e,o,n,t,r,i){let a=(await je.post("https://api.anthropic.com/v1/messages",{model:e,max_tokens:t,temperature:r,messages:[{role:"user",content:o}]},{headers:{"x-api-key":n,"anthropic-version":"2023-06-01","Content-Type":"application/json"},timeout:i})).data?.content;if(Array.isArray(a))return a.filter(c=>c.type==="text").map(c=>c.text).join("");throw new Error("Unexpected Anthropic API response format")}async function Ut(e,o,n,t,r,i){let a=(await je.post("https://api.openai.com/v1/chat/completions",{model:e,max_tokens:t,temperature:r,messages:[{role:"user",content:o}]},{headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},timeout:i})).data?.choices?.[0]?.message;if(a?.content)return a.content;throw new Error("Unexpected OpenAI API response format")}async function Wt(e,o,n,t,r,i){let c=(await je.post(`https://generativelanguage.googleapis.com/v1beta/models/${e}:generateContent?key=${n}`,{contents:[{parts:[{text:o}]}],generationConfig:{maxOutputTokens:t,temperature:r}},{headers:{"Content-Type":"application/json"},timeout:i})).data?.candidates?.[0]?.content?.parts?.[0]?.text;if(c)return c;throw new Error("Unexpected Google AI API response format")}async function Kt(e,o,n,t,r,i){let s=n||"http://localhost:11434",c=(await je.post(`${s}/api/generate`,{model:e,prompt:o,stream:!1,options:{temperature:r}},{headers:{"Content-Type":"application/json"},timeout:i})).data?.response;if(c)return c;throw new Error("Unexpected Ollama API response format")}var $e=null;async function Co(e){if($e)return $e;try{let o={};e!==void 0&&(o.maxTargetFiles=String(e));let{data:n}=await N.get("/api/agent/critic-prompt",{params:o});return $e={promptTemplate:n.promptTemplate,approvalThreshold:n.approvalThreshold??85,maxTargetFiles:n.maxTargetFiles??e??5},te=$e.approvalThreshold,Pe=$e.maxTargetFiles,$e}catch{return console.warn("Failed to fetch critic config from API"),null}}var Pe=5,te=85;function _o(e){let o=e.indexOf("```json");if(o!==-1){let t=o+7,r=e.indexOf("{",t);if(r!==-1){let i=To(e,r);if(i)return JSON.parse(i)}}let n=e.indexOf('"stories"');if(n!==-1){let r=e.substring(0,n).lastIndexOf("{");if(r!==-1){let i=To(e,r);if(i)return JSON.parse(i)}}throw new Error("Could not find JSON execution plan in output")}function To(e,o){let n=0,t=!1,r=!1;for(let i=o;i<e.length;i++){let s=e[i];if(r){r=!1;continue}if(s==="\\"){t&&(r=!0);continue}if(s==='"'){t=!t;continue}if(!t){if(s==="{")n++;else if(s==="}"&&(n--,n===0))return e.substring(o,i+1)}}return null}function Ro(e){let o=0,n=[];for(let t of e.stories)if(!t.targetFiles||!Array.isArray(t.targetFiles))t.targetFiles=[];else if(t.targetFiles.length>Pe){let r=t.targetFiles.slice(Pe);n.push(`${t.id}: ${t.targetFiles.length} files \u2192 ${Pe} (dropped: ${r.join(", ")})`),t.targetFiles=t.targetFiles.slice(0,Pe),o++}return{truncatedCount:o,details:n}}function Po(e,o){if(e.stories.length<=o)return{droppedCount:0,details:[]};let n=e.stories.length-o,r=e.stories.slice(o).map(s=>`${s.id}: "${s.title}" (${s.persona})`);e.stories=e.stories.slice(0,o);let i=new Set(e.stories.map(s=>s.id));for(let s of e.stories)s.dependencies=s.dependencies.filter(a=>i.has(a));return{droppedCount:n,details:r}}function xo(e){let o=new Map,n=0,t=[];for(let r of e.stories){if(!r.targetFiles||r.targetFiles.length===0)continue;let i=[],s=[];for(let a of r.targetFiles)o.get(a)?s.push(a):(o.set(a,r.id),i.push(a));s.length>0&&(r.targetFiles=i,n+=s.length,t.push(`${r.id}: removed ${s.join(", ")} (owned by ${s.map(a=>o.get(a)).join(", ")})`))}return{resolvedCount:n,details:t}}function vo(e){return"```json\n"+JSON.stringify(e,null,2)+"\n```"}function jt(e,o){if(!$e)return null;let n=JSON.stringify(o,null,2);return $e.promptTemplate.replace("{{PRD}}",e).replace("{{PLAN}}",n)}function Bt(e){let o=e.trim();if(o.includes("```")){let r=o.match(/```(?:json)?\s*([\s\S]*?)```/);r&&(o=r[1].trim())}let n=o.indexOf("{");n>0&&(o=o.substring(n));let t=JSON.parse(o);return{approved:t.approved,score:Math.max(0,Math.min(100,Math.round(t.score))),risks:t.risks||[],suggestions:t.suggestions,storyFeedback:Array.isArray(t.storyFeedback)?t.storyFeedback:void 0}}function Vt(e,o,n,t,r){return new Promise((i,s)=>{let a=Gt(e,["--print","--model",o,"--permission-mode","bypassPermissions"],{env:t,stdio:["pipe","pipe","pipe"]});a.stdin.write(n),a.stdin.end();let c="",h="";a.stdout.on("data",m=>{let g=m.toString();c+=g;let P=g.split(`
4
- `).filter(d=>d.trim());for(let d of P){let $=d.trim().length>200?d.trim().substring(0,200)+"\u2026":d.trim();$&&(r&&Oo(r,`${No} [critic] ${$}`,"output"),console.log(`${Oe()} ${we.dim("\u{1F50D}")} ${we.dim($)}`))}}),a.stderr.on("data",m=>{h+=m.toString()});let w=setTimeout(()=>{a.kill("SIGTERM"),s(new Error("Critic CLI timed out after 20 minutes"))},12e5);a.on("exit",m=>{clearTimeout(w),m!==0?s(new Error(`Critic CLI failed (exit ${m}): ${h.substring(0,300)}`)):i(c)}),a.on("error",m=>{clearTimeout(w),s(m)})})}function Mo(e){let o=["","## CRITIC FEEDBACK \u2014 Your previous plan was REJECTED","",`Score: ${e.score}/100 (need >= ${te} to pass)`,""];if(e.risks.length>0){o.push("### Risks Identified:");for(let n of e.risks)o.push(`- ${n}`);o.push("")}if(e.suggestions&&e.suggestions.length>0){o.push("### Required Changes:");for(let n of e.suggestions)o.push(`- ${n}`);o.push("")}if(e.storyFeedback&&e.storyFeedback.length>0){o.push("### Per-Story Feedback:");for(let n of e.storyFeedback)if(o.push(`- **${n.storyId}**: ${n.feedback}`),n.suggestedChanges)for(let t of n.suggestedChanges)o.push(` - ${t}`);o.push("")}return o.push(`**You MUST address ALL feedback above.** Each story must target at most ${Pe} files.`,"Stories MUST NOT overlap on targetFiles.","","**CRITICAL \u2014 OUTPUT FORMAT:** You MUST output a revised plan as a ```json code block containing the full JSON object with `summary`, `stories`, `risks`, and `assumptions` fields. Do NOT just describe what you would change \u2014 output the COMPLETE revised JSON plan. If you do not output a ```json block, the plan will fail to parse and the task will fail.","","**DO NOT re-explore the repository.** You already explored it in the previous attempt. Go directly to outputting the revised ```json plan. Every tool call wastes output budget \u2014 prioritize emitting the JSON plan."),o.join(`
5
- `)}var No="[\u{1F5FA}\uFE0F planning_agent \u{1F916}]";function Oe(){return we.dim(new Date().toLocaleTimeString())}async function Oo(e,o,n="system",t="info"){try{await N.post("/api/control-center/logs",{taskId:e,type:n,message:o,severity:t})}catch{}}async function Lo(e,o,n,t,r,i,s,a,c){let h=jt(n,t);if(!h)return console.warn(`${Oe()} ${i} ${we.yellow("\u26A0")} Critic config not available \u2014 skipping validation`),null;let w=s||"anthropic";console.log(`${Oe()} ${i} ${we.dim(`Running critic validation (${w})...`)}`),c&&Oo(c,`${No} Running critic validation (${w})...`);try{let m;if(w==="anthropic")m=await Vt(e,o,h,r,c);else{if(!a)throw new Error(`No API key for critic provider "${w}"`);m=await So(w,o,h,a,{maxTokens:4096,temperature:.3,timeoutMs:12e5})}let g=Bt(m),P=g.score>=te?we.green("\u2713"):we.red("\u2717");return console.log(`${Oe()} ${i} ${P} Critic score: ${g.score}/100 (threshold: ${te})`),g}catch(m){let g=m instanceof Error?m.message:String(m);return console.error(`${Oe()} ${i} ${we.yellow("\u26A0")} Critic failed: ${g.substring(0,100)}`),null}}import{generateText as zt,tool as co,stepCountIs as qt}from"ai";import{createOpenAI as Fo}from"@ai-sdk/openai";import{createAnthropic as Yt}from"@ai-sdk/anthropic";import{createGoogleGenerativeAI as Ht}from"@ai-sdk/google";import{z as ye}from"zod";import{execSync as uo}from"child_process";import{readFileSync as Jt,existsSync as Xt}from"fs";function Qt(e,o,n){switch(e){case"anthropic":return Yt({apiKey:n})(o);case"openai":return Fo({apiKey:n})(o);case"google":return Ht({apiKey:n})(o);case"ollama":return Fo({baseURL:n||"http://localhost:11434/v1",apiKey:"ollama"})(o);default:throw new Error(`Unsupported AI provider: ${e}`)}}var Zt=ye.object({pattern:ye.string().describe("Glob pattern like '**/*.ts', 'src/**/*.js', 'package.json'")}),en=ye.object({path:ye.string().describe("File path relative to the working directory"),limit:ye.number().optional().describe("Max number of lines to read (default: 500)")}),on=ye.object({pattern:ye.string().describe("Search pattern (regex supported)"),glob:ye.string().optional().describe("File glob to filter (e.g. '*.ts', '*.py')")});function tn(e){return{glob:co({description:"Find files matching a glob pattern. Returns file paths relative to the working directory.",inputSchema:Zt,execute:async o=>{try{let n=uo(`find . -path './.git' -prune -o -path './node_modules' -prune -o -name '${o.pattern.replace(/\*\*/g,"*")}' -print 2>/dev/null | head -200`,{cwd:e,encoding:"utf-8",timeout:15e3}).trim();return n||uo("find . -path './.git' -prune -o -path './node_modules' -prune -o -type f -print 2>/dev/null | head -500",{cwd:e,encoding:"utf-8",timeout:15e3}).trim()||"No files found"}catch{return"Error running glob search"}}}),read_file:co({description:"Read the contents of a file. Returns the file text.",inputSchema:en,execute:async o=>{try{let n=`${e}/${o.path}`.replace(/\/\//g,"/");if(!Xt(n))return`File not found: ${o.path}`;let t=Jt(n,"utf-8"),r=t.split(`
6
- `),i=o.limit||500;return r.length>i?r.slice(0,i).join(`
2
+ var Tt=Object.defineProperty;var St=(e,o)=>()=>(e&&(o=e(e=0)),o);var Ct=(e,o)=>{for(var t in o)Tt(e,t,{get:o[t],enumerable:!0})};var _o={};Ct(_o,{checkPrerequisites:()=>io,findClaudePath:()=>se,getConfigDir:()=>Ot,getConfigFile:()=>ee,getLogFile:()=>xe,getPidFile:()=>le,getSystemInfo:()=>Ge,loadConfig:()=>Co,loadConfigFromFile:()=>$e,saveConfigToFile:()=>so,validatePrerequisites:()=>Ro});import{existsSync as Fe,readFileSync as Rt,mkdirSync as _t,writeFileSync as Pt,chmodSync as vt}from"fs";import{execSync as he}from"child_process";import{hostname as So,homedir as _e}from"os";import{join as Z}from"path";function Ot(){return ve}function ee(){return Pe}function le(){return xt}function xe(){return Mt}function $e(){Fe(Pe)||(console.error("No config found. Run 'workermill-agent setup' first."),process.exit(1));let e;try{e=Rt(Pe,"utf-8")}catch{console.error("Failed to read config file:",Pe),process.exit(1)}let o;try{o=JSON.parse(e)}catch{console.error("Config file is corrupted. Re-run 'workermill-agent setup'."),process.exit(1)}(!o.apiUrl||!o.apiKey)&&(console.error("Config file is missing required fields (apiUrl, apiKey). Re-run 'workermill-agent setup'."),process.exit(1));let t=o.workerImage||"workermill-worker:local";return{apiUrl:o.apiUrl,apiKey:o.apiKey,agentId:o.agentId,maxWorkers:o.maxWorkers||4,pollIntervalMs:o.pollIntervalMs||5e3,heartbeatIntervalMs:o.heartbeatIntervalMs||3e4,githubToken:o.tokens?.github||"",bitbucketToken:o.tokens?.bitbucket||"",gitlabToken:o.tokens?.gitlab||"",workerImage:t}}function so(e){Fe(ve)||_t(ve,{recursive:!0}),Pt(Pe,JSON.stringify(e,null,2),"utf-8");try{vt(Pe,384)}catch{}}function Co(){let e=process.env.WORKERMILL_API_URL,o=process.env.WORKERMILL_API_KEY;return e||(console.error("WORKERMILL_API_URL is required in .env.remote"),process.exit(1)),o||(console.error("WORKERMILL_API_KEY is required in .env.remote"),console.error("Get your API key from Settings > Integrations on the WorkerMill dashboard."),process.exit(1)),{apiUrl:e.replace(/\/$/,""),apiKey:o,agentId:process.env.AGENT_ID||`agent-${So()}`,maxWorkers:parseInt(process.env.MAX_WORKERS||"4",10),pollIntervalMs:parseInt(process.env.POLL_INTERVAL_MS||"5000",10),heartbeatIntervalMs:parseInt(process.env.HEARTBEAT_INTERVAL_MS||"30000",10),githubToken:process.env.GITHUB_TOKEN||"",bitbucketToken:process.env.BITBUCKET_TOKEN||"",gitlabToken:process.env.GITLAB_TOKEN||"",workerImage:process.env.WORKER_IMAGE||"workermill-worker:local"}}function se(){let e=process.platform==="win32",o=e?"where":"which";try{return he(`${o} claude`,{stdio:"ignore",timeout:1e4}),"claude"}catch{}let t=[];e?t.push(Z(process.env.ProgramFiles||"C:\\Program Files","ClaudeCode","claude.exe"),Z(process.env.LOCALAPPDATA||"","Programs","ClaudeCode","claude.exe"),Z(_e(),"AppData","Local","Programs","ClaudeCode","claude.exe"),Z(_e(),".local","bin","claude.exe")):t.push(Z(_e(),".local","bin","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude");for(let n of t)if(n&&Fe(n))return n;return null}function io(e){let o=[],t=e||"workermill-worker:local";try{let c=he("docker version --format {{.Server.Version}}",{encoding:"utf-8",timeout:1e4}).trim();o.push({name:"Docker",ok:!0,detail:c})}catch{o.push({name:"Docker",ok:!1,detail:"Not running or not installed"})}let n=se();if(n)try{let c=he(`"${n}" --version`,{encoding:"utf-8",timeout:1e4}).trim();o.push({name:"Claude CLI",ok:!0,detail:c})}catch{o.push({name:"Claude CLI",ok:!0,detail:n})}else o.push({name:"Claude CLI",ok:!1,detail:"Not installed"});let r=_e(),s=Z(r,".claude",".credentials.json");Fe(s)?o.push({name:"Claude auth",ok:!0,detail:"Credentials found"}):o.push({name:"Claude auth",ok:!1,detail:"Run 'claude' and complete sign-in"});let i=process.version;parseInt(i.slice(1).split(".")[0],10)>=20?o.push({name:"Node.js",ok:!0,detail:i}):o.push({name:"Node.js",ok:!1,detail:`${i} (need >= 20)`});try{he(`docker image inspect ${t}`,{stdio:"ignore",timeout:1e4}),o.push({name:"Worker image",ok:!0,detail:t})}catch{o.push({name:"Worker image",ok:!1,detail:`'${t}' not found`})}return o}function Ro(){try{he("docker version",{stdio:"ignore"})}catch{console.error("Docker is not available. Please install Docker and ensure it's running."),process.exit(1)}let e=process.env.WORKER_IMAGE||"workermill-worker:local";try{he(`docker image inspect ${e}`,{stdio:"ignore"})}catch{console.error(`Worker image '${e}' not found.`),console.error(e==="workermill-worker:local"?"Build it with: ./bin/local-workermill build-worker":`Pull it with: docker pull ${e}`),process.exit(1)}se()||(console.error("Claude CLI is not installed."),console.error("Install it: curl -fsSL https://claude.ai/install.sh | bash"),process.exit(1));let o=_e(),t=Z(o,".claude",".credentials.json");Fe(t)||(console.error("Claude credentials not found."),console.error("Run 'claude' and complete the sign-in flow to authenticate."),process.exit(1))}function Ge(){let e="unknown";try{e=he("docker version --format {{.Server.Version}}",{encoding:"utf-8",timeout:1e4}).trim()}catch{}let o="unknown",t=se();if(t)try{o=he(`"${t}" --version`,{encoding:"utf-8",timeout:1e4}).trim()}catch{}return{hostname:So(),platform:process.platform,nodeVersion:process.version,dockerVersion:e,claudeVersion:o}}var ve,Pe,xt,Mt,oe=St(()=>{"use strict";ve=Z(_e(),".workermill"),Pe=Z(ve,"config.json"),xt=Z(ve,"agent.pid"),Mt=Z(ve,"agent.log")});import{existsSync as Hn}from"fs";import{Command as Jn}from"commander";oe();import d from"chalk";import Me from"ora";import ao from"inquirer";import{execSync as ce,spawnSync as Po}from"child_process";import{existsSync as Be}from"fs";import{hostname as Nt,homedir as xo,totalmem as Lt,cpus as Ft}from"os";import{join as je}from"path";import Dt from"axios";var Ee=process.platform==="win32";function co(e){try{return ce(`${Ee?"where":"which"} ${e}`,{stdio:"ignore",timeout:1e4}),!0}catch{return!1}}function lo(e){try{return ce(`"${e}" --version`,{encoding:"utf-8",timeout:1e4}).trim()}catch{return null}}function vo(){if(!Ee)return null;if(co("git"))try{let o=ce("where git",{encoding:"utf-8",timeout:1e4}).trim().split(`
3
+ `)[0],t=je(o,"..","..","bin","bash.exe");if(Be(t))return t}catch{}let e=[je(process.env.ProgramFiles||"C:\\Program Files","Git","bin","bash.exe"),"C:\\Program Files\\Git\\bin\\bash.exe","C:\\Program Files (x86)\\Git\\bin\\bash.exe",je(xo(),"scoop","apps","git","current","bin","bash.exe")];for(let o of e)if(Be(o))return o;return null}function Ut(){if(Ee)try{return ce("winget install Anthropic.ClaudeCode --accept-package-agreements --accept-source-agreements",{stdio:"inherit",timeout:18e4}),!0}catch{return!1}else{if(process.platform==="darwin")try{return ce("brew install --cask claude-code",{stdio:"inherit",timeout:18e4}),!0}catch{}try{return ce("curl -fsSL https://claude.ai/install.sh | bash",{stdio:"inherit",timeout:12e4}),!0}catch{return!1}}}async function uo(){console.log(),console.log(d.bold.cyan(" WorkerMill Remote Agent Setup")),console.log(d.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),console.log(" Run AI workers locally with your Claude Max subscription."),console.log(" Workers execute on your machine, logs stream to the cloud dashboard."),console.log();let e=Math.round(Lt()/(1024*1024*1024)),o=Ft().length;console.log(d.dim(" System")),console.log(` ${d.dim("RAM:")} ${e} GB ${d.dim("CPUs:")} ${o}`),e<8?(console.log(),console.log(d.red(" \u2717 Insufficient RAM")),console.log(d.yellow(" WorkerMill requires at least 8 GB of RAM (16 GB recommended).")),console.log(d.yellow(` Your system has ${e} GB.`)),console.log(),process.exit(1)):e<16?(console.log(d.yellow(` \u26A0 ${e} GB RAM is below the recommended 16 GB.`)),console.log(d.yellow(" Workers may run slowly or be killed by the OS under memory pressure."))):console.log(d.green(" \u2713 System meets requirements")),console.log();let t=Me("Checking Docker...").start();if(co("docker")){let l=lo("docker");try{let T=ce("docker info --format {{.OSType}}",{encoding:"utf-8",timeout:15e3}).trim();Ee&&T==="windows"&&(t.fail("Docker is running in Windows containers mode"),console.log(),console.log(d.yellow(" WorkerMill workers require Linux containers.")),console.log(d.yellow(" Right-click the Docker Desktop icon in the system tray \u2192")),console.log(d.yellow(" 'Switch to Linux containers...'")),console.log(),console.log(" Then re-run: workermill-agent"),process.exit(1))}catch{t.fail("Docker is installed but the daemon is not running"),console.log(),console.log(d.yellow(" Start Docker Desktop, wait for it to fully initialize,")),console.log(d.yellow(" then re-run: workermill-agent")),process.exit(1)}t.succeed(`Docker ${d.dim(l?`(${l})`:"")}`)}else t.fail("Docker is not installed"),console.log(),console.log(d.yellow(" Docker Desktop is required but must be installed manually:")),console.log(` ${d.cyan("https://docs.docker.com/get-docker/")}`),console.log(),console.log(" Install Docker, start it, then re-run: workermill-agent"),process.exit(1);if(Ee){let l=Me("Checking Git for Windows...").start(),T=vo();T?(l.succeed(`Git for Windows ${d.dim(`(${T})`)}`),process.env.CLAUDE_CODE_GIT_BASH_PATH=T):(l.fail("Git for Windows is not installed"),console.log(),console.log(d.yellow(" Claude Code on Windows requires Git for Windows (Git Bash):")),console.log(` ${d.cyan("https://git-scm.com/downloads/win")}`),console.log(),console.log(" Install Git for Windows, then re-run: workermill-agent"),process.exit(1))}let n=Me("Checking Claude CLI...").start(),r=se();if(r){let l=lo(r);n.succeed(`Claude CLI ${d.dim(l?`(${l})`:"")}`)}else if(n.warn("Claude CLI not found \u2014 installing..."),console.log(),Ut()&&(r=se()),r){let T=lo(r);console.log(),console.log(d.green(` \u2713 Claude CLI installed ${d.dim(T?`(${T})`:"")}`))}else console.log(),console.log(d.red(" Claude CLI was installed but could not be found.")),console.log(),Ee?(console.log(d.yellow(" Winget updated your PATH but this shell doesn't have it yet.")),console.log(d.yellow(" Close this terminal, open a new one, and re-run: workermill-agent"))):(console.log(" Try manually:"),console.log(d.cyan(" curl -fsSL https://claude.ai/install.sh | bash")),console.log(" Then re-run: workermill-agent")),process.exit(1);let s=Me("Checking Claude authentication...").start(),i=je(xo(),".claude",".credentials.json");if(Be(i))s.succeed("Claude authenticated");else{s.warn("Not authenticated \u2014 launching Claude..."),console.log(),console.log(d.dim(" Claude will open and prompt you to authenticate.")),console.log(d.dim(" Sign in with your Claude Max account, then exit Claude (Ctrl+C).")),console.log();let l={...process.env};if(Ee){let T=vo();T&&(l.CLAUDE_CODE_GIT_BASH_PATH=T)}Po(r,[],{stdio:"inherit",timeout:3e5,env:l}),Be(i)?(console.log(),console.log(d.green(" \u2713 Claude authenticated"))):(console.log(),console.log(d.red(" Authentication failed or was cancelled.")),console.log(" Try manually: open a new terminal and run 'claude'"),console.log(" Then re-run: workermill-agent"),process.exit(1))}console.log(d.green(" \u2713")+` Node.js ${d.dim(`(${process.version})`)}`),console.log(),console.log(d.bold("Configuration")),console.log();let{apiUrl:a}=await ao.prompt([{type:"input",name:"apiUrl",message:"WorkerMill API URL:",default:"https://workermill.com",validate:l=>l.startsWith("http://")||l.startsWith("https://")?!0:"Must be a valid URL"}]),{apiKey:c}=await ao.prompt([{type:"password",name:"apiKey",message:"API Key (from Settings > Integrations):",mask:"*",validate:l=>l.length>0?!0:"API key is required"}]),h=Me("Validating API key...").start(),w="github",m="",p="";try{let l=await Dt.get(`${a.replace(/\/$/,"")}/api/agent/config`,{headers:{"x-api-key":c},timeout:15e3});w=l.data.scmProvider||"github",m=l.data.workerImageUrl||"",p=l.data.ecrRegistry||"",h.succeed(`Connected! SCM provider: ${w}`)}catch(l){l.response?.status===401?h.fail("Invalid API key. Check Settings > Integrations on the dashboard."):h.fail("Failed to connect to WorkerMill API. Check the URL and try again."),process.exit(1)}console.log(d.dim(" SCM tokens are managed via Settings > Integrations on the dashboard.")),console.log();let{agentId:P}=await ao.prompt([{type:"input",name:"agentId",message:"Agent name:",default:`agent-${Nt()}`}]);console.log();let u=m||"workermill-worker:local",$=p.length>0,v=Me("Checking AWS CLI...").start();if(co("aws"))try{ce("aws sts get-caller-identity",{stdio:"pipe",timeout:15e3}),v.succeed("AWS CLI configured")}catch{v.warn("AWS CLI found but credentials not configured"),console.log(),console.log(d.yellow(" Configure AWS credentials for private ECR image access:")),console.log(d.cyan(" aws configure")),console.log(d.dim(" Contact your WorkerMill admin for AWS access key / secret key.")),console.log(d.dim(" Setup will continue \u2014 you can configure AWS later before starting."))}else v.warn("AWS CLI not found"),console.log(),console.log(d.yellow(" AWS CLI is required for pulling worker images from private ECR.")),console.log(d.cyan(" Install: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html")),console.log(d.dim(" Setup will continue \u2014 install AWS CLI before starting the agent."));let k=!1;if($){console.log(),console.log(d.dim(" Authenticating with private ECR..."));let l=p.match(/\.ecr\.([a-z0-9-]+)\.amazonaws\.com/),T=l?l[1]:"us-east-1";try{ce(`aws ecr get-login-password --region ${T} | docker login --username AWS --password-stdin ${p}`,{stdio:"pipe",timeout:3e4}),console.log(d.green(" \u2713 ECR authenticated")),k=!0}catch{console.log(d.yellow(" \u26A0 ECR authentication failed (AWS credentials may not be configured yet)")),console.log(d.dim(" Worker image pull will be skipped \u2014 authenticate later with:")),console.log(d.dim(` aws ecr get-login-password --region ${T} | docker login --username AWS --password-stdin ${p}`))}}if(k||!$){console.log(),console.log(d.dim(` Pulling worker image: ${u}`)),console.log(d.dim(" This may take a few minutes on first run (~1.1 GB)...")),console.log();let l=Po("docker",["pull",u],{stdio:"inherit",timeout:6e5});l.status===0?(console.log(),console.log(d.green(" \u2713 Worker image pulled"))):(console.log(),console.log(d.red(" \u2717 Failed to pull worker image.")),l.error&&console.log(d.yellow(` Error: ${l.error.message}`)),console.log(d.dim(" Setup will continue \u2014 you can pull the image later before starting.")))}let B={apiUrl:a.replace(/\/$/,""),apiKey:c,agentId:P,maxWorkers:1,pollIntervalMs:5e3,heartbeatIntervalMs:3e4,tokens:{github:"",bitbucket:"",gitlab:""},workerImage:u,setupCompletedAt:new Date().toISOString()};so(B),console.log(),console.log(d.green.bold(" Setup complete!")),console.log(),console.log(` Config saved to: ${d.dim(ee())}`),console.log(),console.log(` Start the agent with: ${d.cyan("workermill-agent start")}`),console.log()}import U from"chalk";import{totalmem as Rn}from"os";import{spawn as _n}from"child_process";import{writeFileSync as mt,existsSync as Pn,unlinkSync as vn,openSync as xn,createWriteStream as Mn}from"fs";import{createRequire as Wt}from"module";var Kt=Wt(import.meta.url),Gt=Kt("../package.json"),z=Gt.version;oe();import K from"chalk";import jt from"axios";var go=null;function Ve(e,o){go=jt.create({baseURL:e,headers:{"Content-Type":"application/json","x-api-key":o},timeout:3e4})}var O=new Proxy({},{get(e,o){if(!go)throw new Error("API client not initialized. Call initApi() first.");return go[o]}});import S from"chalk";oe();import g from"chalk";import{spawn as gn,execSync as bo}from"child_process";import{spawn as Jt}from"child_process";import ye from"chalk";import ze from"axios";var Bt=16384,Vt=6e5;async function Mo(e,o,t,n,r){let s=r?.maxTokens??Bt,i=r?.temperature??.7,a=r?.timeoutMs??Vt;switch(e){case"anthropic":return zt(o,t,n,s,i,a);case"openai":return qt(o,t,n,s,i,a);case"google":return Yt(o,t,n,s,i,a);case"ollama":return Ht(o,t,n,s,i,a);default:throw new Error(`Unsupported AI provider: ${e}`)}}async function zt(e,o,t,n,r,s){let a=(await ze.post("https://api.anthropic.com/v1/messages",{model:e,max_tokens:n,temperature:r,messages:[{role:"user",content:o}]},{headers:{"x-api-key":t,"anthropic-version":"2023-06-01","Content-Type":"application/json"},timeout:s})).data?.content;if(Array.isArray(a))return a.filter(c=>c.type==="text").map(c=>c.text).join("");throw new Error("Unexpected Anthropic API response format")}async function qt(e,o,t,n,r,s){let a=(await ze.post("https://api.openai.com/v1/chat/completions",{model:e,max_tokens:n,temperature:r,messages:[{role:"user",content:o}]},{headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},timeout:s})).data?.choices?.[0]?.message;if(a?.content)return a.content;throw new Error("Unexpected OpenAI API response format")}async function Yt(e,o,t,n,r,s){let c=(await ze.post(`https://generativelanguage.googleapis.com/v1beta/models/${e}:generateContent?key=${t}`,{contents:[{parts:[{text:o}]}],generationConfig:{maxOutputTokens:n,temperature:r}},{headers:{"Content-Type":"application/json"},timeout:s})).data?.candidates?.[0]?.content?.parts?.[0]?.text;if(c)return c;throw new Error("Unexpected Google AI API response format")}async function Ht(e,o,t,n,r,s){let i=t||"http://localhost:11434",c=(await ze.post(`${i}/api/generate`,{model:e,prompt:o,stream:!1,options:{temperature:r}},{headers:{"Content-Type":"application/json"},timeout:s})).data?.response;if(c)return c;throw new Error("Unexpected Ollama API response format")}var we=null;async function No(e){if(we)return we;try{let o={};e!==void 0&&(o.maxTargetFiles=String(e));let{data:t}=await O.get("/api/agent/critic-prompt",{params:o});return we={promptTemplate:t.promptTemplate,approvalThreshold:t.approvalThreshold??85,maxTargetFiles:t.maxTargetFiles??e??5},te=we.approvalThreshold,Te=we.maxTargetFiles,we}catch{return console.warn("Failed to fetch critic config from API"),null}}var Te=5,te=85;function po(e){let o=e.indexOf("```json");if(o!==-1){let n=o+7,r=e.indexOf("{",n);if(r!==-1){let s=Oo(e,r);if(s)return JSON.parse(s)}}let t=e.indexOf('"stories"');if(t!==-1){let r=e.substring(0,t).lastIndexOf("{");if(r!==-1){let s=Oo(e,r);if(s)return JSON.parse(s)}}throw new Error("Could not find JSON execution plan in output")}function Oo(e,o){let t=0,n=!1,r=!1;for(let s=o;s<e.length;s++){let i=e[s];if(r){r=!1;continue}if(i==="\\"){n&&(r=!0);continue}if(i==='"'){n=!n;continue}if(!n){if(i==="{")t++;else if(i==="}"&&(t--,t===0))return e.substring(o,s+1)}}return null}function mo(e){let o=0,t=[];for(let n of e.stories)if(!n.targetFiles||!Array.isArray(n.targetFiles))n.targetFiles=[];else if(n.targetFiles.length>Te){let r=n.targetFiles.slice(Te);t.push(`${n.id}: ${n.targetFiles.length} files \u2192 ${Te} (dropped: ${r.join(", ")})`),n.targetFiles=n.targetFiles.slice(0,Te),o++}return{truncatedCount:o,details:t}}function fo(e,o){if(e.stories.length<=o)return{droppedCount:0,details:[]};let t=e.stories.length-o,r=e.stories.slice(o).map(i=>`${i.id}: "${i.title}" (${i.persona})`);e.stories=e.stories.slice(0,o);let s=new Set(e.stories.map(i=>i.id));for(let i of e.stories)i.dependencies=i.dependencies.filter(a=>s.has(a));return{droppedCount:t,details:r}}function ho(e){let o=new Map,t=0,n=[];for(let r of e.stories){if(!r.targetFiles||r.targetFiles.length===0)continue;let s=[],i=[];for(let a of r.targetFiles)o.get(a)?i.push(a):(o.set(a,r.id),s.push(a));i.length>0&&(r.targetFiles=s,t+=i.length,n.push(`${r.id}: removed ${i.join(", ")} (owned by ${i.map(a=>o.get(a)).join(", ")})`))}return{resolvedCount:t,details:n}}function Lo(e){return"```json\n"+JSON.stringify(e,null,2)+"\n```"}function Xt(e,o){if(!we)return null;let t=JSON.stringify(o,null,2);return we.promptTemplate.replace("{{PRD}}",e).replace("{{PLAN}}",t)}function Qt(e){let o=e.trim();if(o.includes("```")){let r=o.match(/```(?:json)?\s*([\s\S]*?)```/);r&&(o=r[1].trim())}let t=o.indexOf("{");t>0&&(o=o.substring(t));let n=JSON.parse(o);return{approved:n.approved,score:Math.max(0,Math.min(100,Math.round(n.score))),risks:n.risks||[],suggestions:n.suggestions,storyFeedback:Array.isArray(n.storyFeedback)?n.storyFeedback:void 0}}function Zt(e,o,t,n,r){return new Promise((s,i)=>{let a=Jt(e,["--print","--model",o,"--permission-mode","bypassPermissions"],{env:n,stdio:["pipe","pipe","pipe"]});a.stdin.write(t),a.stdin.end();let c="",h="";a.stdout.on("data",m=>{let p=m.toString();c+=p;let P=p.split(`
4
+ `).filter(u=>u.trim());for(let u of P){let $=u.trim().length>200?u.trim().substring(0,200)+"\u2026":u.trim();$&&(r&&Wo(r,`${Uo} [critic] ${$}`,"output"),console.log(`${De()} ${ye.dim("\u{1F50D}")} ${ye.dim($)}`))}}),a.stderr.on("data",m=>{h+=m.toString()});let w=setTimeout(()=>{a.kill("SIGTERM"),i(new Error("Critic CLI timed out after 20 minutes"))},12e5);a.on("exit",m=>{clearTimeout(w),m!==0?i(new Error(`Critic CLI failed (exit ${m}): ${h.substring(0,300)}`)):s(c)}),a.on("error",m=>{clearTimeout(w),i(m)})})}function Fo(e){let o=["","## CRITIC FEEDBACK \u2014 Your previous plan was REJECTED","",`Score: ${e.score}/100 (need >= ${te} to pass)`,""];if(e.risks.length>0){o.push("### Risks Identified:");for(let t of e.risks)o.push(`- ${t}`);o.push("")}if(e.suggestions&&e.suggestions.length>0){o.push("### Required Changes:");for(let t of e.suggestions)o.push(`- ${t}`);o.push("")}if(e.storyFeedback&&e.storyFeedback.length>0){o.push("### Per-Story Feedback:");for(let t of e.storyFeedback)if(o.push(`- **${t.storyId}**: ${t.feedback}`),t.suggestedChanges)for(let n of t.suggestedChanges)o.push(` - ${n}`);o.push("")}return o.push(`**You MUST address ALL feedback above.** Each story must target at most ${Te} files.`,"Stories MUST NOT overlap on targetFiles.","","**CRITICAL \u2014 OUTPUT FORMAT:** You MUST output a revised plan as a ```json code block containing the full JSON object with `summary`, `stories`, `risks`, and `assumptions` fields. Do NOT just describe what you would change \u2014 output the COMPLETE revised JSON plan. If you do not output a ```json block, the plan will fail to parse and the task will fail.","","**DO NOT re-explore the repository.** You already explored it in the previous attempt. Go directly to outputting the revised ```json plan. Every tool call wastes output budget \u2014 prioritize emitting the JSON plan."),o.join(`
5
+ `)}function Do(e){let o=["","## REVIEWER NOTES \u2014 Your plan was APPROVED, but the reviewer has suggestions","",`Score: ${e.score}/100 (approved)`,"","The reviewer approved your plan but identified opportunities for improvement.","Review each suggestion and incorporate the ones that genuinely improve the plan.","You may reject suggestions that would reduce quality or don't apply.",""];if(e.risks.length>0){o.push("### Risks Identified:");for(let t of e.risks)o.push(`- ${t}`);o.push("")}if(e.suggestions&&e.suggestions.length>0){o.push("### Suggested Improvements:");for(let t of e.suggestions)o.push(`- ${t}`);o.push("")}if(e.storyFeedback&&e.storyFeedback.length>0){o.push("### Per-Story Notes:");for(let t of e.storyFeedback)if(o.push(`- **${t.storyId}**: ${t.feedback}`),t.suggestedChanges)for(let n of t.suggestedChanges)o.push(` - ${n}`);o.push("")}return o.push(`Each story must target at most ${Te} files. Stories MUST NOT overlap on targetFiles.`,"","**CRITICAL \u2014 OUTPUT FORMAT:** Output the refined plan as a ```json code block with the COMPLETE JSON object (`summary`, `stories`, `risks`, `assumptions`). Do NOT describe changes \u2014 output the full JSON.","","**DO NOT re-explore the repository.** Go directly to outputting the refined ```json plan."),o.join(`
6
+ `)}var Uo="[\u{1F5FA}\uFE0F planning_agent \u{1F916}]";function De(){return ye.dim(new Date().toLocaleTimeString())}async function Wo(e,o,t="system",n="info"){try{await O.post("/api/control-center/logs",{taskId:e,type:t,message:o,severity:n})}catch{}}async function Ko(e,o,t,n,r,s,i,a,c){let h=Xt(t,n);if(!h)return console.warn(`${De()} ${s} ${ye.yellow("\u26A0")} Critic config not available \u2014 skipping validation`),null;let w=i||"anthropic";console.log(`${De()} ${s} ${ye.dim(`Running critic validation (${w})...`)}`),c&&Wo(c,`${Uo} Running critic validation (${w})...`);try{let m;if(w==="anthropic")m=await Zt(e,o,h,r,c);else{if(!a)throw new Error(`No API key for critic provider "${w}"`);m=await Mo(w,o,h,a,{maxTokens:4096,temperature:.3,timeoutMs:12e5})}let p=Qt(m),P=p.score>=te?ye.green("\u2713"):ye.red("\u2717");return console.log(`${De()} ${s} ${P} Critic score: ${p.score}/100 (threshold: ${te})`),p}catch(m){let p=m instanceof Error?m.message:String(m);return console.error(`${De()} ${s} ${ye.yellow("\u26A0")} Critic failed: ${p.substring(0,100)}`),null}}import{generateText as en,tool as $o,stepCountIs as on}from"ai";import{createOpenAI as Go}from"@ai-sdk/openai";import{createAnthropic as tn}from"@ai-sdk/anthropic";import{createGoogleGenerativeAI as nn}from"@ai-sdk/google";import{z as Ie}from"zod";import{execSync as wo}from"child_process";import{readFileSync as rn,existsSync as sn}from"fs";function an(e,o,t){switch(e){case"anthropic":return tn({apiKey:t})(o);case"openai":return Go({apiKey:t})(o);case"google":return nn({apiKey:t})(o);case"ollama":return Go({baseURL:t||"http://localhost:11434/v1",apiKey:"ollama"})(o);default:throw new Error(`Unsupported AI provider: ${e}`)}}var ln=Ie.object({pattern:Ie.string().describe("Glob pattern like '**/*.ts', 'src/**/*.js', 'package.json'")}),cn=Ie.object({path:Ie.string().describe("File path relative to the working directory"),limit:Ie.number().optional().describe("Max number of lines to read (default: 500)")}),un=Ie.object({pattern:Ie.string().describe("Search pattern (regex supported)"),glob:Ie.string().optional().describe("File glob to filter (e.g. '*.ts', '*.py')")});function dn(e){return{glob:$o({description:"Find files matching a glob pattern. Returns file paths relative to the working directory.",inputSchema:ln,execute:async o=>{try{let t=wo(`find . -path './.git' -prune -o -path './node_modules' -prune -o -name '${o.pattern.replace(/\*\*/g,"*")}' -print 2>/dev/null | head -200`,{cwd:e,encoding:"utf-8",timeout:15e3}).trim();return t||wo("find . -path './.git' -prune -o -path './node_modules' -prune -o -type f -print 2>/dev/null | head -500",{cwd:e,encoding:"utf-8",timeout:15e3}).trim()||"No files found"}catch{return"Error running glob search"}}}),read_file:$o({description:"Read the contents of a file. Returns the file text.",inputSchema:cn,execute:async o=>{try{let t=`${e}/${o.path}`.replace(/\/\//g,"/");if(!sn(t))return`File not found: ${o.path}`;let n=rn(t,"utf-8"),r=n.split(`
7
+ `),s=o.limit||500;return r.length>s?r.slice(0,s).join(`
7
8
  `)+`
8
- ... (truncated, ${r.length-i} more lines)`:t}catch(n){return`Error reading file: ${n instanceof Error?n.message:String(n)}`}}}),grep:co({description:"Search for a pattern in files. Returns matching lines with file paths and line numbers.",inputSchema:on,execute:async o=>{try{let n=o.glob?`--include='${o.glob}'`:"";return uo(`grep -rn ${n} --exclude-dir=node_modules --exclude-dir=.git '${o.pattern.replace(/'/g,"'\\''")}' . 2>/dev/null | head -100`,{cwd:e,encoding:"utf-8",timeout:15e3}).trim()||"No matches found"}catch{return"No matches found"}}})}}async function Do(e){let{provider:o,model:n,apiKey:t,prompt:r,systemPrompt:i,workingDir:s,maxTokens:a=16384,temperature:c=.7,timeoutMs:h=6e5,maxSteps:w=15,enableTools:m=!0}=e,g=Qt(o,n,t),P=m&&s?tn(s):void 0,d=new AbortController,$=setTimeout(()=>d.abort(),h);try{return(await zt({model:g,prompt:r,system:i,maxOutputTokens:a,temperature:c,tools:P,stopWhen:P?qt(w):void 0,abortSignal:d.signal})).text}finally{clearTimeout($)}}function rn(e,o){let n=[e.usage,e.message?.usage,e.result?.usage];for(let t of n)if(t&&typeof t=="object"){let r=t;typeof r.input_tokens=="number"&&(o.inputTokens=Math.max(o.inputTokens,r.input_tokens)),typeof r.output_tokens=="number"&&(o.outputTokens=Math.max(o.outputTokens,r.output_tokens)),typeof r.cache_creation_input_tokens=="number"&&(o.cacheCreationTokens=Math.max(o.cacheCreationTokens,r.cache_creation_input_tokens)),typeof r.cache_read_input_tokens=="number"&&(o.cacheReadTokens=Math.max(o.cacheReadTokens,r.cache_read_input_tokens))}}async function Uo(e,o,n,t){if(!(o.inputTokens===0&&o.outputTokens===0))try{await N.post(`/api/tasks/${e}/usage/partial`,{inputTokens:o.inputTokens,outputTokens:o.outputTokens,cacheCreationTokens:o.cacheCreationTokens,cacheReadTokens:o.cacheReadTokens,model:n,mode:t})}catch{}}var ue=3;function I(){return p.dim(new Date().toLocaleTimeString())}var xe=[],Ie=null;async function Ko(){for(;xe.length>0;){let e=xe.splice(0,50);try{await N.post("/api/control-center/logs/batch",{entries:e},{timeout:5e3})}catch{}}}async function R(e,o,n="system",t="info"){xe.length>=200&&xe.shift(),xe.push({taskId:e,message:o,type:n,severity:t}),Ie||(Ie=Ko().finally(()=>{Ie=null}))}async function sn(){Ie&&await Ie,xe.length>0&&(Ie=Ko().finally(()=>{Ie=null}),await Ie)}async function ve(e,o,n,t,r,i){try{await N.post("/api/agent/planning-progress",{taskId:e,phase:o,elapsedSeconds:n,detail:t,charsGenerated:r,toolCallCount:i})}catch{}}var E="[\u{1F5FA}\uFE0F planning_agent \u{1F916}]";function Be(e){let o=Math.floor(e/60),n=e%60;return o>0?`${o}m ${n}s`:`${n}s`}function Wo(e,o){switch(e){case"initializing":return`${E} Starting planning agent...`;case"reading_repo":return`${E} Reading repository structure...`;case"analyzing":return`${E} Analyzing requirements...`;case"generating_plan":return`${E} Planning in progress \u2014 analyzing requirements and decomposing into steps (${Be(o)} elapsed)`;case"validating":return`${E} Validating plan...`;case"complete":return`${E} Planning complete`}}function an(e,o,n,t,r,i,s){let a=p.cyan(r.slice(0,8));return new Promise((c,h)=>{let m=nn(e,["--print","--verbose","--output-format","stream-json","--model",o,"--permission-mode","bypassPermissions"],{cwd:s,env:t,stdio:["pipe","pipe","pipe"]});m.stdin.write(n),m.stdin.end();let g="",P="",d="",$=0,v=0,A={inputTokens:0,outputTokens:0,cacheCreationTokens:0,cacheReadTokens:0},B=o,l="";function b(k=!1){if(!l)return;let G=l.split(`
9
- `),pe=k?"":G.pop()||"";for(let Y of G)if(Y.trim()){R(r,`${E} ${Y}`,"output");let F=Y.trim().length>160?Y.trim().substring(0,160)+"\u2026":Y.trim();console.log(`${I()} ${a} ${p.dim("\u{1F4AD}")} ${p.dim(F)}`)}l=pe}let T="initializing",O=!1,y={started:!0,reading:!1,analyzing:!1,generating:!1};function L(k){if(k===T)return;T=k;let G=Math.round((Date.now()-i)/1e3),pe=Wo(k,G);R(r,pe),console.log(`${I()} ${a} ${p.dim(pe)}`)}let V=setInterval(()=>b(),500),q=setInterval(()=>{let k=Math.round((Date.now()-i)/1e3);ve(r,T,k,Wo(T,k),$,v)},2e3),x=0,ae=setInterval(()=>{let k=Math.round((Date.now()-i)/1e3);if(T==="initializing"&&k>=5?L("reading_repo"):T==="reading_repo"&&k>=15&&!O&&L("analyzing"),T==="generating_plan"&&k-x>=30){x=k;let G=`${E} Planning in progress \u2014 analyzing requirements and decomposing into steps (${Be(k)} elapsed)`;R(r,G),console.log(`${I()} ${a} ${p.dim(G)}`)}},5e3),X="";m.stdout.on("data",k=>{X+=k.toString();let G=X.split(`
10
- `);X=G.pop()||"";for(let pe of G){let Y=pe.trim();if(Y)try{let F=JSON.parse(Y);if(F.type==="assistant"&&F.message?.content){let H=F.message.content;if(Array.isArray(H))for(let me of H)me.type==="text"&&me.text?(g+=me.text,$+=me.text.length,l+=me.text,O||(O=!0,v>0&&!y.analyzing&&(L("analyzing"),y.analyzing=!0)),$>500&&!y.generating&&(L("generating_plan"),y.generating=!0,x=Math.round((Date.now()-i)/1e3))):me.type==="tool_use"&&(v++,y.reading||(L("reading_repo"),y.reading=!0));else typeof H=="string"&&H&&(g+=H,$+=H.length,l+=H)}else F.type==="content_block_delta"&&F.delta?.text?(g+=F.delta.text,$+=F.delta.text.length,l+=F.delta.text,O||(O=!0,v>0&&!y.analyzing&&(L("analyzing"),y.analyzing=!0)),$>500&&!y.generating&&(L("generating_plan"),y.generating=!0,x=Math.round((Date.now()-i)/1e3))):F.type==="content_block_start"&&F.content_block?.type==="tool_use"?(v++,y.reading||(L("reading_repo"),y.reading=!0)):F.type==="result"&&F.result&&(P=typeof F.result=="string"?F.result:"");if(rn(F,A),F.type==="result"&&F.total_cost_usd!==void 0&&F.modelUsage&&typeof F.modelUsage=="object"){let H=Object.keys(F.modelUsage);H.length>0&&(B=H[0])}}catch{g+=Y+`
11
- `,$+=Y.length}}}),m.stderr.on("data",k=>{d+=k.toString()});let re=setInterval(()=>{(A.inputTokens>0||A.outputTokens>0)&&Uo(r,A,B,"greatest").catch(()=>{})},3e4);function le(){clearInterval(ae),clearInterval(q),clearInterval(V),clearInterval(re),b(!0)}let De=setTimeout(()=>{le(),m.kill("SIGTERM"),h(new Error("Claude CLI timed out after 20 minutes"))},12e5);m.on("exit",k=>{clearTimeout(De),le();let G=Math.round((Date.now()-i)/1e3);ve(r,"validating",G,"Validating plan...",$,v),Uo(r,A,B,"greatest").catch(()=>{}),k!==0?h(new Error(`Claude CLI failed (exit ${k}): ${d.substring(0,300)}`)):c(P||g)}),m.on("error",k=>{clearTimeout(De),le(),h(k)})})}function ln(e,o){if(o)switch(e){case"anthropic":return o.anthropicApiKey;case"openai":return o.openaiApiKey;case"google":return o.googleApiKey;case"ollama":return o.ollamaBaseUrl||"http://localhost:11434";default:return}}function cn(e,o,n){switch(n){case"bitbucket":return`https://x-token-auth:${o}@bitbucket.org/${e}.git`;case"gitlab":return`https://oauth2:${o}@gitlab.com/${e}.git`;default:return`https://x-access-token:${o}@github.com/${e}.git`}}async function dn(e,o,n,t){let r=p.cyan(t.slice(0,8)),i=`/tmp/workermill-planning-${t.slice(0,8)}-${Date.now()}`;try{let s=cn(e,o,n);return console.log(`${I()} ${r} ${p.dim("Cloning repo for planner...")}`),po(`git clone --depth 1 --single-branch "${s}" "${i}"`,{stdio:"ignore",timeout:6e4}),console.log(`${I()} ${r} ${p.green("\u2713")} Repo cloned to ${p.dim(i)}`),i}catch(s){let a=s instanceof Error?s.message:String(s);console.error(`${I()} ${r} ${p.yellow("\u26A0")} Clone failed, planner will run without repo access: ${a.substring(0,100)}`);try{po(`rm -rf "${i}"`,{stdio:"ignore"})}catch{}return null}}async function Go(e,o,n){let t=p.cyan(e.id.slice(0,8));console.log(`${I()} ${t} Fetching planning prompt...`),await R(e.id,`${E} Fetching planning prompt from cloud API...`);let r=await N.get("/api/agent/planning-prompt",{params:{taskId:e.id}}),{prompt:i,model:s,provider:a,maxStories:c,maxTargetFiles:h}=r.data,w=typeof c=="number"?c:8,m=s,g=a||"anthropic",P=g==="anthropic",d=process.env.CLAUDE_CLI_PATH||ie()||"claude",$={...process.env};delete $.CLAUDE_CODE_OAUTH_TOKEN;let v=ln(g,n),A=Date.now(),B=e.description||e.summary,l=null;if(e.githubRepo){let q=e.scmProvider||"github",x=q==="bitbucket"?o.bitbucketToken:q==="gitlab"?o.gitlabToken:o.githubToken;x?l=await dn(e.githubRepo,x,q,e.id):console.log(`${I()} ${t} ${p.yellow("\u26A0")} No SCM token for ${q}, planner will run without repo access`)}let b=i,T=null,O=0,y=[],L=0,V=await Co(typeof h=="number"?h:void 0);V||(console.log(`${I()} ${t} ${p.yellow("\u26A0")} Could not fetch critic config \u2014 critic validation will be skipped`),await R(e.id,`${E} \u26A0\uFE0F Could not fetch critic config from API \u2014 critic validation will be skipped`));try{for(let x=1;x<=ue;x++){let ae=ue>1?` (attempt ${x}/${ue})`:"",X=`${g}/${m}`;x>1?(console.log(`${I()} ${t} Running planner${ae} ${p.dim(`(${p.yellow(X)})`)}`),await R(e.id,`${E} Re-planning${ae} using ${X}`)):(console.log(`${I()} ${t} Running planner ${p.dim(`(${p.yellow(X)})`)}`),await R(e.id,`${E} Starting planning agent using ${X}`));let re;try{if(P)re=await an(d,m,b,$,e.id,A,l||void 0);else{if(!v)throw new Error(`No API key available for provider "${g}". Configure it in Settings > Integrations.`);let _=Math.round((Date.now()-A)/1e3);await ve(e.id,"generating_plan",_,"Generating plan via AI SDK...",0,0),re=await Do({provider:g,model:m,apiKey:v,prompt:b,workingDir:l||void 0,enableTools:!!l,maxSteps:10});let M=Math.round((Date.now()-A)/1e3);await ve(e.id,"validating",M,"Validating plan...",re.length,0)}}catch(_){let M=Math.round((Date.now()-A)/1e3),Q=_ instanceof Error?_.message:String(_);return console.error(`${I()} ${t} ${p.red("\u2717")} Failed after ${M}s: ${Q.substring(0,100)}`),await R(e.id,`${E} Planning failed after ${Be(M)}: ${Q.substring(0,200)}`,"error","error"),!1}let le=Math.round((Date.now()-A)/1e3),De=P?"Claude CLI":`${g} API`;console.log(`${I()} ${t} ${p.green("\u2713")} ${De} done ${p.dim(`(${le}s, ${re.length} chars)`)}`);let k;try{k=_o(re)}catch(_){let M=_ instanceof Error?_.message:String(_);return console.error(`${I()} ${t} ${p.red("\u2717")} Plan parse failed: ${M.substring(0,100)}`),await R(e.id,`${E} Failed to parse execution plan from Claude output: ${M.substring(0,200)}`,"error","error"),await un(e.id,re,o.agentId,t,le)}let{truncatedCount:G,details:pe}=Ro(k);if(G>0){L+=G;let _=`${E} File cap applied: ${G} stories truncated to max ${V?.maxTargetFiles??5} targetFiles`;console.log(`${I()} ${t} ${p.yellow("\u26A0")} ${_}`),await R(e.id,_);for(let M of pe)console.log(`${I()} ${t} ${p.dim(M)}`)}let{droppedCount:Y,details:F}=Po(k,w);if(Y>0){let _=`${E} Story cap applied: ${Y} stories dropped (max ${w})`;console.log(`${I()} ${t} ${p.yellow("\u26A0")} ${_}`),await R(e.id,_);for(let M of F)console.log(`${I()} ${t} ${p.dim(M)}`)}let{resolvedCount:H,details:me}=xo(k);if(H>0){let _=`${E} File overlap resolved: ${H} shared file(s) de-duped across stories`;console.log(`${I()} ${t} ${p.yellow("\u26A0")} ${_}`),await R(e.id,_);for(let M of me)console.log(`${I()} ${t} ${p.dim(M)}`)}console.log(`${I()} ${t} Plan: ${p.bold(k.stories.length)} stories (max ${w})`),await R(e.id,`${E} Plan generated: ${k.stories.length} stories (${Be(le)}). Running critic validation...`);let C=await Lo(d,m,B,k,$,t,g,v,e.id);if(C&&C.score>O?(T=k,O=C.score):!C&&!T&&(T=k),C&&y.push({iteration:x,score:C.score,approved:C.approved||C.score>=te,risks:C.risks,suggestions:C.suggestions,filesCapApplied:G>0?G:void 0}),!C){let _=`${E} \u26A0\uFE0F CRITIC BYPASSED \u2014 Critic validation failed (timeout/parse error). Posting plan WITHOUT quality gate.`;console.log(`${I()} ${t} ${p.yellow("\u26A0")} ${_}`),await R(e.id,_,"error","warning");let M=Date.now()-A;return await go(e.id,k,o.agentId,t,le,void 0,void 0,y,L,M,x)}if(C.approved||C.score>=te){let _=`${E} Critic approved (score: ${C.score}/100)`;if(console.log(`${I()} ${t} ${p.green("\u2713")} ${_}`),await R(e.id,_),C.risks.length>0){let Q=`${E} Critic risks (non-blocking): ${C.risks.join("; ")}`;console.log(`${I()} ${t} ${p.dim(Q)}`),await R(e.id,Q)}let M=Date.now()-A;return await go(e.id,k,o.agentId,t,le,C.score,C.risks,y,L,M,x)}if(x<ue){let _=Mo(C);b=b+`
9
+ ... (truncated, ${r.length-s} more lines)`:n}catch(t){return`Error reading file: ${t instanceof Error?t.message:String(t)}`}}}),grep:$o({description:"Search for a pattern in files. Returns matching lines with file paths and line numbers.",inputSchema:un,execute:async o=>{try{let t=o.glob?`--include='${o.glob}'`:"";return wo(`grep -rn ${t} --exclude-dir=node_modules --exclude-dir=.git '${o.pattern.replace(/'/g,"'\\''")}' . 2>/dev/null | head -100`,{cwd:e,encoding:"utf-8",timeout:15e3}).trim()||"No matches found"}catch{return"No matches found"}}})}}async function yo(e){let{provider:o,model:t,apiKey:n,prompt:r,systemPrompt:s,workingDir:i,maxTokens:a=16384,temperature:c=.7,timeoutMs:h=6e5,maxSteps:w=15,enableTools:m=!0}=e,p=an(o,t,n),P=m&&i?dn(i):void 0,u=new AbortController,$=setTimeout(()=>u.abort(),h);try{return(await en({model:p,prompt:r,system:s,maxOutputTokens:a,temperature:c,tools:P,stopWhen:P?on(w):void 0,abortSignal:u.signal})).text}finally{clearTimeout($)}}function pn(e,o){let t=[e.usage,e.message?.usage,e.result?.usage];for(let n of t)if(n&&typeof n=="object"){let r=n;typeof r.input_tokens=="number"&&(o.inputTokens=Math.max(o.inputTokens,r.input_tokens)),typeof r.output_tokens=="number"&&(o.outputTokens=Math.max(o.outputTokens,r.output_tokens)),typeof r.cache_creation_input_tokens=="number"&&(o.cacheCreationTokens=Math.max(o.cacheCreationTokens,r.cache_creation_input_tokens)),typeof r.cache_read_input_tokens=="number"&&(o.cacheReadTokens=Math.max(o.cacheReadTokens,r.cache_read_input_tokens))}}async function jo(e,o,t,n){if(!(o.inputTokens===0&&o.outputTokens===0))try{await O.post(`/api/tasks/${e}/usage/partial`,{inputTokens:o.inputTokens,outputTokens:o.outputTokens,cacheCreationTokens:o.cacheCreationTokens,cacheReadTokens:o.cacheReadTokens,model:t,mode:n})}catch{}}var ue=3;function y(){return g.dim(new Date().toLocaleTimeString())}var Oe=[],be=null;async function zo(){for(;Oe.length>0;){let e=Oe.splice(0,50);try{await O.post("/api/control-center/logs/batch",{entries:e},{timeout:5e3})}catch{}}}async function C(e,o,t="system",n="info"){Oe.length>=200&&Oe.shift(),Oe.push({taskId:e,message:o,type:t,severity:n}),be||(be=zo().finally(()=>{be=null}))}async function mn(){be&&await be,Oe.length>0&&(be=zo().finally(()=>{be=null}),await be)}async function Ne(e,o,t,n,r,s){try{await O.post("/api/agent/planning-progress",{taskId:e,phase:o,elapsedSeconds:t,detail:n,charsGenerated:r,toolCallCount:s})}catch{}}var A="[\u{1F5FA}\uFE0F planning_agent \u{1F916}]";function qe(e){let o=Math.floor(e/60),t=e%60;return o>0?`${o}m ${t}s`:`${t}s`}function Bo(e,o){switch(e){case"initializing":return`${A} Starting planning agent...`;case"reading_repo":return`${A} Reading repository structure...`;case"analyzing":return`${A} Analyzing requirements...`;case"generating_plan":return`${A} Planning in progress \u2014 analyzing requirements and decomposing into steps (${qe(o)} elapsed)`;case"validating":return`${A} Validating plan...`;case"complete":return`${A} Planning complete`}}function Vo(e,o,t,n,r,s,i){let a=g.cyan(r.slice(0,8));return new Promise((c,h)=>{let m=gn(e,["--print","--verbose","--output-format","stream-json","--model",o,"--permission-mode","bypassPermissions"],{cwd:i,env:n,stdio:["pipe","pipe","pipe"]});m.stdin.write(t),m.stdin.end();let p="",P="",u="",$=0,v=0,k={inputTokens:0,outputTokens:0,cacheCreationTokens:0,cacheReadTokens:0},B=o,l="";function T(E=!1){if(!l)return;let G=l.split(`
10
+ `),pe=E?"":G.pop()||"";for(let Y of G)if(Y.trim()){C(r,`${A} ${Y}`,"output");let F=Y.trim().length>160?Y.trim().substring(0,160)+"\u2026":Y.trim();console.log(`${y()} ${a} ${g.dim("\u{1F4AD}")} ${g.dim(F)}`)}l=pe}let R="initializing",N=!1,I={started:!0,reading:!1,analyzing:!1,generating:!1};function L(E){if(E===R)return;R=E;let G=Math.round((Date.now()-s)/1e3),pe=Bo(E,G);C(r,pe),console.log(`${y()} ${a} ${g.dim(pe)}`)}let V=setInterval(()=>T(),500),q=setInterval(()=>{let E=Math.round((Date.now()-s)/1e3);Ne(r,R,E,Bo(R,E),$,v)},2e3),x=0,ae=setInterval(()=>{let E=Math.round((Date.now()-s)/1e3);if(R==="initializing"&&E>=5?L("reading_repo"):R==="reading_repo"&&E>=15&&!N&&L("analyzing"),R==="generating_plan"&&E-x>=30){x=E;let G=`${A} Planning in progress \u2014 analyzing requirements and decomposing into steps (${qe(E)} elapsed)`;C(r,G),console.log(`${y()} ${a} ${g.dim(G)}`)}},5e3),X="";m.stdout.on("data",E=>{X+=E.toString();let G=X.split(`
11
+ `);X=G.pop()||"";for(let pe of G){let Y=pe.trim();if(Y)try{let F=JSON.parse(Y);if(F.type==="assistant"&&F.message?.content){let H=F.message.content;if(Array.isArray(H))for(let me of H)me.type==="text"&&me.text?(p+=me.text,$+=me.text.length,l+=me.text,N||(N=!0,v>0&&!I.analyzing&&(L("analyzing"),I.analyzing=!0)),$>500&&!I.generating&&(L("generating_plan"),I.generating=!0,x=Math.round((Date.now()-s)/1e3))):me.type==="tool_use"&&(v++,I.reading||(L("reading_repo"),I.reading=!0));else typeof H=="string"&&H&&(p+=H,$+=H.length,l+=H)}else F.type==="content_block_delta"&&F.delta?.text?(p+=F.delta.text,$+=F.delta.text.length,l+=F.delta.text,N||(N=!0,v>0&&!I.analyzing&&(L("analyzing"),I.analyzing=!0)),$>500&&!I.generating&&(L("generating_plan"),I.generating=!0,x=Math.round((Date.now()-s)/1e3))):F.type==="content_block_start"&&F.content_block?.type==="tool_use"?(v++,I.reading||(L("reading_repo"),I.reading=!0)):F.type==="result"&&F.result&&(P=typeof F.result=="string"?F.result:"");if(pn(F,k),F.type==="result"&&F.total_cost_usd!==void 0&&F.modelUsage&&typeof F.modelUsage=="object"){let H=Object.keys(F.modelUsage);H.length>0&&(B=H[0])}}catch{p+=Y+`
12
+ `,$+=Y.length}}}),m.stderr.on("data",E=>{u+=E.toString()});let re=setInterval(()=>{(k.inputTokens>0||k.outputTokens>0)&&jo(r,k,B,"greatest").catch(()=>{})},3e4);function ge(){clearInterval(ae),clearInterval(q),clearInterval(V),clearInterval(re),T(!0)}let Ke=setTimeout(()=>{ge(),m.kill("SIGTERM"),h(new Error("Claude CLI timed out after 20 minutes"))},12e5);m.on("exit",E=>{clearTimeout(Ke),ge();let G=Math.round((Date.now()-s)/1e3);Ne(r,"validating",G,"Validating plan...",$,v),jo(r,k,B,"greatest").catch(()=>{}),E!==0?h(new Error(`Claude CLI failed (exit ${E}): ${u.substring(0,300)}`)):c(P||p)}),m.on("error",E=>{clearTimeout(Ke),ge(),h(E)})})}function fn(e,o){if(o)switch(e){case"anthropic":return o.anthropicApiKey;case"openai":return o.openaiApiKey;case"google":return o.googleApiKey;case"ollama":return o.ollamaBaseUrl||"http://localhost:11434";default:return}}function hn(e,o,t){switch(t){case"bitbucket":return`https://x-token-auth:${o}@bitbucket.org/${e}.git`;case"gitlab":return`https://oauth2:${o}@gitlab.com/${e}.git`;default:return`https://x-access-token:${o}@github.com/${e}.git`}}async function $n(e,o,t,n){let r=g.cyan(n.slice(0,8)),s=`/tmp/workermill-planning-${n.slice(0,8)}-${Date.now()}`;try{let i=hn(e,o,t);return console.log(`${y()} ${r} ${g.dim("Cloning repo for planner...")}`),bo(`git clone --depth 1 --single-branch "${i}" "${s}"`,{stdio:"ignore",timeout:6e4}),console.log(`${y()} ${r} ${g.green("\u2713")} Repo cloned to ${g.dim(s)}`),s}catch(i){let a=i instanceof Error?i.message:String(i);console.error(`${y()} ${r} ${g.yellow("\u26A0")} Clone failed, planner will run without repo access: ${a.substring(0,100)}`);try{bo(`rm -rf "${s}"`,{stdio:"ignore"})}catch{}return null}}async function qo(e,o,t){let n=g.cyan(e.id.slice(0,8));console.log(`${y()} ${n} Fetching planning prompt...`),await C(e.id,`${A} Fetching planning prompt from cloud API...`);let r=await O.get("/api/agent/planning-prompt",{params:{taskId:e.id}}),{prompt:s,model:i,provider:a,maxStories:c,maxTargetFiles:h}=r.data,w=typeof c=="number"?c:8,m=i,p=a||"anthropic",P=p==="anthropic",u=process.env.CLAUDE_CLI_PATH||se()||"claude",$={...process.env};delete $.CLAUDE_CODE_OAUTH_TOKEN;let v=fn(p,t),k=Date.now(),B=e.description||e.summary,l=null;if(e.githubRepo){let q=e.scmProvider||"github",x=q==="bitbucket"?t?.scmToken||o.bitbucketToken:q==="gitlab"?t?.scmToken||o.gitlabToken:t?.githubToken||o.githubToken;x?l=await $n(e.githubRepo,x,q,e.id):console.log(`${y()} ${n} ${g.yellow("\u26A0")} No SCM token for ${q}, planner will run without repo access`)}let T=s,R=null,N=0,I=[],L=0,V=await No(typeof h=="number"?h:void 0);V||(console.log(`${y()} ${n} ${g.yellow("\u26A0")} Could not fetch critic config \u2014 critic validation will be skipped`),await C(e.id,`${A} \u26A0\uFE0F Could not fetch critic config from API \u2014 critic validation will be skipped`));try{for(let x=1;x<=ue;x++){let ae=ue>1?` (attempt ${x}/${ue})`:"",X=`${p}/${m}`;x>1?(console.log(`${y()} ${n} Running planner${ae} ${g.dim(`(${g.yellow(X)})`)}`),await C(e.id,`${A} Re-planning${ae} using ${X}`)):(console.log(`${y()} ${n} Running planner ${g.dim(`(${g.yellow(X)})`)}`),await C(e.id,`${A} Starting planning agent using ${X}`));let re;try{if(P)re=await Vo(u,m,T,$,e.id,k,l||void 0);else{if(!v)throw new Error(`No API key available for provider "${p}". Configure it in Settings > Integrations.`);let _=Math.round((Date.now()-k)/1e3);await Ne(e.id,"generating_plan",_,"Generating plan via AI SDK...",0,0),re=await yo({provider:p,model:m,apiKey:v,prompt:T,workingDir:l||void 0,enableTools:!!l,maxSteps:10});let M=Math.round((Date.now()-k)/1e3);await Ne(e.id,"validating",M,"Validating plan...",re.length,0)}}catch(_){let M=Math.round((Date.now()-k)/1e3),Q=_ instanceof Error?_.message:String(_);return console.error(`${y()} ${n} ${g.red("\u2717")} Failed after ${M}s: ${Q.substring(0,100)}`),await C(e.id,`${A} Planning failed after ${qe(M)}: ${Q.substring(0,200)}`,"error","error"),!1}let ge=Math.round((Date.now()-k)/1e3),Ke=P?"Claude CLI":`${p} API`;console.log(`${y()} ${n} ${g.green("\u2713")} ${Ke} done ${g.dim(`(${ge}s, ${re.length} chars)`)}`);let E;try{E=po(re)}catch(_){let M=_ instanceof Error?_.message:String(_);return console.error(`${y()} ${n} ${g.red("\u2717")} Plan parse failed: ${M.substring(0,100)}`),await C(e.id,`${A} Failed to parse execution plan from Claude output: ${M.substring(0,200)}`,"error","error"),await wn(e.id,re,o.agentId,n,ge)}let{truncatedCount:G,details:pe}=mo(E);if(G>0){L+=G;let _=`${A} File cap applied: ${G} stories truncated to max ${V?.maxTargetFiles??5} targetFiles`;console.log(`${y()} ${n} ${g.yellow("\u26A0")} ${_}`),await C(e.id,_);for(let M of pe)console.log(`${y()} ${n} ${g.dim(M)}`)}let{droppedCount:Y,details:F}=fo(E,w);if(Y>0){let _=`${A} Story cap applied: ${Y} stories dropped (max ${w})`;console.log(`${y()} ${n} ${g.yellow("\u26A0")} ${_}`),await C(e.id,_);for(let M of F)console.log(`${y()} ${n} ${g.dim(M)}`)}let{resolvedCount:H,details:me}=ho(E);if(H>0){let _=`${A} File overlap resolved: ${H} shared file(s) de-duped across stories`;console.log(`${y()} ${n} ${g.yellow("\u26A0")} ${_}`),await C(e.id,_);for(let M of me)console.log(`${y()} ${n} ${g.dim(M)}`)}console.log(`${y()} ${n} Plan: ${g.bold(E.stories.length)} stories (max ${w})`),await C(e.id,`${A} Plan generated: ${E.stories.length} stories (${qe(ge)}). Running critic validation...`);let b=await Ko(u,m,B,E,$,n,p,v,e.id);if(b&&b.score>N?(R=E,N=b.score):!b&&!R&&(R=E),b&&I.push({iteration:x,score:b.score,approved:b.approved||b.score>=te,risks:b.risks,suggestions:b.suggestions,filesCapApplied:G>0?G:void 0}),!b){let _=`${A} \u26A0\uFE0F CRITIC BYPASSED \u2014 Critic validation failed (timeout/parse error). Posting plan WITHOUT quality gate.`;console.log(`${y()} ${n} ${g.yellow("\u26A0")} ${_}`),await C(e.id,_,"error","warning");let M=Date.now()-k;return await Io(e.id,E,o.agentId,n,ge,void 0,void 0,I,L,M,x)}if(b.approved||b.score>=te){let _=`${A} Critic approved (score: ${b.score}/100)`;if(console.log(`${y()} ${n} ${g.green("\u2713")} ${_}`),await C(e.id,_),b.risks.length>0){let fe=`${A} Critic risks: ${b.risks.join("; ")}`;console.log(`${y()} ${n} ${g.dim(fe)}`),await C(e.id,fe)}if(b.suggestions&&b.suggestions.length>0){let fe=`${A} Critic suggestions: ${b.suggestions.join("; ")}`;console.log(`${y()} ${n} ${g.dim(fe)}`),await C(e.id,fe)}let M=b.risks.length>0||b.suggestions&&b.suggestions.length>0||b.storyFeedback&&b.storyFeedback.length>0,Q=E;if(M){await C(e.id,`${A} Running refinement pass \u2014 incorporating reviewer suggestions...`),console.log(`${y()} ${n} Running refinement pass...`);let fe=s+Do(b);try{let ke;if(P)ke=await Vo(u,m,fe,$,e.id,k,l||void 0);else{if(!v)throw new Error(`No API key for "${p}"`);ke=await yo({provider:p,model:m,apiKey:v,prompt:fe,workingDir:l||void 0,enableTools:!!l,maxSteps:10})}let Ae=po(ke);mo(Ae),fo(Ae,w),ho(Ae),Q=Ae;let Et=Math.round((Date.now()-k)/1e3);console.log(`${y()} ${n} ${g.green("\u2713")} Refinement complete ${g.dim(`(${Et}s)`)}`),await C(e.id,`${A} Refinement complete \u2014 plan updated with reviewer suggestions`)}catch(ke){let Ae=ke instanceof Error?ke.message:String(ke);console.warn(`${y()} ${n} ${g.yellow("\u26A0")} Refinement failed, using original plan: ${Ae.substring(0,100)}`),await C(e.id,`${A} \u26A0\uFE0F Refinement pass failed (${Ae.substring(0,100)}) \u2014 using original approved plan`)}}let kt=Date.now()-k,At=Math.round((Date.now()-k)/1e3);return await Io(e.id,Q,o.agentId,n,At,b.score,b.risks,I,L,kt,x)}if(x<ue){let _=Fo(b);T=T+`
12
13
 
13
- `+_;let M=`${E} Critic rejected (score: ${C.score}/100, threshold: ${te}). Re-planning with feedback...`;if(console.log(`${I()} ${t} ${p.yellow("\u26A0")} ${M}`),await R(e.id,M),C.risks.length>0){let Q=`${E} Critic risks: ${C.risks.join("; ")}`;console.log(`${I()} ${t} ${p.dim(Q)}`),await R(e.id,Q)}if(C.suggestions&&C.suggestions.length>0){let Q=`${E} Critic suggestions: ${C.suggestions.join("; ")}`;console.log(`${I()} ${t} ${p.dim(Q)}`),await R(e.id,Q)}}else{let _=`${E} Critic rejected after ${ue} iterations (best score: ${O}/100, threshold: ${te})`;if(console.error(`${I()} ${t} ${p.red("\u2717")} ${_}`),await R(e.id,_,"error","error"),C.risks.length>0){let M=`${E} Final risks: ${C.risks.join("; ")}`;console.error(`${I()} ${t} ${M}`),await R(e.id,M,"error","error")}if(C.suggestions&&C.suggestions.length>0){let M=`${E} Suggestions: ${C.suggestions.join("; ")}`;console.error(`${I()} ${t} ${M}`),await R(e.id,M,"error","error")}}}let q=50;if(T&&O>=q){let x=Math.round((Date.now()-A)/1e3),ae=`${E} Best-plan fallback: posting plan with score ${O}/100 (below ${te} threshold, above ${q} minimum)`;console.log(`${I()} ${t} ${p.yellow("\u26A0")} ${ae}`),await R(e.id,ae);let X=Date.now()-A;if(await go(e.id,T,o.agentId,t,x,O,[`Best-plan fallback: critic rejected after ${ue} iterations`],y,L,X,ue))return!0;console.log(`${I()} ${t} ${p.yellow("\u26A0")} ${E} Fallback post rejected by server, reporting plan-failed`),await R(e.id,`${E} Fallback plan rejected by server \u2014 reporting failure`)}try{let x=T&&O>=q?`Best-plan fallback rejected by server after ${ue} iterations (best score: ${O}/100)`:`Critic rejected after ${ue} iterations (best score: ${O}/100, threshold: ${te}, fallback minimum: ${q})`;await N.post("/api/agent/plan-failed",{taskId:e.id,agentId:o.agentId,reason:x,criticHistory:y})}catch{}return!1}finally{if(await sn(),l)try{po(`rm -rf "${l}"`,{stdio:"ignore"})}catch{}}}async function go(e,o,n,t,r,i,s,a,c,h,w){let m=vo(o);try{let P=(await N.post("/api/agent/plan-result",{taskId:e,rawOutput:m,agentId:n,criticScore:i,criticRisks:s,criticHistory:a,criticIterations:w,fileCapTruncations:c,planningDurationMs:h})).data.storyCount;return console.log(`${I()} ${t} ${p.green("\u2713")} Plan validated: ${p.bold(P)} stories \u2192 ${p.green("queued")}`),await R(e,`${E} Plan validated: ${P} stories. Task queued for execution.`),await ve(e,"complete",r,"Planning complete",0,0),!0}catch(g){let P=g,d=P.response?.data?.error||P.response?.data?.detail||String(g),$=P.response?.status?` (${P.response.status})`:"";return console.error(`${I()} ${t} ${p.red("\u2717")} Server validation failed${$}: ${d.substring(0,100)}`),await R(e,`${E} Server-side plan validation failed${$}: ${d.substring(0,200)}`,"error","error"),!1}}async function un(e,o,n,t,r){try{let s=(await N.post("/api/agent/plan-result",{taskId:e,rawOutput:o,agentId:n})).data.storyCount;return console.log(`${I()} ${t} ${p.green("\u2713")} Plan validated (server-side): ${p.bold(s)} stories \u2192 ${p.green("queued")}`),await R(e,`${E} Plan validated: ${s} stories. Task queued for execution.`),await ve(e,"complete",r,"Planning complete",0,0),!0}catch(i){let a=i.response?.data?.detail||String(i);return console.error(`${I()} ${t} ${p.red("\u2717")} Validation failed: ${a.substring(0,100)}`),await R(e,`${E} Plan validation failed: ${a.substring(0,200)}`,"error","error"),!1}}import f from"chalk";import{spawn as Bo,execSync as qe}from"child_process";import*as Ve from"path";import*as se from"fs";import*as Ye from"os";function D(){return f.dim(new Date().toLocaleTimeString())}var gn=[[/(:\/\/[^:/?#]+:)[^@]+(@)/g,"$1***$2"],[/\b(ghp_|gho_|ghs_|github_pat_)[A-Za-z0-9_]+/g,"$1***"],[/\bglpat-[A-Za-z0-9\-_]+/g,"glpat-***"],[/\b(AKIA)[A-Z0-9]{16}\b/g,"$1***"],[/(Bearer\s+)[A-Za-z0-9._\-]+/gi,"$1***"],[/(x-api-key:\s*)[^\s,'"]+/gi,"$1***"]];function ze(e){let o=e;for(let[n,t]of gn)o=o.replace(n,t);return o}var J=new Map;function pn(){if(process.env.WSL_DISTRO_NAME||process.env.WSL_INTEROP)return!0;try{return se.readFileSync("/proc/version","utf-8").toLowerCase().includes("microsoft")}catch{return!1}}var He=pn(),Vo=He||process.platform==="darwin"||process.platform==="win32";function zo(){if(!He)return null;try{let e=qe("hostname -I",{encoding:"utf-8"}).trim().split(/\s+/)[0];if(e&&/^\d+\.\d+\.\d+\.\d+$/.test(e))return e}catch{}return null}function qo(e){if(!He)return e;let o=e.match(/^\/mnt\/([a-zA-Z])\/(.*)$/);return o?`${o[1].toUpperCase()}:/${o[2]}`:e}function Yo(){let e=Ve.join(Ye.homedir(),".claude");if(se.existsSync(e))return e;if(He){let o="/mnt/c/Users";if(se.existsSync(o))try{for(let n of se.readdirSync(o)){if(["Public","Default","Default User","All Users"].includes(n))continue;let t=Ve.join(o,n,".claude");if(se.existsSync(t))return t}}catch{}}return null}var jo=0;function Ho(e){let o=e.match(/^(\d+\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com)/);return o?o[1]:null}function mn(e){let o=e.match(/\.ecr\.([a-z0-9-]+)\.amazonaws\.com/);return o?o[1]:"us-east-1"}function Jo(e){if(Date.now()<jo)return!0;let o=mn(e);try{return qe(`aws ecr get-login-password --region ${o} | docker login --username AWS --password-stdin ${e}`,{stdio:"pipe",timeout:3e4}),jo=Date.now()+660*60*1e3,!0}catch{return!1}}function Xo(e,o,n){if(n?.scmToken)return n.scmToken;switch(e){case"bitbucket":return o.bitbucketToken;case"gitlab":return o.gitlabToken;default:return o.githubToken}}function fn(e){let o=e.jiraFields;if(!o)return!1;let n=o.labels;if(Array.isArray(n)&&n.some(i=>typeof i=="string"&&i.toLowerCase()==="self-review"))return!0;let r=o.issue?.labels;return!!(Array.isArray(r)&&r.some(i=>typeof i=="string"?i.toLowerCase()==="self-review":i&&typeof i=="object"&&"name"in i?(i.name||"").toLowerCase()==="self-review":!1))}async function Qo(e,o,n,t){let r=f.cyan(e.id.slice(0,8));if(J.has(e.id)){console.log(`${D()} ${r} ${f.dim("Already running, skipping")}`);return}let i=`workermill-${e.id.slice(0,8)}`,a=["run","--rm",...!o.workerImage.includes("/")?[]:["--pull","always"],"--name",i],c=Math.round(Ye.totalmem()/(1024*1024*1024));if(c<=16?a.push("--memory","6g","--memory-swap","10g","--cpus","2"):(c<=32,a.push("--memory","6g","--memory-swap","12g","--cpus","4")),Vo){let y=zo();a.push(`--add-host=host.docker.internal:${y||"host-gateway"}`)}else a.push("--network","host");let h=e.workerProvider||"anthropic",w=Yo();if(!w&&h==="anthropic"){console.error(`${D()} ${r} ${f.red("\u2717")} Claude credentials not found. Run 'claude' and complete the sign-in flow.`);return}if(w){let y=Ve.join(w,".credentials.json");try{se.chmodSync(y,438)}catch{}let L=qo(w);a.push("-v",`${L}:/home/worker/.claude`)}else console.log(`${D()} ${r} ${f.dim("Skipping Claude mount (non-Anthropic worker)")}`);let m=o.apiUrl.replace(/localhost|127\.0\.0\.1/,"host.docker.internal"),g=e.scmProvider||"github",P=Xo(g,o,t),d=t?.githubToken||o.githubToken,$=g==="bitbucket"&&t?.scmToken||o.bitbucketToken,v=g==="gitlab"&&t?.scmToken||o.gitlabToken,A={NODE_OPTIONS:"--max-old-space-size=3072",EPIC_MODE:"true",EXECUTION_MODE:"local",TASK_ID:e.id,ORG_ID:e.orgId||"",JIRA_ISSUE_KEY:e.jiraIssueKey||"",JIRA_SUMMARY:e.summary||"",JIRA_DESCRIPTION:e.description||"",TASK_SUMMARY:e.summary||"",TASK_DESCRIPTION:e.description||"",WORKER_PERSONA:e.workerPersona||"",RETRY_NUMBER:String(e.retryCount??0),TICKET_KEY:e.jiraIssueKey||"",API_BASE_URL:m,ORG_API_KEY:o.apiKey,SCM_PROVIDER:g,SCM_TOKEN:P,SCM_BASE_URL:t?.scmBaseUrl||"",GITHUB_TOKEN:d,GH_TOKEN:d,GITHUB_REVIEWER_TOKEN:t?.githubReviewerToken||"",BITBUCKET_TOKEN:$,BITBUCKET_USERNAME:t?.bitbucketUsername||"x-token-auth",GITLAB_TOKEN:v,TARGET_REPO:e.githubRepo||"",GITHUB_REPO:e.githubRepo||"",WORKER_MODEL:e.workerModel||String(n.defaultWorkerModel||""),CLAUDE_MODEL:e.workerModel||String(n.defaultWorkerModel||""),JIRA_BASE_URL:t?.jiraBaseUrl||"",JIRA_EMAIL:t?.jiraEmail||"",JIRA_API_TOKEN:t?.jiraApiToken||"",TICKET_SYSTEM:t?.issueTrackerProvider||"jira",LINEAR_API_KEY:t?.linearApiKey||"",AWS_ACCESS_KEY_ID:t?.customerAwsAccessKeyId||"",AWS_SECRET_ACCESS_KEY:t?.customerAwsSecretAccessKey||"",AWS_DEFAULT_REGION:t?.customerAwsRegion||"",AWS_REGION:t?.customerAwsRegion||"",CUSTOMER_AWS_ROLE_ARN:t?.customerAwsRoleArn||"",CUSTOMER_AWS_EXTERNAL_ID:t?.customerAwsExternalId||"",CUSTOMER_AWS_REGION:t?.customerAwsRegion||"",MANAGER_PROVIDER:t?.managerProvider||"anthropic",MANAGER_MODEL:t?.managerModelId||"",BITBUCKET_EMAIL:t?.bitbucketEmail||"",DEPLOYMENT_ENABLED:e.deploymentEnabled||e.parentTaskId?"true":"false",PRD_CHILD_TASK:e.parentTaskId?"true":"false",IMPROVEMENT_ENABLED:e.improvementEnabled?"true":"false",QUALITY_GATE_BYPASS:e.qualityGateBypass?"true":"false",STANDARD_SDK_MODE:e.standardSdkMode?"true":"false",MAX_REVIEW_REVISIONS:String(n.maxReviewRevisions??3),CODEBASE_INDEXING_ENABLED:n.codebaseIndexingEnabled===!0?"true":"false",EXISTING_PR_URL:e.githubPrUrl||"",EXISTING_PR_NUMBER:e.githubPrNumber?String(e.githubPrNumber):"",PARENT_TASK_ID:e.parentTaskId||e.id,PARENT_JIRA_KEY:e.jiraIssueKey&&/-S\d+$/.test(e.jiraIssueKey)&&e.jiraFields?.parentJiraKey||"",TARGET_BRANCH:e.jiraFields?.targetBranch||"",STORY_BRANCH:e.jiraFields?.storyBranch||"",TASK_NOTES:e.taskNotes||"",TARGET_FILES:JSON.stringify(e.jiraFields?.targetFiles||[]),REFERENCE_FILES:JSON.stringify(e.jiraFields?.referenceFiles||[]),PIPELINE_VERSION:e.jiraFields?.pipelineVersion||e.pipelineVersion||"",V2_STEP_INPUT:e.jiraFields?.v2StepInput?JSON.stringify(e.jiraFields.v2StepInput):"",EXECUTION_MODE_SETTING:e.jiraFields?.executionMode||"autonomous",ANTHROPIC_API_KEY:w?"":t?.anthropicApiKey||process.env.ANTHROPIC_API_KEY||"",WORKER_PROVIDER:e.workerProvider||"anthropic",OPENAI_API_KEY:t?.openaiApiKey||"",GOOGLE_API_KEY:t?.googleApiKey||"",GOOGLE_GENERATIVE_AI_API_KEY:t?.googleApiKey||"",OLLAMA_HOST:t?.ollamaBaseUrl||"",OLLAMA_CONTEXT_WINDOW:t?.ollamaContextWindow?String(t.ollamaContextWindow):"",VLLM_BASE_URL:t?.vllmBaseUrl||"",BLOCKER_MAX_AUTO_RETRIES:String(n.blockerMaxAutoRetries??3),BLOCKER_AUTO_RETRY_ENABLED:n.blockerAutoRetryEnabled!==!1?"true":"false",PUSH_AFTER_COMMIT:n.pushAfterCommit!==!1?"true":"false",GRACEFUL_SHUTDOWN_ENABLED:n.gracefulShutdownEnabled!==!1?"true":"false",MAX_PARALLEL_EXPERTS:String(n.maxParallelExperts??4),REVIEW_ENABLED:e.skipManagerReview===!1?"true":"false",SELF_REVIEW_ENABLED:fn(e)||n.selfReviewEnabled!==!1?"true":"false"};for(let[y,L]of Object.entries(A))L!==""&&a.push("-e",`${y}=${L}`);let B=o.workerImage,l=Ho(B);l&&Jo(l),a.push(B);let b=e.skipManagerReview===!1;console.log(`${D()} ${r} ${f.dim("Starting container")} ${f.yellow(i)}`),console.log(`${D()} ${r} ${f.dim(` skipManagerReview=${e.skipManagerReview} \u2192 REVIEW_ENABLED=${b}`)}`),console.log(`${D()} ${r} ${f.dim(` model=${e.workerModel} repo=${e.githubRepo}`)}`),console.log(`${D()} ${r} ${f.dim(` totalRamGB=${c} docker args:`)} ${a.slice(0,10).join(" ")}`);let T=Bo("docker",a,{stdio:["ignore","pipe","pipe"],detached:!1});if(!T.pid){console.error(`${D()} ${r} ${f.red("\u2717")} Failed to spawn container`);return}let O={taskId:e.id,containerName:i,process:T,startedAt:new Date,status:"running",resultEmitted:!1};J.set(e.id,O),T.stdout?.on("data",y=>{let L=y.toString().split(`
14
- `).filter(V=>V.trim());for(let V of L)console.log(`${D()} ${r} ${f.dim(ze(V))}`),V.includes("::result::")&&(O.resultEmitted=!0)}),T.stderr?.on("data",y=>{let L=y.toString().split(`
15
- `).filter(V=>V.trim());for(let V of L)console.log(`${D()} ${r} ${f.red(ze(V))}`)}),T.on("exit",y=>{O.status=y===0?"completed":"failed";let L=Math.round((Date.now()-O.startedAt.getTime())/1e3),V=y===0?f.green("\u2713"):f.red("\u2717"),q=y===0?f.green("completed"):f.red(`failed (exit ${y})`);console.log(`${D()} ${r} ${V} Container ${q} ${f.dim(`(${L}s)`)}`),O.resultEmitted||(console.log(`${D()} ${r} ${f.yellow("\u26A0")} No ::result:: marker seen \u2014 posting fallback completion in 15s`),setTimeout(async()=>{try{let x=y===0?"completed":"failed",ae=y!==0?`Worker container exited with code ${y} without reporting completion`:void 0;(await(await fetch(`${o.apiUrl}/api/tasks/${e.id}/worker-complete`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o.apiKey},body:JSON.stringify({exitCode:y??1,result:x,errorMessage:ae})})).json()).status==="ignored"?console.log(`${D()} ${r} ${f.dim("Fallback completion ignored (task already transitioned)")}`):console.log(`${D()} ${r} ${f.yellow("\u26A0")} Fallback completion applied: ${x}`)}catch(x){console.error(`${D()} ${r} ${f.red("\u2717")} Fallback completion failed:`,x instanceof Error?x.message:x)}},15e3)),setTimeout(()=>J.delete(e.id),9e4)}),T.on("error",y=>{O.status="failed",console.error(`${D()} ${r} ${f.red("\u2717")} Container error: ${y.message}`)})}function mo(){return Array.from(J.values()).filter(e=>e.status==="running").length}function Zo(){return Array.from(J.values()).filter(e=>e.status==="running").map(e=>e.taskId)}function et(e){let o=J.get(e);if(!o||o.status!=="running")return;let n=f.cyan(e.slice(0,8));console.log(`${D()} ${n} ${f.red("\u25A0")} Stopping container (cancelled by dashboard)`);try{qe(`docker stop ${o.containerName}`,{stdio:"ignore",timeout:15e3}),o.status="completed"}catch{}J.delete(e)}async function ot(){console.log(`${D()} ${f.dim(`Stopping ${J.size} containers...`)}`);for(let[,e]of J)if(e.status==="running")try{qe(`docker stop ${e.containerName}`,{stdio:"ignore",timeout:15e3}),e.status="completed"}catch{}J.clear()}async function tt(e,o,n){let t=f.cyan(e.id.slice(0,8)),r=`manager-${e.id}`;if(J.has(r))return;let i=`wm-manager-${e.id.slice(0,8)}-${Date.now()}`,s=Yo(),a=["run","--rm","--name",i,"--memory=4g","--cpus=2"];if(Vo){let l=zo();a.push(`--add-host=host.docker.internal:${l||"host-gateway"}`)}else a.push("--network","host");if(s){let l=qo(s);a.push("-v",`${l}:/home/worker/.claude`)}let c=o.apiUrl.replace(/localhost|127\.0\.0\.1/,"host.docker.internal"),h=e.scmProvider||"github",w=Xo(h,o,n),m=n?.githubToken||o.githubToken,g=h==="bitbucket"&&n?.scmToken||o.bitbucketToken,P=h==="gitlab"&&n?.scmToken||o.gitlabToken,d={NODE_OPTIONS:"--max-old-space-size=3072",TASK_ID:e.id,MANAGER_ACTION:e.managerAction,JIRA_ISSUE_KEY:e.jiraIssueKey||"",JIRA_SUMMARY:e.summary||"",JIRA_DESCRIPTION:e.description||"",GITHUB_REPO:e.githubRepo||"",PR_URL:e.githubPrUrl||"",PR_NUMBER:e.githubPrNumber?String(e.githubPrNumber):"",API_BASE_URL:c,ORG_API_KEY:o.apiKey,SCM_PROVIDER:h,SCM_TOKEN:w,GITHUB_TOKEN:m,GH_TOKEN:m,BITBUCKET_TOKEN:g,BITBUCKET_USERNAME:n?.bitbucketUsername||"x-token-auth",GITLAB_TOKEN:P,MANAGER_PROVIDER:n?.managerProvider||"anthropic",MANAGER_MODEL:n?.managerModelId||"",ANTHROPIC_API_KEY:s?"":n?.anthropicApiKey||process.env.ANTHROPIC_API_KEY||"",OPENAI_API_KEY:n?.openaiApiKey||"",GOOGLE_API_KEY:n?.googleApiKey||"",JIRA_BASE_URL:n?.jiraBaseUrl||"",JIRA_EMAIL:n?.jiraEmail||"",JIRA_API_TOKEN:n?.jiraApiToken||"",TICKET_SYSTEM:n?.issueTrackerProvider||"jira",LINEAR_API_KEY:n?.linearApiKey||""};for(let[l,b]of Object.entries(d))b!==""&&a.push("-e",`${l}=${b}`);let $=o.workerImage,v=Ho($);v&&Jo(v),a.push("--entrypoint","/bin/bash"),a.push($),a.push("/app/manager-entrypoint.sh"),console.log(`${D()} ${t} ${f.magenta("\u25C6 MANAGER")} Starting ${e.managerAction} container ${f.yellow(i)}`);let A=Bo("docker",a,{stdio:["ignore","pipe","pipe"],detached:!1});if(!A.pid){console.error(`${D()} ${t} ${f.red("\u2717")} Failed to spawn manager container`);return}let B={taskId:r,containerName:i,process:A,startedAt:new Date,status:"running",resultEmitted:!1};J.set(r,B),A.stdout?.on("data",l=>{let b=l.toString().split(`
16
- `).filter(T=>T.trim());for(let T of b)console.log(`${D()} ${t} ${f.magenta("MGR")} ${f.dim(ze(T))}`)}),A.stderr?.on("data",l=>{let b=l.toString().split(`
17
- `).filter(T=>T.trim());for(let T of b)console.log(`${D()} ${t} ${f.magenta("MGR")} ${f.red(ze(T))}`)}),A.on("exit",l=>{B.status=l===0?"completed":"failed";let b=Math.round((Date.now()-B.startedAt.getTime())/1e3),T=l===0?f.green("\u2713"):f.red("\u2717"),O=l===0?f.green("completed"):f.red(`failed (exit ${l})`);console.log(`${D()} ${t} ${f.magenta("MGR")} ${T} Manager ${e.managerAction} ${O} ${f.dim(`(${b}s)`)}`),setTimeout(()=>J.delete(r),6e4)}),A.on("error",l=>{B.status="failed",console.error(`${D()} ${t} ${f.magenta("MGR")} ${f.red("\u2717")} Container error: ${l.message}`)})}import{spawn as nt}from"child_process";import Le from"chalk";async function Me(){return console.log(Le.cyan(" Updating @workermill/agent...")),new Promise(e=>{let o=nt("npm",["install","-g","@workermill/agent@latest"],{stdio:"inherit",shell:!0});o.on("error",n=>{console.error(Le.red(` Update failed: ${n.message}`)),e(!1)}),o.on("close",n=>{n===0?(console.log(Le.green(" Update successful.")),e(!0)):(console.error(Le.red(` Update failed with exit code ${n}`)),e(!1))})})}function Je(){console.log(Le.cyan(" Restarting agent...")),nt(process.argv[0],process.argv.slice(1),{stdio:"inherit",detached:!0}).unref(),process.exit(0)}var ke=new Set,be=new Set,Xe=null,rt=!1,Qe=!1;function W(){return S.dim(new Date().toLocaleTimeString())}async function hn(){if(Xe)return Xe;try{return Xe=(await N.get("/api/agent/config")).data,Xe}catch{return console.error(`${W()} ${S.red("\u2717")} Failed to fetch org config`),{}}}async function it(e){if(!Qe)try{let o=await N.get("/api/agent/poll",{params:{agentId:e.agentId}}),n=o.data.tasks;if(n.length===0)return;for(let r of n)r.status==="planning"&&!ke.has(r.id)?await $n(r,e):r.status==="queued"&&await wn(r,e);let t=o.data.managerTasks;if(t&&t.length>0)for(let r of t)be.has(r.id)||await yn(r,e)}catch(o){let n=o,t=ke.size>0||mo()>0||be.size>0;n.response?.status===401?t||console.error(`${W()} ${S.red("\u2717")} Authentication failed. Check your API key.`):t||console.warn(`${W()} ${S.yellow("\u26A0")} Poll error: ${n.message||String(o)}`)}}async function $n(e,o){let n,t;try{let s=await N.post("/api/agent/claim",{taskId:e.id,agentId:o.agentId});if(!s.data.claimed)return;n=s.data.credentials,t=s.data.task}catch{return}let r=S.cyan(e.id.slice(0,8));if(t&&(t.retryCount??0)>0&&t.executionPlanV2!=null){console.log(),console.log(`${W()} ${S.magenta("\u25C6 RESUME")} ${r} ${e.summary.substring(0,60)}`),console.log(`${W()} ${r} Retry #${t.retryCount} with existing plan \u2014 skipping planning`),ke.add(e.id);try{await N.post("/api/agent/resume-plan",{taskId:e.id,agentId:o.agentId}),console.log(`${W()} ${r} ${S.green("\u2713")} Resumed with existing plan \u2192 ${S.green("queued")}`)}catch(s){let a=s,c=a.response?.data?.error||a.message||String(s);console.error(`${W()} ${r} ${S.red("\u2717")} Resume failed: ${c}`)}ke.delete(e.id);return}console.log(),console.log(`${W()} ${S.magenta("\u25C6 PLANNING")} ${r} ${e.summary.substring(0,60)}`),ke.add(e.id),Go(e,o,n).then(s=>{console.log(s?`${W()} ${S.green("\u2713")} Planning complete for ${r}`:`${W()} ${S.red("\u2717")} Planning failed for ${r}`)}).catch(s=>console.error(`${W()} ${S.red("\u2717")} Planning error for ${r}:`,s.message||s)).finally(()=>ke.delete(e.id))}async function wn(e,o){if(mo()>=o.maxWorkers)return;let t;try{if(t=(await N.post("/api/agent/claim",{taskId:e.id,agentId:o.agentId})).data,!t.claimed)return}catch{return}try{await N.post("/api/agent/started",{taskId:e.id,agentId:o.agentId})}catch{let h=S.cyan(e.id.slice(0,8));console.warn(`${W()} ${S.yellow("\u26A0")} Failed to report started for ${h}`)}let r=S.cyan(e.id.slice(0,8));console.log(),console.log(`${W()} ${S.blue("\u25B6 EXECUTING")} ${r} ${e.summary.substring(0,60)}`);let i=await hn(),s=t.task||{id:e.id,summary:e.summary,description:e.description,jiraIssueKey:e.jiraIssueKey,workerModel:e.workerModel,workerProvider:e.workerProvider,githubRepo:e.githubRepo,scmProvider:e.scmProvider,skipManagerReview:e.skipManagerReview,deploymentEnabled:e.deploymentEnabled,improvementEnabled:e.improvementEnabled,qualityGateBypass:e.qualityGateBypass,standardSdkMode:e.standardSdkMode,parentTaskId:e.parentTaskId,taskNotes:e.taskNotes,githubPrUrl:e.githubPrUrl,githubPrNumber:e.githubPrNumber,executionPlanV2:e.executionPlanV2,jiraFields:e.jiraFields||{}},a=t.credentials;Qo(s,o,i,a).catch(c=>console.error(`${W()} ${S.red("\u2717")} Spawn failed for ${r}:`,c.message||c))}async function yn(e,o){let n=S.cyan(e.id.slice(0,8));be.add(e.id);try{let t=await N.post("/api/agent/claim-manager",{taskId:e.id,agentId:o.agentId,action:e.managerAction});if(!t.data.claimed){be.delete(e.id);return}let r=t.data.task,i=t.data.credentials||{},s=e.managerAction==="analyze_logs"?S.yellow("LOG ANALYSIS"):S.yellow("PR REVIEW");console.log(),console.log(`${W()} ${S.magenta("\u25C6 MANAGER")} ${s} ${n} ${e.summary.substring(0,60)}`);let a={id:e.id,summary:r?.summary||e.summary,description:r?.description||e.description,jiraIssueKey:r?.jiraIssueKey||e.jiraIssueKey,githubRepo:r?.githubRepo||e.githubRepo,scmProvider:r?.scmProvider||e.scmProvider,githubPrUrl:r?.githubPrUrl||e.githubPrUrl,githubPrNumber:r?.githubPrNumber||e.githubPrNumber,managerAction:e.managerAction};tt(a,o,i).then(()=>{console.log(`${W()} ${n} ${S.magenta("MGR")} ${S.green("\u2713")} Manager ${e.managerAction} dispatched`)}).catch(c=>{console.error(`${W()} ${n} ${S.magenta("MGR")} ${S.red("\u2717")} Manager spawn failed:`,c.message||c)}).finally(()=>be.delete(e.id))}catch(t){be.delete(e.id);let r=t;console.error(`${W()} ${n} ${S.red("\u2717")} Failed to claim manager task:`,r.message||String(t))}}var Ze=null,eo=null;function st(){Ze&&(clearInterval(Ze),Ze=null),eo&&(clearInterval(eo),eo=null)}function at(e){console.log(` ${S.dim("Polling every")} ${e.pollIntervalMs/1e3}s ${S.dim("\xB7 waiting for tasks...")}`),it(e),Ze=setInterval(()=>it(e),e.pollIntervalMs)}function lt(e){eo=setInterval(async()=>{let o=Zo(),n=Array.from(ke),t=Array.from(be),r=[...o,...n,...t];try{let i=await N.post("/api/agent/heartbeat",{agentId:e.agentId,activeTasks:r,agentVersion:z}),s=i.data?.cancelledTasks;if(s&&s.length>0)for(let w of s)et(w);let{updateAvailable:a,updateRequired:c,latestVersion:h}=i.data??{};c&&!Qe?(Qe=!0,console.log(`${W()} ${S.red("\u26A0 Agent update required")} (current: ${z}, required: ${h})`),console.log(`${W()} ${S.yellow("Refusing new tasks until updated.")}`),await Me()?Je():(console.log(`${W()} ${S.red("Auto-update failed.")} Run: npm install -g @workermill/agent@latest`),Qe=!1)):a&&!rt&&!c&&(rt=!0,console.log(`${W()} ${S.yellow(`Update available: ${h}`)} (current: ${z}). Run: workermill-agent update`))}catch{}},e.heartbeatIntervalMs)}oe();async function fo(e){console.log(),console.log(K.bold.cyan(" WorkerMill Remote Agent")),console.log(K.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),Ge(e.apiUrl,e.apiKey);try{let o=await N.get("/api/agent/config"),n=o.data.maxConcurrentWorkers;n&&typeof n=="number"&&(e.maxWorkers=n),o.data.workerImageUrl&&(e.workerImage=o.data.workerImageUrl),console.log(` ${K.green("\u25CF")} Connected to ${K.cyan(e.apiUrl)}`),console.log(` ${K.dim("Agent:")} ${e.agentId}`),console.log(` ${K.dim("Workers:")} ${K.yellow(String(e.maxWorkers))} parallel`),console.log(` ${K.dim("Image:")} ${e.workerImage}`),console.log(` ${K.dim("SCM:")} ${o.data.scmProvider}`),console.log(` ${K.dim("Model:")} ${K.yellow(o.data.defaultWorkerModel)}`),console.log()}catch(o){let n=o;throw n.response?.status===401?new Error("Authentication failed. Check your API key."):new Error(`Failed to connect to WorkerMill API: ${n.message||String(o)}`)}try{let o=await N.post("/api/agent/register",{agentId:e.agentId,maxWorkers:e.maxWorkers,agentVersion:z}),{updateAvailable:n,updateRequired:t,latestVersion:r}=o.data;t?(console.log(K.red(` \u26A0 Agent update required (current: ${z}, required: ${r})`)),await Me()?Je():console.log(K.yellow(" Auto-update failed. Run: npm install -g @workermill/agent@latest"))):n&&console.log(K.yellow(` Update available: ${r} (current: ${z}). Run: workermill-agent update`))}catch{}return at(e),lt(e),console.log(K.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` ${K.green("\u25CF")} Agent is running. ${K.dim("Press Ctrl+C to stop.")}`),console.log(),async()=>{console.log(),console.log(K.dim(" Shutting down...")),st();try{await N.post("/api/agent/deregister",{agentId:e.agentId})}catch{}await ot(),console.log(` ${K.red("\u25CF")} Agent stopped.`)}}var In=typeof process<"u"&&process.argv[1]&&(process.argv[1].endsWith("/index.ts")||process.argv[1].endsWith("/index.js"));if(In){try{await import("dotenv/config")}catch{}let{loadConfig:e,validatePrerequisites:o}=await Promise.resolve().then(()=>(oe(),Ao)),n=e();o(),console.log(K.dim(" Prerequisites validated."));let t=await fo(n);process.on("SIGINT",async()=>{await t(),process.exit(0)}),process.on("SIGTERM",async()=>{await t(),process.exit(0)})}async function ho(e){bn(ee())||(console.log(U.red("No configuration found.")),console.log(`Run ${U.cyan("workermill-agent setup")} first.`),process.exit(1));let o=he(),t=no(o.workerImage).filter(d=>!d.ok),r=t.find(d=>d.name==="Worker image"),i=new Set(["Claude CLI","Claude auth"]),s=t.filter(d=>d.name!=="Worker image"&&!i.has(d.name)),a=t.filter(d=>i.has(d.name));if(s.length>0){console.log(U.red("Prerequisites check failed:"));for(let d of s)console.log(U.red(` \u2717 ${d.name}: ${d.detail}`));process.exit(1)}if(a.length>0)for(let d of a)console.log(U.yellow(` \u26A0 ${d.name}: ${d.detail} (required for Anthropic provider)`));if(r){console.log(U.yellow(` Worker image not found locally. Pulling ${o.workerImage}...`));let{spawnSync:d}=await import("child_process");d("docker",["pull",o.workerImage],{stdio:"inherit",timeout:6e5}).status!==0&&(console.log(U.red(" Failed to pull worker image.")),process.exit(1)),console.log(U.green(" \u2713 Worker image pulled"))}if(e.detach){let d=_e(),$=ce();console.log(U.dim("Starting agent in background...")),console.log(U.dim(` Logs: ${d}`)),console.log(U.dim(` PID: ${$}`));let v=Sn(d,"a"),A=kn("workermill-agent",["start"],{detached:!0,stdio:["ignore",v,v],shell:!0});A.pid?(ct($,String(A.pid),"utf-8"),A.unref(),console.log(U.green(`Agent started (PID: ${A.pid})`)),console.log(`Check status with: ${U.cyan("workermill-agent status")}`)):(console.log(U.red("Failed to start agent in background.")),process.exit(1));return}let c=_e(),h=Tn(c,{flags:"a"}),w=process.stdout.write.bind(process.stdout),m=process.stderr.write.bind(process.stderr);process.stdout.write=(d,...$)=>(h.write(d),w(d,...$)),process.stderr.write=(d,...$)=>(h.write(d),m(d,...$)),console.log(),console.log(U.bold.cyan(" WorkerMill Remote Agent")),console.log(U.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log();let g=Math.round(An()/(1024*1024*1024));g<8?(console.log(U.red(` \u2717 Insufficient RAM: ${g} GB (minimum 8 GB, recommended 16 GB)`)),process.exit(1)):g<16&&console.log(U.yellow(` \u26A0 RAM: ${g} GB (below recommended 16 GB \u2014 workers may be slow)`));let P=Ue();console.log(U.dim(` Agent: ${o.agentId}`)),console.log(U.dim(` Version: ${z}`)),console.log(U.dim(` Image: ${o.workerImage}`)),console.log();try{let d=await fo(o);ct(ce(),String(process.pid),"utf-8");let $=!1,v=async()=>{$&&(console.log(U.red(`
18
- Force exit.`)),process.exit(1)),$=!0;let A=setTimeout(()=>{console.log(U.red(`
19
- Cleanup timed out. Force exit.`)),process.exit(1)},1e4);A.unref(),await d(),clearTimeout(A);try{En(ce())}catch{}process.exit(0)};process.on("SIGINT",v),process.on("SIGTERM",v)}catch(d){console.log(U.red(`Failed to start: ${d instanceof Error?d.message:String(d)}`)),process.exit(1)}}oe();import Ee from"chalk";import{existsSync as Cn,readFileSync as _n,unlinkSync as $o}from"fs";async function dt(){let e=ce();if(!Cn(e)){console.log(Ee.yellow("No running agent found (no PID file).")),console.log(Ee.dim(`Expected PID file at: ${e}`));return}let o=_n(e,"utf-8").trim(),n=parseInt(o,10);if(isNaN(n)){console.log(Ee.red(`Invalid PID in ${e}: ${o}`)),$o(e);return}try{process.kill(n,0)}catch{console.log(Ee.yellow(`Agent (PID ${n}) is not running. Cleaning up PID file.`)),$o(e);return}console.log(Ee.dim(`Stopping agent (PID ${n})...`));try{process.kill(n,"SIGTERM")}catch(r){console.log(Ee.red(`Failed to stop agent: ${r instanceof Error?r.message:String(r)}`));return}let t=Date.now();for(;Date.now()-t<15e3;)try{process.kill(n,0),await new Promise(r=>setTimeout(r,500))}catch{break}try{$o(e)}catch{}console.log(Ee.green("Agent stopped."))}oe();import j from"chalk";import{existsSync as ut,readFileSync as Rn}from"fs";import{execSync as Pn}from"child_process";import xn from"axios";async function gt(){if(console.log(),console.log(j.bold("WorkerMill Remote Agent Status")),console.log(j.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),!ut(ee())){console.log(j.yellow(" Not configured. Run 'workermill-agent setup' first."));return}let e=he(),o=ce(),n=!1,t=null;if(ut(o)){let i=Rn(o,"utf-8").trim();if(t=parseInt(i,10),!isNaN(t))try{process.kill(t,0),n=!0}catch{n=!1}}let r=n?j.green("\u25CF online"):j.red("\u25CF offline");console.log(` Status: ${r}${t?j.dim(` (PID ${t})`):""}`),console.log(` Agent ID: ${e.agentId}`),console.log(` API URL: ${e.apiUrl}`),console.log(` Max workers: ${e.maxWorkers}`),console.log(` Image: ${e.workerImage}`),console.log(),console.log(j.bold(" Active Containers"));try{let i=Pn('docker ps --filter "name=workermill-" --format "{{.Names}} {{.Status}} {{.RunningFor}}"',{encoding:"utf-8",timeout:1e4}).trim();if(i){let s=i.split(`
20
- `);console.log(j.dim(` Found ${s.length} container(s):`));for(let a of s){let[c,h,w]=a.split(" ");console.log(` ${j.cyan(c)} ${h} ${j.dim(w||"")}`)}}else console.log(j.dim(" No active containers"))}catch{console.log(j.dim(" Could not query Docker"))}console.log(),console.log(j.bold(" API Connectivity"));try{let i=await xn.get(`${e.apiUrl}/api/agent/config`,{headers:{"x-api-key":e.apiKey},timeout:1e4});console.log(` ${j.green("\u2713")} Connected to ${e.apiUrl}`),console.log(j.dim(` SCM: ${i.data.scmProvider}, Model: ${i.data.defaultWorkerModel}`))}catch(i){i.response?.status===401?console.log(` ${j.red("\u2717")} Authentication failed (invalid API key)`):console.log(` ${j.red("\u2717")} Cannot reach ${e.apiUrl}`)}console.log()}oe();import oo from"chalk";import{existsSync as vn,readFileSync as Mn,watchFile as Nn,statSync as pt,openSync as On,readSync as Ln,closeSync as Fn}from"fs";async function mt(e){let o=_e();if(!vn(o)){console.log(oo.yellow("No log file found.")),console.log(oo.dim(`Expected at: ${o}`)),console.log(oo.dim("Start the agent with --detach to generate logs."));return}let n=parseInt(e.lines||"50",10),r=Mn(o,"utf-8").split(`
21
- `),i=Math.max(0,r.length-n),s=r.slice(i).join(`
22
- `);s.trim()&&(process.stdout.write(s),s.endsWith(`
14
+ `+_;let M=`${A} Critic rejected (score: ${b.score}/100, threshold: ${te}). Re-planning with feedback...`;if(console.log(`${y()} ${n} ${g.yellow("\u26A0")} ${M}`),await C(e.id,M),b.risks.length>0){let Q=`${A} Critic risks: ${b.risks.join("; ")}`;console.log(`${y()} ${n} ${g.dim(Q)}`),await C(e.id,Q)}if(b.suggestions&&b.suggestions.length>0){let Q=`${A} Critic suggestions: ${b.suggestions.join("; ")}`;console.log(`${y()} ${n} ${g.dim(Q)}`),await C(e.id,Q)}}else{let _=`${A} Critic rejected after ${ue} iterations (best score: ${N}/100, threshold: ${te})`;if(console.error(`${y()} ${n} ${g.red("\u2717")} ${_}`),await C(e.id,_,"error","error"),b.risks.length>0){let M=`${A} Final risks: ${b.risks.join("; ")}`;console.error(`${y()} ${n} ${M}`),await C(e.id,M,"error","error")}if(b.suggestions&&b.suggestions.length>0){let M=`${A} Suggestions: ${b.suggestions.join("; ")}`;console.error(`${y()} ${n} ${M}`),await C(e.id,M,"error","error")}}}let q=50;if(R&&N>=q){let x=Math.round((Date.now()-k)/1e3),ae=`${A} Best-plan fallback: posting plan with score ${N}/100 (below ${te} threshold, above ${q} minimum)`;console.log(`${y()} ${n} ${g.yellow("\u26A0")} ${ae}`),await C(e.id,ae);let X=Date.now()-k;if(await Io(e.id,R,o.agentId,n,x,N,[`Best-plan fallback: critic rejected after ${ue} iterations`],I,L,X,ue))return!0;console.log(`${y()} ${n} ${g.yellow("\u26A0")} ${A} Fallback post rejected by server, reporting plan-failed`),await C(e.id,`${A} Fallback plan rejected by server \u2014 reporting failure`)}try{let x=R&&N>=q?`Best-plan fallback rejected by server after ${ue} iterations (best score: ${N}/100)`:`Critic rejected after ${ue} iterations (best score: ${N}/100, threshold: ${te}, fallback minimum: ${q})`;await O.post("/api/agent/plan-failed",{taskId:e.id,agentId:o.agentId,reason:x,criticHistory:I})}catch{}return!1}finally{if(await mn(),l)try{bo(`rm -rf "${l}"`,{stdio:"ignore"})}catch{}}}async function Io(e,o,t,n,r,s,i,a,c,h,w){let m=Lo(o);try{let P=(await O.post("/api/agent/plan-result",{taskId:e,rawOutput:m,agentId:t,criticScore:s,criticRisks:i,criticHistory:a,criticIterations:w,fileCapTruncations:c,planningDurationMs:h})).data.storyCount;return console.log(`${y()} ${n} ${g.green("\u2713")} Plan validated: ${g.bold(P)} stories \u2192 ${g.green("queued")}`),await C(e,`${A} Plan validated: ${P} stories. Task queued for execution.`),await Ne(e,"complete",r,"Planning complete",0,0),!0}catch(p){let P=p,u=P.response?.data?.error||P.response?.data?.detail||String(p),$=P.response?.status?` (${P.response.status})`:"";return console.error(`${y()} ${n} ${g.red("\u2717")} Server validation failed${$}: ${u.substring(0,100)}`),await C(e,`${A} Server-side plan validation failed${$}: ${u.substring(0,200)}`,"error","error"),!1}}async function wn(e,o,t,n,r){try{let i=(await O.post("/api/agent/plan-result",{taskId:e,rawOutput:o,agentId:t})).data.storyCount;return console.log(`${y()} ${n} ${g.green("\u2713")} Plan validated (server-side): ${g.bold(i)} stories \u2192 ${g.green("queued")}`),await C(e,`${A} Plan validated: ${i} stories. Task queued for execution.`),await Ne(e,"complete",r,"Planning complete",0,0),!0}catch(s){let a=s.response?.data?.detail||String(s);return console.error(`${y()} ${n} ${g.red("\u2717")} Validation failed: ${a.substring(0,100)}`),await C(e,`${A} Plan validation failed: ${a.substring(0,200)}`,"error","error"),!1}}import f from"chalk";import{spawn as Ho,execSync as Je}from"child_process";import*as Ye from"path";import*as ie from"fs";import*as Xe from"os";function D(){return f.dim(new Date().toLocaleTimeString())}var yn=[[/(:\/\/[^:/?#]+:)[^@]+(@)/g,"$1***$2"],[/\b(ghp_|gho_|ghs_|github_pat_)[A-Za-z0-9_]+/g,"$1***"],[/\bglpat-[A-Za-z0-9\-_]+/g,"glpat-***"],[/\b(AKIA)[A-Z0-9]{16}\b/g,"$1***"],[/(Bearer\s+)[A-Za-z0-9._\-]+/gi,"$1***"],[/(x-api-key:\s*)[^\s,'"]+/gi,"$1***"]];function He(e){let o=e;for(let[t,n]of yn)o=o.replace(t,n);return o}var J=new Map;function In(){if(process.env.WSL_DISTRO_NAME||process.env.WSL_INTEROP)return!0;try{return ie.readFileSync("/proc/version","utf-8").toLowerCase().includes("microsoft")}catch{return!1}}var Qe=In(),Jo=Qe||process.platform==="darwin"||process.platform==="win32";function Xo(){if(!Qe)return null;try{let e=Je("hostname -I",{encoding:"utf-8"}).trim().split(/\s+/)[0];if(e&&/^\d+\.\d+\.\d+\.\d+$/.test(e))return e}catch{}return null}function Qo(e){if(!Qe)return e;let o=e.match(/^\/mnt\/([a-zA-Z])\/(.*)$/);return o?`${o[1].toUpperCase()}:/${o[2]}`:e}function Zo(){let e=Ye.join(Xe.homedir(),".claude");if(ie.existsSync(e))return e;if(Qe){let o="/mnt/c/Users";if(ie.existsSync(o))try{for(let t of ie.readdirSync(o)){if(["Public","Default","Default User","All Users"].includes(t))continue;let n=Ye.join(o,t,".claude");if(ie.existsSync(n))return n}}catch{}}return null}var Yo=0;function et(e){let o=e.match(/^(\d+\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com)/);return o?o[1]:null}function bn(e){let o=e.match(/\.ecr\.([a-z0-9-]+)\.amazonaws\.com/);return o?o[1]:"us-east-1"}function ot(e){if(Date.now()<Yo)return!0;let o=bn(e);try{return Je(`aws ecr get-login-password --region ${o} | docker login --username AWS --password-stdin ${e}`,{stdio:"pipe",timeout:3e4}),Yo=Date.now()+660*60*1e3,!0}catch{return!1}}function tt(e,o,t){if(t?.scmToken)return t.scmToken;switch(e){case"bitbucket":return o.bitbucketToken;case"gitlab":return o.gitlabToken;default:return o.githubToken}}function kn(e){let o=e.jiraFields;if(!o)return!1;let t=o.labels;if(Array.isArray(t)&&t.some(s=>typeof s=="string"&&s.toLowerCase()==="self-review"))return!0;let r=o.issue?.labels;return!!(Array.isArray(r)&&r.some(s=>typeof s=="string"?s.toLowerCase()==="self-review":s&&typeof s=="object"&&"name"in s?(s.name||"").toLowerCase()==="self-review":!1))}async function nt(e,o,t,n){let r=f.cyan(e.id.slice(0,8));if(J.has(e.id)){console.log(`${D()} ${r} ${f.dim("Already running, skipping")}`);return}let s=`workermill-${e.id.slice(0,8)}`,a=["run","--rm",...!o.workerImage.includes("/")?[]:["--pull","always"],"--name",s],c=Math.round(Xe.totalmem()/(1024*1024*1024));if(c<=16?a.push("--memory","6g","--memory-swap","10g","--cpus","2"):(c<=32,a.push("--memory","6g","--memory-swap","12g","--cpus","4")),Jo){let I=Xo();a.push(`--add-host=host.docker.internal:${I||"host-gateway"}`)}else a.push("--network","host");let h=e.workerProvider||"anthropic",w=Zo();if(!w&&h==="anthropic"){console.error(`${D()} ${r} ${f.red("\u2717")} Claude credentials not found. Run 'claude' and complete the sign-in flow.`);return}if(w){let I=Ye.join(w,".credentials.json");try{ie.chmodSync(I,438)}catch{}let L=Qo(w);a.push("-v",`${L}:/home/worker/.claude`)}else console.log(`${D()} ${r} ${f.dim("Skipping Claude mount (non-Anthropic worker)")}`);let m=o.apiUrl.replace(/localhost|127\.0\.0\.1/,"host.docker.internal"),p=e.scmProvider||"github",P=tt(p,o,n),u=n?.githubToken||o.githubToken,$=p==="bitbucket"&&n?.scmToken||o.bitbucketToken,v=p==="gitlab"&&n?.scmToken||o.gitlabToken,k={NODE_OPTIONS:"--max-old-space-size=3072",EPIC_MODE:"true",EXECUTION_MODE:"local",TASK_ID:e.id,ORG_ID:e.orgId||"",JIRA_ISSUE_KEY:e.jiraIssueKey||"",JIRA_SUMMARY:e.summary||"",JIRA_DESCRIPTION:e.description||"",TASK_SUMMARY:e.summary||"",TASK_DESCRIPTION:e.description||"",WORKER_PERSONA:e.workerPersona||"",RETRY_NUMBER:String(e.retryCount??0),TICKET_KEY:e.jiraIssueKey||"",API_BASE_URL:m,ORG_API_KEY:o.apiKey,SCM_PROVIDER:p,SCM_TOKEN:P,SCM_BASE_URL:n?.scmBaseUrl||"",GITHUB_TOKEN:u,GH_TOKEN:u,GITHUB_REVIEWER_TOKEN:n?.githubReviewerToken||"",BITBUCKET_TOKEN:$,BITBUCKET_USERNAME:n?.bitbucketUsername||"x-token-auth",GITLAB_TOKEN:v,TARGET_REPO:e.githubRepo||"",GITHUB_REPO:e.githubRepo||"",WORKER_MODEL:e.workerModel||String(t.defaultWorkerModel||""),CLAUDE_MODEL:e.workerModel||String(t.defaultWorkerModel||""),JIRA_BASE_URL:n?.jiraBaseUrl||"",JIRA_EMAIL:n?.jiraEmail||"",JIRA_API_TOKEN:n?.jiraApiToken||"",TICKET_SYSTEM:n?.issueTrackerProvider||"jira",LINEAR_API_KEY:n?.linearApiKey||"",AWS_ACCESS_KEY_ID:n?.customerAwsAccessKeyId||"",AWS_SECRET_ACCESS_KEY:n?.customerAwsSecretAccessKey||"",AWS_DEFAULT_REGION:n?.customerAwsRegion||"",AWS_REGION:n?.customerAwsRegion||"",CUSTOMER_AWS_ROLE_ARN:n?.customerAwsRoleArn||"",CUSTOMER_AWS_EXTERNAL_ID:n?.customerAwsExternalId||"",CUSTOMER_AWS_REGION:n?.customerAwsRegion||"",MANAGER_PROVIDER:n?.managerProvider||"anthropic",MANAGER_MODEL:n?.managerModelId||"",BITBUCKET_EMAIL:n?.bitbucketEmail||"",DEPLOYMENT_ENABLED:e.deploymentEnabled||e.parentTaskId?"true":"false",PRD_CHILD_TASK:e.parentTaskId?"true":"false",IMPROVEMENT_ENABLED:e.improvementEnabled?"true":"false",QUALITY_GATE_BYPASS:e.qualityGateBypass?"true":"false",STANDARD_SDK_MODE:e.standardSdkMode?"true":"false",MAX_REVIEW_REVISIONS:String(t.maxReviewRevisions??3),MAX_PER_STORY_REVISIONS:String(t.maxPerStoryRevisions??2),CODEBASE_INDEXING_ENABLED:t.codebaseIndexingEnabled===!0?"true":"false",EXISTING_PR_URL:e.githubPrUrl||"",EXISTING_PR_NUMBER:e.githubPrNumber?String(e.githubPrNumber):"",PARENT_TASK_ID:e.parentTaskId||e.id,PARENT_JIRA_KEY:e.jiraIssueKey&&/-S\d+$/.test(e.jiraIssueKey)&&e.jiraFields?.parentJiraKey||"",TARGET_BRANCH:e.jiraFields?.targetBranch||"",STORY_BRANCH:e.jiraFields?.storyBranch||"",TASK_NOTES:e.taskNotes||"",TARGET_FILES:JSON.stringify(e.jiraFields?.targetFiles||[]),REFERENCE_FILES:JSON.stringify(e.jiraFields?.referenceFiles||[]),PIPELINE_VERSION:e.jiraFields?.pipelineVersion||e.pipelineVersion||"",V2_STEP_INPUT:e.jiraFields?.v2StepInput?JSON.stringify(e.jiraFields.v2StepInput):"",EXECUTION_MODE_SETTING:e.jiraFields?.executionMode||"autonomous",ANTHROPIC_API_KEY:w?"":n?.anthropicApiKey||process.env.ANTHROPIC_API_KEY||"",WORKER_PROVIDER:e.workerProvider||"anthropic",OPENAI_API_KEY:n?.openaiApiKey||"",GOOGLE_API_KEY:n?.googleApiKey||"",GOOGLE_GENERATIVE_AI_API_KEY:n?.googleApiKey||"",OLLAMA_HOST:n?.ollamaBaseUrl||"",OLLAMA_CONTEXT_WINDOW:n?.ollamaContextWindow?String(n.ollamaContextWindow):"",VLLM_BASE_URL:n?.vllmBaseUrl||"",BLOCKER_MAX_AUTO_RETRIES:String(t.blockerMaxAutoRetries??3),BLOCKER_AUTO_RETRY_ENABLED:t.blockerAutoRetryEnabled!==!1?"true":"false",PUSH_AFTER_COMMIT:t.pushAfterCommit!==!1?"true":"false",GRACEFUL_SHUTDOWN_ENABLED:t.gracefulShutdownEnabled!==!1?"true":"false",MAX_PARALLEL_EXPERTS:String(t.maxParallelExperts??4),REVIEW_ENABLED:e.skipManagerReview===!1?"true":"false",SELF_REVIEW_ENABLED:kn(e)||t.selfReviewEnabled!==!1?"true":"false"};for(let[I,L]of Object.entries(k))L!==""&&a.push("-e",`${I}=${L}`);let B=o.workerImage,l=et(B);l&&ot(l),a.push(B);let T=e.skipManagerReview===!1;console.log(`${D()} ${r} ${f.dim("Starting container")} ${f.yellow(s)}`),console.log(`${D()} ${r} ${f.dim(` skipManagerReview=${e.skipManagerReview} \u2192 REVIEW_ENABLED=${T}`)}`),console.log(`${D()} ${r} ${f.dim(` model=${e.workerModel} repo=${e.githubRepo}`)}`),console.log(`${D()} ${r} ${f.dim(` totalRamGB=${c} docker args:`)} ${a.slice(0,10).join(" ")}`);let R=Ho("docker",a,{stdio:["ignore","pipe","pipe"],detached:!1});if(!R.pid){console.error(`${D()} ${r} ${f.red("\u2717")} Failed to spawn container`);return}let N={taskId:e.id,containerName:s,process:R,startedAt:new Date,status:"running",resultEmitted:!1};J.set(e.id,N),R.stdout?.on("data",I=>{let L=I.toString().split(`
15
+ `).filter(V=>V.trim());for(let V of L)console.log(`${D()} ${r} ${f.dim(He(V))}`),V.includes("::result::")&&(N.resultEmitted=!0)}),R.stderr?.on("data",I=>{let L=I.toString().split(`
16
+ `).filter(V=>V.trim());for(let V of L)console.log(`${D()} ${r} ${f.red(He(V))}`)}),R.on("exit",I=>{N.status=I===0?"completed":"failed";let L=Math.round((Date.now()-N.startedAt.getTime())/1e3),V=I===0?f.green("\u2713"):f.red("\u2717"),q=I===0?f.green("completed"):f.red(`failed (exit ${I})`);console.log(`${D()} ${r} ${V} Container ${q} ${f.dim(`(${L}s)`)}`),N.resultEmitted||(console.log(`${D()} ${r} ${f.yellow("\u26A0")} No ::result:: marker seen \u2014 posting fallback completion in 15s`),setTimeout(async()=>{try{let x=I===0?"completed":"failed",ae=I!==0?`Worker container exited with code ${I} without reporting completion`:void 0;(await(await fetch(`${o.apiUrl}/api/tasks/${e.id}/worker-complete`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":o.apiKey},body:JSON.stringify({exitCode:I??1,result:x,errorMessage:ae})})).json()).status==="ignored"?console.log(`${D()} ${r} ${f.dim("Fallback completion ignored (task already transitioned)")}`):console.log(`${D()} ${r} ${f.yellow("\u26A0")} Fallback completion applied: ${x}`)}catch(x){console.error(`${D()} ${r} ${f.red("\u2717")} Fallback completion failed:`,x instanceof Error?x.message:x)}},15e3)),setTimeout(()=>J.delete(e.id),9e4)}),R.on("error",I=>{N.status="failed",console.error(`${D()} ${r} ${f.red("\u2717")} Container error: ${I.message}`)})}function ko(){return Array.from(J.values()).filter(e=>e.status==="running").length}function rt(){return Array.from(J.values()).filter(e=>e.status==="running").map(e=>e.taskId)}function st(e){let o=J.get(e);if(!o||o.status!=="running")return;let t=f.cyan(e.slice(0,8));console.log(`${D()} ${t} ${f.red("\u25A0")} Stopping container (cancelled by dashboard)`);try{Je(`docker stop ${o.containerName}`,{stdio:"ignore",timeout:15e3}),o.status="completed"}catch{}J.delete(e)}async function it(){console.log(`${D()} ${f.dim(`Stopping ${J.size} containers...`)}`);for(let[,e]of J)if(e.status==="running")try{Je(`docker stop ${e.containerName}`,{stdio:"ignore",timeout:15e3}),e.status="completed"}catch{}J.clear()}async function at(e,o,t){let n=f.cyan(e.id.slice(0,8)),r=`manager-${e.id}`;if(J.has(r))return;let s=`wm-manager-${e.id.slice(0,8)}-${Date.now()}`,i=Zo(),a=["run","--rm","--name",s,"--memory=4g","--cpus=2"];if(Jo){let l=Xo();a.push(`--add-host=host.docker.internal:${l||"host-gateway"}`)}else a.push("--network","host");if(i){let l=Qo(i);a.push("-v",`${l}:/home/worker/.claude`)}let c=o.apiUrl.replace(/localhost|127\.0\.0\.1/,"host.docker.internal"),h=e.scmProvider||"github",w=tt(h,o,t),m=t?.githubToken||o.githubToken,p=h==="bitbucket"&&t?.scmToken||o.bitbucketToken,P=h==="gitlab"&&t?.scmToken||o.gitlabToken,u={NODE_OPTIONS:"--max-old-space-size=3072",TASK_ID:e.id,MANAGER_ACTION:e.managerAction,JIRA_ISSUE_KEY:e.jiraIssueKey||"",JIRA_SUMMARY:e.summary||"",JIRA_DESCRIPTION:e.description||"",GITHUB_REPO:e.githubRepo||"",PR_URL:e.githubPrUrl||"",PR_NUMBER:e.githubPrNumber?String(e.githubPrNumber):"",API_BASE_URL:c,ORG_API_KEY:o.apiKey,SCM_PROVIDER:h,SCM_TOKEN:w,GITHUB_TOKEN:m,GH_TOKEN:m,BITBUCKET_TOKEN:p,BITBUCKET_USERNAME:t?.bitbucketUsername||"x-token-auth",GITLAB_TOKEN:P,MANAGER_PROVIDER:t?.managerProvider||"anthropic",MANAGER_MODEL:t?.managerModelId||"",ANTHROPIC_API_KEY:i?"":t?.anthropicApiKey||process.env.ANTHROPIC_API_KEY||"",OPENAI_API_KEY:t?.openaiApiKey||"",GOOGLE_API_KEY:t?.googleApiKey||"",JIRA_BASE_URL:t?.jiraBaseUrl||"",JIRA_EMAIL:t?.jiraEmail||"",JIRA_API_TOKEN:t?.jiraApiToken||"",TICKET_SYSTEM:t?.issueTrackerProvider||"jira",LINEAR_API_KEY:t?.linearApiKey||""};for(let[l,T]of Object.entries(u))T!==""&&a.push("-e",`${l}=${T}`);let $=o.workerImage,v=et($);v&&ot(v),a.push("--entrypoint","/bin/bash"),a.push($),a.push("/app/manager-entrypoint.sh"),console.log(`${D()} ${n} ${f.magenta("\u25C6 MANAGER")} Starting ${e.managerAction} container ${f.yellow(s)}`);let k=Ho("docker",a,{stdio:["ignore","pipe","pipe"],detached:!1});if(!k.pid){console.error(`${D()} ${n} ${f.red("\u2717")} Failed to spawn manager container`);return}let B={taskId:r,containerName:s,process:k,startedAt:new Date,status:"running",resultEmitted:!1};J.set(r,B),k.stdout?.on("data",l=>{let T=l.toString().split(`
17
+ `).filter(R=>R.trim());for(let R of T)console.log(`${D()} ${n} ${f.magenta("MGR")} ${f.dim(He(R))}`)}),k.stderr?.on("data",l=>{let T=l.toString().split(`
18
+ `).filter(R=>R.trim());for(let R of T)console.log(`${D()} ${n} ${f.magenta("MGR")} ${f.red(He(R))}`)}),k.on("exit",l=>{B.status=l===0?"completed":"failed";let T=Math.round((Date.now()-B.startedAt.getTime())/1e3),R=l===0?f.green("\u2713"):f.red("\u2717"),N=l===0?f.green("completed"):f.red(`failed (exit ${l})`);console.log(`${D()} ${n} ${f.magenta("MGR")} ${R} Manager ${e.managerAction} ${N} ${f.dim(`(${T}s)`)}`),setTimeout(()=>J.delete(r),6e4)}),k.on("error",l=>{B.status="failed",console.error(`${D()} ${n} ${f.magenta("MGR")} ${f.red("\u2717")} Container error: ${l.message}`)})}import{spawn as lt}from"child_process";import Ue from"chalk";async function Le(){return console.log(Ue.cyan(" Updating @workermill/agent...")),new Promise(e=>{let o=lt("npm",["install","-g","@workermill/agent@latest"],{stdio:"inherit",shell:!0});o.on("error",t=>{console.error(Ue.red(` Update failed: ${t.message}`)),e(!1)}),o.on("close",t=>{t===0?(console.log(Ue.green(" Update successful.")),e(!0)):(console.error(Ue.red(` Update failed with exit code ${t}`)),e(!1))})})}function Ze(){console.log(Ue.cyan(" Restarting agent...")),lt(process.argv[0],process.argv.slice(1),{stdio:"inherit",detached:!0}).unref(),process.exit(0)}var Se=new Set,Ce=new Set,eo=null,ct=!1,oo=!1;function W(){return S.dim(new Date().toLocaleTimeString())}async function An(){if(eo)return eo;try{return eo=(await O.get("/api/agent/config")).data,eo}catch{return console.error(`${W()} ${S.red("\u2717")} Failed to fetch org config`),{}}}async function ut(e){if(!oo)try{let o=await O.get("/api/agent/poll",{params:{agentId:e.agentId}}),t=o.data.tasks;if(t.length===0)return;for(let r of t)r.status==="planning"&&!Se.has(r.id)?await En(r,e):r.status==="queued"&&await Tn(r,e);let n=o.data.managerTasks;if(n&&n.length>0)for(let r of n)Ce.has(r.id)||await Sn(r,e)}catch(o){let t=o,n=Se.size>0||ko()>0||Ce.size>0;t.response?.status===401?n||console.error(`${W()} ${S.red("\u2717")} Authentication failed. Check your API key.`):n||console.warn(`${W()} ${S.yellow("\u26A0")} Poll error: ${t.message||String(o)}`)}}async function En(e,o){let t,n;try{let i=await O.post("/api/agent/claim",{taskId:e.id,agentId:o.agentId});if(!i.data.claimed)return;t=i.data.credentials,n=i.data.task}catch{return}let r=S.cyan(e.id.slice(0,8));if(n&&(n.retryCount??0)>0&&n.executionPlanV2!=null){console.log(),console.log(`${W()} ${S.magenta("\u25C6 RESUME")} ${r} ${e.summary.substring(0,60)}`),console.log(`${W()} ${r} Retry #${n.retryCount} with existing plan \u2014 skipping planning`),Se.add(e.id);try{await O.post("/api/agent/resume-plan",{taskId:e.id,agentId:o.agentId}),console.log(`${W()} ${r} ${S.green("\u2713")} Resumed with existing plan \u2192 ${S.green("queued")}`)}catch(i){let a=i,c=a.response?.data?.error||a.message||String(i);console.error(`${W()} ${r} ${S.red("\u2717")} Resume failed: ${c}`)}Se.delete(e.id);return}console.log(),console.log(`${W()} ${S.magenta("\u25C6 PLANNING")} ${r} ${e.summary.substring(0,60)}`),Se.add(e.id),qo(e,o,t).then(i=>{console.log(i?`${W()} ${S.green("\u2713")} Planning complete for ${r}`:`${W()} ${S.red("\u2717")} Planning failed for ${r}`)}).catch(i=>console.error(`${W()} ${S.red("\u2717")} Planning error for ${r}:`,i.message||i)).finally(()=>Se.delete(e.id))}async function Tn(e,o){if(ko()>=o.maxWorkers)return;let n;try{if(n=(await O.post("/api/agent/claim",{taskId:e.id,agentId:o.agentId})).data,!n.claimed)return}catch{return}try{await O.post("/api/agent/started",{taskId:e.id,agentId:o.agentId})}catch{let h=S.cyan(e.id.slice(0,8));console.warn(`${W()} ${S.yellow("\u26A0")} Failed to report started for ${h}`)}let r=S.cyan(e.id.slice(0,8));console.log(),console.log(`${W()} ${S.blue("\u25B6 EXECUTING")} ${r} ${e.summary.substring(0,60)}`);let s=await An(),i=n.task||{id:e.id,summary:e.summary,description:e.description,jiraIssueKey:e.jiraIssueKey,workerModel:e.workerModel,workerProvider:e.workerProvider,githubRepo:e.githubRepo,scmProvider:e.scmProvider,skipManagerReview:e.skipManagerReview,deploymentEnabled:e.deploymentEnabled,improvementEnabled:e.improvementEnabled,qualityGateBypass:e.qualityGateBypass,standardSdkMode:e.standardSdkMode,parentTaskId:e.parentTaskId,taskNotes:e.taskNotes,githubPrUrl:e.githubPrUrl,githubPrNumber:e.githubPrNumber,executionPlanV2:e.executionPlanV2,jiraFields:e.jiraFields||{}},a=n.credentials;nt(i,o,s,a).catch(c=>console.error(`${W()} ${S.red("\u2717")} Spawn failed for ${r}:`,c.message||c))}async function Sn(e,o){let t=S.cyan(e.id.slice(0,8));Ce.add(e.id);try{let n=await O.post("/api/agent/claim-manager",{taskId:e.id,agentId:o.agentId,action:e.managerAction});if(!n.data.claimed){Ce.delete(e.id);return}let r=n.data.task,s=n.data.credentials||{},i=e.managerAction==="analyze_logs"?S.yellow("LOG ANALYSIS"):S.yellow("PR REVIEW");console.log(),console.log(`${W()} ${S.magenta("\u25C6 MANAGER")} ${i} ${t} ${e.summary.substring(0,60)}`);let a={id:e.id,summary:r?.summary||e.summary,description:r?.description||e.description,jiraIssueKey:r?.jiraIssueKey||e.jiraIssueKey,githubRepo:r?.githubRepo||e.githubRepo,scmProvider:r?.scmProvider||e.scmProvider,githubPrUrl:r?.githubPrUrl||e.githubPrUrl,githubPrNumber:r?.githubPrNumber||e.githubPrNumber,managerAction:e.managerAction};at(a,o,s).then(()=>{console.log(`${W()} ${t} ${S.magenta("MGR")} ${S.green("\u2713")} Manager ${e.managerAction} dispatched`)}).catch(c=>{console.error(`${W()} ${t} ${S.magenta("MGR")} ${S.red("\u2717")} Manager spawn failed:`,c.message||c)}).finally(()=>Ce.delete(e.id))}catch(n){Ce.delete(e.id);let r=n;console.error(`${W()} ${t} ${S.red("\u2717")} Failed to claim manager task:`,r.message||String(n))}}var to=null,no=null;function dt(){to&&(clearInterval(to),to=null),no&&(clearInterval(no),no=null)}function gt(e){console.log(` ${S.dim("Polling every")} ${e.pollIntervalMs/1e3}s ${S.dim("\xB7 waiting for tasks...")}`),ut(e),to=setInterval(()=>ut(e),e.pollIntervalMs)}function pt(e){no=setInterval(async()=>{let o=rt(),t=Array.from(Se),n=Array.from(Ce),r=[...o,...t,...n];try{let s=await O.post("/api/agent/heartbeat",{agentId:e.agentId,activeTasks:r,agentVersion:z}),i=s.data?.cancelledTasks;if(i&&i.length>0)for(let w of i)st(w);let{updateAvailable:a,updateRequired:c,latestVersion:h}=s.data??{};c&&!oo?(oo=!0,console.log(`${W()} ${S.red("\u26A0 Agent update required")} (current: ${z}, required: ${h})`),console.log(`${W()} ${S.yellow("Refusing new tasks until updated.")}`),await Le()?Ze():(console.log(`${W()} ${S.red("Auto-update failed.")} Run: npm install -g @workermill/agent@latest`),oo=!1)):a&&!ct&&!c&&(ct=!0,console.log(`${W()} ${S.yellow(`Update available: ${h}`)} (current: ${z}). Run: workermill-agent update`))}catch{}},e.heartbeatIntervalMs)}oe();async function Ao(e){console.log(),console.log(K.bold.cyan(" WorkerMill Remote Agent")),console.log(K.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),Ve(e.apiUrl,e.apiKey);try{let o=await O.get("/api/agent/config"),t=o.data.maxConcurrentWorkers;t&&typeof t=="number"&&(e.maxWorkers=t),o.data.workerImageUrl&&(e.workerImage=o.data.workerImageUrl),console.log(` ${K.green("\u25CF")} Connected to ${K.cyan(e.apiUrl)}`),console.log(` ${K.dim("Agent:")} ${e.agentId}`),console.log(` ${K.dim("Workers:")} ${K.yellow(String(e.maxWorkers))} parallel`),console.log(` ${K.dim("Image:")} ${e.workerImage}`),console.log(` ${K.dim("SCM:")} ${o.data.scmProvider}`),console.log(` ${K.dim("Model:")} ${K.yellow(o.data.defaultWorkerModel)}`),console.log()}catch(o){let t=o;throw t.response?.status===401?new Error("Authentication failed. Check your API key."):new Error(`Failed to connect to WorkerMill API: ${t.message||String(o)}`)}try{let o=await O.post("/api/agent/register",{agentId:e.agentId,maxWorkers:e.maxWorkers,agentVersion:z}),{updateAvailable:t,updateRequired:n,latestVersion:r}=o.data;n?(console.log(K.red(` \u26A0 Agent update required (current: ${z}, required: ${r})`)),await Le()?Ze():console.log(K.yellow(" Auto-update failed. Run: npm install -g @workermill/agent@latest"))):t&&console.log(K.yellow(` Update available: ${r} (current: ${z}). Run: workermill-agent update`))}catch{}return gt(e),pt(e),console.log(K.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` ${K.green("\u25CF")} Agent is running. ${K.dim("Press Ctrl+C to stop.")}`),console.log(),async()=>{console.log(),console.log(K.dim(" Shutting down...")),dt();try{await O.post("/api/agent/deregister",{agentId:e.agentId})}catch{}await it(),console.log(` ${K.red("\u25CF")} Agent stopped.`)}}var Cn=typeof process<"u"&&process.argv[1]&&(process.argv[1].endsWith("/index.ts")||process.argv[1].endsWith("/index.js"));if(Cn){try{await import("dotenv/config")}catch{}let{loadConfig:e,validatePrerequisites:o}=await Promise.resolve().then(()=>(oe(),_o)),t=e();o(),console.log(K.dim(" Prerequisites validated."));let n=await Ao(t);process.on("SIGINT",async()=>{await n(),process.exit(0)}),process.on("SIGTERM",async()=>{await n(),process.exit(0)})}async function Eo(e){Pn(ee())||(console.log(U.red("No configuration found.")),console.log(`Run ${U.cyan("workermill-agent setup")} first.`),process.exit(1));let o=$e(),n=io(o.workerImage).filter(u=>!u.ok),r=n.find(u=>u.name==="Worker image"),s=new Set(["Claude CLI","Claude auth"]),i=n.filter(u=>u.name!=="Worker image"&&!s.has(u.name)),a=n.filter(u=>s.has(u.name));if(i.length>0){console.log(U.red("Prerequisites check failed:"));for(let u of i)console.log(U.red(` \u2717 ${u.name}: ${u.detail}`));process.exit(1)}if(a.length>0)for(let u of a)console.log(U.yellow(` \u26A0 ${u.name}: ${u.detail} (required for Anthropic provider)`));if(r){console.log(U.yellow(` Worker image not found locally. Pulling ${o.workerImage}...`));let{spawnSync:u}=await import("child_process");u("docker",["pull",o.workerImage],{stdio:"inherit",timeout:6e5}).status!==0&&(console.log(U.red(" Failed to pull worker image.")),process.exit(1)),console.log(U.green(" \u2713 Worker image pulled"))}if(e.detach){let u=xe(),$=le();console.log(U.dim("Starting agent in background...")),console.log(U.dim(` Logs: ${u}`)),console.log(U.dim(` PID: ${$}`));let v=xn(u,"a"),k=_n("workermill-agent",["start"],{detached:!0,stdio:["ignore",v,v],shell:!0});k.pid?(mt($,String(k.pid),"utf-8"),k.unref(),console.log(U.green(`Agent started (PID: ${k.pid})`)),console.log(`Check status with: ${U.cyan("workermill-agent status")}`)):(console.log(U.red("Failed to start agent in background.")),process.exit(1));return}let c=xe(),h=Mn(c,{flags:"a"}),w=process.stdout.write.bind(process.stdout),m=process.stderr.write.bind(process.stderr);process.stdout.write=(u,...$)=>(h.write(u),w(u,...$)),process.stderr.write=(u,...$)=>(h.write(u),m(u,...$)),console.log(),console.log(U.bold.cyan(" WorkerMill Remote Agent")),console.log(U.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log();let p=Math.round(Rn()/(1024*1024*1024));p<8?(console.log(U.red(` \u2717 Insufficient RAM: ${p} GB (minimum 8 GB, recommended 16 GB)`)),process.exit(1)):p<16&&console.log(U.yellow(` \u26A0 RAM: ${p} GB (below recommended 16 GB \u2014 workers may be slow)`));let P=Ge();console.log(U.dim(` Agent: ${o.agentId}`)),console.log(U.dim(` Version: ${z}`)),console.log(U.dim(` Image: ${o.workerImage}`)),console.log();try{let u=await Ao(o);mt(le(),String(process.pid),"utf-8");let $=!1,v=async()=>{$&&(console.log(U.red(`
19
+ Force exit.`)),process.exit(1)),$=!0;let k=setTimeout(()=>{console.log(U.red(`
20
+ Cleanup timed out. Force exit.`)),process.exit(1)},1e4);k.unref(),await u(),clearTimeout(k);try{vn(le())}catch{}process.exit(0)};process.on("SIGINT",v),process.on("SIGTERM",v)}catch(u){console.log(U.red(`Failed to start: ${u instanceof Error?u.message:String(u)}`)),process.exit(1)}}oe();import Re from"chalk";import{existsSync as On,readFileSync as Nn,unlinkSync as To}from"fs";async function ft(){let e=le();if(!On(e)){console.log(Re.yellow("No running agent found (no PID file).")),console.log(Re.dim(`Expected PID file at: ${e}`));return}let o=Nn(e,"utf-8").trim(),t=parseInt(o,10);if(isNaN(t)){console.log(Re.red(`Invalid PID in ${e}: ${o}`)),To(e);return}try{process.kill(t,0)}catch{console.log(Re.yellow(`Agent (PID ${t}) is not running. Cleaning up PID file.`)),To(e);return}console.log(Re.dim(`Stopping agent (PID ${t})...`));try{process.kill(t,"SIGTERM")}catch(r){console.log(Re.red(`Failed to stop agent: ${r instanceof Error?r.message:String(r)}`));return}let n=Date.now();for(;Date.now()-n<15e3;)try{process.kill(t,0),await new Promise(r=>setTimeout(r,500))}catch{break}try{To(e)}catch{}console.log(Re.green("Agent stopped."))}oe();import j from"chalk";import{existsSync as ht,readFileSync as Ln}from"fs";import{execSync as Fn}from"child_process";import Dn from"axios";async function $t(){if(console.log(),console.log(j.bold("WorkerMill Remote Agent Status")),console.log(j.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),!ht(ee())){console.log(j.yellow(" Not configured. Run 'workermill-agent setup' first."));return}let e=$e(),o=le(),t=!1,n=null;if(ht(o)){let s=Ln(o,"utf-8").trim();if(n=parseInt(s,10),!isNaN(n))try{process.kill(n,0),t=!0}catch{t=!1}}let r=t?j.green("\u25CF online"):j.red("\u25CF offline");console.log(` Status: ${r}${n?j.dim(` (PID ${n})`):""}`),console.log(` Agent ID: ${e.agentId}`),console.log(` API URL: ${e.apiUrl}`),console.log(` Max workers: ${e.maxWorkers}`),console.log(` Image: ${e.workerImage}`),console.log(),console.log(j.bold(" Active Containers"));try{let s=Fn('docker ps --filter "name=workermill-" --format "{{.Names}} {{.Status}} {{.RunningFor}}"',{encoding:"utf-8",timeout:1e4}).trim();if(s){let i=s.split(`
21
+ `);console.log(j.dim(` Found ${i.length} container(s):`));for(let a of i){let[c,h,w]=a.split(" ");console.log(` ${j.cyan(c)} ${h} ${j.dim(w||"")}`)}}else console.log(j.dim(" No active containers"))}catch{console.log(j.dim(" Could not query Docker"))}console.log(),console.log(j.bold(" API Connectivity"));try{let s=await Dn.get(`${e.apiUrl}/api/agent/config`,{headers:{"x-api-key":e.apiKey},timeout:1e4});console.log(` ${j.green("\u2713")} Connected to ${e.apiUrl}`),console.log(j.dim(` SCM: ${s.data.scmProvider}, Model: ${s.data.defaultWorkerModel}`))}catch(s){s.response?.status===401?console.log(` ${j.red("\u2717")} Authentication failed (invalid API key)`):console.log(` ${j.red("\u2717")} Cannot reach ${e.apiUrl}`)}console.log()}oe();import ro from"chalk";import{existsSync as Un,readFileSync as Wn,watchFile as Kn,statSync as wt,openSync as Gn,readSync as jn,closeSync as Bn}from"fs";async function yt(e){let o=xe();if(!Un(o)){console.log(ro.yellow("No log file found.")),console.log(ro.dim(`Expected at: ${o}`)),console.log(ro.dim("Start the agent with --detach to generate logs."));return}let t=parseInt(e.lines||"50",10),r=Wn(o,"utf-8").split(`
22
+ `),s=Math.max(0,r.length-t),i=r.slice(s).join(`
23
+ `);i.trim()&&(process.stdout.write(i),i.endsWith(`
23
24
  `)||process.stdout.write(`
24
- `)),console.log(oo.dim(`\u2500\u2500 Following ${o} (Ctrl+C to stop) \u2500\u2500`));let a=pt(o).size;Nn(o,{interval:500},()=>{try{let c=pt(o).size;if(c<=a){a=c;return}let h=On(o,"r"),w=Buffer.alloc(c-a);Ln(h,w,0,w.length,a),Fn(h),process.stdout.write(w.toString()),a=c}catch{}}),await new Promise(()=>{})}oe();import ne from"chalk";import{spawnSync as Dn,execSync as Un}from"child_process";import{existsSync as Wn}from"fs";function Kn(e){let o=e.match(/^(\d+\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com)/);return o?o[1]:null}async function ft(){Wn(ee())||(console.log(ne.red(" No config found. Run 'workermill-agent setup' first.")),process.exit(1));let e=he(),o=e.workerImage;try{Ge(e.apiUrl,e.apiKey);let{data:r}=await N.get("/api/agent/config");r.workerImageUrl&&(o=r.workerImageUrl)}catch{console.log(ne.yellow(" \u26A0 Could not fetch server config \u2014 using local image setting"))}let n=Kn(o);if(n){console.log(ne.dim(" Authenticating to private ECR..."));let r=n.match(/\.ecr\.([a-z0-9-]+)\.amazonaws\.com/),i=r?r[1]:"us-east-1";try{Un(`aws ecr get-login-password --region ${i} | docker login --username AWS --password-stdin ${n}`,{stdio:"pipe",timeout:3e4})}catch{console.log(ne.red(" \u2717 ECR authentication failed.")),console.log(ne.yellow(" Ensure AWS CLI is configured: aws configure")),process.exit(1)}}console.log(),console.log(ne.dim(` Pulling worker image: ${o}`)),console.log(ne.dim(" This may take a few minutes...")),console.log();let t=Dn("docker",["pull",o],{stdio:"inherit",timeout:6e5});console.log(),t.status===0?console.log(ne.green(" \u2713 Worker image updated")):(console.log(ne.red(" \u2717 Failed to pull worker image.")),t.error&&console.log(ne.yellow(` Error: ${t.error.message}`)),console.log(ne.yellow(" Is Docker Desktop running?")),process.exit(1))}import Fe from"chalk";async function ht(){console.log(),console.log(Fe.bold.cyan(" WorkerMill Agent Update")),console.log(Fe.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` ${Fe.dim("Current version:")} ${z}`),console.log(),await Me()?(console.log(),console.log(Fe.green(" Update complete. If the agent is running, restart it to use the new version."))):(console.log(),console.error(Fe.red(" Update failed. Try running manually: npm install -g @workermill/agent@latest")),process.exitCode=1)}oe();var ge=new jn;ge.name("workermill-agent").description("WorkerMill Remote Agent - Run AI workers locally with your Claude Max subscription").version(z);ge.command("setup").description("Interactive setup wizard - configure API key, validate prerequisites, pull worker image").action(ao);ge.command("start").description("Start the agent, polling the cloud API for tasks").option("--detach","Run in background (daemon mode)").action(ho);ge.command("stop").description("Stop the running agent").action(dt);ge.command("status").description("Show agent status, active containers, and API connectivity").action(gt);ge.command("logs").description("Live tail of agent logs (like tail -f)").option("-n, --lines <count>","Number of lines to show initially","50").action(mt);ge.command("pull").description("Pull the latest worker Docker image").action(ft);ge.command("update").description("Update the agent to the latest version").action(ht);process.argv.length<=2?Gn(ee())?ho({detach:!1}):ao():ge.parse();
25
+ `)),console.log(ro.dim(`\u2500\u2500 Following ${o} (Ctrl+C to stop) \u2500\u2500`));let a=wt(o).size;Kn(o,{interval:500},()=>{try{let c=wt(o).size;if(c<=a){a=c;return}let h=Gn(o,"r"),w=Buffer.alloc(c-a);jn(h,w,0,w.length,a),Bn(h),process.stdout.write(w.toString()),a=c}catch{}}),await new Promise(()=>{})}oe();import ne from"chalk";import{spawnSync as Vn,execSync as zn}from"child_process";import{existsSync as qn}from"fs";function Yn(e){let o=e.match(/^(\d+\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com)/);return o?o[1]:null}async function It(){qn(ee())||(console.log(ne.red(" No config found. Run 'workermill-agent setup' first.")),process.exit(1));let e=$e(),o=e.workerImage;try{Ve(e.apiUrl,e.apiKey);let{data:r}=await O.get("/api/agent/config");r.workerImageUrl&&(o=r.workerImageUrl)}catch{console.log(ne.yellow(" \u26A0 Could not fetch server config \u2014 using local image setting"))}let t=Yn(o);if(t){console.log(ne.dim(" Authenticating to private ECR..."));let r=t.match(/\.ecr\.([a-z0-9-]+)\.amazonaws\.com/),s=r?r[1]:"us-east-1";try{zn(`aws ecr get-login-password --region ${s} | docker login --username AWS --password-stdin ${t}`,{stdio:"pipe",timeout:3e4})}catch{console.log(ne.red(" \u2717 ECR authentication failed.")),console.log(ne.yellow(" Ensure AWS CLI is configured: aws configure")),process.exit(1)}}console.log(),console.log(ne.dim(` Pulling worker image: ${o}`)),console.log(ne.dim(" This may take a few minutes...")),console.log();let n=Vn("docker",["pull",o],{stdio:"inherit",timeout:6e5});console.log(),n.status===0?console.log(ne.green(" \u2713 Worker image updated")):(console.log(ne.red(" \u2717 Failed to pull worker image.")),n.error&&console.log(ne.yellow(` Error: ${n.error.message}`)),console.log(ne.yellow(" Is Docker Desktop running?")),process.exit(1))}import We from"chalk";async function bt(){console.log(),console.log(We.bold.cyan(" WorkerMill Agent Update")),console.log(We.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` ${We.dim("Current version:")} ${z}`),console.log(),await Le()?(console.log(),console.log(We.green(" Update complete. If the agent is running, restart it to use the new version."))):(console.log(),console.error(We.red(" Update failed. Try running manually: npm install -g @workermill/agent@latest")),process.exitCode=1)}oe();var de=new Jn;de.name("workermill-agent").description("WorkerMill Remote Agent - Run AI workers locally with your Claude Max subscription").version(z);de.command("setup").description("Interactive setup wizard - configure API key, validate prerequisites, pull worker image").action(uo);de.command("start").description("Start the agent, polling the cloud API for tasks").option("--detach","Run in background (daemon mode)").action(Eo);de.command("stop").description("Stop the running agent").action(ft);de.command("status").description("Show agent status, active containers, and API connectivity").action($t);de.command("logs").description("Live tail of agent logs (like tail -f)").option("-n, --lines <count>","Number of lines to show initially","50").action(yt);de.command("pull").description("Pull the latest worker Docker image").action(It);de.command("update").description("Update the agent to the latest version").action(bt);process.argv.length<=2?Hn(ee())?Eo({detach:!1}):uo():de.parse();
package/dist/index.js CHANGED
@@ -1,15 +1,16 @@
1
- var Ot=Object.defineProperty;var Nt=(e,t)=>()=>(e&&(t=e(e=0)),t);var Lt=(e,t)=>{for(var r in t)Ot(e,r,{get:t[r],enumerable:!0})};var He={};Lt(He,{checkPrerequisites:()=>Ht,findClaudePath:()=>ue,getConfigDir:()=>Wt,getConfigFile:()=>Vt,getLogFile:()=>zt,getPidFile:()=>Yt,getSystemInfo:()=>Je,loadConfig:()=>Ye,loadConfigFromFile:()=>Ve,saveConfigToFile:()=>Jt,validatePrerequisites:()=>ze});import{existsSync as we,readFileSync as Dt,mkdirSync as Ft,writeFileSync as Kt,chmodSync as jt}from"fs";import{execSync as ne}from"child_process";import{hostname as We,homedir as ge}from"os";import{join as H}from"path";function Wt(){return fe}function Vt(){return me}function Yt(){return Gt}function zt(){return Bt}function Ve(){we(me)||(console.error("No config found. Run 'workermill-agent setup' first."),process.exit(1));let e;try{e=Dt(me,"utf-8")}catch{console.error("Failed to read config file:",me),process.exit(1)}let t;try{t=JSON.parse(e)}catch{console.error("Config file is corrupted. Re-run 'workermill-agent setup'."),process.exit(1)}(!t.apiUrl||!t.apiKey)&&(console.error("Config file is missing required fields (apiUrl, apiKey). Re-run 'workermill-agent setup'."),process.exit(1));let r=t.workerImage||"workermill-worker:local";return{apiUrl:t.apiUrl,apiKey:t.apiKey,agentId:t.agentId,maxWorkers:t.maxWorkers||4,pollIntervalMs:t.pollIntervalMs||5e3,heartbeatIntervalMs:t.heartbeatIntervalMs||3e4,githubToken:t.tokens?.github||"",bitbucketToken:t.tokens?.bitbucket||"",gitlabToken:t.tokens?.gitlab||"",workerImage:r}}function Jt(e){we(fe)||Ft(fe,{recursive:!0}),Kt(me,JSON.stringify(e,null,2),"utf-8");try{jt(me,384)}catch{}}function Ye(){let e=process.env.WORKERMILL_API_URL,t=process.env.WORKERMILL_API_KEY;return e||(console.error("WORKERMILL_API_URL is required in .env.remote"),process.exit(1)),t||(console.error("WORKERMILL_API_KEY is required in .env.remote"),console.error("Get your API key from Settings > Integrations on the WorkerMill dashboard."),process.exit(1)),{apiUrl:e.replace(/\/$/,""),apiKey:t,agentId:process.env.AGENT_ID||`agent-${We()}`,maxWorkers:parseInt(process.env.MAX_WORKERS||"4",10),pollIntervalMs:parseInt(process.env.POLL_INTERVAL_MS||"5000",10),heartbeatIntervalMs:parseInt(process.env.HEARTBEAT_INTERVAL_MS||"30000",10),githubToken:process.env.GITHUB_TOKEN||"",bitbucketToken:process.env.BITBUCKET_TOKEN||"",gitlabToken:process.env.GITLAB_TOKEN||"",workerImage:process.env.WORKER_IMAGE||"workermill-worker:local"}}function ue(){let e=process.platform==="win32",t=e?"where":"which";try{return ne(`${t} claude`,{stdio:"ignore",timeout:1e4}),"claude"}catch{}let r=[];e?r.push(H(process.env.ProgramFiles||"C:\\Program Files","ClaudeCode","claude.exe"),H(process.env.LOCALAPPDATA||"","Programs","ClaudeCode","claude.exe"),H(ge(),"AppData","Local","Programs","ClaudeCode","claude.exe"),H(ge(),".local","bin","claude.exe")):r.push(H(ge(),".local","bin","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude");for(let o of r)if(o&&we(o))return o;return null}function Ht(e){let t=[],r=e||"workermill-worker:local";try{let l=ne("docker version --format {{.Server.Version}}",{encoding:"utf-8",timeout:1e4}).trim();t.push({name:"Docker",ok:!0,detail:l})}catch{t.push({name:"Docker",ok:!1,detail:"Not running or not installed"})}let o=ue();if(o)try{let l=ne(`"${o}" --version`,{encoding:"utf-8",timeout:1e4}).trim();t.push({name:"Claude CLI",ok:!0,detail:l})}catch{t.push({name:"Claude CLI",ok:!0,detail:o})}else t.push({name:"Claude CLI",ok:!1,detail:"Not installed"});let n=ge(),i=H(n,".claude",".credentials.json");we(i)?t.push({name:"Claude auth",ok:!0,detail:"Credentials found"}):t.push({name:"Claude auth",ok:!1,detail:"Run 'claude' and complete sign-in"});let s=process.version;parseInt(s.slice(1).split(".")[0],10)>=20?t.push({name:"Node.js",ok:!0,detail:s}):t.push({name:"Node.js",ok:!1,detail:`${s} (need >= 20)`});try{ne(`docker image inspect ${r}`,{stdio:"ignore",timeout:1e4}),t.push({name:"Worker image",ok:!0,detail:r})}catch{t.push({name:"Worker image",ok:!1,detail:`'${r}' not found`})}return t}function ze(){try{ne("docker version",{stdio:"ignore"})}catch{console.error("Docker is not available. Please install Docker and ensure it's running."),process.exit(1)}let e=process.env.WORKER_IMAGE||"workermill-worker:local";try{ne(`docker image inspect ${e}`,{stdio:"ignore"})}catch{console.error(`Worker image '${e}' not found.`),console.error(e==="workermill-worker:local"?"Build it with: ./bin/local-workermill build-worker":`Pull it with: docker pull ${e}`),process.exit(1)}ue()||(console.error("Claude CLI is not installed."),console.error("Install it: curl -fsSL https://claude.ai/install.sh | bash"),process.exit(1));let t=ge(),r=H(t,".claude",".credentials.json");we(r)||(console.error("Claude credentials not found."),console.error("Run 'claude' and complete the sign-in flow to authenticate."),process.exit(1))}function Je(){let e="unknown";try{e=ne("docker version --format {{.Server.Version}}",{encoding:"utf-8",timeout:1e4}).trim()}catch{}let t="unknown",r=ue();if(r)try{t=ne(`"${r}" --version`,{encoding:"utf-8",timeout:1e4}).trim()}catch{}return{hostname:We(),platform:process.platform,nodeVersion:process.version,dockerVersion:e,claudeVersion:t}}var fe,me,Gt,Bt,be=Nt(()=>{"use strict";fe=H(ge(),".workermill"),me=H(fe,"config.json"),Gt=H(fe,"agent.pid"),Bt=H(fe,"agent.log")});import U from"chalk";import Ut from"axios";var Ue=null;function Be(e,t){Ue=Ut.create({baseURL:e,headers:{"Content-Type":"application/json","x-api-key":t},timeout:3e4})}var M=new Proxy({},{get(e,t){if(!Ue)throw new Error("API client not initialized. Call initApi() first.");return Ue[t]}});import y from"chalk";be();import c from"chalk";import{spawn as yo,execSync as je}from"child_process";import{spawn as oo}from"child_process";import se from"chalk";import Ae from"axios";var qt=16384,Xt=6e5;async function qe(e,t,r,o,n){let i=n?.maxTokens??qt,s=n?.temperature??.7,a=n?.timeoutMs??Xt;switch(e){case"anthropic":return Qt(t,r,o,i,s,a);case"openai":return Zt(t,r,o,i,s,a);case"google":return eo(t,r,o,i,s,a);case"ollama":return to(t,r,o,i,s,a);default:throw new Error(`Unsupported AI provider: ${e}`)}}async function Qt(e,t,r,o,n,i){let a=(await Ae.post("https://api.anthropic.com/v1/messages",{model:e,max_tokens:o,temperature:n,messages:[{role:"user",content:t}]},{headers:{"x-api-key":r,"anthropic-version":"2023-06-01","Content-Type":"application/json"},timeout:i})).data?.content;if(Array.isArray(a))return a.filter(l=>l.type==="text").map(l=>l.text).join("");throw new Error("Unexpected Anthropic API response format")}async function Zt(e,t,r,o,n,i){let a=(await Ae.post("https://api.openai.com/v1/chat/completions",{model:e,max_tokens:o,temperature:n,messages:[{role:"user",content:t}]},{headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"},timeout:i})).data?.choices?.[0]?.message;if(a?.content)return a.content;throw new Error("Unexpected OpenAI API response format")}async function eo(e,t,r,o,n,i){let l=(await Ae.post(`https://generativelanguage.googleapis.com/v1beta/models/${e}:generateContent?key=${r}`,{contents:[{parts:[{text:t}]}],generationConfig:{maxOutputTokens:o,temperature:n}},{headers:{"Content-Type":"application/json"},timeout:i})).data?.candidates?.[0]?.content?.parts?.[0]?.text;if(l)return l;throw new Error("Unexpected Google AI API response format")}async function to(e,t,r,o,n,i){let s=r||"http://localhost:11434",l=(await Ae.post(`${s}/api/generate`,{model:e,prompt:t,stream:!1,options:{temperature:n}},{headers:{"Content-Type":"application/json"},timeout:i})).data?.response;if(l)return l;throw new Error("Unexpected Ollama API response format")}var ie=null;async function Qe(e){if(ie)return ie;try{let t={};e!==void 0&&(t.maxTargetFiles=String(e));let{data:r}=await M.get("/api/agent/critic-prompt",{params:t});return ie={promptTemplate:r.promptTemplate,approvalThreshold:r.approvalThreshold??85,maxTargetFiles:r.maxTargetFiles??e??5},q=ie.approvalThreshold,$e=ie.maxTargetFiles,ie}catch{return console.warn("Failed to fetch critic config from API"),null}}var $e=5,q=85;function Ze(e){let t=e.indexOf("```json");if(t!==-1){let o=t+7,n=e.indexOf("{",o);if(n!==-1){let i=Xe(e,n);if(i)return JSON.parse(i)}}let r=e.indexOf('"stories"');if(r!==-1){let n=e.substring(0,r).lastIndexOf("{");if(n!==-1){let i=Xe(e,n);if(i)return JSON.parse(i)}}throw new Error("Could not find JSON execution plan in output")}function Xe(e,t){let r=0,o=!1,n=!1;for(let i=t;i<e.length;i++){let s=e[i];if(n){n=!1;continue}if(s==="\\"){o&&(n=!0);continue}if(s==='"'){o=!o;continue}if(!o){if(s==="{")r++;else if(s==="}"&&(r--,r===0))return e.substring(t,i+1)}}return null}function et(e){let t=0,r=[];for(let o of e.stories)if(!o.targetFiles||!Array.isArray(o.targetFiles))o.targetFiles=[];else if(o.targetFiles.length>$e){let n=o.targetFiles.slice($e);r.push(`${o.id}: ${o.targetFiles.length} files \u2192 ${$e} (dropped: ${n.join(", ")})`),o.targetFiles=o.targetFiles.slice(0,$e),t++}return{truncatedCount:t,details:r}}function tt(e,t){if(e.stories.length<=t)return{droppedCount:0,details:[]};let r=e.stories.length-t,n=e.stories.slice(t).map(s=>`${s.id}: "${s.title}" (${s.persona})`);e.stories=e.stories.slice(0,t);let i=new Set(e.stories.map(s=>s.id));for(let s of e.stories)s.dependencies=s.dependencies.filter(a=>i.has(a));return{droppedCount:r,details:n}}function ot(e){let t=new Map,r=0,o=[];for(let n of e.stories){if(!n.targetFiles||n.targetFiles.length===0)continue;let i=[],s=[];for(let a of n.targetFiles)t.get(a)?s.push(a):(t.set(a,n.id),i.push(a));s.length>0&&(n.targetFiles=i,r+=s.length,o.push(`${n.id}: removed ${s.join(", ")} (owned by ${s.map(a=>t.get(a)).join(", ")})`))}return{resolvedCount:r,details:o}}function rt(e){return"```json\n"+JSON.stringify(e,null,2)+"\n```"}function ro(e,t){if(!ie)return null;let r=JSON.stringify(t,null,2);return ie.promptTemplate.replace("{{PRD}}",e).replace("{{PLAN}}",r)}function no(e){let t=e.trim();if(t.includes("```")){let n=t.match(/```(?:json)?\s*([\s\S]*?)```/);n&&(t=n[1].trim())}let r=t.indexOf("{");r>0&&(t=t.substring(r));let o=JSON.parse(t);return{approved:o.approved,score:Math.max(0,Math.min(100,Math.round(o.score))),risks:o.risks||[],suggestions:o.suggestions,storyFeedback:Array.isArray(o.storyFeedback)?o.storyFeedback:void 0}}function io(e,t,r,o,n){return new Promise((i,s)=>{let a=oo(e,["--print","--model",t,"--permission-mode","bypassPermissions"],{env:o,stdio:["pipe","pipe","pipe"]});a.stdin.write(r),a.stdin.end();let l="",I="";a.stdout.on("data",p=>{let m=p.toString();l+=m;let k=m.split(`
2
- `).filter(N=>N.trim());for(let N of k){let R=N.trim().length>200?N.trim().substring(0,200)+"\u2026":N.trim();R&&(n&&st(n,`${it} [critic] ${R}`,"output"),console.log(`${Ee()} ${se.dim("\u{1F50D}")} ${se.dim(R)}`))}}),a.stderr.on("data",p=>{I+=p.toString()});let b=setTimeout(()=>{a.kill("SIGTERM"),s(new Error("Critic CLI timed out after 20 minutes"))},12e5);a.on("exit",p=>{clearTimeout(b),p!==0?s(new Error(`Critic CLI failed (exit ${p}): ${I.substring(0,300)}`)):i(l)}),a.on("error",p=>{clearTimeout(b),s(p)})})}function nt(e){let t=["","## CRITIC FEEDBACK \u2014 Your previous plan was REJECTED","",`Score: ${e.score}/100 (need >= ${q} to pass)`,""];if(e.risks.length>0){t.push("### Risks Identified:");for(let r of e.risks)t.push(`- ${r}`);t.push("")}if(e.suggestions&&e.suggestions.length>0){t.push("### Required Changes:");for(let r of e.suggestions)t.push(`- ${r}`);t.push("")}if(e.storyFeedback&&e.storyFeedback.length>0){t.push("### Per-Story Feedback:");for(let r of e.storyFeedback)if(t.push(`- **${r.storyId}**: ${r.feedback}`),r.suggestedChanges)for(let o of r.suggestedChanges)t.push(` - ${o}`);t.push("")}return t.push(`**You MUST address ALL feedback above.** Each story must target at most ${$e} files.`,"Stories MUST NOT overlap on targetFiles.","","**CRITICAL \u2014 OUTPUT FORMAT:** You MUST output a revised plan as a ```json code block containing the full JSON object with `summary`, `stories`, `risks`, and `assumptions` fields. Do NOT just describe what you would change \u2014 output the COMPLETE revised JSON plan. If you do not output a ```json block, the plan will fail to parse and the task will fail.","","**DO NOT re-explore the repository.** You already explored it in the previous attempt. Go directly to outputting the revised ```json plan. Every tool call wastes output budget \u2014 prioritize emitting the JSON plan."),t.join(`
3
- `)}var it="[\u{1F5FA}\uFE0F planning_agent \u{1F916}]";function Ee(){return se.dim(new Date().toLocaleTimeString())}async function st(e,t,r="system",o="info"){try{await M.post("/api/control-center/logs",{taskId:e,type:r,message:t,severity:o})}catch{}}async function at(e,t,r,o,n,i,s,a,l){let I=ro(r,o);if(!I)return console.warn(`${Ee()} ${i} ${se.yellow("\u26A0")} Critic config not available \u2014 skipping validation`),null;let b=s||"anthropic";console.log(`${Ee()} ${i} ${se.dim(`Running critic validation (${b})...`)}`),l&&st(l,`${it} Running critic validation (${b})...`);try{let p;if(b==="anthropic")p=await io(e,t,I,n,l);else{if(!a)throw new Error(`No API key for critic provider "${b}"`);p=await qe(b,t,I,a,{maxTokens:4096,temperature:.3,timeoutMs:12e5})}let m=no(p),k=m.score>=q?se.green("\u2713"):se.red("\u2717");return console.log(`${Ee()} ${i} ${k} Critic score: ${m.score}/100 (threshold: ${q})`),m}catch(p){let m=p instanceof Error?p.message:String(p);return console.error(`${Ee()} ${i} ${se.yellow("\u26A0")} Critic failed: ${m.substring(0,100)}`),null}}import{generateText as so,tool as De,stepCountIs as ao}from"ai";import{createOpenAI as lt}from"@ai-sdk/openai";import{createAnthropic as lo}from"@ai-sdk/anthropic";import{createGoogleGenerativeAI as co}from"@ai-sdk/google";import{z as ae}from"zod";import{execSync as Fe}from"child_process";import{readFileSync as uo,existsSync as po}from"fs";function go(e,t,r){switch(e){case"anthropic":return lo({apiKey:r})(t);case"openai":return lt({apiKey:r})(t);case"google":return co({apiKey:r})(t);case"ollama":return lt({baseURL:r||"http://localhost:11434/v1",apiKey:"ollama"})(t);default:throw new Error(`Unsupported AI provider: ${e}`)}}var mo=ae.object({pattern:ae.string().describe("Glob pattern like '**/*.ts', 'src/**/*.js', 'package.json'")}),fo=ae.object({path:ae.string().describe("File path relative to the working directory"),limit:ae.number().optional().describe("Max number of lines to read (default: 500)")}),$o=ae.object({pattern:ae.string().describe("Search pattern (regex supported)"),glob:ae.string().optional().describe("File glob to filter (e.g. '*.ts', '*.py')")});function ho(e){return{glob:De({description:"Find files matching a glob pattern. Returns file paths relative to the working directory.",inputSchema:mo,execute:async t=>{try{let r=Fe(`find . -path './.git' -prune -o -path './node_modules' -prune -o -name '${t.pattern.replace(/\*\*/g,"*")}' -print 2>/dev/null | head -200`,{cwd:e,encoding:"utf-8",timeout:15e3}).trim();return r||Fe("find . -path './.git' -prune -o -path './node_modules' -prune -o -type f -print 2>/dev/null | head -500",{cwd:e,encoding:"utf-8",timeout:15e3}).trim()||"No files found"}catch{return"Error running glob search"}}}),read_file:De({description:"Read the contents of a file. Returns the file text.",inputSchema:fo,execute:async t=>{try{let r=`${e}/${t.path}`.replace(/\/\//g,"/");if(!po(r))return`File not found: ${t.path}`;let o=uo(r,"utf-8"),n=o.split(`
4
- `),i=t.limit||500;return n.length>i?n.slice(0,i).join(`
1
+ var Gt=Object.defineProperty;var Bt=(e,t)=>()=>(e&&(t=e(e=0)),t);var Wt=(e,t)=>{for(var n in t)Gt(e,n,{get:t[n],enumerable:!0})};var nt={};Wt(nt,{checkPrerequisites:()=>no,findClaudePath:()=>ge,getConfigDir:()=>Qt,getConfigFile:()=>Zt,getLogFile:()=>to,getPidFile:()=>eo,getSystemInfo:()=>ot,loadConfig:()=>et,loadConfigFromFile:()=>Ze,saveConfigToFile:()=>oo,validatePrerequisites:()=>tt});import{existsSync as Ee,readFileSync as Yt,mkdirSync as zt,writeFileSync as Jt,chmodSync as Ht}from"fs";import{execSync as se}from"child_process";import{hostname as Qe,homedir as he}from"os";import{join as H}from"path";function Qt(){return we}function Zt(){return ye}function eo(){return qt}function to(){return Xt}function Ze(){Ee(ye)||(console.error("No config found. Run 'workermill-agent setup' first."),process.exit(1));let e;try{e=Yt(ye,"utf-8")}catch{console.error("Failed to read config file:",ye),process.exit(1)}let t;try{t=JSON.parse(e)}catch{console.error("Config file is corrupted. Re-run 'workermill-agent setup'."),process.exit(1)}(!t.apiUrl||!t.apiKey)&&(console.error("Config file is missing required fields (apiUrl, apiKey). Re-run 'workermill-agent setup'."),process.exit(1));let n=t.workerImage||"workermill-worker:local";return{apiUrl:t.apiUrl,apiKey:t.apiKey,agentId:t.agentId,maxWorkers:t.maxWorkers||4,pollIntervalMs:t.pollIntervalMs||5e3,heartbeatIntervalMs:t.heartbeatIntervalMs||3e4,githubToken:t.tokens?.github||"",bitbucketToken:t.tokens?.bitbucket||"",gitlabToken:t.tokens?.gitlab||"",workerImage:n}}function oo(e){Ee(we)||zt(we,{recursive:!0}),Jt(ye,JSON.stringify(e,null,2),"utf-8");try{Ht(ye,384)}catch{}}function et(){let e=process.env.WORKERMILL_API_URL,t=process.env.WORKERMILL_API_KEY;return e||(console.error("WORKERMILL_API_URL is required in .env.remote"),process.exit(1)),t||(console.error("WORKERMILL_API_KEY is required in .env.remote"),console.error("Get your API key from Settings > Integrations on the WorkerMill dashboard."),process.exit(1)),{apiUrl:e.replace(/\/$/,""),apiKey:t,agentId:process.env.AGENT_ID||`agent-${Qe()}`,maxWorkers:parseInt(process.env.MAX_WORKERS||"4",10),pollIntervalMs:parseInt(process.env.POLL_INTERVAL_MS||"5000",10),heartbeatIntervalMs:parseInt(process.env.HEARTBEAT_INTERVAL_MS||"30000",10),githubToken:process.env.GITHUB_TOKEN||"",bitbucketToken:process.env.BITBUCKET_TOKEN||"",gitlabToken:process.env.GITLAB_TOKEN||"",workerImage:process.env.WORKER_IMAGE||"workermill-worker:local"}}function ge(){let e=process.platform==="win32",t=e?"where":"which";try{return se(`${t} claude`,{stdio:"ignore",timeout:1e4}),"claude"}catch{}let n=[];e?n.push(H(process.env.ProgramFiles||"C:\\Program Files","ClaudeCode","claude.exe"),H(process.env.LOCALAPPDATA||"","Programs","ClaudeCode","claude.exe"),H(he(),"AppData","Local","Programs","ClaudeCode","claude.exe"),H(he(),".local","bin","claude.exe")):n.push(H(he(),".local","bin","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude");for(let o of n)if(o&&Ee(o))return o;return null}function no(e){let t=[],n=e||"workermill-worker:local";try{let c=se("docker version --format {{.Server.Version}}",{encoding:"utf-8",timeout:1e4}).trim();t.push({name:"Docker",ok:!0,detail:c})}catch{t.push({name:"Docker",ok:!1,detail:"Not running or not installed"})}let o=ge();if(o)try{let c=se(`"${o}" --version`,{encoding:"utf-8",timeout:1e4}).trim();t.push({name:"Claude CLI",ok:!0,detail:c})}catch{t.push({name:"Claude CLI",ok:!0,detail:o})}else t.push({name:"Claude CLI",ok:!1,detail:"Not installed"});let r=he(),s=H(r,".claude",".credentials.json");Ee(s)?t.push({name:"Claude auth",ok:!0,detail:"Credentials found"}):t.push({name:"Claude auth",ok:!1,detail:"Run 'claude' and complete sign-in"});let i=process.version;parseInt(i.slice(1).split(".")[0],10)>=20?t.push({name:"Node.js",ok:!0,detail:i}):t.push({name:"Node.js",ok:!1,detail:`${i} (need >= 20)`});try{se(`docker image inspect ${n}`,{stdio:"ignore",timeout:1e4}),t.push({name:"Worker image",ok:!0,detail:n})}catch{t.push({name:"Worker image",ok:!1,detail:`'${n}' not found`})}return t}function tt(){try{se("docker version",{stdio:"ignore"})}catch{console.error("Docker is not available. Please install Docker and ensure it's running."),process.exit(1)}let e=process.env.WORKER_IMAGE||"workermill-worker:local";try{se(`docker image inspect ${e}`,{stdio:"ignore"})}catch{console.error(`Worker image '${e}' not found.`),console.error(e==="workermill-worker:local"?"Build it with: ./bin/local-workermill build-worker":`Pull it with: docker pull ${e}`),process.exit(1)}ge()||(console.error("Claude CLI is not installed."),console.error("Install it: curl -fsSL https://claude.ai/install.sh | bash"),process.exit(1));let t=he(),n=H(t,".claude",".credentials.json");Ee(n)||(console.error("Claude credentials not found."),console.error("Run 'claude' and complete the sign-in flow to authenticate."),process.exit(1))}function ot(){let e="unknown";try{e=se("docker version --format {{.Server.Version}}",{encoding:"utf-8",timeout:1e4}).trim()}catch{}let t="unknown",n=ge();if(n)try{t=se(`"${n}" --version`,{encoding:"utf-8",timeout:1e4}).trim()}catch{}return{hostname:Qe(),platform:process.platform,nodeVersion:process.version,dockerVersion:e,claudeVersion:t}}var we,ye,qt,Xt,Re=Bt(()=>{"use strict";we=H(he(),".workermill"),ye=H(we,"config.json"),qt=H(we,"agent.pid"),Xt=H(we,"agent.log")});import D from"chalk";import Vt from"axios";var Ke=null;function Xe(e,t){Ke=Vt.create({baseURL:e,headers:{"Content-Type":"application/json","x-api-key":t},timeout:3e4})}var O=new Proxy({},{get(e,t){if(!Ke)throw new Error("API client not initialized. Call initApi() first.");return Ke[t]}});import w from"chalk";Re();import l from"chalk";import{spawn as Ro,execSync as He}from"child_process";import{spawn as uo}from"child_process";import ae from"chalk";import Se from"axios";var ro=16384,so=6e5;async function rt(e,t,n,o,r){let s=r?.maxTokens??ro,i=r?.temperature??.7,a=r?.timeoutMs??so;switch(e){case"anthropic":return io(t,n,o,s,i,a);case"openai":return ao(t,n,o,s,i,a);case"google":return lo(t,n,o,s,i,a);case"ollama":return co(t,n,o,s,i,a);default:throw new Error(`Unsupported AI provider: ${e}`)}}async function io(e,t,n,o,r,s){let a=(await Se.post("https://api.anthropic.com/v1/messages",{model:e,max_tokens:o,temperature:r,messages:[{role:"user",content:t}]},{headers:{"x-api-key":n,"anthropic-version":"2023-06-01","Content-Type":"application/json"},timeout:s})).data?.content;if(Array.isArray(a))return a.filter(c=>c.type==="text").map(c=>c.text).join("");throw new Error("Unexpected Anthropic API response format")}async function ao(e,t,n,o,r,s){let a=(await Se.post("https://api.openai.com/v1/chat/completions",{model:e,max_tokens:o,temperature:r,messages:[{role:"user",content:t}]},{headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},timeout:s})).data?.choices?.[0]?.message;if(a?.content)return a.content;throw new Error("Unexpected OpenAI API response format")}async function lo(e,t,n,o,r,s){let c=(await Se.post(`https://generativelanguage.googleapis.com/v1beta/models/${e}:generateContent?key=${n}`,{contents:[{parts:[{text:t}]}],generationConfig:{maxOutputTokens:o,temperature:r}},{headers:{"Content-Type":"application/json"},timeout:s})).data?.candidates?.[0]?.content?.parts?.[0]?.text;if(c)return c;throw new Error("Unexpected Google AI API response format")}async function co(e,t,n,o,r,s){let i=n||"http://localhost:11434",c=(await Se.post(`${i}/api/generate`,{model:e,prompt:t,stream:!1,options:{temperature:r}},{headers:{"Content-Type":"application/json"},timeout:s})).data?.response;if(c)return c;throw new Error("Unexpected Ollama API response format")}var ie=null;async function it(e){if(ie)return ie;try{let t={};e!==void 0&&(t.maxTargetFiles=String(e));let{data:n}=await O.get("/api/agent/critic-prompt",{params:t});return ie={promptTemplate:n.promptTemplate,approvalThreshold:n.approvalThreshold??85,maxTargetFiles:n.maxTargetFiles??e??5},q=ie.approvalThreshold,me=ie.maxTargetFiles,ie}catch{return console.warn("Failed to fetch critic config from API"),null}}var me=5,q=85;function je(e){let t=e.indexOf("```json");if(t!==-1){let o=t+7,r=e.indexOf("{",o);if(r!==-1){let s=st(e,r);if(s)return JSON.parse(s)}}let n=e.indexOf('"stories"');if(n!==-1){let r=e.substring(0,n).lastIndexOf("{");if(r!==-1){let s=st(e,r);if(s)return JSON.parse(s)}}throw new Error("Could not find JSON execution plan in output")}function st(e,t){let n=0,o=!1,r=!1;for(let s=t;s<e.length;s++){let i=e[s];if(r){r=!1;continue}if(i==="\\"){o&&(r=!0);continue}if(i==='"'){o=!o;continue}if(!o){if(i==="{")n++;else if(i==="}"&&(n--,n===0))return e.substring(t,s+1)}}return null}function Ge(e){let t=0,n=[];for(let o of e.stories)if(!o.targetFiles||!Array.isArray(o.targetFiles))o.targetFiles=[];else if(o.targetFiles.length>me){let r=o.targetFiles.slice(me);n.push(`${o.id}: ${o.targetFiles.length} files \u2192 ${me} (dropped: ${r.join(", ")})`),o.targetFiles=o.targetFiles.slice(0,me),t++}return{truncatedCount:t,details:n}}function Be(e,t){if(e.stories.length<=t)return{droppedCount:0,details:[]};let n=e.stories.length-t,r=e.stories.slice(t).map(i=>`${i.id}: "${i.title}" (${i.persona})`);e.stories=e.stories.slice(0,t);let s=new Set(e.stories.map(i=>i.id));for(let i of e.stories)i.dependencies=i.dependencies.filter(a=>s.has(a));return{droppedCount:n,details:r}}function We(e){let t=new Map,n=0,o=[];for(let r of e.stories){if(!r.targetFiles||r.targetFiles.length===0)continue;let s=[],i=[];for(let a of r.targetFiles)t.get(a)?i.push(a):(t.set(a,r.id),s.push(a));i.length>0&&(r.targetFiles=s,n+=i.length,o.push(`${r.id}: removed ${i.join(", ")} (owned by ${i.map(a=>t.get(a)).join(", ")})`))}return{resolvedCount:n,details:o}}function at(e){return"```json\n"+JSON.stringify(e,null,2)+"\n```"}function po(e,t){if(!ie)return null;let n=JSON.stringify(t,null,2);return ie.promptTemplate.replace("{{PRD}}",e).replace("{{PLAN}}",n)}function go(e){let t=e.trim();if(t.includes("```")){let r=t.match(/```(?:json)?\s*([\s\S]*?)```/);r&&(t=r[1].trim())}let n=t.indexOf("{");n>0&&(t=t.substring(n));let o=JSON.parse(t);return{approved:o.approved,score:Math.max(0,Math.min(100,Math.round(o.score))),risks:o.risks||[],suggestions:o.suggestions,storyFeedback:Array.isArray(o.storyFeedback)?o.storyFeedback:void 0}}function mo(e,t,n,o,r){return new Promise((s,i)=>{let a=uo(e,["--print","--model",t,"--permission-mode","bypassPermissions"],{env:o,stdio:["pipe","pipe","pipe"]});a.stdin.write(n),a.stdin.end();let c="",E="";a.stdout.on("data",d=>{let $=d.toString();c+=$;let P=$.split(`
2
+ `).filter(N=>N.trim());for(let N of P){let _=N.trim().length>200?N.trim().substring(0,200)+"\u2026":N.trim();_&&(r&&dt(r,`${ut} [critic] ${_}`,"output"),console.log(`${Ie()} ${ae.dim("\u{1F50D}")} ${ae.dim(_)}`))}}),a.stderr.on("data",d=>{E+=d.toString()});let I=setTimeout(()=>{a.kill("SIGTERM"),i(new Error("Critic CLI timed out after 20 minutes"))},12e5);a.on("exit",d=>{clearTimeout(I),d!==0?i(new Error(`Critic CLI failed (exit ${d}): ${E.substring(0,300)}`)):s(c)}),a.on("error",d=>{clearTimeout(I),i(d)})})}function lt(e){let t=["","## CRITIC FEEDBACK \u2014 Your previous plan was REJECTED","",`Score: ${e.score}/100 (need >= ${q} to pass)`,""];if(e.risks.length>0){t.push("### Risks Identified:");for(let n of e.risks)t.push(`- ${n}`);t.push("")}if(e.suggestions&&e.suggestions.length>0){t.push("### Required Changes:");for(let n of e.suggestions)t.push(`- ${n}`);t.push("")}if(e.storyFeedback&&e.storyFeedback.length>0){t.push("### Per-Story Feedback:");for(let n of e.storyFeedback)if(t.push(`- **${n.storyId}**: ${n.feedback}`),n.suggestedChanges)for(let o of n.suggestedChanges)t.push(` - ${o}`);t.push("")}return t.push(`**You MUST address ALL feedback above.** Each story must target at most ${me} files.`,"Stories MUST NOT overlap on targetFiles.","","**CRITICAL \u2014 OUTPUT FORMAT:** You MUST output a revised plan as a ```json code block containing the full JSON object with `summary`, `stories`, `risks`, and `assumptions` fields. Do NOT just describe what you would change \u2014 output the COMPLETE revised JSON plan. If you do not output a ```json block, the plan will fail to parse and the task will fail.","","**DO NOT re-explore the repository.** You already explored it in the previous attempt. Go directly to outputting the revised ```json plan. Every tool call wastes output budget \u2014 prioritize emitting the JSON plan."),t.join(`
3
+ `)}function ct(e){let t=["","## REVIEWER NOTES \u2014 Your plan was APPROVED, but the reviewer has suggestions","",`Score: ${e.score}/100 (approved)`,"","The reviewer approved your plan but identified opportunities for improvement.","Review each suggestion and incorporate the ones that genuinely improve the plan.","You may reject suggestions that would reduce quality or don't apply.",""];if(e.risks.length>0){t.push("### Risks Identified:");for(let n of e.risks)t.push(`- ${n}`);t.push("")}if(e.suggestions&&e.suggestions.length>0){t.push("### Suggested Improvements:");for(let n of e.suggestions)t.push(`- ${n}`);t.push("")}if(e.storyFeedback&&e.storyFeedback.length>0){t.push("### Per-Story Notes:");for(let n of e.storyFeedback)if(t.push(`- **${n.storyId}**: ${n.feedback}`),n.suggestedChanges)for(let o of n.suggestedChanges)t.push(` - ${o}`);t.push("")}return t.push(`Each story must target at most ${me} files. Stories MUST NOT overlap on targetFiles.`,"","**CRITICAL \u2014 OUTPUT FORMAT:** Output the refined plan as a ```json code block with the COMPLETE JSON object (`summary`, `stories`, `risks`, `assumptions`). Do NOT describe changes \u2014 output the full JSON.","","**DO NOT re-explore the repository.** Go directly to outputting the refined ```json plan."),t.join(`
4
+ `)}var ut="[\u{1F5FA}\uFE0F planning_agent \u{1F916}]";function Ie(){return ae.dim(new Date().toLocaleTimeString())}async function dt(e,t,n="system",o="info"){try{await O.post("/api/control-center/logs",{taskId:e,type:n,message:t,severity:o})}catch{}}async function pt(e,t,n,o,r,s,i,a,c){let E=po(n,o);if(!E)return console.warn(`${Ie()} ${s} ${ae.yellow("\u26A0")} Critic config not available \u2014 skipping validation`),null;let I=i||"anthropic";console.log(`${Ie()} ${s} ${ae.dim(`Running critic validation (${I})...`)}`),c&&dt(c,`${ut} Running critic validation (${I})...`);try{let d;if(I==="anthropic")d=await mo(e,t,E,r,c);else{if(!a)throw new Error(`No API key for critic provider "${I}"`);d=await rt(I,t,E,a,{maxTokens:4096,temperature:.3,timeoutMs:12e5})}let $=go(d),P=$.score>=q?ae.green("\u2713"):ae.red("\u2717");return console.log(`${Ie()} ${s} ${P} Critic score: ${$.score}/100 (threshold: ${q})`),$}catch(d){let $=d instanceof Error?d.message:String(d);return console.error(`${Ie()} ${s} ${ae.yellow("\u26A0")} Critic failed: ${$.substring(0,100)}`),null}}import{generateText as fo,tool as Ve,stepCountIs as $o}from"ai";import{createOpenAI as gt}from"@ai-sdk/openai";import{createAnthropic as ho}from"@ai-sdk/anthropic";import{createGoogleGenerativeAI as yo}from"@ai-sdk/google";import{z as le}from"zod";import{execSync as Ye}from"child_process";import{readFileSync as wo,existsSync as bo}from"fs";function To(e,t,n){switch(e){case"anthropic":return ho({apiKey:n})(t);case"openai":return gt({apiKey:n})(t);case"google":return yo({apiKey:n})(t);case"ollama":return gt({baseURL:n||"http://localhost:11434/v1",apiKey:"ollama"})(t);default:throw new Error(`Unsupported AI provider: ${e}`)}}var Eo=le.object({pattern:le.string().describe("Glob pattern like '**/*.ts', 'src/**/*.js', 'package.json'")}),Io=le.object({path:le.string().describe("File path relative to the working directory"),limit:le.number().optional().describe("Max number of lines to read (default: 500)")}),Ao=le.object({pattern:le.string().describe("Search pattern (regex supported)"),glob:le.string().optional().describe("File glob to filter (e.g. '*.ts', '*.py')")});function _o(e){return{glob:Ve({description:"Find files matching a glob pattern. Returns file paths relative to the working directory.",inputSchema:Eo,execute:async t=>{try{let n=Ye(`find . -path './.git' -prune -o -path './node_modules' -prune -o -name '${t.pattern.replace(/\*\*/g,"*")}' -print 2>/dev/null | head -200`,{cwd:e,encoding:"utf-8",timeout:15e3}).trim();return n||Ye("find . -path './.git' -prune -o -path './node_modules' -prune -o -type f -print 2>/dev/null | head -500",{cwd:e,encoding:"utf-8",timeout:15e3}).trim()||"No files found"}catch{return"Error running glob search"}}}),read_file:Ve({description:"Read the contents of a file. Returns the file text.",inputSchema:Io,execute:async t=>{try{let n=`${e}/${t.path}`.replace(/\/\//g,"/");if(!bo(n))return`File not found: ${t.path}`;let o=wo(n,"utf-8"),r=o.split(`
5
+ `),s=t.limit||500;return r.length>s?r.slice(0,s).join(`
5
6
  `)+`
6
- ... (truncated, ${n.length-i} more lines)`:o}catch(r){return`Error reading file: ${r instanceof Error?r.message:String(r)}`}}}),grep:De({description:"Search for a pattern in files. Returns matching lines with file paths and line numbers.",inputSchema:$o,execute:async t=>{try{let r=t.glob?`--include='${t.glob}'`:"";return Fe(`grep -rn ${r} --exclude-dir=node_modules --exclude-dir=.git '${t.pattern.replace(/'/g,"'\\''")}' . 2>/dev/null | head -100`,{cwd:e,encoding:"utf-8",timeout:15e3}).trim()||"No matches found"}catch{return"No matches found"}}})}}async function ct(e){let{provider:t,model:r,apiKey:o,prompt:n,systemPrompt:i,workingDir:s,maxTokens:a=16384,temperature:l=.7,timeoutMs:I=6e5,maxSteps:b=15,enableTools:p=!0}=e,m=go(t,r,o),k=p&&s?ho(s):void 0,N=new AbortController,R=setTimeout(()=>N.abort(),I);try{return(await so({model:m,prompt:n,system:i,maxOutputTokens:a,temperature:l,tools:k,stopWhen:k?ao(b):void 0,abortSignal:N.signal})).text}finally{clearTimeout(R)}}function wo(e,t){let r=[e.usage,e.message?.usage,e.result?.usage];for(let o of r)if(o&&typeof o=="object"){let n=o;typeof n.input_tokens=="number"&&(t.inputTokens=Math.max(t.inputTokens,n.input_tokens)),typeof n.output_tokens=="number"&&(t.outputTokens=Math.max(t.outputTokens,n.output_tokens)),typeof n.cache_creation_input_tokens=="number"&&(t.cacheCreationTokens=Math.max(t.cacheCreationTokens,n.cache_creation_input_tokens)),typeof n.cache_read_input_tokens=="number"&&(t.cacheReadTokens=Math.max(t.cacheReadTokens,n.cache_read_input_tokens))}}async function ut(e,t,r,o){if(!(t.inputTokens===0&&t.outputTokens===0))try{await M.post(`/api/tasks/${e}/usage/partial`,{inputTokens:t.inputTokens,outputTokens:t.outputTokens,cacheCreationTokens:t.cacheCreationTokens,cacheReadTokens:t.cacheReadTokens,model:r,mode:o})}catch{}}var te=3;function g(){return c.dim(new Date().toLocaleTimeString())}var he=[],le=null;async function pt(){for(;he.length>0;){let e=he.splice(0,50);try{await M.post("/api/control-center/logs/batch",{entries:e},{timeout:5e3})}catch{}}}async function A(e,t,r="system",o="info"){he.length>=200&&he.shift(),he.push({taskId:e,message:t,type:r,severity:o}),le||(le=pt().finally(()=>{le=null}))}async function Eo(){le&&await le,he.length>0&&(le=pt().finally(()=>{le=null}),await le)}async function ye(e,t,r,o,n,i){try{await M.post("/api/agent/planning-progress",{taskId:e,phase:t,elapsedSeconds:r,detail:o,charsGenerated:n,toolCallCount:i})}catch{}}var $="[\u{1F5FA}\uFE0F planning_agent \u{1F916}]";function _e(e){let t=Math.floor(e/60),r=e%60;return t>0?`${t}m ${r}s`:`${r}s`}function dt(e,t){switch(e){case"initializing":return`${$} Starting planning agent...`;case"reading_repo":return`${$} Reading repository structure...`;case"analyzing":return`${$} Analyzing requirements...`;case"generating_plan":return`${$} Planning in progress \u2014 analyzing requirements and decomposing into steps (${_e(t)} elapsed)`;case"validating":return`${$} Validating plan...`;case"complete":return`${$} Planning complete`}}function Io(e,t,r,o,n,i,s){let a=c.cyan(n.slice(0,8));return new Promise((l,I)=>{let p=yo(e,["--print","--verbose","--output-format","stream-json","--model",t,"--permission-mode","bypassPermissions"],{cwd:s,env:o,stdio:["pipe","pipe","pipe"]});p.stdin.write(r),p.stdin.end();let m="",k="",N="",R=0,K=0,P={inputTokens:0,outputTokens:0,cacheCreationTokens:0,cacheReadTokens:0},G=t,h="";function D(f=!1){if(!h)return;let F=h.split(`
7
- `),oe=f?"":F.pop()||"";for(let W of F)if(W.trim()){A(n,`${$} ${W}`,"output");let x=W.trim().length>160?W.trim().substring(0,160)+"\u2026":W.trim();console.log(`${g()} ${a} ${c.dim("\u{1F4AD}")} ${c.dim(x)}`)}h=oe}let w="initializing",v=!1,d={started:!0,reading:!1,analyzing:!1,generating:!1};function C(f){if(f===w)return;w=f;let F=Math.round((Date.now()-i)/1e3),oe=dt(f,F);A(n,oe),console.log(`${g()} ${a} ${c.dim(oe)}`)}let j=setInterval(()=>D(),500),B=setInterval(()=>{let f=Math.round((Date.now()-i)/1e3);ye(n,w,f,dt(w,f),R,K)},2e3),_=0,Z=setInterval(()=>{let f=Math.round((Date.now()-i)/1e3);if(w==="initializing"&&f>=5?C("reading_repo"):w==="reading_repo"&&f>=15&&!v&&C("analyzing"),w==="generating_plan"&&f-_>=30){_=f;let F=`${$} Planning in progress \u2014 analyzing requirements and decomposing into steps (${_e(f)} elapsed)`;A(n,F),console.log(`${g()} ${a} ${c.dim(F)}`)}},5e3),z="";p.stdout.on("data",f=>{z+=f.toString();let F=z.split(`
8
- `);z=F.pop()||"";for(let oe of F){let W=oe.trim();if(W)try{let x=JSON.parse(W);if(x.type==="assistant"&&x.message?.content){let V=x.message.content;if(Array.isArray(V))for(let re of V)re.type==="text"&&re.text?(m+=re.text,R+=re.text.length,h+=re.text,v||(v=!0,K>0&&!d.analyzing&&(C("analyzing"),d.analyzing=!0)),R>500&&!d.generating&&(C("generating_plan"),d.generating=!0,_=Math.round((Date.now()-i)/1e3))):re.type==="tool_use"&&(K++,d.reading||(C("reading_repo"),d.reading=!0));else typeof V=="string"&&V&&(m+=V,R+=V.length,h+=V)}else x.type==="content_block_delta"&&x.delta?.text?(m+=x.delta.text,R+=x.delta.text.length,h+=x.delta.text,v||(v=!0,K>0&&!d.analyzing&&(C("analyzing"),d.analyzing=!0)),R>500&&!d.generating&&(C("generating_plan"),d.generating=!0,_=Math.round((Date.now()-i)/1e3))):x.type==="content_block_start"&&x.content_block?.type==="tool_use"?(K++,d.reading||(C("reading_repo"),d.reading=!0)):x.type==="result"&&x.result&&(k=typeof x.result=="string"?x.result:"");if(wo(x,P),x.type==="result"&&x.total_cost_usd!==void 0&&x.modelUsage&&typeof x.modelUsage=="object"){let V=Object.keys(x.modelUsage);V.length>0&&(G=V[0])}}catch{m+=W+`
9
- `,R+=W.length}}}),p.stderr.on("data",f=>{N+=f.toString()});let X=setInterval(()=>{(P.inputTokens>0||P.outputTokens>0)&&ut(n,P,G,"greatest").catch(()=>{})},3e4);function ee(){clearInterval(Z),clearInterval(B),clearInterval(j),clearInterval(X),D(!0)}let Te=setTimeout(()=>{ee(),p.kill("SIGTERM"),I(new Error("Claude CLI timed out after 20 minutes"))},12e5);p.on("exit",f=>{clearTimeout(Te),ee();let F=Math.round((Date.now()-i)/1e3);ye(n,"validating",F,"Validating plan...",R,K),ut(n,P,G,"greatest").catch(()=>{}),f!==0?I(new Error(`Claude CLI failed (exit ${f}): ${N.substring(0,300)}`)):l(k||m)}),p.on("error",f=>{clearTimeout(Te),ee(),I(f)})})}function To(e,t){if(t)switch(e){case"anthropic":return t.anthropicApiKey;case"openai":return t.openaiApiKey;case"google":return t.googleApiKey;case"ollama":return t.ollamaBaseUrl||"http://localhost:11434";default:return}}function bo(e,t,r){switch(r){case"bitbucket":return`https://x-token-auth:${t}@bitbucket.org/${e}.git`;case"gitlab":return`https://oauth2:${t}@gitlab.com/${e}.git`;default:return`https://x-access-token:${t}@github.com/${e}.git`}}async function Ao(e,t,r,o){let n=c.cyan(o.slice(0,8)),i=`/tmp/workermill-planning-${o.slice(0,8)}-${Date.now()}`;try{let s=bo(e,t,r);return console.log(`${g()} ${n} ${c.dim("Cloning repo for planner...")}`),je(`git clone --depth 1 --single-branch "${s}" "${i}"`,{stdio:"ignore",timeout:6e4}),console.log(`${g()} ${n} ${c.green("\u2713")} Repo cloned to ${c.dim(i)}`),i}catch(s){let a=s instanceof Error?s.message:String(s);console.error(`${g()} ${n} ${c.yellow("\u26A0")} Clone failed, planner will run without repo access: ${a.substring(0,100)}`);try{je(`rm -rf "${i}"`,{stdio:"ignore"})}catch{}return null}}async function gt(e,t,r){let o=c.cyan(e.id.slice(0,8));console.log(`${g()} ${o} Fetching planning prompt...`),await A(e.id,`${$} Fetching planning prompt from cloud API...`);let n=await M.get("/api/agent/planning-prompt",{params:{taskId:e.id}}),{prompt:i,model:s,provider:a,maxStories:l,maxTargetFiles:I}=n.data,b=typeof l=="number"?l:8,p=s,m=a||"anthropic",k=m==="anthropic",N=process.env.CLAUDE_CLI_PATH||ue()||"claude",R={...process.env};delete R.CLAUDE_CODE_OAUTH_TOKEN;let K=To(m,r),P=Date.now(),G=e.description||e.summary,h=null;if(e.githubRepo){let B=e.scmProvider||"github",_=B==="bitbucket"?t.bitbucketToken:B==="gitlab"?t.gitlabToken:t.githubToken;_?h=await Ao(e.githubRepo,_,B,e.id):console.log(`${g()} ${o} ${c.yellow("\u26A0")} No SCM token for ${B}, planner will run without repo access`)}let D=i,w=null,v=0,d=[],C=0,j=await Qe(typeof I=="number"?I:void 0);j||(console.log(`${g()} ${o} ${c.yellow("\u26A0")} Could not fetch critic config \u2014 critic validation will be skipped`),await A(e.id,`${$} \u26A0\uFE0F Could not fetch critic config from API \u2014 critic validation will be skipped`));try{for(let _=1;_<=te;_++){let Z=te>1?` (attempt ${_}/${te})`:"",z=`${m}/${p}`;_>1?(console.log(`${g()} ${o} Running planner${Z} ${c.dim(`(${c.yellow(z)})`)}`),await A(e.id,`${$} Re-planning${Z} using ${z}`)):(console.log(`${g()} ${o} Running planner ${c.dim(`(${c.yellow(z)})`)}`),await A(e.id,`${$} Starting planning agent using ${z}`));let X;try{if(k)X=await Io(N,p,D,R,e.id,P,h||void 0);else{if(!K)throw new Error(`No API key available for provider "${m}". Configure it in Settings > Integrations.`);let T=Math.round((Date.now()-P)/1e3);await ye(e.id,"generating_plan",T,"Generating plan via AI SDK...",0,0),X=await ct({provider:m,model:p,apiKey:K,prompt:D,workingDir:h||void 0,enableTools:!!h,maxSteps:10});let S=Math.round((Date.now()-P)/1e3);await ye(e.id,"validating",S,"Validating plan...",X.length,0)}}catch(T){let S=Math.round((Date.now()-P)/1e3),J=T instanceof Error?T.message:String(T);return console.error(`${g()} ${o} ${c.red("\u2717")} Failed after ${S}s: ${J.substring(0,100)}`),await A(e.id,`${$} Planning failed after ${_e(S)}: ${J.substring(0,200)}`,"error","error"),!1}let ee=Math.round((Date.now()-P)/1e3),Te=k?"Claude CLI":`${m} API`;console.log(`${g()} ${o} ${c.green("\u2713")} ${Te} done ${c.dim(`(${ee}s, ${X.length} chars)`)}`);let f;try{f=Ze(X)}catch(T){let S=T instanceof Error?T.message:String(T);return console.error(`${g()} ${o} ${c.red("\u2717")} Plan parse failed: ${S.substring(0,100)}`),await A(e.id,`${$} Failed to parse execution plan from Claude output: ${S.substring(0,200)}`,"error","error"),await _o(e.id,X,t.agentId,o,ee)}let{truncatedCount:F,details:oe}=et(f);if(F>0){C+=F;let T=`${$} File cap applied: ${F} stories truncated to max ${j?.maxTargetFiles??5} targetFiles`;console.log(`${g()} ${o} ${c.yellow("\u26A0")} ${T}`),await A(e.id,T);for(let S of oe)console.log(`${g()} ${o} ${c.dim(S)}`)}let{droppedCount:W,details:x}=tt(f,b);if(W>0){let T=`${$} Story cap applied: ${W} stories dropped (max ${b})`;console.log(`${g()} ${o} ${c.yellow("\u26A0")} ${T}`),await A(e.id,T);for(let S of x)console.log(`${g()} ${o} ${c.dim(S)}`)}let{resolvedCount:V,details:re}=ot(f);if(V>0){let T=`${$} File overlap resolved: ${V} shared file(s) de-duped across stories`;console.log(`${g()} ${o} ${c.yellow("\u26A0")} ${T}`),await A(e.id,T);for(let S of re)console.log(`${g()} ${o} ${c.dim(S)}`)}console.log(`${g()} ${o} Plan: ${c.bold(f.stories.length)} stories (max ${b})`),await A(e.id,`${$} Plan generated: ${f.stories.length} stories (${_e(ee)}). Running critic validation...`);let E=await at(N,p,G,f,R,o,m,K,e.id);if(E&&E.score>v?(w=f,v=E.score):!E&&!w&&(w=f),E&&d.push({iteration:_,score:E.score,approved:E.approved||E.score>=q,risks:E.risks,suggestions:E.suggestions,filesCapApplied:F>0?F:void 0}),!E){let T=`${$} \u26A0\uFE0F CRITIC BYPASSED \u2014 Critic validation failed (timeout/parse error). Posting plan WITHOUT quality gate.`;console.log(`${g()} ${o} ${c.yellow("\u26A0")} ${T}`),await A(e.id,T,"error","warning");let S=Date.now()-P;return await Ke(e.id,f,t.agentId,o,ee,void 0,void 0,d,C,S,_)}if(E.approved||E.score>=q){let T=`${$} Critic approved (score: ${E.score}/100)`;if(console.log(`${g()} ${o} ${c.green("\u2713")} ${T}`),await A(e.id,T),E.risks.length>0){let J=`${$} Critic risks (non-blocking): ${E.risks.join("; ")}`;console.log(`${g()} ${o} ${c.dim(J)}`),await A(e.id,J)}let S=Date.now()-P;return await Ke(e.id,f,t.agentId,o,ee,E.score,E.risks,d,C,S,_)}if(_<te){let T=nt(E);D=D+`
7
+ ... (truncated, ${r.length-s} more lines)`:o}catch(n){return`Error reading file: ${n instanceof Error?n.message:String(n)}`}}}),grep:Ve({description:"Search for a pattern in files. Returns matching lines with file paths and line numbers.",inputSchema:Ao,execute:async t=>{try{let n=t.glob?`--include='${t.glob}'`:"";return Ye(`grep -rn ${n} --exclude-dir=node_modules --exclude-dir=.git '${t.pattern.replace(/'/g,"'\\''")}' . 2>/dev/null | head -100`,{cwd:e,encoding:"utf-8",timeout:15e3}).trim()||"No matches found"}catch{return"No matches found"}}})}}async function ze(e){let{provider:t,model:n,apiKey:o,prompt:r,systemPrompt:s,workingDir:i,maxTokens:a=16384,temperature:c=.7,timeoutMs:E=6e5,maxSteps:I=15,enableTools:d=!0}=e,$=To(t,n,o),P=d&&i?_o(i):void 0,N=new AbortController,_=setTimeout(()=>N.abort(),E);try{return(await fo({model:$,prompt:r,system:s,maxOutputTokens:a,temperature:c,tools:P,stopWhen:P?$o(I):void 0,abortSignal:N.signal})).text}finally{clearTimeout(_)}}function So(e,t){let n=[e.usage,e.message?.usage,e.result?.usage];for(let o of n)if(o&&typeof o=="object"){let r=o;typeof r.input_tokens=="number"&&(t.inputTokens=Math.max(t.inputTokens,r.input_tokens)),typeof r.output_tokens=="number"&&(t.outputTokens=Math.max(t.outputTokens,r.output_tokens)),typeof r.cache_creation_input_tokens=="number"&&(t.cacheCreationTokens=Math.max(t.cacheCreationTokens,r.cache_creation_input_tokens)),typeof r.cache_read_input_tokens=="number"&&(t.cacheReadTokens=Math.max(t.cacheReadTokens,r.cache_read_input_tokens))}}async function mt(e,t,n,o){if(!(t.inputTokens===0&&t.outputTokens===0))try{await O.post(`/api/tasks/${e}/usage/partial`,{inputTokens:t.inputTokens,outputTokens:t.outputTokens,cacheCreationTokens:t.cacheCreationTokens,cacheReadTokens:t.cacheReadTokens,model:n,mode:o})}catch{}}var ee=3;function p(){return l.dim(new Date().toLocaleTimeString())}var be=[],ce=null;async function ht(){for(;be.length>0;){let e=be.splice(0,50);try{await O.post("/api/control-center/logs/batch",{entries:e},{timeout:5e3})}catch{}}}async function b(e,t,n="system",o="info"){be.length>=200&&be.shift(),be.push({taskId:e,message:t,type:n,severity:o}),ce||(ce=ht().finally(()=>{ce=null}))}async function ko(){ce&&await ce,be.length>0&&(ce=ht().finally(()=>{ce=null}),await ce)}async function Te(e,t,n,o,r,s){try{await O.post("/api/agent/planning-progress",{taskId:e,phase:t,elapsedSeconds:n,detail:o,charsGenerated:r,toolCallCount:s})}catch{}}var f="[\u{1F5FA}\uFE0F planning_agent \u{1F916}]";function ke(e){let t=Math.floor(e/60),n=e%60;return t>0?`${t}m ${n}s`:`${n}s`}function ft(e,t){switch(e){case"initializing":return`${f} Starting planning agent...`;case"reading_repo":return`${f} Reading repository structure...`;case"analyzing":return`${f} Analyzing requirements...`;case"generating_plan":return`${f} Planning in progress \u2014 analyzing requirements and decomposing into steps (${ke(t)} elapsed)`;case"validating":return`${f} Validating plan...`;case"complete":return`${f} Planning complete`}}function $t(e,t,n,o,r,s,i){let a=l.cyan(r.slice(0,8));return new Promise((c,E)=>{let d=Ro(e,["--print","--verbose","--output-format","stream-json","--model",t,"--permission-mode","bypassPermissions"],{cwd:i,env:o,stdio:["pipe","pipe","pipe"]});d.stdin.write(n),d.stdin.end();let $="",P="",N="",_=0,U=0,R={inputTokens:0,outputTokens:0,cacheCreationTokens:0,cacheReadTokens:0},G=t,h="";function F(y=!1){if(!h)return;let K=h.split(`
8
+ `),oe=y?"":K.pop()||"";for(let W of K)if(W.trim()){b(r,`${f} ${W}`,"output");let x=W.trim().length>160?W.trim().substring(0,160)+"\u2026":W.trim();console.log(`${p()} ${a} ${l.dim("\u{1F4AD}")} ${l.dim(x)}`)}h=oe}let T="initializing",v=!1,g={started:!0,reading:!1,analyzing:!1,generating:!1};function C(y){if(y===T)return;T=y;let K=Math.round((Date.now()-s)/1e3),oe=ft(y,K);b(r,oe),console.log(`${p()} ${a} ${l.dim(oe)}`)}let j=setInterval(()=>F(),500),B=setInterval(()=>{let y=Math.round((Date.now()-s)/1e3);Te(r,T,y,ft(T,y),_,U)},2e3),S=0,Z=setInterval(()=>{let y=Math.round((Date.now()-s)/1e3);if(T==="initializing"&&y>=5?C("reading_repo"):T==="reading_repo"&&y>=15&&!v&&C("analyzing"),T==="generating_plan"&&y-S>=30){S=y;let K=`${f} Planning in progress \u2014 analyzing requirements and decomposing into steps (${ke(y)} elapsed)`;b(r,K),console.log(`${p()} ${a} ${l.dim(K)}`)}},5e3),z="";d.stdout.on("data",y=>{z+=y.toString();let K=z.split(`
9
+ `);z=K.pop()||"";for(let oe of K){let W=oe.trim();if(W)try{let x=JSON.parse(W);if(x.type==="assistant"&&x.message?.content){let V=x.message.content;if(Array.isArray(V))for(let ne of V)ne.type==="text"&&ne.text?($+=ne.text,_+=ne.text.length,h+=ne.text,v||(v=!0,U>0&&!g.analyzing&&(C("analyzing"),g.analyzing=!0)),_>500&&!g.generating&&(C("generating_plan"),g.generating=!0,S=Math.round((Date.now()-s)/1e3))):ne.type==="tool_use"&&(U++,g.reading||(C("reading_repo"),g.reading=!0));else typeof V=="string"&&V&&($+=V,_+=V.length,h+=V)}else x.type==="content_block_delta"&&x.delta?.text?($+=x.delta.text,_+=x.delta.text.length,h+=x.delta.text,v||(v=!0,U>0&&!g.analyzing&&(C("analyzing"),g.analyzing=!0)),_>500&&!g.generating&&(C("generating_plan"),g.generating=!0,S=Math.round((Date.now()-s)/1e3))):x.type==="content_block_start"&&x.content_block?.type==="tool_use"?(U++,g.reading||(C("reading_repo"),g.reading=!0)):x.type==="result"&&x.result&&(P=typeof x.result=="string"?x.result:"");if(So(x,R),x.type==="result"&&x.total_cost_usd!==void 0&&x.modelUsage&&typeof x.modelUsage=="object"){let V=Object.keys(x.modelUsage);V.length>0&&(G=V[0])}}catch{$+=W+`
10
+ `,_+=W.length}}}),d.stderr.on("data",y=>{N+=y.toString()});let X=setInterval(()=>{(R.inputTokens>0||R.outputTokens>0)&&mt(r,R,G,"greatest").catch(()=>{})},3e4);function te(){clearInterval(Z),clearInterval(B),clearInterval(j),clearInterval(X),F(!0)}let _e=setTimeout(()=>{te(),d.kill("SIGTERM"),E(new Error("Claude CLI timed out after 20 minutes"))},12e5);d.on("exit",y=>{clearTimeout(_e),te();let K=Math.round((Date.now()-s)/1e3);Te(r,"validating",K,"Validating plan...",_,U),mt(r,R,G,"greatest").catch(()=>{}),y!==0?E(new Error(`Claude CLI failed (exit ${y}): ${N.substring(0,300)}`)):c(P||$)}),d.on("error",y=>{clearTimeout(_e),te(),E(y)})})}function Po(e,t){if(t)switch(e){case"anthropic":return t.anthropicApiKey;case"openai":return t.openaiApiKey;case"google":return t.googleApiKey;case"ollama":return t.ollamaBaseUrl||"http://localhost:11434";default:return}}function vo(e,t,n){switch(n){case"bitbucket":return`https://x-token-auth:${t}@bitbucket.org/${e}.git`;case"gitlab":return`https://oauth2:${t}@gitlab.com/${e}.git`;default:return`https://x-access-token:${t}@github.com/${e}.git`}}async function Co(e,t,n,o){let r=l.cyan(o.slice(0,8)),s=`/tmp/workermill-planning-${o.slice(0,8)}-${Date.now()}`;try{let i=vo(e,t,n);return console.log(`${p()} ${r} ${l.dim("Cloning repo for planner...")}`),He(`git clone --depth 1 --single-branch "${i}" "${s}"`,{stdio:"ignore",timeout:6e4}),console.log(`${p()} ${r} ${l.green("\u2713")} Repo cloned to ${l.dim(s)}`),s}catch(i){let a=i instanceof Error?i.message:String(i);console.error(`${p()} ${r} ${l.yellow("\u26A0")} Clone failed, planner will run without repo access: ${a.substring(0,100)}`);try{He(`rm -rf "${s}"`,{stdio:"ignore"})}catch{}return null}}async function yt(e,t,n){let o=l.cyan(e.id.slice(0,8));console.log(`${p()} ${o} Fetching planning prompt...`),await b(e.id,`${f} Fetching planning prompt from cloud API...`);let r=await O.get("/api/agent/planning-prompt",{params:{taskId:e.id}}),{prompt:s,model:i,provider:a,maxStories:c,maxTargetFiles:E}=r.data,I=typeof c=="number"?c:8,d=i,$=a||"anthropic",P=$==="anthropic",N=process.env.CLAUDE_CLI_PATH||ge()||"claude",_={...process.env};delete _.CLAUDE_CODE_OAUTH_TOKEN;let U=Po($,n),R=Date.now(),G=e.description||e.summary,h=null;if(e.githubRepo){let B=e.scmProvider||"github",S=B==="bitbucket"?n?.scmToken||t.bitbucketToken:B==="gitlab"?n?.scmToken||t.gitlabToken:n?.githubToken||t.githubToken;S?h=await Co(e.githubRepo,S,B,e.id):console.log(`${p()} ${o} ${l.yellow("\u26A0")} No SCM token for ${B}, planner will run without repo access`)}let F=s,T=null,v=0,g=[],C=0,j=await it(typeof E=="number"?E:void 0);j||(console.log(`${p()} ${o} ${l.yellow("\u26A0")} Could not fetch critic config \u2014 critic validation will be skipped`),await b(e.id,`${f} \u26A0\uFE0F Could not fetch critic config from API \u2014 critic validation will be skipped`));try{for(let S=1;S<=ee;S++){let Z=ee>1?` (attempt ${S}/${ee})`:"",z=`${$}/${d}`;S>1?(console.log(`${p()} ${o} Running planner${Z} ${l.dim(`(${l.yellow(z)})`)}`),await b(e.id,`${f} Re-planning${Z} using ${z}`)):(console.log(`${p()} ${o} Running planner ${l.dim(`(${l.yellow(z)})`)}`),await b(e.id,`${f} Starting planning agent using ${z}`));let X;try{if(P)X=await $t(N,d,F,_,e.id,R,h||void 0);else{if(!U)throw new Error(`No API key available for provider "${$}". Configure it in Settings > Integrations.`);let A=Math.round((Date.now()-R)/1e3);await Te(e.id,"generating_plan",A,"Generating plan via AI SDK...",0,0),X=await ze({provider:$,model:d,apiKey:U,prompt:F,workingDir:h||void 0,enableTools:!!h,maxSteps:10});let k=Math.round((Date.now()-R)/1e3);await Te(e.id,"validating",k,"Validating plan...",X.length,0)}}catch(A){let k=Math.round((Date.now()-R)/1e3),J=A instanceof Error?A.message:String(A);return console.error(`${p()} ${o} ${l.red("\u2717")} Failed after ${k}s: ${J.substring(0,100)}`),await b(e.id,`${f} Planning failed after ${ke(k)}: ${J.substring(0,200)}`,"error","error"),!1}let te=Math.round((Date.now()-R)/1e3),_e=P?"Claude CLI":`${$} API`;console.log(`${p()} ${o} ${l.green("\u2713")} ${_e} done ${l.dim(`(${te}s, ${X.length} chars)`)}`);let y;try{y=je(X)}catch(A){let k=A instanceof Error?A.message:String(A);return console.error(`${p()} ${o} ${l.red("\u2717")} Plan parse failed: ${k.substring(0,100)}`),await b(e.id,`${f} Failed to parse execution plan from Claude output: ${k.substring(0,200)}`,"error","error"),await xo(e.id,X,t.agentId,o,te)}let{truncatedCount:K,details:oe}=Ge(y);if(K>0){C+=K;let A=`${f} File cap applied: ${K} stories truncated to max ${j?.maxTargetFiles??5} targetFiles`;console.log(`${p()} ${o} ${l.yellow("\u26A0")} ${A}`),await b(e.id,A);for(let k of oe)console.log(`${p()} ${o} ${l.dim(k)}`)}let{droppedCount:W,details:x}=Be(y,I);if(W>0){let A=`${f} Story cap applied: ${W} stories dropped (max ${I})`;console.log(`${p()} ${o} ${l.yellow("\u26A0")} ${A}`),await b(e.id,A);for(let k of x)console.log(`${p()} ${o} ${l.dim(k)}`)}let{resolvedCount:V,details:ne}=We(y);if(V>0){let A=`${f} File overlap resolved: ${V} shared file(s) de-duped across stories`;console.log(`${p()} ${o} ${l.yellow("\u26A0")} ${A}`),await b(e.id,A);for(let k of ne)console.log(`${p()} ${o} ${l.dim(k)}`)}console.log(`${p()} ${o} Plan: ${l.bold(y.stories.length)} stories (max ${I})`),await b(e.id,`${f} Plan generated: ${y.stories.length} stories (${ke(te)}). Running critic validation...`);let m=await pt(N,d,G,y,_,o,$,U,e.id);if(m&&m.score>v?(T=y,v=m.score):!m&&!T&&(T=y),m&&g.push({iteration:S,score:m.score,approved:m.approved||m.score>=q,risks:m.risks,suggestions:m.suggestions,filesCapApplied:K>0?K:void 0}),!m){let A=`${f} \u26A0\uFE0F CRITIC BYPASSED \u2014 Critic validation failed (timeout/parse error). Posting plan WITHOUT quality gate.`;console.log(`${p()} ${o} ${l.yellow("\u26A0")} ${A}`),await b(e.id,A,"error","warning");let k=Date.now()-R;return await Je(e.id,y,t.agentId,o,te,void 0,void 0,g,C,k,S)}if(m.approved||m.score>=q){let A=`${f} Critic approved (score: ${m.score}/100)`;if(console.log(`${p()} ${o} ${l.green("\u2713")} ${A}`),await b(e.id,A),m.risks.length>0){let re=`${f} Critic risks: ${m.risks.join("; ")}`;console.log(`${p()} ${o} ${l.dim(re)}`),await b(e.id,re)}if(m.suggestions&&m.suggestions.length>0){let re=`${f} Critic suggestions: ${m.suggestions.join("; ")}`;console.log(`${p()} ${o} ${l.dim(re)}`),await b(e.id,re)}let k=m.risks.length>0||m.suggestions&&m.suggestions.length>0||m.storyFeedback&&m.storyFeedback.length>0,J=y;if(k){await b(e.id,`${f} Running refinement pass \u2014 incorporating reviewer suggestions...`),console.log(`${p()} ${o} Running refinement pass...`);let re=s+ct(m);try{let de;if(P)de=await $t(N,d,re,_,e.id,R,h||void 0);else{if(!U)throw new Error(`No API key for "${$}"`);de=await ze({provider:$,model:d,apiKey:U,prompt:re,workingDir:h||void 0,enableTools:!!h,maxSteps:10})}let pe=je(de);Ge(pe),Be(pe,I),We(pe),J=pe;let jt=Math.round((Date.now()-R)/1e3);console.log(`${p()} ${o} ${l.green("\u2713")} Refinement complete ${l.dim(`(${jt}s)`)}`),await b(e.id,`${f} Refinement complete \u2014 plan updated with reviewer suggestions`)}catch(de){let pe=de instanceof Error?de.message:String(de);console.warn(`${p()} ${o} ${l.yellow("\u26A0")} Refinement failed, using original plan: ${pe.substring(0,100)}`),await b(e.id,`${f} \u26A0\uFE0F Refinement pass failed (${pe.substring(0,100)}) \u2014 using original approved plan`)}}let Ft=Date.now()-R,Kt=Math.round((Date.now()-R)/1e3);return await Je(e.id,J,t.agentId,o,Kt,m.score,m.risks,g,C,Ft,S)}if(S<ee){let A=lt(m);F=F+`
10
11
 
11
- `+T;let S=`${$} Critic rejected (score: ${E.score}/100, threshold: ${q}). Re-planning with feedback...`;if(console.log(`${g()} ${o} ${c.yellow("\u26A0")} ${S}`),await A(e.id,S),E.risks.length>0){let J=`${$} Critic risks: ${E.risks.join("; ")}`;console.log(`${g()} ${o} ${c.dim(J)}`),await A(e.id,J)}if(E.suggestions&&E.suggestions.length>0){let J=`${$} Critic suggestions: ${E.suggestions.join("; ")}`;console.log(`${g()} ${o} ${c.dim(J)}`),await A(e.id,J)}}else{let T=`${$} Critic rejected after ${te} iterations (best score: ${v}/100, threshold: ${q})`;if(console.error(`${g()} ${o} ${c.red("\u2717")} ${T}`),await A(e.id,T,"error","error"),E.risks.length>0){let S=`${$} Final risks: ${E.risks.join("; ")}`;console.error(`${g()} ${o} ${S}`),await A(e.id,S,"error","error")}if(E.suggestions&&E.suggestions.length>0){let S=`${$} Suggestions: ${E.suggestions.join("; ")}`;console.error(`${g()} ${o} ${S}`),await A(e.id,S,"error","error")}}}let B=50;if(w&&v>=B){let _=Math.round((Date.now()-P)/1e3),Z=`${$} Best-plan fallback: posting plan with score ${v}/100 (below ${q} threshold, above ${B} minimum)`;console.log(`${g()} ${o} ${c.yellow("\u26A0")} ${Z}`),await A(e.id,Z);let z=Date.now()-P;if(await Ke(e.id,w,t.agentId,o,_,v,[`Best-plan fallback: critic rejected after ${te} iterations`],d,C,z,te))return!0;console.log(`${g()} ${o} ${c.yellow("\u26A0")} ${$} Fallback post rejected by server, reporting plan-failed`),await A(e.id,`${$} Fallback plan rejected by server \u2014 reporting failure`)}try{let _=w&&v>=B?`Best-plan fallback rejected by server after ${te} iterations (best score: ${v}/100)`:`Critic rejected after ${te} iterations (best score: ${v}/100, threshold: ${q}, fallback minimum: ${B})`;await M.post("/api/agent/plan-failed",{taskId:e.id,agentId:t.agentId,reason:_,criticHistory:d})}catch{}return!1}finally{if(await Eo(),h)try{je(`rm -rf "${h}"`,{stdio:"ignore"})}catch{}}}async function Ke(e,t,r,o,n,i,s,a,l,I,b){let p=rt(t);try{let k=(await M.post("/api/agent/plan-result",{taskId:e,rawOutput:p,agentId:r,criticScore:i,criticRisks:s,criticHistory:a,criticIterations:b,fileCapTruncations:l,planningDurationMs:I})).data.storyCount;return console.log(`${g()} ${o} ${c.green("\u2713")} Plan validated: ${c.bold(k)} stories \u2192 ${c.green("queued")}`),await A(e,`${$} Plan validated: ${k} stories. Task queued for execution.`),await ye(e,"complete",n,"Planning complete",0,0),!0}catch(m){let k=m,N=k.response?.data?.error||k.response?.data?.detail||String(m),R=k.response?.status?` (${k.response.status})`:"";return console.error(`${g()} ${o} ${c.red("\u2717")} Server validation failed${R}: ${N.substring(0,100)}`),await A(e,`${$} Server-side plan validation failed${R}: ${N.substring(0,200)}`,"error","error"),!1}}async function _o(e,t,r,o,n){try{let s=(await M.post("/api/agent/plan-result",{taskId:e,rawOutput:t,agentId:r})).data.storyCount;return console.log(`${g()} ${o} ${c.green("\u2713")} Plan validated (server-side): ${c.bold(s)} stories \u2192 ${c.green("queued")}`),await A(e,`${$} Plan validated: ${s} stories. Task queued for execution.`),await ye(e,"complete",n,"Planning complete",0,0),!0}catch(i){let a=i.response?.data?.detail||String(i);return console.error(`${g()} ${o} ${c.red("\u2717")} Validation failed: ${a.substring(0,100)}`),await A(e,`${$} Plan validation failed: ${a.substring(0,200)}`,"error","error"),!1}}import u from"chalk";import{spawn as ft,execSync as ke}from"child_process";import*as Re from"path";import*as Q from"fs";import*as Pe from"os";function O(){return u.dim(new Date().toLocaleTimeString())}var Ro=[[/(:\/\/[^:/?#]+:)[^@]+(@)/g,"$1***$2"],[/\b(ghp_|gho_|ghs_|github_pat_)[A-Za-z0-9_]+/g,"$1***"],[/\bglpat-[A-Za-z0-9\-_]+/g,"glpat-***"],[/\b(AKIA)[A-Z0-9]{16}\b/g,"$1***"],[/(Bearer\s+)[A-Za-z0-9._\-]+/gi,"$1***"],[/(x-api-key:\s*)[^\s,'"]+/gi,"$1***"]];function Se(e){let t=e;for(let[r,o]of Ro)t=t.replace(r,o);return t}var Y=new Map;function So(){if(process.env.WSL_DISTRO_NAME||process.env.WSL_INTEROP)return!0;try{return Q.readFileSync("/proc/version","utf-8").toLowerCase().includes("microsoft")}catch{return!1}}var ve=So(),$t=ve||process.platform==="darwin"||process.platform==="win32";function ht(){if(!ve)return null;try{let e=ke("hostname -I",{encoding:"utf-8"}).trim().split(/\s+/)[0];if(e&&/^\d+\.\d+\.\d+\.\d+$/.test(e))return e}catch{}return null}function yt(e){if(!ve)return e;let t=e.match(/^\/mnt\/([a-zA-Z])\/(.*)$/);return t?`${t[1].toUpperCase()}:/${t[2]}`:e}function wt(){let e=Re.join(Pe.homedir(),".claude");if(Q.existsSync(e))return e;if(ve){let t="/mnt/c/Users";if(Q.existsSync(t))try{for(let r of Q.readdirSync(t)){if(["Public","Default","Default User","All Users"].includes(r))continue;let o=Re.join(t,r,".claude");if(Q.existsSync(o))return o}}catch{}}return null}var mt=0;function Et(e){let t=e.match(/^(\d+\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com)/);return t?t[1]:null}function ko(e){let t=e.match(/\.ecr\.([a-z0-9-]+)\.amazonaws\.com/);return t?t[1]:"us-east-1"}function It(e){if(Date.now()<mt)return!0;let t=ko(e);try{return ke(`aws ecr get-login-password --region ${t} | docker login --username AWS --password-stdin ${e}`,{stdio:"pipe",timeout:3e4}),mt=Date.now()+660*60*1e3,!0}catch{return!1}}function Tt(e,t,r){if(r?.scmToken)return r.scmToken;switch(e){case"bitbucket":return t.bitbucketToken;case"gitlab":return t.gitlabToken;default:return t.githubToken}}function Po(e){let t=e.jiraFields;if(!t)return!1;let r=t.labels;if(Array.isArray(r)&&r.some(i=>typeof i=="string"&&i.toLowerCase()==="self-review"))return!0;let n=t.issue?.labels;return!!(Array.isArray(n)&&n.some(i=>typeof i=="string"?i.toLowerCase()==="self-review":i&&typeof i=="object"&&"name"in i?(i.name||"").toLowerCase()==="self-review":!1))}async function bt(e,t,r,o){let n=u.cyan(e.id.slice(0,8));if(Y.has(e.id)){console.log(`${O()} ${n} ${u.dim("Already running, skipping")}`);return}let i=`workermill-${e.id.slice(0,8)}`,a=["run","--rm",...!t.workerImage.includes("/")?[]:["--pull","always"],"--name",i],l=Math.round(Pe.totalmem()/(1024*1024*1024));if(l<=16?a.push("--memory","6g","--memory-swap","10g","--cpus","2"):(l<=32,a.push("--memory","6g","--memory-swap","12g","--cpus","4")),$t){let d=ht();a.push(`--add-host=host.docker.internal:${d||"host-gateway"}`)}else a.push("--network","host");let I=e.workerProvider||"anthropic",b=wt();if(!b&&I==="anthropic"){console.error(`${O()} ${n} ${u.red("\u2717")} Claude credentials not found. Run 'claude' and complete the sign-in flow.`);return}if(b){let d=Re.join(b,".credentials.json");try{Q.chmodSync(d,438)}catch{}let C=yt(b);a.push("-v",`${C}:/home/worker/.claude`)}else console.log(`${O()} ${n} ${u.dim("Skipping Claude mount (non-Anthropic worker)")}`);let p=t.apiUrl.replace(/localhost|127\.0\.0\.1/,"host.docker.internal"),m=e.scmProvider||"github",k=Tt(m,t,o),N=o?.githubToken||t.githubToken,R=m==="bitbucket"&&o?.scmToken||t.bitbucketToken,K=m==="gitlab"&&o?.scmToken||t.gitlabToken,P={NODE_OPTIONS:"--max-old-space-size=3072",EPIC_MODE:"true",EXECUTION_MODE:"local",TASK_ID:e.id,ORG_ID:e.orgId||"",JIRA_ISSUE_KEY:e.jiraIssueKey||"",JIRA_SUMMARY:e.summary||"",JIRA_DESCRIPTION:e.description||"",TASK_SUMMARY:e.summary||"",TASK_DESCRIPTION:e.description||"",WORKER_PERSONA:e.workerPersona||"",RETRY_NUMBER:String(e.retryCount??0),TICKET_KEY:e.jiraIssueKey||"",API_BASE_URL:p,ORG_API_KEY:t.apiKey,SCM_PROVIDER:m,SCM_TOKEN:k,SCM_BASE_URL:o?.scmBaseUrl||"",GITHUB_TOKEN:N,GH_TOKEN:N,GITHUB_REVIEWER_TOKEN:o?.githubReviewerToken||"",BITBUCKET_TOKEN:R,BITBUCKET_USERNAME:o?.bitbucketUsername||"x-token-auth",GITLAB_TOKEN:K,TARGET_REPO:e.githubRepo||"",GITHUB_REPO:e.githubRepo||"",WORKER_MODEL:e.workerModel||String(r.defaultWorkerModel||""),CLAUDE_MODEL:e.workerModel||String(r.defaultWorkerModel||""),JIRA_BASE_URL:o?.jiraBaseUrl||"",JIRA_EMAIL:o?.jiraEmail||"",JIRA_API_TOKEN:o?.jiraApiToken||"",TICKET_SYSTEM:o?.issueTrackerProvider||"jira",LINEAR_API_KEY:o?.linearApiKey||"",AWS_ACCESS_KEY_ID:o?.customerAwsAccessKeyId||"",AWS_SECRET_ACCESS_KEY:o?.customerAwsSecretAccessKey||"",AWS_DEFAULT_REGION:o?.customerAwsRegion||"",AWS_REGION:o?.customerAwsRegion||"",CUSTOMER_AWS_ROLE_ARN:o?.customerAwsRoleArn||"",CUSTOMER_AWS_EXTERNAL_ID:o?.customerAwsExternalId||"",CUSTOMER_AWS_REGION:o?.customerAwsRegion||"",MANAGER_PROVIDER:o?.managerProvider||"anthropic",MANAGER_MODEL:o?.managerModelId||"",BITBUCKET_EMAIL:o?.bitbucketEmail||"",DEPLOYMENT_ENABLED:e.deploymentEnabled||e.parentTaskId?"true":"false",PRD_CHILD_TASK:e.parentTaskId?"true":"false",IMPROVEMENT_ENABLED:e.improvementEnabled?"true":"false",QUALITY_GATE_BYPASS:e.qualityGateBypass?"true":"false",STANDARD_SDK_MODE:e.standardSdkMode?"true":"false",MAX_REVIEW_REVISIONS:String(r.maxReviewRevisions??3),CODEBASE_INDEXING_ENABLED:r.codebaseIndexingEnabled===!0?"true":"false",EXISTING_PR_URL:e.githubPrUrl||"",EXISTING_PR_NUMBER:e.githubPrNumber?String(e.githubPrNumber):"",PARENT_TASK_ID:e.parentTaskId||e.id,PARENT_JIRA_KEY:e.jiraIssueKey&&/-S\d+$/.test(e.jiraIssueKey)&&e.jiraFields?.parentJiraKey||"",TARGET_BRANCH:e.jiraFields?.targetBranch||"",STORY_BRANCH:e.jiraFields?.storyBranch||"",TASK_NOTES:e.taskNotes||"",TARGET_FILES:JSON.stringify(e.jiraFields?.targetFiles||[]),REFERENCE_FILES:JSON.stringify(e.jiraFields?.referenceFiles||[]),PIPELINE_VERSION:e.jiraFields?.pipelineVersion||e.pipelineVersion||"",V2_STEP_INPUT:e.jiraFields?.v2StepInput?JSON.stringify(e.jiraFields.v2StepInput):"",EXECUTION_MODE_SETTING:e.jiraFields?.executionMode||"autonomous",ANTHROPIC_API_KEY:b?"":o?.anthropicApiKey||process.env.ANTHROPIC_API_KEY||"",WORKER_PROVIDER:e.workerProvider||"anthropic",OPENAI_API_KEY:o?.openaiApiKey||"",GOOGLE_API_KEY:o?.googleApiKey||"",GOOGLE_GENERATIVE_AI_API_KEY:o?.googleApiKey||"",OLLAMA_HOST:o?.ollamaBaseUrl||"",OLLAMA_CONTEXT_WINDOW:o?.ollamaContextWindow?String(o.ollamaContextWindow):"",VLLM_BASE_URL:o?.vllmBaseUrl||"",BLOCKER_MAX_AUTO_RETRIES:String(r.blockerMaxAutoRetries??3),BLOCKER_AUTO_RETRY_ENABLED:r.blockerAutoRetryEnabled!==!1?"true":"false",PUSH_AFTER_COMMIT:r.pushAfterCommit!==!1?"true":"false",GRACEFUL_SHUTDOWN_ENABLED:r.gracefulShutdownEnabled!==!1?"true":"false",MAX_PARALLEL_EXPERTS:String(r.maxParallelExperts??4),REVIEW_ENABLED:e.skipManagerReview===!1?"true":"false",SELF_REVIEW_ENABLED:Po(e)||r.selfReviewEnabled!==!1?"true":"false"};for(let[d,C]of Object.entries(P))C!==""&&a.push("-e",`${d}=${C}`);let G=t.workerImage,h=Et(G);h&&It(h),a.push(G);let D=e.skipManagerReview===!1;console.log(`${O()} ${n} ${u.dim("Starting container")} ${u.yellow(i)}`),console.log(`${O()} ${n} ${u.dim(` skipManagerReview=${e.skipManagerReview} \u2192 REVIEW_ENABLED=${D}`)}`),console.log(`${O()} ${n} ${u.dim(` model=${e.workerModel} repo=${e.githubRepo}`)}`),console.log(`${O()} ${n} ${u.dim(` totalRamGB=${l} docker args:`)} ${a.slice(0,10).join(" ")}`);let w=ft("docker",a,{stdio:["ignore","pipe","pipe"],detached:!1});if(!w.pid){console.error(`${O()} ${n} ${u.red("\u2717")} Failed to spawn container`);return}let v={taskId:e.id,containerName:i,process:w,startedAt:new Date,status:"running",resultEmitted:!1};Y.set(e.id,v),w.stdout?.on("data",d=>{let C=d.toString().split(`
12
- `).filter(j=>j.trim());for(let j of C)console.log(`${O()} ${n} ${u.dim(Se(j))}`),j.includes("::result::")&&(v.resultEmitted=!0)}),w.stderr?.on("data",d=>{let C=d.toString().split(`
13
- `).filter(j=>j.trim());for(let j of C)console.log(`${O()} ${n} ${u.red(Se(j))}`)}),w.on("exit",d=>{v.status=d===0?"completed":"failed";let C=Math.round((Date.now()-v.startedAt.getTime())/1e3),j=d===0?u.green("\u2713"):u.red("\u2717"),B=d===0?u.green("completed"):u.red(`failed (exit ${d})`);console.log(`${O()} ${n} ${j} Container ${B} ${u.dim(`(${C}s)`)}`),v.resultEmitted||(console.log(`${O()} ${n} ${u.yellow("\u26A0")} No ::result:: marker seen \u2014 posting fallback completion in 15s`),setTimeout(async()=>{try{let _=d===0?"completed":"failed",Z=d!==0?`Worker container exited with code ${d} without reporting completion`:void 0;(await(await fetch(`${t.apiUrl}/api/tasks/${e.id}/worker-complete`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":t.apiKey},body:JSON.stringify({exitCode:d??1,result:_,errorMessage:Z})})).json()).status==="ignored"?console.log(`${O()} ${n} ${u.dim("Fallback completion ignored (task already transitioned)")}`):console.log(`${O()} ${n} ${u.yellow("\u26A0")} Fallback completion applied: ${_}`)}catch(_){console.error(`${O()} ${n} ${u.red("\u2717")} Fallback completion failed:`,_ instanceof Error?_.message:_)}},15e3)),setTimeout(()=>Y.delete(e.id),9e4)}),w.on("error",d=>{v.status="failed",console.error(`${O()} ${n} ${u.red("\u2717")} Container error: ${d.message}`)})}function Ge(){return Array.from(Y.values()).filter(e=>e.status==="running").length}function At(){return Array.from(Y.values()).filter(e=>e.status==="running").map(e=>e.taskId)}function _t(e){let t=Y.get(e);if(!t||t.status!=="running")return;let r=u.cyan(e.slice(0,8));console.log(`${O()} ${r} ${u.red("\u25A0")} Stopping container (cancelled by dashboard)`);try{ke(`docker stop ${t.containerName}`,{stdio:"ignore",timeout:15e3}),t.status="completed"}catch{}Y.delete(e)}async function Rt(){console.log(`${O()} ${u.dim(`Stopping ${Y.size} containers...`)}`);for(let[,e]of Y)if(e.status==="running")try{ke(`docker stop ${e.containerName}`,{stdio:"ignore",timeout:15e3}),e.status="completed"}catch{}Y.clear()}async function St(e,t,r){let o=u.cyan(e.id.slice(0,8)),n=`manager-${e.id}`;if(Y.has(n))return;let i=`wm-manager-${e.id.slice(0,8)}-${Date.now()}`,s=wt(),a=["run","--rm","--name",i,"--memory=4g","--cpus=2"];if($t){let h=ht();a.push(`--add-host=host.docker.internal:${h||"host-gateway"}`)}else a.push("--network","host");if(s){let h=yt(s);a.push("-v",`${h}:/home/worker/.claude`)}let l=t.apiUrl.replace(/localhost|127\.0\.0\.1/,"host.docker.internal"),I=e.scmProvider||"github",b=Tt(I,t,r),p=r?.githubToken||t.githubToken,m=I==="bitbucket"&&r?.scmToken||t.bitbucketToken,k=I==="gitlab"&&r?.scmToken||t.gitlabToken,N={NODE_OPTIONS:"--max-old-space-size=3072",TASK_ID:e.id,MANAGER_ACTION:e.managerAction,JIRA_ISSUE_KEY:e.jiraIssueKey||"",JIRA_SUMMARY:e.summary||"",JIRA_DESCRIPTION:e.description||"",GITHUB_REPO:e.githubRepo||"",PR_URL:e.githubPrUrl||"",PR_NUMBER:e.githubPrNumber?String(e.githubPrNumber):"",API_BASE_URL:l,ORG_API_KEY:t.apiKey,SCM_PROVIDER:I,SCM_TOKEN:b,GITHUB_TOKEN:p,GH_TOKEN:p,BITBUCKET_TOKEN:m,BITBUCKET_USERNAME:r?.bitbucketUsername||"x-token-auth",GITLAB_TOKEN:k,MANAGER_PROVIDER:r?.managerProvider||"anthropic",MANAGER_MODEL:r?.managerModelId||"",ANTHROPIC_API_KEY:s?"":r?.anthropicApiKey||process.env.ANTHROPIC_API_KEY||"",OPENAI_API_KEY:r?.openaiApiKey||"",GOOGLE_API_KEY:r?.googleApiKey||"",JIRA_BASE_URL:r?.jiraBaseUrl||"",JIRA_EMAIL:r?.jiraEmail||"",JIRA_API_TOKEN:r?.jiraApiToken||"",TICKET_SYSTEM:r?.issueTrackerProvider||"jira",LINEAR_API_KEY:r?.linearApiKey||""};for(let[h,D]of Object.entries(N))D!==""&&a.push("-e",`${h}=${D}`);let R=t.workerImage,K=Et(R);K&&It(K),a.push("--entrypoint","/bin/bash"),a.push(R),a.push("/app/manager-entrypoint.sh"),console.log(`${O()} ${o} ${u.magenta("\u25C6 MANAGER")} Starting ${e.managerAction} container ${u.yellow(i)}`);let P=ft("docker",a,{stdio:["ignore","pipe","pipe"],detached:!1});if(!P.pid){console.error(`${O()} ${o} ${u.red("\u2717")} Failed to spawn manager container`);return}let G={taskId:n,containerName:i,process:P,startedAt:new Date,status:"running",resultEmitted:!1};Y.set(n,G),P.stdout?.on("data",h=>{let D=h.toString().split(`
14
- `).filter(w=>w.trim());for(let w of D)console.log(`${O()} ${o} ${u.magenta("MGR")} ${u.dim(Se(w))}`)}),P.stderr?.on("data",h=>{let D=h.toString().split(`
15
- `).filter(w=>w.trim());for(let w of D)console.log(`${O()} ${o} ${u.magenta("MGR")} ${u.red(Se(w))}`)}),P.on("exit",h=>{G.status=h===0?"completed":"failed";let D=Math.round((Date.now()-G.startedAt.getTime())/1e3),w=h===0?u.green("\u2713"):u.red("\u2717"),v=h===0?u.green("completed"):u.red(`failed (exit ${h})`);console.log(`${O()} ${o} ${u.magenta("MGR")} ${w} Manager ${e.managerAction} ${v} ${u.dim(`(${D}s)`)}`),setTimeout(()=>Y.delete(n),6e4)}),P.on("error",h=>{G.status="failed",console.error(`${O()} ${o} ${u.magenta("MGR")} ${u.red("\u2717")} Container error: ${h.message}`)})}import{createRequire as vo}from"module";var Co=vo(import.meta.url),xo=Co("../package.json"),ce=xo.version;import{spawn as kt}from"child_process";import Ie from"chalk";async function Ce(){return console.log(Ie.cyan(" Updating @workermill/agent...")),new Promise(e=>{let t=kt("npm",["install","-g","@workermill/agent@latest"],{stdio:"inherit",shell:!0});t.on("error",r=>{console.error(Ie.red(` Update failed: ${r.message}`)),e(!1)}),t.on("close",r=>{r===0?(console.log(Ie.green(" Update successful.")),e(!0)):(console.error(Ie.red(` Update failed with exit code ${r}`)),e(!1))})})}function xe(){console.log(Ie.cyan(" Restarting agent...")),kt(process.argv[0],process.argv.slice(1),{stdio:"inherit",detached:!0}).unref(),process.exit(0)}var de=new Set,pe=new Set,Me=null,Pt=!1,Oe=!1;function L(){return y.dim(new Date().toLocaleTimeString())}async function Mo(){if(Me)return Me;try{return Me=(await M.get("/api/agent/config")).data,Me}catch{return console.error(`${L()} ${y.red("\u2717")} Failed to fetch org config`),{}}}async function vt(e){if(!Oe)try{let t=await M.get("/api/agent/poll",{params:{agentId:e.agentId}}),r=t.data.tasks;if(r.length===0)return;for(let n of r)n.status==="planning"&&!de.has(n.id)?await Oo(n,e):n.status==="queued"&&await No(n,e);let o=t.data.managerTasks;if(o&&o.length>0)for(let n of o)pe.has(n.id)||await Lo(n,e)}catch(t){let r=t,o=de.size>0||Ge()>0||pe.size>0;r.response?.status===401?o||console.error(`${L()} ${y.red("\u2717")} Authentication failed. Check your API key.`):o||console.warn(`${L()} ${y.yellow("\u26A0")} Poll error: ${r.message||String(t)}`)}}async function Oo(e,t){let r,o;try{let s=await M.post("/api/agent/claim",{taskId:e.id,agentId:t.agentId});if(!s.data.claimed)return;r=s.data.credentials,o=s.data.task}catch{return}let n=y.cyan(e.id.slice(0,8));if(o&&(o.retryCount??0)>0&&o.executionPlanV2!=null){console.log(),console.log(`${L()} ${y.magenta("\u25C6 RESUME")} ${n} ${e.summary.substring(0,60)}`),console.log(`${L()} ${n} Retry #${o.retryCount} with existing plan \u2014 skipping planning`),de.add(e.id);try{await M.post("/api/agent/resume-plan",{taskId:e.id,agentId:t.agentId}),console.log(`${L()} ${n} ${y.green("\u2713")} Resumed with existing plan \u2192 ${y.green("queued")}`)}catch(s){let a=s,l=a.response?.data?.error||a.message||String(s);console.error(`${L()} ${n} ${y.red("\u2717")} Resume failed: ${l}`)}de.delete(e.id);return}console.log(),console.log(`${L()} ${y.magenta("\u25C6 PLANNING")} ${n} ${e.summary.substring(0,60)}`),de.add(e.id),gt(e,t,r).then(s=>{console.log(s?`${L()} ${y.green("\u2713")} Planning complete for ${n}`:`${L()} ${y.red("\u2717")} Planning failed for ${n}`)}).catch(s=>console.error(`${L()} ${y.red("\u2717")} Planning error for ${n}:`,s.message||s)).finally(()=>de.delete(e.id))}async function No(e,t){if(Ge()>=t.maxWorkers)return;let o;try{if(o=(await M.post("/api/agent/claim",{taskId:e.id,agentId:t.agentId})).data,!o.claimed)return}catch{return}try{await M.post("/api/agent/started",{taskId:e.id,agentId:t.agentId})}catch{let I=y.cyan(e.id.slice(0,8));console.warn(`${L()} ${y.yellow("\u26A0")} Failed to report started for ${I}`)}let n=y.cyan(e.id.slice(0,8));console.log(),console.log(`${L()} ${y.blue("\u25B6 EXECUTING")} ${n} ${e.summary.substring(0,60)}`);let i=await Mo(),s=o.task||{id:e.id,summary:e.summary,description:e.description,jiraIssueKey:e.jiraIssueKey,workerModel:e.workerModel,workerProvider:e.workerProvider,githubRepo:e.githubRepo,scmProvider:e.scmProvider,skipManagerReview:e.skipManagerReview,deploymentEnabled:e.deploymentEnabled,improvementEnabled:e.improvementEnabled,qualityGateBypass:e.qualityGateBypass,standardSdkMode:e.standardSdkMode,parentTaskId:e.parentTaskId,taskNotes:e.taskNotes,githubPrUrl:e.githubPrUrl,githubPrNumber:e.githubPrNumber,executionPlanV2:e.executionPlanV2,jiraFields:e.jiraFields||{}},a=o.credentials;bt(s,t,i,a).catch(l=>console.error(`${L()} ${y.red("\u2717")} Spawn failed for ${n}:`,l.message||l))}async function Lo(e,t){let r=y.cyan(e.id.slice(0,8));pe.add(e.id);try{let o=await M.post("/api/agent/claim-manager",{taskId:e.id,agentId:t.agentId,action:e.managerAction});if(!o.data.claimed){pe.delete(e.id);return}let n=o.data.task,i=o.data.credentials||{},s=e.managerAction==="analyze_logs"?y.yellow("LOG ANALYSIS"):y.yellow("PR REVIEW");console.log(),console.log(`${L()} ${y.magenta("\u25C6 MANAGER")} ${s} ${r} ${e.summary.substring(0,60)}`);let a={id:e.id,summary:n?.summary||e.summary,description:n?.description||e.description,jiraIssueKey:n?.jiraIssueKey||e.jiraIssueKey,githubRepo:n?.githubRepo||e.githubRepo,scmProvider:n?.scmProvider||e.scmProvider,githubPrUrl:n?.githubPrUrl||e.githubPrUrl,githubPrNumber:n?.githubPrNumber||e.githubPrNumber,managerAction:e.managerAction};St(a,t,i).then(()=>{console.log(`${L()} ${r} ${y.magenta("MGR")} ${y.green("\u2713")} Manager ${e.managerAction} dispatched`)}).catch(l=>{console.error(`${L()} ${r} ${y.magenta("MGR")} ${y.red("\u2717")} Manager spawn failed:`,l.message||l)}).finally(()=>pe.delete(e.id))}catch(o){pe.delete(e.id);let n=o;console.error(`${L()} ${r} ${y.red("\u2717")} Failed to claim manager task:`,n.message||String(o))}}var Ne=null,Le=null;function Ct(){Ne&&(clearInterval(Ne),Ne=null),Le&&(clearInterval(Le),Le=null)}function xt(e){console.log(` ${y.dim("Polling every")} ${e.pollIntervalMs/1e3}s ${y.dim("\xB7 waiting for tasks...")}`),vt(e),Ne=setInterval(()=>vt(e),e.pollIntervalMs)}function Mt(e){Le=setInterval(async()=>{let t=At(),r=Array.from(de),o=Array.from(pe),n=[...t,...r,...o];try{let i=await M.post("/api/agent/heartbeat",{agentId:e.agentId,activeTasks:n,agentVersion:ce}),s=i.data?.cancelledTasks;if(s&&s.length>0)for(let b of s)_t(b);let{updateAvailable:a,updateRequired:l,latestVersion:I}=i.data??{};l&&!Oe?(Oe=!0,console.log(`${L()} ${y.red("\u26A0 Agent update required")} (current: ${ce}, required: ${I})`),console.log(`${L()} ${y.yellow("Refusing new tasks until updated.")}`),await Ce()?xe():(console.log(`${L()} ${y.red("Auto-update failed.")} Run: npm install -g @workermill/agent@latest`),Oe=!1)):a&&!Pt&&!l&&(Pt=!0,console.log(`${L()} ${y.yellow(`Update available: ${I}`)} (current: ${ce}). Run: workermill-agent update`))}catch{}},e.heartbeatIntervalMs)}be();async function Uo(e){console.log(),console.log(U.bold.cyan(" WorkerMill Remote Agent")),console.log(U.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),Be(e.apiUrl,e.apiKey);try{let t=await M.get("/api/agent/config"),r=t.data.maxConcurrentWorkers;r&&typeof r=="number"&&(e.maxWorkers=r),t.data.workerImageUrl&&(e.workerImage=t.data.workerImageUrl),console.log(` ${U.green("\u25CF")} Connected to ${U.cyan(e.apiUrl)}`),console.log(` ${U.dim("Agent:")} ${e.agentId}`),console.log(` ${U.dim("Workers:")} ${U.yellow(String(e.maxWorkers))} parallel`),console.log(` ${U.dim("Image:")} ${e.workerImage}`),console.log(` ${U.dim("SCM:")} ${t.data.scmProvider}`),console.log(` ${U.dim("Model:")} ${U.yellow(t.data.defaultWorkerModel)}`),console.log()}catch(t){let r=t;throw r.response?.status===401?new Error("Authentication failed. Check your API key."):new Error(`Failed to connect to WorkerMill API: ${r.message||String(t)}`)}try{let t=await M.post("/api/agent/register",{agentId:e.agentId,maxWorkers:e.maxWorkers,agentVersion:ce}),{updateAvailable:r,updateRequired:o,latestVersion:n}=t.data;o?(console.log(U.red(` \u26A0 Agent update required (current: ${ce}, required: ${n})`)),await Ce()?xe():console.log(U.yellow(" Auto-update failed. Run: npm install -g @workermill/agent@latest"))):r&&console.log(U.yellow(` Update available: ${n} (current: ${ce}). Run: workermill-agent update`))}catch{}return xt(e),Mt(e),console.log(U.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` ${U.green("\u25CF")} Agent is running. ${U.dim("Press Ctrl+C to stop.")}`),console.log(),async()=>{console.log(),console.log(U.dim(" Shutting down...")),Ct();try{await M.post("/api/agent/deregister",{agentId:e.agentId})}catch{}await Rt(),console.log(` ${U.red("\u25CF")} Agent stopped.`)}}var Do=typeof process<"u"&&process.argv[1]&&(process.argv[1].endsWith("/index.ts")||process.argv[1].endsWith("/index.js"));if(Do){try{await import("dotenv/config")}catch{}let{loadConfig:e,validatePrerequisites:t}=await Promise.resolve().then(()=>(be(),He)),r=e();t(),console.log(U.dim(" Prerequisites validated."));let o=await Uo(r);process.on("SIGINT",async()=>{await o(),process.exit(0)}),process.on("SIGTERM",async()=>{await o(),process.exit(0)})}export{ue as findClaudePath,Je as getSystemInfo,Ye as loadConfig,Ve as loadConfigFromFile,Uo as startAgent,ze as validatePrerequisites};
12
+ `+A;let k=`${f} Critic rejected (score: ${m.score}/100, threshold: ${q}). Re-planning with feedback...`;if(console.log(`${p()} ${o} ${l.yellow("\u26A0")} ${k}`),await b(e.id,k),m.risks.length>0){let J=`${f} Critic risks: ${m.risks.join("; ")}`;console.log(`${p()} ${o} ${l.dim(J)}`),await b(e.id,J)}if(m.suggestions&&m.suggestions.length>0){let J=`${f} Critic suggestions: ${m.suggestions.join("; ")}`;console.log(`${p()} ${o} ${l.dim(J)}`),await b(e.id,J)}}else{let A=`${f} Critic rejected after ${ee} iterations (best score: ${v}/100, threshold: ${q})`;if(console.error(`${p()} ${o} ${l.red("\u2717")} ${A}`),await b(e.id,A,"error","error"),m.risks.length>0){let k=`${f} Final risks: ${m.risks.join("; ")}`;console.error(`${p()} ${o} ${k}`),await b(e.id,k,"error","error")}if(m.suggestions&&m.suggestions.length>0){let k=`${f} Suggestions: ${m.suggestions.join("; ")}`;console.error(`${p()} ${o} ${k}`),await b(e.id,k,"error","error")}}}let B=50;if(T&&v>=B){let S=Math.round((Date.now()-R)/1e3),Z=`${f} Best-plan fallback: posting plan with score ${v}/100 (below ${q} threshold, above ${B} minimum)`;console.log(`${p()} ${o} ${l.yellow("\u26A0")} ${Z}`),await b(e.id,Z);let z=Date.now()-R;if(await Je(e.id,T,t.agentId,o,S,v,[`Best-plan fallback: critic rejected after ${ee} iterations`],g,C,z,ee))return!0;console.log(`${p()} ${o} ${l.yellow("\u26A0")} ${f} Fallback post rejected by server, reporting plan-failed`),await b(e.id,`${f} Fallback plan rejected by server \u2014 reporting failure`)}try{let S=T&&v>=B?`Best-plan fallback rejected by server after ${ee} iterations (best score: ${v}/100)`:`Critic rejected after ${ee} iterations (best score: ${v}/100, threshold: ${q}, fallback minimum: ${B})`;await O.post("/api/agent/plan-failed",{taskId:e.id,agentId:t.agentId,reason:S,criticHistory:g})}catch{}return!1}finally{if(await ko(),h)try{He(`rm -rf "${h}"`,{stdio:"ignore"})}catch{}}}async function Je(e,t,n,o,r,s,i,a,c,E,I){let d=at(t);try{let P=(await O.post("/api/agent/plan-result",{taskId:e,rawOutput:d,agentId:n,criticScore:s,criticRisks:i,criticHistory:a,criticIterations:I,fileCapTruncations:c,planningDurationMs:E})).data.storyCount;return console.log(`${p()} ${o} ${l.green("\u2713")} Plan validated: ${l.bold(P)} stories \u2192 ${l.green("queued")}`),await b(e,`${f} Plan validated: ${P} stories. Task queued for execution.`),await Te(e,"complete",r,"Planning complete",0,0),!0}catch($){let P=$,N=P.response?.data?.error||P.response?.data?.detail||String($),_=P.response?.status?` (${P.response.status})`:"";return console.error(`${p()} ${o} ${l.red("\u2717")} Server validation failed${_}: ${N.substring(0,100)}`),await b(e,`${f} Server-side plan validation failed${_}: ${N.substring(0,200)}`,"error","error"),!1}}async function xo(e,t,n,o,r){try{let i=(await O.post("/api/agent/plan-result",{taskId:e,rawOutput:t,agentId:n})).data.storyCount;return console.log(`${p()} ${o} ${l.green("\u2713")} Plan validated (server-side): ${l.bold(i)} stories \u2192 ${l.green("queued")}`),await b(e,`${f} Plan validated: ${i} stories. Task queued for execution.`),await Te(e,"complete",r,"Planning complete",0,0),!0}catch(s){let a=s.response?.data?.detail||String(s);return console.error(`${p()} ${o} ${l.red("\u2717")} Validation failed: ${a.substring(0,100)}`),await b(e,`${f} Plan validation failed: ${a.substring(0,200)}`,"error","error"),!1}}import u from"chalk";import{spawn as bt,execSync as Ce}from"child_process";import*as Pe from"path";import*as Q from"fs";import*as xe from"os";function M(){return u.dim(new Date().toLocaleTimeString())}var Oo=[[/(:\/\/[^:/?#]+:)[^@]+(@)/g,"$1***$2"],[/\b(ghp_|gho_|ghs_|github_pat_)[A-Za-z0-9_]+/g,"$1***"],[/\bglpat-[A-Za-z0-9\-_]+/g,"glpat-***"],[/\b(AKIA)[A-Z0-9]{16}\b/g,"$1***"],[/(Bearer\s+)[A-Za-z0-9._\-]+/gi,"$1***"],[/(x-api-key:\s*)[^\s,'"]+/gi,"$1***"]];function ve(e){let t=e;for(let[n,o]of Oo)t=t.replace(n,o);return t}var Y=new Map;function Mo(){if(process.env.WSL_DISTRO_NAME||process.env.WSL_INTEROP)return!0;try{return Q.readFileSync("/proc/version","utf-8").toLowerCase().includes("microsoft")}catch{return!1}}var Oe=Mo(),Tt=Oe||process.platform==="darwin"||process.platform==="win32";function Et(){if(!Oe)return null;try{let e=Ce("hostname -I",{encoding:"utf-8"}).trim().split(/\s+/)[0];if(e&&/^\d+\.\d+\.\d+\.\d+$/.test(e))return e}catch{}return null}function It(e){if(!Oe)return e;let t=e.match(/^\/mnt\/([a-zA-Z])\/(.*)$/);return t?`${t[1].toUpperCase()}:/${t[2]}`:e}function At(){let e=Pe.join(xe.homedir(),".claude");if(Q.existsSync(e))return e;if(Oe){let t="/mnt/c/Users";if(Q.existsSync(t))try{for(let n of Q.readdirSync(t)){if(["Public","Default","Default User","All Users"].includes(n))continue;let o=Pe.join(t,n,".claude");if(Q.existsSync(o))return o}}catch{}}return null}var wt=0;function _t(e){let t=e.match(/^(\d+\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com)/);return t?t[1]:null}function No(e){let t=e.match(/\.ecr\.([a-z0-9-]+)\.amazonaws\.com/);return t?t[1]:"us-east-1"}function Rt(e){if(Date.now()<wt)return!0;let t=No(e);try{return Ce(`aws ecr get-login-password --region ${t} | docker login --username AWS --password-stdin ${e}`,{stdio:"pipe",timeout:3e4}),wt=Date.now()+660*60*1e3,!0}catch{return!1}}function St(e,t,n){if(n?.scmToken)return n.scmToken;switch(e){case"bitbucket":return t.bitbucketToken;case"gitlab":return t.gitlabToken;default:return t.githubToken}}function Lo(e){let t=e.jiraFields;if(!t)return!1;let n=t.labels;if(Array.isArray(n)&&n.some(s=>typeof s=="string"&&s.toLowerCase()==="self-review"))return!0;let r=t.issue?.labels;return!!(Array.isArray(r)&&r.some(s=>typeof s=="string"?s.toLowerCase()==="self-review":s&&typeof s=="object"&&"name"in s?(s.name||"").toLowerCase()==="self-review":!1))}async function kt(e,t,n,o){let r=u.cyan(e.id.slice(0,8));if(Y.has(e.id)){console.log(`${M()} ${r} ${u.dim("Already running, skipping")}`);return}let s=`workermill-${e.id.slice(0,8)}`,a=["run","--rm",...!t.workerImage.includes("/")?[]:["--pull","always"],"--name",s],c=Math.round(xe.totalmem()/(1024*1024*1024));if(c<=16?a.push("--memory","6g","--memory-swap","10g","--cpus","2"):(c<=32,a.push("--memory","6g","--memory-swap","12g","--cpus","4")),Tt){let g=Et();a.push(`--add-host=host.docker.internal:${g||"host-gateway"}`)}else a.push("--network","host");let E=e.workerProvider||"anthropic",I=At();if(!I&&E==="anthropic"){console.error(`${M()} ${r} ${u.red("\u2717")} Claude credentials not found. Run 'claude' and complete the sign-in flow.`);return}if(I){let g=Pe.join(I,".credentials.json");try{Q.chmodSync(g,438)}catch{}let C=It(I);a.push("-v",`${C}:/home/worker/.claude`)}else console.log(`${M()} ${r} ${u.dim("Skipping Claude mount (non-Anthropic worker)")}`);let d=t.apiUrl.replace(/localhost|127\.0\.0\.1/,"host.docker.internal"),$=e.scmProvider||"github",P=St($,t,o),N=o?.githubToken||t.githubToken,_=$==="bitbucket"&&o?.scmToken||t.bitbucketToken,U=$==="gitlab"&&o?.scmToken||t.gitlabToken,R={NODE_OPTIONS:"--max-old-space-size=3072",EPIC_MODE:"true",EXECUTION_MODE:"local",TASK_ID:e.id,ORG_ID:e.orgId||"",JIRA_ISSUE_KEY:e.jiraIssueKey||"",JIRA_SUMMARY:e.summary||"",JIRA_DESCRIPTION:e.description||"",TASK_SUMMARY:e.summary||"",TASK_DESCRIPTION:e.description||"",WORKER_PERSONA:e.workerPersona||"",RETRY_NUMBER:String(e.retryCount??0),TICKET_KEY:e.jiraIssueKey||"",API_BASE_URL:d,ORG_API_KEY:t.apiKey,SCM_PROVIDER:$,SCM_TOKEN:P,SCM_BASE_URL:o?.scmBaseUrl||"",GITHUB_TOKEN:N,GH_TOKEN:N,GITHUB_REVIEWER_TOKEN:o?.githubReviewerToken||"",BITBUCKET_TOKEN:_,BITBUCKET_USERNAME:o?.bitbucketUsername||"x-token-auth",GITLAB_TOKEN:U,TARGET_REPO:e.githubRepo||"",GITHUB_REPO:e.githubRepo||"",WORKER_MODEL:e.workerModel||String(n.defaultWorkerModel||""),CLAUDE_MODEL:e.workerModel||String(n.defaultWorkerModel||""),JIRA_BASE_URL:o?.jiraBaseUrl||"",JIRA_EMAIL:o?.jiraEmail||"",JIRA_API_TOKEN:o?.jiraApiToken||"",TICKET_SYSTEM:o?.issueTrackerProvider||"jira",LINEAR_API_KEY:o?.linearApiKey||"",AWS_ACCESS_KEY_ID:o?.customerAwsAccessKeyId||"",AWS_SECRET_ACCESS_KEY:o?.customerAwsSecretAccessKey||"",AWS_DEFAULT_REGION:o?.customerAwsRegion||"",AWS_REGION:o?.customerAwsRegion||"",CUSTOMER_AWS_ROLE_ARN:o?.customerAwsRoleArn||"",CUSTOMER_AWS_EXTERNAL_ID:o?.customerAwsExternalId||"",CUSTOMER_AWS_REGION:o?.customerAwsRegion||"",MANAGER_PROVIDER:o?.managerProvider||"anthropic",MANAGER_MODEL:o?.managerModelId||"",BITBUCKET_EMAIL:o?.bitbucketEmail||"",DEPLOYMENT_ENABLED:e.deploymentEnabled||e.parentTaskId?"true":"false",PRD_CHILD_TASK:e.parentTaskId?"true":"false",IMPROVEMENT_ENABLED:e.improvementEnabled?"true":"false",QUALITY_GATE_BYPASS:e.qualityGateBypass?"true":"false",STANDARD_SDK_MODE:e.standardSdkMode?"true":"false",MAX_REVIEW_REVISIONS:String(n.maxReviewRevisions??3),MAX_PER_STORY_REVISIONS:String(n.maxPerStoryRevisions??2),CODEBASE_INDEXING_ENABLED:n.codebaseIndexingEnabled===!0?"true":"false",EXISTING_PR_URL:e.githubPrUrl||"",EXISTING_PR_NUMBER:e.githubPrNumber?String(e.githubPrNumber):"",PARENT_TASK_ID:e.parentTaskId||e.id,PARENT_JIRA_KEY:e.jiraIssueKey&&/-S\d+$/.test(e.jiraIssueKey)&&e.jiraFields?.parentJiraKey||"",TARGET_BRANCH:e.jiraFields?.targetBranch||"",STORY_BRANCH:e.jiraFields?.storyBranch||"",TASK_NOTES:e.taskNotes||"",TARGET_FILES:JSON.stringify(e.jiraFields?.targetFiles||[]),REFERENCE_FILES:JSON.stringify(e.jiraFields?.referenceFiles||[]),PIPELINE_VERSION:e.jiraFields?.pipelineVersion||e.pipelineVersion||"",V2_STEP_INPUT:e.jiraFields?.v2StepInput?JSON.stringify(e.jiraFields.v2StepInput):"",EXECUTION_MODE_SETTING:e.jiraFields?.executionMode||"autonomous",ANTHROPIC_API_KEY:I?"":o?.anthropicApiKey||process.env.ANTHROPIC_API_KEY||"",WORKER_PROVIDER:e.workerProvider||"anthropic",OPENAI_API_KEY:o?.openaiApiKey||"",GOOGLE_API_KEY:o?.googleApiKey||"",GOOGLE_GENERATIVE_AI_API_KEY:o?.googleApiKey||"",OLLAMA_HOST:o?.ollamaBaseUrl||"",OLLAMA_CONTEXT_WINDOW:o?.ollamaContextWindow?String(o.ollamaContextWindow):"",VLLM_BASE_URL:o?.vllmBaseUrl||"",BLOCKER_MAX_AUTO_RETRIES:String(n.blockerMaxAutoRetries??3),BLOCKER_AUTO_RETRY_ENABLED:n.blockerAutoRetryEnabled!==!1?"true":"false",PUSH_AFTER_COMMIT:n.pushAfterCommit!==!1?"true":"false",GRACEFUL_SHUTDOWN_ENABLED:n.gracefulShutdownEnabled!==!1?"true":"false",MAX_PARALLEL_EXPERTS:String(n.maxParallelExperts??4),REVIEW_ENABLED:e.skipManagerReview===!1?"true":"false",SELF_REVIEW_ENABLED:Lo(e)||n.selfReviewEnabled!==!1?"true":"false"};for(let[g,C]of Object.entries(R))C!==""&&a.push("-e",`${g}=${C}`);let G=t.workerImage,h=_t(G);h&&Rt(h),a.push(G);let F=e.skipManagerReview===!1;console.log(`${M()} ${r} ${u.dim("Starting container")} ${u.yellow(s)}`),console.log(`${M()} ${r} ${u.dim(` skipManagerReview=${e.skipManagerReview} \u2192 REVIEW_ENABLED=${F}`)}`),console.log(`${M()} ${r} ${u.dim(` model=${e.workerModel} repo=${e.githubRepo}`)}`),console.log(`${M()} ${r} ${u.dim(` totalRamGB=${c} docker args:`)} ${a.slice(0,10).join(" ")}`);let T=bt("docker",a,{stdio:["ignore","pipe","pipe"],detached:!1});if(!T.pid){console.error(`${M()} ${r} ${u.red("\u2717")} Failed to spawn container`);return}let v={taskId:e.id,containerName:s,process:T,startedAt:new Date,status:"running",resultEmitted:!1};Y.set(e.id,v),T.stdout?.on("data",g=>{let C=g.toString().split(`
13
+ `).filter(j=>j.trim());for(let j of C)console.log(`${M()} ${r} ${u.dim(ve(j))}`),j.includes("::result::")&&(v.resultEmitted=!0)}),T.stderr?.on("data",g=>{let C=g.toString().split(`
14
+ `).filter(j=>j.trim());for(let j of C)console.log(`${M()} ${r} ${u.red(ve(j))}`)}),T.on("exit",g=>{v.status=g===0?"completed":"failed";let C=Math.round((Date.now()-v.startedAt.getTime())/1e3),j=g===0?u.green("\u2713"):u.red("\u2717"),B=g===0?u.green("completed"):u.red(`failed (exit ${g})`);console.log(`${M()} ${r} ${j} Container ${B} ${u.dim(`(${C}s)`)}`),v.resultEmitted||(console.log(`${M()} ${r} ${u.yellow("\u26A0")} No ::result:: marker seen \u2014 posting fallback completion in 15s`),setTimeout(async()=>{try{let S=g===0?"completed":"failed",Z=g!==0?`Worker container exited with code ${g} without reporting completion`:void 0;(await(await fetch(`${t.apiUrl}/api/tasks/${e.id}/worker-complete`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":t.apiKey},body:JSON.stringify({exitCode:g??1,result:S,errorMessage:Z})})).json()).status==="ignored"?console.log(`${M()} ${r} ${u.dim("Fallback completion ignored (task already transitioned)")}`):console.log(`${M()} ${r} ${u.yellow("\u26A0")} Fallback completion applied: ${S}`)}catch(S){console.error(`${M()} ${r} ${u.red("\u2717")} Fallback completion failed:`,S instanceof Error?S.message:S)}},15e3)),setTimeout(()=>Y.delete(e.id),9e4)}),T.on("error",g=>{v.status="failed",console.error(`${M()} ${r} ${u.red("\u2717")} Container error: ${g.message}`)})}function qe(){return Array.from(Y.values()).filter(e=>e.status==="running").length}function Pt(){return Array.from(Y.values()).filter(e=>e.status==="running").map(e=>e.taskId)}function vt(e){let t=Y.get(e);if(!t||t.status!=="running")return;let n=u.cyan(e.slice(0,8));console.log(`${M()} ${n} ${u.red("\u25A0")} Stopping container (cancelled by dashboard)`);try{Ce(`docker stop ${t.containerName}`,{stdio:"ignore",timeout:15e3}),t.status="completed"}catch{}Y.delete(e)}async function Ct(){console.log(`${M()} ${u.dim(`Stopping ${Y.size} containers...`)}`);for(let[,e]of Y)if(e.status==="running")try{Ce(`docker stop ${e.containerName}`,{stdio:"ignore",timeout:15e3}),e.status="completed"}catch{}Y.clear()}async function xt(e,t,n){let o=u.cyan(e.id.slice(0,8)),r=`manager-${e.id}`;if(Y.has(r))return;let s=`wm-manager-${e.id.slice(0,8)}-${Date.now()}`,i=At(),a=["run","--rm","--name",s,"--memory=4g","--cpus=2"];if(Tt){let h=Et();a.push(`--add-host=host.docker.internal:${h||"host-gateway"}`)}else a.push("--network","host");if(i){let h=It(i);a.push("-v",`${h}:/home/worker/.claude`)}let c=t.apiUrl.replace(/localhost|127\.0\.0\.1/,"host.docker.internal"),E=e.scmProvider||"github",I=St(E,t,n),d=n?.githubToken||t.githubToken,$=E==="bitbucket"&&n?.scmToken||t.bitbucketToken,P=E==="gitlab"&&n?.scmToken||t.gitlabToken,N={NODE_OPTIONS:"--max-old-space-size=3072",TASK_ID:e.id,MANAGER_ACTION:e.managerAction,JIRA_ISSUE_KEY:e.jiraIssueKey||"",JIRA_SUMMARY:e.summary||"",JIRA_DESCRIPTION:e.description||"",GITHUB_REPO:e.githubRepo||"",PR_URL:e.githubPrUrl||"",PR_NUMBER:e.githubPrNumber?String(e.githubPrNumber):"",API_BASE_URL:c,ORG_API_KEY:t.apiKey,SCM_PROVIDER:E,SCM_TOKEN:I,GITHUB_TOKEN:d,GH_TOKEN:d,BITBUCKET_TOKEN:$,BITBUCKET_USERNAME:n?.bitbucketUsername||"x-token-auth",GITLAB_TOKEN:P,MANAGER_PROVIDER:n?.managerProvider||"anthropic",MANAGER_MODEL:n?.managerModelId||"",ANTHROPIC_API_KEY:i?"":n?.anthropicApiKey||process.env.ANTHROPIC_API_KEY||"",OPENAI_API_KEY:n?.openaiApiKey||"",GOOGLE_API_KEY:n?.googleApiKey||"",JIRA_BASE_URL:n?.jiraBaseUrl||"",JIRA_EMAIL:n?.jiraEmail||"",JIRA_API_TOKEN:n?.jiraApiToken||"",TICKET_SYSTEM:n?.issueTrackerProvider||"jira",LINEAR_API_KEY:n?.linearApiKey||""};for(let[h,F]of Object.entries(N))F!==""&&a.push("-e",`${h}=${F}`);let _=t.workerImage,U=_t(_);U&&Rt(U),a.push("--entrypoint","/bin/bash"),a.push(_),a.push("/app/manager-entrypoint.sh"),console.log(`${M()} ${o} ${u.magenta("\u25C6 MANAGER")} Starting ${e.managerAction} container ${u.yellow(s)}`);let R=bt("docker",a,{stdio:["ignore","pipe","pipe"],detached:!1});if(!R.pid){console.error(`${M()} ${o} ${u.red("\u2717")} Failed to spawn manager container`);return}let G={taskId:r,containerName:s,process:R,startedAt:new Date,status:"running",resultEmitted:!1};Y.set(r,G),R.stdout?.on("data",h=>{let F=h.toString().split(`
15
+ `).filter(T=>T.trim());for(let T of F)console.log(`${M()} ${o} ${u.magenta("MGR")} ${u.dim(ve(T))}`)}),R.stderr?.on("data",h=>{let F=h.toString().split(`
16
+ `).filter(T=>T.trim());for(let T of F)console.log(`${M()} ${o} ${u.magenta("MGR")} ${u.red(ve(T))}`)}),R.on("exit",h=>{G.status=h===0?"completed":"failed";let F=Math.round((Date.now()-G.startedAt.getTime())/1e3),T=h===0?u.green("\u2713"):u.red("\u2717"),v=h===0?u.green("completed"):u.red(`failed (exit ${h})`);console.log(`${M()} ${o} ${u.magenta("MGR")} ${T} Manager ${e.managerAction} ${v} ${u.dim(`(${F}s)`)}`),setTimeout(()=>Y.delete(r),6e4)}),R.on("error",h=>{G.status="failed",console.error(`${M()} ${o} ${u.magenta("MGR")} ${u.red("\u2717")} Container error: ${h.message}`)})}import{createRequire as Do}from"module";var Uo=Do(import.meta.url),Fo=Uo("../package.json"),ue=Fo.version;import{spawn as Ot}from"child_process";import Ae from"chalk";async function Me(){return console.log(Ae.cyan(" Updating @workermill/agent...")),new Promise(e=>{let t=Ot("npm",["install","-g","@workermill/agent@latest"],{stdio:"inherit",shell:!0});t.on("error",n=>{console.error(Ae.red(` Update failed: ${n.message}`)),e(!1)}),t.on("close",n=>{n===0?(console.log(Ae.green(" Update successful.")),e(!0)):(console.error(Ae.red(` Update failed with exit code ${n}`)),e(!1))})})}function Ne(){console.log(Ae.cyan(" Restarting agent...")),Ot(process.argv[0],process.argv.slice(1),{stdio:"inherit",detached:!0}).unref(),process.exit(0)}var fe=new Set,$e=new Set,Le=null,Mt=!1,De=!1;function L(){return w.dim(new Date().toLocaleTimeString())}async function Ko(){if(Le)return Le;try{return Le=(await O.get("/api/agent/config")).data,Le}catch{return console.error(`${L()} ${w.red("\u2717")} Failed to fetch org config`),{}}}async function Nt(e){if(!De)try{let t=await O.get("/api/agent/poll",{params:{agentId:e.agentId}}),n=t.data.tasks;if(n.length===0)return;for(let r of n)r.status==="planning"&&!fe.has(r.id)?await jo(r,e):r.status==="queued"&&await Go(r,e);let o=t.data.managerTasks;if(o&&o.length>0)for(let r of o)$e.has(r.id)||await Bo(r,e)}catch(t){let n=t,o=fe.size>0||qe()>0||$e.size>0;n.response?.status===401?o||console.error(`${L()} ${w.red("\u2717")} Authentication failed. Check your API key.`):o||console.warn(`${L()} ${w.yellow("\u26A0")} Poll error: ${n.message||String(t)}`)}}async function jo(e,t){let n,o;try{let i=await O.post("/api/agent/claim",{taskId:e.id,agentId:t.agentId});if(!i.data.claimed)return;n=i.data.credentials,o=i.data.task}catch{return}let r=w.cyan(e.id.slice(0,8));if(o&&(o.retryCount??0)>0&&o.executionPlanV2!=null){console.log(),console.log(`${L()} ${w.magenta("\u25C6 RESUME")} ${r} ${e.summary.substring(0,60)}`),console.log(`${L()} ${r} Retry #${o.retryCount} with existing plan \u2014 skipping planning`),fe.add(e.id);try{await O.post("/api/agent/resume-plan",{taskId:e.id,agentId:t.agentId}),console.log(`${L()} ${r} ${w.green("\u2713")} Resumed with existing plan \u2192 ${w.green("queued")}`)}catch(i){let a=i,c=a.response?.data?.error||a.message||String(i);console.error(`${L()} ${r} ${w.red("\u2717")} Resume failed: ${c}`)}fe.delete(e.id);return}console.log(),console.log(`${L()} ${w.magenta("\u25C6 PLANNING")} ${r} ${e.summary.substring(0,60)}`),fe.add(e.id),yt(e,t,n).then(i=>{console.log(i?`${L()} ${w.green("\u2713")} Planning complete for ${r}`:`${L()} ${w.red("\u2717")} Planning failed for ${r}`)}).catch(i=>console.error(`${L()} ${w.red("\u2717")} Planning error for ${r}:`,i.message||i)).finally(()=>fe.delete(e.id))}async function Go(e,t){if(qe()>=t.maxWorkers)return;let o;try{if(o=(await O.post("/api/agent/claim",{taskId:e.id,agentId:t.agentId})).data,!o.claimed)return}catch{return}try{await O.post("/api/agent/started",{taskId:e.id,agentId:t.agentId})}catch{let E=w.cyan(e.id.slice(0,8));console.warn(`${L()} ${w.yellow("\u26A0")} Failed to report started for ${E}`)}let r=w.cyan(e.id.slice(0,8));console.log(),console.log(`${L()} ${w.blue("\u25B6 EXECUTING")} ${r} ${e.summary.substring(0,60)}`);let s=await Ko(),i=o.task||{id:e.id,summary:e.summary,description:e.description,jiraIssueKey:e.jiraIssueKey,workerModel:e.workerModel,workerProvider:e.workerProvider,githubRepo:e.githubRepo,scmProvider:e.scmProvider,skipManagerReview:e.skipManagerReview,deploymentEnabled:e.deploymentEnabled,improvementEnabled:e.improvementEnabled,qualityGateBypass:e.qualityGateBypass,standardSdkMode:e.standardSdkMode,parentTaskId:e.parentTaskId,taskNotes:e.taskNotes,githubPrUrl:e.githubPrUrl,githubPrNumber:e.githubPrNumber,executionPlanV2:e.executionPlanV2,jiraFields:e.jiraFields||{}},a=o.credentials;kt(i,t,s,a).catch(c=>console.error(`${L()} ${w.red("\u2717")} Spawn failed for ${r}:`,c.message||c))}async function Bo(e,t){let n=w.cyan(e.id.slice(0,8));$e.add(e.id);try{let o=await O.post("/api/agent/claim-manager",{taskId:e.id,agentId:t.agentId,action:e.managerAction});if(!o.data.claimed){$e.delete(e.id);return}let r=o.data.task,s=o.data.credentials||{},i=e.managerAction==="analyze_logs"?w.yellow("LOG ANALYSIS"):w.yellow("PR REVIEW");console.log(),console.log(`${L()} ${w.magenta("\u25C6 MANAGER")} ${i} ${n} ${e.summary.substring(0,60)}`);let a={id:e.id,summary:r?.summary||e.summary,description:r?.description||e.description,jiraIssueKey:r?.jiraIssueKey||e.jiraIssueKey,githubRepo:r?.githubRepo||e.githubRepo,scmProvider:r?.scmProvider||e.scmProvider,githubPrUrl:r?.githubPrUrl||e.githubPrUrl,githubPrNumber:r?.githubPrNumber||e.githubPrNumber,managerAction:e.managerAction};xt(a,t,s).then(()=>{console.log(`${L()} ${n} ${w.magenta("MGR")} ${w.green("\u2713")} Manager ${e.managerAction} dispatched`)}).catch(c=>{console.error(`${L()} ${n} ${w.magenta("MGR")} ${w.red("\u2717")} Manager spawn failed:`,c.message||c)}).finally(()=>$e.delete(e.id))}catch(o){$e.delete(e.id);let r=o;console.error(`${L()} ${n} ${w.red("\u2717")} Failed to claim manager task:`,r.message||String(o))}}var Ue=null,Fe=null;function Lt(){Ue&&(clearInterval(Ue),Ue=null),Fe&&(clearInterval(Fe),Fe=null)}function Dt(e){console.log(` ${w.dim("Polling every")} ${e.pollIntervalMs/1e3}s ${w.dim("\xB7 waiting for tasks...")}`),Nt(e),Ue=setInterval(()=>Nt(e),e.pollIntervalMs)}function Ut(e){Fe=setInterval(async()=>{let t=Pt(),n=Array.from(fe),o=Array.from($e),r=[...t,...n,...o];try{let s=await O.post("/api/agent/heartbeat",{agentId:e.agentId,activeTasks:r,agentVersion:ue}),i=s.data?.cancelledTasks;if(i&&i.length>0)for(let I of i)vt(I);let{updateAvailable:a,updateRequired:c,latestVersion:E}=s.data??{};c&&!De?(De=!0,console.log(`${L()} ${w.red("\u26A0 Agent update required")} (current: ${ue}, required: ${E})`),console.log(`${L()} ${w.yellow("Refusing new tasks until updated.")}`),await Me()?Ne():(console.log(`${L()} ${w.red("Auto-update failed.")} Run: npm install -g @workermill/agent@latest`),De=!1)):a&&!Mt&&!c&&(Mt=!0,console.log(`${L()} ${w.yellow(`Update available: ${E}`)} (current: ${ue}). Run: workermill-agent update`))}catch{}},e.heartbeatIntervalMs)}Re();async function Wo(e){console.log(),console.log(D.bold.cyan(" WorkerMill Remote Agent")),console.log(D.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(),Xe(e.apiUrl,e.apiKey);try{let t=await O.get("/api/agent/config"),n=t.data.maxConcurrentWorkers;n&&typeof n=="number"&&(e.maxWorkers=n),t.data.workerImageUrl&&(e.workerImage=t.data.workerImageUrl),console.log(` ${D.green("\u25CF")} Connected to ${D.cyan(e.apiUrl)}`),console.log(` ${D.dim("Agent:")} ${e.agentId}`),console.log(` ${D.dim("Workers:")} ${D.yellow(String(e.maxWorkers))} parallel`),console.log(` ${D.dim("Image:")} ${e.workerImage}`),console.log(` ${D.dim("SCM:")} ${t.data.scmProvider}`),console.log(` ${D.dim("Model:")} ${D.yellow(t.data.defaultWorkerModel)}`),console.log()}catch(t){let n=t;throw n.response?.status===401?new Error("Authentication failed. Check your API key."):new Error(`Failed to connect to WorkerMill API: ${n.message||String(t)}`)}try{let t=await O.post("/api/agent/register",{agentId:e.agentId,maxWorkers:e.maxWorkers,agentVersion:ue}),{updateAvailable:n,updateRequired:o,latestVersion:r}=t.data;o?(console.log(D.red(` \u26A0 Agent update required (current: ${ue}, required: ${r})`)),await Me()?Ne():console.log(D.yellow(" Auto-update failed. Run: npm install -g @workermill/agent@latest"))):n&&console.log(D.yellow(` Update available: ${r} (current: ${ue}). Run: workermill-agent update`))}catch{}return Dt(e),Ut(e),console.log(D.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` ${D.green("\u25CF")} Agent is running. ${D.dim("Press Ctrl+C to stop.")}`),console.log(),async()=>{console.log(),console.log(D.dim(" Shutting down...")),Lt();try{await O.post("/api/agent/deregister",{agentId:e.agentId})}catch{}await Ct(),console.log(` ${D.red("\u25CF")} Agent stopped.`)}}var Vo=typeof process<"u"&&process.argv[1]&&(process.argv[1].endsWith("/index.ts")||process.argv[1].endsWith("/index.js"));if(Vo){try{await import("dotenv/config")}catch{}let{loadConfig:e,validatePrerequisites:t}=await Promise.resolve().then(()=>(Re(),nt)),n=e();t(),console.log(D.dim(" Prerequisites validated."));let o=await Wo(n);process.on("SIGINT",async()=>{await o(),process.exit(0)}),process.on("SIGTERM",async()=>{await o(),process.exit(0)})}export{ge as findClaudePath,ot as getSystemInfo,et as loadConfig,Ze as loadConfigFromFile,Wo as startAgent,tt as validatePrerequisites};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workermill/agent",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "WorkerMill Remote Agent - Run AI workers locally with your Claude Max subscription",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",