task-master-ai
Version:
A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.
36 lines (28 loc) • 136 kB
JavaScript
#!/usr/bin/env node
import{o as e,s as t}from"./ai-services-unified-B6rojvOM.js";import{$t as n,Dt as r,Gt as i,Jt as a,Mt as o,Rt as s,Tn as c,Tt as l,Vt as u,Yt as d,Zt as f,_n as p,an as m,bn as h,cn as g,en as _,ht as v,jt as y,m as b,ot as x,pn as ee,sn as te,st as S,tt as C,vt as w,wt as ne,x as re,yn as ie}from"./config-manager-CP3MTO3Q.js";import"./git-utils-DllbRE35.js";import{r as ae}from"./sentry-DB6W4QZQ.js";import{$ as oe,A as se,B as T,C as ce,D as le,F as ue,G as de,H as fe,I as pe,J as me,M as he,N as ge,O as _e,P as ve,Q as ye,R as E,S as be,U as xe,V as Se,W as Ce,X as we,Y as Te,Z as Ee,at as De,ct as Oe,dt as ke,gt as Ae,ht as je,i as Me,it as Ne,j as Pe,lt as Fe,n as Ie,pt as Le,r as Re,rt as ze,st as Be,t as Ve,ut as He,w as Ue,z as D}from"./dependency-manager-D9EPEYP3.js";import{t as We}from"./response-language-4tCn1Q-e.js";import{a as Ge,c as Ke,f as qe,g as Je,h as O,l as k,m as Ye,p as Xe,v as A}from"./profiles-84gD5LYb.js";import j from"node:path";import M from"chalk";import N from"fs";import P from"path";import Ze from"os";import Qe from"node:fs";import{z as F}from"zod";import{fileURLToPath as $e}from"url";import I from"dotenv";import*as L from"@sentry/node";import{FastMCP as et}from"fastmcp";const R={debug:0,info:1,warn:2,error:3,success:4},tt=R[re().toLowerCase()]??R.info;function z(e,...t){if(w())return;let n={debug:M.gray(`[DEBUG]`),info:M.blue(`[INFO]`),warn:M.yellow(`[WARN]`),error:M.red(`[ERROR]`),success:M.green(`[SUCCESS]`)};if(R[e]!==void 0&&R[e]>=tt){let r=n[e]||``,i=t;try{switch(e){case`error`:i=t.map(e=>typeof e==`string`?M.red(e):e);break;case`warn`:i=t.map(e=>typeof e==`string`?M.yellow(e):e);break;case`success`:i=t.map(e=>typeof e==`string`?M.green(e):e);break;case`info`:i=t.map(e=>typeof e==`string`?M.blue(e):e);break;case`debug`:i=t.map(e=>typeof e==`string`?M.gray(e):e);break}}catch(e){console.error(`Internal Logger Error applying chalk color:`,e),i=t}console.error(r,...i)}}function nt(){let e=e=>(...t)=>z(e,...t);return{debug:e(`debug`),info:e(`info`),warn:e(`warn`),error:e(`error`),success:e(`success`),log:z}}var B=nt(),V=class extends Error{constructor(e,t={}){super(e),this.name=`MCPError`,this.code=t.code,this.cause=t.cause,this.mcpResponse=t.mcpResponse}},H=class extends V{constructor(e,t={}){super(e,t),this.name=`MCPSessionError`}},rt=class extends V{constructor(e,t={}){super(e,t),this.name=`MCPSamplingError`}};function U(e){if(e instanceof V)return e;let t=e.message||`Unknown MCP error`,n=e;return t.includes(`session`)||t.includes(`connection`)?new H(t,{cause:n,code:`SESSION_ERROR`}):t.includes(`sampling`)||t.includes(`timeout`)?new rt(t,{cause:n,code:`SAMPLING_ERROR`}):t.includes(`capabilities`)||t.includes(`not supported`)?new H(t,{cause:n,code:`CAPABILITY_ERROR`}):new V(t,{cause:n,code:`UNKNOWN_ERROR`})}function it(e){let t=e.trim();t=t.replace(/^```json\s*/gm,``),t=t.replace(/^```\s*/gm,``),t=t.replace(/```\s*$/gm,``),t=t.replace(/^const\s+\w+\s*=\s*/,``),t=t.replace(/^let\s+\w+\s*=\s*/,``),t=t.replace(/^var\s+\w+\s*=\s*/,``),t=t.replace(/;?\s*$/,``),t=t.replace(/^.*?(?=\{|\[)/s,``),t.split(`
`);let n=-1,r=0,i=!1,a=!1;for(let e=0;e<t.length;e++){let o=t[e];if(a){a=!1;continue}if(o===`\\`){a=!0;continue}if(o===`"`&&!a){i=!i;continue}if(!i){if(o===`{`||o===`[`)r++;else if((o===`}`||o===`]`)&&(r--,r===0)){n=e;break}}}if(n>-1&&(t=t.substring(0,n+1)),n===-1){let e=t.match(/{[\s\S]*}/),n=t.match(/\[[\s\S]*\]/);e?t=e[0]:n&&(t=n[0])}try{return JSON.parse(t),t}catch{try{let e=t.replace(/([{,]\s*)([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/g,`$1"$2":`).replace(/'/g,`"`).replace(/,\s*([}\]])/g,`$1`);return JSON.parse(e),e}catch{return e}}}function W(e){let t=[],n=``;for(let r of e)r.role===`system`?n=K(r.content):(r.role===`user`||r.role===`assistant`)&&t.push({role:r.role,content:{type:`text`,text:K(r.content)}});return{messages:t,systemPrompt:n}}function G(e){let t=``,n=null,r=`stop`,i=[];return typeof e==`string`?t=e:e.content?(t=K(e.content),n=e.usage,r=e.finishReason||`stop`):e.text?(t=e.text,n=e.usage,r=e.finishReason||`stop`):(t=JSON.stringify(e),i.push(`Unexpected MCP response format, used JSON fallback`)),{text:t,usage:n,finishReason:r,warnings:i}}function K(e){return typeof e==`string`?e:Array.isArray(e)?e.map(e=>typeof e==`string`?e:e.type===`text`&&e.text||e.text?e.text:``).filter(e=>e.length>0).join(` `):e&&typeof e==`object`&&(e.type===`text`&&e.text||e.text)?e.text:String(e||``)}function at(e,t=`result`){try{let n=q(e);return`
CRITICAL JSON GENERATION INSTRUCTIONS:
You must respond with ONLY valid JSON that matches this exact structure for "${t}":
${JSON.stringify(n,null,2)}
STRICT REQUIREMENTS:
1. Response must start with { and end with }
2. Use double quotes for all strings and property names
3. Do not include any text before or after the JSON
4. Do not wrap in markdown code blocks
5. Do not include explanations or comments
6. Follow the exact property names and types shown above
7. All required fields must be present
Begin your response immediately with the opening brace {`}catch{return`
CRITICAL JSON GENERATION INSTRUCTIONS:
You must respond with ONLY valid JSON for "${t}".
STRICT REQUIREMENTS:
1. Response must start with { and end with }
2. Use double quotes for all strings and property names
3. Do not include any text before or after the JSON
4. Do not wrap in markdown code blocks
5. Do not include explanations or comments
Begin your response immediately with the opening brace {`}}function q(e){if(!e||e._def===void 0)return{};let t=e._def;switch(t.typeName){case`ZodObject`:let e={},n=t.shape();for(let[t,r]of Object.entries(n))e[t]=q(r);return e;case`ZodString`:if(t.checks){let e=t.checks.find(e=>e.kind===`min`),n=t.checks.find(e=>e.kind===`max`);if(e&&n)return`<string between `+e.value+`-`+n.value+` characters>`;if(e)return`<string with at least `+e.value+` characters>`;if(n)return`<string up to `+n.value+` characters>`}return`<string>`;case`ZodNumber`:if(t.checks){let e=t.checks.find(e=>e.kind===`int`),n=t.checks.find(e=>e.kind===`min`),r=t.checks.find(e=>e.kind===`max`);if(e&&n&&n.value>0)return`<positive integer>`;if(e)return`<integer>`;if(n||r)return`<number`+(n?` >= `+n.value:``)+(r?` <= `+r.value:``)+`>`}return`<number>`;case`ZodBoolean`:return`<boolean>`;case`ZodArray`:return[q(t.type)];case`ZodOptional`:return q(t.innerType);case`ZodNullable`:return q(t.innerType);case`ZodEnum`:return t.values[0]||`enum_value`;case`ZodLiteral`:return t.value;case`ZodUnion`:return t.options&&t.options.length>0?q(t.options[0]):`union_value`;case`ZodRecord`:return{key:q(t.valueType)};default:return`<${t.typeName||`unknown`}>`}}function ot(e,t){let n=[...e],r=n.findIndex(e=>e.role===`system`);if(r>=0){let e=n[r].content;n[r]={...n[r],content:e+`
`+t}}else n.unshift({role:`system`,content:t});return n}var st=class{specificationVersion=`v1`;defaultObjectGenerationMode=`json`;supportsImageUrls=!1;supportsStructuredOutputs=!0;constructor(e){this.session=e.session,this.modelId=e.modelId,this.settings=e.settings||{},this.provider=`mcp-ai-sdk`,this.maxTokens=this.settings.maxTokens,this.temperature=this.settings.temperature,this.validateSession()}validateSession(){if(!this.session?.clientCapabilities?.sampling)throw new V(`MCP session must have client sampling capabilities`)}async doGenerate(e){try{let{messages:t,systemPrompt:n}=W(e.prompt),r=await this.session.requestSampling({messages:t,systemPrompt:n,temperature:this.settings.temperature,maxTokens:this.settings.maxTokens,includeContext:`thisServer`},{timeout:24e4}),i=G(r);return{text:i.text,finishReason:i.finishReason||`stop`,usage:{promptTokens:i.usage?.inputTokens||0,completionTokens:i.usage?.outputTokens||0,totalTokens:(i.usage?.inputTokens||0)+(i.usage?.outputTokens||0)},rawResponse:r,warnings:i.warnings}}catch(e){throw U(e)}}async doGenerateObject(e){try{let{schema:t,mode:n=`json`,...r}=e;if(!t)throw new V(`Schema is required for object generation`);let i=at(t,r.objectName||`generated_object`),{messages:a,systemPrompt:o}=W(ot(e.prompt,i)),s=await this.session.requestSampling({messages:a,systemPrompt:o,temperature:this.settings.temperature,maxTokens:this.settings.maxTokens,includeContext:`thisServer`},{timeout:24e4}),c=G(s),l=it(c.text),u;try{u=JSON.parse(l)}catch(e){throw new V(`Failed to parse JSON response: ${e.message}. Response: ${c.text.substring(0,200)}...`)}try{return{object:t.parse(u),finishReason:c.finishReason||`stop`,usage:{promptTokens:c.usage?.inputTokens||0,completionTokens:c.usage?.outputTokens||0,totalTokens:(c.usage?.inputTokens||0)+(c.usage?.outputTokens||0)},rawResponse:s,warnings:c.warnings}}catch(e){throw new V(`Generated object does not match schema: ${e.message}. Generated: ${JSON.stringify(u,null,2)}`)}}catch(e){throw U(e)}}async doStream(e){try{let t=await this.doGenerate(e);return this.simulateStreaming(t)}catch(e){throw U(e)}}async*simulateStreaming(e){let t=e.text,n=Math.max(1,Math.floor(t.length/10));for(let e=0;e<t.length;e+=n){let r=t.slice(e,e+n);e+n,t.length,yield{type:`text-delta`,textDelta:r},await new Promise(e=>setTimeout(e,50))}yield{type:`finish`,finishReason:e.finishReason,usage:e.usage}}};function ct(e={}){if(!e.session)throw Error(`MCP provider requires session object`);let t=function(t,n={}){if(new.target)throw Error(`The MCP model function cannot be called with the new keyword.`);return new st({session:e.session,modelId:t||`claude-3-5-sonnet-20241022`,settings:{temperature:n.temperature,maxTokens:n.maxTokens,...e.defaultSettings,...n}})};return t.languageModel=(e,n)=>t(e,n),t.chat=(e,n)=>t(e,n),t}var lt=class extends e{constructor(){super(),this.name=`mcp`,this.session=null}getRequiredApiKeyName(){return`MCP_API_KEY`}isRequiredApiKey(){return!1}validateAuth(e){if(!this.session)throw Error(`MCP Provider requires active MCP session`);if(!this.session.clientCapabilities?.sampling)throw Error(`MCP session must have client sampling capabilities`)}getClient(e){try{return ct({session:this.session,defaultSettings:{temperature:e.temperature,maxTokens:e.maxTokens}})}catch(e){this.handleError(`client initialization`,e)}}setSession(e){this.session=e,e?this.logger?.debug(`Updated MCP Provider session`):this.logger?.warn(`Set null session on MCP Provider`)}hasValidSession(){return!!(this.session&&this.session.clientCapabilities?.sampling)}};function ut(){return{version:h||`unknown`,name:ie||`task-master-ai`}}function J(e,t,n){t||=ut();let r=`Error: ${e}
Version: ${t.version}
Name: ${t.name}`;return n&&(r+=`
Current Tag: ${n.currentTag}`),{content:[{type:`text`,text:r}],isError:!0}}function dt(e,t){if(typeof e!=`function`){t?.debug?.(`reportProgress not available - operation will run without progress updates`);return}return e}function ft(e){try{let t=j.join(e,`.taskmaster`,`state.json`);return Qe.existsSync(t)&&JSON.parse(Qe.readFileSync(t,`utf-8`)).currentTag||`master`}catch{return null}}async function Y(e){let{result:t,log:n,errorPrefix:r=`API error`,projectRoot:i,tag:a}=e,o=ut(),s=a===void 0?i?ft(i):null:a;if(!t.success){let e=t.error?.message||`Unknown ${r}`;n?.error?.(`${r}: ${e}`);let i=`Error: ${e}\nVersion: ${o.version}\nName: ${o.name}`;return s&&(i+=`\nCurrent Tag: ${s}`),{content:[{type:`text`,text:i}],isError:!0}}n?.info?.(`Successfully completed operation`);let c={data:t.data,version:o};return s&&(c.tag=s),{content:[{type:`text`,text:JSON.stringify(c,null,2)}]}}function X(e){if(!e)return process.cwd();try{let t=e;try{t=decodeURIComponent(t)}catch{}return(t.startsWith(`file:///`)||t.startsWith(`file://`))&&(t=t.slice(7)),t.startsWith(`/`)&&/[A-Za-z]:/.test(t.substring(1,3))&&(t=t.substring(1)),t=t.replace(/\\/g,`/`),j.resolve(t)}catch{return j.resolve(e)}}function pt(e){try{return e?.roots?.[0]?.uri?X(e.roots[0].uri):e?.roots?.roots?.[0]?.uri?X(e.roots.roots[0].uri):null}catch{return null}}function Z(e){return async(t,n)=>{let{log:r,session:i}=n,a=null,o=`unknown`;try{if(process.env.TASK_MASTER_PROJECT_ROOT){let e=process.env.TASK_MASTER_PROJECT_ROOT;a=j.isAbsolute(e)?e:j.resolve(process.cwd(),e),o=`TASK_MASTER_PROJECT_ROOT environment variable`,r?.info?.(`Using project root from ${o}: ${a}`)}else if(i?.env?.TASK_MASTER_PROJECT_ROOT){let e=i.env.TASK_MASTER_PROJECT_ROOT;a=j.isAbsolute(e)?e:j.resolve(process.cwd(),e),o=`TASK_MASTER_PROJECT_ROOT session environment variable`,r?.info?.(`Using project root from ${o}: ${a}`)}else if(t.projectRoot)a=X(t.projectRoot),o=`args.projectRoot`,r?.info?.(`Using project root from ${o}: ${a}`);else{let e=pt(i);e&&(a=e,o=`session`,r?.info?.(`Using project root from ${o}: ${a}`))}return a?await e({...t,projectRoot:a},n):(r?.error?.(`Could not determine project root from environment, args, or session.`),Y({result:{success:!1,error:{message:`Could not determine project root. Please provide projectRoot argument or ensure TASK_MASTER_PROJECT_ROOT environment variable is set.`}}}))}catch(e){return r?.error?.(`Error within withNormalizedProjectRoot HOF (Normalized Root: ${a}): ${e.message}`),e.stack&&r?.debug&&r.debug(e.stack),Y({result:{success:!1,error:{message:`Operation failed: ${e.message}`}}})}}}function Q(e,t){return Z(async(n,r)=>{let i=await m({projectPath:n.projectRoot,loggerConfig:{mcpMode:!0,logCallback:r.log}});if(c.includes(e)){let t=await i.auth.guardCommand(e,i.tasks.getStorageType());if(t.isBlocked){let e=`You're working on the ${t.briefName} Brief in Hamster so this command is managed for you. This command is only available for local file storage. Log out with 'tm auth logout' to use local commands.`;return r.log.info(e),Y({result:{success:!1,error:{message:e}},log:r.log,projectRoot:n.projectRoot})}}return t(n,{log:r.log,session:r.session,tmCore:i})})}const mt=F.object({taskId:f.describe(`Main task ID to start workflow for (e.g., "1", "2", "HAM-123"). Subtask IDs (e.g., "2.3", "1.1") are not allowed.`),projectRoot:F.string().describe(`Absolute path to the project root directory`),maxAttempts:F.number().optional().default(3).describe(`Maximum attempts per subtask (default: 3)`),force:F.boolean().optional().default(!1).describe(`Force start even if workflow state exists`)});function ht(e){e.addTool({name:`autopilot_start`,description:`Initialize and start a new TDD workflow for a task. Creates a git branch and sets up the workflow state machine.`,parameters:mt,execute:Q(`autopilot-start`,async(e,{log:t,tmCore:n})=>{let{taskId:r,projectRoot:i,maxAttempts:a,force:o}=e,s=_(r);try{t.info(`Starting autopilot workflow for task ${s} in ${i}`);let e=n.config.getActiveTag(),r=n.auth.getContext()?.orgSlug,c=await n.tasks.get(s);if(!c||!c.task)return Y({result:{success:!1,error:{message:`Task ${s} not found`}},log:t,projectRoot:i});let l=c.task;if(!l.subtasks||l.subtasks.length===0)return Y({result:{success:!1,error:{message:`Task ${s} has no subtasks. Please use expand_task (with id="${s}") to create subtasks first. For improved results, consider running analyze_complexity before expanding the task.`}},log:t,projectRoot:i});if(await n.workflow.hasWorkflow()&&!o)return t.warn(`Workflow state already exists`),Y({result:{success:!1,error:{message:`Workflow already in progress. Use force=true to override or resume the existing workflow. Suggestion: Use autopilot_resume to continue the existing workflow`}},log:t,projectRoot:i});let u=await n.workflow.start({taskId:s,taskTitle:l.title,subtasks:l.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,maxAttempts:a})),maxAttempts:a,force:o,tag:e,orgSlug:r});t.info(`Workflow started successfully for task ${s}`);let d=n.workflow.getNextAction();return Y({result:{success:!0,data:{message:`Workflow started for task ${s}`,taskId:s,branchName:u.branchName,phase:u.phase,tddPhase:u.tddPhase,progress:u.progress,currentSubtask:u.currentSubtask,nextAction:d.action,nextSteps:d.nextSteps}},log:t,projectRoot:i})}catch(e){return t.error(`Error in autopilot-start: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to start workflow: ${e.message}`}},log:t,projectRoot:i})}})})}const gt=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function _t(e){e.addTool({name:`autopilot_resume`,description:`Resume a previously started TDD workflow from saved state. Restores the workflow state machine and continues from where it left off.`,parameters:gt,execute:Q(`autopilot-resume`,async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Resuming autopilot workflow in ${r}`),!await n.workflow.hasWorkflow())return Y({result:{success:!1,error:{message:`No workflow state found. Start a new workflow with autopilot_start`}},log:t,projectRoot:r});let e=await n.workflow.resume(),i=n.workflow.getNextAction();return t.info(`Workflow resumed successfully for task ${e.taskId}`),Y({result:{success:!0,data:{message:`Workflow resumed`,...e,nextAction:i.action,actionDescription:i.description,nextSteps:i.nextSteps}},log:t,projectRoot:r})}catch(e){return t.error(`Error in autopilot-resume: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to resume workflow: ${e.message}`}},log:t,projectRoot:r})}})})}const vt=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function yt(e){e.addTool({name:`autopilot_next`,description:`Get the next action to perform in the TDD workflow. Returns detailed context about what needs to be done next, including the current phase, subtask, and expected actions.`,parameters:vt,execute:Q(`autopilot-next`,async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Getting next action for workflow in ${r}`),!await n.workflow.hasWorkflow())return Y({result:{success:!1,error:{message:`No active workflow found. Start a workflow with autopilot_start`}},log:t,projectRoot:r});await n.workflow.resume();let e=n.workflow.getNextAction(),i=n.workflow.getStatus();return t.info(`Next action determined: ${e.action}`),Y({result:{success:!0,data:{action:e.action,actionDescription:e.description,...i,nextSteps:e.nextSteps}},log:t,projectRoot:r})}catch(e){return t.error(`Error in autopilot-next: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to get next action: ${e.message}`}},log:t,projectRoot:r})}})})}const bt=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function xt(e){e.addTool({name:`autopilot_status`,description:`Get comprehensive workflow status including current phase, progress, subtask details, and activity history.`,parameters:bt,execute:Q(`autopilot-status`,async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Getting workflow status for ${r}`),!await n.workflow.hasWorkflow())return Y({result:{success:!1,error:{message:`No active workflow found. Start a workflow with autopilot_start`}},log:t,projectRoot:r});await n.workflow.resume();let e=n.workflow.getStatus();return t.info(`Workflow status retrieved for task ${e.taskId}`),Y({result:{success:!0,data:e},log:t,projectRoot:r})}catch(e){return t.error(`Error in autopilot-status: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to get workflow status: ${e.message}`}},log:t,projectRoot:r})}})})}const St=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`),testResults:F.object({total:F.number().describe(`Total number of tests`),passed:F.number().describe(`Number of passing tests`),failed:F.number().describe(`Number of failing tests`),skipped:F.number().optional().describe(`Number of skipped tests`)}).describe(`Test results from running the test suite`)});function Ct(e){e.addTool({name:`autopilot_complete_phase`,description:`Complete the current TDD phase (RED or GREEN) with test result validation. RED phase: expects failures (if 0 failures, feature is already implemented and subtask auto-completes). GREEN phase: expects all tests passing. For COMMIT phase, use autopilot_commit instead.`,parameters:St,execute:Q(`autopilot-complete-phase`,async(e,{log:t,tmCore:n})=>{let{projectRoot:r,testResults:i}=e;try{if(t.info(`Completing current phase in workflow for ${r}`),!await n.workflow.hasWorkflow())return Y({result:{success:!1,error:{message:`No active workflow found. Start a workflow with autopilot_start`}},log:t,projectRoot:r});await n.workflow.resume();let e=n.workflow.getStatus();if(!e.tddPhase)return Y({result:{success:!1,error:{message:`Cannot complete phase: not in a TDD phase (current phase: ${e.phase})`}},log:t,projectRoot:r});if(e.tddPhase===`COMMIT`)return Y({result:{success:!1,error:{message:`Cannot complete COMMIT phase with this tool. Use autopilot_commit instead`}},log:t,projectRoot:r});let a=e.tddPhase,o={total:i.total,passed:i.passed,failed:i.failed,skipped:i.skipped??0,phase:a},s=await n.workflow.completePhase(o),c=n.workflow.getNextAction();return t.info(`Phase completed. New phase: ${s.tddPhase||s.phase}`),Y({result:{success:!0,data:{message:`Phase completed. Transitioned to ${s.tddPhase||s.phase}`,...s,nextAction:c.action,actionDescription:c.description,nextSteps:c.nextSteps}},log:t,projectRoot:r})}catch(e){return t.error(`Error in autopilot-complete: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to complete phase: ${e.message}`}},log:t,projectRoot:r})}})})}const wt=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`),files:F.array(F.string()).optional().describe(`Specific files to stage (relative to project root). If not provided, stages all changes.`),customMessage:F.string().optional().describe(`Custom commit message to use instead of auto-generated message`)});function Tt(e){e.addTool({name:`autopilot_commit`,description:`Create a git commit with automatic staging, message generation, and metadata embedding. Generates appropriate commit messages based on subtask context and TDD phase.`,parameters:wt,execute:Q(`autopilot-commit`,async(e,{log:t,tmCore:n})=>{let{projectRoot:r,files:i,customMessage:a}=e;try{if(t.info(`Creating commit for workflow in ${r}`),!await n.workflow.hasWorkflow())return Y({result:{success:!1,error:{message:`No active workflow found. Start a workflow with autopilot_start`}},log:t,projectRoot:r});await n.workflow.resume();let e=n.workflow.getStatus(),o=n.workflow.getContext();if(e.tddPhase!==`COMMIT`)return t.warn(`Not in COMMIT phase (currently in ${e.tddPhase})`),Y({result:{success:!1,error:{message:`Cannot commit: currently in ${e.tddPhase} phase. Complete the ${e.tddPhase} phase first using autopilot_complete_phase`}},log:t,projectRoot:r});if(!e.currentSubtask)return Y({result:{success:!1,error:{message:`No active subtask to commit`}},log:t,projectRoot:r});let s=new g(r);try{i&&i.length>0?(await s.stageFiles(i),t.info(`Staged ${i.length} files`)):(await s.stageFiles([`.`]),t.info(`Staged all changes`))}catch(e){return t.error(`Failed to stage files: ${e.message}`),Y({result:{success:!1,error:{message:`Failed to stage files: ${e.message}`}},log:t,projectRoot:r})}if(!await s.hasStagedChanges())return t.warn(`No staged changes to commit`),Y({result:{success:!1,error:{message:`No staged changes to commit. Make code changes before committing`}},log:t,projectRoot:r});let c=await s.getStatus(),l;if(a)l=a,t.info(`Using custom commit message`);else{let n=new te,r={type:e.tddPhase===`COMMIT`?`feat`:`test`,description:e.currentSubtask.title,changedFiles:c.staged,taskId:e.taskId,phase:e.tddPhase,testsPassing:o.lastTestResults?.passed,testsFailing:o.lastTestResults?.failed};l=n.generateMessage(r),t.info(`Generated commit message automatically`)}try{await s.createCommit(l),t.info(`Commit created successfully`)}catch(e){return t.error(`Failed to create commit: ${e.message}`),Y({result:{success:!1,error:{message:`Failed to create commit: ${e.message}`}},log:t,projectRoot:r})}let u=await s.getLastCommit(),d=await n.workflow.commit();t.info(`Commit completed. Current phase: ${d.tddPhase||d.phase}`);let f=d.phase===`COMPLETE`,p=n.workflow.getNextAction();return Y({result:{success:!0,data:{message:f?`Workflow completed successfully`:`Commit created and workflow advanced`,commitSha:u.sha,commitMessage:l,...d,isComplete:f,nextAction:p.action,nextSteps:p.nextSteps}},log:t,projectRoot:r})}catch(e){return t.error(`Error in autopilot-commit: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to commit: ${e.message}`}},log:t,projectRoot:r})}})})}const Et=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function Dt(e){e.addTool({name:`autopilot_finalize`,description:`Finalize and complete the workflow. Validates that all changes are committed and working tree is clean before marking workflow as complete.`,parameters:Et,execute:Q(`autopilot-finalize`,async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Finalizing workflow in ${r}`),!await n.workflow.hasWorkflow())return Y({result:{success:!1,error:{message:`No active workflow found. Start a workflow with autopilot_start`}},log:t,projectRoot:r});await n.workflow.resume();let e=n.workflow.getStatus();if(e.phase!==`FINALIZE`)return Y({result:{success:!1,error:{message:`Cannot finalize: workflow is in ${e.phase} phase. Complete all subtasks first.`}},log:t,projectRoot:r});let i=await n.workflow.finalize();t.info(`Workflow finalized successfully`);let a=n.workflow.getNextAction();return Y({result:{success:!0,data:{message:`Workflow completed successfully`,...i,nextAction:a.action,nextSteps:a.nextSteps}},log:t,projectRoot:r})}catch(e){return t.error(`Error in autopilot-finalize: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to finalize workflow: ${e.message}`}},log:t,projectRoot:r})}})})}const Ot=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function kt(e){e.addTool({name:`autopilot_abort`,description:`Abort the current TDD workflow and clean up workflow state. This will remove the workflow state file but will NOT delete the git branch or any code changes.`,parameters:Ot,execute:Q(`autopilot-abort`,async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Aborting autopilot workflow in ${r}`),!await n.workflow.hasWorkflow())return t.warn(`No active workflow to abort`),Y({result:{success:!0,data:{message:`No active workflow to abort`,hadWorkflow:!1}},log:t,projectRoot:r});await n.workflow.resume();let e=n.workflow.getStatus();return await n.workflow.abort(),t.info(`Workflow state deleted`),Y({result:{success:!0,data:{message:`Workflow aborted`,hadWorkflow:!0,taskId:e.taskId,branchName:e.branchName,note:`Git branch and code changes were preserved. You can manually clean them up if needed.`}},log:t,projectRoot:r})}catch(e){return t.error(`Error in autopilot-abort: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to abort workflow: ${e.message}`}},log:t,projectRoot:r})}})})}const At=F.object({projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),status:F.string().optional().describe(`Filter tasks by status (e.g., 'pending', 'done') or multiple statuses separated by commas (e.g., 'blocked,deferred')`),withSubtasks:F.boolean().optional().describe(`Include subtasks nested within their parent tasks in the response`),tag:F.string().optional().describe(`Tag context to operate on`)});function jt(e){e.addTool({name:`get_tasks`,description:`Get all tasks from Task Master, optionally filtering by status and including subtasks.`,parameters:At,execute:Q(`get-tasks`,async(e,{log:t,tmCore:n})=>{let{projectRoot:r,status:i,withSubtasks:a,tag:o}=e;try{t.info(`Getting tasks from ${r}${i?` with status filter: ${i}`:``}${o?` for tag: ${o}`:``}`);let e=i&&i!==`all`?{status:i.split(`,`).map(e=>e.trim())}:void 0,s=await n.tasks.list({tag:o,filter:e,includeSubtasks:a});t.info(`Retrieved ${s.tasks?.length||0} tasks (${s.filtered} filtered, ${s.total} total)`);let c=s.tasks??[],l=s.total,u=c.reduce((e,t)=>(e[t.status]=(e[t.status]||0)+1,e),{}),d=l>0?(u.done||0)/l*100:0,f=c.reduce((e,t)=>(t.subtasks?.forEach(t=>{e.total++,e[t.status]=(e[t.status]||0)+1}),e),{total:0}),p=f.total>0?(f.done||0)/f.total*100:0;return Y({result:{success:!0,data:{tasks:c,filter:i||`all`,stats:{total:l,completed:u.done||0,inProgress:u[`in-progress`]||0,pending:u.pending||0,blocked:u.blocked||0,deferred:u.deferred||0,cancelled:u.cancelled||0,review:u.review||0,completionPercentage:d,subtasks:{total:f.total,completed:f.done||0,inProgress:f[`in-progress`]||0,pending:f.pending||0,blocked:f.blocked||0,deferred:f.deferred||0,cancelled:f.cancelled||0,completionPercentage:p}}}},log:t,projectRoot:r,tag:s.tag})}catch(e){return t.error(`Error in get-tasks: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to get tasks: ${e.message}`}},log:t,projectRoot:r})}})})}const Mt=F.object({id:d.describe(`Task ID(s) to get (can be comma-separated for multiple tasks)`),status:F.string().optional().describe(`Filter subtasks by status (e.g., 'pending', 'done')`),projectRoot:F.string().describe(`Absolute path to the project root directory (Optional, usually from session)`),tag:F.string().optional().describe(`Tag context to operate on`)});function Nt(e){e.addTool({name:`get_task`,description:`Get detailed information about a specific task`,parameters:Mt,execute:Q(`get-task`,async(e,{log:t,tmCore:n})=>{let{id:r,status:i,projectRoot:o,tag:s}=e;try{t.info(`Getting task details for ID: ${r}${i?` (filtering subtasks by status: ${i})`:``} in root: ${o}`);let e=a(r),c=await Promise.all(e.map(e=>n.tasks.get(e,s))),l=[];for(let e of c)if(e.task)if(i&&e.task.subtasks){let t=i.split(`,`).map(e=>e.trim().toLowerCase()),n=e.task.subtasks.filter(e=>t.includes(String(e.status).toLowerCase()));l.push({...e.task,subtasks:n})}else l.push(e.task);return l.length===0?(t.warn(`No tasks found for ID(s): ${r}`),Y({result:{success:!1,error:{message:`No tasks found for ID(s): ${r}`}},log:t,projectRoot:o})):(t.info(`Successfully retrieved ${l.length} task(s) for ID(s): ${r}`),Y({result:{success:!0,data:e.length===1?l[0]:l},log:t,projectRoot:o,tag:s}))}catch(e){return t.error(`Error in get-task: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to get task: ${e.message}`}},log:t,projectRoot:o})}})})}const Pt=F.object({output:F.string().optional().describe(`Output directory for generated files (default: same directory as tasks file)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`)});function Ft(e){e.addTool({name:`generate`,description:`Generates individual task files in tasks/ directory based on tasks.json. Only works with local file storage.`,parameters:Pt,execute:Q(`generate`,async(e,{log:t,tmCore:n})=>{let{projectRoot:r,tag:i,output:a}=e;try{t.info(`Generating task files with args: ${JSON.stringify(e)}`);let o=a?j.resolve(r,a):void 0,s=await n.tasks.generateTaskFiles({tag:i,outputDir:o});return s.success?(t.info(`Successfully generated ${s.count} task files in ${s.directory}`),s.orphanedFilesRemoved>0&&t.info(`Removed ${s.orphanedFilesRemoved} orphaned task files`)):t.error(`Failed to generate task files: ${s.error||`Unknown error`}`),Y({result:{success:s.success,data:s.success?{message:`Successfully generated ${s.count} task file(s)`,count:s.count,directory:s.directory,orphanedFilesRemoved:s.orphanedFilesRemoved}:void 0,error:s.success?void 0:{message:s.error||`Unknown error`}},log:t,projectRoot:r,tag:i})}catch(e){return t.error(`Error in generate tool: ${e.message}`),e.stack&&t.debug(e.stack),Y({result:{success:!1,error:{message:`Failed to generate task files: ${e.message}`}},log:t,projectRoot:r})}})})}const It=F.object({id:d.describe(`Task ID or subtask ID (e.g., '15', '15.2'). Can be comma-separated to update multiple tasks/subtasks at once.`),status:F.enum(ee).describe(`New status to set (e.g., 'pending', 'done', 'in-progress', 'review', 'deferred', 'cancelled').`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Optional tag context to operate on`)});function Lt(e){e.addTool({name:`set_task_status`,description:`Set the status of one or more tasks or subtasks.`,parameters:It,execute:Q(`set-task-status`,async(e,{log:t,tmCore:n})=>{let{id:r,status:i,projectRoot:o,tag:s}=e;try{t.info(`Setting status of task(s) ${r} to: ${i}${s?` in tag: ${s}`:` in current tag`}`);let e=a(r),c=[];for(let r of e){let e=await n.tasks.updateStatus(r,i,s);c.push(e),t.info(`Updated task ${r}: ${e.oldStatus} → ${e.newStatus}`)}return t.info(`Successfully updated status for ${c.length} task(s) to "${i}"`),Y({result:{success:!0,data:{message:`Successfully updated ${c.length} task(s) to "${i}"`,tasks:c}},log:t,projectRoot:o,tag:s})}catch(e){let n=e instanceof Error?e:Error(String(e));return t.error(`Error in set-task-status: ${n.message}`),n.stack&&t.debug(n.stack),Y({result:{success:!1,error:{message:`Failed to set task status: ${n.message}`}},log:t,projectRoot:o,tag:s})}})})}async function Rt(e,t){let{tasksJsonPath:n,id:r,dependsOn:i,tag:a,projectRoot:o}=e;try{if(t.info(`Adding dependency with args: ${JSON.stringify(e)}`),!n)return t.error(`addDependencyDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!r)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Task ID (id) is required`}};if(!i)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Dependency ID (dependsOn) is required`}};let s=n,c=r&&r.includes&&r.includes(`.`)?r:parseInt(r,10),l=i&&i.includes&&i.includes(`.`)?i:parseInt(i,10);return t.info(`Adding dependency: task ${c} will depend on ${l}`),S(),await Ve(s,c,l,{projectRoot:o,tag:a}),x(),{success:!0,data:{message:`Successfully added dependency: Task ${c} now depends on ${l}`,taskId:c,dependencyId:l}}}catch(e){return x(),t.error(`Error in addDependencyDirect: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function zt(e,t){let{tasksJsonPath:n,id:r,taskId:i,title:a,description:o,details:s,status:c,dependencies:l,skipGenerate:u,projectRoot:d,tag:f}=e;try{if(t.info(`Adding subtask with args: ${JSON.stringify(e)}`),!n)return t.error(`addSubtaskDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!r)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Parent task ID is required`}};if(!i&&!a)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Either taskId or title must be provided`}};let p=n,m=[];l&&(m=l.split(`,`).map(e=>e.includes(`.`)?e.trim():parseInt(e.trim(),10)));let h=i?parseInt(i,10):null,g=parseInt(r,10),_=!u;S();let v={projectRoot:d,tag:f};if(h){t.info(`Converting task ${h} to a subtask of ${g}`);let e=await oe(p,g,h,null,_,v);return x(),{success:!0,data:{message:`Task ${h} successfully converted to a subtask of task ${g}`,subtask:e}}}else{t.info(`Creating new subtask for parent task ${g}`);let e=await oe(p,g,null,{title:a,description:o||``,details:s||``,status:c||`pending`,dependencies:m},_,v);return x(),{success:!0,data:{message:`New subtask ${g}.${e.id} successfully created`,subtask:e}}}}catch(e){return x(),t.error(`Error in addSubtaskDirect: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function Bt(e,t,n={}){let{tasksJsonPath:r,name:i,copyFromCurrent:a=!1,copyFromTag:o,fromBranch:s=!1,description:c,projectRoot:l}=e,{session:u}=n;S();let d=E(t);try{if(!r)return t.error(`addTagDirect called without tasksJsonPath`),x(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(s){t.info(`Creating tag from current git branch`);let e=await import(`./git-utils-PBP1PRVP.js`);if(!await e.isGitRepository(l))return t.error(`Not in a git repository`),x(),{success:!1,error:{code:`NOT_GIT_REPO`,message:`Not in a git repository. Cannot use fromBranch option.`}};let n=await e.getCurrentBranch(l);if(!n)return t.error(`Could not determine current git branch`),x(),{success:!1,error:{code:`NO_CURRENT_BRANCH`,message:`Could not determine current git branch.`}};let i=await Fe(r,n,{copyFromCurrent:a,copyFromTag:o,description:c||`Tag created from git branch "${n}"`},{session:u,mcpLog:d,projectRoot:l},`json`);return x(),{success:!0,data:{branchName:i.branchName,tagName:i.tagName,created:i.created,mappingUpdated:i.mappingUpdated,message:`Successfully created tag "${i.tagName}" from git branch "${i.branchName}"`}}}else{if(!i||typeof i!=`string`)return t.error(`Missing required parameter: name`),x(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Tag name is required and must be a string`}};t.info(`Creating new tag: ${i}`);let e=await Oe(r,i,{copyFromCurrent:a,copyFromTag:o,description:c},{session:u,mcpLog:d,projectRoot:l},`json`);return x(),{success:!0,data:{tagName:e.tagName,created:e.created,tasksCopied:e.tasksCopied,sourceTag:e.sourceTag,description:e.description,message:`Successfully created tag "${e.tagName}"`}}}}catch(e){return x(),t.error(`Error in addTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`ADD_TAG_ERROR`,message:e.message}}}}async function Vt(e,t,n={}){let{tasksJsonPath:r,prompt:i,dependencies:a,priority:o,research:s,projectRoot:c,tag:l}=e,{session:u}=n;S();let d=E(t);try{if(!r)return t.error(`addTaskDirect called without tasksJsonPath`),x(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};let n=r,f=e.title&&e.description;if(!e.prompt&&!f)return t.error(`Missing required parameters: either prompt or title+description must be provided`),x(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Either the prompt parameter or both title and description parameters are required for adding a task`}};let p=Array.isArray(a)?a:a?String(a).split(`,`).map(e=>parseInt(e.trim(),10)):[],m=o||`medium`,h=null,g,_,v;if(f){h={title:e.title,description:e.description,details:e.details||``,testStrategy:e.testStrategy||``},t.info(`Adding new task manually with title: "${e.title}", dependencies: [${p.join(`, `)}], priority: ${o}`);let r=await ye(n,null,p,m,{session:u,mcpLog:d,projectRoot:c,commandName:`add-task`,outputType:`mcp`,tag:l},`json`,h,!1);g=r.newTaskId,_=r.telemetryData,v=r.tagInfo}else{t.info(`Adding new task with prompt: "${i}", dependencies: [${p.join(`, `)}], priority: ${m}, research: ${s}`);let e=await ye(n,i,p,m,{session:u,mcpLog:d,projectRoot:c,commandName:`add-task`,outputType:`mcp`,tag:l},`json`,null,s);g=e.newTaskId,_=e.telemetryData,v=e.tagInfo}return x(),{success:!0,data:{taskId:g,message:`Successfully added new task #${g}`,telemetryData:_,tagInfo:v}}}catch(e){return x(),t.error(`Error in addTaskDirect: ${e.message}`),{success:!1,error:{code:e.code||`ADD_TASK_ERROR`,message:e.message}}}}async function Ht(e,t,n={}){let{session:r}=n,{tasksJsonPath:i,outputPath:a,threshold:o,research:s,projectRoot:c,ids:l,from:u,to:d,tag:f}=e,p=E(t);try{if(t.info(`Analyzing task complexity with args: ${JSON.stringify(e)}`),!i)return t.error(`analyzeTaskComplexityDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!a)return t.error(`analyzeTaskComplexityDirect called without outputPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`outputPath is required`}};let n=i,m=a;if(t.info(`Analyzing task complexity from: ${n}`),t.info(`Output report will be saved to: ${m}`),l)t.info(`Analyzing specific task IDs: ${l}`);else if(u||d){let e=u===void 0?`first`:u,n=d===void 0?`last`:d;t.info(`Analyzing tasks in range: ${e} to ${n}`)}s&&t.info(`Using research role for complexity analysis`);let h={file:i,output:a,threshold:o,research:s===!0,projectRoot:c,id:l,from:u,to:d,tag:f},g=w();g||S();let _;try{_=await Ee(h,{session:r,mcpLog:p,commandName:`analyze-complexity`,outputType:`mcp`,projectRoot:c,tag:f}),_.report}catch(e){return t.error(`Error in analyzeTaskComplexity core function: ${e.message}`),!g&&w()&&x(),{success:!1,error:{code:`ANALYZE_CORE_ERROR`,message:`Error running core complexity analysis: ${e.message}`}}}finally{!g&&w()&&x()}if(!N.existsSync(m))return{success:!1,error:{code:`ANALYZE_REPORT_MISSING`,message:`Analysis completed but no report file was created at the expected path.`}};if(!_||!_.report||typeof _.report!=`object`)return t.error(`Core analysis function returned an invalid or undefined response.`),{success:!1,error:{code:`INVALID_CORE_RESPONSE`,message:`Core analysis function returned an invalid response.`}};try{let e=Array.isArray(_.report.complexityAnalysis)?_.report.complexityAnalysis:[],t=e.filter(e=>e.complexityScore>=8).length,n=e.filter(e=>e.complexityScore>=5&&e.complexityScore<8).length,r=e.filter(e=>e.complexityScore<5).length;return{success:!0,data:{message:`Task complexity analysis complete. Report saved to ${a}`,reportPath:a,reportSummary:{taskCount:e.length,highComplexityTasks:t,mediumComplexityTasks:n,lowComplexityTasks:r},fullReport:_.report,telemetryData:_.telemetryData,tagInfo:_.tagInfo}}}catch(e){return t.error(`Internal error processing report data: ${e.message}`),{success:!1,error:{code:`REPORT_PROCESS_ERROR`,message:`Internal error processing complexity report: ${e.message}`}}}}catch(e){return w()&&x(),t.error(`Error in analyzeTaskComplexityDirect setup: ${e.message}`),{success:!1,error:{code:`DIRECT_FUNCTION_SETUP_ERROR`,message:e.message}}}}async function Ut(e,t){let{tasksJsonPath:n,id:r,all:i,tag:a,projectRoot:o}=e;try{if(t.info(`Clearing subtasks with args: ${JSON.stringify(e)}`),!n)return t.error(`clearSubtasksDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!r&&!i)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Either task IDs with id parameter or all parameter must be provided`}};let s=n;if(!N.existsSync(s))return{success:!1,error:{code:`FILE_NOT_FOUND_ERROR`,message:`Tasks file not found at ${s}`}};let c,u=l(s,o,a);if(!u||!u.tasks)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`No tasks found in tasks file: ${s}`}};let d=u.tag||a,f=u.tasks;if(i){if(t.info(`Clearing subtasks from all tasks in tag '${d}'`),f.length===0)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`No tasks found in tag context '${d}'`}};c=f.map(e=>e.id).join(`,`)}else c=r;t.info(`Clearing subtasks from tasks: ${c} in tag '${d}'`),S(),we(s,c,{projectRoot:o,tag:d}),x();let p=l(s,o,d),m=c.split(`,`).map(e=>parseInt(e.trim(),10)),h=m.length,g=p.tasks||[],_=m.map(e=>{let t=g.find(t=>t.id===e);return t?{id:e,title:t.title}:{id:e,title:`Task not found`}});return{success:!0,data:{message:`Successfully cleared subtasks from ${h} task(s) in tag '${d}'`,tasksCleared:_,tag:d}}}catch(e){return x(),t.error(`Error in clearSubtasksDirect: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function Wt(e,t){let{reportPath:n}=e;try{if(t.info(`Getting complexity report with args: ${JSON.stringify(e)}`),!n)return t.error(`complexityReportDirect called without reportPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`reportPath is required`}};t.info(`Looking for complexity report at: ${n}`),`${n}`;let r=async()=>{try{S();let e=ne(n);return x(),e?{success:!0,data:{report:e,reportPath:n}}:(t.warn(`No complexity report found at ${n}`),{success:!1,error:{code:`FILE_NOT_FOUND_ERROR`,message:`No complexity report found at ${n}. Run 'analyze-complexity' first.`}})}catch(e){return x(),t.error(`Error reading complexity report: ${e.message}`),{success:!1,error:{code:`READ_ERROR`,message:e.message}}}};try{let e=await r();return t.info(`complexityReportDirect completed`),e}catch(e){return x(),t.error(`Unexpected error during complexityReport: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}catch(e){return x(),t.error(`Error in complexityReportDirect: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}async function Gt(e,t,n={}){let{tasksJsonPath:r,sourceName:i,targetName:a,description:o,projectRoot:s}=e,{session:c}=n;S();let l=E(t);try{if(!r)return t.error(`copyTagDirect called without tasksJsonPath`),x(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: sourceName`),x(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Source tag name is required and must be a string`}};if(!a||typeof a!=`string`)return t.error(`Missing required parameter: targetName`),x(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Target tag name is required and must be a string`}};t.info(`Copying tag from "${i}" to "${a}"`);let e=await Be(r,i,a,{description:o},{session:c,mcpLog:l,projectRoot:s},`json`);return x(),{success:!0,data:{sourceName:e.sourceName,targetName:e.targetName,copied:e.copied,tasksCopied:e.tasksCopied,description:e.description,message:`Successfully copied tag from "${e.sourceName}" to "${e.targetName}"`}}}catch(e){return x(),t.error(`Error in copyTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`COPY_TAG_ERROR`,message:e.message}}}}async function Kt(e,t,n={}){let{tasksJsonPath:r,name:i,yes:a=!1,projectRoot:o}=e,{session:s}=n;S();let c=E(t);try{if(!r)return t.error(`deleteTagDirect called without tasksJsonPath`),x(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: name`),x(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Tag name is required and must be a string`}};t.info(`Deleting tag: ${i}`);let e=await He(r,i,{yes:a},{session:s,mcpLog:c,projectRoot:o},`json`);return x(),{success:!0,data:{tagName:e.tagName,deleted:e.deleted,tasksDeleted:e.tasksDeleted,wasCurrentTag:e.wasCurrentTag,switchedToMaster:e.switchedToMaster,message:`Successfully deleted tag "${e.tagName}"`}}}catch(e){return x(),t.error(`Error in deleteTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`DELETE_TAG_ERROR`,message:e.message}}}}async function qt(e,t,n={}){let{session:r}=n,{tasksJsonPath:i,num:a,research:o,prompt:s,force:c,projectRoot:l,tag:u,complexityReportPath:d}=e,f=E(t),p=d||C(null,{projectRoot:l,tag:u},t);if(t.info(`Expand all tasks will use complexity report at: ${p}`),!i)return t.error(`expandAllTasksDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};S();try{t.info(`Calling core expandAllTasks with args: ${JSON.stringify({num:a,research:o,prompt:s,force:c,projectRoot:l,tag:u})}`);let e=await me(i,a?parseInt(a,10):void 0,o===!0,s||``,c===!0,{session:r,mcpLog:f,projectRoot:l,tag:u,complexityReportPath:p},`json`);return{success:!0,data:{message:`Expand all operation completed. Expanded: ${e.expandedCount}, Failed: ${e.failedCount}, Skipped: ${e.skippedCount}`,details:{expandedCount:e.expandedCount,failedCount:e.failedCount,skippedCount:e.skippedCount,tasksToExpand:e.tasksToExpand},telemetryData:e.telemetryData}}}catch(e){return t.error(`Error during core expandAllTasks execution: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message}}}finally{x()}}async function Jt(e,t,n={}){let{session:r}=n,{tasksJsonPath:i,id:a,num:o,research:s,prompt:c,force:u,projectRoot:d,tag:f,complexityReportPath:p}=e;if(t.info(`Session data in expandTaskDirect: ${JSON.stringify({hasSession:!!r,sessionKeys:r?Object.keys(r):[],roots:r?.roots,rootsStr:JSON.stringify(r?.roots)})}`),!i)return t.error(`expandTaskDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};let m=i;t.info(`[expandTaskDirect] Using tasksPath: ${m}`);let h=a?parseInt(a,10):null;if(!h)return t.error(`Task ID is required`),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Task ID is required`}};let g=o?parseInt(o,10):void 0,_=s===!0,v=c||``,b=u===!0;try{t.info(`[expandTaskDirect] Expanding task ${h} into ${g||`default`} subtasks. Research: ${_}, Force: ${b}`),t.info(`[expandTaskDirect] Attempting to read JSON from: ${m}`);let e=l(m,d);if(t.info(`[expandTaskDirect] Result of readJSON: ${e?`Data read successfully`:`readJSON returned null or undefined`}`),!e||!e.tasks)return t.error(`[expandTaskDirect] readJSON failed or returned invalid data for path: ${m}`),{success:!1,error:{code:`INVALID_TASKS_FILE`,message:`No valid tasks found in ${m}. readJSON returned: ${JSON.stringify(e)}`}};t.info(`[expandTaskDirect] Searching for task ID ${h} in data`);let n=e.tasks.find(e=>e.id===h);if(t.info(`[expandTaskDirect] Task found: ${n?`Yes`:`No`}`),!n)return{success:!1,error:{code:`TASK_NOT_FOUND`,message:`Task with ID ${h} not found`}};if(n.status===`done`||n.status===`completed`)return{success:!1,error:{code:`TASK_COMPLETED`,message:`Task ${h} is already marked as ${n.status} and cannot be expanded`}};let i=n.subtasks&&n.subtasks.length>0;if(i&&!b)return t.info(`Task ${h} already has ${n.subtasks.length} subtasks. Use --force to overwrite.`),{success:!0,data:{message:`Task ${h} already has subtasks. Expansion skipped.`,task:n,subtasksAdded:0,hasExistingSubtasks:i}};i&&b&&(t.info(`Force flag set. Clearing existing subtasks for task ${h}.`),n.subtasks=[]),JSON.parse(JSON.stringify(n));let a=n.subtasks?n.subtasks.length:0;n.subtasks||=[],y(m,e,d,f);let o=E(t),s;try{s=w(),s||S();let e=await Te(m,h,g,_,v,{complexityReportPath:p,mcpLog:o,session:r,projectRoot:d,commandName:`expand-task`,outputType:`mcp`,tag:f},b);!s&&w()&&x();let n=l(m,d).tasks.find(e=>e.id===h),c=n.subtasks?n.subtasks.length-a:0;return t.info(`Successfully expanded task ${h} with ${c} new subtasks`),{success:!0,data:{task:e.task,subtasksAdded:c,hasExistingSubtasks:i,telemetryData:e.telemetryData,tagInfo:e.tagInfo}}}catch(e){return!s&&w()&&x(),t.error(`Error expanding task: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message||`Failed to expand task`}}}}catch(e){return t.error(`Error expanding task: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message||`Failed to expand task`}}}}async