@segosolutions/auto-task 1.7.5 → 1.7.6

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 (2) hide show
  1. package/dist/index.mjs +11 -11
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -56,7 +56,7 @@ ${Yc(s)}`,i=[];for(let a of Am){let c=Dt.join(s,a),u=Im(c);u!==null&&i.push({pat
56
56
 
57
57
  [... truncated ...]`):t.push(i),t.push("")}return t.push("---"),t.push(""),t.push("## Instructions"),t.push(""),t.push("Please work on this task. Implement the required changes according to the acceptance criteria."),t.push(""),e&&(t.push("**IMPORTANT - Context Already Provided:**"),t.push("- Project structure and key files are shown above - DO NOT run `find`, `ls`, or re-read these files"),t.push("- Start implementing immediately using the pre-loaded context"),t.push("- Only read additional files if specifically needed for implementation"),t.push("")),t.push("**Work efficiently:**"),t.push("- Focus only on what's needed to meet the acceptance criteria"),t.push("- Avoid unnecessary exploration or refactoring beyond the scope"),t.push("- Make targeted file reads instead of scanning the entire codebase"),t.push("- If you have enough context, proceed with implementation"),t.push(""),t.push('When you have completed the task, output "TASK_COMPLETE" on its own line.'),t.push('If you encounter issues that prevent completion, output "TASK_BLOCKED: <reason>" on its own line.'),t.join(`
58
58
  `)}async function Hr(s,e={}){let{timeoutMs:t=12e5,verbose:i=!0,workingDirectory:a,onEvent:c}=e,u=a||process.cwd(),p;if(Zc(u))try{p=Qc(u),i&&console.log("[Agent] Generated pre-loaded context:",{fileTreeLines:p.fileTree.split(`
59
- `).length,keyFilesCount:p.keyFiles.length})}catch(k){i&&console.warn("[Agent] Failed to generate pre-loaded context:",k)}let g=Nm(s,p),m=Date.now(),b="",w=!1;i&&(console.log("[Agent] Starting backlog task with Claude Agent SDK..."),console.log("[Agent] Task:",s.title),console.log("[Agent] Working directory:",u),console.log("[Agent] Model: claude-opus-4-5-20250929"));let E=new AbortController,S=setTimeout(()=>{w=!0,E.abort(),i&&console.log("[Agent] Timeout reached, aborting...")},t),A=(k,O)=>{c&&c({type:k,timestamp:Date.now(),data:O})};A("session_start",{task:s.title,cwd:u});try{let k=Br({prompt:g,options:{allowedTools:["Read","Edit","Glob","Grep","Bash","Write"],permissionMode:"acceptEdits",maxTurns:30}});for await(let O of k)switch(O.type){case"assistant":if(O.message.content){for(let Q of O.message.content)if(Q.type==="text")b+=Q.text,i&&process.stdout.write(Q.text);else if("name"in Q){let Z=Q;i&&console.log(`[Agent] Tool: ${Z.name}`),A("tool_start",{tool:Z.name,toolUseId:Z.id,input:Z.input})}}break;case"result":clearTimeout(S),i&&(console.log(""),console.log(`[Agent] Completed in ${O.duration_ms}ms`),console.log(`[Agent] Cost: $${O.total_cost_usd?.toFixed(4)||"N/A"}`));let N=b.includes("TASK_COMPLETE"),W=b.match(/TASK_BLOCKED:\s*(.+)/);return W?{success:!1,output:b,error:`Task blocked: ${W[1]}`,timedOut:!1,totalCostUsd:O.total_cost_usd}:{success:N||O.subtype==="success",output:b,timedOut:!1,totalCostUsd:O.total_cost_usd}}return clearTimeout(S),{success:!1,output:b,error:"Query stream ended without result",timedOut:w}}catch(k){clearTimeout(S);let O=k instanceof Error?k.message:String(k);return i&&console.error("[Agent] Error:",O),A("error",{error:O}),{success:!1,output:b,error:w?"Process timed out":O,timedOut:w}}}async function sl(){try{return!0}catch{return!1}}function nl(s){return s.includes("[CONVERSATIONAL SESSION]")}function rl(s){return s.includes("MODE: PLANNING")?"planning":s.includes("MODE: BUILD")||s.includes("MODE: WORK")?"work":s.includes("[MODE: PLANNING")?"planning":"work"}function Lm(s){let t=s.replace("[CONVERSATIONAL SESSION]","").trim().split(/\n---\nUser follow-up:\n/);if(t.length===1){let c=t[0].replace(/^User message:\s*/i,"").trim();return{initialMessage:c,followUps:[],latestMessage:c,isFollowUp:!1}}let i=t[0].replace(/^User message:\s*/i,"").trim(),a=t.slice(1).map(c=>c.trim());return{initialMessage:i,followUps:a,latestMessage:a[a.length-1],isFollowUp:!0}}function Dm(s,e){let t=["# PLANNING MODE - Read-Only Exploration & Discovery","","## CRITICAL: THIS IS A READ-ONLY SESSION","","**You CANNOT make any changes to the codebase in this mode.**","","Planning mode is strictly read-only:","- You have access to read-only tools: Read, Glob, Grep, WebSearch, WebFetch","- Bash is available but LIMITED to read-only commands only (ls, git status, git log, git diff, pwd, etc.)","- Edit, Write, and NotebookEdit tools are NOT available","- You CANNOT modify any files or execute write operations","- Your role is purely to explore, understand, and discuss","","---","","## YOUR ROLE","","You are a thoughtful collaborator helping a user explore and refine their ideas. Your job is to ask questions, discuss trade-offs, and help clarify requirements.","","## STRICT RULES FOR PLANNING MODE","","**DO NOT generate any tasks.** This is a strict requirement.","- Never output <task>JSON</task> blocks","- Never suggest specific task titles or estimates","- Focus entirely on understanding and exploration","","**Your goals in planning mode:**","1. Ask clarifying questions to understand the user's goals","2. Discuss trade-offs and alternatives","3. Help the user think through their idea thoroughly","4. Explore the codebase to understand context (read-only exploration)","","---","",`**Project Name:** ${s.projectContext.projectName}`];return s.projectContext.projectDescription&&t.push(`**Project Description:** ${s.projectContext.projectDescription}`),s.projectContext.techStack&&s.projectContext.techStack.length>0&&t.push(`**Tech Stack:** ${s.projectContext.techStack.join(", ")}`),t.push(""),t.push("---"),t.push(""),e.isFollowUp?(t.push("## Conversation History"),t.push(""),t.push(`**Initial request:** ${e.initialMessage}`),t.push(""),e.followUps.length>1&&(t.push("**Previous follow-ups:**"),e.followUps.slice(0,-1).forEach((i,a)=>{t.push(`${a+1}. ${i}`)}),t.push("")),t.push("---"),t.push(""),t.push("## Latest Message"),t.push(""),t.push(e.latestMessage)):(t.push("## User's Message"),t.push(""),t.push(e.initialMessage)),t.push(""),t.push("---"),t.push(""),t.push("## Mode Switch Suggestion"),t.push(""),t.push("When you believe the requirements are clear enough to create actionable tasks, suggest switching to Build mode by outputting:"),t.push(""),t.push("<suggest_build_mode>"),t.push("Your reasoning for why the requirements are now clear enough"),t.push("</suggest_build_mode>"),t.push(""),t.push("Only suggest this when:"),t.push("- You have a good understanding of what the user wants to accomplish"),t.push("- Key technical decisions have been discussed"),t.push("- The scope is reasonably defined"),t.push(""),t.push("---"),t.push(""),t.push("## REMINDER: READ-ONLY MODE"),t.push(""),t.push("You are in Planning mode which is READ-ONLY:"),t.push("- You can READ files and search the codebase to understand context"),t.push("- You can run read-only Bash commands (ls, git status, git log, git diff, pwd, etc.)"),t.push("- You CANNOT modify files, edit code, or run write operations"),t.push("- You CANNOT generate tasks - only explore and discuss"),t.push("- Any actual implementation happens later, after tasks are created in Build mode"),t.join(`
59
+ `).length,keyFilesCount:p.keyFiles.length})}catch(k){i&&console.warn("[Agent] Failed to generate pre-loaded context:",k)}let g=Nm(s,p),m=Date.now(),b="",w=!1;i&&(console.log("[Agent] Starting backlog task with Claude Agent SDK..."),console.log("[Agent] Task:",s.title),console.log("[Agent] Working directory:",u),console.log("[Agent] Model: claude-opus-4-5-20250929"));let E=new AbortController,S=setTimeout(()=>{w=!0,E.abort(),i&&console.log("[Agent] Timeout reached, aborting...")},t),A=(k,O)=>{c&&c({type:k,timestamp:Date.now(),data:O})};A("session_start",{task:s.title,cwd:u});try{let k=Br({prompt:g,options:{allowedTools:["Read","Edit","Glob","Grep","Bash","Write"],permissionMode:"acceptEdits",maxTurns:30}});for await(let O of k)switch(O.type){case"assistant":if(O.message.content){for(let Q of O.message.content)if(Q.type==="text")b+=Q.text,i&&process.stdout.write(Q.text);else if("name"in Q){let Z=Q;i&&console.log(`[Agent] Tool: ${Z.name}`),A("tool_start",{tool:Z.name,toolUseId:Z.id,input:Z.input})}}break;case"result":clearTimeout(S),i&&(console.log(""),console.log(`[Agent] Completed in ${O.duration_ms}ms`),console.log(`[Agent] Cost: $${O.total_cost_usd?.toFixed(4)||"N/A"}`));let N=b.includes("TASK_COMPLETE"),W=b.match(/TASK_BLOCKED:\s*(.+)/);return W?{success:!1,output:b,error:`Task blocked: ${W[1]}`,timedOut:!1,totalCostUsd:O.total_cost_usd,inputTokens:O.usage?.input_tokens,outputTokens:O.usage?.output_tokens}:{success:N||O.subtype==="success",output:b,timedOut:!1,totalCostUsd:O.total_cost_usd,inputTokens:O.usage?.input_tokens,outputTokens:O.usage?.output_tokens}}return clearTimeout(S),{success:!1,output:b,error:"Query stream ended without result",timedOut:w}}catch(k){clearTimeout(S);let O=k instanceof Error?k.message:String(k);return i&&console.error("[Agent] Error:",O),A("error",{error:O}),{success:!1,output:b,error:w?"Process timed out":O,timedOut:w}}}async function sl(){try{return!0}catch{return!1}}function nl(s){return s.includes("[CONVERSATIONAL SESSION]")}function rl(s){return s.includes("MODE: PLANNING")?"planning":s.includes("MODE: BUILD")||s.includes("MODE: WORK")?"work":s.includes("[MODE: PLANNING")?"planning":"work"}function Lm(s){let t=s.replace("[CONVERSATIONAL SESSION]","").trim().split(/\n---\nUser follow-up:\n/);if(t.length===1){let c=t[0].replace(/^User message:\s*/i,"").trim();return{initialMessage:c,followUps:[],latestMessage:c,isFollowUp:!1}}let i=t[0].replace(/^User message:\s*/i,"").trim(),a=t.slice(1).map(c=>c.trim());return{initialMessage:i,followUps:a,latestMessage:a[a.length-1],isFollowUp:!0}}function Dm(s,e){let t=["# PLANNING MODE - Read-Only Exploration & Discovery","","## CRITICAL: THIS IS A READ-ONLY SESSION","","**You CANNOT make any changes to the codebase in this mode.**","","Planning mode is strictly read-only:","- You have access to read-only tools: Read, Glob, Grep, WebSearch, WebFetch","- Bash is available but LIMITED to read-only commands only (ls, git status, git log, git diff, pwd, etc.)","- Edit, Write, and NotebookEdit tools are NOT available","- You CANNOT modify any files or execute write operations","- Your role is purely to explore, understand, and discuss","","---","","## YOUR ROLE","","You are a thoughtful collaborator helping a user explore and refine their ideas. Your job is to ask questions, discuss trade-offs, and help clarify requirements.","","## STRICT RULES FOR PLANNING MODE","","**DO NOT generate any tasks.** This is a strict requirement.","- Never output <task>JSON</task> blocks","- Never suggest specific task titles or estimates","- Focus entirely on understanding and exploration","","**Your goals in planning mode:**","1. Ask clarifying questions to understand the user's goals","2. Discuss trade-offs and alternatives","3. Help the user think through their idea thoroughly","4. Explore the codebase to understand context (read-only exploration)","","---","",`**Project Name:** ${s.projectContext.projectName}`];return s.projectContext.projectDescription&&t.push(`**Project Description:** ${s.projectContext.projectDescription}`),s.projectContext.techStack&&s.projectContext.techStack.length>0&&t.push(`**Tech Stack:** ${s.projectContext.techStack.join(", ")}`),t.push(""),t.push("---"),t.push(""),e.isFollowUp?(t.push("## Conversation History"),t.push(""),t.push(`**Initial request:** ${e.initialMessage}`),t.push(""),e.followUps.length>1&&(t.push("**Previous follow-ups:**"),e.followUps.slice(0,-1).forEach((i,a)=>{t.push(`${a+1}. ${i}`)}),t.push("")),t.push("---"),t.push(""),t.push("## Latest Message"),t.push(""),t.push(e.latestMessage)):(t.push("## User's Message"),t.push(""),t.push(e.initialMessage)),t.push(""),t.push("---"),t.push(""),t.push("## Mode Switch Suggestion"),t.push(""),t.push("When you believe the requirements are clear enough to create actionable tasks, suggest switching to Build mode by outputting:"),t.push(""),t.push("<suggest_build_mode>"),t.push("Your reasoning for why the requirements are now clear enough"),t.push("</suggest_build_mode>"),t.push(""),t.push("Only suggest this when:"),t.push("- You have a good understanding of what the user wants to accomplish"),t.push("- Key technical decisions have been discussed"),t.push("- The scope is reasonably defined"),t.push(""),t.push("---"),t.push(""),t.push("## REMINDER: READ-ONLY MODE"),t.push(""),t.push("You are in Planning mode which is READ-ONLY:"),t.push("- You can READ files and search the codebase to understand context"),t.push("- You can run read-only Bash commands (ls, git status, git log, git diff, pwd, etc.)"),t.push("- You CANNOT modify files, edit code, or run write operations"),t.push("- You CANNOT generate tasks - only explore and discuss"),t.push("- Any actual implementation happens later, after tasks are created in Build mode"),t.join(`
60
60
  `)}function Um(s,e){let t=["# BUILD MODE - Read-Only Task Creation","","## CRITICAL: THIS IS A READ-ONLY SESSION","","**You CANNOT make any changes to the codebase in this mode.**","","Build mode is strictly read-only:","- You have access to read-only tools: Read, Glob, Grep, WebSearch, WebFetch","- Bash is available but LIMITED to read-only commands only (ls, git status, git log, git diff, pwd, etc.)","- Edit, Write, and NotebookEdit tools are NOT available","- You CANNOT modify any files or execute write operations","- Your role is to explore, understand, and CREATE TASK DEFINITIONS","- Actual implementation happens later, when tasks are executed separately","","---","","## YOUR ROLE","","You are helping create actionable development tasks. Your goal is to generate well-structured task definitions based on the user's requirements.","",`**Project Name:** ${s.projectContext.projectName}`];return s.projectContext.projectDescription&&t.push(`**Project Description:** ${s.projectContext.projectDescription}`),s.projectContext.techStack&&s.projectContext.techStack.length>0&&t.push(`**Tech Stack:** ${s.projectContext.techStack.join(", ")}`),t.push(""),t.push("---"),t.push(""),e.isFollowUp?(t.push("## Conversation History"),t.push(""),t.push("This is an ongoing conversation. Here is what was discussed:"),t.push(""),t.push(`**Initial request:** ${e.initialMessage}`),t.push(""),e.followUps.length>1&&(t.push("**Previous follow-ups:**"),e.followUps.slice(0,-1).forEach((i,a)=>{t.push(`${a+1}. ${i}`)}),t.push("")),t.push("---"),t.push(""),t.push("## Latest Message (respond to this)"),t.push(""),t.push(e.latestMessage),t.push(""),t.push("---"),t.push(""),t.push("## Instructions"),t.push(""),t.push("This is a FOLLOW-UP message. DO NOT start over or re-introduce yourself."),t.push("Simply respond directly to their latest message, building on the context of the conversation."),t.push(""),t.push("If you already explored the codebase in a previous turn, you do NOT need to explore it again unless the user asks about something new."),t.push(""),t.push("**Refinement mode:** If the user is providing feedback on suggested tasks, immediately update or regenerate the tasks with their input.")):(t.push("## User's Message"),t.push(""),t.push(e.initialMessage),t.push(""),t.push("---"),t.push(""),t.push("## Instructions"),t.push(""),t.push("You have access to the full codebase, so explore it to understand the project structure."),t.push(""),t.push("**Your goal is to generate actionable tasks within this first exchange.** Don't spend time asking qualifying questions - use the codebase and project context to make informed assumptions. Briefly explore relevant files if needed, then propose concrete tasks."),t.push(""),t.push("The client should feel like their work is being shaped into actionable items immediately, not that they're entering an interview process.")),t.push(""),t.push("## Task Generation"),t.push(""),t.push("**IMPORTANT: Prioritize generating tasks quickly.** Clients want to feel like work is starting immediately."),t.push(""),t.push("- Generate initial task suggestions within your FIRST response whenever possible"),t.push("- Make reasonable assumptions based on the project context and codebase - don't ask questions you can answer yourself"),t.push("- If something is unclear, make a sensible default assumption, note it in the task, and let the client refine it"),t.push("- Only ask 1-2 critical questions if absolutely essential - prefer to suggest tasks with noted assumptions"),t.push("- Tasks can always be refined through follow-up conversation - the goal is momentum, not perfection"),t.push(""),t.push("When you identify work that should become a task, output it in this format:"),t.push("<task>"),t.push("{"),t.push(' "title": "Task title",'),t.push(' "description": "What needs to be done",'),t.push(' "acceptanceCriteria": ["Criterion 1", "Criterion 2"],'),t.push(' "estimatedHours": 4,'),t.push(' "priority": "MEDIUM",'),t.push(' "type": "FEATURE",'),t.push(' "technicalNotes": "Implementation notes (include any assumptions made)",'),t.push(' "aiConfidence": 0.85'),t.push("}"),t.push("</task>"),t.push(""),t.push('Include an "assumptions" section in technicalNotes if you made decisions the client might want to change.'),t.push(`After suggesting tasks, invite the client to refine: "These tasks are ready for review. Let me know if you'd like to adjust scope, estimates, or approach."`),t.push(""),t.push("Valid priority values: LOW, MEDIUM, HIGH, URGENT"),t.push("Valid type values: FEATURE, BUG, ENHANCEMENT, DOCUMENTATION, DESIGN, TECHNICAL_DEBT"),t.push(""),t.push("---"),t.push(""),t.push("## REMINDER: READ-ONLY MODE"),t.push(""),t.push("You are in Build mode which is READ-ONLY:"),t.push("- You can READ files and search the codebase to understand context"),t.push("- You can run read-only Bash commands (ls, git status, git log, git diff, pwd, etc.)"),t.push("- You CANNOT modify files, edit code, or run write operations"),t.push("- You CAN generate task definitions using <task>JSON</task> format"),t.push("- Any actual implementation happens later, when tasks are executed separately"),t.push("- DO NOT attempt to implement the changes yourself - only define the tasks"),t.join(`
61
61
  `)}function jm(s,e="work"){let t=Lm(s.description);return e==="planning"?Dm(s,t):Um(s,t)}var qm=["LOW","MEDIUM","HIGH","URGENT"],Bm=["FEATURE","BUG","ENHANCEMENT","DOCUMENTATION","DESIGN","TECHNICAL_DEBT"];function $m(s){let e=[],t=s.includes("<task>")&&s.includes("</task>");if(console.log(`[Agent] parseTasksFromOutput: hasTaskTags=${t}, outputLength=${s.length}`),!t)return console.log("[Agent] No <task> tags found in output"),e;let i=/<task>([\s\S]*?)<\/task>/g,a,c=0;for(;(a=i.exec(s))!==null;){c++;let u=a[1].trim();console.log(`[Agent] Found task block #${c}, parsing JSON...`);try{let p=u.replace(/^```json\s*/i,"").replace(/^```\s*/i,"").replace(/\s*```$/i,"").trim(),g=p.match(/\{[\s\S]*\}/);g&&(p=g[0]);let m=JSON.parse(p);if(!m.title||typeof m.title!="string"){console.warn(`[Agent] Task #${c} missing or invalid title, skipping`);continue}let b=qm.includes(m.priority?.toUpperCase?.())?m.priority.toUpperCase():"MEDIUM",w=Bm.includes(m.type?.toUpperCase?.())?m.type.toUpperCase():"FEATURE",E=Array.isArray(m.acceptanceCriteria)?m.acceptanceCriteria.filter(k=>typeof k=="string").map(k=>k.trim()):[],S=Math.max(0,Number(m.estimatedHours)||4),A=Math.min(1,Math.max(0,Number(m.aiConfidence||m.confidence)||.8));console.log(`[Agent] Parsed task #${c}: "${m.title}" (${b}, ${w}, ${S}h)`),e.push({title:String(m.title).trim(),description:String(m.description||"").trim(),acceptanceCriteria:E,estimatedHours:S,priority:b,type:w,technicalNotes:m.technicalNotes?String(m.technicalNotes).trim():void 0,aiConfidence:A})}catch(p){console.error(`[Agent] Failed to parse task #${c} JSON:`,p instanceof Error?p.message:p),console.error("[Agent] Raw task content (first 500 chars):",u.substring(0,500))}}return console.log(`[Agent] parseTasksFromOutput: returning ${e.length} valid tasks (found ${c} total blocks)`),e}async function il(s,e={}){let{timeoutMs:t=3e5,verbose:i=!0,workingDirectory:a,onEvent:c,mode:u="work"}=e,p=a||process.cwd(),g=jm(s,u),m="",b=!1;i&&(console.log("[Agent] Starting conversational session..."),console.log("[Agent] Mode:",u),console.log("[Agent] Working directory:",p));let w=new AbortController,E=setTimeout(()=>{b=!0,w.abort(),i&&console.log("[Agent] Timeout reached, aborting...")},t),S=(Y,X)=>{c&&c({type:Y,timestamp:Date.now(),data:X})};S("session_start",{cwd:p,mode:u});let A=["Read","Glob","Grep","WebSearch","WebFetch","Bash"],k=["Edit","Write","NotebookEdit"],O=["ls","pwd","tree","find","which","whereis","file","stat","git status","git log","git diff","git branch","git show","git blame","git remote","git tag","git stash list","git rev-parse","npm list","npm ls","npm outdated","npm view","pnpm list","pnpm ls","pnpm outdated","yarn list","yarn info","whoami","hostname","uname","date","uptime","env","printenv","wc","sort","uniq","head","tail","cat","less","more","ps","top","htop","du","df"],N=[/[;]/,/&&/,/\|\|/,/[`]/,/\$\(/,/>\s*[^&]/,/>>/,/\bsudo\b/,/\brm\b/,/\bmv\b/,/\bcp\b/,/\bmkdir\b/,/\btouch\b/,/\bchmod\b/,/\bchown\b/,/\bcurl\b.*-[dXPo]/,/\bwget\b/,/\bnpm\s+(install|i|uninstall|remove|update|publish|link)/,/\bpnpm\s+(install|i|add|remove|update|publish|link)/,/\byarn\s+(add|remove|install|upgrade|publish|link)/,/\bgit\s+(commit|push|pull|merge|rebase|reset|checkout|add|rm|stash\s+(?!list))/,/\bkill\b/,/\bpkill\b/],W=Y=>{let X=Y.trim();for(let te of N)if(te.test(X))return{allowed:!1,reason:"Bash command contains restricted pattern. Only read-only commands are allowed in conversation sessions."};let ce=X.split(/\s+/)[0];return O.some(te=>{if(X.startsWith(te+" ")||X===te)return!0;let Ge=te.split(" ")[0];return ce===Ge&&te.split(" ").length===1})?{allowed:!0}:{allowed:!1,reason:`Bash command "${ce}" is not in the read-only whitelist. Only read-only commands (ls, git status, git log, etc.) are allowed in conversation sessions.`}},Q=[...A];i&&(console.log(`[Agent] Mode: ${u}, Allowed tools: ${Q.join(", ")}`),console.log(`[Agent] Restricted tools (not available): ${k.join(", ")}`));let Z=(Y,X)=>{if(Y==="Bash"){let ce=X;return ce?.command?W(ce.command):{allowed:!1,reason:"Bash command is empty or missing."}}return k.includes(Y)?{allowed:!1,reason:`Tool "${Y}" is restricted in ${u} mode. Conversation sessions are read-only.`}:Q.includes(Y)?{allowed:!0}:{allowed:!1,reason:`Tool "${Y}" is not in the allowed list for ${u} mode.`}};try{let Y=Br({prompt:g,options:{allowedTools:Q,permissionMode:"acceptEdits",maxTurns:30}});for await(let X of Y)switch(X.type){case"assistant":if(X.message.content){for(let ie of X.message.content)if(ie.type==="text")m+=ie.text,i&&process.stdout.write(ie.text),S("assistant_message",{text:ie.text,uuid:X.uuid});else if(ie.type==="thinking"){let te=ie;i&&console.log(`[Agent] Thinking: ${te.thinking.substring(0,100)}...`),S("thinking",{text:te.thinking,uuid:X.uuid})}else if(ie.type==="tool_use"||"name"in ie){let te=ie,Ge=Z(te.name,te.input);Ge.allowed||(console.error(`[Agent] SECURITY VIOLATION: ${Ge.reason}`),console.error(`[Agent] Tool attempt details: ${JSON.stringify({tool:te.name,mode:u,toolUseId:te.id,timestamp:new Date().toISOString()})}`),S("error",{error:Ge.reason,securityViolation:!0,tool:te.name,mode:u})),i&&console.log(`[Agent] Tool: ${te.name}${Ge.allowed?"":" (RESTRICTED - should not execute)"}`),S("tool_start",{tool:te.name,toolUseId:te.id,input:te.input})}}break;case"user":if(X.message.content){for(let ie of X.message.content)if(typeof ie=="object"&&ie!==null&&"type"in ie&&ie.type==="tool_result"){let te=ie;S("tool_end",{toolUseId:te.tool_use_id,isError:te.is_error||!1,hasContent:!!te.content})}}break;case"result":clearTimeout(E),i&&(console.log(""),console.log(`[Agent] Completed in ${X.duration_ms}ms`),console.log(`[Agent] Cost: $${X.total_cost_usd?.toFixed(4)||"N/A"}`));let ce=$m(m);return i&&ce.length>0&&console.log(`[Agent] Found ${ce.length} task(s) in output`),S("result",{success:!0,output:m,tasks:ce,costUsd:X.total_cost_usd}),{success:!0,output:m,tasks:ce,timedOut:!1,totalCostUsd:X.total_cost_usd}}return clearTimeout(E),{success:!1,output:m,tasks:[],error:"Query stream ended without result",timedOut:b}}catch(Y){clearTimeout(E);let X=Y instanceof Error?Y.message:String(Y);return i&&console.error("[Agent] Error:",X),S("error",{error:X}),{success:!1,output:m,tasks:[],error:b?"Process timed out":X,timedOut:b}}}var Bd=wr(qd(),1),zn=class s{baseUrl;apiKey;projectId;monitorId;ably=null;channel=null;isRunning=!1;isStopping=!1;heartbeatInterval=null;static HEARTBEAT_INTERVAL_MS=3e4;onNewWorkHandler=null;onConnectedHandler=null;onErrorHandler=null;onDisconnectedHandler=null;constructor(e,t,i,a){this.baseUrl=e.replace(/\/$/,""),this.apiKey=t,this.projectId=i,this.monitorId=a}async start(){if(this.isRunning){console.log("[AblyWorkClient] Already running");return}console.log(`[AblyWorkClient] Starting Ably client for project ${this.projectId}`),this.isRunning=!0,this.isStopping=!1;try{this.ably=new Bd.default.Realtime({authCallback:(e,t)=>{this.fetchToken().then(i=>t(null,i)).catch(i=>t(i,null))},disconnectedRetryTimeout:1e3,suspendedRetryTimeout:5e3}),this.ably.connection.on("connected",()=>{console.log("[AblyWorkClient] Connected to Ably"),this.onConnectedHandler&&this.onConnectedHandler({projectId:this.projectId,projectName:"",monitorId:this.monitorId,timestamp:new Date().toISOString()})}),this.ably.connection.on("disconnected",()=>{console.log("[AblyWorkClient] Disconnected from Ably (will auto-reconnect)")}),this.ably.connection.on("suspended",()=>{console.log("[AblyWorkClient] Connection suspended"),this.onDisconnectedHandler&&this.onDisconnectedHandler()}),this.ably.connection.on("failed",e=>{console.error("[AblyWorkClient] Connection failed:",e.reason),this.onErrorHandler&&this.onErrorHandler(new Error(`Ably connection failed: ${e.reason?.message||"Unknown error"}`))}),this.channel=this.ably.channels.get(`project:${this.projectId}:work`),this.channel.subscribe("new_request",e=>{let t=e.data;console.log("[AblyWorkClient] Received work notification:",t),this.onNewWorkHandler&&!this.isStopping&&Promise.resolve(this.onNewWorkHandler(t)).catch(i=>{console.error("[AblyWorkClient] Error in new work handler:",i)})}),console.log(`[AblyWorkClient] Subscribed to project:${this.projectId}:work channel`),await this.waitForConnection(),this.startHeartbeat()}catch(e){throw console.error("[AblyWorkClient] Failed to start:",e),this.isRunning=!1,this.onErrorHandler&&this.onErrorHandler(e instanceof Error?e:new Error(String(e))),e}}async fetchToken(){let e=`${this.baseUrl}/api/ably/token`,t=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"ngrok-skip-browser-warning":"true"},body:JSON.stringify({projectId:this.projectId,monitorId:this.monitorId})});if(!t.ok){let a=await t.text();throw new Error(`Failed to get Ably token (${t.status}): ${a}`)}let{tokenRequest:i}=await t.json();return console.log("[AblyWorkClient] Got scoped Ably token (registered as active)"),i}startHeartbeat(){this.stopHeartbeat(),this.sendHeartbeat(),this.heartbeatInterval=setInterval(()=>{this.sendHeartbeat()},s.HEARTBEAT_INTERVAL_MS),console.log(`[AblyWorkClient] Started heartbeat (every ${s.HEARTBEAT_INTERVAL_MS/1e3}s)`)}stopHeartbeat(){this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=null)}async sendHeartbeat(){if(!(!this.isRunning||this.isStopping))try{let e=`${this.baseUrl}/api/projects/${this.projectId}/monitor/heartbeat`,t=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,"ngrok-skip-browser-warning":"true"},body:JSON.stringify({monitorId:this.monitorId})});t.ok||console.error(`[AblyWorkClient] Heartbeat failed (${t.status})`)}catch(e){this.isRunning&&!this.isStopping&&console.error("[AblyWorkClient] Heartbeat error:",e)}}waitForConnection(e=1e4){return new Promise((t,i)=>{if(!this.ably){i(new Error("Ably client not initialized"));return}if(this.ably.connection.state==="connected"){t();return}let a=setTimeout(()=>{i(new Error("Connection timeout"))},e),c=u=>{u.current==="connected"?(clearTimeout(a),this.ably?.connection.off(c),t()):u.current==="failed"&&(clearTimeout(a),this.ably?.connection.off(c),i(new Error(`Connection failed: ${u.reason?.message||"Unknown error"}`)))};this.ably.connection.on(c)})}stop(){console.log("[AblyWorkClient] Stopping..."),this.isStopping=!0,this.isRunning=!1,this.stopHeartbeat(),this.channel&&(this.channel.unsubscribe(),this.channel=null),this.ably&&(this.ably.close(),this.ably=null),this.onDisconnectedHandler&&this.onDisconnectedHandler()}isConnected(){return this.isRunning&&!this.isStopping&&this.ably?.connection.state==="connected"}onNewWork(e){this.onNewWorkHandler=e}onConnected(e){this.onConnectedHandler=e}onError(e){this.onErrorHandler=e}onDisconnected(e){this.onDisconnectedHandler=e}};import{exec as uw}from"child_process";import{promisify as hw}from"util";var $d=hw(uw);async function ct(s,e){try{return await $d(s,{cwd:e,maxBuffer:10485760})}catch(t){let i=t;if(i.stdout!==void 0||i.stderr!==void 0)return{stdout:i.stdout||"",stderr:i.stderr||""};throw t}}async function dw(s){try{return await ct("git rev-parse --is-inside-work-tree",s),!0}catch{return!1}}async function Ao(s){let{stdout:e}=await ct("git status --porcelain",s),t=[],i=[],a=[],c=e.trim().split(`
62
62
  `).filter(Boolean);for(let u of c){let p=u[0],g=u[1],m=u.substring(3).trim();p!==" "&&p!=="?"&&t.push(m),g!==" "&&g!=="?"&&i.push(m),p==="?"&&g==="?"&&a.push(m)}return{hasChanges:t.length>0||i.length>0||a.length>0,staged:t,unstaged:i,untracked:a}}async function fw(s){let{stdout:e}=await ct("git rev-parse --abbrev-ref HEAD",s);return e.trim()}async function pw(s){let{stdout:e}=await ct("git rev-parse --short HEAD",s);return e.trim()}async function gw(s){await ct("git add .",s)}async function mw(s,e,t){try{if(!(await Ao(s)).hasChanges)return{success:!1,filesCommitted:[],error:"No changes to commit"};await gw(s);let c=(await Ao(s)).staged,u=e;t&&(u=`${e}
@@ -65,25 +65,25 @@ Task-ID: ${t}`);let p=u.replace(/'/g,"'\\''");return await ct(`git commit -m '${
65
65
 
66
66
  Automatically committed by Sego Auto-Task Monitor`;console.log("[Git] Committing changes...");let u=await mw(s,c,e.taskId);if(!u.success)return t.error=u.error,t;if(t.committed=!0,t.commitHash=u.commitHash,t.filesCommitted=u.filesCommitted,console.log(`[Git] Committed ${u.filesCommitted.length} files (${u.commitHash})`),e.autoPush){console.log("[Git] Pushing to remote...");let p=await yw(s);p.success?(t.pushed=!0,console.log(`[Git] Pushed to ${p.remote}/${p.branch}`)):(console.error(`[Git] Push failed: ${p.error}`),t.error=`Commit succeeded but push failed: ${p.error}`)}return t}import{exec as bw}from"child_process";import{promisify as vw}from"util";var ww=vw(bw);function Cw(s){return s.some(e=>e==="prisma/schema.prisma"||e.endsWith("/schema.prisma")||e.includes("prisma/schema.prisma"))}async function Ew(s,e={}){let{skipGenerate:t=!0,acceptDataLoss:i=!0}=e;try{let a=[];t&&a.push("--skip-generate"),i&&a.push("--accept-data-loss");let c=`npx prisma db push ${a.join(" ")}`;console.log(`[Schema] Running: ${c}`);let{stdout:u,stderr:p}=await ww(c,{cwd:s,maxBuffer:10*1024*1024,timeout:12e4}),g=u+(p?`
67
67
  ${p}`:"");return g.includes("Your database is now in sync")||g.includes("Database is already in sync")?(console.log("[Schema] Database schema synced successfully"),{success:!0,applied:!0,output:g.trim()}):{success:!1,applied:!1,error:"Unexpected output from prisma db push",output:g.trim()}}catch(a){let c=a,u=[c.stdout,c.stderr].filter(Boolean).join(`
68
- `);return u.includes("Your database is now in sync")||u.includes("Database is already in sync")?(console.log("[Schema] Database schema synced successfully"),{success:!0,applied:!0,output:u.trim()}):(console.error("[Schema] Failed to apply schema:",c.message),{success:!1,applied:!1,error:c.message||"Unknown error applying schema",output:u.trim()})}}async function Hd(s,e,t={}){return Cw(e)?(console.log("[Schema] Prisma schema changes detected, syncing database..."),t.dryRun?(console.log("[Schema] Dry run mode - skipping actual schema push"),{success:!0,applied:!1,output:"Dry run - schema push skipped"}):Ew(s,{skipGenerate:!0,acceptDataLoss:t.acceptDataLoss??!0})):{success:!0,applied:!1}}import{randomBytes as kw}from"crypto";import{createServer as Sw}from"http";var Kn=class{client;config;isProcessing=!1;isProcessingClientRequest=!1;isProcessingBacklogTask=!1;isRunning=!1;pollTimeout=null;ablyClient=null;monitorId;backlogTaskQueue=[];lastActivityTime=Date.now();idleCheckInterval=null;healthServer=null;startedAt=Date.now();constructor(e){this.config=e,this.client=new Xs(e.apiUrl,e.apiKey,e.projectId),this.monitorId=`monitor-${kw(8).toString("hex")}`}updateActivityTime(){this.lastActivityTime=Date.now()}startHealthServer(){let e=this.config.healthPort;this.healthServer=Sw((t,i)=>{if(t.url==="/health"||t.url==="/"){let a=Math.floor((Date.now()-this.startedAt)/1e3),c=Math.floor((Date.now()-this.lastActivityTime)/1e3),u={status:"healthy",monitorId:this.monitorId,projectId:this.config.projectId,uptime:a,idleSeconds:c,idleTimeoutMinutes:this.config.idleTimeoutMinutes,isProcessing:this.isProcessing||this.isProcessingClientRequest||this.isProcessingBacklogTask,queueLength:this.backlogTaskQueue.length,timestamp:Date.now()};i.writeHead(200,{"Content-Type":"application/json"}),i.end(JSON.stringify(u))}else i.writeHead(404,{"Content-Type":"application/json"}),i.end(JSON.stringify({error:"Not found"}))}),this.healthServer.listen(e,()=>{console.log(`[Monitor] Health server listening on port ${e}`)}),this.healthServer.on("error",t=>{console.error("[Monitor] Health server error:",t)})}startIdleChecker(){if(this.config.idleTimeoutMinutes<=0){console.log("[Monitor] Idle timeout disabled");return}let e=this.config.idleTimeoutMinutes*60*1e3;console.log(`[Monitor] Idle timeout: ${this.config.idleTimeoutMinutes} minutes`),this.idleCheckInterval=setInterval(()=>{let t=Date.now()-this.lastActivityTime,i=t/6e4;this.isProcessing||this.isProcessingClientRequest||this.isProcessingBacklogTask||this.backlogTaskQueue.length>0||t>=e&&(console.log(`[Monitor] Idle timeout reached (${i.toFixed(1)} minutes)`),console.log("[Monitor] Initiating graceful shutdown..."),this.stop(),setTimeout(()=>{console.log("[Monitor] Exiting due to idle timeout"),process.exit(0)},2e3))},6e4)}async start(){if(this.isRunning){console.log("[Monitor] Already running");return}if(console.log("[Monitor] Starting auto-task monitor..."),console.log(`[Monitor] Monitor ID: ${this.monitorId}`),console.log(`[Monitor] API URL: ${this.config.apiUrl}`),console.log(`[Monitor] Project ID: ${this.config.projectId||"all projects"}`),console.log(`[Monitor] Poll interval: ${this.config.pollIntervalMs}ms`),console.log(`[Monitor] Task timeout: ${this.config.timeoutMs}ms`),console.log(`[Monitor] Real-time (Ably) enabled: ${this.config.sseEnabled}`),console.log(`[Monitor] Dry run: ${this.config.dryRun}`),console.log(`[Monitor] Working directory: ${this.config.workingDirectory||process.cwd()}`),console.log(`[Monitor] Use Agent SDK: ${this.config.useAgentSdk}`),console.log(`[Monitor] Stream progress: ${this.config.streamProgress}`),console.log(`[Monitor] Conversation only: ${this.config.conversationOnly}`),console.log(`[Monitor] Idle timeout: ${this.config.idleTimeoutMinutes>0?`${this.config.idleTimeoutMinutes} minutes`:"disabled"}`),console.log(`[Monitor] Health port: ${this.config.healthPort}`),!await this.client.validateAuth())throw new Error("API key validation failed");console.log("[Monitor] API key validated successfully"),this.isRunning=!0,this.startedAt=Date.now(),this.lastActivityTime=Date.now(),this.startHealthServer(),this.startIdleChecker(),this.config.sseEnabled&&this.config.projectId?await this.startAbly():this.config.sseEnabled&&!this.config.projectId&&console.log("[Monitor] Real-time disabled - project ID required for client request monitoring"),this.config.conversationOnly?console.log("[Monitor] Conversation-only mode - skipping auto-task polling"):await this.poll()}async startAbly(){try{console.log(`[Monitor] Connecting to Ably for project: ${this.config.projectId}`),this.ablyClient=new zn(this.config.apiUrl,this.config.apiKey,this.config.projectId,this.monitorId),this.ablyClient.onConnected(e=>{console.log(`[Monitor] Ably connected to project: ${e.projectId}`),console.log(`[Monitor] Monitor ID: ${e.monitorId}`),console.log("[Monitor] Ready to receive work notifications")}),this.ablyClient.onNewWork(async e=>{console.log(`[Monitor] Received work notification: ${e.type} for ${e.requestId}`);try{let t=await this.client.getClientRequest(e.requestId);if(!t){console.error(`[Monitor] Client request ${e.requestId} not found`);return}let i={id:t.id,projectId:t.projectId,description:t.description,channel:t.channel,createdById:t.createdById,projectContext:t.projectContext||{projectName:"Unknown Project"}};await this.processClientRequest(i)}catch(t){console.error(`[Monitor] Error fetching client request ${e.requestId}:`,t)}}),this.ablyClient.onError(e=>{console.error("[Monitor] Ably error:",e.message)}),this.ablyClient.onDisconnected(()=>{console.log("[Monitor] Ably disconnected")}),await this.ablyClient.start()}catch(e){throw console.error("[Monitor] Failed to start Ably:",e),e}}async processClientRequest(e){if(this.isProcessingClientRequest){console.log("[Monitor] Already processing a client request, skipping");return}let t=nl(e.description);if(console.log(""),console.log("=".repeat(60)),console.log(`[Monitor] Processing client request: ${e.id}`),console.log(`[Monitor] Project: ${e.projectContext.projectName}`),console.log(`[Monitor] Mode: ${t?"Conversational":"Analysis"}`),console.log(`[Monitor] Description: ${e.description.substring(0,200)}${e.description.length>200?"...":""}`),console.log(`[Monitor] Timeout: ${this.config.clientRequestTimeoutMs}ms`),console.log(`[Monitor] SDK Mode: ${this.config.useAgentSdk?"Agent SDK":"CLI subprocess"}`),console.log("=".repeat(60)),console.log(""),this.config.dryRun){console.log("[Monitor] Dry run - skipping client request processing");return}if(this.config.conversationOnly&&!t){console.log("[Monitor] Conversation-only mode - skipping non-conversational request analysis");return}this.isProcessingClientRequest=!0;let i=Date.now(),a=Date.now(),c="session_start",u=null;this.config.streamProgress&&(u=setInterval(async()=>{let p=Date.now()-a,g=Date.now()-i;if(p>5e3)try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"processing",timestamp:Date.now(),message:c==="tool_end"?`Analyzing results... (${Math.round(g/1e3)}s)`:`Processing... (${Math.round(g/1e3)}s)`,emoji:"\u23F3",data:{elapsedMs:g,lastEventType:c,timeSinceLastEventMs:p}})}catch{}},5e3));try{console.log(`[Monitor] Running Claude for ${t?"conversation":"analysis"}...`),console.log("[Monitor] Claude output will stream below:"),console.log("-".repeat(60));let p=this.config.streamProgress?async w=>{a=Date.now(),c=w.type;let E=$r(w);console.log(`[Monitor] ${E.emoji} ${E.message}`);try{await this.client.sendAgentProgress(e.id,this.monitorId,E)}catch(S){console.error("[Monitor] Failed to send progress event:",S)}}:void 0;if(t&&this.config.useAgentSdk){let w=rl(e.description);console.log(`[Monitor] Conversation mode: ${w}`);let E=await il(e,{timeoutMs:this.config.clientRequestTimeoutMs,verbose:!0,workingDirectory:this.config.workingDirectory,onEvent:p,mode:w});console.log("-".repeat(60));let S=Date.now()-i;if(E.totalCostUsd&&console.log(`[Monitor] Agent cost: $${E.totalCostUsd.toFixed(4)}`),E.timedOut){console.log("[Monitor] Claude timed out for conversation");try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"error",timestamp:Date.now(),message:"Conversation timed out",emoji:"\u23F1\uFE0F",data:{error:"timeout",message:"The agent took too long to respond"}})}catch(A){console.error("[Monitor] Failed to send timeout event:",A)}return}if(!E.success){console.log(`[Monitor] Conversation error: ${E.error}`);try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"error",timestamp:Date.now(),message:E.error||"Unknown error",emoji:"\u274C",data:{error:E.error}})}catch(A){console.error("[Monitor] Failed to send error event:",A)}return}if(console.log(`[Monitor] Conversation completed (${S}ms)`),console.log(`[Monitor] Result has ${E.tasks?.length||0} tasks`),E.tasks&&E.tasks.length>0){console.log(`[Monitor] Sending ${E.tasks.length} suggested task(s) to frontend`);for(let A of E.tasks)try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"task_suggested",timestamp:Date.now(),message:`Task suggested: ${A.title}`,emoji:"\u{1F4CB}",data:{task:A}}),console.log(`[Monitor] \u{1F4CB} Sent task: ${A.title}`)}catch(k){console.error("[Monitor] Failed to send task_suggested event:",k)}}try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"result",timestamp:Date.now(),message:`Conversation completed with ${E.tasks?.length||0} task(s)`,emoji:"\u2705",data:{success:!0,tasksCount:E.tasks?.length||0,processingTimeMs:S}}),console.log("[Monitor] \u2705 Sent result event")}catch(A){console.error("[Monitor] Failed to send result event:",A)}return}let g;this.config.useAgentSdk?(g=await tl(e,{timeoutMs:this.config.clientRequestTimeoutMs,verbose:!0,workingDirectory:this.config.workingDirectory,onEvent:p}),g.totalCostUsd&&console.log(`[Monitor] Agent cost: $${g.totalCostUsd.toFixed(4)}`)):g=await Kc(e,this.config.clientRequestTimeoutMs,{verbose:!0}),console.log("-".repeat(60));let m=Date.now()-i;if(g.timedOut){console.log("[Monitor] Claude timed out for client request"),await this.client.reportAnalysisFailure(e.id,this.monitorId,"Analysis timed out");return}if(!g.success||!g.analysis){console.log(`[Monitor] Claude analysis failed: ${g.error}`),await this.client.reportAnalysisFailure(e.id,this.monitorId,g.error||"Unknown error");return}console.log("[Monitor] Submitting analysis...");let b=await this.client.submitAnalysis(e.id,this.monitorId,g.analysis,m,{costUsd:g.totalCostUsd,tokensUsed:g.usage?g.usage.inputTokens+g.usage.outputTokens:void 0,inputTokens:g.usage?.inputTokens,outputTokens:g.usage?.outputTokens});console.log(`[Monitor] Analysis submitted successfully - ${b.tasksCount} tasks suggested (${m}ms)`)}catch(p){console.error("[Monitor] Error processing client request:",p);try{await this.client.reportAnalysisFailure(e.id,this.monitorId,p instanceof Error?p.message:"Unknown error")}catch(g){console.error("[Monitor] Failed to report analysis failure:",g)}}finally{u&&clearInterval(u),this.isProcessingClientRequest=!1,this.updateActivityTime()}}async handleTaskAvailable(e){if(console.log(`[Monitor] Task available: ${e.id} - ${e.title}`),this.config.conversationOnly){console.log("[Monitor] Conversation-only mode - skipping task processing");return}this.backlogTaskQueue.some(t=>t.id===e.id)||(this.backlogTaskQueue.push(e),console.log(`[Monitor] Added to queue (${this.backlogTaskQueue.length} tasks in queue)`)),await this.processNextBacklogTask()}async processNextBacklogTask(){if(this.isProcessingBacklogTask){console.log("[Monitor] Already processing a backlog task");return}if(this.backlogTaskQueue.length===0){console.log("[Monitor] No backlog tasks in queue");return}let e=this.backlogTaskQueue.shift();if(console.log(""),console.log("=".repeat(60)),console.log(`[Monitor] Processing backlog task: ${e.id}`),console.log(`[Monitor] Title: ${e.title}`),console.log(`[Monitor] Type: ${e.type} | Priority: ${e.priority}`),console.log(`[Monitor] Estimated hours: ${e.estimatedHours||"N/A"}`),console.log(`[Monitor] Mode: ${this.config.useAgentSdk?"Agent SDK":"CLI subprocess"}`),console.log("=".repeat(60)),console.log(""),this.config.dryRun){console.log("[Monitor] Dry run - skipping backlog task processing"),this.backlogTaskQueue.length>0&&await this.processNextBacklogTask();return}this.isProcessingBacklogTask=!0;let t=Date.now(),i=async(c,u)=>{if(!this.config.streamProgress)return;let p={type:"phase",timestamp:Date.now(),message:u,emoji:{claiming:"\u{1F4CB}",analyzing:"\u{1F50D}",implementing:"\u{1F6E0}\uFE0F",testing:"\u{1F9EA}",committing:"\u{1F4BE}","schema-migration":"\u{1F5C4}\uFE0F",completed:"\u2705",error:"\u274C"}[c]||"\u{1F504}",data:{phase:c,message:u}};console.log(`[Monitor] ${p.emoji} ${u}`);try{await this.client.sendTaskAgentProgress(e.id,this.monitorId,p)}catch(g){console.error("[Monitor] Failed to send phase event:",g)}},a="claiming";try{console.log("[Monitor] Claiming task..."),await i("claiming","Claiming task..."),await this.client.claimTask(e.id,this.monitorId),console.log("[Monitor] Task claimed successfully"),console.log("[Monitor] Running Claude for backlog task..."),console.log("[Monitor] Claude output will stream below:"),console.log("-".repeat(60)),await i("analyzing","Analyzing codebase..."),a="analyzing";let c;this.config.useAgentSdk?(c=await Hr(e,{timeoutMs:this.config.timeoutMs,verbose:!0,workingDirectory:this.config.workingDirectory,onEvent:this.config.streamProgress?async m=>{if(m.type==="tool_start"){let w=m.data;if((w.tool==="Edit"||w.tool==="Write")&&a==="analyzing"&&(a="implementing",await i("implementing","Implementing changes...")),w.tool==="Bash"&&a==="implementing"){let S=w.input?.command||"";(S.includes("test")||S.includes("jest")||S.includes("pytest")||S.includes("npm run test")||S.includes("pnpm test")||S.includes("yarn test"))&&(a="testing",await i("testing","Running tests..."))}}let b=$r(m);console.log(`[Monitor] ${b.emoji} ${b.message}`);try{await this.client.sendTaskAgentProgress(e.id,this.monitorId,b)}catch(w){console.error("[Monitor] Failed to send progress event:",w)}}:void 0}),c.totalCostUsd&&console.log(`[Monitor] Agent cost: $${c.totalCostUsd.toFixed(4)}`)):c=await Jc(e,this.config.timeoutMs,{verbose:!0,workingDirectory:this.config.workingDirectory}),console.log("-".repeat(60));let u=Date.now()-t;if(c.timedOut){console.log("[Monitor] Claude timed out for backlog task"),await i("error","Task processing timed out"),await this.client.failBacklogTask(e.id,this.monitorId,"Task processing timed out",!0);return}if(!c.success){console.log(`[Monitor] Claude failed: ${c.error}`),await i("error",c.error||"Task processing failed"),await this.client.failBacklogTask(e.id,this.monitorId,c.error||"Unknown error",!0);return}let p,g=[];if(this.config.autoCommit){await i("committing","Verifying build and committing changes..."),console.log("[Monitor] Running build verification and auto-commit...");let m=this.config.workingDirectory||process.cwd(),b=await Ro(m,{taskId:e.id,taskTitle:e.title,autoCommit:this.config.autoCommit,autoPush:this.config.autoPush,verifyBuild:!0});if(b.buildFailed){console.error("[Monitor] Build verification failed - NOT pushing broken code"),console.error(`[Monitor] Build error: ${b.error}`),await i("error","Build verification failed - code not committed"),await this.client.failBacklogTask(e.id,this.monitorId,`Build verification failed: ${b.error?.substring(0,500)||"Unknown build error"}`,!0);return}if(b.committed){if(p=b.commitHash,g=b.filesCommitted,console.log(`[Monitor] Auto-commit successful: ${p} (${g.length} files)`),this.config.autoSchemaMigration&&g.length>0){await i("schema-migration","Applying database schema changes...");let w=await Hd(m,g,{dryRun:this.config.dryRun,acceptDataLoss:!0});w.applied?console.log("[Monitor] Schema migration applied successfully"):w.error&&console.warn(`[Monitor] Schema migration failed: ${w.error}`)}b.pushed?console.log("[Monitor] Auto-push successful"):this.config.autoPush&&b.error&&console.warn(`[Monitor] Auto-push failed: ${b.error}`)}else b.error&&b.error!=="No changes to commit"?console.warn(`[Monitor] Auto-commit failed: ${b.error}`):console.log("[Monitor] No changes to commit")}console.log("[Monitor] Completing task..."),await this.client.completeBacklogTask(e.id,this.monitorId,{summary:c.output?.substring(0,1e3)||"Task completed by auto-monitor",filesChanged:g.length>0?g:void 0,commitHash:p},{costUsd:c.totalCostUsd,tokensUsed:void 0}),await i("completed","Task completed successfully"),console.log(`[Monitor] Task ${e.id} completed successfully (${u}ms)`),await this.triggerContainerRebuild()}catch(c){console.error("[Monitor] Error processing backlog task:",c);let u=c instanceof Error?c.message:"Unknown error";await i("error",u);try{await this.client.failBacklogTask(e.id,this.monitorId,u,!0)}catch(p){console.error("[Monitor] Failed to report task failure:",p)}}finally{this.isProcessingBacklogTask=!1,this.updateActivityTime(),this.backlogTaskQueue.length>0&&(console.log(`[Monitor] ${this.backlogTaskQueue.length} more tasks in queue, processing next...`),await this.processNextBacklogTask())}}async triggerContainerRebuild(){try{console.log("[Monitor] Triggering container rebuild...");let e=await fetch("http://localhost:3000/api/rebuild",{method:"POST",headers:{"Content-Type":"application/json"}});if(e.ok){let t=await e.json();console.log(`[Monitor] Rebuild completed in ${t.duration}ms`)}else console.warn("[Monitor] Rebuild request failed:",e.status)}catch(e){console.warn("[Monitor] Could not trigger rebuild:",e)}}stop(){console.log("[Monitor] Stopping..."),this.isRunning=!1,this.pollTimeout&&(clearTimeout(this.pollTimeout),this.pollTimeout=null),this.ablyClient&&(this.ablyClient.stop(),this.ablyClient=null),this.idleCheckInterval&&(clearInterval(this.idleCheckInterval),this.idleCheckInterval=null),this.healthServer&&(this.healthServer.close(),this.healthServer=null)}async poll(){if(this.isRunning){try{this.isProcessing||await this.checkForTask()}catch(e){console.error("[Monitor] Poll error:",e)}this.isRunning&&(this.pollTimeout=setTimeout(()=>this.poll(),this.config.pollIntervalMs))}}async checkForTask(){console.log("[Monitor] Checking for eligible tasks...");let e=await this.client.getEligibleTask();if(!e){console.log("[Monitor] No eligible tasks found");return}if(console.log(`[Monitor] Found eligible task: ${e.title} (confidence: ${e.aiConfidence})`),this.config.dryRun){console.log("[Monitor] Dry run - skipping task processing");return}await this.processTask(e)}async processTask(e){this.isProcessing=!0;try{console.log(`[Monitor] Starting task: ${e.id}`);let t=await this.client.startTask(e.id);console.log(`[Monitor] Task started, run ID: ${t.runId}`),console.log("[Monitor] Invoking Claude...");let i;if(this.config.useAgentSdk){let a={id:e.id,projectId:e.project.id,title:e.title,description:e.description,type:e.type||"FEATURE",status:e.status,priority:e.priority||"MEDIUM",estimatedHours:e.estimatedHours?parseFloat(e.estimatedHours):null,acceptanceCriteria:e.acceptanceCriteria||[],technicalNotes:e.technicalNotes,clientRequestId:null,createdById:e.createdBy?.id||"",projectContext:{projectName:e.project.name,knowledgeBase:e.project.knowledgeBase||void 0}};i=await Hr(a,{timeoutMs:this.config.timeoutMs,maxTurns:this.config.maxTurns,workingDirectory:this.config.workingDirectory,verbose:!0}),i.totalCostUsd&&console.log(`[Monitor] Agent cost: $${i.totalCostUsd.toFixed(4)}`)}else i=await Vc(e,this.config.timeoutMs);if(i.timedOut){console.log("[Monitor] Claude timed out"),await this.handleFailure(t.runId,e,"TIMEOUT",i.output,"Task processing timed out");return}if(!i.success){console.log(`[Monitor] Claude failed: ${i.error}`),await this.handleFailure(t.runId,e,"FAILED",i.output,i.error);return}console.log("[Monitor] Claude completed successfully"),await this.handleSuccess(t.runId,e,i.output,i.totalCostUsd)}catch(t){console.error("[Monitor] Error processing task:",t)}finally{this.isProcessing=!1}}async handleSuccess(e,t,i,a){let c="";if(this.config.autoCommit){console.log("[Monitor] Running build verification and auto-commit...");let g=this.config.workingDirectory||process.cwd(),m=await Ro(g,{taskId:t.id,taskTitle:t.title,autoCommit:this.config.autoCommit,autoPush:this.config.autoPush,verifyBuild:!0});if(m.buildFailed){console.error("[Monitor] Build verification failed - NOT pushing broken code"),c=`
68
+ `);return u.includes("Your database is now in sync")||u.includes("Database is already in sync")?(console.log("[Schema] Database schema synced successfully"),{success:!0,applied:!0,output:u.trim()}):(console.error("[Schema] Failed to apply schema:",c.message),{success:!1,applied:!1,error:c.message||"Unknown error applying schema",output:u.trim()})}}async function Hd(s,e,t={}){return Cw(e)?(console.log("[Schema] Prisma schema changes detected, syncing database..."),t.dryRun?(console.log("[Schema] Dry run mode - skipping actual schema push"),{success:!0,applied:!1,output:"Dry run - schema push skipped"}):Ew(s,{skipGenerate:!0,acceptDataLoss:t.acceptDataLoss??!0})):{success:!0,applied:!1}}import{randomBytes as kw}from"crypto";import{createServer as Sw}from"http";var Kn=class{client;config;isProcessing=!1;isProcessingClientRequest=!1;isProcessingBacklogTask=!1;isRunning=!1;pollTimeout=null;ablyClient=null;monitorId;backlogTaskQueue=[];lastActivityTime=Date.now();idleCheckInterval=null;healthServer=null;startedAt=Date.now();constructor(e){this.config=e,this.client=new Xs(e.apiUrl,e.apiKey,e.projectId),this.monitorId=`monitor-${kw(8).toString("hex")}`}updateActivityTime(){this.lastActivityTime=Date.now()}startHealthServer(){let e=this.config.healthPort;this.healthServer=Sw((t,i)=>{if(t.url==="/health"||t.url==="/"){let a=Math.floor((Date.now()-this.startedAt)/1e3),c=Math.floor((Date.now()-this.lastActivityTime)/1e3),u={status:"healthy",monitorId:this.monitorId,projectId:this.config.projectId,uptime:a,idleSeconds:c,idleTimeoutMinutes:this.config.idleTimeoutMinutes,isProcessing:this.isProcessing||this.isProcessingClientRequest||this.isProcessingBacklogTask,queueLength:this.backlogTaskQueue.length,timestamp:Date.now()};i.writeHead(200,{"Content-Type":"application/json"}),i.end(JSON.stringify(u))}else i.writeHead(404,{"Content-Type":"application/json"}),i.end(JSON.stringify({error:"Not found"}))}),this.healthServer.listen(e,()=>{console.log(`[Monitor] Health server listening on port ${e}`)}),this.healthServer.on("error",t=>{console.error("[Monitor] Health server error:",t)})}startIdleChecker(){if(this.config.idleTimeoutMinutes<=0){console.log("[Monitor] Idle timeout disabled");return}let e=this.config.idleTimeoutMinutes*60*1e3;console.log(`[Monitor] Idle timeout: ${this.config.idleTimeoutMinutes} minutes`),this.idleCheckInterval=setInterval(()=>{let t=Date.now()-this.lastActivityTime,i=t/6e4;this.isProcessing||this.isProcessingClientRequest||this.isProcessingBacklogTask||this.backlogTaskQueue.length>0||t>=e&&(console.log(`[Monitor] Idle timeout reached (${i.toFixed(1)} minutes)`),console.log("[Monitor] Initiating graceful shutdown..."),this.stop(),setTimeout(()=>{console.log("[Monitor] Exiting due to idle timeout"),process.exit(0)},2e3))},6e4)}async start(){if(this.isRunning){console.log("[Monitor] Already running");return}if(console.log("[Monitor] Starting auto-task monitor..."),console.log(`[Monitor] Monitor ID: ${this.monitorId}`),console.log(`[Monitor] API URL: ${this.config.apiUrl}`),console.log(`[Monitor] Project ID: ${this.config.projectId||"all projects"}`),console.log(`[Monitor] Poll interval: ${this.config.pollIntervalMs}ms`),console.log(`[Monitor] Task timeout: ${this.config.timeoutMs}ms`),console.log(`[Monitor] Real-time (Ably) enabled: ${this.config.sseEnabled}`),console.log(`[Monitor] Dry run: ${this.config.dryRun}`),console.log(`[Monitor] Working directory: ${this.config.workingDirectory||process.cwd()}`),console.log(`[Monitor] Use Agent SDK: ${this.config.useAgentSdk}`),console.log(`[Monitor] Stream progress: ${this.config.streamProgress}`),console.log(`[Monitor] Conversation only: ${this.config.conversationOnly}`),console.log(`[Monitor] Idle timeout: ${this.config.idleTimeoutMinutes>0?`${this.config.idleTimeoutMinutes} minutes`:"disabled"}`),console.log(`[Monitor] Health port: ${this.config.healthPort}`),!await this.client.validateAuth())throw new Error("API key validation failed");console.log("[Monitor] API key validated successfully"),this.isRunning=!0,this.startedAt=Date.now(),this.lastActivityTime=Date.now(),this.startHealthServer(),this.startIdleChecker(),this.config.sseEnabled&&this.config.projectId?await this.startAbly():this.config.sseEnabled&&!this.config.projectId&&console.log("[Monitor] Real-time disabled - project ID required for client request monitoring"),this.config.conversationOnly?console.log("[Monitor] Conversation-only mode - skipping auto-task polling"):await this.poll()}async startAbly(){try{console.log(`[Monitor] Connecting to Ably for project: ${this.config.projectId}`),this.ablyClient=new zn(this.config.apiUrl,this.config.apiKey,this.config.projectId,this.monitorId),this.ablyClient.onConnected(e=>{console.log(`[Monitor] Ably connected to project: ${e.projectId}`),console.log(`[Monitor] Monitor ID: ${e.monitorId}`),console.log("[Monitor] Ready to receive work notifications")}),this.ablyClient.onNewWork(async e=>{console.log(`[Monitor] Received work notification: ${e.type} for ${e.requestId}`);try{let t=await this.client.getClientRequest(e.requestId);if(!t){console.error(`[Monitor] Client request ${e.requestId} not found`);return}let i={id:t.id,projectId:t.projectId,description:t.description,channel:t.channel,createdById:t.createdById,projectContext:t.projectContext||{projectName:"Unknown Project"}};await this.processClientRequest(i)}catch(t){console.error(`[Monitor] Error fetching client request ${e.requestId}:`,t)}}),this.ablyClient.onError(e=>{console.error("[Monitor] Ably error:",e.message)}),this.ablyClient.onDisconnected(()=>{console.log("[Monitor] Ably disconnected")}),await this.ablyClient.start()}catch(e){throw console.error("[Monitor] Failed to start Ably:",e),e}}async processClientRequest(e){if(this.isProcessingClientRequest){console.log("[Monitor] Already processing a client request, skipping");return}let t=nl(e.description);if(console.log(""),console.log("=".repeat(60)),console.log(`[Monitor] Processing client request: ${e.id}`),console.log(`[Monitor] Project: ${e.projectContext.projectName}`),console.log(`[Monitor] Mode: ${t?"Conversational":"Analysis"}`),console.log(`[Monitor] Description: ${e.description.substring(0,200)}${e.description.length>200?"...":""}`),console.log(`[Monitor] Timeout: ${this.config.clientRequestTimeoutMs}ms`),console.log(`[Monitor] SDK Mode: ${this.config.useAgentSdk?"Agent SDK":"CLI subprocess"}`),console.log("=".repeat(60)),console.log(""),this.config.dryRun){console.log("[Monitor] Dry run - skipping client request processing");return}if(this.config.conversationOnly&&!t){console.log("[Monitor] Conversation-only mode - skipping non-conversational request analysis");return}this.isProcessingClientRequest=!0;let i=Date.now(),a=Date.now(),c="session_start",u=null;this.config.streamProgress&&(u=setInterval(async()=>{let p=Date.now()-a,g=Date.now()-i;if(p>5e3)try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"processing",timestamp:Date.now(),message:c==="tool_end"?`Analyzing results... (${Math.round(g/1e3)}s)`:`Processing... (${Math.round(g/1e3)}s)`,emoji:"\u23F3",data:{elapsedMs:g,lastEventType:c,timeSinceLastEventMs:p}})}catch{}},5e3));try{console.log(`[Monitor] Running Claude for ${t?"conversation":"analysis"}...`),console.log("[Monitor] Claude output will stream below:"),console.log("-".repeat(60));let p=this.config.streamProgress?async w=>{a=Date.now(),c=w.type;let E=$r(w);console.log(`[Monitor] ${E.emoji} ${E.message}`);try{await this.client.sendAgentProgress(e.id,this.monitorId,E)}catch(S){console.error("[Monitor] Failed to send progress event:",S)}}:void 0;if(t&&this.config.useAgentSdk){let w=rl(e.description);console.log(`[Monitor] Conversation mode: ${w}`);let E=await il(e,{timeoutMs:this.config.clientRequestTimeoutMs,verbose:!0,workingDirectory:this.config.workingDirectory,onEvent:p,mode:w});console.log("-".repeat(60));let S=Date.now()-i;if(E.totalCostUsd&&console.log(`[Monitor] Agent cost: $${E.totalCostUsd.toFixed(4)}`),E.timedOut){console.log("[Monitor] Claude timed out for conversation");try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"error",timestamp:Date.now(),message:"Conversation timed out",emoji:"\u23F1\uFE0F",data:{error:"timeout",message:"The agent took too long to respond"}})}catch(A){console.error("[Monitor] Failed to send timeout event:",A)}return}if(!E.success){console.log(`[Monitor] Conversation error: ${E.error}`);try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"error",timestamp:Date.now(),message:E.error||"Unknown error",emoji:"\u274C",data:{error:E.error}})}catch(A){console.error("[Monitor] Failed to send error event:",A)}return}if(console.log(`[Monitor] Conversation completed (${S}ms)`),console.log(`[Monitor] Result has ${E.tasks?.length||0} tasks`),E.tasks&&E.tasks.length>0){console.log(`[Monitor] Sending ${E.tasks.length} suggested task(s) to frontend`);for(let A of E.tasks)try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"task_suggested",timestamp:Date.now(),message:`Task suggested: ${A.title}`,emoji:"\u{1F4CB}",data:{task:A}}),console.log(`[Monitor] \u{1F4CB} Sent task: ${A.title}`)}catch(k){console.error("[Monitor] Failed to send task_suggested event:",k)}}try{await this.client.sendAgentProgress(e.id,this.monitorId,{type:"result",timestamp:Date.now(),message:`Conversation completed with ${E.tasks?.length||0} task(s)`,emoji:"\u2705",data:{success:!0,tasksCount:E.tasks?.length||0,processingTimeMs:S}}),console.log("[Monitor] \u2705 Sent result event")}catch(A){console.error("[Monitor] Failed to send result event:",A)}return}let g;this.config.useAgentSdk?(g=await tl(e,{timeoutMs:this.config.clientRequestTimeoutMs,verbose:!0,workingDirectory:this.config.workingDirectory,onEvent:p}),g.totalCostUsd&&console.log(`[Monitor] Agent cost: $${g.totalCostUsd.toFixed(4)}`)):g=await Kc(e,this.config.clientRequestTimeoutMs,{verbose:!0}),console.log("-".repeat(60));let m=Date.now()-i;if(g.timedOut){console.log("[Monitor] Claude timed out for client request"),await this.client.reportAnalysisFailure(e.id,this.monitorId,"Analysis timed out");return}if(!g.success||!g.analysis){console.log(`[Monitor] Claude analysis failed: ${g.error}`),await this.client.reportAnalysisFailure(e.id,this.monitorId,g.error||"Unknown error");return}console.log("[Monitor] Submitting analysis...");let b=await this.client.submitAnalysis(e.id,this.monitorId,g.analysis,m,{costUsd:g.totalCostUsd,tokensUsed:g.usage?g.usage.inputTokens+g.usage.outputTokens:void 0,inputTokens:g.usage?.inputTokens,outputTokens:g.usage?.outputTokens});console.log(`[Monitor] Analysis submitted successfully - ${b.tasksCount} tasks suggested (${m}ms)`)}catch(p){console.error("[Monitor] Error processing client request:",p);try{await this.client.reportAnalysisFailure(e.id,this.monitorId,p instanceof Error?p.message:"Unknown error")}catch(g){console.error("[Monitor] Failed to report analysis failure:",g)}}finally{u&&clearInterval(u),this.isProcessingClientRequest=!1,this.updateActivityTime()}}async handleTaskAvailable(e){if(console.log(`[Monitor] Task available: ${e.id} - ${e.title}`),this.config.conversationOnly){console.log("[Monitor] Conversation-only mode - skipping task processing");return}this.backlogTaskQueue.some(t=>t.id===e.id)||(this.backlogTaskQueue.push(e),console.log(`[Monitor] Added to queue (${this.backlogTaskQueue.length} tasks in queue)`)),await this.processNextBacklogTask()}async processNextBacklogTask(){if(this.isProcessingBacklogTask){console.log("[Monitor] Already processing a backlog task");return}if(this.backlogTaskQueue.length===0){console.log("[Monitor] No backlog tasks in queue");return}let e=this.backlogTaskQueue.shift();if(console.log(""),console.log("=".repeat(60)),console.log(`[Monitor] Processing backlog task: ${e.id}`),console.log(`[Monitor] Title: ${e.title}`),console.log(`[Monitor] Type: ${e.type} | Priority: ${e.priority}`),console.log(`[Monitor] Estimated hours: ${e.estimatedHours||"N/A"}`),console.log(`[Monitor] Mode: ${this.config.useAgentSdk?"Agent SDK":"CLI subprocess"}`),console.log("=".repeat(60)),console.log(""),this.config.dryRun){console.log("[Monitor] Dry run - skipping backlog task processing"),this.backlogTaskQueue.length>0&&await this.processNextBacklogTask();return}this.isProcessingBacklogTask=!0;let t=Date.now(),i=async(c,u)=>{if(!this.config.streamProgress)return;let p={type:"phase",timestamp:Date.now(),message:u,emoji:{claiming:"\u{1F4CB}",analyzing:"\u{1F50D}",implementing:"\u{1F6E0}\uFE0F",testing:"\u{1F9EA}",committing:"\u{1F4BE}","schema-migration":"\u{1F5C4}\uFE0F",completed:"\u2705",error:"\u274C"}[c]||"\u{1F504}",data:{phase:c,message:u}};console.log(`[Monitor] ${p.emoji} ${u}`);try{await this.client.sendTaskAgentProgress(e.id,this.monitorId,p)}catch(g){console.error("[Monitor] Failed to send phase event:",g)}},a="claiming";try{console.log("[Monitor] Claiming task..."),await i("claiming","Claiming task..."),await this.client.claimTask(e.id,this.monitorId),console.log("[Monitor] Task claimed successfully"),console.log("[Monitor] Running Claude for backlog task..."),console.log("[Monitor] Claude output will stream below:"),console.log("-".repeat(60)),await i("analyzing","Analyzing codebase..."),a="analyzing";let c;this.config.useAgentSdk?(c=await Hr(e,{timeoutMs:this.config.timeoutMs,verbose:!0,workingDirectory:this.config.workingDirectory,onEvent:this.config.streamProgress?async w=>{if(w.type==="tool_start"){let S=w.data;if((S.tool==="Edit"||S.tool==="Write")&&a==="analyzing"&&(a="implementing",await i("implementing","Implementing changes...")),S.tool==="Bash"&&a==="implementing"){let k=S.input?.command||"";(k.includes("test")||k.includes("jest")||k.includes("pytest")||k.includes("npm run test")||k.includes("pnpm test")||k.includes("yarn test"))&&(a="testing",await i("testing","Running tests..."))}}let E=$r(w);console.log(`[Monitor] ${E.emoji} ${E.message}`);try{await this.client.sendTaskAgentProgress(e.id,this.monitorId,E)}catch(S){console.error("[Monitor] Failed to send progress event:",S)}}:void 0}),c.totalCostUsd&&console.log(`[Monitor] Agent cost: $${c.totalCostUsd.toFixed(4)}`)):c=await Jc(e,this.config.timeoutMs,{verbose:!0,workingDirectory:this.config.workingDirectory}),console.log("-".repeat(60));let u=Date.now()-t;if(c.timedOut){console.log("[Monitor] Claude timed out for backlog task"),await i("error","Task processing timed out"),await this.client.failBacklogTask(e.id,this.monitorId,"Task processing timed out",!0);return}if(!c.success){console.log(`[Monitor] Claude failed: ${c.error}`),await i("error",c.error||"Task processing failed"),await this.client.failBacklogTask(e.id,this.monitorId,c.error||"Unknown error",!0);return}let p,g=[];if(this.config.autoCommit){await i("committing","Verifying build and committing changes..."),console.log("[Monitor] Running build verification and auto-commit...");let w=this.config.workingDirectory||process.cwd(),E=await Ro(w,{taskId:e.id,taskTitle:e.title,autoCommit:this.config.autoCommit,autoPush:this.config.autoPush,verifyBuild:!0});if(E.buildFailed){console.error("[Monitor] Build verification failed - NOT pushing broken code"),console.error(`[Monitor] Build error: ${E.error}`),await i("error","Build verification failed - code not committed"),await this.client.failBacklogTask(e.id,this.monitorId,`Build verification failed: ${E.error?.substring(0,500)||"Unknown build error"}`,!0);return}if(E.committed){if(p=E.commitHash,g=E.filesCommitted,console.log(`[Monitor] Auto-commit successful: ${p} (${g.length} files)`),this.config.autoSchemaMigration&&g.length>0){await i("schema-migration","Applying database schema changes...");let S=await Hd(w,g,{dryRun:this.config.dryRun,acceptDataLoss:!0});S.applied?console.log("[Monitor] Schema migration applied successfully"):S.error&&console.warn(`[Monitor] Schema migration failed: ${S.error}`)}E.pushed?console.log("[Monitor] Auto-push successful"):this.config.autoPush&&E.error&&console.warn(`[Monitor] Auto-push failed: ${E.error}`)}else E.error&&E.error!=="No changes to commit"?console.warn(`[Monitor] Auto-commit failed: ${E.error}`):console.log("[Monitor] No changes to commit")}console.log("[Monitor] Completing task..."),await this.client.completeBacklogTask(e.id,this.monitorId,{summary:c.output?.substring(0,1e3)||"Task completed by auto-monitor",filesChanged:g.length>0?g:void 0,commitHash:p},{costUsd:c.totalCostUsd,tokensUsed:(c.inputTokens||0)+(c.outputTokens||0)||void 0});let m=(c.inputTokens||0)+(c.outputTokens||0),b=c.totalCostUsd?` (cost: $${c.totalCostUsd.toFixed(4)}${m?`, ${m.toLocaleString()} tokens`:""})`:"";await i("completed","Task completed successfully"),console.log(`[Monitor] Task ${e.id} completed successfully${b} (${u}ms)`),await this.triggerContainerRebuild()}catch(c){console.error("[Monitor] Error processing backlog task:",c);let u=c instanceof Error?c.message:"Unknown error";await i("error",u);try{await this.client.failBacklogTask(e.id,this.monitorId,u,!0)}catch(p){console.error("[Monitor] Failed to report task failure:",p)}}finally{this.isProcessingBacklogTask=!1,this.updateActivityTime(),this.backlogTaskQueue.length>0&&(console.log(`[Monitor] ${this.backlogTaskQueue.length} more tasks in queue, processing next...`),await this.processNextBacklogTask())}}async triggerContainerRebuild(){try{console.log("[Monitor] Triggering container rebuild...");let e=await fetch("http://localhost:3000/api/rebuild",{method:"POST",headers:{"Content-Type":"application/json"}});if(e.ok){let t=await e.json();console.log(`[Monitor] Rebuild completed in ${t.duration}ms`)}else console.warn("[Monitor] Rebuild request failed:",e.status)}catch(e){console.warn("[Monitor] Could not trigger rebuild:",e)}}stop(){console.log("[Monitor] Stopping..."),this.isRunning=!1,this.pollTimeout&&(clearTimeout(this.pollTimeout),this.pollTimeout=null),this.ablyClient&&(this.ablyClient.stop(),this.ablyClient=null),this.idleCheckInterval&&(clearInterval(this.idleCheckInterval),this.idleCheckInterval=null),this.healthServer&&(this.healthServer.close(),this.healthServer=null)}async poll(){if(this.isRunning){try{this.isProcessing||await this.checkForTask()}catch(e){console.error("[Monitor] Poll error:",e)}this.isRunning&&(this.pollTimeout=setTimeout(()=>this.poll(),this.config.pollIntervalMs))}}async checkForTask(){console.log("[Monitor] Checking for eligible tasks...");let e=await this.client.getEligibleTask();if(!e){console.log("[Monitor] No eligible tasks found");return}if(console.log(`[Monitor] Found eligible task: ${e.title} (confidence: ${e.aiConfidence})`),this.config.dryRun){console.log("[Monitor] Dry run - skipping task processing");return}await this.processTask(e)}async processTask(e){this.isProcessing=!0;try{console.log(`[Monitor] Starting task: ${e.id}`);let t=await this.client.startTask(e.id);console.log(`[Monitor] Task started, run ID: ${t.runId}`),console.log("[Monitor] Invoking Claude...");let i;if(this.config.useAgentSdk){let c={id:e.id,projectId:e.project.id,title:e.title,description:e.description,type:e.type||"FEATURE",status:e.status,priority:e.priority||"MEDIUM",estimatedHours:e.estimatedHours?parseFloat(e.estimatedHours):null,acceptanceCriteria:e.acceptanceCriteria||[],technicalNotes:e.technicalNotes,clientRequestId:null,createdById:e.createdBy?.id||"",projectContext:{projectName:e.project.name,knowledgeBase:e.project.knowledgeBase||void 0}};i=await Hr(c,{timeoutMs:this.config.timeoutMs,maxTurns:this.config.maxTurns,workingDirectory:this.config.workingDirectory,verbose:!0}),i.totalCostUsd&&console.log(`[Monitor] Agent cost: $${i.totalCostUsd.toFixed(4)}`)}else i=await Vc(e,this.config.timeoutMs);if(i.timedOut){console.log("[Monitor] Claude timed out"),await this.handleFailure(t.runId,e,"TIMEOUT",i.output,"Task processing timed out");return}if(!i.success){console.log(`[Monitor] Claude failed: ${i.error}`),await this.handleFailure(t.runId,e,"FAILED",i.output,i.error);return}console.log("[Monitor] Claude completed successfully");let a=(i.inputTokens||0)+(i.outputTokens||0);await this.handleSuccess(t.runId,e,i.output,i.totalCostUsd,a||void 0)}catch(t){console.error("[Monitor] Error processing task:",t)}finally{this.isProcessing=!1}}async handleSuccess(e,t,i,a,c){let u="";if(this.config.autoCommit){console.log("[Monitor] Running build verification and auto-commit...");let m=this.config.workingDirectory||process.cwd(),b=await Ro(m,{taskId:t.id,taskTitle:t.title,autoCommit:this.config.autoCommit,autoPush:this.config.autoPush,verifyBuild:!0});if(b.buildFailed){console.error("[Monitor] Build verification failed - NOT pushing broken code"),u=`
69
69
 
70
70
  ### Git
71
71
  - \u26A0\uFE0F Build verification FAILED
72
72
  - Code NOT committed
73
- - Error: ${m.error?.substring(0,300)||"Unknown error"}`,await this.handleFailure(e,t,"FAILED",i,`Build verification failed. The code changes do not build successfully. Error: ${m.error?.substring(0,500)||"Unknown build error"}`);return}m.committed?(c=`
73
+ - Error: ${b.error?.substring(0,300)||"Unknown error"}`,await this.handleFailure(e,t,"FAILED",i,`Build verification failed. The code changes do not build successfully. Error: ${b.error?.substring(0,500)||"Unknown build error"}`);return}b.committed?(u=`
74
74
 
75
75
  ### Git
76
- - Commit: \`${m.commitHash}\`
77
- - Files: ${m.filesCommitted.length}`,console.log(`[Monitor] Auto-commit successful: ${m.commitHash}`),m.pushed?(c+=`
78
- - Pushed: Yes`,console.log("[Monitor] Auto-push successful")):this.config.autoPush&&m.error&&(c+=`
79
- - Push failed: ${m.error}`,console.warn(`[Monitor] Auto-push failed: ${m.error}`))):m.error&&m.error!=="No changes to commit"&&(c=`
76
+ - Commit: \`${b.commitHash}\`
77
+ - Files: ${b.filesCommitted.length}`,console.log(`[Monitor] Auto-commit successful: ${b.commitHash}`),b.pushed?(u+=`
78
+ - Pushed: Yes`,console.log("[Monitor] Auto-push successful")):this.config.autoPush&&b.error&&(u+=`
79
+ - Push failed: ${b.error}`,console.warn(`[Monitor] Auto-push failed: ${b.error}`))):b.error&&b.error!=="No changes to commit"&&(u=`
80
80
 
81
81
  ### Git
82
- - Auto-commit failed: ${m.error}`,console.warn(`[Monitor] Auto-commit failed: ${m.error}`))}let u=5e3,p=i.length>u?`${i.substring(0,u)}...
82
+ - Auto-commit failed: ${b.error}`,console.warn(`[Monitor] Auto-commit failed: ${b.error}`))}let p=5e3,g=i.length>p?`${i.substring(0,p)}...
83
83
 
84
- [Output truncated]`:i;await this.client.completeTask(e,"COMPLETED",{comment:`## Auto-Task Completed
84
+ [Output truncated]`:i;if(await this.client.completeTask(e,"COMPLETED",{comment:`## Auto-Task Completed
85
85
 
86
- ${p}${c}`,costUsd:a}),console.log(a?`[Monitor] Task ${t.id} completed (cost: $${a.toFixed(4)})`:`[Monitor] Task ${t.id} completed and moved to IN_REVIEW`)}async handleFailure(e,t,i,a,c){let p=a.length>3e3?`${a.substring(0,3e3)}...
86
+ ${g}${u}`,costUsd:a,tokensUsed:c}),a){let m=c?`, ${c.toLocaleString()} tokens`:"";console.log(`[Monitor] Task ${t.id} completed (cost: $${a.toFixed(4)}${m})`)}else console.log(`[Monitor] Task ${t.id} completed and moved to IN_REVIEW`)}async handleFailure(e,t,i,a,c){let p=a.length>3e3?`${a.substring(0,3e3)}...
87
87
 
88
88
  [Output truncated]`:a,g=[`## Auto-Task ${i==="TIMEOUT"?"Timed Out":"Failed"}`,"",c?`**Error:** ${c}`:"","","### Output","```",p,"```"].filter(Boolean).join(`
89
89
  `);await this.client.completeTask(e,i,{comment:g,errorMessage:c}),console.log(`[Monitor] Task ${t.id} marked as ${i}, sending alert...`);try{let m=await this.client.sendAlert(e,i,c);console.log(`[Monitor] Alert sent to ${m.emailsSent} recipients`)}catch(m){console.error("[Monitor] Failed to send alert:",m)}}};import{createInterface as Ow}from"readline";import{writeFileSync as Gd,existsSync as Tw}from"fs";import{resolve as Fd}from"path";function Aw(){let s=Ow({input:process.stdin,output:process.stdout});return{ask:e=>new Promise(t=>{s.question(e,i=>{t(i.trim())})}),close:()=>s.close()}}async function Wd(s,e){try{return(await fetch(`${s}/api/mcp/auth/validate`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`}})).ok}catch{return!1}}function Vd(s){let e=`# Sego Auto-Task Monitor Configuration
@@ -100,7 +100,7 @@ SEGO_PROJECT_ID=${s.projectId}
100
100
  `),e}async function Kd(s={}){let e=s.yes||!1;if(console.log(""),console.log("=".repeat(50)),console.log(" Sego Auto-Task Monitor Setup Wizard"),console.log("=".repeat(50)),console.log(""),e){console.log("Running in non-interactive mode (--yes flag)"),console.log("");let i=process.env.SEGO_API_KEY,a=process.env.SEGO_API_URL||"https://sego.pm",c=process.env.SEGO_PROJECT_ID;i||(console.error("Error: SEGO_API_KEY environment variable is required in non-interactive mode."),console.error(""),console.error("Usage:"),console.error(" SEGO_API_KEY=your_key sego-auto-task init --yes"),console.error(""),console.error("Or run without --yes for interactive setup."),process.exit(1)),console.log("Validating API key..."),await Wd(a,i)||(console.error(`
101
101
  Error: Invalid API key or unable to connect to the API.`),console.error("Please check:"),console.error(" 1. Your API key is correct"),console.error(` 2. You can reach ${a}`),console.error(" 3. Your API key has not expired"),process.exit(1)),console.log("API key validated successfully!");let p={apiKey:i,apiUrl:a,projectId:c||void 0},g=Fd(process.cwd(),".env"),m=Vd(p);Gd(g,m),zd(g);return}let t=Aw();try{console.log("Step 1: API Key"),console.log("Get your API key from: https://sego.pm/developer/api-keys"),console.log("");let i=await t.ask("Enter your Sego PM API key: ");i||(console.error(`
102
102
  Error: API key is required.`),process.exit(1)),console.log(""),console.log("Step 2: API URL");let c=await t.ask("Enter API URL (press Enter for https://sego.pm): ")||"https://sego.pm";console.log(""),console.log("Validating API key..."),await Wd(c,i)||(console.error(`
103
- Error: Invalid API key or unable to connect to the API.`),console.error("Please check:"),console.error(" 1. Your API key is correct"),console.error(` 2. You can reach ${c}`),console.error(" 3. Your API key has not expired"),process.exit(1)),console.log("API key validated successfully!"),console.log(""),console.log("Step 3: Project ID (Optional)"),console.log("You can filter to a specific project, or monitor all projects.");let p=await t.ask("Enter Project ID (press Enter to skip): "),g={apiKey:i,apiUrl:c,projectId:p||void 0};console.log(""),console.log("Step 4: Save Configuration");let m=Fd(process.cwd(),".env");if(Tw(m)&&(console.log(`Warning: .env file already exists at ${m}`),(await t.ask("Overwrite? (y/N): ")).toLowerCase()!=="y")){console.log(""),console.log("Configuration not saved. You can set these environment variables manually:"),console.log(""),console.log(`export SEGO_API_KEY="${g.apiKey}"`),console.log(`export SEGO_API_URL="${g.apiUrl}"`),g.projectId&&console.log(`export SEGO_PROJECT_ID="${g.projectId}"`),console.log(""),t.close();return}let w=Vd(g);Gd(m,w),zd(m)}finally{t.close()}}function zd(s){console.log(""),console.log("=".repeat(50)),console.log(" Setup Complete!"),console.log("=".repeat(50)),console.log(""),console.log(`Configuration saved to: ${s}`),console.log(""),console.log("Next steps:"),console.log(" 1. Make sure Claude Code CLI is installed and authenticated:"),console.log(" npm install -g @anthropic-ai/claude-code"),console.log(" claude auth login"),console.log(""),console.log(" 2. Start the monitor:"),console.log(" sego-auto-task"),console.log(""),console.log(" 3. Or run in dry-run mode to test:"),console.log(" sego-auto-task --dry-run"),console.log("")}import{existsSync as Yd,mkdirSync as Rw,readFileSync as Pw,writeFileSync as Iw}from"fs";import{homedir as Mw}from"os";import{join as Qd}from"path";var Xd="@segosolutions/auto-task",Po=Qd(Mw(),".sego-auto-task"),Io=Qd(Po,"version-check.json"),xw=24*60*60*1e3;function Jd(s,e){let t=s.replace(/^v/,"").split(".").map(Number),i=e.replace(/^v/,"").split(".").map(Number);for(let a=0;a<Math.max(t.length,i.length);a++){let c=t[a]||0,u=i[a]||0;if(c<u)return-1;if(c>u)return 1}return 0}function Nw(){try{if(!Yd(Io))return null;let s=JSON.parse(Pw(Io,"utf-8"));return Date.now()-s.checkedAt<xw?s:null}catch{return null}}function Lw(s){try{Yd(Po)||Rw(Po,{recursive:!0});let e={latestVersion:s,checkedAt:Date.now()};Iw(Io,JSON.stringify(e,null,2))}catch{}}async function Dw(){try{let s=new AbortController,e=setTimeout(()=>s.abort(),5e3),t=await fetch(`https://registry.npmjs.org/${encodeURIComponent(Xd)}/latest`,{signal:s.signal});return clearTimeout(e),t.ok&&(await t.json()).version||null}catch{return null}}async function Zd(s){let e=Nw();if(e)return{currentVersion:s,latestVersion:e.latestVersion,updateAvailable:Jd(s,e.latestVersion)<0};let t=await Dw();return t&&Lw(t),{currentVersion:s,latestVersion:t,updateAvailable:t?Jd(s,t)<0:!1}}function ef(s){!s.updateAvailable||!s.latestVersion||(console.log(""),console.log("\x1B[33m"+"=".repeat(60)+"\x1B[0m"),console.log("\x1B[33m Update available!\x1B[0m"),console.log(` Current version: \x1B[90m${s.currentVersion}\x1B[0m`),console.log(` Latest version: \x1B[32m${s.latestVersion}\x1B[0m`),console.log(""),console.log(" Run to update:"),console.log(` \x1B[36m npm update -g ${Xd}\x1B[0m`),console.log("\x1B[33m"+"=".repeat(60)+"\x1B[0m"),console.log(""))}var nf="1.7.5",Mo=null;fs.name("sego-auto-task").description(`Background task monitor for Sego PM - automatically processes high-confidence tasks using Claude.
103
+ Error: Invalid API key or unable to connect to the API.`),console.error("Please check:"),console.error(" 1. Your API key is correct"),console.error(` 2. You can reach ${c}`),console.error(" 3. Your API key has not expired"),process.exit(1)),console.log("API key validated successfully!"),console.log(""),console.log("Step 3: Project ID (Optional)"),console.log("You can filter to a specific project, or monitor all projects.");let p=await t.ask("Enter Project ID (press Enter to skip): "),g={apiKey:i,apiUrl:c,projectId:p||void 0};console.log(""),console.log("Step 4: Save Configuration");let m=Fd(process.cwd(),".env");if(Tw(m)&&(console.log(`Warning: .env file already exists at ${m}`),(await t.ask("Overwrite? (y/N): ")).toLowerCase()!=="y")){console.log(""),console.log("Configuration not saved. You can set these environment variables manually:"),console.log(""),console.log(`export SEGO_API_KEY="${g.apiKey}"`),console.log(`export SEGO_API_URL="${g.apiUrl}"`),g.projectId&&console.log(`export SEGO_PROJECT_ID="${g.projectId}"`),console.log(""),t.close();return}let w=Vd(g);Gd(m,w),zd(m)}finally{t.close()}}function zd(s){console.log(""),console.log("=".repeat(50)),console.log(" Setup Complete!"),console.log("=".repeat(50)),console.log(""),console.log(`Configuration saved to: ${s}`),console.log(""),console.log("Next steps:"),console.log(" 1. Make sure Claude Code CLI is installed and authenticated:"),console.log(" npm install -g @anthropic-ai/claude-code"),console.log(" claude auth login"),console.log(""),console.log(" 2. Start the monitor:"),console.log(" sego-auto-task"),console.log(""),console.log(" 3. Or run in dry-run mode to test:"),console.log(" sego-auto-task --dry-run"),console.log("")}import{existsSync as Yd,mkdirSync as Rw,readFileSync as Pw,writeFileSync as Iw}from"fs";import{homedir as Mw}from"os";import{join as Qd}from"path";var Xd="@segosolutions/auto-task",Po=Qd(Mw(),".sego-auto-task"),Io=Qd(Po,"version-check.json"),xw=24*60*60*1e3;function Jd(s,e){let t=s.replace(/^v/,"").split(".").map(Number),i=e.replace(/^v/,"").split(".").map(Number);for(let a=0;a<Math.max(t.length,i.length);a++){let c=t[a]||0,u=i[a]||0;if(c<u)return-1;if(c>u)return 1}return 0}function Nw(){try{if(!Yd(Io))return null;let s=JSON.parse(Pw(Io,"utf-8"));return Date.now()-s.checkedAt<xw?s:null}catch{return null}}function Lw(s){try{Yd(Po)||Rw(Po,{recursive:!0});let e={latestVersion:s,checkedAt:Date.now()};Iw(Io,JSON.stringify(e,null,2))}catch{}}async function Dw(){try{let s=new AbortController,e=setTimeout(()=>s.abort(),5e3),t=await fetch(`https://registry.npmjs.org/${encodeURIComponent(Xd)}/latest`,{signal:s.signal});return clearTimeout(e),t.ok&&(await t.json()).version||null}catch{return null}}async function Zd(s){let e=Nw();if(e)return{currentVersion:s,latestVersion:e.latestVersion,updateAvailable:Jd(s,e.latestVersion)<0};let t=await Dw();return t&&Lw(t),{currentVersion:s,latestVersion:t,updateAvailable:t?Jd(s,t)<0:!1}}function ef(s){!s.updateAvailable||!s.latestVersion||(console.log(""),console.log("\x1B[33m"+"=".repeat(60)+"\x1B[0m"),console.log("\x1B[33m Update available!\x1B[0m"),console.log(` Current version: \x1B[90m${s.currentVersion}\x1B[0m`),console.log(` Latest version: \x1B[32m${s.latestVersion}\x1B[0m`),console.log(""),console.log(" Run to update:"),console.log(` \x1B[36m npm update -g ${Xd}\x1B[0m`),console.log("\x1B[33m"+"=".repeat(60)+"\x1B[0m"),console.log(""))}var nf="1.7.6",Mo=null;fs.name("sego-auto-task").description(`Background task monitor for Sego PM - automatically processes high-confidence tasks using Claude.
104
104
 
105
105
  Runs in hybrid mode:
106
106
  - SSE: Listens for client request events and processes them with local Claude
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@segosolutions/auto-task",
3
- "version": "1.7.5",
3
+ "version": "1.7.6",
4
4
  "description": "Background task monitor for Sego PM - automatically processes high-confidence tasks using Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",