taskgraph-ai 0.54.12 → 0.54.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-services-unified-COsdujxy.js +1 -0
- package/dist/{ai-services-unified-BPPVDTpt.js → ai-services-unified-CvcPXr89.js} +1 -1
- package/dist/{commands-DJc5m0Gi.js → commands-C59cmYBr.js} +4 -4
- package/dist/config-manager-Cs19NriM.js +1 -0
- package/dist/{config-manager-CKwBfpAp.js → config-manager-CtE1yo1I.js} +1 -1
- package/dist/{init-CK_i6ZcN.js → init-DXIlIKlc.js} +2 -2
- package/dist/mcp-server.js +2 -2
- package/dist/{research-BKsPc_oX.js → research-CEiR5MKk.js} +1 -1
- package/dist/{research-C8rAJdp0.js → research-DcB3PdqA.js} +1 -1
- package/dist/{response-language-C8euRV2w.js → response-language-BdYSHT6o.js} +1 -1
- package/dist/response-language-Cve83SLc.js +1 -0
- package/dist/{src-DRpuDe-k.js → src-DvvdBXWU.js} +1 -1
- package/dist/{src-CK3olqVP.js → src-Dz_uZuYA.js} +1 -1
- package/dist/tag-management-BH0vY7RP.js +1 -0
- package/dist/{task-manager-BipYRXFW.js → task-manager-C-lF7v2M.js} +2 -2
- package/dist/{task-manager-B_UFNQnE.js → task-manager-rfPalXaq.js} +1 -1
- package/dist/taskgraph.js +1 -1
- package/package.json +2 -1
- package/dist/ai-services-unified-Dskm2lPO.js +0 -1
- package/dist/config-manager-Db2R8Tgw.js +0 -1
- package/dist/response-language-DiIdcmnK.js +0 -1
- package/dist/tag-management-BL0w3Tk3.js +0 -1
package/dist/mcp-server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{C as e,D as t,F as n,N as r,O as i,P as a,R as o,a as s,d as c,i as l,z as u}from"./src-
|
|
2
|
+
import{C as e,D as t,F as n,N as r,O as i,P as a,R as o,a as s,d as c,i as l,z as u}from"./src-DvvdBXWU.js";import{C as d,S as f,T as p,_ as m,a as h,b as g,c as _,d as v,f as y,g as ee,h as te,i as ne,l as re,n as ie,r as ae,s as oe,t as se,u as ce,v as le,w as ue,x as b,y as x}from"./task-manager-C-lF7v2M.js";import{F as de,H as S,L as C,N as fe,Q as w,R as T,St as pe,Tt as me,U as E,X as he,dt as ge,f as _e,it as D,kt as ve,ot as O,rt as ye,s as be,ut as xe,vt as Se,z as k}from"./config-manager-CtE1yo1I.js";import{c as Ce,f as we,h as Te,i as Ee,l as De,m as Oe,n as ke,o as Ae,r as je,s as Me,u as Ne}from"./src-Dz_uZuYA.js";import{n as Pe}from"./research-DcB3PdqA.js";import{a as Fe}from"./ai-services-unified-CvcPXr89.js";import{t as Ie}from"./response-language-BdYSHT6o.js";import{n as A,t as Le}from"./init-DXIlIKlc.js";import j from"chalk";import M from"node:path";import N from"node:fs";import P from"path";import{z as F}from"zod";import I from"dotenv";import L from"fs";import{fileURLToPath as R}from"url";import{FastMCP as Re}from"fastmcp";import ze from"os";const z={debug:0,info:1,warn:2,error:3,success:4},Be=z[_e().toLowerCase()]??z.info;function B(e,...t){if(w())return;let n={debug:j.dim(`[DEBUG]`),info:j.blue(`[INFO]`),warn:j.yellow(`[WARN]`),error:j.red(`[ERROR]`),success:j.green(`[SUCCESS]`)};if(z[e]!==void 0&&z[e]>=Be){let r=n[e]||``,i=t;try{switch(e){case`error`:i=t.map(e=>typeof e==`string`?j.red(e):e);break;case`warn`:i=t.map(e=>typeof e==`string`?j.yellow(e):e);break;case`success`:i=t.map(e=>typeof e==`string`?j.green(e):e);break;case`info`:i=t.map(e=>typeof e==`string`?j.blue(e):e);break;case`debug`:i=t.map(e=>typeof e==`string`?j.dim(e):e)}}catch(e){console.error(`Internal Logger Error applying chalk color:`,e),i=t}console.error(r,...i)}}function Ve(){let e=e=>(...t)=>B(e,...t);return{debug:e(`debug`),info:e(`info`),warn:e(`warn`),error:e(`error`),success:e(`success`),log:B}}const V=Ve();function He(e){return new Proxy(e,{get(e,t){if(t===`addTool`)return t=>e.addTool({...t,execute:(...e)=>xe(()=>t.execute(...e))});let n=e[t];return typeof n==`function`?n.bind(e):n}})}function Ue(){return{version:i||`unknown`,name:t||`taskgraph-ai`}}function H(e,t,n){t||=Ue();let r=`Error: ${e}
|
|
3
3
|
Version: ${t.version}
|
|
4
4
|
Name: ${t.name}`;return n&&(r+=`
|
|
5
|
-
Current Tag: ${n.currentTag}`),{content:[{type:`text`,text:r}],isError:!0}}function He(e,t){if(typeof e!=`function`)t?.debug?.(`reportProgress not available - operation will run without progress updates`);else return e}function Ue(e){try{let t=N.join(e,`.taskgraph`,`state.json`);return P.existsSync(t)&&JSON.parse(P.readFileSync(t,`utf-8`)).currentTag||`master`}catch{return null}}async function G(e){let{result:t,log:n,errorPrefix:r=`API error`,projectRoot:i,tag:a}=e,o=U(),s=a===void 0?i?Ue(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 K(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,`/`),N.resolve(t)}catch{return N.resolve(e)}}function We(e){try{return e?.roots?.[0]?.uri?K(e.roots[0].uri):e?.roots?.roots?.[0]?.uri?K(e.roots.roots[0].uri):null}catch{return null}}const Ge=/^[A-Za-z0-9_-]+$/;function q(e){return async(t,n)=>{let{log:r,session:i}=n,a=t.tag;if(a!==void 0&&!(typeof a==`string`&&Ge.test(a)))return W(`Invalid tag "${String(a)}": use only letters, numbers, hyphens and underscores`);let o=null,s=`unknown`;try{if(process.env.TASKGRAPH_PROJECT_ROOT){let e=process.env.TASKGRAPH_PROJECT_ROOT;o=N.isAbsolute(e)?e:N.resolve(process.cwd(),e),s=`TASKGRAPH_PROJECT_ROOT environment variable`,r?.info?.(`Using project root from ${s}: ${o}`)}else if(i?.env?.TASKGRAPH_PROJECT_ROOT){let e=i.env.TASKGRAPH_PROJECT_ROOT;o=N.isAbsolute(e)?e:N.resolve(process.cwd(),e),s=`TASKGRAPH_PROJECT_ROOT session environment variable`,r?.info?.(`Using project root from ${s}: ${o}`)}else if(t.projectRoot)o=K(t.projectRoot),s=`args.projectRoot`,r?.info?.(`Using project root from ${s}: ${o}`);else{let e=We(i);e&&(o=e,s=`session`,r?.info?.(`Using project root from ${s}: ${o}`))}return o?await e({...t,projectRoot:o},n):(r?.error?.(`Could not determine project root from environment, args, or session.`),G({result:{success:!1,error:{message:`Could not determine project root. Please provide projectRoot argument or ensure TASKGRAPH_PROJECT_ROOT environment variable is set.`}}}))}catch(e){return r?.error?.(`Error within withNormalizedProjectRoot HOF (Normalized Root: ${o}): ${e.message}`),e.stack&&r?.debug&&r.debug(e.stack),G({result:{success:!1,error:{message:`Operation failed: ${e.message}`}}})}}}function J(e){return q(async(t,n)=>{let r=await c({projectPath:t.projectRoot,loggerConfig:{mcpMode:!0,logCallback:n.log}});return e(t,{log:n.log,session:n.session,tmCore:r})})}function Ke(e,t){if(!e)return{parsedMetadata:null};if(process.env.TASKGRAPH_ALLOW_METADATA_UPDATES!==`true`)return{parsedMetadata:null,error:t(`Metadata updates are disabled. Set TASKGRAPH_ALLOW_METADATA_UPDATES=true in your MCP server environment to enable metadata modifications.`)};try{let n=JSON.parse(e);return typeof n!=`object`||!n||Array.isArray(n)?{parsedMetadata:null,error:t(`Invalid metadata: must be a JSON object (not null or array)`)}:{parsedMetadata:n}}catch(e){return{parsedMetadata:null,error:t(`Invalid metadata JSON: ${e instanceof Error?e.message:`Unknown parse error`}. Provide a valid JSON object string.`)}}}const qe=I.object({taskId:l.describe(`Main task ID to start workflow for (e.g., "1", "2"). Subtask IDs (e.g., "2.3", "1.1") are not allowed.`),projectRoot:I.string().describe(`Absolute path to the project root directory`),maxAttempts:I.number().optional().default(3).describe(`Maximum attempts per subtask (default: 3)`),force:I.boolean().optional().default(!1).describe(`Force start even if workflow state exists`)});function Je(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:qe,annotations:{title:`Start Autopilot Workflow`,destructiveHint:!0},execute:J(async(e,{log:t,tmCore:n})=>{let{taskId:r,projectRoot:i,maxAttempts:a,force:o}=e;try{t.info(`Starting autopilot workflow for task ${r} in ${i}`);let e=n.config.getActiveTag(),s=await n.tasks.get(r);if(!s||!s.task)return G({result:{success:!1,error:{message:`Task ${r} not found`}},log:t,projectRoot:i});let c=s.task;if(!c.subtasks||c.subtasks.length===0)return G({result:{success:!1,error:{message:`Task ${r} has no subtasks. Please use expand_task (with id="${r}") 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`),G({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 l=await n.workflow.start({taskId:r,taskTitle:c.title,subtasks:c.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,maxAttempts:a})),maxAttempts:a,force:o,tag:e});t.info(`Workflow started successfully for task ${r}`);let u=n.workflow.getNextAction();return G({result:{success:!0,data:{message:`Workflow started for task ${r}`,taskId:r,branchName:l.branchName,phase:l.phase,tddPhase:l.tddPhase,progress:l.progress,currentSubtask:l.currentSubtask,nextAction:u.action,nextSteps:u.nextSteps}},log:t,projectRoot:i})}catch(e){return t.error(`Error in autopilot-start: ${e.message}`),e.stack&&t.debug(e.stack),G({result:{success:!1,error:{message:`Failed to start workflow: ${e.message}`}},log:t,projectRoot:i})}})})}const Ye=I.object({projectRoot:I.string().describe(`Absolute path to the project root directory`)});function Xe(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:Ye,annotations:{title:`Resume Autopilot Workflow`,readOnlyHint:!0},execute:J(async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Resuming autopilot workflow in ${r}`),!await n.workflow.hasWorkflow())return G({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}`),G({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),G({result:{success:!1,error:{message:`Failed to resume workflow: ${e.message}`}},log:t,projectRoot:r})}})})}const Ze=I.object({projectRoot:I.string().describe(`Absolute path to the project root directory`)});function Qe(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:Ze,annotations:{title:`Get Next Autopilot Action`,readOnlyHint:!0},execute:J(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 G({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}`),G({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),G({result:{success:!1,error:{message:`Failed to get next action: ${e.message}`}},log:t,projectRoot:r})}})})}const $e=I.object({projectRoot:I.string().describe(`Absolute path to the project root directory`)});function et(e){e.addTool({name:`autopilot_status`,description:`Get comprehensive workflow status including current phase, progress, subtask details, and activity history.`,parameters:$e,annotations:{title:`Get Autopilot Status`,readOnlyHint:!0},execute:J(async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Getting workflow status for ${r}`),!await n.workflow.hasWorkflow())return G({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}`),G({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),G({result:{success:!1,error:{message:`Failed to get workflow status: ${e.message}`}},log:t,projectRoot:r})}})})}const tt=I.object({projectRoot:I.string().describe(`Absolute path to the project root directory`),testResults:I.object({total:I.number().describe(`Total number of tests`),passed:I.number().describe(`Number of passing tests`),failed:I.number().describe(`Number of failing tests`),skipped:I.number().optional().describe(`Number of skipped tests`)}).describe(`Test results from running the test suite`)});function nt(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:tt,annotations:{title:`Complete Autopilot Phase`,destructiveHint:!0},execute:J(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 G({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 G({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 G({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}`),G({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),G({result:{success:!1,error:{message:`Failed to complete phase: ${e.message}`}},log:t,projectRoot:r})}})})}const rt=I.object({projectRoot:I.string().describe(`Absolute path to the project root directory`),files:I.array(I.string()).optional().describe(`Specific files to stage (relative to project root). If not provided, stages all changes.`),customMessage:I.string().optional().describe(`Custom commit message to use instead of auto-generated message`)});function it(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:rt,annotations:{title:`Commit Autopilot Changes`,destructiveHint:!0},execute:J(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 G({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(),s=n.workflow.getContext();if(e.tddPhase!==`COMMIT`)return t.warn(`Not in COMMIT phase (currently in ${e.tddPhase})`),G({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 G({result:{success:!1,error:{message:`No active subtask to commit`}},log:t,projectRoot:r});let c=new u(r);try{i&&i.length>0?(await c.stageFiles(i),t.info(`Staged ${i.length} files`)):(await c.stageFiles([`.`]),t.info(`Staged all changes`))}catch(e){return t.error(`Failed to stage files: ${e.message}`),G({result:{success:!1,error:{message:`Failed to stage files: ${e.message}`}},log:t,projectRoot:r})}if(!await c.hasStagedChanges())return t.warn(`No staged changes to commit`),G({result:{success:!1,error:{message:`No staged changes to commit. Make code changes before committing`}},log:t,projectRoot:r});let l=await c.getStatus(),d;if(a)d=a,t.info(`Using custom commit message`);else{let n=new o,r={type:e.tddPhase===`COMMIT`?`feat`:`test`,description:e.currentSubtask.title,changedFiles:l.staged,taskId:e.taskId,phase:e.tddPhase,testsPassing:s.lastTestResults?.passed,testsFailing:s.lastTestResults?.failed};d=n.generateMessage(r),t.info(`Generated commit message automatically`)}try{await c.createCommit(d),t.info(`Commit created successfully`)}catch(e){return t.error(`Failed to create commit: ${e.message}`),G({result:{success:!1,error:{message:`Failed to create commit: ${e.message}`}},log:t,projectRoot:r})}let f=await c.getLastCommit(),p=await n.workflow.commit();t.info(`Commit completed. Current phase: ${p.tddPhase||p.phase}`);let m=p.phase===`COMPLETE`,h=n.workflow.getNextAction();return G({result:{success:!0,data:{message:m?`Workflow completed successfully`:`Commit created and workflow advanced`,commitSha:f.sha,commitMessage:d,...p,isComplete:m,nextAction:h.action,nextSteps:h.nextSteps}},log:t,projectRoot:r})}catch(e){return t.error(`Error in autopilot-commit: ${e.message}`),e.stack&&t.debug(e.stack),G({result:{success:!1,error:{message:`Failed to commit: ${e.message}`}},log:t,projectRoot:r})}})})}const at=I.object({projectRoot:I.string().describe(`Absolute path to the project root directory`)});function ot(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:at,annotations:{title:`Finalize Autopilot Workflow`,destructiveHint:!0},execute:J(async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Finalizing workflow in ${r}`),!await n.workflow.hasWorkflow())return G({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 G({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 G({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),G({result:{success:!1,error:{message:`Failed to finalize workflow: ${e.message}`}},log:t,projectRoot:r})}})})}const st=I.object({projectRoot:I.string().describe(`Absolute path to the project root directory`)});function ct(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:st,annotations:{title:`Abort Autopilot Workflow`,destructiveHint:!0},execute:J(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`),G({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`),G({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),G({result:{success:!1,error:{message:`Failed to abort workflow: ${e.message}`}},log:t,projectRoot:r})}})})}const lt=I.object({projectRoot:I.string().describe(`Absolute path to the project root directory`),repo:I.string().optional().describe(`Repository as owner/name (default: detected through gh)`)});function ut(e){e.addTool({name:`github_status`,description:`Check whether the gh CLI is usable, which GitHub repository tasks would be pushed to, and how many tasks are already linked to issues.`,parameters:lt,annotations:{title:`GitHub Sync Status`,readOnlyHint:!0},execute:J(async(e,{log:t,tmCore:n})=>{let{projectRoot:r,repo:i}=e;try{return t.info(`Checking GitHub sync status for ${r}`),G({result:{success:!0,data:await n.github.status({repo:i})},log:t,projectRoot:r})}catch(e){return t.error(`Error in github_status: ${e.message}`),G({result:{success:!1,error:{message:`Failed to get GitHub status: ${e.message}`}},log:t,projectRoot:r})}})})}const dt=I.object({projectRoot:I.string().describe(`Absolute path to the project root directory`),dryRun:I.boolean().optional().default(!0).describe(`Preview the plan without writing to GitHub (default: true). Pass false to create and update issues.`),tag:I.string().optional().describe(`Tag to push (default: the active tag)`),allTags:I.boolean().optional().describe(`Push every tag instead of one`),id:I.string().optional().describe(`Only push these top-level task IDs, comma separated`),repo:I.string().optional().describe(`Repository as owner/name (default: detected through gh)`),includeDetails:I.boolean().optional().describe(`Include the task details field in issue bodies`),closeOrphans:I.boolean().optional().describe(`Close open issues whose task no longer exists`)});function ft(e){e.addTool({name:`github_push`,description:`Push tasks to GitHub Issues through the gh CLI: creates issues, updates changed ones and closes finished ones. Runs as a dry run unless dryRun is false, so call it once to review the plan before writing.`,parameters:dt,annotations:{title:`Push Tasks to GitHub`,readOnlyHint:!1,destructiveHint:!1,openWorldHint:!0},execute:J(async(e,{log:t,tmCore:n})=>{let{projectRoot:r,id:i,dryRun:a=!0,...o}=e;try{return t.info(`Pushing tasks to GitHub for ${r} (dryRun: ${a})`),G({result:{success:!0,data:await n.github.push({...o,dryRun:a,taskIds:i})},log:t,projectRoot:r})}catch(e){return t.error(`Error in github_push: ${e.message}`),G({result:{success:!1,error:{message:`Failed to push to GitHub: ${e.message}`}},log:t,projectRoot:r})}})})}const pt=I.object({id:a.optional().describe(`Task or subtask ID (e.g. 5 or 5.2) to explain what blocks it`),limit:I.number().int().positive().optional().describe(`How many bottlenecks to return (default 5)`),projectRoot:I.string().describe(`Absolute path to the project root directory`),tag:I.string().optional().describe(`Tag context to operate on`)});function mt(e){e.addTool({name:`dependency_analysis`,description:`Find the bottlenecks (open tasks holding up the most work), the critical path and dependency cycles. With id, also explain what blocks that task.`,parameters:pt,annotations:{title:`Dependency Analysis`,readOnlyHint:!0},execute:J(async(e,{log:t,tmCore:n})=>{let{id:r,limit:i,projectRoot:a,tag:o}=e;try{return t.info(`Analyzing dependencies${r?` for task ${r}`:``} in ${a}`),G({result:{success:!0,data:await n.tasks.analyzeDependencies({tag:o,limit:i,taskId:r})},log:t,projectRoot:a,tag:o})}catch(e){return t.error(`Error in dependency_analysis: ${e.message}`),G({result:{success:!1,error:{message:`Failed to analyze dependencies: ${e.message}`}},log:t,projectRoot:a})}})})}const ht=I.object({projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),status:I.string().optional().describe(`Filter tasks by status (e.g., 'pending', 'done') or multiple statuses separated by commas (e.g., 'blocked,deferred')`),withSubtasks:I.boolean().optional().describe(`Include subtasks nested within their parent tasks in the response`),tag:I.string().optional().describe(`Tag context to operate on`)});function gt(e){e.addTool({name:`get_tasks`,description:`Get all tasks from TaskGraph, optionally filtering by status and including subtasks.`,parameters:ht,annotations:{title:`Get Tasks`,readOnlyHint:!0},execute:J(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 G({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),G({result:{success:!1,error:{message:`Failed to get tasks: ${e.message}`}},log:t,projectRoot:r})}})})}const _t=I.object({id:n.describe(`Task ID(s) to get (can be comma-separated for multiple tasks)`),status:I.string().optional().describe(`Filter subtasks by status (e.g., 'pending', 'done')`),projectRoot:I.string().describe(`Absolute path to the project root directory (Optional, usually from session)`),tag:I.string().optional().describe(`Tag context to operate on`)});function vt(e){e.addTool({name:`get_task`,description:`Get detailed information about a specific task`,parameters:_t,annotations:{title:`Get Task`,readOnlyHint:!0},execute:J(async(e,{log:t,tmCore:n})=>{let{id:i,status:a,projectRoot:o,tag:s}=e;try{t.info(`Getting task details for ID: ${i}${a?` (filtering subtasks by status: ${a})`:``} in root: ${o}`);let e=r(i),c=await Promise.all(e.map(e=>n.tasks.get(e,s))),l=[];for(let e of c)if(e.task){if(a&&e.task.subtasks){let t=a.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): ${i}`),G({result:{success:!1,error:{message:`No tasks found for ID(s): ${i}`}},log:t,projectRoot:o})):(t.info(`Successfully retrieved ${l.length} task(s) for ID(s): ${i}`),G({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),G({result:{success:!1,error:{message:`Failed to get task: ${e.message}`}},log:t,projectRoot:o})}})})}const yt=I.object({output:I.string().optional().describe(`Output directory for generated files (default: same directory as tasks file)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)});function bt(e){e.addTool({name:`generate`,description:`Generates individual task files in tasks/ directory based on tasks.json. Only works with local file storage.`,parameters:yt,annotations:{title:`Generate Task Files`,destructiveHint:!0},execute:J(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?N.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`}`),G({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),G({result:{success:!1,error:{message:`Failed to generate task files: ${e.message}`}},log:t,projectRoot:r})}})})}const xt=I.object({id:n.describe(`Task ID or subtask ID (e.g., '15', '15.2'). Can be comma-separated to update multiple tasks/subtasks at once.`),status:I.enum(e).describe(`New status to set (e.g., 'pending', 'done', 'in-progress', 'review', 'deferred', 'cancelled').`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Optional tag context to operate on`)});function St(e){e.addTool({name:`set_task_status`,description:`Set the status of one or more tasks or subtasks.`,parameters:xt,annotations:{title:`Set Task Status`,destructiveHint:!0},execute:J(async(e,{log:t,tmCore:n})=>{let{id:i,status:a,projectRoot:o,tag:s}=e;try{t.info(`Setting status of task(s) ${i} to: ${a}${s?` in tag: ${s}`:` in current tag`}`);let e=r(i),c=[];for(let r of e){let e=await n.tasks.updateStatus(r,a,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 "${a}"`),G({result:{success:!0,data:{message:`Successfully updated ${c.length} task(s) to "${a}"`,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),G({result:{success:!1,error:{message:`Failed to set task status: ${n.message}`}},log:t,projectRoot:o,tag:s})}})})}async function Ct(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}`),O(),await f(s,c,l,{projectRoot:o,tag:a}),C(),{success:!0,data:{message:`Successfully added dependency: Task ${c} now depends on ${l}`,taskId:c,dependencyId:l}}}catch(e){return C(),t.error(`Error in addDependencyDirect: ${e.message}`),{success:!1,error:{code:e instanceof b?e.code:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function wt(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,_=parseInt(r,10),v=!u;O();let y={projectRoot:d,tag:f};if(h){t.info(`Converting task ${h} to a subtask of ${_}`);let e=await g(p,_,h,null,v,y);return C(),{success:!0,data:{message:`Task ${h} successfully converted to a subtask of task ${_}`,subtask:e}}}{t.info(`Creating new subtask for parent task ${_}`);let e=await g(p,_,null,{title:a,description:o||``,details:s||``,status:c||`pending`,dependencies:m},v,y);return C(),{success:!0,data:{message:`New subtask ${_}.${e.id} successfully created`,subtask:e}}}}catch(e){return C(),t.error(`Error in addSubtaskDirect: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message}}}}function Y(e,t){let n=F.resolve(e);try{n=R.realpathSync(e)}catch{}if(!Ne(n,t))throw Error(`Path '${t}' is outside the project root '${e}'`);return F.resolve(e,t)}const X={info:()=>{},warn:()=>{},error:()=>{},debug:()=>{},success:()=>{}};function Tt(e,t=X){let n=e?.file,r=e?.projectRoot;if(n&&!r&&F.isAbsolute(n))throw Error(`projectRoot is required when a file path is absolute`);let i=r?D(r):null;if(n&&i)return Y(i,n);if(i){let e=w(n,{projectRoot:i},t);if(e===null&&!n){let e=F.join(i,`.taskgraph`,`tasks`,`tasks.json`);return t?.info?.(`Core findTasksPath returned null, using default path: ${e}`),e}return e}return w(n,null,t)}function Et(e,t=X){let n=e?.input,r=e?.projectRoot;if(n&&!r&&F.isAbsolute(n))throw Error(`projectRoot is required when a file path is absolute`);let i=r?D(r):null;return n&&i?Y(i,n):i?S(n,{projectRoot:i},t):S(n,null,t)}function Dt(e,t=X){let n=e?.complexityReport,r=e?.projectRoot,i=e?.tag;if(n&&!r&&F.isAbsolute(n))throw Error(`projectRoot is required when a file path is absolute`);let a=r?D(r):null;return n&&a?Y(a,n):a?T(n,{projectRoot:a,tag:i},t):T(n,null,t)}function Ot(e,t){if(!t?.projectRoot)throw Error(`projectRoot is required in args to resolve project paths`);let n=D(t.projectRoot);return F.isAbsolute(e)?e:F.resolve(n,e)}function Z(e,t=X){return Tt(e,t)}function kt(e,t=X){return Dt(e,t)}function At(e,t,n=X){return j(e,t,n)}z(import.meta.url);function Q(e){return{info:(t,...n)=>e.info(t,...n),warn:(t,...n)=>e.warn(t,...n),error:(t,...n)=>e.error(t,...n),debug:(t,...n)=>e.debug?e.debug(t,...n):null,success:(t,...n)=>e.info(t,...n)}}async function jt(e,t,n={}){let{tasksJsonPath:r,name:i,copyFromCurrent:a=!1,copyFromTag:o,fromBranch:s=!1,description:c,projectRoot:l}=e,{session:u}=n;O();let d=Q(t);try{if(!r)return t.error(`addTagDirect called without tasksJsonPath`),C(),{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-CRR3iPaC.js`);if(!await e.isGitRepository(l))return t.error(`Not in a git repository`),C(),{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`),C(),{success:!1,error:{code:`NO_CURRENT_BRANCH`,message:`Could not determine current git branch.`}};let i={copyFromCurrent:a,copyFromTag:o,description:c||`Tag created from git branch "${n}"`},s=await xe(r,n,i,{session:u,mcpLog:d,projectRoot:l},`json`);return C(),{success:!0,data:{branchName:s.branchName,tagName:s.tagName,created:s.created,mappingUpdated:s.mappingUpdated,message:`Successfully created tag "${s.tagName}" from git branch "${s.branchName}"`}}}{if(!i||typeof i!=`string`)return t.error(`Missing required parameter: name`),C(),{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 Ae(r,i,{copyFromCurrent:a,copyFromTag:o,description:c},{session:u,mcpLog:d,projectRoot:l},`json`);return C(),{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 C(),t.error(`Error in addTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`ADD_TAG_ERROR`,message:e.message}}}}async function Mt(e,t,n={}){let{tasksJsonPath:r,prompt:i,dependencies:a,priority:o,research:s,projectRoot:c,tag:l}=e,{session:u}=n;O();let d=Q(t);try{if(!r)return t.error(`addTaskDirect called without tasksJsonPath`),C(),{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`),C(),{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 x(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 x(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 C(),{success:!0,data:{taskId:g,message:`Successfully added new task #${g}`,telemetryData:_,tagInfo:v}}}catch(e){return C(),t.error(`Error in addTaskDirect: ${e.message}`),{success:!1,error:{code:e.code||`ADD_TASK_ERROR`,message:e.message}}}}async function Nt(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=Q(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=E();g||O();let _;try{_=await le(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&&E()&&C(),{success:!1,error:{code:`ANALYZE_CORE_ERROR`,message:`Error running core complexity analysis: ${e.message}`}}}finally{!g&&E()&&C()}if(!R.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 E()&&C(),t.error(`Error in analyzeTaskComplexityDirect setup: ${e.message}`),{success:!1,error:{code:`DIRECT_FUNCTION_SETUP_ERROR`,message:e.message}}}}async function Pt(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(!R.existsSync(s))return{success:!1,error:{code:`FILE_NOT_FOUND_ERROR`,message:`Tasks file not found at ${s}`}};let c,l=k(s,o,a);if(!l||!l.tasks)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`No tasks found in tasks file: ${s}`}};let u=l.tag||a,d=l.tasks;if(i){if(t.info(`Clearing subtasks from all tasks in tag '${u}'`),d.length===0)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`No tasks found in tag context '${u}'`}};c=d.map(e=>e.id).join(`,`)}else c=r;t.info(`Clearing subtasks from tasks: ${c} in tag '${u}'`),O();let f;try{f=m(s,c,{projectRoot:o,tag:u})}finally{C()}let{cleared:p,empty:h}=f,g=p.reduce((e,t)=>e+t.count,0);return{success:!0,data:{message:p.length>0?`Cleared ${g} subtask(s) from ${p.length} task(s) in tag '${u}'`:`No subtasks to clear in tag '${u}'`,tasksCleared:p.map(({id:e,title:t,count:n})=>({id:e,title:t,subtasksCleared:n})),tasksWithoutSubtasks:h,tag:u}}}catch(e){return t.error(`Error in clearSubtasksDirect: ${e.message}`),{success:!1,error:{code:e.name===`ClearSubtasksError`?`INPUT_VALIDATION_ERROR`:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function Ft(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{O();let e=_e(n);return C(),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 C(),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 C(),t.error(`Unexpected error during complexityReport: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}catch(e){return C(),t.error(`Error in complexityReportDirect: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}async function It(e,t,n={}){let{tasksJsonPath:r,sourceName:i,targetName:a,description:o,projectRoot:s}=e,{session:c}=n;O();let l=Q(t);try{if(!r)return t.error(`copyTagDirect called without tasksJsonPath`),C(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: sourceName`),C(),{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`),C(),{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 Oe(r,i,a,{description:o},{session:c,mcpLog:l,projectRoot:s},`json`);return C(),{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 C(),t.error(`Error in copyTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`COPY_TAG_ERROR`,message:e.message}}}}async function Lt(e,t,n={}){let{tasksJsonPath:r,name:i,yes:a=!1,projectRoot:o}=e,{session:s}=n;O();let c=Q(t);try{if(!r)return t.error(`deleteTagDirect called without tasksJsonPath`),C(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: name`),C(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Tag name is required and must be a string`}};t.info(`Deleting tag: ${i}`);let e=await Te(r,i,{yes:a},{session:s,mcpLog:c,projectRoot:o},`json`);return C(),{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 C(),t.error(`Error in deleteTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`DELETE_TAG_ERROR`,message:e.message}}}}async function Rt(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=Q(t),p=d||j(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`}};O();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 te(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{C()}}async function zt(e,t,n={}){let{session:r}=n,{tasksJsonPath:i,id:a,num:o,research:s,prompt:c,force:l,projectRoot:u,tag:d,complexityReportPath:f}=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 p=i;t.info(`[expandTaskDirect] Using tasksPath: ${p}`);let m=a?parseInt(a,10):null;if(!m)return t.error(`Task ID is required`),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Task ID is required`}};let h=o?parseInt(o,10):void 0,g=s===!0,_=c||``,v=l===!0;try{t.info(`[expandTaskDirect] Expanding task ${m} into ${h||`default`} subtasks. Research: ${g}, Force: ${v}`),t.info(`[expandTaskDirect] Attempting to read JSON from: ${p}`);let e=k(p,u);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: ${p}`),{success:!1,error:{code:`INVALID_TASKS_FILE`,message:`No valid tasks found in ${p}. readJSON returned: ${JSON.stringify(e)}`}};t.info(`[expandTaskDirect] Searching for task ID ${m} in data`);let n=e.tasks.find(e=>e.id===m);if(t.info(`[expandTaskDirect] Task found: ${n?`Yes`:`No`}`),!n)return{success:!1,error:{code:`TASK_NOT_FOUND`,message:`Task with ID ${m} not found`}};if(n.status===`done`||n.status===`completed`)return{success:!1,error:{code:`TASK_COMPLETED`,message:`Task ${m} is already marked as ${n.status} and cannot be expanded`}};let i=n.subtasks&&n.subtasks.length>0;if(i&&!v)return t.info(`Task ${m} already has ${n.subtasks.length} subtasks. Use --force to overwrite.`),{success:!0,data:{message:`Task ${m} already has subtasks. Expansion skipped.`,task:n,subtasksAdded:0,hasExistingSubtasks:i}};i&&v&&(t.info(`Force flag set. Clearing existing subtasks for task ${m}.`),n.subtasks=[]),JSON.parse(JSON.stringify(n));let a=n.subtasks?n.subtasks.length:0;n.subtasks||=[],me(p,e,u,d);let o=Q(t),s;try{s=E(),s||O();let e=await ee(p,m,h,g,_,{complexityReportPath:f,mcpLog:o,session:r,projectRoot:u,commandName:`expand-task`,outputType:`mcp`,tag:d},v);!s&&E()&&C();let n=k(p,u).tasks.find(e=>e.id===m),c=n.subtasks?n.subtasks.length-a:0;return t.info(`Successfully expanded task ${m} with ${c} new subtasks`),{success:!0,data:{task:e.task,subtasksAdded:c,hasExistingSubtasks:i,telemetryData:e.telemetryData,tagInfo:e.tagInfo}}}catch(e){return!s&&E()&&C(),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 function Bt(e,t){let{tasksJsonPath:n,projectRoot:r,tag:i}=e;try{if(t.info(`Fixing invalid dependencies in tasks: ${n}`),!n)return t.error(`fixDependenciesDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};let e=n;if(!R.existsSync(e))return{success:!1,error:{code:`FILE_NOT_FOUND`,message:`Tasks file not found at ${e}`}};O();let a=await d(e,{context:{projectRoot:r,tag:i}});return C(),{success:!0,data:{message:a.remaining.length>0?`Fixed ${a.fixes.length} dependency problem(s); ${a.remaining.length} left that need a decision, such as loops between tasks`:`Fixed ${a.fixes.length} dependency problem(s)`,...a,tasksPath:e,tag:i||`master`}}}catch(e){return C(),t.error(`Error fixing dependencies: ${e.message}`),{success:!1,error:{code:e instanceof b?e.code:`FIX_DEPENDENCIES_ERROR`,message:e.message}}}}async function Vt(e,t,n={}){let{session:r}=n,i=Re.homedir();t.info(`Args received in direct function: ${JSON.stringify(e)}`);let a=e.projectRoot;if(!a||typeof a!=`string`||a===`/`||a===i)return t.error(`Invalid target directory received from tool layer: '${a}'`),{success:!1,error:{code:`INVALID_TARGET_DIRECTORY`,message:`Cannot initialize project: Invalid target directory '${a}' received. Please ensure a valid workspace/folder is open or specified.`,details:`Received args.projectRoot: ${e.projectRoot}`}};t.info(`Validated target directory for initialization: ${a}`);let o=process.cwd(),s,c=!1,l=null;t.info(`Temporarily changing CWD to ${a} for initialization.`),process.chdir(a),O();try{let n={addAliases:e.addAliases,initGit:e.initGit,storeTasksInGit:e.storeTasksInGit,skipInstall:e.skipInstall,yes:!0};Array.isArray(e.rules)&&e.rules.length>0?(n.rules=e.rules,n.rulesExplicitlyProvided=!0,t.info(`Including rules: ${e.rules.join(`, `)}`)):(n.rules=[`claude`],n.rulesExplicitlyProvided=!0,t.info(`No rule profiles specified, defaulting to: Claude`)),t.info(`Initializing project with options: ${JSON.stringify(n)}`),s={message:`Project initialized successfully.`,next_step:`Now that the project is initialized, the next step is to create the tasks by parsing a PRD. This will create the tasks folder and the initial task files (tasks folder will be created when parse-prd is run). The parse-prd tool will require a prd.txt file as input (typically found in .taskgraph/docs/ directory). You can create a prd.txt file by asking the user about their idea, and then using the .taskgraph/templates/example_prd.txt file as a template to generate a prd.txt file in .taskgraph/docs/. You may skip all of this if the user already has a prd.txt file. You can THEN use the parse-prd tool to create the tasks. So: step 1 after initialization is to create a prd.txt file in .taskgraph/docs/prd.txt or confirm the user already has one. Step 2 is to use the parse-prd tool to create the tasks. Do not bother looking for tasks after initialization, just use the parse-prd tool to create the tasks after creating a prd.txt from which to parse the tasks. You do NOT need to reinitialize the project to parse-prd.`,...await Ie(n)},c=!0,t.info(`Project initialization completed successfully in ${a}.`)}catch(e){t.error(`Core initializeProject failed: ${e.message}`),l={code:`INITIALIZATION_FAILED`,message:`Core project initialization failed: ${e.message}`,details:e.stack},c=!1}finally{C(),t.info(`Restoring original CWD: ${o}`),process.chdir(o)}return c?{success:!0,data:s}:{success:!1,error:l}}async function Ht(e,t,n={}){let{tasksJsonPath:r,showMetadata:i=!1,projectRoot:a}=e,{session:o}=n;O();let s=Q(t);try{if(!r)return t.error(`listTagsDirect called without tasksJsonPath`),C(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};t.info(`Listing all tags`);let e=await Se(r,{showMetadata:i},{session:o,mcpLog:s,projectRoot:a},`json`),n=e.tags.map(e=>{let t=e.tasks||[],n=t.reduce((e,t)=>{let n=t.status||`pending`;return e[n]=(e[n]||0)+1,e},{}),r=t.reduce((e,t)=>(t.subtasks&&t.subtasks.length>0&&(e.totalSubtasks+=t.subtasks.length,t.subtasks.forEach(t=>{let n=t.status||`pending`;e.subtasksByStatus[n]=(e.subtasksByStatus[n]||0)+1})),e),{totalSubtasks:0,subtasksByStatus:{}});return{name:e.name,isCurrent:e.isCurrent,taskCount:t.length,completedTasks:e.completedTasks,statusBreakdown:n,subtaskCounts:r,created:e.created,description:e.description}});return C(),{success:!0,data:{tags:n,currentTag:e.currentTag,totalTags:e.totalTags,message:`Found ${e.totalTags} tag(s)`}}}catch(e){return C(),t.error(`Error in listTagsDirect: ${e.message}`),{success:!1,error:{code:e.code||`LIST_TAGS_ERROR`,message:e.message}}}}const Ut=[`main`,`research`,`fallback`];async function Wt(e,t){for(let n of Ut){let r=`set${n.charAt(0).toUpperCase()+n.slice(1)}`;if(e[r])return await we(n,e[r],t)}return null}async function Gt(e,t,n={}){let{session:r}=n,{projectRoot:i}=e,a=Q(t);t.info(`Executing models_direct with args: ${JSON.stringify(e)}`),t.info(`Using project root: ${i}`);try{O();try{return e.listAvailableModels===!0?await De({session:r,mcpLog:a,projectRoot:i}):await Wt(e,{session:r,mcpLog:a,projectRoot:i})||await ke({session:r,mcpLog:a,projectRoot:i})}finally{C()}}catch(e){return t.error(`Error in models_direct: ${e.message}`),{success:!1,error:{code:`DIRECT_FUNCTION_ERROR`,message:e.message,details:e.stack}}}}async function Kt(e,t,n={}){let{session:r}=n,{projectRoot:i}=e;if(t.info(`moveTaskCrossTagDirect called with args: ${JSON.stringify(e)}`),!e.sourceIds)return{success:!1,error:{message:`Source IDs are required`,code:`MISSING_SOURCE_IDS`}};if(!e.sourceTag)return{success:!1,error:{message:`Source tag is required for cross-tag moves`,code:`MISSING_SOURCE_TAG`}};if(!e.targetTag)return{success:!1,error:{message:`Target tag is required for cross-tag moves`,code:`MISSING_TARGET_TAG`}};if(e.sourceTag===e.targetTag)return{success:!1,error:{message:`Source and target tags are the same ("${e.sourceTag}")`,code:`SAME_SOURCE_TARGET_TAG`,suggestions:[`Use different tags for cross-tag moves`,`Use within-tag move: taskgraph move --from=<id> --to=<id> --tag=<tag>`,`Check available tags: taskgraph tags`]}};try{let n=e.tasksJsonPath||e.file;if(!n){if(!e.projectRoot)return{success:!1,error:{message:`Project root is required if tasksJsonPath is not provided`,code:`MISSING_PROJECT_ROOT`}};n=Z(e,t)}O();try{let t=e.sourceIds.split(`,`).map(e=>e.trim()),r={withDependencies:e.withDependencies||!1,ignoreDependencies:e.ignoreDependencies||!1};return{success:!0,data:{...await y(n,t,e.sourceTag,e.targetTag,r,{projectRoot:i}),message:`Successfully moved ${t.length} task(s) from "${e.sourceTag}" to "${e.targetTag}"`,moveOptions:r,sourceTag:e.sourceTag,targetTag:e.targetTag}}}finally{C()}}catch(e){t.error(`Failed to move tasks between tags: ${e.message}`),t.error(`Error code: ${e.code}, Error name: ${e.name}`);let n=`MOVE_TASK_CROSS_TAG_ERROR`,r=[];return e.code===`CROSS_TAG_DEPENDENCY_CONFLICTS`?(n=`CROSS_TAG_DEPENDENCY_CONFLICT`,r=[`Use --with-dependencies to move dependent tasks together`,`Use --ignore-dependencies to break cross-tag dependencies`,`Run taskgraph validate-dependencies to check for issues`,`Move dependencies first, then move the main task`]):e.code===`CANNOT_MOVE_SUBTASK`?(n=`SUBTASK_MOVE_RESTRICTION`,r=[`Promote subtask to full task first: taskgraph remove-subtask --id=<subtaskId> --convert`,`Move the parent task with all subtasks using --with-dependencies`]):e.code===`TASK_NOT_FOUND`||e.code===`INVALID_SOURCE_TAG`||e.code===`INVALID_TARGET_TAG`?(n=`TAG_OR_TASK_NOT_FOUND`,r=[`Check available tags: taskgraph tags`,`Verify task IDs exist: taskgraph list`,`Check task details: taskgraph show <id>`]):e.message.includes(`cross-tag dependency conflicts`)?(n=`CROSS_TAG_DEPENDENCY_CONFLICT`,r=[`Use --with-dependencies to move dependent tasks together`,`Use --ignore-dependencies to break cross-tag dependencies`,`Run taskgraph validate-dependencies to check for issues`,`Move dependencies first, then move the main task`]):e.message.includes(`Cannot move subtask`)?(n=`SUBTASK_MOVE_RESTRICTION`,r=[`Promote subtask to full task first: taskgraph remove-subtask --id=<subtaskId> --convert`,`Move the parent task with all subtasks using --with-dependencies`]):e.message.includes(`not found`)?(n=`TAG_OR_TASK_NOT_FOUND`,r=[`Check available tags: taskgraph tags`,`Verify task IDs exist: taskgraph list`,`Check task details: taskgraph show <id>`]):(e.code===`TASK_ALREADY_EXISTS`||e.message?.includes(`already exists in target tag`))&&(n=`TASK_ALREADY_EXISTS`,r=[`Choose a different target tag without conflicting IDs`,`Move a different set of IDs (avoid existing ones)`,`If needed, move within-tag to a new ID first, then cross-tag move`]),{success:!1,error:{message:e.message,code:n,suggestions:r}}}}async function qt(e,t,n={}){let{session:r}=n,{projectRoot:i,tag:a}=e;if(!e.sourceId)return{success:!1,error:{message:`Source ID is required`,code:`MISSING_SOURCE_ID`}};if(!e.destinationId)return{success:!1,error:{message:`Destination ID is required`,code:`MISSING_DESTINATION_ID`}};try{let n=e.tasksJsonPath||e.file;if(!n){if(!e.projectRoot)return{success:!1,error:{message:`Project root is required if tasksJsonPath is not provided`,code:`MISSING_PROJECT_ROOT`}};n=Z(e,t)}O();let r=e.generateFiles!==!1,o=await v(n,e.sourceId,e.destinationId,r,{projectRoot:i,tag:a});return C(),{success:!0,data:{...o,message:`Successfully moved task/subtask ${e.sourceId} to ${e.destinationId}`}}}catch(e){return C(),t.error(`Failed to move task: ${e.message}`),{success:!1,error:{message:e.message,code:`MOVE_TASK_ERROR`}}}}async function Jt(e,t,n={}){let{tasksJsonPath:r,reportPath:i,projectRoot:a,tag:o}=e,{session:s}=n;if(!r)return t.error(`nextTaskDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};let c=async()=>{try{O(),t.info(`Finding next task from ${r}`);let e=k(r,a,o);if(!e||!e.tasks)return C(),{success:!1,error:{code:`INVALID_TASKS_FILE`,message:`No valid tasks found in ${r}`}};let n=_e(i),s=Ce(e.tasks,n);if(!s)return t.info(`No eligible next task found. All tasks are either completed or have unsatisfied dependencies`),{success:!0,data:{message:`No eligible next task found. All tasks are either completed or have unsatisfied dependencies`,nextTask:null}};let c=typeof s.id==`string`&&s.id.includes(`.`),l=c?`subtask`:`task`,u=c?`Subtasks can be updated with timestamped details as you implement them. This is useful for tracking progress, marking milestones and insights (of successful or successive falures in attempting to implement the subtask). Research can be used when updating the subtask to collect up-to-date information, and can be helpful to solve a repeating problem the agent is unable to solve. It is a good idea to get-task the parent task to collect the overall context of the task, and to get-task the subtask to collect the specific details of the subtask.`:`Tasks can be updated to reflect a change in the direction of the task, or to reformulate the task per your prompt. Research can be used when updating the task to collect up-to-date information. It is best to update subtasks as you work on them, and to update the task for more high-level changes that may affect pending subtasks or the general direction of the task.`;return C(),t.info(`Successfully found next task ${s.id}: ${s.title}. Is subtask: ${c}`),{success:!0,data:{nextTask:s,isSubtask:c,nextSteps:`When ready to work on the ${l}, use set-status to set the status to "in progress" ${u}`}}}catch(e){return C(),t.error(`Error finding next task: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message||`Failed to find next task`}}}};try{let e=await c();return t.info(`nextTaskDirect completed.`),e}catch(e){return t.error(`Unexpected error during nextTask: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}async function Yt(e,t,n={}){let{session:r,reportProgress:i}=n,{input:a,output:o,numTasks:s,force:c,append:l,research:u,projectRoot:d,tag:f}=e,p=Q(t);if(!d)return p.error(`parsePRDDirect requires a projectRoot argument.`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`projectRoot is required.`}};let m;if(a)try{m=Et({input:a,projectRoot:d},r)}catch(e){return p.error(`Error resolving PRD path: ${e.message}`),{success:!1,error:{code:`FILE_NOT_FOUND`,message:e.message}}}else return p.error(`parsePRDDirect called without input path`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`Input path is required`}};let h;try{h=o?Y(d,o):Ot(`.taskgraph/tasks/tasks.json`,e)||F.resolve(d,`.taskgraph/tasks/tasks.json`)}catch(e){return p.error(`Error resolving output path: ${e.message}`),{success:!1,error:{code:`INVALID_PATH`,message:e.message}}}if(!R.existsSync(m)){let e=`Input PRD file not found at resolved path: ${m}`;return p.error(e),{success:!1,error:{code:`FILE_NOT_FOUND`,message:e}}}let g=F.dirname(h);try{R.existsSync(g)||(p.info(`Creating output directory: ${g}`),R.mkdirSync(g,{recursive:!0}))}catch(e){let t=`Failed to create output directory ${g}: ${e.message}`;return p.error(t),{success:!1,error:{code:`DIRECTORY_CREATE_FAILED`,message:t}}}let _=ve(d);s&&(_=typeof s==`string`?parseInt(s,10):s,(Number.isNaN(_)||_<0)&&(_=ve(d),p.warn(`Invalid numTasks value: ${s}. Using default: ${_}`))),l&&(p.info(`Append mode enabled.`),c&&p.warn(`Both --force and --append flags were provided. --force takes precedence; append mode will be ignored.`)),u&&p.info(`Research mode enabled. Using Claude Code web research for enhanced PRD analysis.`),p.info(`Parsing PRD via direct function. Input: ${m}, Output: ${h}, NumTasks: ${_}, Force: ${c}, Append: ${l}, Research: ${u}, ProjectRoot: ${d}`);let v=E();v||O();try{let e=await ce(m,h,_,{session:r,mcpLog:p,projectRoot:d,tag:f,force:c,append:l,research:u,reportProgress:i,commandName:`parse-prd`,outputType:`mcp`},`json`);if(e&&e.success){let t=`Successfully parsed PRD and generated tasks in ${e.tasksPath}`;return p.success(t),{success:!0,data:{message:t,outputPath:e.tasksPath,telemetryData:e.telemetryData,tagInfo:e.tagInfo}}}return p.error(`Core parsePRD function did not return a successful structure.`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e?.message||`Core function failed to parse PRD or returned unexpected result.`}}}catch(e){return p.error(`Error executing core parsePRD: ${e.message}`),{success:!1,error:{code:`PARSE_PRD_CORE_ERROR`,message:e.message||`Unknown error parsing PRD`}}}finally{!v&&E()&&C()}}async function Xt(e,t){let{tasksJsonPath:n,id:r,dependsOn:i,projectRoot:a,tag:o}=e;try{if(t.info(`Removing dependency with args: ${JSON.stringify(e)}`),!n)return t.error(`removeDependencyDirect 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(`Removing dependency: task ${c} no longer depends on ${l}`),O(),await ue(s,c,l,{projectRoot:a,tag:o}),C(),{success:!0,data:{message:`Successfully removed dependency: Task ${c} no longer depends on ${l}`,taskId:c,dependencyId:l}}}catch(e){return C(),t.error(`Error in removeDependencyDirect: ${e.message}`),{success:!1,error:{code:e instanceof b?e.code:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function Zt(e,t){let{tasksJsonPath:n,id:r,convert:i,skipGenerate:a,projectRoot:o,tag:s}=e;try{if(O(),t.info(`Removing subtask with args: ${JSON.stringify(e)}`),!n)return t.error(`removeSubtaskDirect called without tasksJsonPath`),C(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!r)return C(),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Subtask ID is required and must be in format "parentId.subtaskId"`}};if(!r.includes(`.`))return C(),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Invalid subtask ID format: ${r}. Expected format: "parentId.subtaskId"`}};let c=n,l=i===!0,u=!a;t.info(`Removing subtask ${r} (convertToTask: ${l}, generateFiles: ${u})`);let d=await re(c,r,l,u,{projectRoot:o,tag:s});return C(),l&&d?{success:!0,data:{message:`Subtask ${r} successfully converted to task #${d.id}`,task:d}}:{success:!0,data:{message:`Subtask ${r} successfully removed`}}}catch(e){return C(),t.error(`Error in removeSubtaskDirect: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function Qt(e,t,n={}){let{tasksJsonPath:r,id:i,projectRoot:a,tag:o}=e,{session:s}=n;try{if(!r)return t.error(`removeTaskDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i)return t.error(`Task ID is required`),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Task ID is required`}};let e=i.split(`,`).map(e=>e.trim());t.info(`Removing ${e.length} task(s) with ID(s): ${e.join(`, `)} from ${r}${o?` in tag '${o}'`:``}`);let n=k(r,a,o);if(!n||!n.tasks)return{success:!1,error:{code:`INVALID_TASKS_FILE`,message:`No valid tasks found in ${r}${o?` for tag '${o}'`:``}`}};let s=e.filter(e=>!_(n.tasks,e));if(s.length>0)return{success:!1,error:{code:`INVALID_TASK_ID`,message:`The following tasks were not found${o?` in tag '${o}'`:``}: ${s.join(`, `)}`}};O();try{let n=await oe(r,i,{projectRoot:a,tag:o});return n.success?(t.info(`Successfully removed ${n.removedTasks.length} task(s)`),{success:!0,data:{totalTasks:e.length,successful:n.removedTasks.length,failed:e.length-n.removedTasks.length,removedTasks:n.removedTasks,message:n.message,tasksPath:r,tag:o}}):{success:!1,error:{code:`REMOVE_TASK_ERROR`,message:n.error||`Failed to remove tasks`}}}finally{C()}}catch(e){return C(),t.error(`Unexpected error in removeTaskDirect: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}async function $t(e,t,n={}){let{tasksJsonPath:r,oldName:i,newName:a,projectRoot:o}=e,{session:s}=n;O();let c=Q(t);try{if(!r)return t.error(`renameTagDirect called without tasksJsonPath`),C(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: oldName`),C(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Old tag name is required and must be a string`}};if(!a||typeof a!=`string`)return t.error(`Missing required parameter: newName`),C(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`New tag name is required and must be a string`}};t.info(`Renaming tag from "${i}" to "${a}"`);let e=await je(r,i,a,{},{session:s,mcpLog:c,projectRoot:o},`json`);return C(),{success:!0,data:{oldName:e.oldName,newName:e.newName,renamed:e.renamed,taskCount:e.taskCount,wasCurrentTag:e.wasCurrentTag,message:`Successfully renamed tag from "${e.oldName}" to "${e.newName}"`}}}catch(e){return C(),t.error(`Error in renameTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`RENAME_TAG_ERROR`,message:e.message}}}}async function en(e,t,n={}){let{query:r,taskIds:i,filePaths:a,customContext:o,includeProjectTree:s=!1,detailLevel:c=`medium`,saveTo:l,saveToFile:u=!1,projectRoot:d,tag:f}=e,{session:p}=n;O();let m=Q(t);try{if(!r||typeof r!=`string`||r.trim().length===0)return t.error(`Missing or invalid required parameter: query`),C(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`The query parameter is required and must be a non-empty string`}};let e=i?i.split(`,`).map(e=>e.trim()).filter(e=>e.length>0):[],n=a?a.split(`,`).map(e=>e.trim()).filter(e=>e.length>0):[];if(d)try{n.forEach(e=>Y(d,e))}catch(e){return C(),{success:!1,error:{code:`INVALID_PATH`,message:e.message}}}let h=[`low`,`medium`,`high`];if(!h.includes(c))return t.error(`Invalid detail level: ${c}`),C(),{success:!1,error:{code:`INVALID_PARAMETER`,message:`Detail level must be one of: ${h.join(`, `)}`}};t.info(`Performing research query: "${r.substring(0,100)}${r.length>100?`...`:``}", taskIds: [${e.join(`, `)}], filePaths: [${n.join(`, `)}], detailLevel: ${c}, includeProjectTree: ${s}, projectRoot: ${d}`);let g={taskIds:e,filePaths:n,customContext:o||``,includeProjectTree:s,detailLevel:c,projectRoot:d,tag:f,saveToFile:u},_={session:p,mcpLog:m,commandName:`research`,outputType:`mcp`},v=await Me(r.trim(),g,_,`json`,!1);if(l)try{let{appendResearchToTask:e}=await import(`./research-BKsPc_oX.js`);e(F.join(d,`.taskgraph`,`tasks`,`tasks.json`),l,`## Research: ${r.trim()}\n\n${v.result}`,{projectRoot:d,tag:f}),t.info(`Research saved to ${l.includes(`.`)?`subtask`:`task`} ${l}`)}catch(e){t.warn(`Error saving research to task/subtask: ${e.message}`)}return C(),{success:!0,data:{query:v.query,result:v.result,contextSize:v.contextSize,contextTokens:v.contextTokens,tokenBreakdown:v.tokenBreakdown,systemPromptTokens:v.systemPromptTokens,userPromptTokens:v.userPromptTokens,totalInputTokens:v.totalInputTokens,detailLevel:v.detailLevel,telemetryData:v.telemetryData,tagInfo:v.tagInfo,savedFilePath:v.savedFilePath}}}catch(e){return C(),t.error(`Error in researchDirect: ${e.message}`),{success:!1,error:{code:e.code||`RESEARCH_ERROR`,message:e.message}}}}async function tn(e,t,n={}){let{tasksJsonPath:r,id:i,strength:a=`regular`,prompt:o,research:s=!1,projectRoot:c,tag:l}=e,{session:u}=n;O();let d=Q(t);try{if(!r)return t.error(`scopeDownDirect called without tasksJsonPath`),C(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i)return t.error(`Missing required parameter: id`),C(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`The id parameter is required for scoping down tasks`}};let e=i.split(`,`).map(e=>parseInt(e.trim(),10));t.info(`Scoping down tasks: ${e.join(`, `)}, strength: ${a}, research: ${s}`);let n=await ne(r,e,a,o,{session:u,mcpLog:d,projectRoot:c,commandName:`scope-down`,outputType:`mcp`,tag:l,research:s},`json`);return C(),{success:!0,data:{updatedTasks:n.updatedTasks,tasksUpdated:n.updatedTasks.length,message:`Successfully scoped down ${n.updatedTasks.length} task(s)`,telemetryData:n.telemetryData}}}catch(e){return C(),t.error(`Error in scopeDownDirect: ${e.message}`),{success:!1,error:{code:e.code||`SCOPE_DOWN_ERROR`,message:e.message}}}}async function nn(e,t,n={}){let{tasksJsonPath:r,id:i,strength:a=`regular`,prompt:o,research:s=!1,projectRoot:c,tag:l}=e,{session:u}=n;O();let d=Q(t);try{if(!r)return t.error(`scopeUpDirect called without tasksJsonPath`),C(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i)return t.error(`Missing required parameter: id`),C(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`The id parameter is required for scoping up tasks`}};let e=i.split(`,`).map(e=>parseInt(e.trim(),10));t.info(`Scoping up tasks: ${e.join(`, `)}, strength: ${a}, research: ${s}`);let n=await h(r,e,a,o,{session:u,mcpLog:d,projectRoot:c,commandName:`scope-up`,outputType:`mcp`,tag:l,research:s},`json`);return C(),{success:!0,data:{updatedTasks:n.updatedTasks,tasksUpdated:n.updatedTasks.length,message:`Successfully scoped up ${n.updatedTasks.length} task(s)`,telemetryData:n.telemetryData}}}catch(e){return C(),t.error(`Error in scopeUpDirect: ${e.message}`),{success:!1,error:{code:e.code||`SCOPE_UP_ERROR`,message:e.message}}}}async function rn(e,t,n={}){let{session:r}=n,{tasksJsonPath:i,id:a,prompt:o,research:s,metadata:c,projectRoot:l,tag:u}=e,d=Q(t);try{if(d.info(`Updating subtask by ID via direct function. ID: ${a}, ProjectRoot: ${l}`),!i){let e=`tasksJsonPath is required but was not provided.`;return d.error(e),{success:!1,error:{code:`MISSING_ARGUMENT`,message:e}}}if(!a||typeof a!=`string`||!a.trim()){let e=`Subtask ID cannot be empty.`;return d.error(e),{success:!1,error:{code:`INVALID_SUBTASK_ID`,message:e}}}if(!o&&!c){let e=`No prompt or metadata specified. Please provide information to append or metadata to update.`;return d.error(e),{success:!1,error:{code:`MISSING_PROMPT`,message:e}}}let e=String(a).trim(),n=i,f=s===!0;t.info(`Updating subtask with ID ${e} with prompt "${o||`(metadata-only)`}" and research: ${f}`);let p=E();p||O();try{let t=await ae(n,e,o,f,{mcpLog:d,session:r,projectRoot:l,tag:u,commandName:`update-subtask`,outputType:`mcp`,metadata:c},`json`);if(!t||t.updatedSubtask===null){let e=`Subtask ${a} or its parent task not found.`;return d.error(e),{success:!1,error:{code:`SUBTASK_NOT_FOUND`,message:e}}}let i=e.split(`.`)[0],s=`Successfully updated subtask with ID ${e}`;return d.success(s),{success:!0,data:{message:`Successfully updated subtask with ID ${e}`,subtaskId:e,parentId:i,subtask:t.updatedSubtask,tasksPath:n,useResearch:f,telemetryData:t.telemetryData,tagInfo:t.tagInfo}}}catch(e){return d.error(`Error updating subtask by ID: ${e.message}`),{success:!1,error:{code:`UPDATE_SUBTASK_CORE_ERROR`,message:e.message||`Unknown error updating subtask`}}}finally{!p&&E()&&C()}}catch(e){return d.error(`Setup error in updateSubtaskByIdDirect: ${e.message}`),E()&&C(),{success:!1,error:{code:`DIRECT_FUNCTION_SETUP_ERROR`,message:e.message||`Unknown setup error`}}}}async function an(e,t,n={}){let{session:r}=n,{tasksJsonPath:i,id:a,prompt:o,research:s,append:c,metadata:l,projectRoot:u,tag:d}=e,f=Q(t);try{if(f.info(`Updating task by ID via direct function. ID: ${a}, ProjectRoot: ${u}`),!a){let e=`No task ID specified. Please provide a task ID to update.`;return f.error(e),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:e}}}if(!o&&!l){let e=`No prompt or metadata specified. Please provide a prompt with new information or metadata for the task update.`;return f.error(e),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:e}}}let t;if(typeof a==`string`)t=a;else if(typeof a==`number`)t=String(a);else{let e=`Invalid task ID type: ${typeof a}. Task ID must be a string or number.`;return f.error(e),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:e}}}let n=i||Z({projectRoot:u,file:e.file},f);if(!n){let e=`tasks.json path could not be resolved.`;return f.error(e),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:e}}}let p=s===!0;f.info(`Updating task with ID ${t} with prompt "${o||`(metadata-only)`}" and research: ${p}`);let m=E();m||O();try{let e=await ie(n,t,o,p,{mcpLog:f,session:r,projectRoot:u,tag:d,commandName:`update-task`,outputType:`mcp`,metadata:l},`json`,c||!1);if(!e||e.updatedTask===null){let n=`Task ${t} was not updated (likely already completed).`;return f.info(n),{success:!0,data:{message:n,taskId:t,updated:!1,telemetryData:e?.telemetryData,tagInfo:e?.tagInfo}}}let i=`Successfully updated task with ID ${t} based on the prompt`;return f.info(i),{success:!0,data:{message:i,taskId:t,tasksPath:n,useResearch:p,updated:!0,updatedTask:e.updatedTask,telemetryData:e.telemetryData,tagInfo:e.tagInfo}}}catch(e){return f.error(`Error updating task by ID: ${e.message}`),{success:!1,error:{code:`UPDATE_TASK_CORE_ERROR`,message:e.message||`Unknown error updating task`}}}finally{!m&&E()&&C()}}catch(e){return f.error(`Setup error in updateTaskByIdDirect: ${e.message}`),E()&&C(),{success:!1,error:{code:`DIRECT_FUNCTION_SETUP_ERROR`,message:e.message||`Unknown setup error`}}}}async function on(e,t,n={}){let{session:r}=n,{from:i,prompt:a,research:o,tasksJsonPath:s,projectRoot:c,tag:l}=e,u=Q(t);if(!c)return u.error(`updateTasksDirect requires a projectRoot argument.`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`projectRoot is required.`}};if(!i)return u.error(`updateTasksDirect called without from ID`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`Starting task ID (from) is required`}};if(!a)return u.error(`updateTasksDirect called without prompt`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`Update prompt is required`}};u.info(`Updating tasks via direct function. From: ${i}, Research: ${o}, File: ${s}, ProjectRoot: ${c}`),O();try{let e=await se(s,i,a,o,{session:r,mcpLog:u,projectRoot:c,tag:l},`json`);return e&&e.success&&Array.isArray(e.updatedTasks)?(u.success(`Successfully updated ${e.updatedTasks.length} tasks.`),{success:!0,data:{message:`Successfully updated ${e.updatedTasks.length} tasks.`,tasksPath:s,updatedCount:e.updatedTasks.length,telemetryData:e.telemetryData,tagInfo:e.tagInfo}}):(u.error(`Core updateTasks function did not return a successful structure.`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e?.message||`Core function failed to update tasks or returned unexpected result.`}})}catch(e){return u.error(`Error executing core updateTasks: ${e.message}`),{success:!1,error:{code:`UPDATE_TASKS_CORE_ERROR`,message:e.message||`Unknown error updating tasks`}}}finally{C()}}async function sn(e,t,n={}){let{tasksJsonPath:r,name:i,projectRoot:a}=e,{session:o}=n;O();let s=Q(t);try{if(!r)return t.error(`useTagDirect called without tasksJsonPath`),C(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: name`),C(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Tag name is required and must be a string`}};t.info(`Switching to tag: ${i}`);let e=await Ee(r,i,{},{session:o,mcpLog:s,projectRoot:a},`json`);return C(),{success:!0,data:{tagName:e.currentTag,switched:e.switched,previousTag:e.previousTag,taskCount:e.taskCount,message:`Successfully switched to tag "${e.currentTag}"`}}}catch(e){return C(),t.error(`Error in useTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`USE_TAG_ERROR`,message:e.message}}}}async function cn(e,t){let{tasksJsonPath:n,projectRoot:r,tag:i}=e;if(!n)return t.error(`validateDependenciesDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};try{t.info(`Validating dependencies in tasks: ${n}`);let e=n;if(!R.existsSync(e))return{success:!1,error:{code:`FILE_NOT_FOUND`,message:`Tasks file not found at ${e}`}};O();let a=await p(e,{context:{projectRoot:r,tag:i}});return C(),{success:!0,data:{message:a.valid?`No dependency problems`:`Found ${a.issues.length} dependency problem(s)`,...a,tasksPath:e}}}catch(e){return C(),t.error(`Error validating dependencies: ${e.message}`),{success:!1,error:{code:e instanceof b?e.code:`VALIDATION_ERROR`,message:e.message}}}}function ln(e){e.addTool({name:`add_dependency`,description:`Add a dependency relationship between two tasks`,parameters:I.object({id:I.string().describe(`ID of task that will depend on another task`),dependsOn:I.string().describe(`ID of task that will become a dependency`),file:I.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Add Dependency`,destructiveHint:!0},execute:J(`add-dependency`,async(e,{log:t,session:n})=>{try{t.info(`Adding dependency for task ${e.id} to depend on ${e.dependsOn}`);let n=A({projectRoot:e.projectRoot,tag:e.tag}),r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let i=await Ct({tasksJsonPath:r,id:e.id,dependsOn:e.dependsOn,projectRoot:e.projectRoot,tag:n},t);return i.success?t.info(`Successfully added dependency: ${i.data.message}`):t.error(`Failed to add dependency: ${i.error.message}`),G({result:i,log:t,errorPrefix:`Error adding dependency`,projectRoot:e.projectRoot,tag:n})}catch(e){return t.error(`Error in addDependency tool: ${e.message}`),W(e.message)}})})}function un(e){e.addTool({name:`add_subtask`,description:`Add a subtask to an existing task`,parameters:I.object({id:I.string().describe(`Parent task ID (required)`),taskId:I.string().optional().describe(`Existing task ID to convert to subtask`),title:I.string().optional().describe(`Title for the new subtask (when creating a new subtask)`),description:I.string().optional().describe(`Description for the new subtask`),details:I.string().optional().describe(`Implementation details for the new subtask`),status:I.string().optional().describe(`Status for the new subtask (default: 'pending')`),dependencies:I.string().optional().describe(`Comma-separated list of dependency IDs for the new subtask`),file:I.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),skipGenerate:I.boolean().optional().describe(`Skip regenerating task files`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Add Subtask`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{let r=A({projectRoot:e.projectRoot,tag:e.tag});t.info(`Adding subtask with args: ${JSON.stringify(e)}`);let i;try{i=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let a=await wt({tasksJsonPath:i,id:e.id,taskId:e.taskId,title:e.title,description:e.description,details:e.details,status:e.status,dependencies:e.dependencies,skipGenerate:e.skipGenerate,projectRoot:e.projectRoot,tag:r},t,{session:n});return a.success?t.info(`Subtask added successfully: ${a.data.message}`):t.error(`Failed to add subtask: ${a.error.message}`),G({result:a,log:t,errorPrefix:`Error adding subtask`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in addSubtask tool: ${e.message}`),W(e.message)}})})}function dn(e){e.addTool({name:`add_tag`,description:`Create a new tag for organizing tasks in different contexts`,parameters:I.object({name:I.string().describe(`Name of the new tag to create`),copyFromCurrent:I.boolean().optional().describe(`Whether to copy tasks from the current tag (default: false)`),copyFromTag:I.string().optional().describe(`Specific tag to copy tasks from`),fromBranch:I.boolean().optional().describe(`Create tag name from current git branch (ignores name parameter)`),description:I.string().optional().describe(`Optional description for the tag`),file:I.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Add Tag`,destructiveHint:!1},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting add-tag with args: ${JSON.stringify(e)}`);let r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}return G({result:await jt({tasksJsonPath:r,name:e.name,copyFromCurrent:e.copyFromCurrent,copyFromTag:e.copyFromTag,fromBranch:e.fromBranch,description:e.description,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error creating tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in add-tag tool: ${e.message}`),W(e.message)}})})}function fn(e){e.addTool({name:`add_task`,description:`Add a new task using AI`,parameters:I.object({prompt:I.string().optional().describe(`Description of the task to add (required if not using manual fields)`),title:I.string().optional().describe(`Task title (for manual task creation)`),description:I.string().optional().describe(`Task description (for manual task creation)`),details:I.string().optional().describe(`Implementation details (for manual task creation)`),testStrategy:I.string().optional().describe(`Test strategy (for manual task creation)`),dependencies:I.string().optional().describe(`Comma-separated list of task IDs this task depends on`),priority:I.string().optional().describe(`Task priority (high, medium, low)`),file:I.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`),research:I.boolean().optional().describe(`Whether to use research capabilities for task creation`)}),annotations:{title:`Add Task`,destructiveHint:!1},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting add-task with args: ${JSON.stringify(e)}`);let r=A({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}return G({result:await Mt({tasksJsonPath:i,prompt:e.prompt,title:e.title,description:e.description,details:e.details,testStrategy:e.testStrategy,dependencies:e.dependencies,priority:e.priority,research:e.research,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error adding task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in add-task tool: ${e.message}`),W(e.message)}})})}function pn(e){e.addTool({name:`analyze_project_complexity`,description:`Analyze task complexity and generate expansion recommendations.`,parameters:I.object({threshold:I.coerce.number().int().min(1).max(10).optional().default(5).describe(`Complexity score threshold (1-10) to recommend expansion.`),research:I.boolean().optional().default(!1).describe(`Use Claude Code web research for research-backed analysis.`),output:I.string().optional().describe(`Output file path relative to project root (default: ${be}).`),file:I.string().optional().describe(`Path to the tasks file relative to project root (default: tasks/tasks.json).`),ids:I.string().optional().describe(`Comma-separated list of task IDs to analyze specifically (e.g., "1,3,5").`),from:I.coerce.number().int().positive().optional().describe(`Starting task ID in a range to analyze.`),to:I.coerce.number().int().positive().optional().describe(`Ending task ID in a range to analyze.`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Analyze Project Complexity`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{let r=`analyze_project_complexity`;try{t.info(`Executing ${r} tool with args: ${JSON.stringify(e)}`);let i=A({projectRoot:e.projectRoot,tag:e.tag}),a;try{a=Z({projectRoot:e.projectRoot,file:e.file},t),t.info(`${r}: Resolved tasks path: ${a}`)}catch(n){return t.error(`${r}: Error finding tasks.json: ${n.message}`),W(`Failed to find tasks.json within project root '${e.projectRoot}': ${n.message}`)}let o;try{o=e.output?Y(e.projectRoot,e.output):j(null,{projectRoot:e.projectRoot,tag:i},t)}catch(e){return W(e.message)}t.info(`${r}: Report output path: ${o}`);let s=F.dirname(o);try{R.existsSync(s)||(R.mkdirSync(s,{recursive:!0}),t.info(`${r}: Created output directory: ${s}`))}catch(e){return t.error(`${r}: Failed to create output directory ${s}: ${e.message}`),W(`Failed to create output directory: ${e.message}`)}let c=await Nt({tasksJsonPath:a,outputPath:o,threshold:e.threshold,research:e.research,projectRoot:e.projectRoot,tag:i,ids:e.ids,from:e.from,to:e.to},t,{session:n});return t.info(`${r}: Direct function result: success=${c.success}`),G({result:c,log:t,errorPrefix:`Error analyzing task complexity`,projectRoot:e.projectRoot})}catch(e){return t.error(`Critical error in ${r} tool execute: ${e.message}`),W(`Internal tool error (${r}): ${e.message}`)}})})}function mn(e){e.addTool({name:`clear_subtasks`,description:`Clear subtasks from specified tasks`,parameters:I.object({id:I.string().optional().describe(`Task IDs (comma-separated) to clear subtasks from`),all:I.boolean().optional().describe(`Clear subtasks from all tasks`),file:I.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}).refine(e=>e.id||e.all,{message:`Either 'id' or 'all' parameter must be provided`,path:[`id`,`all`]}),annotations:{title:`Clear Subtasks`,destructiveHint:!0},execute:J(`clear-subtasks`,async(e,t)=>{try{t.log.info(`Clearing subtasks with args: ${JSON.stringify(e)}`);let n=A({projectRoot:e.projectRoot,tag:e.tag}),r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t.log)}catch(e){return t.log.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let i=await Pt({tasksJsonPath:r,id:e.id,all:e.all,projectRoot:e.projectRoot,tag:n},t.log,{session:t.session});return i.success?t.log.info(`Subtasks cleared successfully: ${i.data.message}`):t.log.error(`Failed to clear subtasks: ${i.error.message}`),G({result:i,log:t.log,errorPrefix:`Error clearing subtasks`,projectRoot:e.projectRoot})}catch(e){return t.log.error(`Error in clearSubtasks tool: ${e.message}`),W(e.message)}})})}function hn(e){e.addTool({name:`complexity_report`,description:`Display the complexity analysis report in a readable format`,parameters:I.object({file:I.string().optional().describe(`Path to the report file (default: ${be})`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Complexity Report`,readOnlyHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Getting complexity report with args: ${JSON.stringify(e)}`);let n=pe(e.projectRoot),r=kt({projectRoot:e.projectRoot,complexityReport:e.file,tag:n},t);if(t.info(`Reading complexity report from path: `,r),!r)return W(`No complexity report found. Run taskgraph analyze-complexity first.`);let i=await Ft({reportPath:r},t);return i.success?t.info(`Successfully retrieved complexity report`):t.error(`Failed to retrieve complexity report: ${i.error.message}`),G({result:i,log:t,errorPrefix:`Error retrieving complexity report`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in complexity-report tool: ${e.message}`),W(`Failed to retrieve complexity report: ${e.message}`)}})})}function gn(e){e.addTool({name:`copy_tag`,description:`Copy an existing tag to create a new tag with all tasks and metadata`,parameters:I.object({sourceName:I.string().describe(`Name of the source tag to copy from`),targetName:I.string().describe(`Name of the new tag to create`),description:I.string().optional().describe(`Optional description for the new tag`),file:I.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Copy Tag`,destructiveHint:!1},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting copy-tag with args: ${JSON.stringify(e)}`);let r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}return G({result:await It({tasksJsonPath:r,sourceName:e.sourceName,targetName:e.targetName,description:e.description,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error copying tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in copy-tag tool: ${e.message}`),W(e.message)}})})}function _n(e){e.addTool({name:`delete_tag`,description:`Delete an existing tag and all its tasks`,parameters:I.object({name:I.string().describe(`Name of the tag to delete`),yes:I.boolean().optional().describe(`Skip confirmation prompts (default: true for MCP)`),file:I.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Delete Tag`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting delete-tag with args: ${JSON.stringify(e)}`);let r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}return G({result:await Lt({tasksJsonPath:r,name:e.name,yes:e.yes===void 0||e.yes,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error deleting tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in delete-tag tool: ${e.message}`),W(e.message)}})})}function vn(e){e.addTool({name:`expand_all`,description:`Expand all pending tasks into subtasks based on complexity or defaults`,parameters:I.object({num:I.string().optional().describe(`Target number of subtasks per task (uses complexity/defaults otherwise)`),research:I.boolean().optional().describe(`Enable research-backed subtask generation (web research via Claude Code)`),prompt:I.string().optional().describe(`Additional context to guide subtask generation for all tasks`),force:I.boolean().optional().describe(`Force regeneration of subtasks for tasks that already have them`),file:I.string().optional().describe(`Absolute path to the tasks file in the /tasks folder inside the project root (default: tasks/tasks.json)`),projectRoot:I.string().optional().describe(`Absolute path to the project root directory (derived from session if possible)`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Expand All Tasks`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Tool expand_all execution started with args: ${JSON.stringify(e)}`);let r=A({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=Z({projectRoot:e.projectRoot,file:e.file},t),t.info(`Resolved tasks.json path: ${i}`)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let a=At(null,{projectRoot:e.projectRoot,tag:r},t);return t.info(`Using complexity report path: ${a}`),G({result:await Rt({tasksJsonPath:i,num:e.num,research:e.research,prompt:e.prompt,force:e.force,projectRoot:e.projectRoot,tag:r,complexityReportPath:a},t,{session:n}),log:t,errorPrefix:`Error expanding all tasks`,projectRoot:e.projectRoot})}catch(e){return t.error(`Unexpected error in expand_all tool execute: ${e.message}`),e.stack&&t.error(e.stack),W(`An unexpected error occurred: ${e.message}`)}})})}function yn(e){e.addTool({name:`expand_task`,description:`Expand a task into subtasks for detailed implementation`,parameters:I.object({id:I.string().describe(`ID of task to expand`),num:I.string().optional().describe(`Number of subtasks to generate`),research:I.boolean().optional().default(!1).describe(`Use research role for generation`),prompt:I.string().optional().describe(`Additional context for subtask generation`),file:I.string().optional().describe(`Path to the tasks file relative to project root (e.g., tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),force:I.boolean().optional().default(!1).describe(`Force expansion even if subtasks exist`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Expand Task`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting expand-task with args: ${JSON.stringify(e)}`);let r=A({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let a=kt({...e,tag:r},t);return G({result:await zt({tasksJsonPath:i,id:e.id,num:e.num,research:e.research,prompt:e.prompt,force:e.force,complexityReportPath:a,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error expanding task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in expand-task tool: ${e.message}`),W(e.message)}})})}function bn(e){e.addTool({name:`fix_dependencies`,description:`Fix invalid dependencies in tasks automatically`,parameters:I.object({file:I.string().optional().describe(`Absolute path to the tasks file`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Fix Dependencies`,destructiveHint:!0},execute:J(`fix-dependencies`,async(e,t)=>{try{t.log.info(`Fixing dependencies with args: ${JSON.stringify(e)}`);let n=A({projectRoot:e.projectRoot,tag:e.tag}),r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t.log)}catch(e){return t.log.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let i=await Bt({tasksJsonPath:r,projectRoot:e.projectRoot,tag:n},t.log);return i.success?t.log.info(`Successfully fixed dependencies: ${i.data.message}`):t.log.error(`Failed to fix dependencies: ${i.error.message}`),G({result:i,log:t.log,errorPrefix:`Error fixing dependencies`,projectRoot:e.projectRoot})}catch(e){return t.log.error(`Error in fixDependencies tool: ${e.message}`),W(e.message)}})})}function xn(e){e.addTool({name:`initialize_project`,description:`Initializes a new TaskGraph project structure by calling the core initialization logic. Creates necessary folders and configuration files for TaskGraph in the current directory.`,parameters:I.object({skipInstall:I.boolean().optional().default(!1).describe(`Skip installing dependencies automatically. Never do this unless you are sure the project is already installed.`),addAliases:I.boolean().optional().default(!0).describe(`Add shell aliases (tm, taskgraph) to shell config file.`),initGit:I.boolean().optional().default(!0).describe(`Initialize Git repository in project root.`),storeTasksInGit:I.boolean().optional().default(!0).describe(`Store tasks in Git (tasks.json and tasks/ directory).`),yes:I.boolean().optional().default(!0).describe(`Skip prompts and use default values. Always set to true for MCP tools.`),projectRoot:I.string().describe(`The root directory for the project. ALWAYS SET THIS TO THE PROJECT ROOT DIRECTORY. IF NOT SET, THE TOOL WILL NOT WORK.`),rules:I.array(I.enum(Fe)).optional().describe(`List of rule profiles to include at initialization. If omitted, defaults to the Claude profile. Available options: ${Fe.join(`, `)}`)}),annotations:{title:`Initialize Project`,destructiveHint:!0},execute:q(async(e,t)=>{let{log:n}=t,r=t.session;try{return n.info(`Executing initialize_project tool with args: ${JSON.stringify(e)}`),G({result:await Vt(e,n,{session:r}),log:n,errorPrefix:`Initialization failed`,projectRoot:e.projectRoot})}catch(e){let t=`Project initialization tool failed: ${e.message||`Unknown error`}`;return n.error(t,e),W(t,{details:e.stack})}})})}function Sn(e){e.addTool({name:`list_tags`,description:`List all available tags with task counts and metadata`,parameters:I.object({showMetadata:I.boolean().optional().describe(`Whether to include metadata in the output (default: false)`),file:I.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`List Tags`,readOnlyHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting list-tags with args: ${JSON.stringify(e)}`);let r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}return G({result:await Ht({tasksJsonPath:r,showMetadata:e.showMetadata,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error listing tags`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in list-tags tool: ${e.message}`),W(e.message)}})})}function Cn(e){e.addTool({name:`models`,description:`Get information about available AI models or set model configurations. TaskGraph uses Claude Code (models: opus, sonnet, haiku). Run without arguments to get the current model configuration.`,parameters:I.object({setMain:I.string().optional().describe(`Set the primary model for task generation/updates. One of: opus, sonnet, haiku.`),setResearch:I.string().optional().describe(`Set the model for research-backed operations. One of: opus, sonnet, haiku.`),setFallback:I.string().optional().describe(`Set the model to use if the primary fails. One of: opus, sonnet, haiku.`),listAvailableModels:I.boolean().optional().describe(`List all available models.`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Models`,destructiveHint:!0},execute:J(`models`,async(e,t)=>{try{return t.log.info(`Starting models tool with args: ${JSON.stringify(e)}`),G({result:await Gt({...e,projectRoot:e.projectRoot},t.log,{session:t.session}),log:t.log,errorPrefix:`Error managing models`,projectRoot:e.projectRoot})}catch(e){return t.log.error(`Error in models tool: ${e.message}`),W(e.message)}})})}function wn(e){e.addTool({name:`move_task`,description:`Move a task or subtask to a new position`,parameters:I.object({from:I.string().describe(`ID of the task/subtask to move (e.g., "5" or "5.2"). Can be comma-separated to move multiple tasks (e.g., "5,6,7")`),to:I.string().optional().describe(`ID of the destination (e.g., "7" or "7.3"). Required for within-tag moves. For cross-tag moves, if omitted, task will be moved to the target tag maintaining its ID`),file:I.string().optional().describe(`Custom path to tasks.json file`),projectRoot:I.string().describe(`Root directory of the project (typically derived from session)`),tag:I.string().optional().describe(`Tag context to operate on`),fromTag:I.string().optional().describe(`Source tag for cross-tag moves`),toTag:I.string().optional().describe(`Target tag for cross-tag moves`),withDependencies:I.boolean().optional().describe(`Move dependent tasks along with main task`),ignoreDependencies:I.boolean().optional().describe(`Break cross-tag dependencies during move`)}),annotations:{title:`Move Task`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{if(e.fromTag&&e.toTag&&e.fromTag!==e.toTag){if(!e.from)return W(`Source IDs are required for cross-tag moves`,`MISSING_SOURCE_IDS`);e.to&&t.warn(`The "to" parameter is not used for cross-tag moves and will be ignored. Tasks retain their original IDs in the target tag.`);let r=e.file;return r||=Z(e,t),G({result:await Kt({sourceIds:e.from,sourceTag:e.fromTag,targetTag:e.toTag,withDependencies:e.withDependencies||!1,ignoreDependencies:e.ignoreDependencies||!1,tasksJsonPath:r,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error moving tasks between tags`,projectRoot:e.projectRoot})}{if(!e.to)return W(`Destination ID is required for within-tag moves`,`MISSING_DESTINATION_ID`);let r=A({projectRoot:e.projectRoot,tag:e.tag}),i=e.file;i||=Z(e,t);let a=e.from.split(`,`).map(e=>e.trim()),o=e.to.split(`,`).map(e=>e.trim());if(a.length!==o.length){if(a.length>1){let s=[],c=[];for(let l=0;l<a.length;l++){let u=a[l],d=o[l];if(u===d){t.info(`Skipping ${u} -> ${d} (same ID)`),c.push({fromId:u,toId:d,reason:`same ID`});continue}let f=l===a.length-1,p=await qt({sourceId:u,destinationId:d,tasksJsonPath:i,projectRoot:e.projectRoot,tag:r,generateFiles:f},t,{session:n});p.success?s.push(p.data):t.error(`Failed to move ${u} to ${d}: ${p.error.message}`)}return G({result:{success:!0,data:{moves:s,skipped:c.length>0?c:void 0,message:`Successfully moved ${s.length} tasks${c.length>0?`, skipped ${c.length}`:``}`}},log:t,errorPrefix:`Error moving multiple tasks`,projectRoot:e.projectRoot})}return G({result:{success:!0,data:{moves:results,skippedMoves,message:`Successfully moved ${results.length} tasks${skippedMoves.length>0?`, skipped ${skippedMoves.length} moves`:``}`}},log:t,errorPrefix:`Error moving multiple tasks`,projectRoot:e.projectRoot})}return G({result:await qt({sourceId:e.from,destinationId:e.to,tasksJsonPath:i,projectRoot:e.projectRoot,tag:r,generateFiles:!0},t,{session:n}),log:t,errorPrefix:`Error moving task`,projectRoot:e.projectRoot})}}catch(e){return W(`Failed to move task: ${e.message}`,`MOVE_TASK_ERROR`)}})})}function Tn(e){e.addTool({name:`next_task`,description:`Find the next task to work on based on dependencies and status`,parameters:I.object({file:I.string().optional().describe(`Absolute path to the tasks file`),complexityReport:I.string().optional().describe(`Path to the complexity report file (relative to project root or absolute)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Next Task`,readOnlyHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Finding next task with args: ${JSON.stringify(e)}`);let r=A({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=Tt(e,n)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let a;try{a=Dt({...e,tag:r},n)}catch(e){t.error(`Error finding complexity report: ${e.message}`),a=null}let o=await Jt({tasksJsonPath:i,reportPath:a,projectRoot:e.projectRoot,tag:r},t,{session:n});return t.info(`Next task result: ${o.success?`found`:`none`}`),G({result:o,log:t,errorPrefix:`Error finding next task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error finding next task: ${e.message}`),W(e.message)}})})}function En(e){e.addTool({name:`parse_prd`,description:`Parse a Product Requirements Document (PRD) text file to automatically generate initial tasks. Reinitializing the project is not necessary to run this tool. It is recommended to run parse-prd after initializing the project and creating/importing a prd.txt file in the project root's ${fe} directory.`,parameters:I.object({input:I.string().optional().default(de).describe(`Absolute path to the PRD document file (.txt, .md, etc.)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`),output:I.string().optional().describe(`Output path for tasks.json file (default: ${ge})`),numTasks:I.string().optional().describe(`Approximate number of top-level tasks to generate (default: 10). As the agent, if you have enough information, ensure to enter a number of tasks that would logically scale with project complexity. Setting to 0 will allow TaskGraph to determine the appropriate number of tasks based on the complexity of the PRD. Avoid entering numbers above 50 due to context window limitations.`),force:I.boolean().optional().default(!1).describe(`Overwrite existing output file without prompting.`),research:I.boolean().optional().describe(`Enable TaskGraph to use the research role for potentially more informed task generation. Requires appropriate API key.`),append:I.boolean().optional().describe(`Append generated tasks to existing file.`)}),annotations:{title:`Parse PRD`,destructiveHint:!0},execute:q(async(e,{log:t,session:n,reportProgress:r})=>{try{let i=A({projectRoot:e.projectRoot,tag:e.tag}),a=He(r,t);return G({result:await Yt({...e,tag:i},t,{session:n,reportProgress:a}),log:t,errorPrefix:`Error parsing PRD`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in parse_prd: ${e.message}`),W(`Failed to parse PRD: ${e.message}`)}})})}function Dn(e){e.addTool({name:`remove_dependency`,description:`Remove a dependency from a task`,parameters:I.object({id:I.string().describe(`Task ID to remove dependency from`),dependsOn:I.string().describe(`Task ID to remove as a dependency`),file:I.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Remove Dependency`,destructiveHint:!0},execute:J(`remove-dependency`,async(e,t)=>{try{let n=A({projectRoot:e.projectRoot,tag:e.tag});t.log.info(`Removing dependency for task ${e.id} from ${e.dependsOn} with args: ${JSON.stringify(e)}`);let r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t.log)}catch(e){return t.log.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let i=await Xt({tasksJsonPath:r,id:e.id,dependsOn:e.dependsOn,projectRoot:e.projectRoot,tag:n},t.log);return i.success?t.log.info(`Successfully removed dependency: ${i.data.message}`):t.log.error(`Failed to remove dependency: ${i.error.message}`),G({result:i,log:t.log,errorPrefix:`Error removing dependency`,projectRoot:e.projectRoot})}catch(e){return t.log.error(`Error in removeDependency tool: ${e.message}`),W(e.message)}})})}function On(e){e.addTool({name:`remove_subtask`,description:`Remove a subtask from its parent task`,parameters:I.object({id:I.string().describe(`Subtask ID to remove in format 'parentId.subtaskId' (required)`),convert:I.boolean().optional().describe(`Convert the subtask to a standalone task instead of deleting it`),file:I.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),skipGenerate:I.boolean().optional().describe(`Skip regenerating task files`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Remove Subtask`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{let r=A({projectRoot:e.projectRoot,tag:e.tag});t.info(`Removing subtask with args: ${JSON.stringify(e)}`);let i;try{i=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let a=await Zt({tasksJsonPath:i,id:e.id,convert:e.convert,skipGenerate:e.skipGenerate,projectRoot:e.projectRoot,tag:r},t,{session:n});return a.success?t.info(`Subtask removed successfully: ${a.data.message}`):t.error(`Failed to remove subtask: ${a.error.message}`),G({result:a,log:t,errorPrefix:`Error removing subtask`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in removeSubtask tool: ${e.message}`),W(e.message)}})})}function kn(e){e.addTool({name:`remove_task`,description:`Remove a task or subtask permanently from the tasks list`,parameters:I.object({id:I.string().describe(`ID of the task or subtask to remove (e.g., '5' or '5.2'). Can be comma-separated to update multiple tasks/subtasks at once.`),file:I.string().optional().describe(`Absolute path to the tasks file`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),confirm:I.boolean().optional().describe(`Whether to skip confirmation prompt (default: false)`),tag:I.string().optional().describe(`Specify which tag context to operate on. Defaults to the current active tag.`)}),annotations:{title:`Remove Task`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Removing task(s) with ID(s): ${e.id}`);let r=A({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}t.info(`Using tasks file path: ${i}`);let a=await Qt({tasksJsonPath:i,id:e.id,projectRoot:e.projectRoot,tag:r},t,{session:n});return a.success?t.info(`Successfully removed task: ${e.id}`):t.error(`Failed to remove task: ${a.error.message}`),G({result:a,log:t,errorPrefix:`Error removing task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in remove-task tool: ${e.message}`),W(`Failed to remove task: ${e.message}`)}})})}function An(e){e.addTool({name:`rename_tag`,description:`Rename an existing tag`,parameters:I.object({oldName:I.string().describe(`Current name of the tag to rename`),newName:I.string().describe(`New name for the tag`),file:I.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Rename Tag`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting rename-tag with args: ${JSON.stringify(e)}`);let r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}return G({result:await $t({tasksJsonPath:r,oldName:e.oldName,newName:e.newName,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error renaming tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in rename-tag tool: ${e.message}`),W(e.message)}})})}function jn(e){e.addTool({name:`research`,description:`Perform AI-powered research queries with project context`,parameters:I.object({query:I.string().describe(`Research query/prompt (required)`),taskIds:I.string().optional().describe(`Comma-separated list of task/subtask IDs for context (e.g., "15,16.2,17")`),filePaths:I.string().optional().describe(`Comma-separated list of file paths for context (e.g., "src/api.js,docs/readme.md")`),customContext:I.string().optional().describe(`Additional custom context text to include in the research`),includeProjectTree:I.boolean().optional().describe(`Include project file tree structure in context (default: false)`),detailLevel:I.enum([`low`,`medium`,`high`]).optional().describe(`Detail level for the research response (default: medium)`),saveTo:I.string().optional().describe(`Automatically save research results to specified task/subtask ID (e.g., "15" or "15.2")`),saveToFile:I.boolean().optional().describe(`Save research results to .taskgraph/docs/research/ directory (default: false)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Research`,destructiveHint:!0,openWorldHint:!0},execute:q(async(e,{log:t,session:n})=>{try{let r=A({projectRoot:e.projectRoot,tag:e.tag});return t.info(`Starting research with query: "${e.query.substring(0,100)}${e.query.length>100?`...`:``}"`),G({result:await en({query:e.query,taskIds:e.taskIds,filePaths:e.filePaths,customContext:e.customContext,includeProjectTree:e.includeProjectTree||!1,detailLevel:e.detailLevel||`medium`,saveTo:e.saveTo,saveToFile:e.saveToFile||!1,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error performing research`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in research tool: ${e.message}`),W(e.message)}})})}async function Mn(e,t,n={}){let{projectRoot:r,language:i}=e,a=Q(t);t.info(`Executing response-language_direct with args: ${JSON.stringify(e)}`),t.info(`Using project root: ${r}`);try{return O(),Pe(i,{mcpLog:a,projectRoot:r})}catch(e){return{success:!1,error:{code:`DIRECT_FUNCTION_ERROR`,message:e.message,details:e.stack}}}finally{C()}}function Nn(e){e.addTool({name:`response-language`,description:`Get or set the response language for the project`,parameters:I.object({projectRoot:I.string().describe(`The root directory for the project. ALWAYS SET THIS TO THE PROJECT ROOT DIRECTORY. IF NOT SET, THE TOOL WILL NOT WORK.`),language:I.string().describe(`The new response language to set. like "中文" "English" or "español".`)}),annotations:{title:`Response Language`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{return t.info(`Executing response-language tool with args: ${JSON.stringify(e)}`),G({result:await Mn({...e,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error setting response language`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in response-language tool: ${e.message}`),W(e.message)}})})}function Pn(e){e.addTool({name:`scope_down_task`,description:`Decrease the complexity of one or more tasks using AI`,parameters:I.object({id:I.string().describe(`Comma-separated list of task IDs to scope down (e.g., "1,3,5")`),strength:I.string().optional().describe(`Strength level: light, regular, or heavy (default: regular)`),prompt:I.string().optional().describe(`Custom prompt for specific scoping adjustments`),file:I.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`),research:I.boolean().optional().describe(`Whether to use research capabilities for scoping`)}),annotations:{title:`Scope Down Task`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting scope-down with args: ${JSON.stringify(e)}`);let r=A({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}return G({result:await tn({tasksJsonPath:i,id:e.id,strength:e.strength,prompt:e.prompt,research:e.research,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error scoping down task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in scope-down tool: ${e.message}`),W(e.message)}})})}function Fn(e){e.addTool({name:`scope_up_task`,description:`Increase the complexity of one or more tasks using AI`,parameters:I.object({id:I.string().describe(`Comma-separated list of task IDs to scope up (e.g., "1,3,5")`),strength:I.string().optional().describe(`Strength level: light, regular, or heavy (default: regular)`),prompt:I.string().optional().describe(`Custom prompt for specific scoping adjustments`),file:I.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`),research:I.boolean().optional().describe(`Whether to use research capabilities for scoping`)}),annotations:{title:`Scope Up Task`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting scope-up with args: ${JSON.stringify(e)}`);let r=A({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}return G({result:await nn({tasksJsonPath:i,id:e.id,strength:e.strength,prompt:e.prompt,research:e.research,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error scoping up task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in scope-up tool: ${e.message}`),W(e.message)}})})}function In(e){e.addTool({name:`update`,description:`Update multiple upcoming tasks (with ID >= 'from' ID) based on new context or changes provided in the prompt. Use 'update_task' instead for a single specific task or 'update_subtask' for subtasks.`,parameters:I.object({from:I.string().describe(`Task ID from which to start updating (inclusive). IMPORTANT: This tool uses 'from', not 'id'`),prompt:I.string().describe(`Explanation of changes or new context to apply`),research:I.boolean().optional().describe(`Use Claude Code web research for research-backed updates`),file:I.string().optional().describe(`Path to the tasks file relative to project root`),projectRoot:I.string().optional().describe(`The directory of the project. (Optional, usually from session)`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Update Tasks`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{let r=`update`,{from:i,prompt:a,research:o,file:s,projectRoot:c,tag:l}=e,u=A({projectRoot:e.projectRoot,tag:e.tag});try{t.info(`Executing ${r} tool with normalized root: ${c}`);let l;try{l=Z({projectRoot:c,file:s},t),t.info(`${r}: Resolved tasks path: ${l}`)}catch(e){return t.error(`${r}: Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json within project root '${c}': ${e.message}`)}let d=await on({tasksJsonPath:l,from:i,prompt:a,research:o,projectRoot:c,tag:u},t,{session:n});return t.info(`${r}: Direct function result: success=${d.success}`),G({result:d,log:t,errorPrefix:`Error updating tasks`,projectRoot:e.projectRoot})}catch(e){return t.error(`Critical error in ${r} tool execute: ${e.message}`),W(`Internal tool error (${r}): ${e.message}`)}})})}function Ln(e){e.addTool({name:`update_subtask`,description:`Appends timestamped information to a specific subtask without replacing existing content. If you just want to update the subtask status, use set_task_status instead.`,parameters:I.object({id:s.describe(`ID of the subtask to update in format "parentId.subtaskId" (e.g., "5.2"). Parent ID is the ID of the task that contains the subtask.`),prompt:I.string().optional().describe(`Information to add to the subtask. Required unless only updating metadata.`),research:I.boolean().optional().describe(`Use Claude Code web research for research-backed updates`),metadata:I.string().optional().describe(`JSON string of metadata to merge into subtask metadata. Example: '{"ticketId": "JIRA-456", "reviewed": true}'. Requires TASKGRAPH_ALLOW_METADATA_UPDATES=true in MCP environment.`),file:I.string().optional().describe(`Absolute path to the tasks file`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Update Subtask`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{let r=`update_subtask`;try{let i=A({projectRoot:e.projectRoot,tag:e.tag});t.info(`Updating subtask with args: ${JSON.stringify(e)}`);let a;try{a=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`${r}: Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let o=Ke(e.metadata,W);if(o.error)return o.error;let s=o.parsedMetadata;if(!e.prompt&&!s)return W(`Either prompt or metadata must be provided for update-subtask`);let c=await rn({tasksJsonPath:a,id:e.id,prompt:e.prompt,research:e.research,metadata:s,projectRoot:e.projectRoot,tag:i},t,{session:n});return c.success?t.info(`Successfully updated subtask with ID ${e.id}`):t.error(`Failed to update subtask: ${c.error?.message||`Unknown error`}`),G({result:c,log:t,errorPrefix:`Error updating subtask`,projectRoot:e.projectRoot})}catch(e){return t.error(`Critical error in ${r} tool execute: ${e.message}`),W(`Internal tool error (${r}): ${e.message}`)}})})}function Rn(e){e.addTool({name:`update_task`,description:`Updates a single task by ID with new information or context provided in the prompt.`,parameters:I.object({id:I.string().describe(`ID of the task (e.g., '15') to update. Subtasks are supported using the update-subtask tool.`),prompt:I.string().optional().describe(`New information or context to incorporate into the task. Required unless only updating metadata.`),research:I.boolean().optional().describe(`Use Claude Code web research for research-backed updates`),append:I.boolean().optional().describe(`Append timestamped information to task details instead of full update`),metadata:I.string().optional().describe(`JSON string of metadata to merge into task metadata. Example: '{"githubIssue": 42, "sprint": "Q1-S3"}'. Requires TASKGRAPH_ALLOW_METADATA_UPDATES=true in MCP environment.`),file:I.string().optional().describe(`Absolute path to the tasks file`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Update Task`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{let r=`update_task`;try{let i=A({projectRoot:e.projectRoot,tag:e.tag});t.info(`Executing ${r} tool with args: ${JSON.stringify(e)}`);let a;try{a=Z({projectRoot:e.projectRoot,file:e.file},t),t.info(`${r}: Resolved tasks path: ${a}`)}catch(e){return t.error(`${r}: Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let o=Ke(e.metadata,W);if(o.error)return o.error;let s=o.parsedMetadata;if(!e.prompt&&!s)return W(`Either prompt or metadata must be provided for update-task`);let c=await an({tasksJsonPath:a,id:e.id,prompt:e.prompt,research:e.research,append:e.append,metadata:s,projectRoot:e.projectRoot,tag:i},t,{session:n});return t.info(`${r}: Direct function result: success=${c.success}`),G({result:c,log:t,errorPrefix:`Error updating task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Critical error in ${r} tool execute: ${e.message}`),W(`Internal tool error (${r}): ${e.message}`)}})})}function zn(e){e.addTool({name:`use_tag`,description:`Switch to a different tag context for task operations`,parameters:I.object({name:I.string().describe(`Name of the tag to switch to`),file:I.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Use Tag`,destructiveHint:!0},execute:q(async(e,{log:t,session:n})=>{try{t.info(`Starting use-tag with args: ${JSON.stringify(e)}`);let r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}return G({result:await sn({tasksJsonPath:r,name:e.name,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error switching tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in use-tag tool: ${e.message}`),W(e.message)}})})}function Bn(e){e.addTool({name:`validate_dependencies`,description:`Check tasks for dependency issues (like circular references or links to non-existent tasks) without making changes.`,parameters:I.object({file:I.string().optional().describe(`Absolute path to the tasks file`),projectRoot:I.string().describe(`The directory of the project. Must be an absolute path.`),tag:I.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Validate Dependencies`,readOnlyHint:!0},execute:J(`validate-dependencies`,async(e,{log:t,session:n})=>{try{let n=A({projectRoot:e.projectRoot,tag:e.tag});t.info(`Validating dependencies with args: ${JSON.stringify(e)}`);let r;try{r=Z({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),W(`Failed to find tasks.json: ${e.message}`)}let i=await cn({tasksJsonPath:r,projectRoot:e.projectRoot,tag:n},t);return i.success?t.info(`Successfully validated dependencies: ${i.data.message}`):t.error(`Failed to validate dependencies: ${i.error.message}`),G({result:i,log:t,errorPrefix:`Error validating dependencies`,projectRoot:e.projectRoot,tag:n})}catch(e){return t.error(`Error in validateDependencies tool: ${e.message}`),W(e.message)}})})}const $={initialize_project:xn,models:Cn,parse_prd:En,"response-language":Nn,analyze_project_complexity:pn,expand_task:yn,expand_all:vn,scope_up_task:Fn,scope_down_task:Pn,get_tasks:gt,get_task:vt,next_task:Tn,complexity_report:hn,dependency_analysis:mt,set_task_status:St,add_task:fn,add_subtask:un,update:In,update_task:Rn,update_subtask:Ln,remove_task:kn,remove_subtask:On,clear_subtasks:mn,move_task:wn,add_dependency:ln,remove_dependency:Dn,validate_dependencies:Bn,fix_dependencies:bn,list_tags:Sn,add_tag:dn,delete_tag:_n,use_tag:zn,rename_tag:An,copy_tag:gn,research:jn,autopilot_start:Je,autopilot_resume:Xe,autopilot_next:Qe,autopilot_status:et,autopilot_complete:nt,autopilot_commit:it,autopilot_finalize:ot,autopilot_abort:ct,generate:bt,github_status:ut,github_push:ft},Vn=[`get_tasks`,`next_task`,`get_task`,`set_task_status`,`update_subtask`,`parse_prd`,`expand_task`],Hn=[...Vn,`initialize_project`,`analyze_project_complexity`,`expand_all`,`add_subtask`,`remove_task`,`add_task`,`complexity_report`,`dependency_analysis`];function Un(e){return $[e]||null}function Wn(){let e=process.env.TASKGRAPH_TOOLS;if(!e||e.trim()===``)return H.debug(`No TASKGRAPH_TOOLS env var found, defaulting to "core"`),`core`;let t=e.trim();return H.debug(`TASKGRAPH_TOOLS env var: "${t}"`),t}function Gn(e,t=`core`){let n=Ve(e),r=[],i=[];try{let e=t.trim(),a=[],o=e.toLowerCase();switch(o){case`all`:a=Object.keys($),H.info(`Loading all available tools`);break;case`core`:case`lean`:a=Vn,H.info(`Loading core tools only`);break;case`standard`:a=Hn,H.info(`Loading standard tools`);break;default:let t=e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0),n=/* @__PURE__ */ new Set,r=[],i={response_language:`response-language`};for(let e of t){let t=null,a=e.toLowerCase();if(i[a]){let e=i[a];for(let n of Object.keys($))if(n.toLowerCase()===e.toLowerCase()){t=n;break}}if(!t){for(let e of Object.keys($))if(e.toLowerCase()===a){t=e;break}}if(!t){let e=a.replace(/_/g,`-`);for(let n of Object.keys($))if(n.toLowerCase()===e){t=n;break}}if(!t){let e=a.replace(/-/g,`_`);for(let n of Object.keys($))if(n.toLowerCase()===e){t=n;break}}t?(n.add(t),H.debug(`Resolved tool "${e}" to "${t}"`)):(r.push(e),H.warn(`Unknown tool specified: "${e}"`))}a=Array.from(n),r.length>0&&H.warn(`Unknown tools: ${r.join(`, `)}`),a.length===0?(H.warn(`No valid tools found in custom list. Loading all tools as fallback.`),a=Object.keys($)):H.info(`Loading ${a.length} custom tools from list (${n.size} unique after normalization)`)}return H.info(`Registering ${a.length} MCP tools (mode: ${e})`),a.forEach(e=>{try{let t=Un(e);t?(t(n),H.debug(`Registered tool: ${e}`),r.push(e)):(H.warn(`Tool ${e} not found in registry`),i.push(e))}catch(t){t.message&&t.message.includes(`already registered`)?(H.debug(`Tool ${e} already registered, skipping`),r.push(e)):(H.error(`Failed to register tool ${e}: ${t.message}`),i.push(e))}}),H.info(`Successfully registered ${r.length}/${a.length} tools`),i.length>0&&H.warn(`Failed tools: ${i.join(`, `)}`),{registeredTools:r,failedTools:i,normalizedMode:o}}catch(e){H.error(`Error parsing TASKGRAPH_TOOLS environment variable: ${e.message}`),H.info(`Falling back to loading all tools`);let t=Object.keys($);for(let e of t){let t=Un(e);if(t)try{t(n),r.push(e)}catch(t){t.message&&t.message.includes(`already registered`)?(H.debug(`Fallback tool ${e} already registered, skipping`),r.push(e)):(H.warn(`Failed to register fallback tool '${e}': ${t.message}`),i.push(e))}else H.warn(`Tool '${e}' not found in registry`),i.push(e)}return H.info(`Successfully registered ${r.length} fallback tools`),{registeredTools:r,failedTools:i,normalizedMode:`all`}}}L.config({quiet:!0});const Kn=z(import.meta.url);F.dirname(Kn);var qn=class{constructor(){this.options={name:`TaskGraph MCP Server`,version:i};let e=new Le(this.options);this.server=e,this.initialized=!1,this.init=this.init.bind(this),this.start=this.start.bind(this),this.stop=this.stop.bind(this),this.logger=H}async init(){if(this.initialized)return;let e=Wn();this.logger.info(`TaskGraph MCP Server starting...`),this.logger.info(`Tool mode configuration: ${e}`);let t=Gn(this.server,e);return this.logger.info(`Normalized tool mode: ${t.normalizedMode}`),this.logger.info(`Registered ${t.registeredTools.length} tools successfully`),t.registeredTools.length>0&&this.logger.debug(`Registered tools: ${t.registeredTools.join(`, `)}`),t.failedTools.length>0&&this.logger.warn(`Failed to register ${t.failedTools.length} tools: ${t.failedTools.join(`, `)}`),this.initialized=!0,this}async start(){return this.initialized||await this.init(),this.server.on(`connect`,e=>{e.session.server.sendLoggingMessage({data:{context:e.session.context,message:`MCP Server connected: ${e.session.name}`},level:`info`})}),await this.server.start({transportType:`stdio`,timeout:12e4}),this}async stop(){this.server&&await this.server.stop()}};L.config({quiet:!0}),process.env.TASKGRAPH_MCP=`true`;async function Jn(){let e=new qn;process.on(`SIGINT`,async()=>{await e.stop(),process.exit(0)}),process.on(`SIGTERM`,async()=>{await e.stop(),process.exit(0)});try{await e.start()}catch(e){H.error(`Failed to start MCP server: ${e.message}`),process.exit(1)}}Jn();export{};
|
|
5
|
+
Current Tag: ${n.currentTag}`),{content:[{type:`text`,text:r}],isError:!0}}function We(e,t){if(typeof e!=`function`)t?.debug?.(`reportProgress not available - operation will run without progress updates`);else return e}function Ge(e){try{let t=M.join(e,`.taskgraph`,`state.json`);return N.existsSync(t)&&JSON.parse(N.readFileSync(t,`utf-8`)).currentTag||`master`}catch{return null}}async function U(e){let{result:t,log:n,errorPrefix:r=`API error`,projectRoot:i,tag:a}=e,o=Ue(),s=a===void 0?i?Ge(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 W(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,`/`),M.resolve(t)}catch{return M.resolve(e)}}function Ke(e){try{return e?.roots?.[0]?.uri?W(e.roots[0].uri):e?.roots?.roots?.[0]?.uri?W(e.roots.roots[0].uri):null}catch{return null}}const qe=/^[A-Za-z0-9_-]+$/;function G(e){return async(t,n)=>{let{log:r,session:i}=n,a=t.tag;if(a!==void 0&&!(typeof a==`string`&&qe.test(a)))return H(`Invalid tag "${String(a)}": use only letters, numbers, hyphens and underscores`);let o=null,s=`unknown`;try{if(process.env.TASKGRAPH_PROJECT_ROOT){let e=process.env.TASKGRAPH_PROJECT_ROOT;o=M.isAbsolute(e)?e:M.resolve(process.cwd(),e),s=`TASKGRAPH_PROJECT_ROOT environment variable`,r?.info?.(`Using project root from ${s}: ${o}`)}else if(i?.env?.TASKGRAPH_PROJECT_ROOT){let e=i.env.TASKGRAPH_PROJECT_ROOT;o=M.isAbsolute(e)?e:M.resolve(process.cwd(),e),s=`TASKGRAPH_PROJECT_ROOT session environment variable`,r?.info?.(`Using project root from ${s}: ${o}`)}else if(t.projectRoot)o=W(t.projectRoot),s=`args.projectRoot`,r?.info?.(`Using project root from ${s}: ${o}`);else{let e=Ke(i);e&&(o=e,s=`session`,r?.info?.(`Using project root from ${s}: ${o}`))}return o?await e({...t,projectRoot:o},n):(r?.error?.(`Could not determine project root from environment, args, or session.`),U({result:{success:!1,error:{message:`Could not determine project root. Please provide projectRoot argument or ensure TASKGRAPH_PROJECT_ROOT environment variable is set.`}}}))}catch(e){return r?.error?.(`Error within withNormalizedProjectRoot HOF (Normalized Root: ${o}): ${e.message}`),e.stack&&r?.debug&&r.debug(e.stack),U({result:{success:!1,error:{message:`Operation failed: ${e.message}`}}})}}}function K(e){return G(async(t,n)=>{let r=await c({projectPath:t.projectRoot,loggerConfig:{mcpMode:!0,logCallback:n.log}});return e(t,{log:n.log,session:n.session,tmCore:r})})}function Je(e,t){let n=N.realpathSync(e),r=M.resolve(e,t),i=r,a=[];for(;;)try{i=N.realpathSync(i);break}catch{a.unshift(M.basename(i)),i=M.dirname(i)}let o=M.relative(n,M.join(i,...a)),s=o===`..`||o.startsWith(`..${M.sep}`)||M.isAbsolute(o);if(t.startsWith(`~`)||s)throw Error(`Path '${t}' is outside the project root '${e}'`);return r}function q(e,t){if(!e)return{parsedMetadata:null};if(process.env.TASKGRAPH_ALLOW_METADATA_UPDATES!==`true`)return{parsedMetadata:null,error:t(`Metadata updates are disabled. Set TASKGRAPH_ALLOW_METADATA_UPDATES=true in your MCP server environment to enable metadata modifications.`)};try{let n=JSON.parse(e);return typeof n!=`object`||!n||Array.isArray(n)?{parsedMetadata:null,error:t(`Invalid metadata: must be a JSON object (not null or array)`)}:{parsedMetadata:n}}catch(e){return{parsedMetadata:null,error:t(`Invalid metadata JSON: ${e instanceof Error?e.message:`Unknown parse error`}. Provide a valid JSON object string.`)}}}const Ye=F.object({taskId:l.describe(`Main task ID to start workflow for (e.g., "1", "2"). 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 Xe(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:Ye,annotations:{title:`Start Autopilot Workflow`,destructiveHint:!0},execute:K(async(e,{log:t,tmCore:n})=>{let{taskId:r,projectRoot:i,maxAttempts:a,force:o}=e;try{t.info(`Starting autopilot workflow for task ${r} in ${i}`);let e=n.config.getActiveTag(),s=await n.tasks.get(r);if(!s||!s.task)return U({result:{success:!1,error:{message:`Task ${r} not found`}},log:t,projectRoot:i});let c=s.task;if(!c.subtasks||c.subtasks.length===0)return U({result:{success:!1,error:{message:`Task ${r} has no subtasks. Please use expand_task (with id="${r}") 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`),U({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 l=await n.workflow.start({taskId:r,taskTitle:c.title,subtasks:c.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,maxAttempts:a})),maxAttempts:a,force:o,tag:e});t.info(`Workflow started successfully for task ${r}`);let u=n.workflow.getNextAction();return U({result:{success:!0,data:{message:`Workflow started for task ${r}`,taskId:r,branchName:l.branchName,phase:l.phase,tddPhase:l.tddPhase,progress:l.progress,currentSubtask:l.currentSubtask,nextAction:u.action,nextSteps:u.nextSteps}},log:t,projectRoot:i})}catch(e){return t.error(`Error in autopilot-start: ${e.message}`),e.stack&&t.debug(e.stack),U({result:{success:!1,error:{message:`Failed to start workflow: ${e.message}`}},log:t,projectRoot:i})}})})}const Ze=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function Qe(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:Ze,annotations:{title:`Resume Autopilot Workflow`,readOnlyHint:!0},execute:K(async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Resuming autopilot workflow in ${r}`),!await n.workflow.hasWorkflow())return U({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}`),U({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),U({result:{success:!1,error:{message:`Failed to resume workflow: ${e.message}`}},log:t,projectRoot:r})}})})}const $e=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function et(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:$e,annotations:{title:`Get Next Autopilot Action`,readOnlyHint:!0},execute:K(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 U({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}`),U({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),U({result:{success:!1,error:{message:`Failed to get next action: ${e.message}`}},log:t,projectRoot:r})}})})}const tt=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function nt(e){e.addTool({name:`autopilot_status`,description:`Get comprehensive workflow status including current phase, progress, subtask details, and activity history.`,parameters:tt,annotations:{title:`Get Autopilot Status`,readOnlyHint:!0},execute:K(async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Getting workflow status for ${r}`),!await n.workflow.hasWorkflow())return U({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}`),U({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),U({result:{success:!1,error:{message:`Failed to get workflow status: ${e.message}`}},log:t,projectRoot:r})}})})}const rt=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 it(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:rt,annotations:{title:`Complete Autopilot Phase`,destructiveHint:!0},execute:K(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 U({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 U({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 U({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}`),U({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),U({result:{success:!1,error:{message:`Failed to complete phase: ${e.message}`}},log:t,projectRoot:r})}})})}const at=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 ot(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:at,annotations:{title:`Commit Autopilot Changes`,destructiveHint:!0},execute:K(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 U({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(),s=n.workflow.getContext();if(e.tddPhase!==`COMMIT`)return t.warn(`Not in COMMIT phase (currently in ${e.tddPhase})`),U({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 U({result:{success:!1,error:{message:`No active subtask to commit`}},log:t,projectRoot:r});let c=new u(r);try{i&&i.length>0?(await c.stageFiles(i),t.info(`Staged ${i.length} files`)):(await c.stageFiles([`.`]),t.info(`Staged all changes`))}catch(e){return t.error(`Failed to stage files: ${e.message}`),U({result:{success:!1,error:{message:`Failed to stage files: ${e.message}`}},log:t,projectRoot:r})}if(!await c.hasStagedChanges())return t.warn(`No staged changes to commit`),U({result:{success:!1,error:{message:`No staged changes to commit. Make code changes before committing`}},log:t,projectRoot:r});let l=await c.getStatus(),d;if(a)d=a,t.info(`Using custom commit message`);else{let n=new o,r={type:e.tddPhase===`COMMIT`?`feat`:`test`,description:e.currentSubtask.title,changedFiles:l.staged,taskId:e.taskId,phase:e.tddPhase,testsPassing:s.lastTestResults?.passed,testsFailing:s.lastTestResults?.failed};d=n.generateMessage(r),t.info(`Generated commit message automatically`)}try{await c.createCommit(d),t.info(`Commit created successfully`)}catch(e){return t.error(`Failed to create commit: ${e.message}`),U({result:{success:!1,error:{message:`Failed to create commit: ${e.message}`}},log:t,projectRoot:r})}let f=await c.getLastCommit(),p=await n.workflow.commit();t.info(`Commit completed. Current phase: ${p.tddPhase||p.phase}`);let m=p.phase===`COMPLETE`,h=n.workflow.getNextAction();return U({result:{success:!0,data:{message:m?`Workflow completed successfully`:`Commit created and workflow advanced`,commitSha:f.sha,commitMessage:d,...p,isComplete:m,nextAction:h.action,nextSteps:h.nextSteps}},log:t,projectRoot:r})}catch(e){return t.error(`Error in autopilot-commit: ${e.message}`),e.stack&&t.debug(e.stack),U({result:{success:!1,error:{message:`Failed to commit: ${e.message}`}},log:t,projectRoot:r})}})})}const st=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function ct(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:st,annotations:{title:`Finalize Autopilot Workflow`,destructiveHint:!0},execute:K(async(e,{log:t,tmCore:n})=>{let{projectRoot:r}=e;try{if(t.info(`Finalizing workflow in ${r}`),!await n.workflow.hasWorkflow())return U({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 U({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 U({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),U({result:{success:!1,error:{message:`Failed to finalize workflow: ${e.message}`}},log:t,projectRoot:r})}})})}const lt=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`)});function ut(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:lt,annotations:{title:`Abort Autopilot Workflow`,destructiveHint:!0},execute:K(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`),U({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`),U({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),U({result:{success:!1,error:{message:`Failed to abort workflow: ${e.message}`}},log:t,projectRoot:r})}})})}const dt=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`),repo:F.string().optional().describe(`Repository as owner/name (default: detected through gh)`)});function ft(e){e.addTool({name:`github_status`,description:`Check whether the gh CLI is usable, which GitHub repository tasks would be pushed to, and how many tasks are already linked to issues.`,parameters:dt,annotations:{title:`GitHub Sync Status`,readOnlyHint:!0},execute:K(async(e,{log:t,tmCore:n})=>{let{projectRoot:r,repo:i}=e;try{return t.info(`Checking GitHub sync status for ${r}`),U({result:{success:!0,data:await n.github.status({repo:i})},log:t,projectRoot:r})}catch(e){return t.error(`Error in github_status: ${e.message}`),U({result:{success:!1,error:{message:`Failed to get GitHub status: ${e.message}`}},log:t,projectRoot:r})}})})}const pt=F.object({projectRoot:F.string().describe(`Absolute path to the project root directory`),dryRun:F.boolean().optional().default(!0).describe(`Preview the plan without writing to GitHub (default: true). Pass false to create and update issues.`),tag:F.string().optional().describe(`Tag to push (default: the active tag)`),allTags:F.boolean().optional().describe(`Push every tag instead of one`),id:F.string().optional().describe(`Only push these top-level task IDs, comma separated`),repo:F.string().optional().describe(`Repository as owner/name (default: detected through gh)`),includeDetails:F.boolean().optional().describe(`Include the task details field in issue bodies`),closeOrphans:F.boolean().optional().describe(`Close open issues whose task no longer exists`)});function mt(e){e.addTool({name:`github_push`,description:`Push tasks to GitHub Issues through the gh CLI: creates issues, updates changed ones and closes finished ones. Runs as a dry run unless dryRun is false, so call it once to review the plan before writing.`,parameters:pt,annotations:{title:`Push Tasks to GitHub`,readOnlyHint:!1,destructiveHint:!1,openWorldHint:!0},execute:K(async(e,{log:t,tmCore:n})=>{let{projectRoot:r,id:i,dryRun:a=!0,...o}=e;try{return t.info(`Pushing tasks to GitHub for ${r} (dryRun: ${a})`),U({result:{success:!0,data:await n.github.push({...o,dryRun:a,taskIds:i})},log:t,projectRoot:r})}catch(e){return t.error(`Error in github_push: ${e.message}`),U({result:{success:!1,error:{message:`Failed to push to GitHub: ${e.message}`}},log:t,projectRoot:r})}})})}const ht=F.object({id:a.optional().describe(`Task or subtask ID (e.g. 5 or 5.2) to explain what blocks it`),limit:F.number().int().positive().optional().describe(`How many bottlenecks to return (default 5)`),projectRoot:F.string().describe(`Absolute path to the project root directory`),tag:F.string().optional().describe(`Tag context to operate on`)});function gt(e){e.addTool({name:`dependency_analysis`,description:`Find the bottlenecks (open tasks holding up the most work), the critical path and dependency cycles. With id, also explain what blocks that task.`,parameters:ht,annotations:{title:`Dependency Analysis`,readOnlyHint:!0},execute:K(async(e,{log:t,tmCore:n})=>{let{id:r,limit:i,projectRoot:a,tag:o}=e;try{return t.info(`Analyzing dependencies${r?` for task ${r}`:``} in ${a}`),U({result:{success:!0,data:await n.tasks.analyzeDependencies({tag:o,limit:i,taskId:r})},log:t,projectRoot:a,tag:o})}catch(e){return t.error(`Error in dependency_analysis: ${e.message}`),U({result:{success:!1,error:{message:`Failed to analyze dependencies: ${e.message}`}},log:t,projectRoot:a})}})})}const _t=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 vt(e){e.addTool({name:`get_tasks`,description:`Get all tasks from TaskGraph, optionally filtering by status and including subtasks.`,parameters:_t,annotations:{title:`Get Tasks`,readOnlyHint:!0},execute:K(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 U({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),U({result:{success:!1,error:{message:`Failed to get tasks: ${e.message}`}},log:t,projectRoot:r})}})})}const yt=F.object({id:n.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 bt(e){e.addTool({name:`get_task`,description:`Get detailed information about a specific task`,parameters:yt,annotations:{title:`Get Task`,readOnlyHint:!0},execute:K(async(e,{log:t,tmCore:n})=>{let{id:i,status:a,projectRoot:o,tag:s}=e;try{t.info(`Getting task details for ID: ${i}${a?` (filtering subtasks by status: ${a})`:``} in root: ${o}`);let e=r(i),c=await Promise.all(e.map(e=>n.tasks.get(e,s))),l=[];for(let e of c)if(e.task){if(a&&e.task.subtasks){let t=a.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): ${i}`),U({result:{success:!1,error:{message:`No tasks found for ID(s): ${i}`}},log:t,projectRoot:o})):(t.info(`Successfully retrieved ${l.length} task(s) for ID(s): ${i}`),U({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),U({result:{success:!1,error:{message:`Failed to get task: ${e.message}`}},log:t,projectRoot:o})}})})}const xt=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 St(e){e.addTool({name:`generate`,description:`Generates individual task files in tasks/ directory based on tasks.json. Only works with local file storage.`,parameters:xt,annotations:{title:`Generate Task Files`,destructiveHint:!0},execute:K(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?Je(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`}`),U({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),U({result:{success:!1,error:{message:`Failed to generate task files: ${e.message}`}},log:t,projectRoot:r})}})})}const Ct=F.object({id:n.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(e).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 wt(e){e.addTool({name:`set_task_status`,description:`Set the status of one or more tasks or subtasks.`,parameters:Ct,annotations:{title:`Set Task Status`,destructiveHint:!0},execute:K(async(e,{log:t,tmCore:n})=>{let{id:i,status:a,projectRoot:o,tag:s}=e;try{t.info(`Setting status of task(s) ${i} to: ${a}${s?` in tag: ${s}`:` in current tag`}`);let e=r(i),c=[];for(let r of e){let e=await n.tasks.updateStatus(r,a,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 "${a}"`),U({result:{success:!0,data:{message:`Successfully updated ${c.length} task(s) to "${a}"`,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),U({result:{success:!1,error:{message:`Failed to set task status: ${n.message}`}},log:t,projectRoot:o,tag:s})}})})}async function Tt(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}`),E(),await f(s,c,l,{projectRoot:o,tag:a}),S(),{success:!0,data:{message:`Successfully added dependency: Task ${c} now depends on ${l}`,taskId:c,dependencyId:l}}}catch(e){return S(),t.error(`Error in addDependencyDirect: ${e.message}`),{success:!1,error:{code:e instanceof b?e.code:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function Et(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,_=parseInt(r,10),v=!u;E();let y={projectRoot:d,tag:f};if(h){t.info(`Converting task ${h} to a subtask of ${_}`);let e=await g(p,_,h,null,v,y);return S(),{success:!0,data:{message:`Task ${h} successfully converted to a subtask of task ${_}`,subtask:e}}}{t.info(`Creating new subtask for parent task ${_}`);let e=await g(p,_,null,{title:a,description:o||``,details:s||``,status:c||`pending`,dependencies:m},v,y);return S(),{success:!0,data:{message:`New subtask ${_}.${e.id} successfully created`,subtask:e}}}}catch(e){return S(),t.error(`Error in addSubtaskDirect: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message}}}}function J(e,t){let n=P.resolve(e);try{n=L.realpathSync(e)}catch{}if(!Fe(n,t))throw Error(`Path '${t}' is outside the project root '${e}'`);return P.resolve(e,t)}const Y={info:()=>{},warn:()=>{},error:()=>{},debug:()=>{},success:()=>{}};function Dt(e,t=Y){let n=e?.file,r=e?.projectRoot;if(n&&!r&&P.isAbsolute(n))throw Error(`projectRoot is required when a file path is absolute`);let i=r?T(r):null;if(n&&i)return J(i,n);if(i){let e=C(n,{projectRoot:i},t);if(e===null&&!n){let e=P.join(i,`.taskgraph`,`tasks`,`tasks.json`);return t?.info?.(`Core findTasksPath returned null, using default path: ${e}`),e}return e}return C(n,null,t)}function Ot(e,t=Y){let n=e?.input,r=e?.projectRoot;if(n&&!r&&P.isAbsolute(n))throw Error(`projectRoot is required when a file path is absolute`);let i=r?T(r):null;return n&&i?J(i,n):i?de(n,{projectRoot:i},t):de(n,null,t)}function kt(e,t=Y){let n=e?.complexityReport,r=e?.projectRoot,i=e?.tag;if(n&&!r&&P.isAbsolute(n))throw Error(`projectRoot is required when a file path is absolute`);let a=r?T(r):null;return n&&a?J(a,n):a?fe(n,{projectRoot:a,tag:i},t):fe(n,null,t)}function At(e,t){if(!t?.projectRoot)throw Error(`projectRoot is required in args to resolve project paths`);let n=T(t.projectRoot);return P.isAbsolute(e)?e:P.resolve(n,e)}function X(e,t=Y){return Dt(e,t)}function jt(e,t=Y){return kt(e,t)}function Mt(e,t,n=Y){return k(e,t,n)}R(import.meta.url);function Z(e){return{info:(t,...n)=>e.info(t,...n),warn:(t,...n)=>e.warn(t,...n),error:(t,...n)=>e.error(t,...n),debug:(t,...n)=>e.debug?e.debug(t,...n):null,success:(t,...n)=>e.info(t,...n)}}async function Nt(e,t,n={}){let{tasksJsonPath:r,name:i,copyFromCurrent:a=!1,copyFromTag:o,fromBranch:s=!1,description:c,projectRoot:l}=e,{session:u}=n;E();let d=Z(t);try{if(!r)return t.error(`addTagDirect called without tasksJsonPath`),S(),{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-CRR3iPaC.js`);if(!await e.isGitRepository(l))return t.error(`Not in a git repository`),S(),{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`),S(),{success:!1,error:{code:`NO_CURRENT_BRANCH`,message:`Could not determine current git branch.`}};let i={copyFromCurrent:a,copyFromTag:o,description:c||`Tag created from git branch "${n}"`},s=await Ce(r,n,i,{session:u,mcpLog:d,projectRoot:l},`json`);return S(),{success:!0,data:{branchName:s.branchName,tagName:s.tagName,created:s.created,mappingUpdated:s.mappingUpdated,message:`Successfully created tag "${s.tagName}" from git branch "${s.branchName}"`}}}{if(!i||typeof i!=`string`)return t.error(`Missing required parameter: name`),S(),{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 Me(r,i,{copyFromCurrent:a,copyFromTag:o,description:c},{session:u,mcpLog:d,projectRoot:l},`json`);return S(),{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 S(),t.error(`Error in addTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`ADD_TAG_ERROR`,message:e.message}}}}async function Pt(e,t,n={}){let{tasksJsonPath:r,prompt:i,dependencies:a,priority:o,research:s,projectRoot:c,tag:l}=e,{session:u}=n;E();let d=Z(t);try{if(!r)return t.error(`addTaskDirect called without tasksJsonPath`),S(),{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`),S(),{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 x(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 x(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 S(),{success:!0,data:{taskId:g,message:`Successfully added new task #${g}`,telemetryData:_,tagInfo:v}}}catch(e){return S(),t.error(`Error in addTaskDirect: ${e.message}`),{success:!1,error:{code:e.code||`ADD_TASK_ERROR`,message:e.message}}}}async function Ft(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=Z(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||E();let _;try{_=await le(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()&&S(),{success:!1,error:{code:`ANALYZE_CORE_ERROR`,message:`Error running core complexity analysis: ${e.message}`}}}finally{!g&&w()&&S()}if(!L.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()&&S(),t.error(`Error in analyzeTaskComplexityDirect setup: ${e.message}`),{success:!1,error:{code:`DIRECT_FUNCTION_SETUP_ERROR`,message:e.message}}}}async function It(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(!L.existsSync(s))return{success:!1,error:{code:`FILE_NOT_FOUND_ERROR`,message:`Tasks file not found at ${s}`}};let c,l=D(s,o,a);if(!l||!l.tasks)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`No tasks found in tasks file: ${s}`}};let u=l.tag||a,d=l.tasks;if(i){if(t.info(`Clearing subtasks from all tasks in tag '${u}'`),d.length===0)return{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`No tasks found in tag context '${u}'`}};c=d.map(e=>e.id).join(`,`)}else c=r;t.info(`Clearing subtasks from tasks: ${c} in tag '${u}'`),E();let f;try{f=m(s,c,{projectRoot:o,tag:u})}finally{S()}let{cleared:p,empty:h}=f,g=p.reduce((e,t)=>e+t.count,0);return{success:!0,data:{message:p.length>0?`Cleared ${g} subtask(s) from ${p.length} task(s) in tag '${u}'`:`No subtasks to clear in tag '${u}'`,tasksCleared:p.map(({id:e,title:t,count:n})=>({id:e,title:t,subtasksCleared:n})),tasksWithoutSubtasks:h,tag:u}}}catch(e){return t.error(`Error in clearSubtasksDirect: ${e.message}`),{success:!1,error:{code:e.name===`ClearSubtasksError`?`INPUT_VALIDATION_ERROR`:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function Lt(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{E();let e=ye(n);return S(),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 S(),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 S(),t.error(`Unexpected error during complexityReport: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}catch(e){return S(),t.error(`Error in complexityReportDirect: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}async function Rt(e,t,n={}){let{tasksJsonPath:r,sourceName:i,targetName:a,description:o,projectRoot:s}=e,{session:c}=n;E();let l=Z(t);try{if(!r)return t.error(`copyTagDirect called without tasksJsonPath`),S(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: sourceName`),S(),{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`),S(),{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 Ae(r,i,a,{description:o},{session:c,mcpLog:l,projectRoot:s},`json`);return S(),{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 S(),t.error(`Error in copyTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`COPY_TAG_ERROR`,message:e.message}}}}async function zt(e,t,n={}){let{tasksJsonPath:r,name:i,yes:a=!1,projectRoot:o}=e,{session:s}=n;E();let c=Z(t);try{if(!r)return t.error(`deleteTagDirect called without tasksJsonPath`),S(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: name`),S(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Tag name is required and must be a string`}};t.info(`Deleting tag: ${i}`);let e=await De(r,i,{yes:a},{session:s,mcpLog:c,projectRoot:o},`json`);return S(),{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 S(),t.error(`Error in deleteTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`DELETE_TAG_ERROR`,message:e.message}}}}async function Bt(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=Z(t),p=d||k(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`}};E();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 te(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{S()}}async function Vt(e,t,n={}){let{session:r}=n,{tasksJsonPath:i,id:a,num:o,research:s,prompt:c,force:l,projectRoot:u,tag:d,complexityReportPath:f}=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 p=i;t.info(`[expandTaskDirect] Using tasksPath: ${p}`);let m=a?parseInt(a,10):null;if(!m)return t.error(`Task ID is required`),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Task ID is required`}};let h=o?parseInt(o,10):void 0,g=s===!0,_=c||``,v=l===!0;try{t.info(`[expandTaskDirect] Expanding task ${m} into ${h||`default`} subtasks. Research: ${g}, Force: ${v}`),t.info(`[expandTaskDirect] Attempting to read JSON from: ${p}`);let e=D(p,u);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: ${p}`),{success:!1,error:{code:`INVALID_TASKS_FILE`,message:`No valid tasks found in ${p}. readJSON returned: ${JSON.stringify(e)}`}};t.info(`[expandTaskDirect] Searching for task ID ${m} in data`);let n=e.tasks.find(e=>e.id===m);if(t.info(`[expandTaskDirect] Task found: ${n?`Yes`:`No`}`),!n)return{success:!1,error:{code:`TASK_NOT_FOUND`,message:`Task with ID ${m} not found`}};if(n.status===`done`||n.status===`completed`)return{success:!1,error:{code:`TASK_COMPLETED`,message:`Task ${m} is already marked as ${n.status} and cannot be expanded`}};let i=n.subtasks&&n.subtasks.length>0;if(i&&!v)return t.info(`Task ${m} already has ${n.subtasks.length} subtasks. Use --force to overwrite.`),{success:!0,data:{message:`Task ${m} already has subtasks. Expansion skipped.`,task:n,subtasksAdded:0,hasExistingSubtasks:i}};i&&v&&(t.info(`Force flag set. Clearing existing subtasks for task ${m}.`),n.subtasks=[]),JSON.parse(JSON.stringify(n));let a=n.subtasks?n.subtasks.length:0;n.subtasks||=[],ge(p,e,u,d);let o=Z(t),s;try{s=w(),s||E();let e=await ee(p,m,h,g,_,{complexityReportPath:f,mcpLog:o,session:r,projectRoot:u,commandName:`expand-task`,outputType:`mcp`,tag:d},v);!s&&w()&&S();let n=D(p,u).tasks.find(e=>e.id===m),c=n.subtasks?n.subtasks.length-a:0;return t.info(`Successfully expanded task ${m} 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()&&S(),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 function Ht(e,t){let{tasksJsonPath:n,projectRoot:r,tag:i}=e;try{if(t.info(`Fixing invalid dependencies in tasks: ${n}`),!n)return t.error(`fixDependenciesDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};let e=n;if(!L.existsSync(e))return{success:!1,error:{code:`FILE_NOT_FOUND`,message:`Tasks file not found at ${e}`}};E();let a=await d(e,{context:{projectRoot:r,tag:i}});return S(),{success:!0,data:{message:a.remaining.length>0?`Fixed ${a.fixes.length} dependency problem(s); ${a.remaining.length} left that need a decision, such as loops between tasks`:`Fixed ${a.fixes.length} dependency problem(s)`,...a,tasksPath:e,tag:i||`master`}}}catch(e){return S(),t.error(`Error fixing dependencies: ${e.message}`),{success:!1,error:{code:e instanceof b?e.code:`FIX_DEPENDENCIES_ERROR`,message:e.message}}}}async function Ut(e,t,n={}){let{session:r}=n,i=ze.homedir();t.info(`Args received in direct function: ${JSON.stringify(e)}`);let a=e.projectRoot;if(!a||typeof a!=`string`||a===`/`||a===i)return t.error(`Invalid target directory received from tool layer: '${a}'`),{success:!1,error:{code:`INVALID_TARGET_DIRECTORY`,message:`Cannot initialize project: Invalid target directory '${a}' received. Please ensure a valid workspace/folder is open or specified.`,details:`Received args.projectRoot: ${e.projectRoot}`}};t.info(`Validated target directory for initialization: ${a}`);let o=process.cwd(),s,c=!1,l=null;t.info(`Temporarily changing CWD to ${a} for initialization.`),process.chdir(a),E();try{let n={addAliases:e.addAliases,initGit:e.initGit,storeTasksInGit:e.storeTasksInGit,skipInstall:e.skipInstall,yes:!0};Array.isArray(e.rules)&&e.rules.length>0?(n.rules=e.rules,n.rulesExplicitlyProvided=!0,t.info(`Including rules: ${e.rules.join(`, `)}`)):(n.rules=[`claude`],n.rulesExplicitlyProvided=!0,t.info(`No rule profiles specified, defaulting to: Claude`)),t.info(`Initializing project with options: ${JSON.stringify(n)}`),s={message:`Project initialized successfully.`,next_step:`Now that the project is initialized, the next step is to create the tasks by parsing a PRD. This will create the tasks folder and the initial task files (tasks folder will be created when parse-prd is run). The parse-prd tool will require a prd.txt file as input (typically found in .taskgraph/docs/ directory). You can create a prd.txt file by asking the user about their idea, and then using the .taskgraph/templates/example_prd.txt file as a template to generate a prd.txt file in .taskgraph/docs/. You may skip all of this if the user already has a prd.txt file. You can THEN use the parse-prd tool to create the tasks. So: step 1 after initialization is to create a prd.txt file in .taskgraph/docs/prd.txt or confirm the user already has one. Step 2 is to use the parse-prd tool to create the tasks. Do not bother looking for tasks after initialization, just use the parse-prd tool to create the tasks after creating a prd.txt from which to parse the tasks. You do NOT need to reinitialize the project to parse-prd.`,...await Le(n)},c=!0,t.info(`Project initialization completed successfully in ${a}.`)}catch(e){t.error(`Core initializeProject failed: ${e.message}`),l={code:`INITIALIZATION_FAILED`,message:`Core project initialization failed: ${e.message}`,details:e.stack},c=!1}finally{S(),t.info(`Restoring original CWD: ${o}`),process.chdir(o)}return c?{success:!0,data:s}:{success:!1,error:l}}async function Wt(e,t,n={}){let{tasksJsonPath:r,showMetadata:i=!1,projectRoot:a}=e,{session:o}=n;E();let s=Z(t);try{if(!r)return t.error(`listTagsDirect called without tasksJsonPath`),S(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};t.info(`Listing all tags`);let e=await we(r,{showMetadata:i},{session:o,mcpLog:s,projectRoot:a},`json`),n=e.tags.map(e=>{let t=e.tasks||[],n=t.reduce((e,t)=>{let n=t.status||`pending`;return e[n]=(e[n]||0)+1,e},{}),r=t.reduce((e,t)=>(t.subtasks&&t.subtasks.length>0&&(e.totalSubtasks+=t.subtasks.length,t.subtasks.forEach(t=>{let n=t.status||`pending`;e.subtasksByStatus[n]=(e.subtasksByStatus[n]||0)+1})),e),{totalSubtasks:0,subtasksByStatus:{}});return{name:e.name,isCurrent:e.isCurrent,taskCount:t.length,completedTasks:e.completedTasks,statusBreakdown:n,subtaskCounts:r,created:e.created,description:e.description}});return S(),{success:!0,data:{tags:n,currentTag:e.currentTag,totalTags:e.totalTags,message:`Found ${e.totalTags} tag(s)`}}}catch(e){return S(),t.error(`Error in listTagsDirect: ${e.message}`),{success:!1,error:{code:e.code||`LIST_TAGS_ERROR`,message:e.message}}}}const Gt=[`main`,`research`,`fallback`];async function Kt(e,t){for(let n of Gt){let r=`set${n.charAt(0).toUpperCase()+n.slice(1)}`;if(e[r])return await Ee(n,e[r],t)}return null}async function qt(e,t,n={}){let{session:r}=n,{projectRoot:i}=e,a=Z(t);t.info(`Executing models_direct with args: ${JSON.stringify(e)}`),t.info(`Using project root: ${i}`);try{E();try{return e.listAvailableModels===!0?await ke({session:r,mcpLog:a,projectRoot:i}):await Kt(e,{session:r,mcpLog:a,projectRoot:i})||await je({session:r,mcpLog:a,projectRoot:i})}finally{S()}}catch(e){return t.error(`Error in models_direct: ${e.message}`),{success:!1,error:{code:`DIRECT_FUNCTION_ERROR`,message:e.message,details:e.stack}}}}async function Jt(e,t,n={}){let{session:r}=n,{projectRoot:i}=e;if(t.info(`moveTaskCrossTagDirect called with args: ${JSON.stringify(e)}`),!e.sourceIds)return{success:!1,error:{message:`Source IDs are required`,code:`MISSING_SOURCE_IDS`}};if(!e.sourceTag)return{success:!1,error:{message:`Source tag is required for cross-tag moves`,code:`MISSING_SOURCE_TAG`}};if(!e.targetTag)return{success:!1,error:{message:`Target tag is required for cross-tag moves`,code:`MISSING_TARGET_TAG`}};if(e.sourceTag===e.targetTag)return{success:!1,error:{message:`Source and target tags are the same ("${e.sourceTag}")`,code:`SAME_SOURCE_TARGET_TAG`,suggestions:[`Use different tags for cross-tag moves`,`Use within-tag move: taskgraph move --from=<id> --to=<id> --tag=<tag>`,`Check available tags: taskgraph tags`]}};try{let n=e.tasksJsonPath||e.file;if(!n){if(!e.projectRoot)return{success:!1,error:{message:`Project root is required if tasksJsonPath is not provided`,code:`MISSING_PROJECT_ROOT`}};n=X(e,t)}E();try{let t=e.sourceIds.split(`,`).map(e=>e.trim()),r={withDependencies:e.withDependencies||!1,ignoreDependencies:e.ignoreDependencies||!1};return{success:!0,data:{...await y(n,t,e.sourceTag,e.targetTag,r,{projectRoot:i}),message:`Successfully moved ${t.length} task(s) from "${e.sourceTag}" to "${e.targetTag}"`,moveOptions:r,sourceTag:e.sourceTag,targetTag:e.targetTag}}}finally{S()}}catch(e){t.error(`Failed to move tasks between tags: ${e.message}`),t.error(`Error code: ${e.code}, Error name: ${e.name}`);let n=`MOVE_TASK_CROSS_TAG_ERROR`,r=[];return e.code===`CROSS_TAG_DEPENDENCY_CONFLICTS`?(n=`CROSS_TAG_DEPENDENCY_CONFLICT`,r=[`Use --with-dependencies to move dependent tasks together`,`Use --ignore-dependencies to break cross-tag dependencies`,`Run taskgraph validate-dependencies to check for issues`,`Move dependencies first, then move the main task`]):e.code===`CANNOT_MOVE_SUBTASK`?(n=`SUBTASK_MOVE_RESTRICTION`,r=[`Promote subtask to full task first: taskgraph remove-subtask --id=<subtaskId> --convert`,`Move the parent task with all subtasks using --with-dependencies`]):e.code===`TASK_NOT_FOUND`||e.code===`INVALID_SOURCE_TAG`||e.code===`INVALID_TARGET_TAG`?(n=`TAG_OR_TASK_NOT_FOUND`,r=[`Check available tags: taskgraph tags`,`Verify task IDs exist: taskgraph list`,`Check task details: taskgraph show <id>`]):e.message.includes(`cross-tag dependency conflicts`)?(n=`CROSS_TAG_DEPENDENCY_CONFLICT`,r=[`Use --with-dependencies to move dependent tasks together`,`Use --ignore-dependencies to break cross-tag dependencies`,`Run taskgraph validate-dependencies to check for issues`,`Move dependencies first, then move the main task`]):e.message.includes(`Cannot move subtask`)?(n=`SUBTASK_MOVE_RESTRICTION`,r=[`Promote subtask to full task first: taskgraph remove-subtask --id=<subtaskId> --convert`,`Move the parent task with all subtasks using --with-dependencies`]):e.message.includes(`not found`)?(n=`TAG_OR_TASK_NOT_FOUND`,r=[`Check available tags: taskgraph tags`,`Verify task IDs exist: taskgraph list`,`Check task details: taskgraph show <id>`]):(e.code===`TASK_ALREADY_EXISTS`||e.message?.includes(`already exists in target tag`))&&(n=`TASK_ALREADY_EXISTS`,r=[`Choose a different target tag without conflicting IDs`,`Move a different set of IDs (avoid existing ones)`,`If needed, move within-tag to a new ID first, then cross-tag move`]),{success:!1,error:{message:e.message,code:n,suggestions:r}}}}async function Q(e,t,n={}){let{session:r}=n,{projectRoot:i,tag:a}=e;if(!e.sourceId)return{success:!1,error:{message:`Source ID is required`,code:`MISSING_SOURCE_ID`}};if(!e.destinationId)return{success:!1,error:{message:`Destination ID is required`,code:`MISSING_DESTINATION_ID`}};try{let n=e.tasksJsonPath||e.file;if(!n){if(!e.projectRoot)return{success:!1,error:{message:`Project root is required if tasksJsonPath is not provided`,code:`MISSING_PROJECT_ROOT`}};n=X(e,t)}E();let r=e.generateFiles!==!1,o=await v(n,e.sourceId,e.destinationId,r,{projectRoot:i,tag:a});return S(),{success:!0,data:{...o,message:`Successfully moved task/subtask ${e.sourceId} to ${e.destinationId}`}}}catch(e){return S(),t.error(`Failed to move task: ${e.message}`),{success:!1,error:{message:e.message,code:`MOVE_TASK_ERROR`}}}}async function Yt(e,t,n={}){let{tasksJsonPath:r,reportPath:i,projectRoot:a,tag:o}=e,{session:s}=n;if(!r)return t.error(`nextTaskDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};let c=async()=>{try{E(),t.info(`Finding next task from ${r}`);let e=D(r,a,o);if(!e||!e.tasks)return S(),{success:!1,error:{code:`INVALID_TASKS_FILE`,message:`No valid tasks found in ${r}`}};let n=ye(i),s=Te(e.tasks,n);if(!s)return t.info(`No eligible next task found. All tasks are either completed or have unsatisfied dependencies`),{success:!0,data:{message:`No eligible next task found. All tasks are either completed or have unsatisfied dependencies`,nextTask:null}};let c=typeof s.id==`string`&&s.id.includes(`.`),l=c?`subtask`:`task`,u=c?`Subtasks can be updated with timestamped details as you implement them. This is useful for tracking progress, marking milestones and insights (of successful or successive falures in attempting to implement the subtask). Research can be used when updating the subtask to collect up-to-date information, and can be helpful to solve a repeating problem the agent is unable to solve. It is a good idea to get-task the parent task to collect the overall context of the task, and to get-task the subtask to collect the specific details of the subtask.`:`Tasks can be updated to reflect a change in the direction of the task, or to reformulate the task per your prompt. Research can be used when updating the task to collect up-to-date information. It is best to update subtasks as you work on them, and to update the task for more high-level changes that may affect pending subtasks or the general direction of the task.`;return S(),t.info(`Successfully found next task ${s.id}: ${s.title}. Is subtask: ${c}`),{success:!0,data:{nextTask:s,isSubtask:c,nextSteps:`When ready to work on the ${l}, use set-status to set the status to "in progress" ${u}`}}}catch(e){return S(),t.error(`Error finding next task: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message||`Failed to find next task`}}}};try{let e=await c();return t.info(`nextTaskDirect completed.`),e}catch(e){return t.error(`Unexpected error during nextTask: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}async function Xt(e,t,n={}){let{session:r,reportProgress:i}=n,{input:a,output:o,numTasks:s,force:c,append:l,research:u,projectRoot:d,tag:f}=e,p=Z(t);if(!d)return p.error(`parsePRDDirect requires a projectRoot argument.`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`projectRoot is required.`}};let m;if(a)try{m=Ot({input:a,projectRoot:d},r)}catch(e){return p.error(`Error resolving PRD path: ${e.message}`),{success:!1,error:{code:`FILE_NOT_FOUND`,message:e.message}}}else return p.error(`parsePRDDirect called without input path`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`Input path is required`}};let h;try{h=o?J(d,o):At(`.taskgraph/tasks/tasks.json`,e)||P.resolve(d,`.taskgraph/tasks/tasks.json`)}catch(e){return p.error(`Error resolving output path: ${e.message}`),{success:!1,error:{code:`INVALID_PATH`,message:e.message}}}if(!L.existsSync(m)){let e=`Input PRD file not found at resolved path: ${m}`;return p.error(e),{success:!1,error:{code:`FILE_NOT_FOUND`,message:e}}}let g=P.dirname(h);try{L.existsSync(g)||(p.info(`Creating output directory: ${g}`),L.mkdirSync(g,{recursive:!0}))}catch(e){let t=`Failed to create output directory ${g}: ${e.message}`;return p.error(t),{success:!1,error:{code:`DIRECTORY_CREATE_FAILED`,message:t}}}let _=be(d);s&&(_=typeof s==`string`?parseInt(s,10):s,(Number.isNaN(_)||_<0)&&(_=be(d),p.warn(`Invalid numTasks value: ${s}. Using default: ${_}`))),l&&(p.info(`Append mode enabled.`),c&&p.warn(`Both --force and --append flags were provided. --force takes precedence; append mode will be ignored.`)),u&&p.info(`Research mode enabled. Using Claude Code web research for enhanced PRD analysis.`),p.info(`Parsing PRD via direct function. Input: ${m}, Output: ${h}, NumTasks: ${_}, Force: ${c}, Append: ${l}, Research: ${u}, ProjectRoot: ${d}`);let v=w();v||E();try{let e=await ce(m,h,_,{session:r,mcpLog:p,projectRoot:d,tag:f,force:c,append:l,research:u,reportProgress:i,commandName:`parse-prd`,outputType:`mcp`},`json`);if(e&&e.success){let t=`Successfully parsed PRD and generated tasks in ${e.tasksPath}`;return p.success(t),{success:!0,data:{message:t,outputPath:e.tasksPath,telemetryData:e.telemetryData,tagInfo:e.tagInfo}}}return p.error(`Core parsePRD function did not return a successful structure.`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e?.message||`Core function failed to parse PRD or returned unexpected result.`}}}catch(e){return p.error(`Error executing core parsePRD: ${e.message}`),{success:!1,error:{code:`PARSE_PRD_CORE_ERROR`,message:e.message||`Unknown error parsing PRD`}}}finally{!v&&w()&&S()}}async function Zt(e,t){let{tasksJsonPath:n,id:r,dependsOn:i,projectRoot:a,tag:o}=e;try{if(t.info(`Removing dependency with args: ${JSON.stringify(e)}`),!n)return t.error(`removeDependencyDirect 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(`Removing dependency: task ${c} no longer depends on ${l}`),E(),await ue(s,c,l,{projectRoot:a,tag:o}),S(),{success:!0,data:{message:`Successfully removed dependency: Task ${c} no longer depends on ${l}`,taskId:c,dependencyId:l}}}catch(e){return S(),t.error(`Error in removeDependencyDirect: ${e.message}`),{success:!1,error:{code:e instanceof b?e.code:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function Qt(e,t){let{tasksJsonPath:n,id:r,convert:i,skipGenerate:a,projectRoot:o,tag:s}=e;try{if(E(),t.info(`Removing subtask with args: ${JSON.stringify(e)}`),!n)return t.error(`removeSubtaskDirect called without tasksJsonPath`),S(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!r)return S(),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Subtask ID is required and must be in format "parentId.subtaskId"`}};if(!r.includes(`.`))return S(),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Invalid subtask ID format: ${r}. Expected format: "parentId.subtaskId"`}};let c=n,l=i===!0,u=!a;t.info(`Removing subtask ${r} (convertToTask: ${l}, generateFiles: ${u})`);let d=await re(c,r,l,u,{projectRoot:o,tag:s});return S(),l&&d?{success:!0,data:{message:`Subtask ${r} successfully converted to task #${d.id}`,task:d}}:{success:!0,data:{message:`Subtask ${r} successfully removed`}}}catch(e){return S(),t.error(`Error in removeSubtaskDirect: ${e.message}`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e.message}}}}async function $t(e,t,n={}){let{tasksJsonPath:r,id:i,projectRoot:a,tag:o}=e,{session:s}=n;try{if(!r)return t.error(`removeTaskDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i)return t.error(`Task ID is required`),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:`Task ID is required`}};let e=i.split(`,`).map(e=>e.trim());t.info(`Removing ${e.length} task(s) with ID(s): ${e.join(`, `)} from ${r}${o?` in tag '${o}'`:``}`);let n=D(r,a,o);if(!n||!n.tasks)return{success:!1,error:{code:`INVALID_TASKS_FILE`,message:`No valid tasks found in ${r}${o?` for tag '${o}'`:``}`}};let s=e.filter(e=>!_(n.tasks,e));if(s.length>0)return{success:!1,error:{code:`INVALID_TASK_ID`,message:`The following tasks were not found${o?` in tag '${o}'`:``}: ${s.join(`, `)}`}};E();try{let n=await oe(r,i,{projectRoot:a,tag:o});return n.success?(t.info(`Successfully removed ${n.removedTasks.length} task(s)`),{success:!0,data:{totalTasks:e.length,successful:n.removedTasks.length,failed:e.length-n.removedTasks.length,removedTasks:n.removedTasks,message:n.message,tasksPath:r,tag:o}}):{success:!1,error:{code:`REMOVE_TASK_ERROR`,message:n.error||`Failed to remove tasks`}}}finally{S()}}catch(e){return S(),t.error(`Unexpected error in removeTaskDirect: ${e.message}`),{success:!1,error:{code:`UNEXPECTED_ERROR`,message:e.message}}}}async function en(e,t,n={}){let{tasksJsonPath:r,oldName:i,newName:a,projectRoot:o}=e,{session:s}=n;E();let c=Z(t);try{if(!r)return t.error(`renameTagDirect called without tasksJsonPath`),S(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: oldName`),S(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Old tag name is required and must be a string`}};if(!a||typeof a!=`string`)return t.error(`Missing required parameter: newName`),S(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`New tag name is required and must be a string`}};t.info(`Renaming tag from "${i}" to "${a}"`);let e=await Ne(r,i,a,{},{session:s,mcpLog:c,projectRoot:o},`json`);return S(),{success:!0,data:{oldName:e.oldName,newName:e.newName,renamed:e.renamed,taskCount:e.taskCount,wasCurrentTag:e.wasCurrentTag,message:`Successfully renamed tag from "${e.oldName}" to "${e.newName}"`}}}catch(e){return S(),t.error(`Error in renameTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`RENAME_TAG_ERROR`,message:e.message}}}}async function tn(e,t,n={}){let{query:r,taskIds:i,filePaths:a,customContext:o,includeProjectTree:s=!1,detailLevel:c=`medium`,saveTo:l,saveToFile:u=!1,projectRoot:d,tag:f}=e,{session:p}=n;E();let m=Z(t);try{if(!r||typeof r!=`string`||r.trim().length===0)return t.error(`Missing or invalid required parameter: query`),S(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`The query parameter is required and must be a non-empty string`}};let e=i?i.split(`,`).map(e=>e.trim()).filter(e=>e.length>0):[],n=a?a.split(`,`).map(e=>e.trim()).filter(e=>e.length>0):[];if(d)try{n.forEach(e=>J(d,e))}catch(e){return S(),{success:!1,error:{code:`INVALID_PATH`,message:e.message}}}let h=[`low`,`medium`,`high`];if(!h.includes(c))return t.error(`Invalid detail level: ${c}`),S(),{success:!1,error:{code:`INVALID_PARAMETER`,message:`Detail level must be one of: ${h.join(`, `)}`}};t.info(`Performing research query: "${r.substring(0,100)}${r.length>100?`...`:``}", taskIds: [${e.join(`, `)}], filePaths: [${n.join(`, `)}], detailLevel: ${c}, includeProjectTree: ${s}, projectRoot: ${d}`);let g={taskIds:e,filePaths:n,customContext:o||``,includeProjectTree:s,detailLevel:c,projectRoot:d,tag:f,saveToFile:u},_={session:p,mcpLog:m,commandName:`research`,outputType:`mcp`},v=await Pe(r.trim(),g,_,`json`,!1);if(l)try{let{appendResearchToTask:e}=await import(`./research-CEiR5MKk.js`);e(P.join(d,`.taskgraph`,`tasks`,`tasks.json`),l,`## Research: ${r.trim()}\n\n${v.result}`,{projectRoot:d,tag:f}),t.info(`Research saved to ${l.includes(`.`)?`subtask`:`task`} ${l}`)}catch(e){t.warn(`Error saving research to task/subtask: ${e.message}`)}return S(),{success:!0,data:{query:v.query,result:v.result,contextSize:v.contextSize,contextTokens:v.contextTokens,tokenBreakdown:v.tokenBreakdown,systemPromptTokens:v.systemPromptTokens,userPromptTokens:v.userPromptTokens,totalInputTokens:v.totalInputTokens,detailLevel:v.detailLevel,telemetryData:v.telemetryData,tagInfo:v.tagInfo,savedFilePath:v.savedFilePath}}}catch(e){return S(),t.error(`Error in researchDirect: ${e.message}`),{success:!1,error:{code:e.code||`RESEARCH_ERROR`,message:e.message}}}}async function nn(e,t,n={}){let{tasksJsonPath:r,id:i,strength:a=`regular`,prompt:o,research:s=!1,projectRoot:c,tag:l}=e,{session:u}=n;E();let d=Z(t);try{if(!r)return t.error(`scopeDownDirect called without tasksJsonPath`),S(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i)return t.error(`Missing required parameter: id`),S(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`The id parameter is required for scoping down tasks`}};let e=i.split(`,`).map(e=>parseInt(e.trim(),10));t.info(`Scoping down tasks: ${e.join(`, `)}, strength: ${a}, research: ${s}`);let n=await ne(r,e,a,o,{session:u,mcpLog:d,projectRoot:c,commandName:`scope-down`,outputType:`mcp`,tag:l,research:s},`json`);return S(),{success:!0,data:{updatedTasks:n.updatedTasks,tasksUpdated:n.updatedTasks.length,message:`Successfully scoped down ${n.updatedTasks.length} task(s)`,telemetryData:n.telemetryData}}}catch(e){return S(),t.error(`Error in scopeDownDirect: ${e.message}`),{success:!1,error:{code:e.code||`SCOPE_DOWN_ERROR`,message:e.message}}}}async function rn(e,t,n={}){let{tasksJsonPath:r,id:i,strength:a=`regular`,prompt:o,research:s=!1,projectRoot:c,tag:l}=e,{session:u}=n;E();let d=Z(t);try{if(!r)return t.error(`scopeUpDirect called without tasksJsonPath`),S(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i)return t.error(`Missing required parameter: id`),S(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`The id parameter is required for scoping up tasks`}};let e=i.split(`,`).map(e=>parseInt(e.trim(),10));t.info(`Scoping up tasks: ${e.join(`, `)}, strength: ${a}, research: ${s}`);let n=await h(r,e,a,o,{session:u,mcpLog:d,projectRoot:c,commandName:`scope-up`,outputType:`mcp`,tag:l,research:s},`json`);return S(),{success:!0,data:{updatedTasks:n.updatedTasks,tasksUpdated:n.updatedTasks.length,message:`Successfully scoped up ${n.updatedTasks.length} task(s)`,telemetryData:n.telemetryData}}}catch(e){return S(),t.error(`Error in scopeUpDirect: ${e.message}`),{success:!1,error:{code:e.code||`SCOPE_UP_ERROR`,message:e.message}}}}async function an(e,t,n={}){let{session:r}=n,{tasksJsonPath:i,id:a,prompt:o,research:s,metadata:c,projectRoot:l,tag:u}=e,d=Z(t);try{if(d.info(`Updating subtask by ID via direct function. ID: ${a}, ProjectRoot: ${l}`),!i){let e=`tasksJsonPath is required but was not provided.`;return d.error(e),{success:!1,error:{code:`MISSING_ARGUMENT`,message:e}}}if(!a||typeof a!=`string`||!a.trim()){let e=`Subtask ID cannot be empty.`;return d.error(e),{success:!1,error:{code:`INVALID_SUBTASK_ID`,message:e}}}if(!o&&!c){let e=`No prompt or metadata specified. Please provide information to append or metadata to update.`;return d.error(e),{success:!1,error:{code:`MISSING_PROMPT`,message:e}}}let e=String(a).trim(),n=i,f=s===!0;t.info(`Updating subtask with ID ${e} with prompt "${o||`(metadata-only)`}" and research: ${f}`);let p=w();p||E();try{let t=await ae(n,e,o,f,{mcpLog:d,session:r,projectRoot:l,tag:u,commandName:`update-subtask`,outputType:`mcp`,metadata:c},`json`);if(!t||t.updatedSubtask===null){let e=`Subtask ${a} or its parent task not found.`;return d.error(e),{success:!1,error:{code:`SUBTASK_NOT_FOUND`,message:e}}}let i=e.split(`.`)[0],s=`Successfully updated subtask with ID ${e}`;return d.success(s),{success:!0,data:{message:`Successfully updated subtask with ID ${e}`,subtaskId:e,parentId:i,subtask:t.updatedSubtask,tasksPath:n,useResearch:f,telemetryData:t.telemetryData,tagInfo:t.tagInfo}}}catch(e){return d.error(`Error updating subtask by ID: ${e.message}`),{success:!1,error:{code:`UPDATE_SUBTASK_CORE_ERROR`,message:e.message||`Unknown error updating subtask`}}}finally{!p&&w()&&S()}}catch(e){return d.error(`Setup error in updateSubtaskByIdDirect: ${e.message}`),w()&&S(),{success:!1,error:{code:`DIRECT_FUNCTION_SETUP_ERROR`,message:e.message||`Unknown setup error`}}}}async function on(e,t,n={}){let{session:r}=n,{tasksJsonPath:i,id:a,prompt:o,research:s,append:c,metadata:l,projectRoot:u,tag:d}=e,f=Z(t);try{if(f.info(`Updating task by ID via direct function. ID: ${a}, ProjectRoot: ${u}`),!a){let e=`No task ID specified. Please provide a task ID to update.`;return f.error(e),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:e}}}if(!o&&!l){let e=`No prompt or metadata specified. Please provide a prompt with new information or metadata for the task update.`;return f.error(e),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:e}}}let t;if(typeof a==`string`)t=a;else if(typeof a==`number`)t=String(a);else{let e=`Invalid task ID type: ${typeof a}. Task ID must be a string or number.`;return f.error(e),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:e}}}let n=i||X({projectRoot:u,file:e.file},f);if(!n){let e=`tasks.json path could not be resolved.`;return f.error(e),{success:!1,error:{code:`INPUT_VALIDATION_ERROR`,message:e}}}let p=s===!0;f.info(`Updating task with ID ${t} with prompt "${o||`(metadata-only)`}" and research: ${p}`);let m=w();m||E();try{let e=await ie(n,t,o,p,{mcpLog:f,session:r,projectRoot:u,tag:d,commandName:`update-task`,outputType:`mcp`,metadata:l},`json`,c||!1);if(!e||e.updatedTask===null){let n=`Task ${t} was not updated (likely already completed).`;return f.info(n),{success:!0,data:{message:n,taskId:t,updated:!1,telemetryData:e?.telemetryData,tagInfo:e?.tagInfo}}}let i=`Successfully updated task with ID ${t} based on the prompt`;return f.info(i),{success:!0,data:{message:i,taskId:t,tasksPath:n,useResearch:p,updated:!0,updatedTask:e.updatedTask,telemetryData:e.telemetryData,tagInfo:e.tagInfo}}}catch(e){return f.error(`Error updating task by ID: ${e.message}`),{success:!1,error:{code:`UPDATE_TASK_CORE_ERROR`,message:e.message||`Unknown error updating task`}}}finally{!m&&w()&&S()}}catch(e){return f.error(`Setup error in updateTaskByIdDirect: ${e.message}`),w()&&S(),{success:!1,error:{code:`DIRECT_FUNCTION_SETUP_ERROR`,message:e.message||`Unknown setup error`}}}}async function sn(e,t,n={}){let{session:r}=n,{from:i,prompt:a,research:o,tasksJsonPath:s,projectRoot:c,tag:l}=e,u=Z(t);if(!c)return u.error(`updateTasksDirect requires a projectRoot argument.`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`projectRoot is required.`}};if(!i)return u.error(`updateTasksDirect called without from ID`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`Starting task ID (from) is required`}};if(!a)return u.error(`updateTasksDirect called without prompt`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`Update prompt is required`}};u.info(`Updating tasks via direct function. From: ${i}, Research: ${o}, File: ${s}, ProjectRoot: ${c}`),E();try{let e=await se(s,i,a,o,{session:r,mcpLog:u,projectRoot:c,tag:l},`json`);return e&&e.success&&Array.isArray(e.updatedTasks)?(u.success(`Successfully updated ${e.updatedTasks.length} tasks.`),{success:!0,data:{message:`Successfully updated ${e.updatedTasks.length} tasks.`,tasksPath:s,updatedCount:e.updatedTasks.length,telemetryData:e.telemetryData,tagInfo:e.tagInfo}}):(u.error(`Core updateTasks function did not return a successful structure.`),{success:!1,error:{code:`CORE_FUNCTION_ERROR`,message:e?.message||`Core function failed to update tasks or returned unexpected result.`}})}catch(e){return u.error(`Error executing core updateTasks: ${e.message}`),{success:!1,error:{code:`UPDATE_TASKS_CORE_ERROR`,message:e.message||`Unknown error updating tasks`}}}finally{S()}}async function cn(e,t,n={}){let{tasksJsonPath:r,name:i,projectRoot:a}=e,{session:o}=n;E();let s=Z(t);try{if(!r)return t.error(`useTagDirect called without tasksJsonPath`),S(),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};if(!i||typeof i!=`string`)return t.error(`Missing required parameter: name`),S(),{success:!1,error:{code:`MISSING_PARAMETER`,message:`Tag name is required and must be a string`}};t.info(`Switching to tag: ${i}`);let e=await Oe(r,i,{},{session:o,mcpLog:s,projectRoot:a},`json`);return S(),{success:!0,data:{tagName:e.currentTag,switched:e.switched,previousTag:e.previousTag,taskCount:e.taskCount,message:`Successfully switched to tag "${e.currentTag}"`}}}catch(e){return S(),t.error(`Error in useTagDirect: ${e.message}`),{success:!1,error:{code:e.code||`USE_TAG_ERROR`,message:e.message}}}}async function ln(e,t){let{tasksJsonPath:n,projectRoot:r,tag:i}=e;if(!n)return t.error(`validateDependenciesDirect called without tasksJsonPath`),{success:!1,error:{code:`MISSING_ARGUMENT`,message:`tasksJsonPath is required`}};try{t.info(`Validating dependencies in tasks: ${n}`);let e=n;if(!L.existsSync(e))return{success:!1,error:{code:`FILE_NOT_FOUND`,message:`Tasks file not found at ${e}`}};E();let a=await p(e,{context:{projectRoot:r,tag:i}});return S(),{success:!0,data:{message:a.valid?`No dependency problems`:`Found ${a.issues.length} dependency problem(s)`,...a,tasksPath:e}}}catch(e){return S(),t.error(`Error validating dependencies: ${e.message}`),{success:!1,error:{code:e instanceof b?e.code:`VALIDATION_ERROR`,message:e.message}}}}function un(e){e.addTool({name:`add_dependency`,description:`Add a dependency relationship between two tasks`,parameters:F.object({id:F.string().describe(`ID of task that will depend on another task`),dependsOn:F.string().describe(`ID of task that will become a dependency`),file:F.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Add Dependency`,destructiveHint:!0},execute:K(`add-dependency`,async(e,{log:t,session:n})=>{try{t.info(`Adding dependency for task ${e.id} to depend on ${e.dependsOn}`);let n=O({projectRoot:e.projectRoot,tag:e.tag}),r;try{r=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let i=await Tt({tasksJsonPath:r,id:e.id,dependsOn:e.dependsOn,projectRoot:e.projectRoot,tag:n},t);return i.success?t.info(`Successfully added dependency: ${i.data.message}`):t.error(`Failed to add dependency: ${i.error.message}`),U({result:i,log:t,errorPrefix:`Error adding dependency`,projectRoot:e.projectRoot,tag:n})}catch(e){return t.error(`Error in addDependency tool: ${e.message}`),H(e.message)}})})}function dn(e){e.addTool({name:`add_subtask`,description:`Add a subtask to an existing task`,parameters:F.object({id:F.string().describe(`Parent task ID (required)`),taskId:F.string().optional().describe(`Existing task ID to convert to subtask`),title:F.string().optional().describe(`Title for the new subtask (when creating a new subtask)`),description:F.string().optional().describe(`Description for the new subtask`),details:F.string().optional().describe(`Implementation details for the new subtask`),status:F.string().optional().describe(`Status for the new subtask (default: 'pending')`),dependencies:F.string().optional().describe(`Comma-separated list of dependency IDs for the new subtask`),file:F.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),skipGenerate:F.boolean().optional().describe(`Skip regenerating task files`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Add Subtask`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{let r=O({projectRoot:e.projectRoot,tag:e.tag});t.info(`Adding subtask with args: ${JSON.stringify(e)}`);let i;try{i=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let a=await Et({tasksJsonPath:i,id:e.id,taskId:e.taskId,title:e.title,description:e.description,details:e.details,status:e.status,dependencies:e.dependencies,skipGenerate:e.skipGenerate,projectRoot:e.projectRoot,tag:r},t,{session:n});return a.success?t.info(`Subtask added successfully: ${a.data.message}`):t.error(`Failed to add subtask: ${a.error.message}`),U({result:a,log:t,errorPrefix:`Error adding subtask`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in addSubtask tool: ${e.message}`),H(e.message)}})})}function fn(e){e.addTool({name:`add_tag`,description:`Create a new tag for organizing tasks in different contexts`,parameters:F.object({name:F.string().describe(`Name of the new tag to create`),copyFromCurrent:F.boolean().optional().describe(`Whether to copy tasks from the current tag (default: false)`),copyFromTag:F.string().optional().describe(`Specific tag to copy tasks from`),fromBranch:F.boolean().optional().describe(`Create tag name from current git branch (ignores name parameter)`),description:F.string().optional().describe(`Optional description for the tag`),file:F.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Add Tag`,destructiveHint:!1},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting add-tag with args: ${JSON.stringify(e)}`);let r;try{r=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}return U({result:await Nt({tasksJsonPath:r,name:e.name,copyFromCurrent:e.copyFromCurrent,copyFromTag:e.copyFromTag,fromBranch:e.fromBranch,description:e.description,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error creating tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in add-tag tool: ${e.message}`),H(e.message)}})})}function pn(e){e.addTool({name:`add_task`,description:`Add a new task using AI`,parameters:F.object({prompt:F.string().optional().describe(`Description of the task to add (required if not using manual fields)`),title:F.string().optional().describe(`Task title (for manual task creation)`),description:F.string().optional().describe(`Task description (for manual task creation)`),details:F.string().optional().describe(`Implementation details (for manual task creation)`),testStrategy:F.string().optional().describe(`Test strategy (for manual task creation)`),dependencies:F.string().optional().describe(`Comma-separated list of task IDs this task depends on`),priority:F.string().optional().describe(`Task priority (high, medium, low)`),file:F.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`),research:F.boolean().optional().describe(`Whether to use research capabilities for task creation`)}),annotations:{title:`Add Task`,destructiveHint:!1},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting add-task with args: ${JSON.stringify(e)}`);let r=O({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}return U({result:await Pt({tasksJsonPath:i,prompt:e.prompt,title:e.title,description:e.description,details:e.details,testStrategy:e.testStrategy,dependencies:e.dependencies,priority:e.priority,research:e.research,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error adding task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in add-task tool: ${e.message}`),H(e.message)}})})}function mn(e){e.addTool({name:`analyze_project_complexity`,description:`Analyze task complexity and generate expansion recommendations.`,parameters:F.object({threshold:F.coerce.number().int().min(1).max(10).optional().default(5).describe(`Complexity score threshold (1-10) to recommend expansion.`),research:F.boolean().optional().default(!1).describe(`Use Claude Code web research for research-backed analysis.`),output:F.string().optional().describe(`Output file path relative to project root (default: ${Se}).`),file:F.string().optional().describe(`Path to the tasks file relative to project root (default: tasks/tasks.json).`),ids:F.string().optional().describe(`Comma-separated list of task IDs to analyze specifically (e.g., "1,3,5").`),from:F.coerce.number().int().positive().optional().describe(`Starting task ID in a range to analyze.`),to:F.coerce.number().int().positive().optional().describe(`Ending task ID in a range to analyze.`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Analyze Project Complexity`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{let r=`analyze_project_complexity`;try{t.info(`Executing ${r} tool with args: ${JSON.stringify(e)}`);let i=O({projectRoot:e.projectRoot,tag:e.tag}),a;try{a=X({projectRoot:e.projectRoot,file:e.file},t),t.info(`${r}: Resolved tasks path: ${a}`)}catch(n){return t.error(`${r}: Error finding tasks.json: ${n.message}`),H(`Failed to find tasks.json within project root '${e.projectRoot}': ${n.message}`)}let o;try{o=e.output?J(e.projectRoot,e.output):k(null,{projectRoot:e.projectRoot,tag:i},t)}catch(e){return H(e.message)}t.info(`${r}: Report output path: ${o}`);let s=P.dirname(o);try{L.existsSync(s)||(L.mkdirSync(s,{recursive:!0}),t.info(`${r}: Created output directory: ${s}`))}catch(e){return t.error(`${r}: Failed to create output directory ${s}: ${e.message}`),H(`Failed to create output directory: ${e.message}`)}let c=await Ft({tasksJsonPath:a,outputPath:o,threshold:e.threshold,research:e.research,projectRoot:e.projectRoot,tag:i,ids:e.ids,from:e.from,to:e.to},t,{session:n});return t.info(`${r}: Direct function result: success=${c.success}`),U({result:c,log:t,errorPrefix:`Error analyzing task complexity`,projectRoot:e.projectRoot})}catch(e){return t.error(`Critical error in ${r} tool execute: ${e.message}`),H(`Internal tool error (${r}): ${e.message}`)}})})}function hn(e){e.addTool({name:`clear_subtasks`,description:`Clear subtasks from specified tasks`,parameters:F.object({id:F.string().optional().describe(`Task IDs (comma-separated) to clear subtasks from`),all:F.boolean().optional().describe(`Clear subtasks from all tasks`),file:F.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`)}).refine(e=>e.id||e.all,{message:`Either 'id' or 'all' parameter must be provided`,path:[`id`,`all`]}),annotations:{title:`Clear Subtasks`,destructiveHint:!0},execute:K(`clear-subtasks`,async(e,t)=>{try{t.log.info(`Clearing subtasks with args: ${JSON.stringify(e)}`);let n=O({projectRoot:e.projectRoot,tag:e.tag}),r;try{r=X({projectRoot:e.projectRoot,file:e.file},t.log)}catch(e){return t.log.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let i=await It({tasksJsonPath:r,id:e.id,all:e.all,projectRoot:e.projectRoot,tag:n},t.log,{session:t.session});return i.success?t.log.info(`Subtasks cleared successfully: ${i.data.message}`):t.log.error(`Failed to clear subtasks: ${i.error.message}`),U({result:i,log:t.log,errorPrefix:`Error clearing subtasks`,projectRoot:e.projectRoot})}catch(e){return t.log.error(`Error in clearSubtasks tool: ${e.message}`),H(e.message)}})})}function gn(e){e.addTool({name:`complexity_report`,description:`Display the complexity analysis report in a readable format`,parameters:F.object({file:F.string().optional().describe(`Path to the report file (default: ${Se})`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Complexity Report`,readOnlyHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Getting complexity report with args: ${JSON.stringify(e)}`);let n=he(e.projectRoot),r=jt({projectRoot:e.projectRoot,complexityReport:e.file,tag:n},t);if(t.info(`Reading complexity report from path: `,r),!r)return H(`No complexity report found. Run taskgraph analyze-complexity first.`);let i=await Lt({reportPath:r},t);return i.success?t.info(`Successfully retrieved complexity report`):t.error(`Failed to retrieve complexity report: ${i.error.message}`),U({result:i,log:t,errorPrefix:`Error retrieving complexity report`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in complexity-report tool: ${e.message}`),H(`Failed to retrieve complexity report: ${e.message}`)}})})}function _n(e){e.addTool({name:`copy_tag`,description:`Copy an existing tag to create a new tag with all tasks and metadata`,parameters:F.object({sourceName:F.string().describe(`Name of the source tag to copy from`),targetName:F.string().describe(`Name of the new tag to create`),description:F.string().optional().describe(`Optional description for the new tag`),file:F.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Copy Tag`,destructiveHint:!1},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting copy-tag with args: ${JSON.stringify(e)}`);let r;try{r=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}return U({result:await Rt({tasksJsonPath:r,sourceName:e.sourceName,targetName:e.targetName,description:e.description,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error copying tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in copy-tag tool: ${e.message}`),H(e.message)}})})}function vn(e){e.addTool({name:`delete_tag`,description:`Delete an existing tag and all its tasks`,parameters:F.object({name:F.string().describe(`Name of the tag to delete`),yes:F.boolean().optional().describe(`Skip confirmation prompts (default: true for MCP)`),file:F.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Delete Tag`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting delete-tag with args: ${JSON.stringify(e)}`);let r;try{r=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}return U({result:await zt({tasksJsonPath:r,name:e.name,yes:e.yes===void 0||e.yes,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error deleting tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in delete-tag tool: ${e.message}`),H(e.message)}})})}function yn(e){e.addTool({name:`expand_all`,description:`Expand all pending tasks into subtasks based on complexity or defaults`,parameters:F.object({num:F.string().optional().describe(`Target number of subtasks per task (uses complexity/defaults otherwise)`),research:F.boolean().optional().describe(`Enable research-backed subtask generation (web research via Claude Code)`),prompt:F.string().optional().describe(`Additional context to guide subtask generation for all tasks`),force:F.boolean().optional().describe(`Force regeneration of subtasks for tasks that already have them`),file:F.string().optional().describe(`Absolute path to the tasks file in the /tasks folder inside the project root (default: tasks/tasks.json)`),projectRoot:F.string().optional().describe(`Absolute path to the project root directory (derived from session if possible)`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Expand All Tasks`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Tool expand_all execution started with args: ${JSON.stringify(e)}`);let r=O({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=X({projectRoot:e.projectRoot,file:e.file},t),t.info(`Resolved tasks.json path: ${i}`)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let a=Mt(null,{projectRoot:e.projectRoot,tag:r},t);return t.info(`Using complexity report path: ${a}`),U({result:await Bt({tasksJsonPath:i,num:e.num,research:e.research,prompt:e.prompt,force:e.force,projectRoot:e.projectRoot,tag:r,complexityReportPath:a},t,{session:n}),log:t,errorPrefix:`Error expanding all tasks`,projectRoot:e.projectRoot})}catch(e){return t.error(`Unexpected error in expand_all tool execute: ${e.message}`),e.stack&&t.error(e.stack),H(`An unexpected error occurred: ${e.message}`)}})})}function bn(e){e.addTool({name:`expand_task`,description:`Expand a task into subtasks for detailed implementation`,parameters:F.object({id:F.string().describe(`ID of task to expand`),num:F.string().optional().describe(`Number of subtasks to generate`),research:F.boolean().optional().default(!1).describe(`Use research role for generation`),prompt:F.string().optional().describe(`Additional context for subtask generation`),file:F.string().optional().describe(`Path to the tasks file relative to project root (e.g., tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),force:F.boolean().optional().default(!1).describe(`Force expansion even if subtasks exist`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Expand Task`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting expand-task with args: ${JSON.stringify(e)}`);let r=O({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let a=jt({...e,tag:r},t);return U({result:await Vt({tasksJsonPath:i,id:e.id,num:e.num,research:e.research,prompt:e.prompt,force:e.force,complexityReportPath:a,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error expanding task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in expand-task tool: ${e.message}`),H(e.message)}})})}function xn(e){e.addTool({name:`fix_dependencies`,description:`Fix invalid dependencies in tasks automatically`,parameters:F.object({file:F.string().optional().describe(`Absolute path to the 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`)}),annotations:{title:`Fix Dependencies`,destructiveHint:!0},execute:K(`fix-dependencies`,async(e,t)=>{try{t.log.info(`Fixing dependencies with args: ${JSON.stringify(e)}`);let n=O({projectRoot:e.projectRoot,tag:e.tag}),r;try{r=X({projectRoot:e.projectRoot,file:e.file},t.log)}catch(e){return t.log.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let i=await Ht({tasksJsonPath:r,projectRoot:e.projectRoot,tag:n},t.log);return i.success?t.log.info(`Successfully fixed dependencies: ${i.data.message}`):t.log.error(`Failed to fix dependencies: ${i.error.message}`),U({result:i,log:t.log,errorPrefix:`Error fixing dependencies`,projectRoot:e.projectRoot})}catch(e){return t.log.error(`Error in fixDependencies tool: ${e.message}`),H(e.message)}})})}function Sn(e){e.addTool({name:`initialize_project`,description:`Initializes a new TaskGraph project structure by calling the core initialization logic. Creates necessary folders and configuration files for TaskGraph in the current directory.`,parameters:F.object({skipInstall:F.boolean().optional().default(!1).describe(`Skip installing dependencies automatically. Never do this unless you are sure the project is already installed.`),addAliases:F.boolean().optional().default(!0).describe(`Add shell aliases (tm, taskgraph) to shell config file.`),initGit:F.boolean().optional().default(!0).describe(`Initialize Git repository in project root.`),storeTasksInGit:F.boolean().optional().default(!0).describe(`Store tasks in Git (tasks.json and tasks/ directory).`),yes:F.boolean().optional().default(!0).describe(`Skip prompts and use default values. Always set to true for MCP tools.`),projectRoot:F.string().describe(`The root directory for the project. ALWAYS SET THIS TO THE PROJECT ROOT DIRECTORY. IF NOT SET, THE TOOL WILL NOT WORK.`),rules:F.array(F.enum(A)).optional().describe(`List of rule profiles to include at initialization. If omitted, defaults to the Claude profile. Available options: ${A.join(`, `)}`)}),annotations:{title:`Initialize Project`,destructiveHint:!0},execute:G(async(e,t)=>{let{log:n}=t,r=t.session;try{return n.info(`Executing initialize_project tool with args: ${JSON.stringify(e)}`),U({result:await Ut(e,n,{session:r}),log:n,errorPrefix:`Initialization failed`,projectRoot:e.projectRoot})}catch(e){let t=`Project initialization tool failed: ${e.message||`Unknown error`}`;return n.error(t,e),H(t,{details:e.stack})}})})}function Cn(e){e.addTool({name:`list_tags`,description:`List all available tags with task counts and metadata`,parameters:F.object({showMetadata:F.boolean().optional().describe(`Whether to include metadata in the output (default: false)`),file:F.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`List Tags`,readOnlyHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting list-tags with args: ${JSON.stringify(e)}`);let r;try{r=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}return U({result:await Wt({tasksJsonPath:r,showMetadata:e.showMetadata,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error listing tags`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in list-tags tool: ${e.message}`),H(e.message)}})})}function wn(e){e.addTool({name:`models`,description:`Get information about available AI models or set model configurations. TaskGraph uses Claude Code (models: opus, sonnet, haiku). Run without arguments to get the current model configuration.`,parameters:F.object({setMain:F.string().optional().describe(`Set the primary model for task generation/updates. One of: opus, sonnet, haiku.`),setResearch:F.string().optional().describe(`Set the model for research-backed operations. One of: opus, sonnet, haiku.`),setFallback:F.string().optional().describe(`Set the model to use if the primary fails. One of: opus, sonnet, haiku.`),listAvailableModels:F.boolean().optional().describe(`List all available models.`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Models`,destructiveHint:!0},execute:K(`models`,async(e,t)=>{try{return t.log.info(`Starting models tool with args: ${JSON.stringify(e)}`),U({result:await qt({...e,projectRoot:e.projectRoot},t.log,{session:t.session}),log:t.log,errorPrefix:`Error managing models`,projectRoot:e.projectRoot})}catch(e){return t.log.error(`Error in models tool: ${e.message}`),H(e.message)}})})}function Tn(e){e.addTool({name:`move_task`,description:`Move a task or subtask to a new position`,parameters:F.object({from:F.string().describe(`ID of the task/subtask to move (e.g., "5" or "5.2"). Can be comma-separated to move multiple tasks (e.g., "5,6,7")`),to:F.string().optional().describe(`ID of the destination (e.g., "7" or "7.3"). Required for within-tag moves. For cross-tag moves, if omitted, task will be moved to the target tag maintaining its ID`),file:F.string().optional().describe(`Custom path to tasks.json file`),projectRoot:F.string().describe(`Root directory of the project (typically derived from session)`),tag:F.string().optional().describe(`Tag context to operate on`),fromTag:F.string().optional().describe(`Source tag for cross-tag moves`),toTag:F.string().optional().describe(`Target tag for cross-tag moves`),withDependencies:F.boolean().optional().describe(`Move dependent tasks along with main task`),ignoreDependencies:F.boolean().optional().describe(`Break cross-tag dependencies during move`)}),annotations:{title:`Move Task`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{if(e.fromTag&&e.toTag&&e.fromTag!==e.toTag){if(!e.from)return H(`Source IDs are required for cross-tag moves`,`MISSING_SOURCE_IDS`);e.to&&t.warn(`The "to" parameter is not used for cross-tag moves and will be ignored. Tasks retain their original IDs in the target tag.`);let r=e.file;return r||=X(e,t),U({result:await Jt({sourceIds:e.from,sourceTag:e.fromTag,targetTag:e.toTag,withDependencies:e.withDependencies||!1,ignoreDependencies:e.ignoreDependencies||!1,tasksJsonPath:r,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error moving tasks between tags`,projectRoot:e.projectRoot})}{if(!e.to)return H(`Destination ID is required for within-tag moves`,`MISSING_DESTINATION_ID`);let r=O({projectRoot:e.projectRoot,tag:e.tag}),i=e.file;i||=X(e,t);let a=e.from.split(`,`).map(e=>e.trim()),o=e.to.split(`,`).map(e=>e.trim());if(a.length!==o.length){if(a.length>1){let s=[],c=[];for(let l=0;l<a.length;l++){let u=a[l],d=o[l];if(u===d){t.info(`Skipping ${u} -> ${d} (same ID)`),c.push({fromId:u,toId:d,reason:`same ID`});continue}let f=l===a.length-1,p=await Q({sourceId:u,destinationId:d,tasksJsonPath:i,projectRoot:e.projectRoot,tag:r,generateFiles:f},t,{session:n});p.success?s.push(p.data):t.error(`Failed to move ${u} to ${d}: ${p.error.message}`)}return U({result:{success:!0,data:{moves:s,skipped:c.length>0?c:void 0,message:`Successfully moved ${s.length} tasks${c.length>0?`, skipped ${c.length}`:``}`}},log:t,errorPrefix:`Error moving multiple tasks`,projectRoot:e.projectRoot})}return U({result:{success:!0,data:{moves:results,skippedMoves,message:`Successfully moved ${results.length} tasks${skippedMoves.length>0?`, skipped ${skippedMoves.length} moves`:``}`}},log:t,errorPrefix:`Error moving multiple tasks`,projectRoot:e.projectRoot})}return U({result:await Q({sourceId:e.from,destinationId:e.to,tasksJsonPath:i,projectRoot:e.projectRoot,tag:r,generateFiles:!0},t,{session:n}),log:t,errorPrefix:`Error moving task`,projectRoot:e.projectRoot})}}catch(e){return H(`Failed to move task: ${e.message}`,`MOVE_TASK_ERROR`)}})})}function En(e){e.addTool({name:`next_task`,description:`Find the next task to work on based on dependencies and status`,parameters:F.object({file:F.string().optional().describe(`Absolute path to the tasks file`),complexityReport:F.string().optional().describe(`Path to the complexity report file (relative to project root or absolute)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Next Task`,readOnlyHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Finding next task with args: ${JSON.stringify(e)}`);let r=O({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=Dt(e,n)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let a;try{a=kt({...e,tag:r},n)}catch(e){t.error(`Error finding complexity report: ${e.message}`),a=null}let o=await Yt({tasksJsonPath:i,reportPath:a,projectRoot:e.projectRoot,tag:r},t,{session:n});return t.info(`Next task result: ${o.success?`found`:`none`}`),U({result:o,log:t,errorPrefix:`Error finding next task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error finding next task: ${e.message}`),H(e.message)}})})}function Dn(e){e.addTool({name:`parse_prd`,description:`Parse a Product Requirements Document (PRD) text file to automatically generate initial tasks. Reinitializing the project is not necessary to run this tool. It is recommended to run parse-prd after initializing the project and creating/importing a prd.txt file in the project root's ${me} directory.`,parameters:F.object({input:F.string().optional().default(pe).describe(`Absolute path to the PRD document file (.txt, .md, etc.)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`),output:F.string().optional().describe(`Output path for tasks.json file (default: ${ve})`),numTasks:F.string().optional().describe(`Approximate number of top-level tasks to generate (default: 10). As the agent, if you have enough information, ensure to enter a number of tasks that would logically scale with project complexity. Setting to 0 will allow TaskGraph to determine the appropriate number of tasks based on the complexity of the PRD. Avoid entering numbers above 50 due to context window limitations.`),force:F.boolean().optional().default(!1).describe(`Overwrite existing output file without prompting.`),research:F.boolean().optional().describe(`Enable TaskGraph to use the research role for potentially more informed task generation. Requires appropriate API key.`),append:F.boolean().optional().describe(`Append generated tasks to existing file.`)}),annotations:{title:`Parse PRD`,destructiveHint:!0},execute:G(async(e,{log:t,session:n,reportProgress:r})=>{try{let i=O({projectRoot:e.projectRoot,tag:e.tag}),a=We(r,t);return U({result:await Xt({...e,tag:i},t,{session:n,reportProgress:a}),log:t,errorPrefix:`Error parsing PRD`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in parse_prd: ${e.message}`),H(`Failed to parse PRD: ${e.message}`)}})})}function On(e){e.addTool({name:`remove_dependency`,description:`Remove a dependency from a task`,parameters:F.object({id:F.string().describe(`Task ID to remove dependency from`),dependsOn:F.string().describe(`Task ID to remove as a dependency`),file:F.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Remove Dependency`,destructiveHint:!0},execute:K(`remove-dependency`,async(e,t)=>{try{let n=O({projectRoot:e.projectRoot,tag:e.tag});t.log.info(`Removing dependency for task ${e.id} from ${e.dependsOn} with args: ${JSON.stringify(e)}`);let r;try{r=X({projectRoot:e.projectRoot,file:e.file},t.log)}catch(e){return t.log.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let i=await Zt({tasksJsonPath:r,id:e.id,dependsOn:e.dependsOn,projectRoot:e.projectRoot,tag:n},t.log);return i.success?t.log.info(`Successfully removed dependency: ${i.data.message}`):t.log.error(`Failed to remove dependency: ${i.error.message}`),U({result:i,log:t.log,errorPrefix:`Error removing dependency`,projectRoot:e.projectRoot})}catch(e){return t.log.error(`Error in removeDependency tool: ${e.message}`),H(e.message)}})})}function kn(e){e.addTool({name:`remove_subtask`,description:`Remove a subtask from its parent task`,parameters:F.object({id:F.string().describe(`Subtask ID to remove in format 'parentId.subtaskId' (required)`),convert:F.boolean().optional().describe(`Convert the subtask to a standalone task instead of deleting it`),file:F.string().optional().describe(`Absolute path to the tasks file (default: tasks/tasks.json)`),skipGenerate:F.boolean().optional().describe(`Skip regenerating task files`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Remove Subtask`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{let r=O({projectRoot:e.projectRoot,tag:e.tag});t.info(`Removing subtask with args: ${JSON.stringify(e)}`);let i;try{i=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let a=await Qt({tasksJsonPath:i,id:e.id,convert:e.convert,skipGenerate:e.skipGenerate,projectRoot:e.projectRoot,tag:r},t,{session:n});return a.success?t.info(`Subtask removed successfully: ${a.data.message}`):t.error(`Failed to remove subtask: ${a.error.message}`),U({result:a,log:t,errorPrefix:`Error removing subtask`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in removeSubtask tool: ${e.message}`),H(e.message)}})})}function An(e){e.addTool({name:`remove_task`,description:`Remove a task or subtask permanently from the tasks list`,parameters:F.object({id:F.string().describe(`ID of the task or subtask to remove (e.g., '5' or '5.2'). Can be comma-separated to update multiple tasks/subtasks at once.`),file:F.string().optional().describe(`Absolute path to the tasks file`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),confirm:F.boolean().optional().describe(`Whether to skip confirmation prompt (default: false)`),tag:F.string().optional().describe(`Specify which tag context to operate on. Defaults to the current active tag.`)}),annotations:{title:`Remove Task`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Removing task(s) with ID(s): ${e.id}`);let r=O({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}t.info(`Using tasks file path: ${i}`);let a=await $t({tasksJsonPath:i,id:e.id,projectRoot:e.projectRoot,tag:r},t,{session:n});return a.success?t.info(`Successfully removed task: ${e.id}`):t.error(`Failed to remove task: ${a.error.message}`),U({result:a,log:t,errorPrefix:`Error removing task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in remove-task tool: ${e.message}`),H(`Failed to remove task: ${e.message}`)}})})}function jn(e){e.addTool({name:`rename_tag`,description:`Rename an existing tag`,parameters:F.object({oldName:F.string().describe(`Current name of the tag to rename`),newName:F.string().describe(`New name for the tag`),file:F.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Rename Tag`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting rename-tag with args: ${JSON.stringify(e)}`);let r;try{r=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}return U({result:await en({tasksJsonPath:r,oldName:e.oldName,newName:e.newName,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error renaming tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in rename-tag tool: ${e.message}`),H(e.message)}})})}function Mn(e){e.addTool({name:`research`,description:`Perform AI-powered research queries with project context`,parameters:F.object({query:F.string().describe(`Research query/prompt (required)`),taskIds:F.string().optional().describe(`Comma-separated list of task/subtask IDs for context (e.g., "15,16.2,17")`),filePaths:F.string().optional().describe(`Comma-separated list of file paths for context (e.g., "src/api.js,docs/readme.md")`),customContext:F.string().optional().describe(`Additional custom context text to include in the research`),includeProjectTree:F.boolean().optional().describe(`Include project file tree structure in context (default: false)`),detailLevel:F.enum([`low`,`medium`,`high`]).optional().describe(`Detail level for the research response (default: medium)`),saveTo:F.string().optional().describe(`Automatically save research results to specified task/subtask ID (e.g., "15" or "15.2")`),saveToFile:F.boolean().optional().describe(`Save research results to .taskgraph/docs/research/ directory (default: false)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Research`,destructiveHint:!0,openWorldHint:!0},execute:G(async(e,{log:t,session:n})=>{try{let r=O({projectRoot:e.projectRoot,tag:e.tag});return t.info(`Starting research with query: "${e.query.substring(0,100)}${e.query.length>100?`...`:``}"`),U({result:await tn({query:e.query,taskIds:e.taskIds,filePaths:e.filePaths,customContext:e.customContext,includeProjectTree:e.includeProjectTree||!1,detailLevel:e.detailLevel||`medium`,saveTo:e.saveTo,saveToFile:e.saveToFile||!1,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error performing research`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in research tool: ${e.message}`),H(e.message)}})})}async function Nn(e,t,n={}){let{projectRoot:r,language:i}=e,a=Z(t);t.info(`Executing response-language_direct with args: ${JSON.stringify(e)}`),t.info(`Using project root: ${r}`);try{return E(),Ie(i,{mcpLog:a,projectRoot:r})}catch(e){return{success:!1,error:{code:`DIRECT_FUNCTION_ERROR`,message:e.message,details:e.stack}}}finally{S()}}function Pn(e){e.addTool({name:`response-language`,description:`Get or set the response language for the project`,parameters:F.object({projectRoot:F.string().describe(`The root directory for the project. ALWAYS SET THIS TO THE PROJECT ROOT DIRECTORY. IF NOT SET, THE TOOL WILL NOT WORK.`),language:F.string().describe(`The new response language to set. like "中文" "English" or "español".`)}),annotations:{title:`Response Language`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{return t.info(`Executing response-language tool with args: ${JSON.stringify(e)}`),U({result:await Nn({...e,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error setting response language`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in response-language tool: ${e.message}`),H(e.message)}})})}function Fn(e){e.addTool({name:`scope_down_task`,description:`Decrease the complexity of one or more tasks using AI`,parameters:F.object({id:F.string().describe(`Comma-separated list of task IDs to scope down (e.g., "1,3,5")`),strength:F.string().optional().describe(`Strength level: light, regular, or heavy (default: regular)`),prompt:F.string().optional().describe(`Custom prompt for specific scoping adjustments`),file:F.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`),research:F.boolean().optional().describe(`Whether to use research capabilities for scoping`)}),annotations:{title:`Scope Down Task`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting scope-down with args: ${JSON.stringify(e)}`);let r=O({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}return U({result:await nn({tasksJsonPath:i,id:e.id,strength:e.strength,prompt:e.prompt,research:e.research,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error scoping down task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in scope-down tool: ${e.message}`),H(e.message)}})})}function In(e){e.addTool({name:`scope_up_task`,description:`Increase the complexity of one or more tasks using AI`,parameters:F.object({id:F.string().describe(`Comma-separated list of task IDs to scope up (e.g., "1,3,5")`),strength:F.string().optional().describe(`Strength level: light, regular, or heavy (default: regular)`),prompt:F.string().optional().describe(`Custom prompt for specific scoping adjustments`),file:F.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`),tag:F.string().optional().describe(`Tag context to operate on`),research:F.boolean().optional().describe(`Whether to use research capabilities for scoping`)}),annotations:{title:`Scope Up Task`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting scope-up with args: ${JSON.stringify(e)}`);let r=O({projectRoot:e.projectRoot,tag:e.tag}),i;try{i=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}return U({result:await rn({tasksJsonPath:i,id:e.id,strength:e.strength,prompt:e.prompt,research:e.research,projectRoot:e.projectRoot,tag:r},t,{session:n}),log:t,errorPrefix:`Error scoping up task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in scope-up tool: ${e.message}`),H(e.message)}})})}function Ln(e){e.addTool({name:`update`,description:`Update multiple upcoming tasks (with ID >= 'from' ID) based on new context or changes provided in the prompt. Use 'update_task' instead for a single specific task or 'update_subtask' for subtasks.`,parameters:F.object({from:F.string().describe(`Task ID from which to start updating (inclusive). IMPORTANT: This tool uses 'from', not 'id'`),prompt:F.string().describe(`Explanation of changes or new context to apply`),research:F.boolean().optional().describe(`Use Claude Code web research for research-backed updates`),file:F.string().optional().describe(`Path to the tasks file relative to project root`),projectRoot:F.string().optional().describe(`The directory of the project. (Optional, usually from session)`),tag:F.string().optional().describe(`Tag context to operate on`)}),annotations:{title:`Update Tasks`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{let r=`update`,{from:i,prompt:a,research:o,file:s,projectRoot:c,tag:l}=e,u=O({projectRoot:e.projectRoot,tag:e.tag});try{t.info(`Executing ${r} tool with normalized root: ${c}`);let l;try{l=X({projectRoot:c,file:s},t),t.info(`${r}: Resolved tasks path: ${l}`)}catch(e){return t.error(`${r}: Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json within project root '${c}': ${e.message}`)}let d=await sn({tasksJsonPath:l,from:i,prompt:a,research:o,projectRoot:c,tag:u},t,{session:n});return t.info(`${r}: Direct function result: success=${d.success}`),U({result:d,log:t,errorPrefix:`Error updating tasks`,projectRoot:e.projectRoot})}catch(e){return t.error(`Critical error in ${r} tool execute: ${e.message}`),H(`Internal tool error (${r}): ${e.message}`)}})})}function Rn(e){e.addTool({name:`update_subtask`,description:`Appends timestamped information to a specific subtask without replacing existing content. If you just want to update the subtask status, use set_task_status instead.`,parameters:F.object({id:s.describe(`ID of the subtask to update in format "parentId.subtaskId" (e.g., "5.2"). Parent ID is the ID of the task that contains the subtask.`),prompt:F.string().optional().describe(`Information to add to the subtask. Required unless only updating metadata.`),research:F.boolean().optional().describe(`Use Claude Code web research for research-backed updates`),metadata:F.string().optional().describe(`JSON string of metadata to merge into subtask metadata. Example: '{"ticketId": "JIRA-456", "reviewed": true}'. Requires TASKGRAPH_ALLOW_METADATA_UPDATES=true in MCP environment.`),file:F.string().optional().describe(`Absolute path to the 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`)}),annotations:{title:`Update Subtask`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{let r=`update_subtask`;try{let i=O({projectRoot:e.projectRoot,tag:e.tag});t.info(`Updating subtask with args: ${JSON.stringify(e)}`);let a;try{a=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`${r}: Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let o=q(e.metadata,H);if(o.error)return o.error;let s=o.parsedMetadata;if(!e.prompt&&!s)return H(`Either prompt or metadata must be provided for update-subtask`);let c=await an({tasksJsonPath:a,id:e.id,prompt:e.prompt,research:e.research,metadata:s,projectRoot:e.projectRoot,tag:i},t,{session:n});return c.success?t.info(`Successfully updated subtask with ID ${e.id}`):t.error(`Failed to update subtask: ${c.error?.message||`Unknown error`}`),U({result:c,log:t,errorPrefix:`Error updating subtask`,projectRoot:e.projectRoot})}catch(e){return t.error(`Critical error in ${r} tool execute: ${e.message}`),H(`Internal tool error (${r}): ${e.message}`)}})})}function zn(e){e.addTool({name:`update_task`,description:`Updates a single task by ID with new information or context provided in the prompt.`,parameters:F.object({id:F.string().describe(`ID of the task (e.g., '15') to update. Subtasks are supported using the update-subtask tool.`),prompt:F.string().optional().describe(`New information or context to incorporate into the task. Required unless only updating metadata.`),research:F.boolean().optional().describe(`Use Claude Code web research for research-backed updates`),append:F.boolean().optional().describe(`Append timestamped information to task details instead of full update`),metadata:F.string().optional().describe(`JSON string of metadata to merge into task metadata. Example: '{"githubIssue": 42, "sprint": "Q1-S3"}'. Requires TASKGRAPH_ALLOW_METADATA_UPDATES=true in MCP environment.`),file:F.string().optional().describe(`Absolute path to the 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`)}),annotations:{title:`Update Task`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{let r=`update_task`;try{let i=O({projectRoot:e.projectRoot,tag:e.tag});t.info(`Executing ${r} tool with args: ${JSON.stringify(e)}`);let a;try{a=X({projectRoot:e.projectRoot,file:e.file},t),t.info(`${r}: Resolved tasks path: ${a}`)}catch(e){return t.error(`${r}: Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let o=q(e.metadata,H);if(o.error)return o.error;let s=o.parsedMetadata;if(!e.prompt&&!s)return H(`Either prompt or metadata must be provided for update-task`);let c=await on({tasksJsonPath:a,id:e.id,prompt:e.prompt,research:e.research,append:e.append,metadata:s,projectRoot:e.projectRoot,tag:i},t,{session:n});return t.info(`${r}: Direct function result: success=${c.success}`),U({result:c,log:t,errorPrefix:`Error updating task`,projectRoot:e.projectRoot})}catch(e){return t.error(`Critical error in ${r} tool execute: ${e.message}`),H(`Internal tool error (${r}): ${e.message}`)}})})}function Bn(e){e.addTool({name:`use_tag`,description:`Switch to a different tag context for task operations`,parameters:F.object({name:F.string().describe(`Name of the tag to switch to`),file:F.string().optional().describe(`Path to the tasks file (default: tasks/tasks.json)`),projectRoot:F.string().describe(`The directory of the project. Must be an absolute path.`)}),annotations:{title:`Use Tag`,destructiveHint:!0},execute:G(async(e,{log:t,session:n})=>{try{t.info(`Starting use-tag with args: ${JSON.stringify(e)}`);let r;try{r=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}return U({result:await cn({tasksJsonPath:r,name:e.name,projectRoot:e.projectRoot},t,{session:n}),log:t,errorPrefix:`Error switching tag`,projectRoot:e.projectRoot})}catch(e){return t.error(`Error in use-tag tool: ${e.message}`),H(e.message)}})})}function Vn(e){e.addTool({name:`validate_dependencies`,description:`Check tasks for dependency issues (like circular references or links to non-existent tasks) without making changes.`,parameters:F.object({file:F.string().optional().describe(`Absolute path to the 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`)}),annotations:{title:`Validate Dependencies`,readOnlyHint:!0},execute:K(`validate-dependencies`,async(e,{log:t,session:n})=>{try{let n=O({projectRoot:e.projectRoot,tag:e.tag});t.info(`Validating dependencies with args: ${JSON.stringify(e)}`);let r;try{r=X({projectRoot:e.projectRoot,file:e.file},t)}catch(e){return t.error(`Error finding tasks.json: ${e.message}`),H(`Failed to find tasks.json: ${e.message}`)}let i=await ln({tasksJsonPath:r,projectRoot:e.projectRoot,tag:n},t);return i.success?t.info(`Successfully validated dependencies: ${i.data.message}`):t.error(`Failed to validate dependencies: ${i.error.message}`),U({result:i,log:t,errorPrefix:`Error validating dependencies`,projectRoot:e.projectRoot,tag:n})}catch(e){return t.error(`Error in validateDependencies tool: ${e.message}`),H(e.message)}})})}const $={initialize_project:Sn,models:wn,parse_prd:Dn,"response-language":Pn,analyze_project_complexity:mn,expand_task:bn,expand_all:yn,scope_up_task:In,scope_down_task:Fn,get_tasks:vt,get_task:bt,next_task:En,complexity_report:gn,dependency_analysis:gt,set_task_status:wt,add_task:pn,add_subtask:dn,update:Ln,update_task:zn,update_subtask:Rn,remove_task:An,remove_subtask:kn,clear_subtasks:hn,move_task:Tn,add_dependency:un,remove_dependency:On,validate_dependencies:Vn,fix_dependencies:xn,list_tags:Cn,add_tag:fn,delete_tag:vn,use_tag:Bn,rename_tag:jn,copy_tag:_n,research:Mn,autopilot_start:Xe,autopilot_resume:Qe,autopilot_next:et,autopilot_status:nt,autopilot_complete:it,autopilot_commit:ot,autopilot_finalize:ct,autopilot_abort:ut,generate:St,github_status:ft,github_push:mt},Hn=[`get_tasks`,`next_task`,`get_task`,`set_task_status`,`update_subtask`,`parse_prd`,`expand_task`],Un=[...Hn,`initialize_project`,`analyze_project_complexity`,`expand_all`,`add_subtask`,`remove_task`,`add_task`,`complexity_report`,`dependency_analysis`];function Wn(e){return $[e]||null}function Gn(){let e=process.env.TASKGRAPH_TOOLS;if(!e||e.trim()===``)return V.debug(`No TASKGRAPH_TOOLS env var found, defaulting to "core"`),`core`;let t=e.trim();return V.debug(`TASKGRAPH_TOOLS env var: "${t}"`),t}function Kn(e,t=`core`){let n=He(e),r=[],i=[];try{let e=t.trim(),a=[],o=e.toLowerCase();switch(o){case`all`:a=Object.keys($),V.info(`Loading all available tools`);break;case`core`:case`lean`:a=Hn,V.info(`Loading core tools only`);break;case`standard`:a=Un,V.info(`Loading standard tools`);break;default:let t=e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0),n=/* @__PURE__ */ new Set,r=[],i={response_language:`response-language`};for(let e of t){let t=null,a=e.toLowerCase();if(i[a]){let e=i[a];for(let n of Object.keys($))if(n.toLowerCase()===e.toLowerCase()){t=n;break}}if(!t){for(let e of Object.keys($))if(e.toLowerCase()===a){t=e;break}}if(!t){let e=a.replace(/_/g,`-`);for(let n of Object.keys($))if(n.toLowerCase()===e){t=n;break}}if(!t){let e=a.replace(/-/g,`_`);for(let n of Object.keys($))if(n.toLowerCase()===e){t=n;break}}t?(n.add(t),V.debug(`Resolved tool "${e}" to "${t}"`)):(r.push(e),V.warn(`Unknown tool specified: "${e}"`))}a=Array.from(n),r.length>0&&V.warn(`Unknown tools: ${r.join(`, `)}`),a.length===0?(V.warn(`No valid tools found in custom list. Loading all tools as fallback.`),a=Object.keys($)):V.info(`Loading ${a.length} custom tools from list (${n.size} unique after normalization)`)}return V.info(`Registering ${a.length} MCP tools (mode: ${e})`),a.forEach(e=>{try{let t=Wn(e);t?(t(n),V.debug(`Registered tool: ${e}`),r.push(e)):(V.warn(`Tool ${e} not found in registry`),i.push(e))}catch(t){t.message&&t.message.includes(`already registered`)?(V.debug(`Tool ${e} already registered, skipping`),r.push(e)):(V.error(`Failed to register tool ${e}: ${t.message}`),i.push(e))}}),V.info(`Successfully registered ${r.length}/${a.length} tools`),i.length>0&&V.warn(`Failed tools: ${i.join(`, `)}`),{registeredTools:r,failedTools:i,normalizedMode:o}}catch(e){V.error(`Error parsing TASKGRAPH_TOOLS environment variable: ${e.message}`),V.info(`Falling back to loading all tools`);let t=Object.keys($);for(let e of t){let t=Wn(e);if(t)try{t(n),r.push(e)}catch(t){t.message&&t.message.includes(`already registered`)?(V.debug(`Fallback tool ${e} already registered, skipping`),r.push(e)):(V.warn(`Failed to register fallback tool '${e}': ${t.message}`),i.push(e))}else V.warn(`Tool '${e}' not found in registry`),i.push(e)}return V.info(`Successfully registered ${r.length} fallback tools`),{registeredTools:r,failedTools:i,normalizedMode:`all`}}}I.config({quiet:!0});const qn=R(import.meta.url);P.dirname(qn);var Jn=class{constructor(){this.options={name:`TaskGraph MCP Server`,version:i};let e=new Re(this.options);this.server=e,this.initialized=!1,this.init=this.init.bind(this),this.start=this.start.bind(this),this.stop=this.stop.bind(this),this.logger=V}async init(){if(this.initialized)return;let e=Gn();this.logger.info(`TaskGraph MCP Server starting...`),this.logger.info(`Tool mode configuration: ${e}`);let t=Kn(this.server,e);return this.logger.info(`Normalized tool mode: ${t.normalizedMode}`),this.logger.info(`Registered ${t.registeredTools.length} tools successfully`),t.registeredTools.length>0&&this.logger.debug(`Registered tools: ${t.registeredTools.join(`, `)}`),t.failedTools.length>0&&this.logger.warn(`Failed to register ${t.failedTools.length} tools: ${t.failedTools.join(`, `)}`),this.initialized=!0,this}async start(){return this.initialized||await this.init(),this.server.on(`connect`,e=>{e.session.server.sendLoggingMessage({data:{context:e.session.context,message:`MCP Server connected: ${e.session.name}`},level:`info`})}),await this.server.start({transportType:`stdio`,timeout:12e4}),this}async stop(){this.server&&await this.server.stop()}};I.config({quiet:!0}),process.env.TASKGRAPH_MCP=`true`;async function Yn(){let e=new Jn;process.on(`SIGINT`,async()=>{await e.stop(),process.exit(0)}),process.on(`SIGTERM`,async()=>{await e.stop(),process.exit(0)});try{await e.start()}catch(e){V.error(`Failed to start MCP server: ${e.message}`),process.exit(1)}}Yn();export{};
|