taskgraph-ai 0.52.12 → 0.52.23
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-CigO4oTy.js +1 -0
- package/dist/ai-services-unified-kmQRPU0g.js +3 -0
- package/dist/commands-dFNugMWF.js +116 -0
- package/dist/config-manager-C5Ih13nA.js +1 -0
- package/dist/config-manager-DhVH8AQp.js +1 -0
- package/dist/dependency-manager-CCREovZA.js +758 -0
- package/dist/{init-Cp1ZIvlh.js → init-p_pWjmVE.js} +64 -67
- package/dist/mcp-server.js +2 -10
- package/dist/research-blv_5JOT.js +1 -0
- package/dist/response-language-D9UxmXBp.js +1 -0
- package/dist/response-language-ip84ug-k.js +1 -0
- package/dist/{src-BaM893RS.js → src-TZm8h0X-.js} +17 -17
- package/dist/src-yE1DeXKG.js +468 -0
- package/dist/tag-management-Br2FX-YC.js +1 -0
- package/dist/task-manager-DWPIhAB7.js +1 -0
- package/dist/taskgraph.js +1 -1
- package/package.json +5 -7
- package/dist/ai-services-unified-BuoDs5zU.js +0 -1
- package/dist/ai-services-unified-D8LfWQ4S.js +0 -3
- package/dist/commands-Brsl3ZyL.js +0 -210
- package/dist/config-manager-BxNrtquR.js +0 -1
- package/dist/config-manager-CkwCWw53.js +0 -1
- package/dist/dependency-manager-DRkIU6DR.js +0 -1283
- package/dist/research-Cf8YeyqJ.js +0 -1
- package/dist/response-language-BhegpO-l.js +0 -1
- package/dist/response-language-CvMcnuEd.js +0 -1
- package/dist/tag-management-DILdqQSS.js +0 -1
- package/dist/task-manager-L39eOUEz.js +0 -1
- package/dist/update-subtask-by-id-Dlk8IQru.js +0 -1
- package/dist/update-task-by-id-C1xnfWPp.js +0 -1
- package/dist/utils-CvXyXTNj.js +0 -1
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
import{i as e,n as t,r as n,t as r}from"./ai-services-unified-kmQRPU0g.js";import{d as i,y as a}from"./src-TZm8h0X-.js";import{$ as o,B as s,C as c,G as l,J as u,K as d,N as f,Q as p,V as m,W as h,X as g,Y as _,c as v,ct as y,dt as b,et as x,g as S,h as C,ht as w,l as T,lt as E,mt as D,nt as O,o as k,ot as A,p as j,pt as M,q as N,rt as P,st as F,tt as ee,u as I,ut as L,v as te,xt as ne,z as re}from"./config-manager-DhVH8AQp.js";import{A as R,B as ie,F as ae,I as oe,L as z,N as se,O as ce,P as le,R as ue,W as B,h as de,j as fe,k as pe,x as me,z as he}from"./src-yE1DeXKG.js";import"./response-language-ip84ug-k.js";import V from"chalk";import H from"path";import{z as U}from"zod";import W,*as ge from"fs";import _e from"readline";import ve from"gradient-string";import G from"boxen";import ye from"cli-table3";import be from"cli-progress";import xe from"inquirer";import Se from"fuse.js";import{APICallError as Ce}from"ai";import we from"ajv";import Te from"ajv-formats";import Ee from"gpt-tokens";import"@streamparser/json";const De=[`pending`,`done`,`in-progress`,`review`,`deferred`,`cancelled`];function Oe(e){return De.includes(e)}function ke(){return a||`unknown`}async function Ae(e,t,n=null,r=null,i=!1,a={}){let{projectRoot:s,tag:c}=a;try{o(`debug`,`Adding subtask to parent task ${t}...`);let i=P(e,s,c);if(!i||!i.tasks)throw Error(`Invalid or missing tasks file at ${e}`);let a=parseInt(t,10),l=i.tasks.find(e=>e.id===a);if(!l)throw Error(`Parent task with ID ${a} not found`);l.subtasks||=[];let u;if(n!==null){let e=parseInt(n,10),t=i.tasks.findIndex(t=>t.id===e);if(t===-1)throw Error(`Task with ID ${e} not found`);let r=i.tasks[t];if(r.parentTaskId)throw Error(`Task ${e} is already a subtask of task ${r.parentTaskId}`);if(e===a)throw Error(`Cannot make a task a subtask of itself`);if(xt(i.tasks,l,e))throw Error(`Cannot create circular dependency: task ${a} is already a subtask or dependent of task ${e}`);let s=(l.subtasks.length>0?Math.max(...l.subtasks.map(e=>e.id)):0)+1;u={...r,id:s,parentTaskId:a},l.subtasks.push(u),i.tasks.splice(t,1),o(`debug`,`Converted task ${e} to subtask ${a}.${s}`)}else if(r){let e=(l.subtasks.length>0?Math.max(...l.subtasks.map(e=>e.id)):0)+1;u={id:e,title:r.title,description:r.description||``,details:r.details||``,status:r.status||`pending`,dependencies:r.dependencies||[],parentTaskId:a},l.subtasks.push(u),o(`debug`,`Created new subtask ${a}.${e}`)}else throw Error(`Either existingTaskId or newSubtaskData must be provided`);return E(e,i,s,c),u}catch(e){throw o(`debug`,`Error adding subtask: ${e.message}`),e}}const je=[`high`,`medium`,`low`],Me=`medium`;function Ne(e){return je.includes(e?.toLowerCase())}function Pe(e){if(!e)return null;let t=e.toLowerCase();return Ne(t)?t:null}const Fe=U.object({title:U.string().describe(`Clear, concise title for the task`),description:U.string().describe(`A one or two sentence description of the task`),details:U.string().describe(`In-depth implementation details, considerations, and guidance`),testStrategy:U.string().describe(`Detailed approach for verifying task completion`),dependencies:U.array(U.number()).nullable().describe(`Array of task IDs that this task depends on (must be completed before this task can start)`)}).strict(),Ie=U.object({taskId:U.number().int().positive(),taskTitle:U.string(),complexityScore:U.number().min(1).max(10),recommendedSubtasks:U.number().int().nonnegative(),expansionPrompt:U.string(),reasoning:U.string()}).strict(),Le=U.object({complexityAnalysis:U.array(Ie)}).strict(),Re=U.enum([`pending`,`in-progress`,`blocked`,`done`,`cancelled`,`deferred`]),ze=U.object({id:U.number().int().positive(),title:U.string().min(1).max(200),description:U.string().min(1),status:Re,dependencies:U.array(U.union([U.number().int().positive(),U.string()])),priority:U.enum([`low`,`medium`,`high`,`critical`]).nullable(),details:U.string().nullable(),testStrategy:U.string().nullable()}).strict(),Be=U.object({id:U.number().int().positive(),title:U.string().min(5).max(200),description:U.string().min(10),dependencies:U.array(U.number().int().positive()),details:U.string().min(20),status:U.enum([`pending`,`done`,`completed`]),testStrategy:U.string().nullable()}).strict(),Ve=U.object({subtasks:U.array(Be)}).strict(),He=U.object({id:U.number().int().positive(),title:U.string().min(1),description:U.string().min(1),details:U.string().nullable(),testStrategy:U.string().nullable(),priority:U.enum([`high`,`medium`,`low`]).nullable(),dependencies:U.array(U.number().int().positive()).nullable(),status:U.string().nullable()}).strict(),Ue=U.object({tasks:U.array(He)}).strict(),We=U.object({subtask:Be}).strict(),Ge=ze.extend({subtasks:U.array(Be).nullable()}).strict(),Ke={"update-tasks":U.object({tasks:U.array(Ge)}).strict(),"expand-task":Ve,"analyze-complexity":Le,"update-subtask-by-id":We,"update-task-by-id":U.object({task:Ge}),"add-task":Fe,"parse-prd":Ue};var qe={id:`add-task`,version:`1.0.0`,description:`Generate a new task based on description`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`task-creation`,`generation`]},parameters:{prompt:{type:`string`,required:!0,description:`User's task description`},newTaskId:{type:`number`,required:!0,description:`ID for the new task`},existingTasks:{type:`array`,description:`List of existing tasks for context`},gatheredContext:{type:`string`,description:`Context gathered from codebase analysis`},contextFromArgs:{type:`string`,description:`Additional context from manual args`},priority:{type:`string`,default:`medium`,enum:[`high`,`medium`,`low`],description:`Task priority`},dependencies:{type:`array`,description:`Task dependency IDs`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema.
|
|
2
|
+
|
|
3
|
+
IMPORTANT: Your response MUST be a JSON object with the following structure (no wrapper property, just these fields directly):
|
|
4
|
+
{
|
|
5
|
+
"title": "string",
|
|
6
|
+
"description": "string",
|
|
7
|
+
"details": "string",
|
|
8
|
+
"testStrategy": "string",
|
|
9
|
+
"dependencies": [array of numbers]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
Do not include any other top-level properties. Do NOT wrap this in any additional object.
|
|
13
|
+
|
|
14
|
+
Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.
|
|
15
|
+
|
|
16
|
+
When determining dependencies for a new task, follow these principles:
|
|
17
|
+
1. Select dependencies based on logical requirements - what must be completed before this task can begin.
|
|
18
|
+
2. Prioritize task dependencies that are semantically related to the functionality being built.
|
|
19
|
+
3. Consider both direct dependencies (immediately prerequisite) and indirect dependencies.
|
|
20
|
+
4. Avoid adding unnecessary dependencies - only include tasks that are genuinely prerequisite.
|
|
21
|
+
5. Consider the current status of tasks - prefer completed tasks as dependencies when possible.
|
|
22
|
+
6. Pay special attention to foundation tasks (1-5) but don't automatically include them without reason.
|
|
23
|
+
7. Recent tasks (higher ID numbers) may be more relevant for newer functionality.
|
|
24
|
+
|
|
25
|
+
The dependencies array should contain task IDs (numbers) of prerequisite tasks.{{#if useResearch}}
|
|
26
|
+
|
|
27
|
+
Research current best practices and technologies relevant to this task.{{/if}}`,user:`{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required
|
|
28
|
+
|
|
29
|
+
You have access to powerful codebase analysis tools. Before generating the task:
|
|
30
|
+
|
|
31
|
+
1. Use the Glob tool to explore the project structure (e.g., "**/*.js", "**/*.json", "**/README.md")
|
|
32
|
+
2. Use the Grep tool to search for existing implementations, patterns, and technologies
|
|
33
|
+
3. Use the Read tool to examine key files like package.json, main entry points, and relevant source files
|
|
34
|
+
4. Analyze the current implementation to understand what already exists
|
|
35
|
+
|
|
36
|
+
Based on your analysis:
|
|
37
|
+
- Identify existing components/features that relate to this new task
|
|
38
|
+
- Understand the technology stack, frameworks, and patterns in use
|
|
39
|
+
- Generate implementation details that align with the project's current architecture
|
|
40
|
+
- Reference specific files, functions, or patterns from the codebase in your details
|
|
41
|
+
|
|
42
|
+
Project Root: {{projectRoot}}
|
|
43
|
+
|
|
44
|
+
{{/if}}You are generating the details for Task #{{newTaskId}}. Based on the user's request: "{{prompt}}", create a comprehensive new task for a software development project.
|
|
45
|
+
|
|
46
|
+
{{gatheredContext}}
|
|
47
|
+
|
|
48
|
+
{{#if useResearch}}Research current best practices, technologies, and implementation patterns relevant to this task. {{/if}}Based on the information about existing tasks provided above, include appropriate dependencies in the "dependencies" array. Only include task IDs that this new task directly depends on.
|
|
49
|
+
|
|
50
|
+
Return your answer as a single JSON object matching the schema precisely:
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
"title": "Task title goes here",
|
|
54
|
+
"description": "A concise one or two sentence description of what the task involves",
|
|
55
|
+
"details": "Detailed implementation steps, considerations, code examples, or technical approach",
|
|
56
|
+
"testStrategy": "Specific steps to verify correct implementation and functionality",
|
|
57
|
+
"dependencies": [1, 3] // Example: IDs of tasks that must be completed before this task
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Make sure the details and test strategy are comprehensive and specific{{#if useResearch}}, incorporating current best practices from your research{{/if}}. DO NOT include the task ID in the title.
|
|
61
|
+
{{#if contextFromArgs}}{{contextFromArgs}}{{/if}}`}}},Je={id:`analyze-complexity`,version:`1.0.0`,description:`Analyze task complexity and generate expansion recommendations`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`analysis`,`complexity`,`expansion`,`recommendations`]},parameters:{tasks:{type:`array`,required:!0,description:`Array of tasks to analyze`},gatheredContext:{type:`string`,default:``,description:`Additional project context`},threshold:{type:`number`,default:5,min:1,max:10,description:`Complexity threshold for expansion recommendation`},useResearch:{type:`boolean`,default:!1,description:`Use research mode for deeper analysis`},hasCodebaseAnalysis:{type:`boolean`,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an expert software architect and project manager analyzing task complexity. Your analysis should consider implementation effort, technical challenges, dependencies, and testing requirements.
|
|
62
|
+
|
|
63
|
+
IMPORTANT: For each task, provide an analysis object with ALL of the following fields:
|
|
64
|
+
- taskId: The ID of the task being analyzed (positive integer)
|
|
65
|
+
- taskTitle: The title of the task
|
|
66
|
+
- complexityScore: A score from 1-10 indicating complexity
|
|
67
|
+
- recommendedSubtasks: Number of subtasks recommended (non-negative integer; 0 if no expansion needed)
|
|
68
|
+
- expansionPrompt: A prompt to guide subtask generation
|
|
69
|
+
- reasoning: Your reasoning for the complexity score
|
|
70
|
+
|
|
71
|
+
Your response MUST be a JSON object with a single "complexityAnalysis" property containing an array of these analysis objects. You may optionally include a "metadata" object, but no other top-level properties.`,user:`{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required
|
|
72
|
+
|
|
73
|
+
You have access to powerful codebase analysis tools. Before analyzing task complexity:
|
|
74
|
+
|
|
75
|
+
1. Use the Glob tool to explore the project structure and understand the codebase size
|
|
76
|
+
2. Use the Grep tool to search for existing implementations related to each task
|
|
77
|
+
3. Use the Read tool to examine key files that would be affected by these tasks
|
|
78
|
+
4. Understand the current implementation state, patterns used, and technical debt
|
|
79
|
+
|
|
80
|
+
Based on your codebase analysis:
|
|
81
|
+
- Assess complexity based on ACTUAL code that needs to be modified/created
|
|
82
|
+
- Consider existing abstractions and patterns that could simplify implementation
|
|
83
|
+
- Identify tasks that require refactoring vs. greenfield development
|
|
84
|
+
- Factor in dependencies between existing code and new features
|
|
85
|
+
- Provide more accurate subtask recommendations based on real code structure
|
|
86
|
+
|
|
87
|
+
Project Root: {{projectRoot}}
|
|
88
|
+
|
|
89
|
+
{{/if}}Analyze the following tasks to determine their complexity (1-10 scale) and recommend the number of subtasks for expansion. Provide a brief reasoning and an initial expansion prompt for each.{{#if useResearch}} Consider current best practices, common implementation patterns, and industry standards in your analysis.{{/if}}
|
|
90
|
+
|
|
91
|
+
Tasks:
|
|
92
|
+
{{{json tasks}}}
|
|
93
|
+
{{#if gatheredContext}}
|
|
94
|
+
|
|
95
|
+
# Project Context
|
|
96
|
+
|
|
97
|
+
{{gatheredContext}}
|
|
98
|
+
{{/if}}
|
|
99
|
+
`}}},Ye={id:`expand-task`,version:`1.0.0`,description:`Break down a task into detailed subtasks`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`expansion`,`subtasks`,`breakdown`]},parameters:{subtaskCount:{type:`number`,required:!0,description:`Number of subtasks to generate`},task:{type:`object`,required:!0,description:`The task to expand`},nextSubtaskId:{type:`number`,required:!0,description:`Starting ID for new subtasks`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},expansionPrompt:{type:`string`,required:!1,description:`Expansion prompt from complexity report`},additionalContext:{type:`string`,required:!1,default:``,description:`Additional context for task expansion`},complexityReasoningContext:{type:`string`,required:!1,default:``,description:`Complexity analysis reasoning context`},gatheredContext:{type:`string`,required:!1,default:``,description:`Gathered project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{"complexity-report":{condition:`expansionPrompt`,system:`You are an AI assistant helping with task breakdown. Generate {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks based on the provided prompt and context.
|
|
100
|
+
|
|
101
|
+
IMPORTANT: Your response MUST be a JSON object with a "subtasks" property containing an array of subtask objects. Each subtask must include ALL of the following fields:
|
|
102
|
+
- id: MUST be sequential integers starting EXACTLY from {{nextSubtaskId}}. First subtask id={{nextSubtaskId}}, second id={{nextSubtaskId}}+1, etc. DO NOT use any other numbering pattern!
|
|
103
|
+
- title: A clear, actionable title (5-200 characters)
|
|
104
|
+
- description: A detailed description (minimum 10 characters)
|
|
105
|
+
- dependencies: An array of task IDs this subtask depends on (can be empty [])
|
|
106
|
+
- details: Implementation details (minimum 20 characters)
|
|
107
|
+
- status: Must be "pending" for new subtasks
|
|
108
|
+
- testStrategy: Testing approach (can be null)
|
|
109
|
+
|
|
110
|
+
You may optionally include a "metadata" object. Do not include any other top-level properties.`,user:`Break down the following task:
|
|
111
|
+
|
|
112
|
+
Parent Task:
|
|
113
|
+
ID: {{task.id}}
|
|
114
|
+
Title: {{task.title}}
|
|
115
|
+
Description: {{task.description}}
|
|
116
|
+
Current details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}
|
|
117
|
+
|
|
118
|
+
{{expansionPrompt}}{{#if additionalContext}}
|
|
119
|
+
|
|
120
|
+
{{additionalContext}}{{/if}}{{#if complexityReasoningContext}}
|
|
121
|
+
|
|
122
|
+
{{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}
|
|
123
|
+
|
|
124
|
+
# Project Context
|
|
125
|
+
|
|
126
|
+
{{gatheredContext}}{{/if}}
|
|
127
|
+
|
|
128
|
+
Generate {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks. CRITICAL: Use sequential IDs starting from {{nextSubtaskId}} (first={{nextSubtaskId}}, second={{nextSubtaskId}}+1, etc.).`},research:{condition:`useResearch === true && !expansionPrompt`,system:`You are an AI assistant with research capabilities analyzing and breaking down software development tasks.
|
|
129
|
+
|
|
130
|
+
IMPORTANT: Your response MUST be a JSON object with a "subtasks" property containing an array of subtask objects. Each subtask must include ALL of the following fields:
|
|
131
|
+
- id: MUST be sequential integers starting EXACTLY from {{nextSubtaskId}}. First subtask id={{nextSubtaskId}}, second id={{nextSubtaskId}}+1, etc. DO NOT use any other numbering pattern!
|
|
132
|
+
- title: A clear, actionable title (5-200 characters)
|
|
133
|
+
- description: A detailed description (minimum 10 characters)
|
|
134
|
+
- dependencies: An array of task IDs this subtask depends on (can be empty [])
|
|
135
|
+
- details: Implementation details (minimum 20 characters)
|
|
136
|
+
- status: Must be "pending" for new subtasks
|
|
137
|
+
- testStrategy: Testing approach (can be null)
|
|
138
|
+
|
|
139
|
+
You may optionally include a "metadata" object. Do not include any other top-level properties.`,user:`{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required
|
|
140
|
+
|
|
141
|
+
You have access to powerful codebase analysis tools. Before generating subtasks:
|
|
142
|
+
|
|
143
|
+
1. Use the Glob tool to explore relevant files for this task (e.g., "**/*.js", "src/**/*.ts")
|
|
144
|
+
2. Use the Grep tool to search for existing implementations related to this task
|
|
145
|
+
3. Use the Read tool to examine files that would be affected by this task
|
|
146
|
+
4. Understand the current implementation state and patterns used
|
|
147
|
+
|
|
148
|
+
Based on your analysis:
|
|
149
|
+
- Identify existing code that relates to this task
|
|
150
|
+
- Understand patterns and conventions to follow
|
|
151
|
+
- Generate subtasks that integrate smoothly with existing code
|
|
152
|
+
- Ensure subtasks are specific and actionable based on the actual codebase
|
|
153
|
+
|
|
154
|
+
Project Root: {{projectRoot}}
|
|
155
|
+
|
|
156
|
+
{{/if}}Analyze the following task and break it down into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks. Each subtask should be actionable and well-defined.
|
|
157
|
+
|
|
158
|
+
Parent Task:
|
|
159
|
+
ID: {{task.id}}
|
|
160
|
+
Title: {{task.title}}
|
|
161
|
+
Description: {{task.description}}
|
|
162
|
+
Current details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}
|
|
163
|
+
Consider this context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}
|
|
164
|
+
Complexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}
|
|
165
|
+
|
|
166
|
+
# Project Context
|
|
167
|
+
|
|
168
|
+
{{gatheredContext}}{{/if}}
|
|
169
|
+
|
|
170
|
+
CRITICAL: You MUST use sequential IDs starting from {{nextSubtaskId}}. The first subtask MUST have id={{nextSubtaskId}}, the second MUST have id={{nextSubtaskId}}+1, and so on. Do NOT use parent task ID in subtask numbering!`},default:{system:`You are an AI assistant helping with task breakdown for software development. Break down high-level tasks into specific, actionable subtasks that can be implemented sequentially.
|
|
171
|
+
|
|
172
|
+
IMPORTANT: Your response MUST be a JSON object with a "subtasks" property containing an array of subtask objects. Each subtask must include ALL of the following fields:
|
|
173
|
+
- id: MUST be sequential integers starting EXACTLY from {{nextSubtaskId}}. First subtask id={{nextSubtaskId}}, second id={{nextSubtaskId}}+1, etc. DO NOT use any other numbering pattern!
|
|
174
|
+
- title: A clear, actionable title (5-200 characters)
|
|
175
|
+
- description: A detailed description (minimum 10 characters)
|
|
176
|
+
- dependencies: An array of task IDs this subtask depends on (can be empty [])
|
|
177
|
+
- details: Implementation details (minimum 20 characters)
|
|
178
|
+
- status: Must be "pending" for new subtasks
|
|
179
|
+
- testStrategy: Testing approach (can be null)
|
|
180
|
+
|
|
181
|
+
You may optionally include a "metadata" object. Do not include any other top-level properties.`,user:`{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required
|
|
182
|
+
|
|
183
|
+
You have access to powerful codebase analysis tools. Before generating subtasks:
|
|
184
|
+
|
|
185
|
+
1. Use the Glob tool to explore relevant files for this task (e.g., "**/*.js", "src/**/*.ts")
|
|
186
|
+
2. Use the Grep tool to search for existing implementations related to this task
|
|
187
|
+
3. Use the Read tool to examine files that would be affected by this task
|
|
188
|
+
4. Understand the current implementation state and patterns used
|
|
189
|
+
|
|
190
|
+
Based on your analysis:
|
|
191
|
+
- Identify existing code that relates to this task
|
|
192
|
+
- Understand patterns and conventions to follow
|
|
193
|
+
- Generate subtasks that integrate smoothly with existing code
|
|
194
|
+
- Ensure subtasks are specific and actionable based on the actual codebase
|
|
195
|
+
|
|
196
|
+
Project Root: {{projectRoot}}
|
|
197
|
+
|
|
198
|
+
{{/if}}Break down this task into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks:
|
|
199
|
+
|
|
200
|
+
Task ID: {{task.id}}
|
|
201
|
+
Title: {{task.title}}
|
|
202
|
+
Description: {{task.description}}
|
|
203
|
+
Current details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}
|
|
204
|
+
Additional context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}
|
|
205
|
+
Complexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}
|
|
206
|
+
|
|
207
|
+
# Project Context
|
|
208
|
+
|
|
209
|
+
{{gatheredContext}}{{/if}}
|
|
210
|
+
|
|
211
|
+
CRITICAL: You MUST use sequential IDs starting from {{nextSubtaskId}}. The first subtask MUST have id={{nextSubtaskId}}, the second MUST have id={{nextSubtaskId}}+1, and so on. Do NOT use parent task ID in subtask numbering!`}}},Xe={id:`parse-prd`,version:`1.0.0`,description:`Parse a Product Requirements Document into structured tasks`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`prd`,`parsing`,`initialization`]},parameters:{numTasks:{type:`number`,required:!0,description:`Target number of tasks to generate`},nextId:{type:`number`,required:!0,description:`Starting ID for tasks`},research:{type:`boolean`,default:!1,description:`Enable research mode for latest best practices`},prdContent:{type:`string`,required:!0,description:`Content of the PRD file`},prdPath:{type:`string`,required:!0,description:`Path to the PRD file`},defaultTaskPriority:{type:`string`,required:!1,default:`medium`,enum:[`high`,`medium`,`low`],description:`Default priority for generated tasks`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant specialized in analyzing Product Requirements Documents (PRDs) and generating a structured, logically ordered, dependency-aware and sequenced list of development tasks in JSON format.{{#if research}}
|
|
212
|
+
Before breaking down the PRD into tasks, you will:
|
|
213
|
+
1. Research and analyze the latest technologies, libraries, frameworks, and best practices that would be appropriate for this project
|
|
214
|
+
2. Identify any potential technical challenges, security concerns, or scalability issues not explicitly mentioned in the PRD without discarding any explicit requirements or going overboard with complexity -- always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches
|
|
215
|
+
3. Consider current industry standards and evolving trends relevant to this project (this step aims to solve LLM hallucinations and out of date information due to training data cutoff dates)
|
|
216
|
+
4. Evaluate alternative implementation approaches and recommend the most efficient path
|
|
217
|
+
5. Include specific library versions, helpful APIs, and concrete implementation guidance based on your research
|
|
218
|
+
6. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches
|
|
219
|
+
|
|
220
|
+
Your task breakdown should incorporate this research, resulting in more detailed implementation guidance, more accurate dependency mapping, and more precise technology recommendations than would be possible from the PRD text alone, while maintaining all explicit requirements and best practices and all details and nuances of the PRD.{{/if}}
|
|
221
|
+
|
|
222
|
+
Analyze the provided PRD content and generate {{#if (gt numTasks 0)}}approximately {{numTasks}}{{else}}an appropriate number of{{/if}} top-level development tasks. If the complexity or the level of detail of the PRD is high, generate more tasks relative to the complexity of the PRD
|
|
223
|
+
Each task should represent a logical unit of work needed to implement the requirements and focus on the most direct and effective way to implement the requirements without unnecessary complexity or overengineering. Include pseudo-code, implementation details, and test strategy for each task. Find the most up to date information to implement each task.
|
|
224
|
+
Assign sequential IDs starting from {{nextId}}. Infer title, description, details, and test strategy for each task based *only* on the PRD content.
|
|
225
|
+
Set status to 'pending', dependencies to an empty array [], and priority to '{{defaultTaskPriority}}' initially for all tasks.
|
|
226
|
+
Generate a response containing a single key "tasks", where the value is an array of task objects adhering to the provided schema.
|
|
227
|
+
|
|
228
|
+
Each task should follow this JSON structure:
|
|
229
|
+
{
|
|
230
|
+
"id": number,
|
|
231
|
+
"title": string,
|
|
232
|
+
"description": string,
|
|
233
|
+
"status": "pending",
|
|
234
|
+
"dependencies": number[] (IDs of tasks this depends on),
|
|
235
|
+
"priority": "high" | "medium" | "low",
|
|
236
|
+
"details": string (implementation details),
|
|
237
|
+
"testStrategy": string (validation approach)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
Guidelines:
|
|
241
|
+
1. {{#if (gt numTasks 0)}}Unless complexity warrants otherwise{{else}}Depending on the complexity{{/if}}, create {{#if (gt numTasks 0)}}exactly {{numTasks}}{{else}}an appropriate number of{{/if}} tasks, numbered sequentially starting from {{nextId}}
|
|
242
|
+
2. Each task should be atomic and focused on a single responsibility following the most up to date best practices and standards
|
|
243
|
+
3. Order tasks logically - consider dependencies and implementation sequence
|
|
244
|
+
4. Early tasks should focus on setup, core functionality first, then advanced features
|
|
245
|
+
5. Include clear validation/testing approach for each task
|
|
246
|
+
6. Set appropriate dependency IDs (a task can only depend on tasks with lower IDs, potentially including existing tasks with IDs less than {{nextId}} if applicable)
|
|
247
|
+
7. Assign priority (high/medium/low) based on criticality and dependency order
|
|
248
|
+
8. Include detailed implementation guidance in the "details" field{{#if research}}, with specific libraries and version recommendations based on your research{{/if}}
|
|
249
|
+
9. If the PRD contains specific requirements for libraries, database schemas, frameworks, tech stacks, or any other implementation details, STRICTLY ADHERE to these requirements in your task breakdown and do not discard them under any circumstance
|
|
250
|
+
10. Focus on filling in any gaps left by the PRD or areas that aren't fully specified, while preserving all explicit requirements
|
|
251
|
+
11. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches{{#if research}}
|
|
252
|
+
12. For each task, include specific, actionable guidance based on current industry standards and best practices discovered through research{{/if}}`,user:`{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required
|
|
253
|
+
|
|
254
|
+
You have access to powerful codebase analysis tools. Before generating tasks:
|
|
255
|
+
|
|
256
|
+
1. Use the Glob tool to explore the project structure (e.g., "**/*.js", "**/*.json", "**/README.md")
|
|
257
|
+
2. Use the Grep tool to search for existing implementations, patterns, and technologies
|
|
258
|
+
3. Use the Read tool to examine key files like package.json, README.md, and main entry points
|
|
259
|
+
4. Analyze the current state of implementation to understand what already exists
|
|
260
|
+
|
|
261
|
+
Based on your analysis:
|
|
262
|
+
- Identify what components/features are already implemented
|
|
263
|
+
- Understand the technology stack, frameworks, and patterns in use
|
|
264
|
+
- Generate tasks that build upon the existing codebase rather than duplicating work
|
|
265
|
+
- Ensure tasks align with the project's current architecture and conventions
|
|
266
|
+
|
|
267
|
+
Project Root: {{projectRoot}}
|
|
268
|
+
|
|
269
|
+
{{/if}}Here's the Product Requirements Document (PRD) to break down into {{#if (gt numTasks 0)}}approximately {{numTasks}}{{else}}an appropriate number of{{/if}} tasks, starting IDs from {{nextId}}:{{#if research}}
|
|
270
|
+
|
|
271
|
+
Remember to thoroughly research current best practices and technologies before task breakdown to provide specific, actionable implementation details.{{/if}}
|
|
272
|
+
|
|
273
|
+
{{prdContent}}
|
|
274
|
+
|
|
275
|
+
IMPORTANT: Your response must be a JSON object with a "tasks" property containing an array of task objects. You may optionally include a "metadata" object. Do not include any other properties.`}}},Ze={id:`research`,version:`1.0.0`,description:`Perform AI-powered research with project context`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`research`,`context-aware`,`information-gathering`]},parameters:{query:{type:`string`,required:!0,description:`Research query`},gatheredContext:{type:`string`,default:``,description:`Gathered project context`},detailLevel:{type:`string`,enum:[`low`,`medium`,`high`],default:`medium`,description:`Level of detail for the response`},projectInfo:{type:`object`,description:`Project information`,properties:{root:{type:`string`,description:`Project root path`},taskCount:{type:`number`,description:`Number of related tasks`},fileCount:{type:`number`,description:`Number of related files`}}}},prompts:{default:{system:`You are an expert AI research assistant helping with a software development project. You have access to project context including tasks, files, and project structure.
|
|
276
|
+
|
|
277
|
+
Your role is to provide comprehensive, accurate, and actionable research responses based on the user's query and the provided project context.
|
|
278
|
+
{{#if (eq detailLevel "low")}}
|
|
279
|
+
**Response Style: Concise & Direct**
|
|
280
|
+
- Provide brief, focused answers (2-4 paragraphs maximum)
|
|
281
|
+
- Focus on the most essential information
|
|
282
|
+
- Use bullet points for key takeaways
|
|
283
|
+
- Avoid lengthy explanations unless critical
|
|
284
|
+
- Skip pleasantries, introductions, and conclusions
|
|
285
|
+
- No phrases like "Based on your project context" or "I'll provide guidance"
|
|
286
|
+
- No summary outros or alignment statements
|
|
287
|
+
- Get straight to the actionable information
|
|
288
|
+
- Use simple, direct language - users want info, not explanation{{/if}}{{#if (eq detailLevel "medium")}}
|
|
289
|
+
**Response Style: Balanced & Comprehensive**
|
|
290
|
+
- Provide thorough but well-structured responses (4-8 paragraphs)
|
|
291
|
+
- Include relevant examples and explanations
|
|
292
|
+
- Balance depth with readability
|
|
293
|
+
- Use headings and bullet points for organization{{/if}}{{#if (eq detailLevel "high")}}
|
|
294
|
+
**Response Style: Detailed & Exhaustive**
|
|
295
|
+
- Provide comprehensive, in-depth analysis (8+ paragraphs)
|
|
296
|
+
- Include multiple perspectives and approaches
|
|
297
|
+
- Provide detailed examples, code snippets, and step-by-step guidance
|
|
298
|
+
- Cover edge cases and potential pitfalls
|
|
299
|
+
- Use clear structure with headings, subheadings, and lists{{/if}}
|
|
300
|
+
|
|
301
|
+
**Guidelines:**
|
|
302
|
+
- Always consider the project context when formulating responses
|
|
303
|
+
- Reference specific tasks, files, or project elements when relevant
|
|
304
|
+
- Provide actionable insights that can be applied to the project
|
|
305
|
+
- If the query relates to existing project tasks, suggest how the research applies to those tasks
|
|
306
|
+
- Use markdown formatting for better readability
|
|
307
|
+
- Be precise and avoid speculation unless clearly marked as such
|
|
308
|
+
{{#if (eq detailLevel "low")}}
|
|
309
|
+
**For LOW detail level specifically:**
|
|
310
|
+
- Start immediately with the core information
|
|
311
|
+
- No introductory phrases or context acknowledgments
|
|
312
|
+
- No concluding summaries or project alignment statements
|
|
313
|
+
- Focus purely on facts, steps, and actionable items{{/if}}`,user:`# Research Query
|
|
314
|
+
|
|
315
|
+
{{query}}
|
|
316
|
+
{{#if gatheredContext}}
|
|
317
|
+
|
|
318
|
+
# Project Context
|
|
319
|
+
|
|
320
|
+
{{gatheredContext}}
|
|
321
|
+
{{/if}}
|
|
322
|
+
|
|
323
|
+
# Instructions
|
|
324
|
+
|
|
325
|
+
Please research and provide a {{detailLevel}}-detail response to the query above. Consider the project context provided and make your response as relevant and actionable as possible for this specific project.`}}},Qe={id:`update-subtask`,version:`1.0.0`,description:`Append information to a subtask by generating only new content`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`update`,`subtask`,`append`,`logging`]},parameters:{parentTask:{type:`object`,required:!0,description:`The parent task context`},prevSubtask:{type:`object`,required:!1,description:`The previous subtask if any`},nextSubtask:{type:`object`,required:!1,description:`The next subtask if any`},currentDetails:{type:`string`,required:!0,default:`(No existing details)`,description:`Current subtask details`},updatePrompt:{type:`string`,required:!0,description:`User request for what to add`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},gatheredContext:{type:`string`,default:``,description:`Additional project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant helping to update a subtask. You will be provided with the subtask's existing details, context about its parent and sibling tasks, and a user request string.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}
|
|
326
|
+
|
|
327
|
+
Your Goal: Based *only* on the user's request and all the provided context (including existing details if relevant to the request), GENERATE the new text content that should be added to the subtask's details.
|
|
328
|
+
Focus *only* on generating the substance of the update.
|
|
329
|
+
|
|
330
|
+
Output Requirements:
|
|
331
|
+
1. Return *only* the newly generated text content as a plain string. Do NOT return a JSON object or any other structured data.
|
|
332
|
+
2. Your string response should NOT include any of the subtask's original details, unless the user's request explicitly asks to rephrase, summarize, or directly modify existing text.
|
|
333
|
+
3. Do NOT include any timestamps, XML-like tags, markdown, or any other special formatting in your string response.
|
|
334
|
+
4. Ensure the generated text is concise yet complete for the update based on the user request. Avoid conversational fillers or explanations about what you are doing (e.g., do not start with "Okay, here's the update...").{{#if useResearch}}
|
|
335
|
+
5. Include specific libraries, versions, and current best practices relevant to the subtask implementation.
|
|
336
|
+
6. Provide research-backed technical recommendations and proven approaches.{{/if}}`,user:`{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required
|
|
337
|
+
|
|
338
|
+
You have access to powerful codebase analysis tools. Before generating the subtask update:
|
|
339
|
+
|
|
340
|
+
1. Use the Glob tool to explore the project structure (e.g., "**/*.js", "**/*.json", "**/README.md")
|
|
341
|
+
2. Use the Grep tool to search for existing implementations, patterns, and technologies
|
|
342
|
+
3. Use the Read tool to examine relevant files and understand current implementation
|
|
343
|
+
4. Analyze the current codebase to inform your subtask update
|
|
344
|
+
|
|
345
|
+
Based on your analysis:
|
|
346
|
+
- Include specific file references, code patterns, or implementation details
|
|
347
|
+
- Ensure suggestions align with the project's current architecture
|
|
348
|
+
- Reference existing components or patterns when relevant
|
|
349
|
+
- Make implementation notes specific to the codebase structure
|
|
350
|
+
|
|
351
|
+
Project Root: {{projectRoot}}
|
|
352
|
+
|
|
353
|
+
{{/if}}Task Context:
|
|
354
|
+
|
|
355
|
+
Parent Task: {{{json parentTask}}}
|
|
356
|
+
{{#if prevSubtask}}Previous Subtask: {{{json prevSubtask}}}
|
|
357
|
+
{{/if}}{{#if nextSubtask}}Next Subtask: {{{json nextSubtask}}}
|
|
358
|
+
{{/if}}Current Subtask Details (for context only):
|
|
359
|
+
{{currentDetails}}
|
|
360
|
+
|
|
361
|
+
User Request: "{{updatePrompt}}"
|
|
362
|
+
|
|
363
|
+
{{#if useResearch}}Research and incorporate current best practices, latest stable versions, and proven approaches into your update. {{/if}}Based on the User Request and all the Task Context (including current subtask details provided above), what is the new information or text that should be appended to this subtask's details? Return ONLY this new text as a plain string.{{#if useResearch}} Include specific technical recommendations based on current industry standards.{{/if}}
|
|
364
|
+
{{#if gatheredContext}}
|
|
365
|
+
|
|
366
|
+
# Additional Project Context
|
|
367
|
+
|
|
368
|
+
{{gatheredContext}}
|
|
369
|
+
{{/if}}`}}},$e={id:`update-task`,version:`1.0.0`,description:`Update a single task with new information, supporting full updates and append mode`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`update`,`single-task`,`modification`,`append`]},parameters:{task:{type:`object`,required:!0,description:`The task to update`},taskJson:{type:`string`,required:!0,description:`JSON string representation of the task`},updatePrompt:{type:`string`,required:!0,description:`Description of changes to apply`},appendMode:{type:`boolean`,default:!1,description:`Whether to append to details or do full update`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},currentDetails:{type:`string`,default:`(No existing details)`,description:`Current task details for context`},gatheredContext:{type:`string`,default:``,description:`Additional project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant helping to update a software development task based on new context.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}
|
|
370
|
+
You will be given a task and a prompt describing changes or new implementation details.
|
|
371
|
+
Your job is to update the task to reflect these changes, while preserving its basic structure.
|
|
372
|
+
|
|
373
|
+
Guidelines:
|
|
374
|
+
1. VERY IMPORTANT: NEVER change the title of the task - keep it exactly as is
|
|
375
|
+
2. Maintain the same ID, status, and dependencies unless specifically mentioned in the prompt{{#if useResearch}}
|
|
376
|
+
3. Research and update the description, details, and test strategy with current best practices
|
|
377
|
+
4. Include specific versions, libraries, and approaches that are current and well-tested{{/if}}{{#if (not useResearch)}}
|
|
378
|
+
3. Update the description, details, and test strategy to reflect the new information
|
|
379
|
+
4. Do not change anything unnecessarily - just adapt what needs to change based on the prompt{{/if}}
|
|
380
|
+
5. Return the complete updated task
|
|
381
|
+
6. VERY IMPORTANT: Preserve all subtasks marked as "done" or "completed" - do not modify their content
|
|
382
|
+
7. For tasks with completed subtasks, build upon what has already been done rather than rewriting everything
|
|
383
|
+
8. If an existing completed subtask needs to be changed/undone based on the new context, DO NOT modify it directly
|
|
384
|
+
9. Instead, add a new subtask that clearly indicates what needs to be changed or replaced
|
|
385
|
+
10. Use the existence of completed subtasks as an opportunity to make new subtasks more specific and targeted
|
|
386
|
+
11. Ensure any new subtasks have unique IDs that don't conflict with existing ones
|
|
387
|
+
12. CRITICAL: For subtask IDs, use ONLY numeric values (1, 2, 3, etc.) NOT strings ("1", "2", "3")
|
|
388
|
+
13. CRITICAL: Subtask IDs should start from 1 and increment sequentially (1, 2, 3...) - do NOT use parent task ID as prefix{{#if useResearch}}
|
|
389
|
+
14. Include links to documentation or resources where helpful
|
|
390
|
+
15. Focus on practical, implementable solutions using current technologies{{/if}}
|
|
391
|
+
|
|
392
|
+
The changes described in the prompt should be thoughtfully applied to make the task more accurate and actionable.`,user:`{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required
|
|
393
|
+
|
|
394
|
+
You have access to powerful codebase analysis tools. Before updating the task:
|
|
395
|
+
|
|
396
|
+
1. Use the Glob tool to explore the project structure (e.g., "**/*.js", "**/*.json", "**/README.md")
|
|
397
|
+
2. Use the Grep tool to search for existing implementations, patterns, and technologies
|
|
398
|
+
3. Use the Read tool to examine relevant files and understand current implementation
|
|
399
|
+
4. Analyze how the task changes relate to the existing codebase
|
|
400
|
+
|
|
401
|
+
Based on your analysis:
|
|
402
|
+
- Update task details to reference specific files, functions, or patterns from the codebase
|
|
403
|
+
- Ensure implementation details align with the project's current architecture
|
|
404
|
+
- Include specific code examples or file references where appropriate
|
|
405
|
+
- Consider how changes impact existing components
|
|
406
|
+
|
|
407
|
+
Project Root: {{projectRoot}}
|
|
408
|
+
|
|
409
|
+
{{/if}}Here is the task to update{{#if useResearch}} with research-backed information{{/if}}:
|
|
410
|
+
{{{taskJson}}}
|
|
411
|
+
|
|
412
|
+
Please {{#if useResearch}}research and {{/if}}update this task based on the following {{#if useResearch}}context:
|
|
413
|
+
{{updatePrompt}}
|
|
414
|
+
|
|
415
|
+
Incorporate current best practices, latest stable versions, and proven approaches.{{/if}}{{#if (not useResearch)}}new context:
|
|
416
|
+
{{updatePrompt}}{{/if}}
|
|
417
|
+
|
|
418
|
+
IMPORTANT: {{#if useResearch}}Preserve any subtasks marked as "done" or "completed".{{/if}}{{#if (not useResearch)}}In the task JSON above, any subtasks with "status": "done" or "status": "completed" should be preserved exactly as is. Build your changes around these completed items.{{/if}}
|
|
419
|
+
{{#if gatheredContext}}
|
|
420
|
+
|
|
421
|
+
# Project Context
|
|
422
|
+
|
|
423
|
+
{{gatheredContext}}
|
|
424
|
+
{{/if}}
|
|
425
|
+
|
|
426
|
+
Return the complete updated task{{#if useResearch}} with research-backed improvements{{/if}}.
|
|
427
|
+
|
|
428
|
+
IMPORTANT: Your response must be a JSON object with a single property named "task" containing the updated task object.`},append:{condition:`appendMode === true`,system:`You are an AI assistant helping to append additional information to a software development task. You will be provided with the task's existing details, context, and a user request string.
|
|
429
|
+
|
|
430
|
+
Your Goal: Based *only* on the user's request and all the provided context (including existing details if relevant to the request), GENERATE the new text content that should be added to the task's details.
|
|
431
|
+
Focus *only* on generating the substance of the update.
|
|
432
|
+
|
|
433
|
+
Output Requirements:
|
|
434
|
+
1. Return *only* the newly generated text content as a plain string. Do NOT return a JSON object or any other structured data.
|
|
435
|
+
2. Your string response should NOT include any of the task's original details, unless the user's request explicitly asks to rephrase, summarize, or directly modify existing text.
|
|
436
|
+
3. Do NOT include any timestamps, XML-like tags, markdown, or any other special formatting in your string response.
|
|
437
|
+
4. Ensure the generated text is concise yet complete for the update based on the user request. Avoid conversational fillers or explanations about what you are doing (e.g., do not start with "Okay, here's the update...").`,user:`{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required
|
|
438
|
+
|
|
439
|
+
You have access to powerful codebase analysis tools. Before generating the task update:
|
|
440
|
+
|
|
441
|
+
1. Use the Glob tool to explore the project structure (e.g., "**/*.js", "**/*.json", "**/README.md")
|
|
442
|
+
2. Use the Grep tool to search for existing implementations, patterns, and technologies
|
|
443
|
+
3. Use the Read tool to examine relevant files and understand current implementation
|
|
444
|
+
4. Analyze the current codebase to inform your update
|
|
445
|
+
|
|
446
|
+
Based on your analysis:
|
|
447
|
+
- Include specific file references, code patterns, or implementation details
|
|
448
|
+
- Ensure suggestions align with the project's current architecture
|
|
449
|
+
- Reference existing components or patterns when relevant
|
|
450
|
+
|
|
451
|
+
Project Root: {{projectRoot}}
|
|
452
|
+
|
|
453
|
+
{{/if}}Task Context:
|
|
454
|
+
|
|
455
|
+
Task: {{{json task}}}
|
|
456
|
+
Current Task Details (for context only):
|
|
457
|
+
{{currentDetails}}
|
|
458
|
+
|
|
459
|
+
User Request: "{{updatePrompt}}"
|
|
460
|
+
|
|
461
|
+
Based on the User Request and all the Task Context (including current task details provided above), what is the new information or text that should be appended to this task's details? Return this new text as a plain string.
|
|
462
|
+
{{#if gatheredContext}}
|
|
463
|
+
|
|
464
|
+
# Additional Project Context
|
|
465
|
+
|
|
466
|
+
{{gatheredContext}}
|
|
467
|
+
{{/if}}`}}},et={id:`update-tasks`,version:`1.0.0`,description:`Update multiple tasks based on new context or changes`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`update`,`bulk`,`context-change`]},parameters:{tasks:{type:`array`,required:!0,description:`Array of tasks to update`},updatePrompt:{type:`string`,required:!0,description:`Description of changes to apply`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},projectContext:{type:`string`,description:`Additional project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant helping to update software development tasks based on new context.
|
|
468
|
+
You will be given a set of tasks and a prompt describing changes or new implementation details.
|
|
469
|
+
Your job is to update the tasks to reflect these changes, while preserving their basic structure.
|
|
470
|
+
|
|
471
|
+
Guidelines:
|
|
472
|
+
1. Maintain the same IDs, statuses, and dependencies unless specifically mentioned in the prompt
|
|
473
|
+
2. Update titles, descriptions, details, and test strategies to reflect the new information
|
|
474
|
+
3. Do not change anything unnecessarily - just adapt what needs to change based on the prompt
|
|
475
|
+
4. Return ALL the tasks in order, not just the modified ones
|
|
476
|
+
5. VERY IMPORTANT: Preserve all subtasks marked as "done" or "completed" - do not modify their content
|
|
477
|
+
6. For tasks with completed subtasks, build upon what has already been done rather than rewriting everything
|
|
478
|
+
7. If an existing completed subtask needs to be changed/undone based on the new context, DO NOT modify it directly
|
|
479
|
+
8. Instead, add a new subtask that clearly indicates what needs to be changed or replaced
|
|
480
|
+
9. Use the existence of completed subtasks as an opportunity to make new subtasks more specific and targeted`,user:`{{#if hasCodebaseAnalysis}}## IMPORTANT: Codebase Analysis Required
|
|
481
|
+
|
|
482
|
+
You have access to powerful codebase analysis tools. Before updating tasks:
|
|
483
|
+
|
|
484
|
+
1. Use the Glob tool to explore the project structure (e.g., "**/*.js", "**/*.json", "**/README.md")
|
|
485
|
+
2. Use the Grep tool to search for existing implementations, patterns, and technologies
|
|
486
|
+
3. Use the Read tool to examine relevant files and understand current implementation
|
|
487
|
+
4. Analyze how the new changes relate to the existing codebase
|
|
488
|
+
|
|
489
|
+
Based on your analysis:
|
|
490
|
+
- Update task details to reference specific files, functions, or patterns from the codebase
|
|
491
|
+
- Ensure implementation details align with the project's current architecture
|
|
492
|
+
- Include specific code examples or file references where appropriate
|
|
493
|
+
- Consider how changes impact existing components
|
|
494
|
+
|
|
495
|
+
Project Root: {{projectRoot}}
|
|
496
|
+
|
|
497
|
+
{{/if}}Here are the tasks to update:
|
|
498
|
+
{{{json tasks}}}
|
|
499
|
+
|
|
500
|
+
Please update these tasks based on the following new context:
|
|
501
|
+
{{updatePrompt}}
|
|
502
|
+
|
|
503
|
+
IMPORTANT: In the tasks above, any subtasks with "status": "done" or "status": "completed" should be preserved exactly as is. Build your changes around these completed items.{{#if projectContext}}
|
|
504
|
+
|
|
505
|
+
# Project Context
|
|
506
|
+
|
|
507
|
+
{{projectContext}}{{/if}}
|
|
508
|
+
|
|
509
|
+
IMPORTANT: Your response must be a JSON object with a single property named "tasks" containing the updated array of tasks.`}}},tt={$schema:`http://json-schema.org/draft-07/schema#`,$id:`https://github.com/stephennmiller/taskgraph-ai/blob/main/src/prompts/schemas/prompt-template.schema.json`,version:`1.0.0`,title:`TaskGraph Prompt Template`,description:`Schema for TaskGraph prompt template files`,type:`object`,required:[`id`,`version`,`description`,`prompts`],properties:{id:{type:`string`,pattern:`^[a-z0-9-]+$`,description:`Unique identifier for the prompt template`},version:{type:`string`,pattern:`^\\d+\\.\\d+\\.\\d+$`,description:`Semantic version of the prompt template`},description:{type:`string`,minLength:1,description:`Brief description of what this prompt does`},metadata:{$ref:`#/definitions/metadata`},parameters:{type:`object`,additionalProperties:{$ref:`#/definitions/parameter`}},prompts:{type:`object`,properties:{default:{$ref:`#/definitions/promptVariant`}},additionalProperties:{$ref:`#/definitions/conditionalPromptVariant`}}},definitions:{parameter:{type:`object`,required:[`type`,`description`],properties:{type:{type:`string`,enum:[`string`,`number`,`boolean`,`array`,`object`]},description:{type:`string`,minLength:1},required:{type:`boolean`,default:!1},default:{description:`Default value for optional parameters`},enum:{type:`array`,description:`Valid values for string parameters`},pattern:{type:`string`,description:`Regular expression pattern for string validation`},minimum:{type:`number`,description:`Minimum value for number parameters`},maximum:{type:`number`,description:`Maximum value for number parameters`}}},promptVariant:{type:`object`,required:[`system`,`user`],properties:{system:{type:`string`,minLength:1},user:{type:`string`,minLength:1}}},conditionalPromptVariant:{allOf:[{$ref:`#/definitions/promptVariant`},{type:`object`,properties:{condition:{type:`string`,description:`JavaScript expression for variant selection`}}}]},metadata:{type:`object`,properties:{author:{type:`string`},created:{type:`string`,format:`date-time`},updated:{type:`string`,format:`date-time`},tags:{type:`array`,items:{type:`string`}},category:{type:`string`,enum:[`task`,`analysis`,`research`,`parsing`,`update`,`expansion`]}}}}},nt=class{constructor(){this.prompts=/* @__PURE__ */ new Map([[`analyze-complexity`,Je],[`expand-task`,Ye],[`add-task`,qe],[`research`,Ze],[`parse-prd`,Xe],[`update-task`,$e],[`update-tasks`,et],[`update-subtask`,Qe]]),this.cache=/* @__PURE__ */ new Map,this.setupValidation()}setupValidation(){this.ajv=new we({allErrors:!0,strict:!1}),Te(this.ajv);try{this.validatePrompt=this.ajv.compile(tt),o(`debug`,`✓ JSON schema validation enabled`)}catch(e){o(`warn`,`⚠ Schema validation disabled: ${e.message}`),this.validatePrompt=()=>!0}}loadPrompt(e,t={},n=null){try{let r=`${e}-${JSON.stringify(t)}-${n}`;if(this.cache.has(r))return this.cache.get(r);let i=this.loadTemplate(e);this.validatePrompt&&this.validatePrompt!==!0&&this.validateParameters(i,t);let a=n?{...i.prompts[n],name:n}:this.selectVariant(i,t),o={systemPrompt:this.renderTemplate(a.system,t),userPrompt:this.renderTemplate(a.user,t),metadata:{templateId:i.id,version:i.version,variant:a.name||`default`,parameters:t}};return this.cache.set(r,o),o}catch(t){throw o(`error`,`Failed to load prompt ${e}: ${t.message}`),t}}loadTemplate(e){let t=this.prompts.get(e);if(!t)throw Error(`Prompt template '${e}' not found`);if(this.validatePrompt&&this.validatePrompt!==!0){if(!this.validatePrompt(t)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}}else if(!t.id||!t.prompts||!t.prompts.default)throw Error(`Invalid template structure: missing required fields (id, prompts.default)`);return t}validateParameters(e,t){if(!e.parameters)return;let n=[];for(let[r,i]of Object.entries(e.parameters)){let e=t[r];i.required&&e===void 0?n.push(`Required parameter '${r}' missing`):e!==void 0&&(this.validateParameterType(e,i.type)||n.push(`Parameter '${r}' expected ${i.type}, got ${typeof e}`),i.enum&&!i.enum.includes(e)&&n.push(`Parameter '${r}' must be one of: ${i.enum.join(`, `)}`),i.pattern&&typeof e==`string`&&(new RegExp(i.pattern).test(e)||n.push(`Parameter '${r}' does not match required pattern: ${i.pattern}`)),typeof e==`number`&&(i.minimum!==void 0&&e<i.minimum&&n.push(`Parameter '${r}' must be >= ${i.minimum}`),i.maximum!==void 0&&e>i.maximum&&n.push(`Parameter '${r}' must be <= ${i.maximum}`)))}if(n.length>0)throw Error(`Parameter validation failed: ${n.join(`; `)}`)}validateParameterType(e,t){switch(t){case`string`:return typeof e==`string`;case`number`:return typeof e==`number`;case`boolean`:return typeof e==`boolean`;case`array`:return Array.isArray(e);case`object`:return typeof e==`object`&&!!e&&!Array.isArray(e);default:return!0}}selectVariant(e,t){for(let[n,r]of Object.entries(e.prompts))if(n!=="default"&&r.condition&&this.evaluateCondition(r.condition,t))return{...r,name:n};return{...e.prompts.default,name:`default`}}evaluateCondition(e,t){try{let n={...t};return Function(...Object.keys(n),`return ${e}`)(...Object.values(n))}catch{return o(`warn`,`Failed to evaluate condition: ${e}`),!1}}renderTemplate(e,t){let n=e;return n=n.replace(/\(eq\s+(\w+(?:\.\w+)*)\s+"([^"]+)"\)/g,(e,n,r)=>this.getNestedValue(t,n)===r?`true`:`false`),n=n.replace(/\(not\s+(\w+(?:\.\w+)*)\)/g,(e,n)=>this.getNestedValue(t,n)?`false`:`true`),n=n.replace(/\(gt\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>parseFloat(r)?`true`:`false`}),n=n.replace(/\(gte\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>=parseFloat(r)?`true`:`false`}),n=n.replace(/\{\{#if\s+([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g,(e,n,r,i=``)=>{let a;return a=n===`true`||n!==`false`&&this.getNestedValue(t,n),a?r:i}),n=n.replace(/\{\{#each\s+(\w+(?:\.\w+)*)\}\}([\s\S]*?)\{\{\/each\}\}/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return Array.isArray(i)?i.map((e,n)=>{let a={...t,...e,"@index":n,"@first":n===0,"@last":n===i.length-1};return this.renderTemplate(r,a)}).join(``):``}),n=n.replace(/\{\{\{json\s+(\w+(?:\.\w+)*)\}\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:JSON.stringify(r,null,2)}),n=n.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:r}),n}getNestedValue(e,t){return t.split(`.`).reduce((e,t)=>e&&e[t]!==void 0?e[t]:void 0,e)}validateAllPrompts(){let e={total:0,errors:[],valid:[]};for(let[t,n]of this.prompts.entries()){e.total++;try{if(this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(n)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}e.valid.push(t)}catch(n){e.errors.push(`${t}: ${n.message}`)}}return e}listPrompts(){let e=[];for(let[t,n]of this.prompts.entries())try{e.push({id:n.id,description:n.description,version:n.version,parameters:n.parameters,tags:n.metadata?.tags||[]})}catch(e){o(`warn`,`Failed to process template ${t}: ${e.message}`)}return e}validateTemplate(e){try{let t;if(typeof e==`string`){if(t=this.prompts.get(e),!t)return{valid:!1,error:`Template '${e}' not found`}}else t=e;for(let e of[`id`,`version`,`description`,`prompts`])if(!t[e])return{valid:!1,error:`Missing required field: ${e}`};if(!t.prompts.default)return{valid:!1,error:`Missing default prompt variant`};for(let[e,n]of Object.entries(t.prompts))if(!n.system||!n.user)return{valid:!1,error:`Variant '${e}' missing system or user prompt`};return this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(t)?{valid:!1,error:`Schema validation failed: ${this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `)}`}:{valid:!0}}catch(e){return{valid:!1,error:e.message}}}};let rt=null;function it(){return rt||=new nt,rt}const{encode:at}=Ee;var ot=class{constructor(e,t){this.projectRoot=e,this.tasksPath=H.join(e,`.taskgraph`,`tasks`,`tasks.json`),this.tag=t,this.allTasks=this._loadAllTasks()}_loadAllTasks(){try{return P(this.tasksPath,this.projectRoot,this.tag)?.tasks||[]}catch(e){return console.warn(`Warning: Could not load tasks for ContextGatherer: ${e.message}`),[]}}countTokens(e){if(!e||typeof e!=`string`)return 0;try{return at(e).length}catch{return Math.ceil(e.length/4)}}async gather(e={}){let{tasks:t=[],files:n=[],customContext:r=``,includeProjectTree:i=!1,format:a=`research`,includeTokenCounts:o=!1,semanticQuery:s,maxSemanticResults:c=10,dependencyTasks:l=[]}=e,u=[],d=new Set(t.map(String)),f=null,p=null;if(o&&(p={total:0,customContext:null,tasks:[],files:[],projectTree:null}),s&&this.allTasks.length>0){let e=this._performSemanticSearch(s,c);f=e.analysisData,e.tasks.forEach(e=>{d.add(String(e.id))})}if(l.length>0&&this._buildDependencyGraphs(l).allRelatedTaskIds.forEach(e=>d.add(String(e))),r&&r.trim()){let e=this._formatCustomContext(r,a);u.push(e),o&&(p.customContext={tokens:this.countTokens(e),characters:e.length},p.total+=p.customContext.tokens)}if(d.size>0){let e=await this._gatherTaskContext(Array.from(d),a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.tasks=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(n.length>0){let e=await this._gatherFileContext(n,a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.files=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(i){let e=await this._gatherProjectTreeContext(a,o);e.context&&(u.push(e.context),o&&e.breakdown&&(p.projectTree=e.breakdown,p.total+=e.breakdown.tokens))}let m={context:this._joinContextSections(u,a),analysisData:f,contextSections:u.length,finalTaskIds:Array.from(d)};return o&&(m.tokenBreakdown=p),m}_performSemanticSearch(e,t){let n=this.allTasks.map(e=>{let t=e.dependencies?.length>0?e.dependencies.map(e=>this.allTasks.find(t=>t.id===e)?.title).filter(Boolean).join(` `):``;return{...e,dependencyTitles:t}}),r=new Se(n,{includeScore:!0,threshold:.4,keys:[{name:`title`,weight:1.5},{name:`description`,weight:2},{name:`details`,weight:3},{name:`dependencyTitles`,weight:.5}],shouldSort:!0,useExtendedSearch:!0,limit:50}),i=e.toLowerCase().replace(/[^\w\s-]/g,` `).split(/\s+/).filter(e=>e.length>3),a=r.search(e),o=[];for(let e of i)if(e.length>5){let t=r.search(e);t.length>0&&o.push(...t)}let s=[...a];for(let e of o)s.some(t=>t.item.id===e.item.id)||s.push(e);let c=s.filter(e=>e.score<.25).map(e=>e.item),l=s.filter(e=>e.score>=.25&&e.score<.4).map(e=>e.item),u=[...this.allTasks].sort((e,t)=>t.id-e.id).slice(0,5),d=[...c];for(let e of l)d.some(t=>t.id===e.id)||d.push(e);for(let e of u)d.some(t=>t.id===e.id)||d.push(e);return{tasks:d.slice(0,t),analysisData:{highRelevance:c,mediumRelevance:l,recentTasks:u,allRelevantTasks:d}}}_buildDependencyContext(e){let{allRelatedTaskIds:t,graphs:n,depthMap:r}=this._buildDependencyGraphs(e);if(t.size===0)return``;let i=Array.from(t).map(e=>this.allTasks.find(t=>t.id===e)).filter(Boolean).sort((e,t)=>(r.get(e.id)||0)-(r.get(t.id)||0)),a=i.slice(0,8),o=`\nThis task relates to a dependency structure with ${i.length} related tasks in the chain.`,s=this.allTasks.filter(t=>e.includes(t.id));s.length>0&&(o+=`\n\nDirect dependencies:\n${s.map(e=>`- Task ${e.id}: ${e.title} - ${e.description}`).join(`
|
|
510
|
+
`)}`);let c=i.filter(t=>!e.includes(t.id));c.length>0&&(o+=`\n\nIndirect dependencies (dependencies of dependencies):\n${c.slice(0,5).map(e=>`- Task ${e.id}: ${e.title} - ${e.description}`).join(`
|
|
511
|
+
`)}`,c.length>5&&(o+=`\n- ... and ${c.length-5} more indirect dependencies`)),o+=`
|
|
512
|
+
|
|
513
|
+
Detailed information about dependencies:`;for(let t of a){let n=e.includes(t.id)?` [DIRECT DEPENDENCY]`:``;o+=`\n\n------ Task ${t.id}${n}: ${t.title} ------\n`,o+=`Description: ${t.description}\n`,t.dependencies?.length&&(o+=`Dependencies: ${t.dependencies.join(`, `)}\n`),t.details&&(o+=`Implementation Details: ${y(t.details,400)}\n`)}return n.length>0&&(o+=`
|
|
514
|
+
|
|
515
|
+
Dependency Chain Visualization:`,o+=n.map(e=>this._formatDependencyChain(e)).join(``)),o}_buildDependencyGraphs(e){let t=/* @__PURE__ */ new Set,n=/* @__PURE__ */ new Map,r=[];for(let i of e){let e=this._buildDependencyGraph(i,t,n);e&&r.push(e)}return{allRelatedTaskIds:t,graphs:r,depthMap:n}}_buildDependencyGraph(e,t,n,r=0){if(t.has(e)||r>5)return null;let i=this.allTasks.find(t=>t.id===e);if(!i)return null;t.add(e),(!n.has(e)||r<n.get(e))&&n.set(e,r);let a=i.dependencies?.map(e=>this._buildDependencyGraph(e,t,n,r+1)).filter(Boolean)||[];return{...i,dependencies:a}}_formatDependencyChain(e,t=``,n=!0,r=0){if(r>3)return``;let i=`${t}${n?`└── `:`├── `}Task ${e.id}: ${e.title}`;if(e.dependencies?.length){let a=t+(n?` `:`│ `);i+=e.dependencies.map((t,n)=>this._formatDependencyChain(t,a,n===e.dependencies.length-1,r+1)).join(``)}return`
|
|
516
|
+
`+i}_parseTaskIds(e){let t=[];for(let n of e)if(n.includes(`.`)){let[e,r]=n.split(`.`);t.push({type:`subtask`,parentId:parseInt(e,10),subtaskId:parseInt(r,10),fullId:n})}else t.push({type:`task`,taskId:parseInt(n,10),fullId:n});return t}async _gatherTaskContext(e,t,n=!1){try{if(!this.allTasks||this.allTasks.length===0)return{context:null,breakdown:[]};let r=this._parseTaskIds(e),i=[],a=[];for(let e of r){let r=null,o=null;if(e.type===`task`){let i=d(this.allTasks,e.taskId);i.task&&(r=this._formatTaskForContext(i.task,t),o={id:e.fullId,type:`task`,title:i.task.title,tokens:n?this.countTokens(r):0,characters:r.length})}else if(e.type===`subtask`){let i=d(this.allTasks,e.parentId);if(i.task&&i.task.subtasks){let a=i.task.subtasks.find(t=>t.id===e.subtaskId);a&&(r=this._formatSubtaskForContext(a,i.task,t),o={id:e.fullId,type:`subtask`,title:a.title,parentTitle:i.task.title,tokens:n?this.countTokens(r):0,characters:r.length})}}r&&o&&(i.push(r),n&&a.push(o))}return i.length===0?{context:null,breakdown:[]}:{context:this._formatTaskContextSection(i,t),breakdown:n?a:[]}}catch(e){return console.warn(`Warning: Could not gather task context: ${e.message}`),{context:null,breakdown:[]}}}_formatTaskForContext(e,t){let n=[];if(n.push(`**Task ${e.id}: ${e.title}**`),n.push(`Description: ${e.description}`),n.push(`Status: ${e.status||`pending`}`),n.push(`Priority: ${e.priority||`medium`}`),e.dependencies&&e.dependencies.length>0&&n.push(`Dependencies: ${e.dependencies.join(`, `)}`),e.details){let t=y(e.details,500);n.push(`Implementation Details: ${t}`)}if(e.testStrategy){let t=y(e.testStrategy,300);n.push(`Test Strategy: ${t}`)}return e.subtasks&&e.subtasks.length>0&&n.push(`Subtasks: ${e.subtasks.length} subtasks defined`),n.join(`
|
|
517
|
+
`)}_formatSubtaskForContext(e,t,n){let r=[];if(r.push(`**Subtask ${t.id}.${e.id}: ${e.title}**`),r.push(`Parent Task: ${t.title}`),r.push(`Description: ${e.description}`),r.push(`Status: ${e.status||`pending`}`),e.dependencies&&e.dependencies.length>0&&r.push(`Dependencies: ${e.dependencies.join(`, `)}`),e.details){let t=y(e.details,500);r.push(`Implementation Details: ${t}`)}return r.join(`
|
|
518
|
+
`)}async _gatherFileContext(e,t,n=!1){let r=[],i=[];for(let a of e)try{let e=H.isAbsolute(a)?a:H.join(this.projectRoot,a);if(!W.existsSync(e))continue;let o=W.statSync(e);if(!o.isFile()||o.size>51200)continue;let s=W.readFileSync(e,`utf-8`),c=H.relative(this.projectRoot,e),l={path:c,size:o.size,content:s,lastModified:o.mtime};if(r.push(l),n){let e=this._formatSingleFileForContext(l,t);i.push({path:c,sizeKB:Math.round(o.size/1024),tokens:this.countTokens(e),characters:e.length})}}catch(e){console.warn(`Warning: Could not read file ${a}: ${e.message}`)}return r.length===0?{context:null,breakdown:[]}:{context:this._formatFileContextSection(r,t),breakdown:n?i:[]}}async _gatherProjectTreeContext(e,t=!1){try{let n=this._generateFileTree(this.projectRoot,5),r=this._formatProjectTreeSection(n,e);return{context:r,breakdown:t?{tokens:this.countTokens(r),characters:r.length,fileCount:n.fileCount||0,dirCount:n.dirCount||0}:null}}catch(e){return console.warn(`Warning: Could not generate project tree: ${e.message}`),{context:null,breakdown:null}}}_formatSingleFileForContext(e,t){return`${`**File: ${e.path}** (${Math.round(e.size/1024)}KB)`}\n\n${`\`\`\`\n${e.content}\n\`\`\``}`}_generateFileTree(e,t,n=0){let r=[`.git`,`node_modules`,`.env`,`coverage`,`dist`,`build`],i=[`.DS_Store`,`.env`,`.env.local`,`.env.production`];if(n>=t)return null;try{let a=W.readdirSync(e),o={name:H.basename(e),type:`directory`,children:[],fileCount:0,dirCount:0};for(let s of a){if(r.includes(s)||i.includes(s))continue;let a=H.join(e,s),c=W.statSync(a);if(c.isDirectory()){if(o.dirCount++,n<t-1){let e=this._generateFileTree(a,t,n+1);e&&o.children.push(e)}}else o.fileCount++,o.children.push({name:s,type:`file`,size:c.size})}return o}catch{return null}}_formatCustomContext(e,t){switch(t){case`research`:return`## Additional Context\n\n${e}`;case`chat`:return`**Additional Context:**\n${e}`;case`system-prompt`:return`Additional context: ${e}`;default:return e}}_formatTaskContextSection(e,t){switch(t){case`research`:return`## Task Context\n\n${e.join(`
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
`)}`;case`chat`:return`**Task Context:**\n\n${e.join(`
|
|
523
|
+
|
|
524
|
+
`)}`;case`system-prompt`:return`Task context: ${e.join(` | `)}`;default:return e.join(`
|
|
525
|
+
|
|
526
|
+
`)}}_formatFileContextSection(e,t){let n=e.map(e=>`${`**File: ${e.path}** (${Math.round(e.size/1024)}KB)`}\n\n${`\`\`\`\n${e.content}\n\`\`\``}`);switch(t){case`research`:return`## File Context\n\n${n.join(`
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
`)}`;case`chat`:return`**File Context:**\n\n${n.join(`
|
|
531
|
+
|
|
532
|
+
`)}`;case`system-prompt`:return`File context: ${e.map(e=>`${e.path} (${e.content.substring(0,200)}...)`).join(` | `)}`;default:return n.join(`
|
|
533
|
+
|
|
534
|
+
`)}}_formatProjectTreeSection(e,t){let n=this._renderFileTree(e);switch(t){case`research`:return`## Project Structure\n\n\`\`\`\n${n}\n\`\`\``;case`chat`:return`**Project Structure:**\n\`\`\`\n${n}\n\`\`\``;case`system-prompt`:return`Project structure: ${n.replace(/\n/g,` | `)}`;default:return n}}_renderFileTree(e,t=``){let n=`${t}${e.name}/`;return(e.fileCount>0||e.dirCount>0)&&(n+=` (${e.fileCount} files, ${e.dirCount} dirs)`),n+=`
|
|
535
|
+
`,e.children&&e.children.forEach((r,i)=>{let a=t+(i===e.children.length-1?`└── `:`├── `);t+``,r.type===`directory`?n+=this._renderFileTree(r,a):n+=`${a}${r.name}\n`}),n}_joinContextSections(e,t){if(e.length===0)return``;switch(t){case`research`:return e.join(`
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
`);case`chat`:return e.join(`
|
|
540
|
+
|
|
541
|
+
`);case`system-prompt`:return e.join(` `);default:return e.join(`
|
|
542
|
+
|
|
543
|
+
`)}}};function st(e){let t=[];for(let n in e)Object.prototype.hasOwnProperty.call(e,n)&&e[n]&&Array.isArray(e[n].tasks)&&(t=t.concat(e[n].tasks));return t}async function ct(e,t,n=[],i=null,a={},s=`text`,l=null,u=!1){let{session:d,mcpLog:f,projectRoot:p,commandName:m,outputType:g,tag:_}=a,b=!!f,S=b?f:{info:(...e)=>o(`info`,...e),warn:(...e)=>o(`warn`,...e),error:(...e)=>o(`error`,...e),debug:(...e)=>o(`debug`,...e),success:(...e)=>o(`success`,...e)},C=i||v(p)||`medium`;if(i){let e=Pe(i);e?C=e:(s===`text`&&o(`warn`,`Invalid priority "${i}". Using default priority "${Me}".`),C=Me)}S.debug(`Adding new task with prompt: "${t}", Priority: ${C}, Dependencies: ${n.join(`, `)||`None`}, Research: ${u}, ProjectRoot: ${p}`),_&&S.debug(`Using tag context: ${_}`);let T=null,D=null,O=(e,t=`info`)=>{f?f[t](e):s===`text`&&o(t,e)};function k(e,t,n=/* @__PURE__ */ new Set,r=/* @__PURE__ */ new Map,i=0){if(n.has(t))return null;let a=e.find(e=>e.id===t);if(!a)return null;n.add(t),(!r.has(t)||i<r.get(t))&&r.set(t,i);let o=[];if(a.dependencies&&a.dependencies.length>0)for(let t of a.dependencies){let a=k(e,t,n,r,i+1);a&&o.push(a)}return{id:a.id,title:a.title,description:a.description,status:a.status,dependencies:o}}try{let i=P(e,p,_);i&&i._rawTaggedData&&(i=i._rawTaggedData),i||=(O(`tasks.json not found or invalid. Initializing new structure.`,`info`),{master:{tasks:[],metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),description:`Default tasks context`}}}),i&&Array.isArray(i.tasks)&&!i._rawTaggedData&&(O(`Legacy format detected. Migrating to tagged format...`,`info`),i={master:{tasks:i.tasks,metadata:i.metadata||{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for master context`}}},h(i.master,{description:`Tasks for master context`}),ee(e),x(e),O(`Successfully migrated to tagged format.`,`success`));let a=_;if(!i[a])throw O(`Tag "${a}" does not exist. Please create it first using the 'add-tag' command.`,`error`),Error(`Tag "${a}" not found.`);i[a].tasks||(i[a].tasks=[]),i[a].metadata||(i[a].metadata={created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:``});let o=st(i),f=i[a].tasks,v=(f.length>0?Math.max(...f.map(e=>e.id)):0)+1,S=n.filter(e=>{let t=parseInt(e,10);return Number.isNaN(t)||!o.some(e=>e.id===t)});S.length>0&&(O(`The following dependencies do not exist or are invalid: ${S.join(`, `)}`,`warn`),O(`Removing invalid dependencies...`,`info`),n=n.filter(e=>!S.includes(e)));let A=n.map(e=>parseInt(e,10)),j=[],M=/* @__PURE__ */ new Set,N=/* @__PURE__ */ new Map;for(let e of A){let t=k(o,e,/* @__PURE__ */ new Set,N);t&&j.push(t)}for(let[e,t]of N.entries())M.add(e);let F;if(l){if(O(`Using manually provided task data`,`info`),F=l,O(`DEBUG: Taking MANUAL task data path.`,`debug`),!F.title||typeof F.title!=`string`||!F.description||typeof F.description!=`string`)throw Error(`Manual task data must include at least a title and description.`)}else{O(`DEBUG: Taking AI task generation path.`,`debug`),O(`Generating task data with AI with prompt:\n${t}`,`debug`);let e=await new ot(p,_).gather({semanticQuery:t,dependencyTasks:A,format:`research`}),n=e.context,i=e.analysisData;s===`text`&&i&&Oi(i,t,n.length);let a=``;l?.title&&(a+=`\n- Suggested Title: "${l.title}"`),l?.description&&(a+=`\n- Suggested Description: "${l.description}"`),l?.details&&(a+=`\n- Additional Details Context: "${l.details}"`),l?.testStrategy&&(a+=`\n- Additional Test Strategy Context: "${l.testStrategy}"`);let{systemPrompt:f,userPrompt:h}=await it().loadPrompt(`add-task`,{prompt:t,newTaskId:v,existingTasks:o,gatheredContext:n,contextFromArgs:a,useResearch:u,priority:C,dependencies:A,hasCodebaseAnalysis:c(u,p,d),projectRoot:p});s===`text`&&(T=X(`Writing the new task${u?` with research`:``}…`));try{let e=u?`research`:`main`;if(O(`DEBUG: Calling generateObjectService...`,`debug`),D=await r({role:e,session:d,projectRoot:p,schema:Ke[`add-task`],objectName:`newTaskData`,systemPrompt:f,prompt:h,commandName:m||`add-task`,outputType:g||(b?`mcp`:`cli`)}),O(`DEBUG: generateObjectService returned successfully.`,`debug`),!D||!D.mainResult)throw Error(`AI service did not return the expected object structure.`);if(D.mainResult.title&&D.mainResult.description)F=D.mainResult;else if(D.mainResult.object&&D.mainResult.object.title&&D.mainResult.object.description)F=D.mainResult.object;else throw Error(`AI service did not return a valid task object.`);O(`Successfully generated task data from AI.`,`debug`),T&&=(Z(T),null)}catch(e){throw T&&=(yi(T,`AI generation failed`),null),O(`DEBUG: generateObjectService caught error: ${e.message}`,`debug`),O(`Error generating task with AI: ${e.message}`,`error`),e}finally{O(`DEBUG: generateObjectService finally block reached.`,`debug`),T&&Z(T)}}let I={id:v,title:F.title,description:F.description,details:F.details||``,testStrategy:F.testStrategy||``,status:`pending`,dependencies:F.dependencies?.length?F.dependencies:A,priority:C,subtasks:[]};if(F.dependencies?.length&&(F.dependencies.every(e=>{let t=parseInt(e,10);return!Number.isNaN(t)&&o.some(e=>e.id===t)})||(O(`AI suggested invalid dependencies. Filtering them out...`,`warn`),I.dependencies=F.dependencies.filter(e=>{let t=parseInt(e,10);return!Number.isNaN(t)&&o.some(e=>e.id===t)}))),i[a].tasks.push(I),h(i[a],{description:`Tasks for ${a} context`}),O(`DEBUG: Writing tasks.json...`,`debug`),E(e,i,p,a),O(`DEBUG: tasks.json written.`,`debug`),s===`text`){let e=e=>{switch(e?.toLowerCase()){case`high`:return`red`;case`low`:return`dim`;default:return`yellow`}},t=I.dependencies.filter(e=>!A.includes(e)),n=A.filter(e=>!I.dependencies.includes(e)),r={};I.dependencies.forEach(e=>{let t=o.find(t=>t.id===e);t&&(r[e]=y(t.title,30))});let i=``;I.dependencies.length>0?(i=w.text(`Dependencies:`)+`
|
|
544
|
+
`,I.dependencies.forEach(e=>{let n=t.includes(e)?V.yellow(` (AI suggested)`):``;i+=w.text(` - ${e}: ${r[e]||`Unknown task`}${n}`)+`
|
|
545
|
+
`})):i=w.text(`Dependencies: None`)+`
|
|
546
|
+
`,n.length>0&&(i+=w.muted(`
|
|
547
|
+
User-specified dependencies that were not used:`)+`
|
|
548
|
+
`,n.forEach(e=>{let t=o.find(t=>t.id===e),n=t?y(t.title,30):`Unknown task`;i+=w.muted(` - ${e}: ${n}`)+`
|
|
549
|
+
`}));let a=``;(t.length>0||n.length>0)&&(a=`
|
|
550
|
+
`+w.text.bold(`Dependency Analysis:`)+`
|
|
551
|
+
`,t.length>0&&(a+=V.green(`AI identified ${t.length} additional dependencies`)+`
|
|
552
|
+
`),n.length>0&&(a+=V.yellow(`AI excluded ${n.length} user-provided dependencies`)+`
|
|
553
|
+
`)),console.log(G(w.text.bold(`Task ${v} Created Successfully`)+`
|
|
554
|
+
|
|
555
|
+
`+w.text(`Title: ${I.title}`)+`
|
|
556
|
+
`+w.text(`Status: ${xi(I.status)}`)+`
|
|
557
|
+
`+w.text(`Priority: ${V[e(I.priority)](I.priority)}`)+`
|
|
558
|
+
|
|
559
|
+
`+i+a+`
|
|
560
|
+
`+w.text.bold(`Next Steps:`)+`
|
|
561
|
+
`+V.cyan(`1. Run ${V.yellow(`taskgraph show ${v}`)} to see complete task details`)+`
|
|
562
|
+
`+V.cyan(`2. Run ${V.yellow(`taskgraph set-status --id=${v} --status=in-progress`)} to start working on it`)+`
|
|
563
|
+
`+V.cyan(`3. Run ${V.yellow(`taskgraph expand --id=${v}`)} to break it down into subtasks`),{padding:1,borderColor:`green`,borderStyle:`round`})),D&&D.telemetryData&&(g===`cli`||g===`text`)&&Q(D.telemetryData,`cli`)}return O(`DEBUG: Returning new task ID: ${v} and telemetry.`,`debug`),{newTaskId:v,telemetryData:D?D.telemetryData:null,tagInfo:D?D.tagInfo:null}}catch(e){throw T&&Z(T),s!==`text`&&O(`Error adding task: ${e.message}`,`error`),e}}const lt={research:{threshold:.5,limit:20,keys:[{name:`title`,weight:2},{name:`description`,weight:1},{name:`details`,weight:.5},{name:`dependencyTitles`,weight:.5}]},addTask:{threshold:.4,limit:15,keys:[{name:`title`,weight:2},{name:`description`,weight:1.5},{name:`details`,weight:.8},{name:`dependencyTitles`,weight:.5}]},default:{threshold:.4,limit:15,keys:[{name:`title`,weight:2},{name:`description`,weight:1.5},{name:`details`,weight:1},{name:`dependencyTitles`,weight:.5}]}},ut=[{pattern:/(command|cli|flag)/i,label:`CLI commands`},{pattern:/(task|subtask|add)/i,label:`Task management`},{pattern:/(dependency|depend)/i,label:`Dependency handling`},{pattern:/(AI|model|prompt|research)/i,label:`AI integration`},{pattern:/(UI|display|show|interface)/i,label:`User interface`},{pattern:/(schedule|time|cron)/i,label:`Scheduling`},{pattern:/(config|setting|option)/i,label:`Configuration`},{pattern:/(test|testing|spec)/i,label:`Testing`},{pattern:/(auth|login|user)/i,label:`Authentication`},{pattern:/(database|db|data)/i,label:`Data management`},{pattern:/(api|endpoint|route)/i,label:`API development`},{pattern:/(deploy|build|release)/i,label:`Deployment`},{pattern:/(security|auth|login|user)/i,label:`Security`},{pattern:/.*/,label:`Other`}],dt={high:.25,medium:.4,low:.6};var ft=class{constructor(e,t=`default`){this.tasks=e,this.config=lt[t]||lt.default,this.searchableTasks=this._prepareSearchableTasks(e),this.fuse=new Se(this.searchableTasks,{includeScore:!0,threshold:this.config.threshold,keys:this.config.keys,shouldSort:!0,useExtendedSearch:!0,limit:this.config.limit})}_prepareSearchableTasks(e){return e.map(t=>{let n=t.dependencies?.length>0?t.dependencies.map(t=>{let n=e.find(e=>e.id===t);return n?n.title:``}).filter(e=>e).join(` `):``;return{...t,dependencyTitles:n}})}_extractPromptWords(e){return e.toLowerCase().replace(/[^\w\s-]/g,` `).split(/\s+/).filter(e=>e.length>3)}findRelevantTasks(e,t={}){let{maxResults:n=8,includeRecent:r=!0,includeCategoryMatches:i=!0}=t,a=this._extractPromptWords(e),o=this.fuse.search(e),s=[];for(let e of a)if(e.length>5){let t=this.fuse.search(e);t.length>0&&s.push(...t)}let c=[...o];for(let e of s)c.some(t=>t.item.id===e.item.id)||c.push(e);let l=c.filter(e=>e.score<dt.high).map(e=>({...e.item,score:e.score})),u=c.filter(e=>e.score>=dt.high&&e.score<dt.medium).map(e=>({...e.item,score:e.score})),d=c.filter(e=>e.score>=dt.medium&&e.score<dt.low).map(e=>({...e.item,score:e.score})),f=r?[...this.tasks].sort((e,t)=>t.id-e.id).slice(0,5):[],p=[],m=null;i&&(m=ut.find(t=>t.pattern.test(e)),p=m?this.tasks.filter(e=>m.pattern.test(e.title)||m.pattern.test(e.description)||e.details&&m.pattern.test(e.details)).slice(0,3):[]);let h=[...l];for(let e of u)h.some(t=>t.id===e.id)||h.push(e);for(let e of d)h.some(t=>t.id===e.id)||h.push(e);for(let e of p)h.some(t=>t.id===e.id)||h.push(e);for(let e of f)h.some(t=>t.id===e.id)||h.push(e);let g=h.slice(0,n);return{results:g,breakdown:{highRelevance:l,mediumRelevance:u,lowRelevance:d,categoryTasks:p,recentTasks:f,promptCategory:m,promptWords:a},metadata:{totalSearched:this.tasks.length,fuzzyMatches:o.length,wordMatches:s.length,finalCount:g.length}}}getTaskIds(e){return e.results.map(e=>e.id.toString())}getTaskIdsWithSubtasks(e,t=!1){let n=[];for(let r of e.results)if(n.push(r.id.toString()),t&&r.subtasks&&r.subtasks.length>0)for(let e of r.subtasks)n.push(`${r.id}.${e.id}`);return n}formatSearchSummary(e,t={}){let{includeScores:n=!1,includeBreakdown:r=!1}=t,{results:i,breakdown:a,metadata:o}=e,s=`Found ${i.length} relevant tasks from ${o.totalSearched} total tasks`;if(r&&a){let e=[];a.highRelevance.length>0&&e.push(`${a.highRelevance.length} high relevance`),a.mediumRelevance.length>0&&e.push(`${a.mediumRelevance.length} medium relevance`),a.lowRelevance.length>0&&e.push(`${a.lowRelevance.length} low relevance`),a.categoryTasks.length>0&&e.push(`${a.categoryTasks.length} category matches`),e.length>0&&(s+=` (${e.join(`, `)})`),a.promptCategory&&(s+=`\nCategory detected: ${a.promptCategory.label}`)}return s}};function pt(e,t){let n=H.relative(t||process.cwd(),e);return n&&!n.startsWith(`..`)?n:e}async function mt(e,t={}){let{session:n,mcpLog:i}=t,a=e.file||`.taskgraph/tasks/tasks.json`,s=parseFloat(e.threshold||`5`),l=e.research||!1,d=e.projectRoot,f=e.tag,m=e.id?e.id.split(`,`).map(e=>parseInt(e.trim(),10)).filter(e=>!Number.isNaN(e)):null,h=e.from===void 0?null:parseInt(e.from,10),g=e.to===void 0?null:parseInt(e.to,10),_=i?`json`:`text`,v=(e,t=`info`)=>{i?i[t](e):!p()&&_===`text`&&o(t===`warn`||t===`error`?t:`debug`,e)},y=re(e.output,{projectRoot:d,tag:f},v);try{v(`Reading tasks from ${a}...`,`info`);let t,p=0,b=null,x=0;if(e._filteredTasksData){if(t=e._filteredTasksData,p=e._originalTaskCount||t.tasks.length,!e._originalTaskCount)try{b=P(a,d,f),b&&b.tasks&&(p=b.tasks.length)}catch(e){o(`warn`,`Could not read original tasks file: ${e.message}`)}}else{if(b=P(a,d,f),!b||!b.tasks||!Array.isArray(b.tasks)||b.tasks.length===0)throw Error(`No tasks found in the tasks file`);p=b.tasks.length;let e=[`pending`,`blocked`,`in-progress`],n=t=>e.includes(t.status?.toLowerCase()||`pending`),r=()=>!0,i=b.tasks.filter(n);if(m&&m.length>0){if(v(`Filtering tasks by specific IDs: ${m.join(`, `)}`,`info`),r=e=>m.includes(e.id),i=i.filter(r),_===`text`){if(i.length===0&&m.length>0)console.log(V.yellow(`Warning: No active tasks found with IDs: ${m.join(`, `)}`));else if(i.length<m.length){let e=i.map(e=>e.id),t=m.filter(t=>!e.includes(t));console.log(V.yellow(`Warning: Some requested task IDs were not found or are not active: ${t.join(`, `)}`))}}}else if(h!==null||g!==null){let e=h===null?1:h,t=g===null?Math.max(...b.tasks.map(e=>e.id)):g;v(`Filtering tasks by ID range: ${e} to ${t}`,`info`),r=n=>n.id>=e&&n.id<=t,i=i.filter(r),_===`text`&&i.length===0&&console.log(V.yellow(`Warning: No active tasks found in range: ${e}-${t}`))}x=b.tasks.filter(e=>r(e)&&!n(e)).length,t={...b,tasks:i,_originalTaskCount:p}}let C=``;if(b&&b.tasks.length>0)try{let e=new ot(d,f),n=new ft(u(b.tasks),`analyze-complexity`),r=t.tasks.map(e=>`${e.title} ${e.description}`).join(` `),i=n.findRelevantTasks(r,{maxResults:10}),a=n.getTaskIds(i);a.length>0&&(C=(await e.gather({tasks:a,format:`research`})).context||``)}catch(e){v(`Could not gather additional context: ${e.message}`,`warn`)}v(`Found ${p} total tasks in the task file.`,`info`),m||h!==null||g!==null?v(m?`Analyzing ${t.tasks.length} tasks with specific IDs: ${m.join(`, `)}`:`Analyzing ${t.tasks.length} tasks in range: ${h||1} to ${g||`end`}`,`info`):x>0&&v(`Skipping ${x} tasks marked as done/cancelled/deferred. Analyzing ${t.tasks.length} active tasks.`,`info`);let w=null,T=/* @__PURE__ */ new Map;try{W.existsSync(y)&&(w=JSON.parse(W.readFileSync(y,`utf8`)),v(`Found existing complexity report at ${y}`,`info`),w&&w.complexityAnalysis&&Array.isArray(w.complexityAnalysis)&&(w.complexityAnalysis.forEach(e=>{T.set(e.taskId,e)}),v(`Existing report contains ${w.complexityAnalysis.length} task analyses`,`info`)))}catch(e){v(`Warning: Could not read existing report: ${e.message}`,`warn`),w=null,T.clear()}if(t.tasks.length===0){if(w&&(m||h!==null||g!==null))return v(`No matching tasks found for analysis. Keeping existing report.`,`info`),_===`text`&&console.log(V.dim(`The complexity report is unchanged`)),{report:w,telemetryData:null};let e={meta:{generatedAt:(/* @__PURE__ */ new Date()).toISOString(),tasksAnalyzed:0,thresholdScore:s,projectName:S(n),usedResearch:l},complexityAnalysis:w?.complexityAnalysis||[]};return v(`Writing complexity report to ${y}...`,`info`),W.writeFileSync(y,JSON.stringify(e,null,` `),`utf8`),v(`Task complexity analysis complete. Report written to ${y}`,`success`),_===`text`&&console.log(oe({analyses:[],skipped:x,kept:0,reportPath:pt(y,d)})),{report:e,telemetryData:null}}let E=it(),D={tasks:t.tasks,gatheredContext:C||``,useResearch:l,hasCodebaseAnalysis:c(l,d,n),projectRoot:d||``},{systemPrompt:O,userPrompt:A}=await E.loadPrompt(`analyze-complexity`,D,`default`),j=null;if(_===`text`){let e=t.tasks.length;j=X(`Analyzing ${e} ${e===1?`task`:`tasks`}${l?` with web research`:``}…`)}let M=null,N=null;try{M=await r({prompt:A,systemPrompt:O,role:l?`research`:`main`,session:n,projectRoot:d,schema:Ke[`analyze-complexity`],objectName:`complexityAnalysis`,commandName:`analyze-complexity`,outputType:i?`mcp`:`cli`}),j&&=(Z(j),null),N=M.mainResult?.complexityAnalysis,v(`Received ${N.length} complexity analyses from AI.`,`info`);let e=t.tasks.map(e=>e.id),a=N.map(e=>e.taskId),o=e.filter(e=>!a.includes(e));if(o.length>0){v(`Missing analysis for ${o.length} tasks: ${o.join(`, `)}`,`warn`);for(let e of o){let n=t.tasks.find(t=>t.id===e);n&&(v(`Adding default analysis for task ${e}`,`info`),N.push({taskId:e,taskTitle:n.title,complexityScore:5,recommendedSubtasks:3,expansionPrompt:`Break down this task with a focus on ${n.title.toLowerCase()}.`,reasoning:`Automatically added due to missing analysis in AI response.`}))}}let c=[];if(w&&Array.isArray(w.complexityAnalysis)){let e=new Set(N.map(e=>e.taskId)),n=new Set(t.tasks.map(e=>e.id)),r=w.complexityAnalysis.filter(t=>!e.has(t.taskId)&&n.has(t.taskId));c=[...r,...N],v(`Merged ${N.length} new analyses with ${r.length} existing entries from current tag`,`info`)}else c=N;let u={meta:{generatedAt:(/* @__PURE__ */ new Date()).toISOString(),tasksAnalyzed:t.tasks.length,totalTasks:p,analysisCount:c.length,thresholdScore:s,projectName:S(n),usedResearch:l},complexityAnalysis:c};return v(`Writing complexity report to ${y}...`,`info`),W.writeFileSync(y,JSON.stringify(u,null,` `),`utf8`),v(`Task complexity analysis complete. Report written to ${y}`,`success`),_===`text`&&(console.log(oe({analyses:N,skipped:x,kept:c.length-N.length,reportPath:pt(y,d),usedResearch:l})),k(n)&&console.debug(V.dim(`Final analysis object: ${JSON.stringify(u,null,2)}`)),M.telemetryData&&Q(M.telemetryData,`cli`)),{report:u,telemetryData:M?.telemetryData,tagInfo:M?.tagInfo}}catch(e){throw j&&Z(j),i&&v(`Error during AI service call: ${e.message}`,`error`),e}}catch(e){if(i&&v(`Error analyzing task complexity: ${e.message}`,`error`),_===`text`)B(`Couldn't analyze task complexity: ${e.message}`),k(n)&&console.error(e),process.exit(1);else throw e}}var ht=class extends Error{constructor(e,t,n){super(t),this.name=`ClearSubtasksError`,this.code=e,this.taskId=n}};function gt(e,t){let n=[...new Set(String(t).split(`,`).map(e=>e.trim()).filter(Boolean))];if(n.length===0)throw new ht(`INVALID_TASK_ID`,`No task IDs given`);return n.map(t=>{if(/^\d+\.\d+/.test(t))throw new ht(`SUBTASK_ID`,`${t} is a subtask, not a task`,t);if(!/^\d+$/.test(t))throw new ht(`INVALID_TASK_ID`,`"${t}" isn't a task ID`,t);let n=e.find(e=>String(e.id)===t);if(!n)throw new ht(`TASK_NOT_FOUND`,`Task ${t} not found`,t);return n})}function _t(e,t,n={}){let{projectRoot:r,tag:i}=n;o(`debug`,`Reading tasks from ${e}...`);let a=P(e,r,i);if(!a||!a.tasks)throw new ht(`NO_TASKS`,`No valid tasks found`);let s=gt(a.tasks,t),c=[],l=[];for(let e of s){let t=e.subtasks?.length??0;t===0?l.push({id:e.id,title:e.title}):(e.subtasks=[],c.push({id:e.id,title:e.title,count:t}),o(`debug`,`Cleared ${t} subtasks from task ${e.id}`))}return c.length>0&&E(e,a,r,i),{cleared:c,empty:l}}function vt(e,t){let n=!!e,r=e||{info:e=>!p()&&o(`info`,e),warn:e=>!p()&&o(`warn`,e),error:e=>!p()&&o(`error`,e),debug:e=>!p()&&k(t)&&o(`debug`,e)};return{logger:r,report:(e,...t)=>{n?typeof r[e]==`function`?r[e](...t):r.info(...t):p()||o(e,...t)},isMCP:n}}async function yt(e,t,n,i=!1,a=``,o={},s=!1){let{session:d,mcpLog:f,projectRoot:p,tag:m,complexityReportPath:h}=o,g=f?`json`:`text`,_=p||l(e),{logger:v,report:y,isMCP:b}=vt(f,d);b&&v.debug(`expandTask called with context: session=${!!d}`);try{v.debug(`Reading tasks from ${e}`);let o=P(e,_,m);if(!o||!o.tasks)throw Error(`Invalid tasks data in ${e}`);let l=o.tasks.findIndex(e=>e.id===parseInt(t,10));if(l===-1)throw Error(`Task ${t} not found`);let f=o.tasks[l];v.debug(`Expanding task ${t}: ${f.title}${i?` with research`:``}`),s&&Array.isArray(f.subtasks)&&f.subtasks.length>0&&(v.debug(`Force flag set. Clearing existing ${f.subtasks.length} subtasks for task ${t}.`),f.subtasks=[]);let p=``;try{let e=new ot(_,m),n=new ft(u(o.tasks),`expand-task`),r=`${f.title} ${f.description}`,i=n.findRelevantTasks(r,{maxResults:5,includeSelf:!0}),a=n.getTaskIds(i),s=[.../* @__PURE__ */ new Set([t.toString(),...a])];s.length>0&&(p=(await e.gather({tasks:s,format:`research`})).context||``)}catch(e){v.warn(`Could not gather context: ${e.message}`)}let y,b=``,x=null;v.debug(`Looking for complexity report at: ${h}${m===`master`?``:` (tag-specific for '${m}')`}`);try{W.existsSync(h)?(x=P(h)?.complexityAnalysis?.find(e=>e.taskId===f.id),x?(v.debug(`Found complexity analysis for task ${f.id}: Score ${x.complexityScore}`),x.reasoning&&(b=`\nComplexity Analysis Reasoning: ${x.reasoning}`)):v.debug(`No complexity analysis found for task ${f.id} in report.`)):v.debug(`Complexity report not found at ${h}. Skipping complexity check.`)}catch(e){v.warn(`Could not read or parse complexity report: ${e.message}. Proceeding without it.`)}let S=parseInt(n,10);if(!Number.isNaN(S)&&S>=0)y=S,v.debug(`Using explicitly provided subtask count: ${y}`);else if(x?.recommendedSubtasks!=null){if(y=parseInt(x.recommendedSubtasks,10),v.debug(`Using subtask count from complexity report: ${y}`),y===0)return v.debug(`Complexity report recommends no expansion for task ${t}. Skipping.`),{task:f,skipped:!0}}else y=T(d),v.debug(`Using default number of subtasks: ${y}`);(Number.isNaN(y)||y<0)&&(v.warn(`Invalid subtask count determined (${y}), defaulting to 3.`),y=3);let C=(f.subtasks?.length||0)+1,w=it(),D=c(i,_,d),O=``;(a||b)&&(O=`\n\n${a}${b}`.trim()),p&&(O=`${O}\n\n# Project Context\n\n${p}`.trim());let k;x?.expansionPrompt&&(typeof x.expansionPrompt==`string`?k=x.expansionPrompt:typeof x.expansionPrompt==`object`&&x.expansionPrompt.text&&(k=x.expansionPrompt.text));let A=p;typeof p==`object`&&p&&(A=p.data?p.data:p.text?p.text:JSON.stringify(p));let j={task:f,subtaskCount:y,nextSubtaskId:C,additionalContext:a,complexityReasoningContext:b,gatheredContext:A||``,useResearch:i,expansionPrompt:k||void 0,hasCodebaseAnalysis:D,projectRoot:_||``},M=`default`;k?(M=`complexity-report`,v.debug(`Using expansion prompt from complexity report for task ${f.id}.`)):i?(M=`research`,v.debug(`Using research variant for task ${f.id}.`)):v.debug(`Using standard prompt generation for task ${f.id}.`);let{systemPrompt:N,userPrompt:F}=w.loadPrompt(`expand-task`,j,M);v.debug(`Selected variant: ${M}`),v.debug(`Prompt params passed: ${JSON.stringify(j,null,2)}`),v.debug(`System prompt (first 500 chars): ${N.substring(0,500)}...`),v.debug(`User prompt (first 500 chars): ${F.substring(0,500)}...`);let ee=[],I=null;g===`text`&&(I=X(`Breaking task ${f.id} into ${y||`a few`} subtasks…`));let L=null;try{L=await r({prompt:F,systemPrompt:N,role:i?`research`:`main`,session:d,projectRoot:_,schema:Ke[`expand-task`],objectName:`subtasks`,commandName:`expand-task`,outputType:g});let e=L?.mainResult;if(!e||!Array.isArray(e.subtasks))throw Error(`AI response did not include a valid subtasks array.`);ee=e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})),v.debug(`Received ${ee.length} subtasks from AI.`)}catch(e){throw I&&Z(I),e}finally{I&&Z(I)}return Array.isArray(f.subtasks)||(f.subtasks=[]),f.subtasks.push(...ee),o.tasks[l]=f,E(e,o,_,m),g===`text`&&Di(f.id,ee),g===`text`&&L&&L.telemetryData&&Q(L.telemetryData,`cli`),{task:f,telemetryData:L?.telemetryData,tagInfo:L?.tagInfo}}catch(e){throw g!==`text`&&v.error(`Error expanding task ${t}: ${e.message}`,`error`),e}}async function bt(e,t,n=!1,r=``,i=!1,a={},s=`text`){let{session:c,mcpLog:u,projectRoot:d,tag:f,complexityReportPath:h}=a,g=!!u,_=d||l();if(!_)throw Error(`Could not determine project root directory`);let v=u||(s===`json`?{info:e=>{},warn:e=>{},error:e=>console.error(`ERROR: ${e}`),debug:e=>{}}:{info:e=>!p()&&o(`info`,e),warn:e=>!p()&&o(`warn`,e),error:e=>!p()&&o(`error`,e),debug:e=>!p()&&k(c)&&o(`debug`,e)}),y=null,b=0,x=0,S=0,C=0,T=[];!g&&s===`text`&&(y=X(`Analyzing tasks for expansion...`));try{v.debug(`Reading tasks from ${e}`);let o=P(e,_,f);if(!o||!o.tasks)throw Error(`Invalid tasks data in ${e}`);let c=o.tasks.filter(e=>(e.status===`pending`||e.status===`in-progress`)&&(!e.subtasks||e.subtasks.length===0||i));if(C=c.length,v.info(`Found ${C} tasks eligible for expansion.`),y&&Z(y,`Analysis complete.`),C===0)return v.info(`No tasks eligible for expansion.`),{success:!0,expandedCount:0,failedCount:0,skippedCount:0,tasksToExpand:0,telemetryData:T,message:`No tasks eligible for expansion.`};for(let l of c){let c=null;!g&&s===`text`&&(c=X(`Expanding task ${l.id}...`));try{let s=await yt(e,l.id,t,n,r,{...a,projectRoot:_,tag:o.tag||f,complexityReportPath:h},i);if(s?.skipped){S++,c&&Z(c,`Task ${l.id} skipped (no expansion recommended).`),v.info(`Skipped task ${l.id}: complexity report recommends no expansion.`);continue}b++,s&&s.telemetryData&&T.push(s.telemetryData),c&&Z(c,`Task ${l.id} expanded.`),v.info(`Successfully expanded task ${l.id}.`)}catch(e){x++,c&&Z(c,`Failed to expand task ${l.id}.`,!1),v.error(`Failed to expand task ${l.id}: ${e.message}`)}}v.info(`Expansion complete: ${b} expanded, ${S} skipped, ${x} failed.`);let l=m(T,`expand-all-tasks`);if(s===`text`){let e=`${w.text.bold(`Expansion Summary:`)}\n\n${V.cyan(`-`)} Attempted: ${V.bold(C)}\n${V.green(`-`)} Expanded: ${V.bold(b)}\n${w.muted(`-`)} Skipped: ${V.bold(S)}\n${V.red(`-`)} Failed: ${V.bold(x)}`;console.log(G(e,{padding:1,margin:{top:1},borderColor:x>0?`red`:`green`,borderStyle:`round`}))}return s===`text`&&l&&Q(l,`cli`),{success:!0,expandedCount:b,failedCount:x,skippedCount:S,tasksToExpand:C,telemetryData:l}}catch(e){throw y&&Z(y,`Error.`,!1),v.error(`Error during expand all operation: ${e.message}`),!g&&k(c)&&console.error(e),e}}function xt(e,t,n){if(t.parentTaskId===n||t.dependencies&&t.dependencies.includes(n))return!0;if(t.dependencies)for(let r of t.dependencies){let t=e.find(e=>e.id===r);if(t&&xt(e,t,n))return!0}if(t.subtasks){for(let r of t.subtasks)if(xt(e,r,n))return!0}return!1}async function St(e,t,n=null,r=!1,a=`text`,c={}){let{projectRoot:l,tag:u}=c;try{let c;try{let e=await(await i({projectPath:l||process.cwd()})).tasks.list({tag:u});c={tasks:e.tasks},o(`debug`,`Loaded ${e.tasks.length} tasks via tm-core`)}catch(t){o(`warn`,`TmCore failed, falling back to legacy readJSON: ${t.message}`),c=P(e,l,u)}if(!c||!c.tasks)throw Error(`No valid tasks found in ${e}`);let d=O(n);d&&d.complexityAnalysis&&c.tasks.forEach(e=>s(e,d));let f;if(t&&t.toLowerCase()!==`all`){let e=t.split(`,`).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0);f=c.tasks.filter(t=>t.status&&e.includes(t.status.toLowerCase()))}else f=c.tasks;let p=c.tasks.length,m=c.tasks.filter(e=>e.status===`done`||e.status===`completed`).length,h=p>0?m/p*100:0,g=m,_=c.tasks.filter(e=>e.status===`in-progress`).length,v=c.tasks.filter(e=>e.status===`pending`).length,b=c.tasks.filter(e=>e.status===`blocked`).length,x=c.tasks.filter(e=>e.status===`deferred`).length,S=c.tasks.filter(e=>e.status===`cancelled`).length,C=c.tasks.filter(e=>e.status===`review`).length,w=0,T=0,E=0,D=0,k=0,A=0,j=0,N=0;c.tasks.forEach(e=>{e.subtasks&&e.subtasks.length>0&&(w+=e.subtasks.length,T+=e.subtasks.filter(e=>e.status===`done`||e.status===`completed`).length,E+=e.subtasks.filter(e=>e.status===`in-progress`).length,D+=e.subtasks.filter(e=>e.status===`pending`).length,k+=e.subtasks.filter(e=>e.status===`blocked`).length,A+=e.subtasks.filter(e=>e.status===`deferred`).length,j+=e.subtasks.filter(e=>e.status===`cancelled`).length,N+=e.subtasks.filter(e=>e.status===`review`).length)});let F=w>0?T/w*100:0,ee=new Set(c.tasks.filter(e=>e.status===`done`||e.status===`completed`).map(e=>e.id)),I=c.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&(!e.dependencies||e.dependencies.length===0)).length,L=c.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>ee.has(e))).length,te=c.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&!e.dependencies.every(e=>ee.has(e))).length,ne=I+L,re={};c.tasks.forEach(e=>{e.dependencies&&e.dependencies.length>0&&e.dependencies.forEach(e=>{re[e]=(re[e]||0)+1})});let R=null,ie=0;for(let[e,t]of Object.entries(re))t>ie&&(ie=t,R=parseInt(e));let ae=R===null?null:c.tasks.find(e=>e.id===R),oe=c.tasks.reduce((e,t)=>e+(t.dependencies?t.dependencies.length:0),0)/c.tasks.length,z=de(c.tasks,d);if(a===`json`)return{tasks:f.map(e=>{let{details:t,...n}=e;return n.subtasks&&Array.isArray(n.subtasks)&&(n.subtasks=n.subtasks.map(e=>{let{details:t,...n}=e;return n})),n}),filter:t||`all`,stats:{total:p,completed:g,inProgress:_,pending:v,blocked:b,deferred:x,cancelled:S,review:C,completionPercentage:h,subtasks:{total:w,completed:T,inProgress:E,pending:D,blocked:k,deferred:A,cancelled:j,completionPercentage:F}}};if(a===`markdown-readme`)return wt(c,f,{totalTasks:p,completedTasks:m,completionPercentage:h,doneCount:g,inProgressCount:_,pendingCount:v,blockedCount:b,deferredCount:x,cancelledCount:S,totalSubtasks:w,completedSubtasks:T,subtaskCompletionPercentage:F,inProgressSubtasks:E,pendingSubtasks:D,blockedSubtasks:k,deferredSubtasks:A,cancelledSubtasks:j,reviewSubtasks:N,tasksWithNoDeps:I,tasksReadyToWork:ne,tasksWithUnsatisfiedDeps:te,mostDependedOnTask:ae,mostDependedOnTaskId:R,maxDependents:ie,avgDependenciesPerTask:oe,complexityReport:d,withSubtasks:r,nextItem:z});if(a===`compact`)return Ot(f,r);let se={"in-progress":p>0?_/p*100:0,pending:p>0?v/p*100:0,blocked:p>0?b/p*100:0,deferred:p>0?x/p*100:0,cancelled:p>0?S/p*100:0,review:p>0?C/p*100:0},ce={"in-progress":w>0?E/w*100:0,pending:w>0?D/w*100:0,blocked:w>0?k/w*100:0,deferred:w>0?A/w*100:0,cancelled:w>0?j/w*100:0,review:w>0?N/w*100:0},le=bi(h,30,se),ue=bi(F,30,ce),B;try{B=process.stdout.columns}catch{o(`debug`,`Could not determine terminal width, using default`)}B||=80,B=Math.max(B,80);let fe=V.bold(`Project Dashboard`)+`
|
|
564
|
+
Tasks Progress: ${V.greenBright(le)} ${h.toFixed(0)}%\n${V.green(`█`)} Done: ${V.green(g)} ${V.cyan(`▓`)} In Progress: ${V.cyan(_)} ${V.yellow(`░`)} Pending: ${V.yellow(v)} ${V.red(`!`)} Blocked: ${V.red(b)} ${Y.muted(`─`)} Deferred: ${Y.muted(x)} ${Y.muted(`─`)} Cancelled: ${Y.muted(S)}\n\nSubtasks Progress: ${V.cyan(ue)} ${F.toFixed(0)}%\n${V.green(`█`)} Completed: ${V.green(T)}/${w} ${V.cyan(`▓`)} In Progress: ${V.cyan(E)} ${V.yellow(`░`)} Pending: ${V.yellow(D)} ${V.red(`!`)} Blocked: ${V.red(k)} ${Y.muted(`─`)} Deferred: ${Y.muted(A)} ${Y.muted(`─`)} Cancelled: ${Y.muted(j)}\n\n`+V.cyan.bold(`Priority Breakdown:`)+`
|
|
565
|
+
${V.red(`•`)} ${V.reset(`High priority:`)} ${c.tasks.filter(e=>e.priority===`high`).length}\n${V.yellow(`•`)} ${V.reset(`Medium priority:`)} ${c.tasks.filter(e=>e.priority===`medium`).length}\n${V.green(`•`)} ${V.reset(`Low priority:`)} ${c.tasks.filter(e=>e.priority===`low`).length}`,pe=V.bold(`Dependency Status & Next Task`)+`
|
|
566
|
+
`+V.cyan.bold(`Dependency Metrics:`)+`
|
|
567
|
+
${V.green(`•`)} ${V.reset(`Tasks with no dependencies:`)} ${I}\n${V.green(`•`)} ${V.reset(`Tasks ready to work on:`)} ${ne}\n${V.yellow(`•`)} ${V.reset(`Tasks blocked by dependencies:`)} ${te}\n${V.magenta(`•`)} ${V.reset(`Most depended-on task:`)} ${ae?V.cyan(`#${R} (${ie} dependents)`):Y.muted(`None`)}\n${V.cyan(`•`)} ${V.reset(`Avg dependencies per task:`)} ${oe.toFixed(1)}\n\n`+V.cyan.bold(`Next Task:`)+`
|
|
568
|
+
ID: ${V.cyan(z?z.id:`N/A`)} - ${z?V.bold(y(z.title,40)):V.yellow(`No task available`)}
|
|
569
|
+
Priority: ${z?V.reset(z.priority||`medium`):``} Dependencies: ${z?Si(z.dependencies,c.tasks,!0,d):``}
|
|
570
|
+
Complexity: ${z&&z.complexityScore?wi(z.complexityScore):Y.muted(`N/A`)}`;if(B>=104){let e=Math.floor(B/2),t=e-4,n=G(fe,{padding:1,borderColor:fi,borderStyle:`round`,width:t,dimBorder:!1}),r=G(pe,{padding:1,borderColor:`magenta`,borderStyle:`round`,width:t,dimBorder:!1}),i=n.split(`
|
|
571
|
+
`),a=r.split(`
|
|
572
|
+
`),o=Math.max(i.length,a.length),s=[];for(let t=0;t<o;t++){let n=t<i.length?i[t]:``,r=t<a.length?a[t]:``,o=n.trimEnd().padEnd(e,` `);s.push(o+r)}console.log(s.join(`
|
|
573
|
+
`))}else{let e=G(fe,{padding:1,borderColor:fi,borderStyle:`round`,margin:{top:0,bottom:1}}),t=G(pe,{padding:1,borderColor:`magenta`,borderStyle:`round`,margin:{top:0,bottom:1}});console.log(e),console.log(t)}if(f.length===0){console.log(G(t?V.yellow(`No tasks with status '${t}' found`):V.yellow(`No tasks found`),{padding:1,borderColor:`yellow`,borderStyle:`round`}));return}let me=r?10:7,H=100-me-15-12-20-10,U=B-10,W=Math.floor(me/100*U),ge=Math.floor(15/100*U),_e=Math.floor(12/100*U),ve=Math.floor(20/100*U),be=Math.floor(10/100*U),xe=Math.floor(H/100*U),Se=new ye({head:[V.cyan.bold(`ID`),V.cyan.bold(`Title`),V.cyan.bold(`Status`),V.cyan.bold(`Priority`),V.cyan.bold(`Dependencies`),V.cyan.bold(`Complexity`)],colWidths:[W,xe,ge,_e,ve,be],style:{head:[],border:[],compact:!1},wordWrap:!0,wrapOnWordBoundary:!0});f.forEach(e=>{let t=`None`;t=e.dependencies&&e.dependencies.length>0?Si(e.dependencies,c.tasks,!0,d):Y.muted(`None`);let n=e.title.replace(/\n/g,` `),i={high:V.red,medium:V.yellow,low:Y.muted}[e.priority||`medium`]||V.reset,a=xi(e.status,!0);Se.push([e.id.toString(),y(n,xe-3),a,i(y(e.priority||`medium`,_e-2)),t,e.complexityScore?wi(e.complexityScore):Y.muted(`N/A`)]),r&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(t=>{let n=`None`;t.dependencies&&t.dependencies.length>0&&(n=t.dependencies.map(t=>{if(typeof t==`number`&&t<100){let n=e.subtasks.find(e=>e.id===t);if(n){let r=n.status===`done`||n.status===`completed`,i=n.status===`in-progress`;return r?V.green.bold(`${e.id}.${t}`):i?Y.active.bold(`${e.id}.${t}`):V.red.bold(`${e.id}.${t}`)}}let n=c.tasks.find(e=>e.id===t);if(n){s(n,d);let e=n.status===`done`||n.status===`completed`,r=n.status===`in-progress`;return e?V.green.bold(`${t}`):r?Y.active.bold(`${t}`):V.red.bold(`${t}`)}return V.cyan(t.toString())}).join(`, `)||Y.muted(`None`)),Se.push([`${e.id}.${t.id}`,V.dim(`└─ ${y(t.title,xe-5)}`),xi(t.status,!0),V.dim(`-`),n,t.complexityScore?Y.muted(`${t.complexityScore}`):Y.muted(`N/A`)])})});try{console.log(Se.toString())}catch(e){o(`error`,`Error rendering table: ${e.message}`),console.log(V.yellow(`
|
|
574
|
+
Falling back to simple task list due to terminal width constraints:`)),f.forEach(e=>{console.log(`${V.cyan(e.id)}: ${V.reset(e.title)} - ${xi(e.status)}`)})}t&&(console.log(V.yellow(`\nFiltered by status: ${t}`)),console.log(V.yellow(`Showing ${f.length} of ${p} tasks`)));let Ce={high:V.red.bold,medium:V.yellow,low:Y.muted};if(z){let e=``,t=c.tasks.find(e=>String(e.id)===String(z.id));t&&t.subtasks&&t.subtasks.length>0&&(e=`\n\n${V.bold(`Subtasks:`)}\n`,e+=t.subtasks.map(e=>{s(e,d);let n=e.status||`pending`,r={done:V.green,completed:V.green,pending:V.yellow,"in-progress":V.cyan,deferred:Y.muted,blocked:V.red,cancelled:Y.muted}[n.toLowerCase()]||V.reset;return`${V.cyan(`${t.id}.${e.id}`)} [${r(n)}] ${e.title}`}).join(`
|
|
575
|
+
`));let n=he(z.id,z.status,!!t?.subtasks?.length).slice(0,2).map(e=>`${V.cyan(`Next step:`)} ${V.yellow(e.command)} ${Y.muted(e.description)}`).join(`
|
|
576
|
+
`);console.log(G(Y.heading(`Next task: #${z.id} - ${z.title}`)+`
|
|
577
|
+
|
|
578
|
+
${V.reset(`Priority:`)} ${Ce[z.priority||`medium`](z.priority||`medium`)} ${V.reset(`Status:`)} ${xi(z.status,!0)}\n${V.reset(`Dependencies:`)} ${z.dependencies&&z.dependencies.length>0?Si(z.dependencies,c.tasks,!0,d):Y.muted(`None`)}\n\n${V.reset(`Description:`)} ${Ct(z,c.tasks)}`+e+`
|
|
579
|
+
|
|
580
|
+
${n}\n${V.cyan(`View details:`)} ${V.yellow(`taskgraph show ${z.id}`)}`,{padding:{left:2,right:2,top:1,bottom:1},borderColor:fi,borderStyle:`round`,margin:{top:1,bottom:1},title:`Next task`,titleAlignment:`center`,width:B-4,fullscreen:!1}))}else console.log(G(Y.heading(`No eligible next task found`)+`
|
|
581
|
+
|
|
582
|
+
All pending tasks have dependencies that are not yet completed, or all tasks are done.`,{padding:1,borderColor:fi,borderStyle:`round`,margin:{top:1,bottom:1},title:`Next task`,titleAlignment:`center`,width:B-4}));console.log(G(V.bold(`Suggested Next Steps:`)+`
|
|
583
|
+
|
|
584
|
+
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph next`)} to see what to work on next\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph set-status --id=<id> --status=done`)} to mark a task as complete`,{padding:1,...M,borderStyle:`round`,margin:{top:1}}))}catch(e){if(o(`error`,`Error listing tasks: ${e.message}`),a===`json`)throw{code:`TASK_LIST_ERROR`,message:e.message,details:e.stack};console.error(V.red(`Error: ${e.message}`)),process.exit(1)}}function Ct(e,t){if(!e)return`N/A`;if(e.parentId){let n=t.find(t=>t.id===e.parentId);return n?.subtasks?.find(t=>`${n.id}.${t.id}`===e.id)?.description||`No description available.`}return t.find(t=>String(t.id)===String(e.id))?.description||`No description available.`}function wt(e,t,n){let{totalTasks:r,completedTasks:i,completionPercentage:a,doneCount:o,inProgressCount:s,pendingCount:c,blockedCount:l,deferredCount:u,cancelledCount:d,totalSubtasks:f,completedSubtasks:p,subtaskCompletionPercentage:m,inProgressSubtasks:h,pendingSubtasks:g,blockedSubtasks:_,deferredSubtasks:v,cancelledSubtasks:y,tasksWithNoDeps:b,tasksReadyToWork:x,tasksWithUnsatisfiedDeps:S,mostDependedOnTask:C,mostDependedOnTaskId:w,maxDependents:T,avgDependenciesPerTask:E,complexityReport:D,withSubtasks:O,nextItem:k}=n,A=``,j=(e,t=20)=>{let n=Math.round(e/100*t),r=t-n;return`█`.repeat(n)+`░`.repeat(r)},M=j(a,20),N=j(m,20);A+=`| Project Dashboard | |
|
|
585
|
+
`,A+=`| :- |:-|
|
|
586
|
+
`,A+=`| Task Progress | ${M} ${Math.round(a)}% |\n`,A+=`| Done | ${o} |\n`,A+=`| In Progress | ${s} |\n`,A+=`| Pending | ${c} |\n`,A+=`| Deferred | ${u} |\n`,A+=`| Cancelled | ${d} |\n`,A+=`|-|-|
|
|
587
|
+
`,A+=`| Subtask Progress | ${N} ${Math.round(m)}% |\n`,A+=`| Completed | ${p} |\n`,A+=`| In Progress | ${h} |\n`,A+=`| Pending | ${g} |\n`,A+=`
|
|
588
|
+
|
|
589
|
+
`,A+=`| ID | Title | Status | Priority | Dependencies | Complexity |
|
|
590
|
+
`,A+=`| :- | :- | :- | :- | :- | :- |
|
|
591
|
+
`;let P=e=>{switch(e){case`done`:case`completed`:return`✓ done`;case`in-progress`:return`► in-progress`;case`pending`:return`○ pending`;case`blocked`:return`⭕ blocked`;case`deferred`:return`x deferred`;case`cancelled`:return`x cancelled`;case`review`:return`? review`;default:return e||`pending`}},F=(e,t)=>!e||e.length===0?`None`:e.map(e=>(t.find(t=>t.id===e),e.toString())).join(`, `);return t.forEach(t=>{let n=t.title,r=P(t.status),i=t.priority||`medium`,a=F(t.dependencies,e.tasks),o=t.complexityScore?`● ${t.complexityScore}`:`N/A`;A+=`| ${t.id} | ${n} | ${r} | ${i} | ${a} | ${o} |\n`,O&&t.subtasks&&t.subtasks.length>0&&t.subtasks.forEach(n=>{let r=`${n.title}`,i=P(n.status),a=F(n.dependencies,e.tasks),o=n.complexityScore?n.complexityScore.toString():`N/A`;A+=`| ${t.id}.${n.id} | ${r} | ${i} | - | ${a} | ${o} |\n`})}),A}function Tt(e){if(!e||e.length===0)return``;if(e.length>5){let t=e.slice(0,5).join(`,`),n=e.length-5;return` → ${V.cyan(t)}${Y.muted(`... (+`+n+` more)`)}`}return` → ${V.cyan(e.join(`,`))}`}function Et(e,t=50){let n=e.status||`pending`,r=e.priority||`medium`,i=y(e.title||`Untitled`,t),a=xi(n,!0),o={high:V.red,medium:V.yellow,low:Y.muted}[r]||V.reset,s=Tt(e.dependencies);return`${V.cyan(e.id)} ${a} ${V.reset(i)} ${o(`(`+r+`)`)}${s}`}function Dt(e,t,n=47){let r=e.status||`pending`,i=y(e.title||`Untitled`,n),a=xi(r,!0),o=Tt(e.dependencies);return` ${V.cyan(t+`.`+e.id)} ${a} ${V.dim(i)}${o}`}function Ot(e,t){if(e.length===0){console.log(`No tasks found`);return}let n=[];e.forEach(e=>{n.push(Et(e)),t&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(t=>{n.push(Dt(t,e.id))})}),console.log(n.join(`
|
|
592
|
+
`))}function kt(e,t,n={}){return F(e,t,{...n,direction:`forward`,logger:{warn:console.warn}})}var K=class extends Error{constructor(e,t,n={}){super(t),this.name=`MoveTaskError`,this.code=e,this.data=n}};const q={CROSS_TAG_DEPENDENCY_CONFLICTS:`CROSS_TAG_DEPENDENCY_CONFLICTS`,CANNOT_MOVE_SUBTASK:`CANNOT_MOVE_SUBTASK`,SOURCE_TARGET_TAGS_SAME:`SOURCE_TARGET_TAGS_SAME`,TASK_NOT_FOUND:`TASK_NOT_FOUND`,SUBTASK_NOT_FOUND:`SUBTASK_NOT_FOUND`,PARENT_TASK_NOT_FOUND:`PARENT_TASK_NOT_FOUND`,PARENT_TASK_NO_SUBTASKS:`PARENT_TASK_NO_SUBTASKS`,DESTINATION_TASK_NOT_FOUND:`DESTINATION_TASK_NOT_FOUND`,TASK_ALREADY_EXISTS:`TASK_ALREADY_EXISTS`,INVALID_TASKS_FILE:`INVALID_TASKS_FILE`,ID_COUNT_MISMATCH:`ID_COUNT_MISMATCH`,INVALID_SOURCE_TAG:`INVALID_SOURCE_TAG`,INVALID_TARGET_TAG:`INVALID_TARGET_TAG`};function At(e){if(e==null)return e;if(typeof e==`number`)return Number.isFinite(e)?e:null;if(typeof e==`string`){let t=e.trim();if(t===``)return null;let n=t.includes(`.`)?t.split(`.`)[0]:t,r=parseInt(n,10);return Number.isFinite(r)?r:null}return null}async function jt(e,t,n,r=!1,i={}){let{projectRoot:a,tag:s}=i,c=t.split(`,`).map(e=>e.trim()),l=n.split(`,`).map(e=>e.trim());if(c.length!==l.length)throw new K(q.ID_COUNT_MISMATCH,`Number of source IDs (${c.length}) must match number of destination IDs (${l.length})`);if(c.length>1){let t=[];for(let n=0;n<c.length;n++){let r=await jt(e,c[n],l[n],!1,i);t.push(r)}return{message:`Successfully moved ${c.length} tasks/subtasks`,moves:t}}let u=P(e,a,s);if(u&&u._rawTaggedData&&(u=u._rawTaggedData),!u||!u[s]||!Array.isArray(u[s].tasks))throw new K(q.INVALID_TASKS_FILE,`Invalid tasks file or tag "${s}" not found at ${e}`);let d=u[s].tasks;o(`debug`,`Moving task/subtask ${t} to ${n} (tag: ${s})`);let f=t.includes(`.`),p=n.includes(`.`),m;return m=f&&p?Mt(d,t,n):f&&!p?Nt(d,t,n):!f&&p?Pt(d,t,n):Ft(d,t,n),u[s].tasks=d,E(e,u,i.projectRoot,s),m}function Mt(e,t,n){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),[a,o]=n.split(`.`).map(e=>parseInt(e,10)),s=e.find(e=>e.id===r),c=e.find(e=>e.id===a);if(!s)throw new K(q.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!c)throw new K(q.PARENT_TASK_NOT_FOUND,`Destination parent task with ID ${a} not found`);s.subtasks||=[],c.subtasks||=[];let l=s.subtasks.findIndex(e=>e.id===i);if(l===-1)throw new K(q.SUBTASK_NOT_FOUND,`Source subtask ${t} not found`);let u=s.subtasks[l];if(r===a){if(c.subtasks.length>0){let e=c.subtasks.findIndex(e=>e.id===o);if(e!==-1){s.subtasks.splice(l,1);let t=l<e?e-1:e;c.subtasks.splice(t+1,0,u)}else s.subtasks.splice(l,1),c.subtasks.push(u)}else s.subtasks.splice(l,1),c.subtasks.push(u)}else It(u,s,l,c,o);return{message:`Moved subtask ${t} to ${n}`,movedItem:u}}function Nt(e,t,n){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),a=parseInt(n,10),o=e.find(e=>e.id===r);if(!o)throw new K(q.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!o.subtasks)throw new K(q.PARENT_TASK_NO_SUBTASKS,`Source parent task ${r} has no subtasks`);let s=o.subtasks.findIndex(e=>e.id===i);if(s===-1)throw new K(q.SUBTASK_NOT_FOUND,`Source subtask ${t} not found`);let c=o.subtasks[s];if(e.find(e=>e.id===a))throw new K(q.TASK_ALREADY_EXISTS,`Cannot move to existing task ID ${a}. Choose a different ID or use subtask destination.`);let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],priority:c.priority||`medium`,details:c.details||``,testStrategy:c.testStrategy||``,subtasks:[]};o.subtasks.splice(s,1);let u=e.findIndex(e=>e.id>a);return u===-1?e.push(l):e.splice(u,0,l),{message:`Converted subtask ${t} to task ${n}`,movedItem:l}}function Pt(e,t,n){let r=parseInt(t,10),[i,a]=n.split(`.`).map(e=>parseInt(e,10)),o=e.findIndex(e=>e.id===r),s=e.find(e=>e.id===i);if(o===-1)throw new K(q.TASK_NOT_FOUND,`Source task with ID ${r} not found`);if(!s)throw new K(q.PARENT_TASK_NOT_FOUND,`Destination parent task with ID ${i} not found`);let c=e[o];s.subtasks||=[];let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],details:c.details||``,testStrategy:c.testStrategy||``},u=-1;s.subtasks.length>0&&(u=s.subtasks.findIndex(e=>e.id===a),u===-1&&(u=s.subtasks.length-1));let d=u===-1?0:u+1;return s.subtasks.splice(d,0,l),e.splice(o,1),{message:`Converted task ${t} to subtask ${n}`,movedItem:l}}function Ft(e,t,n){let r=parseInt(t,10),i=parseInt(n,10),a=e.findIndex(e=>e.id===r);if(a===-1)throw new K(q.TASK_NOT_FOUND,`Source task with ID ${r} not found`);let o=e[a],s=e.findIndex(e=>e.id===i);if(s!==-1)throw e[s],new K(q.TASK_ALREADY_EXISTS,`Task with ID ${i} already exists. Use a different destination ID.`);return Lt(e,a,o,i)}function It(e,t,n,r,i){let a=parseInt(i,10),o={...e,id:a};r.subtasks||=[];let s=-1;r.subtasks.length>0&&(s=r.subtasks.findIndex(e=>e.id===a),s===-1&&(s=r.subtasks.length-1));let c=s===-1?0:s+1;return r.subtasks.splice(c,0,o),t.subtasks.splice(n,1),o}function Lt(e,t,n,r){let i=e.findIndex(e=>e.id===r),a={...n,id:r};e.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}e.subtasks&&e.subtasks.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}})}),Array.isArray(a.subtasks)&&a.subtasks.forEach(e=>{Array.isArray(e.dependencies)&&(e.dependencies=e.dependencies.map(e=>{if(typeof e==`string`&&e.includes(`.`)){let[t,i]=e.split(`.`);if(parseInt(t,10)===n.id)return`${r}.${i}`}return e}))}),e.splice(t,1);let s=t<i?i-1:i;return s>=0&&s<e.length?e[s]=a:e.push(a),o(`debug`,`Moved task ${n.id} to new ID ${r}`),{message:`Moved task ${n.id} to new ID ${r}`,movedItem:a}}function Rt(e){let t=[];for(let n in e)if(Object.prototype.hasOwnProperty.call(e,n)&&e[n]&&Array.isArray(e[n].tasks)){let r=e[n].tasks.map(e=>({...e,tag:n}));t=t.concat(r)}return t}async function zt(e,t,n,r,i){let{projectRoot:a}=i,s=P(e,a,n);if(s&&s._rawTaggedData&&(s=s._rawTaggedData),!s||!s[n]||!Array.isArray(s[n].tasks))throw new K(q.INVALID_SOURCE_TAG,`Source tag "${n}" not found or invalid`);s[r]||(s[r]={tasks:[]},o(`info`,`Created new tag "${r}"`));let c=t.map(e=>String(e)),l=s[n].tasks.filter(e=>{let t=String(e.id);return c.includes(t)});return t.forEach(e=>{Qi(e,n,r)}),{rawData:s,sourceTasks:l}}async function Bt(e){let{rawData:t,sourceTasks:n}=e;return{rawData:t,sourceTasks:n,allTasks:Rt(t)}}async function Vt(e,t,n,r,i,a){let{withDependencies:s=!1,ignoreDependencies:c=!1}=n,l=Array.isArray(t)?t.filter(e=>e&&e.tag===i):[];if(s){let t=kt(e,l,{maxDepth:100,includeSelf:!1}),n=new Set(l.map(e=>typeof e.id==`string`?parseInt(e.id,10):e.id)),i=t.filter(e=>{let t=At(e);return Number.isFinite(t)&&n.has(t)}),a=[.../* @__PURE__ */ new Set([...r,...i])];return o(`info`,`Moving ${a.length} tasks (including dependencies): ${a.join(`, `)}`),{tasksToMove:a,dependencyResolution:{type:`with-dependencies`,dependentTasks:i}}}let u=Zi(e,i,a,t);if(u.length>0){if(c)return e.forEach(e=>{let n=l,r=Array.isArray(t)?t.filter(e=>e&&e.tag===a):[];e.dependencies=e.dependencies.filter(e=>{let t=At(e);return Number.isFinite(t)&&n.some(e=>e.id===t)?!1:(Number.isFinite(t)&&r.some(e=>e.id===t),!0)})}),o(`warn`,`Removed ${u.length} cross-tag dependencies`),{tasksToMove:r,dependencyResolution:{type:`ignored-dependencies`,conflicts:u}};throw new K(q.CROSS_TAG_DEPENDENCY_CONFLICTS,`Cannot move tasks: ${u.length} cross-tag dependency conflicts found`,{conflicts:u,sourceTag:i,targetTag:a,taskIds:r})}return{tasksToMove:r,dependencyResolution:{type:`no-conflicts`}}}async function Ht(e,t,n,r,i,a){let{projectRoot:s}=i,c=[];for(let i of e){let e=typeof i==`string`?parseInt(i,10):i,a=r[t].tasks.findIndex(t=>t.id===e);if(a===-1)throw new K(q.TASK_NOT_FOUND,`Task ${i} not found in source tag "${t}"`);let s=r[t].tasks[a];if(r[n].tasks.findIndex(t=>t.id===e)!==-1)throw new K(q.TASK_ALREADY_EXISTS,`Task ${i} already exists in target tag "${n}"`,{conflictingId:e,targetTag:n,suggestions:[`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`]});r[t].tasks.splice(a,1);let l=Gt(s,t,n);r[n].tasks.push(l),c.push({id:i,fromTag:t,toTag:n}),o(`debug`,`Moved task ${i} from "${t}" to "${n}"`)}return{rawData:r,movedTasks:c}}async function Ut(e,t,n,r,i,a){let{projectRoot:o}=n,{rawData:s,movedTasks:c}=e;E(t,s,o,null);let l={message:`Successfully moved ${c.length} tasks from "${r}" to "${i}"`,movedTasks:c};return a&&a.type===`ignored-dependencies`&&(l.tips=[`Run "taskgraph validate-dependencies" to check for dependency issues.`,`Run "taskgraph fix-dependencies" to automatically repair dangling dependencies.`]),l}async function Wt(e,t,n,r,i={},a={}){let{rawData:o,sourceTasks:s,allTasks:c}=await Bt(await zt(e,t,n,r,a)),{tasksToMove:l,dependencyResolution:u}=await Vt(s,c,i,t,n,r);return await Ut(await Ht(l,n,r,o,a,e),e,a,n,r,u)}function Gt(e,t,n){return e.tag=n,e.metadata||={},e.metadata.moveHistory||(e.metadata.moveHistory=[]),e.metadata.moveHistory.push({fromTag:t,toTag:n,timestamp:(/* @__PURE__ */ new Date()).toISOString()}),e}var Kt=class e extends Error{constructor(t,n){super(t),this.name=`StreamingError`,this.code=n,Error.captureStackTrace&&Error.captureStackTrace(this,e)}};const qt={NOT_ASYNC_ITERABLE:`STREAMING_NOT_SUPPORTED`,STREAM_PROCESSING_FAILED:`STREAM_PROCESSING_FAILED`,STREAM_NOT_ITERABLE:`STREAM_NOT_ITERABLE`,BUFFER_SIZE_EXCEEDED:`BUFFER_SIZE_EXCEEDED`};var Jt=class e{static async withTimeout(e,t,n=`Operation`){let r,i=new Promise((e,i)=>{r=setTimeout(()=>{i(new Kt(`${n} timed out after ${t/1e3} seconds`,qt.STREAM_PROCESSING_FAILED))},t)});try{let t=await Promise.race([e,i]);return clearTimeout(r),t}catch(e){throw clearTimeout(r),e}}static async withSoftTimeout(e,t,n=void 0){let r,i=new Promise(e=>{r=setTimeout(()=>{e(n)},t)});try{let t=await Promise.race([e,i]);return clearTimeout(r),t}catch{return clearTimeout(r),n}}static createController(t,n=`Operation`){return{timeoutMs:t,operationName:n,async wrap(r,i=null){let a=i?`${n} - ${i}`:n;return e.withTimeout(r,t,a)},async wrapSoft(n,r=void 0){return e.withSoftTimeout(n,t,r)}}}static isTimeoutError(e){return e instanceof Kt&&e.code===qt.STREAM_PROCESSING_FAILED&&e.message.includes(`timed out`)}},Yt=class e{constructor(e,t=`ms`){this.milliseconds=this._toMilliseconds(e,t)}static milliseconds(t){return new e(t,`ms`)}static seconds(t){return new e(t,`s`)}static minutes(t){return new e(t,`m`)}static hours(t){return new e(t,`h`)}get seconds(){return this.milliseconds/1e3}get minutes(){return this.milliseconds/6e4}get hours(){return this.milliseconds/36e5}toString(){return this.milliseconds<1e3?`${this.milliseconds}ms`:this.milliseconds<6e4?`${this.seconds}s`:this.milliseconds<36e5?`${Math.floor(this.minutes)}m ${Math.floor(this.seconds%60)}s`:`${Math.floor(this.hours)}h ${Math.floor(this.minutes%60)}m`}_toMilliseconds(e,t){return e*({ms:1,s:1e3,m:6e4,h:36e5}[t]||1)}};const Xt=U.object({id:U.number(),title:U.string().min(1),description:U.string().min(1),details:U.string(),testStrategy:U.string(),priority:U.enum(je),dependencies:U.array(U.number()),status:U.string()}),Zt=U.object({tasks:U.array(Xt),metadata:U.union([U.object({projectName:U.string(),totalTasks:U.number(),sourceFile:U.string(),generatedAt:U.string()}),U.null()]).default(null)});var Qt=class{constructor(e,t,n,r={}){this.prdPath=e,this.tasksPath=t,this.numTasks=n,this.force=r.force||!1,this.append=r.append||!1,this.research=r.research||!1,this.reportProgress=r.reportProgress,this.mcpLog=r.mcpLog,this.session=r.session,this.projectRoot=r.projectRoot,this.tag=r.tag,this.streamingTimeout=r.streamingTimeout||Yt.seconds(180).milliseconds,this.targetTag=this.tag||g(this.projectRoot)||`master`,this.isMCP=!!this.mcpLog,this.outputFormat=this.isMCP&&!this.reportProgress?`json`:`text`,this.useStreaming=!1}hasCodebaseAnalysis(){return c(this.research,this.projectRoot,this.session)}},$t=class{constructor(e,t){this.isMCP=!!e,this.outputFormat=this.isMCP&&!t?`json`:`text`,this.logFn=e||{info:(...e)=>o(`info`,...e),warn:(...e)=>o(`warn`,...e),error:(...e)=>o(`error`,...e),debug:(...e)=>o(`debug`,...e),success:(...e)=>o(`success`,...e)}}report(e,t=`info`){this.logFn&&typeof this.logFn[t]==`function`?this.logFn[t](e):!p()&&this.outputFormat===`text`&&o(t,e)}};function en(e){return`${Math.floor(e/60)}m ${Math.floor(e%60).toString().padStart(2,`0`)}s`}const tn={BAR_WIDTH:40,TABLE_COL_WIDTHS:[28,50],DEFAULT_MODEL:`Default`,DEFAULT_TEMPERATURE:.7},J={HIGH:`high`,MEDIUM:`medium`,LOW:`low`},nn={[J.HIGH]:V.red,[J.MEDIUM]:V.yellow,[J.LOW]:w.muted},rn={main:{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderColor:b,borderStyle:`round`},summary:{padding:{top:1,right:1,bottom:1,left:1},borderColor:b,borderStyle:`round`,margin:{top:1,right:1,bottom:1,left:0}},warning:{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1,bottom:1}},nextSteps:{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1,right:0,bottom:1,left:0}}};function an({prdFilePath:e,outputPath:t,numTasks:n,model:r,temperature:i,append:a,research:o}){let s=a?`Appending`:`Generating`,c=`Model: ${r} | Temperature: ${i}`;return o&&(c+=` | ${V.cyan.bold(`🔬 Research Mode`)}`),V.bold(`🤖 Parsing PRD and ${s} Tasks`)+`
|
|
593
|
+
`+V.dim(c)+`
|
|
594
|
+
|
|
595
|
+
`+w.brand(`Input: ${e}`)+`
|
|
596
|
+
`+w.brand(`Output: ${t}`)+`
|
|
597
|
+
`+w.brand(`Tasks to ${a?`Append`:`Generate`}: ${n}`)}function on(e){console.log(G(e,rn.main))}function sn(e,t){console.log(V.yellow.bold(`📝 Append mode`)+` - Adding to ${e} existing tasks (next ID: ${t})`)}function cn(e){let t=V.red.bold(`⚠️ Force flag enabled`);return e?`${t} - Will overwrite if conflicts occur`:`${t} - Overwriting existing tasks`}function ln({prdFilePath:e,outputPath:t,numTasks:n,model:r=tn.DEFAULT_MODEL,temperature:i=tn.DEFAULT_TEMPERATURE,append:a=!1,research:o=!1,force:s=!1,existingTasks:c=[],nextId:l=1}){if(!e||typeof e!=`string`||e.trim()===``)throw Error(`prdFilePath is required and must be a non-empty string`);if(!t||typeof t!=`string`||t.trim()===``)throw Error(`outputPath is required and must be a non-empty string`);on(an({prdFilePath:e,outputPath:t,numTasks:n,model:r,temperature:i,append:a,research:o})),(a||s)&&(a&&sn(c.length,l),s&&console.log(cn(a)),console.log())}function un(e,t){let n={};return Object.values(J).forEach(r=>{let i=e[r]||0;n[r]={count:i,percentage:t>0?Math.round(i/t*100):0}}),n}function dn(e,t){let n=tn.BAR_WIDTH,r={};if(t===0)return Object.values(J).forEach(e=>{r[e]=0}),r;let i={};Object.values(J).forEach(r=>{i[r]=e[r].count/t*n}),Object.values(J).forEach(e=>{r[e]=Math.floor(i[e])}),Object.values(J).forEach(t=>{e[t].count>0&&r[t]===0&&(r[t]=1)});let a=n-Object.values(r).reduce((e,t)=>e+t,0);if(a>0){let e=Object.values(J).map(e=>({priority:e,decimal:i[e]-Math.floor(i[e])})).sort((e,t)=>t.decimal-e.decimal);for(let t=0;t<a&&t<e.length;t++)r[e[t].priority]++}return r}function fn(e){let t=``;t+=nn[J.HIGH](`█`.repeat(e[J.HIGH])),t+=nn[J.MEDIUM](`█`.repeat(e[J.MEDIUM])),t+=nn[J.LOW](`█`.repeat(e[J.LOW]));let n=Object.values(e).reduce((e,t)=>e+t,0);return n<tn.BAR_WIDTH&&(t+=w.muted(`░`.repeat(tn.BAR_WIDTH-n))),t}function pn(e){let t=[];return Object.entries(J).forEach(([n,r])=>{let i=e[r],a=nn[r],o=n.charAt(0)+n.slice(1).toLowerCase();t.push(`${a.bold(i.count)} ${a(o)} (${i.percentage}%)`)}),[V.cyan(`Priority distribution:`),t.join(` · `)]}function mn(e){let{totalTasks:t,taskPriorities:n={},prdFilePath:r,outputPath:i,elapsedTime:a,usedFallback:o=!1,actionVerb:s=`generated`}=e,c=en(a),l=new ye({chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":2},colWidths:tn.TABLE_COL_WIDTHS});if(l.push([V.cyan(`Total tasks ${s}:`),V.bold(t)],[V.cyan(`Processing time:`),V.bold(c)]),n&&Object.keys(n).length>0){let e=un(n,t),r=pn(e);l.push(r);let i=fn(dn(e,t));l.push([V.cyan(`Distribution:`),i])}l.push([V.cyan(`PRD source:`),V.italic(r)],[V.cyan(`Tasks file:`),V.italic(i)]),o&&l.push([V.yellow(`Fallback parsing:`),V.yellow(`✓ Used fallback parsing`)]);let u=[V.bold.underline(`PRD Parsing Complete - Tasks ${s.charAt(0).toUpperCase()+s.slice(1)}`),``,l.toString()].join(`
|
|
598
|
+
`);console.log(G(u,rn.summary)),o&&hn(),gn()}function hn(){let e=V.yellow.bold(`⚠️ Fallback Parsing Used`)+`
|
|
599
|
+
|
|
600
|
+
`+w.text(`The system used fallback parsing to complete task generation.`)+`
|
|
601
|
+
`+w.text(`This typically happens when streaming JSON parsing is incomplete.`)+`
|
|
602
|
+
`+w.text(`Your tasks were successfully generated, but consider:`)+`
|
|
603
|
+
`+w.text(`• Reviewing task completeness`)+`
|
|
604
|
+
`+w.text(`• Checking for any missing details`)+`
|
|
605
|
+
|
|
606
|
+
`+w.text(`This is normal and usually doesn't indicate any issues.`);console.log(G(e,rn.warning))}function gn(){let e=w.text.bold(`Next Steps:`)+`
|
|
607
|
+
|
|
608
|
+
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph list`)} to view all tasks\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph analyze-complexity`)} to analyze task complexity`;console.log(G(e,rn.nextSteps))}function _n(e){if(typeof e!=`string`)return null;let t=e.indexOf(`{`);if(t<0)return null;let n=0,r=!1,i=!1;for(let a=t;a<e.length;a++){let o=e[a];if(r)i?i=!1:o===`\\`?i=!0:o===`"`&&(r=!1);else if(o===`"`)r=!0;else if(o===`{`)n++;else if(o===`}`&&(n--,n===0))return e.slice(t,a+1)}return null}function vn(e){let t=_n(e);if(!t)return null;try{let e=Zt.safeParse(JSON.parse(t));return e.success?e.data:null}catch{return null}}function yn(e){return Math.ceil(e.length/4)}function bn(e){let t=W.readFileSync(e,`utf8`);if(!t)throw Error(`Input file ${e} is empty or could not be read.`);return t}function xn(e,t){let n=[],r=1;if(!W.existsSync(e))return{existingTasks:n,nextId:r};try{let i=W.readFileSync(e,`utf8`),a=JSON.parse(i);a[t]?.tasks&&Array.isArray(a[t].tasks)&&(n=a[t].tasks,n.length>0&&(r=Math.max(...n.map(e=>e.id||0))+1))}catch{return{existingTasks:[],nextId:1}}return{existingTasks:n,nextId:r}}function Sn({existingTasks:e,targetTag:t,append:n,force:r,isMCP:i,logger:a}){if(!(e.length>0))a.report(`Tag '${t}' is empty or doesn't exist. Creating/updating tag with new tasks.`,`debug`);else if(n)a.report(`Append mode enabled. Found ${e.length} existing tasks in tag '${t}'.`,`info`);else{if(!r){let n=`Tag '${t}' already contains ${e.length} tasks. Use --force to overwrite or --append to add to existing tasks.`;if(a.report(n,`error`),i)throw Error(n);console.error(V.red(n)),process.exit(1)}a.report(`Force flag enabled. Overwriting existing tasks in tag '${t}'.`,`debug`)}}function Cn(e,t,n,r){wn(e,t);let i=t,a=/* @__PURE__ */ new Map,o=e.map(e=>{let t=i++;return a.set(e.id,t),{...e,id:t,status:e.status||`pending`,priority:e.priority||r,dependencies:Array.isArray(e.dependencies)?e.dependencies:[],subtasks:e.subtasks||[],title:e.title||``,description:e.description||``,details:e.details||``,testStrategy:e.testStrategy||``}});return o.forEach(e=>{e.dependencies=e.dependencies.map(e=>a.get(e)).filter(t=>t!=null&&t<e.id&&(d(n,t)||o.some(e=>e.id===t)))}),o}function wn(e,t=1){if(!Array.isArray(e)||e.length===0)return;let n=e.map(e=>e.id);if(n.some(e=>!Number.isInteger(e)||e<1))throw Error(`PRD tasks must use sequential positive integer IDs starting at 1.`);let r=new Set(n);if(r.size!==n.length)throw Error(`PRD task IDs must be unique and sequential starting at 1.`);let i=[...r].sort((e,t)=>e-t),a=i[0];if(a!==1&&a!==t)throw Error(`PRD task IDs must start at 1 or ${t} and be sequential.`);for(let e=0;e<i.length;e+=1)if(i[e]!==a+e)throw Error(`PRD task IDs must be a contiguous sequence starting at ${a}.`)}function Tn(e,t,n,r){let i=H.dirname(e);W.existsSync(i)||W.mkdirSync(i,{recursive:!0});let a={};if(W.existsSync(e))try{let t=W.readFileSync(e,`utf8`);a=JSON.parse(t)}catch{a={}}a[n]={tasks:t,metadata:{created:a[n]?.metadata?.created||(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for ${n} context`}},h(a[n],{description:`Tasks for ${n} context`}),W.writeFileSync(e,JSON.stringify(a,null,2)),r.report(`Successfully saved ${t.length} tasks to ${e}`,`debug`)}async function En(e,t,n){let r=it(),i=v(e.projectRoot)||`medium`;return r.loadPrompt(`parse-prd`,{research:e.research,numTasks:e.numTasks,nextId:n,prdContent:t,prdPath:e.prdPath,defaultTaskPriority:i,hasCodebaseAnalysis:e.hasCodebaseAnalysis(),projectRoot:e.projectRoot||``})}async function Dn({task:e,currentCount:t,totalTasks:n,estimatedTokens:r,progressTracker:i,reportProgress:a,priorityMap:o,defaultPriority:s,estimatedInputTokens:c}){let l=e.priority||s,u=o[l]||o.medium;if(i&&(i.addTaskLine(t,e.title,l),r&&i.updateTokens(c,r)),a)try{let i=r?Math.floor(r/n):0;await a({progress:t,total:n,message:`${u} Task ${t}/${n} - ${e.title} | ~Output: ${i} tokens`})}catch{}}async function On({processedTasks:e,nextId:t,summary:n,prdPath:r,tasksPath:i,usedFallback:a,aiServiceResponse:o}){let s=(()=>{if(!Array.isArray(e)||e.length===0)return`task_${String(t).padStart(3,`0`)}.txt`;let n=e[0].id,r=e[e.length-1].id;return e.length===1?`task_${String(n).padStart(3,`0`)}.txt`:`task_${String(n).padStart(3,`0`)}.txt -> task_${String(r).padStart(3,`0`)}.txt`})();mn({totalTasks:e.length,taskPriorities:n.taskPriorities,prdFilePath:r,outputPath:i,elapsedTime:n.elapsedTime,usedFallback:a,taskFilesGenerated:s,actionVerb:n.actionVerb}),o?.telemetryData&&(o.mainResult?.usage&&await Jt.withSoftTimeout(o.mainResult.usage,1e3,void 0),Q(o.telemetryData,`cli`))}function kn({processedTasks:e,research:t,finalTasks:n,tasksPath:r,aiServiceResponse:i}){let a=H.relative(process.cwd(),r)||r,o=n.length>e.length?` · ${n.length} tasks in total`:``,s=t?` · research-backed`:``;console.log(w.muted(`Saved to ${a}${o}${s}`));let c=(e,t)=>`${V.yellow(e.padEnd(28))}${w.muted(t)}`;console.log(G(w.text.bold(`Next steps`)+`
|
|
609
|
+
|
|
610
|
+
`+[c(`taskgraph next`,`the task to start with`),c(`taskgraph graph`,`how the tasks depend on each other`),c(`taskgraph expand --id=<id>`,`split a task into subtasks`)].join(`
|
|
611
|
+
`),{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})),i?.telemetryData&&Q(i.telemetryData,`cli`)}async function An(e,t,n,r=1){let i=new $t(e.mcpLog,e.reportProgress),a=yn(t.systemPrompt+t.userPrompt),o=e.outputFormat===`text`&&!e.isMCP&&!e.reportProgress;if(i.report(`Calling AI service to generate tasks from PRD${e.research?` with research-backed analysis`:``}...`,`debug`),o){let o=null;try{return o=_i({prdName:H.basename(e.prdPath||`PRD`),numTasks:n,startId:r}),{...await jn(e,t,o),estimatedInputTokens:a}}catch(t){if(Ce.isInstance(t)&&!Pn(e))throw o?.fail(`Couldn't generate tasks`),t;o?.stop(),i.report(`Streaming task generation failed (${t.message}); retrying in one request`,`debug`),o?.printedCount&&console.log(`${V.yellow(`⚠`)} Live output stopped. Asking Claude again in one request; the final tasks may differ from the ones above.`)}}return{...await Nn(e,t,o),estimatedInputTokens:a}}async function jn(t,n,r){let i=await e({...Fn(t,n)}),a=i?.mainResult,o=a?.partialObjectStream;if(!o)throw Error(`AI service did not return a stream`);for await(let e of o)r?.update(e);let s;try{s=await a.object}catch(e){if(s=vn(e?.text),!s)throw e}if(!s||!Array.isArray(s.tasks))throw Error(`AI service returned unexpected data structure.`);return r?.succeed(s),i.telemetryData=await Mn(a,i,t),{parsedTasks:s.tasks,aiServiceResponse:i}}async function Mn(e,t,r){let i=t.telemetryData;if(!i?.userId)return i;try{let a=await e.usage;return await n({userId:i.userId,commandName:`parse-prd`,providerName:t.providerName,modelId:t.modelId,inputTokens:a?.inputTokens??a?.promptTokens??0,outputTokens:a?.outputTokens??a?.completionTokens??0,cachedInputTokens:a?.inputTokenDetails?.cacheReadTokens??0,outputType:r.isMCP?`mcp`:`cli`})||i}catch{return i}}async function Nn(e,t,n){let i=n?X(`Parsing PRD and generating tasks…`):null;try{let n=await r(Fn(e,t)),a=In(n?.mainResult);if(!a)throw Error(`AI service returned unexpected data structure after validation.`);return i&&vi(i,`${a.tasks.length} tasks generated`),{parsedTasks:a.tasks,aiServiceResponse:n}}catch(e){throw i&&yi(i,`Couldn't generate tasks`),e}}function Pn(e){let t=e.projectRoot,n=e.research?te(t):j(t);return[j(t),I(t),te(t)].filter(Boolean).some(e=>e!==n)}function Fn(e,t){return{role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:Zt,objectName:`tasks_data`,systemPrompt:t.systemPrompt,prompt:t.userPrompt,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}}function In(e){if(e&&typeof e==`object`){if(Array.isArray(e.tasks))return e;if(Array.isArray(e.object?.tasks))return e.object}return null}const[Ln,Rn,zn]=je,Bn=/* @__PURE__ */ new Map;var Vn=class{constructor(e,t,n,r=null){this.name=e,this.levels=t,this.colors=n,this.thresholds=r}getColor(e){return this.colors[e]||w.muted}getLevelFromScore(e){if(!this.thresholds)throw Error(`${this.name} does not support score-based levels`);return e>=7?this.levels[0]:e<=3?this.levels[2]:this.levels[1]}};const Hn={cli:{filled:`●`,empty:`○`},statusBar:{high:`⋮`,medium:`:`,low:`.`},mcp:{high:`🔴`,medium:`🟠`,low:`🟢`}},Un=new Vn(`priority`,[Ln,Rn,zn],{[Ln]:V.red,[Rn]:V.yellow,[zn]:w.muted});function Wn(e,t){let n=Hn.cli.filled,r=Hn.cli.empty,i=``;for(let a=0;a<3;a++)i+=a<e?t(n):w.text(r);return i}function Gn(e,t){return 3-t.indexOf(e)}function Kn(e,t){if(Bn.has(e))return Bn.get(e);let n=t();return Bn.set(e,n),n}function qn(){return Kn(`mcp-priority-all`,()=>({[Ln]:Hn.mcp.high,[Rn]:Hn.mcp.medium,[zn]:Hn.mcp.low}))}function Jn(){return Kn(`cli-priority-all`,()=>{let e={};return Un.levels.forEach(t=>{let n=Gn(t,Un.levels),r=Un.getColor(t);e[t]=Wn(n,r)}),e})}function Yn(){return Kn(`statusbar-priority-all`,()=>{let e={};return Un.levels.forEach((t,n)=>{let r=n===0?Hn.statusBar.high:n===1?Hn.statusBar.medium:Hn.statusBar.low,i=Un.getColor(t);e[t]=i(r)}),e})}function Xn(){return{[Ln]:Un.colors[Ln],[Rn]:Un.colors[Rn],[zn]:Un.colors[zn]}}function Zn(e=!1){return e?qn():Jn()}function Qn(e,t=!1){let n=Zn(t);return n[e]||n[Rn]}new Vn(`complexity`,[`high`,`medium`,`low`],{high:V.red,medium:V.yellow,low:V.green},{high:e=>e>=7,medium:e=>e>=4&&e<=6,low:e=>e<=3});const $n={clearOnComplete:!1,stopOnComplete:!0,hideCursor:!0,barsize:40},er={shades_classic:be.Presets.shades_classic,shades_grey:be.Presets.shades_grey,rect:be.Presets.rect,legacy:be.Presets.legacy},tr=new class{constructor(e={},t=er.shades_classic){this.defaultOptions={...$n,...e},this.defaultPreset=t}createSingleBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new be.SingleBar(n,r)}createMultiBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new be.MultiBar(n,r)}_mergeConfig(e){return{...this.defaultOptions,...e}}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}setDefaultPreset(e){this.defaultPreset=e}};function nr(e={}){return tr.createMultiBar(e)}var rr=class{constructor(e={}){this.numUnits=e.numUnits||1,this.unitName=e.unitName||`unit`,this.startTime=null,this.completedUnits=0,this.tokensIn=0,this.tokensOut=0,this.isEstimate=!0,this.bestAvgTimePerUnit=null,this.lastEstimateTime=null,this.lastEstimateSeconds=0,this.multibar=null,this.timeTokensBar=null,this.progressBar=null,this._timerInterval=null,this.isStarted=!1,this.isFinished=!1,this._initializeCustomProperties(e)}_initializeCustomProperties(e){}get unitNamePlural(){return`${this.unitName}s`}start(){this.isStarted||this.isFinished||(this.isStarted=!0,this.startTime=Date.now(),this.multibar=nr(),this.timeTokensBar=this.multibar.create(1,0,{},{format:this._getTimeTokensBarFormat(),barsize:1,hideCursor:!0,clearOnComplete:!1}),this.progressBar=this.multibar.create(this.numUnits,0,{},{format:this._getProgressBarFormat(),barCompleteChar:`█`,barIncompleteChar:`░`}),this._updateTimeTokensBar(),this.progressBar.update(0,{[this.unitNamePlural]:`0/${this.numUnits}`}),this._timerInterval=setInterval(()=>this._updateTimeTokensBar(),1e3),this._setupCustomUI())}_setupCustomUI(){}_getTimeTokensBarFormat(){return`{clock} {elapsed} | Tokens (I/O): {in}/{out} | Est: {remaining}`}_getProgressBarFormat(){return`${this.unitName.charAt(0).toUpperCase()+this.unitName.slice(1)}s {${this.unitNamePlural}} |{bar}| {percentage}%`}updateTokens(e,t,n=!1){this.tokensIn=e||0,this.tokensOut=t||0,this.isEstimate=n,this._updateTimeTokensBar()}_updateTimeTokensBar(){if(!this.timeTokensBar||this.isFinished)return;let e=this._formatElapsedTime(),t=this._estimateRemainingTime(),n=this.isEstimate?`~ Tokens (I/O)`:`Tokens (I/O)`;this.timeTokensBar.update(1,{clock:`⏱️`,elapsed:e,in:this.tokensIn,out:this.tokensOut,remaining:t,tokensLabel:n,...this._getCustomTimeTokensPayload()})}_getCustomTimeTokensPayload(){return{}}_formatElapsedTime(){if(!this.startTime)return`0m 00s`;let e=Math.floor((Date.now()-this.startTime)/1e3);return`${Math.floor(e/60)}m ${(e%60).toString().padStart(2,`0`)}s`}_estimateRemainingTime(){let e=this._getProgressFraction();if(e>=1)return`~0s`;let t=Date.now(),n=(t-this.startTime)/1e3;if(e===0)return`~calculating...`;let r=n/e;(this.bestAvgTimePerUnit===null||r<this.bestAvgTimePerUnit)&&(this.bestAvgTimePerUnit=r);let i=this.numUnits*(1-e),a=Math.ceil(i*this.bestAvgTimePerUnit);if(this.lastEstimateTime){let e=Math.floor((t-this.lastEstimateTime)/1e3),n=Math.max(0,this.lastEstimateSeconds-e);if(n===0)return`~0s`;a=Math.min(a,n)}return this.lastEstimateTime=t,this.lastEstimateSeconds=a,`~${this._formatDuration(a)}`}_getProgressFraction(){return this.completedUnits/this.numUnits}_formatDuration(e){if(e<60)return`${e}s`;let t=Math.floor(e/60),n=e%60;return t<60?n>0?`${t}m ${n}s`:`${t}m`:`${Math.floor(t/60)}h ${t%60}m`}getElapsedTime(){return this.startTime?Date.now()-this.startTime:0}stop(){this.isFinished||(this.isFinished=!0,this._timerInterval&&=(clearInterval(this._timerInterval),null),this.multibar&&(this._updateTimeTokensBar(),this.multibar.stop()),this.cleanup())}getSummary(){return{completedUnits:this.completedUnits,elapsedTime:this.getElapsedTime()}}cleanup(){if(this._timerInterval&&=(clearInterval(this._timerInterval),null),this.multibar){try{this.multibar.stop()}catch{}this.multibar=null}this.timeTokensBar=null,this.progressBar=null,this.isStarted=!1,this.isFinished=!0,this._performCustomCleanup()}_performCustomCleanup(){}},ir=class{constructor(e){if(!e)throw Error(`Multibar instance is required`);this.multibar=e}createBar(e,t={}){if(typeof e!=`string`)throw Error(`Format must be a string`);let n=this.multibar.create(1,1,{},{format:e,barsize:1,hideCursor:!0,clearOnComplete:!1});return n.update(1,t),n}createHeader(e,t){this.createBar(t),this.createBar(e),this.createBar(t)}createRow(e,t){if(!t||typeof t!=`object`)throw Error(`Payload must be an object`);return this.createBar(e,t)}createBorder(e){return this.createBar(e)}};function ar(e,t,n){new ir(e).createHeader(t,n)}function or(e,t,n){new ir(e).createRow(t,n)}function sr(e,t){new ir(e).createBorder(t)}Jn();const cr=Yn();Xn();const lr={DEBOUNCE_DELAY:100,MAX_TITLE_LENGTH:57,TRUNCATED_LENGTH:54,TASK_ID_PAD_START:3,TASK_ID_PAD_END:4,PRIORITY_PAD_END:3,VALID_PRIORITIES:[`high`,`medium`,`low`],DEFAULT_PRIORITY:`medium`};var ur=class{constructor(e=lr.DEBOUNCE_DELAY){this.delay=e,this.pendingTimeout=null}debounce(e){this.clear(),this.pendingTimeout=setTimeout(()=>{e(),this.pendingTimeout=null},this.delay)}clear(){this.pendingTimeout&&=(clearTimeout(this.pendingTimeout),null)}hasPending(){return this.pendingTimeout!==null}},dr=class{constructor(){this.priorities={high:0,medium:0,low:0}}increment(e){let t=this.normalize(e);return this.priorities[t]++,t}normalize(e){let t=e?e.toLowerCase():lr.DEFAULT_PRIORITY;return lr.VALID_PRIORITIES.includes(t)?t:lr.DEFAULT_PRIORITY}getCounts(){return{...this.priorities}}},fr=class{static formatTitle(e,t){return e?e.length>lr.MAX_TITLE_LENGTH?e.substring(0,lr.TRUNCATED_LENGTH)+`...`:e:`Task ${t}`}static formatPriority(e){return Qn(e,!1).padEnd(lr.PRIORITY_PAD_END,` `)}static formatTaskId(e){return e.toString().padStart(lr.TASK_ID_PAD_START,` `).padEnd(lr.TASK_ID_PAD_END,` `)}},pr=class extends rr{_initializeCustomProperties(e){this.append=e.append,this.priorityManager=new dr,this.debouncer=new ur,this.headerShown=!1}_getTimeTokensBarFormat(){return`{clock} {elapsed} | ${cr.high} {high} ${cr.medium} {medium} ${cr.low} {low} | Tokens (I/O): {in}/{out} | Est: {remaining}`}_getProgressBarFormat(){return`Tasks {tasks} |{bar}| {percentage}%`}_getCustomTimeTokensPayload(){return this.priorityManager.getCounts()}addTaskLine(e,t,n=`medium`){if(!this.multibar||this.isFinished)return;this._ensureHeaderShown();let r=this._updateTaskCounters(e,n);this._updateTimeTokensBar(),this.debouncer.debounce(()=>{this._updateProgressDisplay(e,t,r)})}_ensureHeaderShown(){this.headerShown||(this.headerShown=!0,ar(this.multibar,` TASK | PRI | TITLE`,`------+-----+----------------------------------------------------------------`))}_updateTaskCounters(e,t){let n=this.priorityManager.increment(t);return this.completedUnits=e,n}_updateProgressDisplay(e,t,n){this.progressBar.update(this.completedUnits,{tasks:`${this.completedUnits}/${this.numUnits}`});let r=fr.formatTitle(t,e),i=fr.formatPriority(n),a=fr.formatTaskId(e);or(this.multibar,` ${a} | ${i} | {title}`,{title:r}),sr(this.multibar,`------+-----+----------------------------------------------------------------`),this._updateTimeTokensBar()}finish(){this.debouncer.hasPending()&&(this.debouncer.clear(),this._updateTimeTokensBar()),this.cleanup(),super.finish()}_performCustomCleanup(){this.debouncer.clear()}getSummary(){return{...super.getSummary(),taskPriorities:this.priorityManager.getCounts(),actionVerb:this.append?`appended`:`generated`}}};function mr(e={}){return new pr(e)}async function hr(e,t,n){let r=gr(e,t,n);await vr(e,n,r.estimatedInputTokens);let i=await yr(e,t,e.streamingTimeout),{progressTracker:a,priorityMap:o}=await br(e,n),s=await xr(i.mainResult,e,t,n,a,o,r.defaultPriority,r.estimatedInputTokens,r.logger);if(_r(s),s.usage&&e.projectRoot){let{logAiUsage:t}=await import(`./ai-services-unified-CigO4oTy.js`),{getUserId:n}=await import(`./config-manager-C5Ih13nA.js`),a=n(e.projectRoot);if(a&&i.providerName&&i.modelId)try{let n=await t({userId:a,commandName:`parse-prd`,providerName:i.providerName,modelId:i.modelId,inputTokens:s.usage.promptTokens||0,outputTokens:s.usage.completionTokens||0,outputType:e.isMCP?`mcp`:`cli`});n&&(i.telemetryData=n)}catch(e){r.logger.report(`Failed to log telemetry: ${e.message}`,`debug`)}}return jr(s,i,r.estimatedInputTokens,a)}function gr(e,t,n){let{systemPrompt:r,userPrompt:i}=t;return{logger:new $t(e.mcpLog,e.reportProgress),estimatedInputTokens:yn(r+i),defaultPriority:v(e.projectRoot)||`medium`}}function _r(e){if(e.parsedTasks.length===0)throw Error(`No tasks were generated from the PRD`)}async function vr(e,t,n){e.reportProgress&&await e.reportProgress({progress:0,total:t,message:`Starting PRD analysis (Input: ${n} tokens)${e.research?` with research`:``}...`})}async function yr(t,n,r){let{systemPrompt:i,userPrompt:a}=n;return await Jt.withTimeout(e({role:t.research?`research`:`main`,session:t.session,projectRoot:t.projectRoot,schema:Zt,systemPrompt:i,prompt:a,commandName:`parse-prd`,outputType:t.isMCP?`mcp`:`cli`}),r,`Streaming operation`)}async function br(e,t){let n=Zn(e.isMCP),r=null;if(e.outputFormat===`text`&&!e.isMCP){r=mr({numUnits:t,unitName:`task`,append:e.append});let n=e.research?te():j(),i=C(e.research?`research`:`main`);ln({prdFilePath:e.prdPath,outputPath:e.tasksPath,numTasks:t,append:e.append,research:e.research,force:e.force,existingTasks:[],nextId:1,model:n||`Default`,temperature:i?.temperature||.7}),r.start()}return{progressTracker:r,priorityMap:n}}async function xr(e,t,n,r,i,a,o,s,c){let{systemPrompt:l,userPrompt:u}=n,d={config:{...t,schema:Zt},numTasks:r,progressTracker:i,priorityMap:a,defaultPriority:o,estimatedInputTokens:s,prompt:u,systemPrompt:l};try{let t={lastPartialObject:null,taskCount:0,estimatedOutputTokens:0,usage:null};if(await Sr(e.partialObjectStream,t,d),e.usage)try{t.usage=await e.usage}catch(e){c.report(`Failed to get usage data: ${e.message}`,`debug`)}return Er(t,d)}catch(e){return c.report(`StreamObject processing failed: ${e.message}. Falling back to generateObject.`,`debug`),await Ar(d,c)}}async function Sr(e,t,n){for await(let r of e)t.lastPartialObject=r,r&&(t.estimatedOutputTokens=yn(JSON.stringify(r))),await Cr(r,t,n)}async function Cr(e,t,n){if(!e?.tasks||!Array.isArray(e.tasks))return;let r=e.tasks.length;r>t.taskCount?(await wr(e.tasks,t.taskCount,r,t.estimatedOutputTokens,n),t.taskCount=r):n.progressTracker&&t.estimatedOutputTokens>0&&n.progressTracker.updateTokens(n.estimatedInputTokens,t.estimatedOutputTokens,!0)}async function wr(e,t,n,r,i){for(let a=t;a<n;a++){let t=e[a]||{};t.title?await Dn({task:t,currentCount:a+1,totalTasks:i.numTasks,estimatedTokens:r,progressTracker:i.progressTracker,reportProgress:i.config.reportProgress,priorityMap:i.priorityMap,defaultPriority:i.defaultPriority,estimatedInputTokens:i.estimatedInputTokens}):await Tr(a+1,r,i)}}async function Tr(e,t,n){let{progressTracker:r,config:i,numTasks:a,defaultPriority:o,estimatedInputTokens:s}=n;r&&(r.addTaskLine(e,`Generating task ${e}...`,o),r.updateTokens(s,t,!0)),i.reportProgress&&!r&&await i.reportProgress({progress:e,total:a,message:`Generating task ${e}/${a}...`})}async function Er(e,t){let{lastPartialObject:n,estimatedOutputTokens:r,taskCount:i,usage:a}=e;if(!n?.tasks||!Array.isArray(n.tasks))throw Error(`No tasks generated from streamObject`);let o=a?.completionTokens||r,s=a?.promptTokens||t.estimatedInputTokens;return t.progressTracker&&await Dr(n.tasks,i,a?o:r,t,a?s:null),{parsedTasks:n.tasks,estimatedOutputTokens:o,actualInputTokens:s,usage:a,usedFallback:!1}}async function Dr(e,t,n,r,i=null){let{progressTracker:a,defaultPriority:o,estimatedInputTokens:s}=r;t>0?Or(e,a,o):await kr(e,n,r),a.updateTokens(i||s,n,!1),a.stop()}function Or(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&t.addTaskLine(r+1,i.title,i.priority||n)}}async function kr(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&await Dn({task:i,currentCount:r+1,totalTasks:n.numTasks,estimatedTokens:t,progressTracker:n.progressTracker,reportProgress:n.config.reportProgress,priorityMap:n.priorityMap,defaultPriority:n.defaultPriority,estimatedInputTokens:n.estimatedInputTokens})}}async function Ar(e,t){if(t.report(`Using generateObject fallback for PRD parsing`,`info`),e.progressTracker)for(let t=0;t<e.numTasks;t++)e.progressTracker.addTaskLine(t+1,`Generating task ${t+1}...`,e.defaultPriority),e.progressTracker.updateTokens(e.estimatedInputTokens,0,!0);let n=await r({role:e.config.research?`research`:`main`,commandName:`parse-prd`,prompt:e.prompt,systemPrompt:e.systemPrompt,schema:e.config.schema,outputFormat:e.config.outputFormat||`text`,projectRoot:e.config.projectRoot,session:e.config.session}),i=n?.mainResult||n;if(i&&Array.isArray(i.tasks)&&(i.tasks=i.tasks.map(e=>({...e,dependencies:e.dependencies??[],priority:e.priority??null,details:e.details??null,testStrategy:e.testStrategy??null}))),i&&Array.isArray(i.tasks)){if(e.progressTracker){for(let t=0;t<i.tasks.length;t++){let n=i.tasks[t];n&&n.title&&e.progressTracker.addTaskLine(t+1,n.title,n.priority||e.defaultPriority)}let t=n.telemetryData?.outputTokens||yn(JSON.stringify(i)),r=n.telemetryData?.inputTokens||e.estimatedInputTokens;e.progressTracker.updateTokens(r,t,!1)}return{parsedTasks:i.tasks,estimatedOutputTokens:n.telemetryData?.outputTokens||yn(JSON.stringify(i)),actualInputTokens:n.telemetryData?.inputTokens,telemetryData:n.telemetryData,usedFallback:!0}}throw Error(`Failed to generate tasks using generateObject fallback`)}function jr(e,t,n,r){let i=null;if(r&&(i=r.getSummary(),r.cleanup()),e.usage&&t){let n=e.usage;t.usage||={promptTokens:n.promptTokens||0,completionTokens:n.completionTokens||0,totalTokens:n.totalTokens||0}}return{parsedTasks:e.parsedTasks,aiServiceResponse:t,estimatedInputTokens:e.actualInputTokens||n,estimatedOutputTokens:e.estimatedOutputTokens,usedFallback:e.usedFallback,progressTracker:r,summary:i}}async function Mr(e,t,n){let r=new $t(e.mcpLog,e.reportProgress);r.report(`Parsing PRD file: ${e.prdPath}, Force: ${e.force}, Append: ${e.append}, Research: ${e.research}`,`debug`);try{let i=xn(e.tasksPath,e.targetTag),a=e.append?i.existingTasks:[],o=e.append?i.nextId:1;Sn({existingTasks:i.existingTasks,targetTag:e.targetTag,append:e.append,force:e.force,isMCP:e.isMCP,logger:r});let s=await t(e,await En(e,bn(e.prdPath),o),e.numTasks,o),c=v(e.projectRoot)||`medium`,l=Cn(s.parsedTasks,o,a,c),u=e.append?[...a,...l]:l;return Tn(e.tasksPath,u,e.targetTag,r),await Nr(e,s,l,u,o,n),{success:!0,tasksPath:e.tasksPath,telemetryData:s.aiServiceResponse?.telemetryData,tagInfo:s.aiServiceResponse?.tagInfo}}catch(t){throw e.isMCP?r.report(`Error parsing PRD: ${t.message}`,`error`):k(e.projectRoot)&&console.error(t),t}}async function Nr(e,t,n,r,i,a){let{aiServiceResponse:o,estimatedInputTokens:s,estimatedOutputTokens:c}=t;if(e.reportProgress){let t=o?.telemetryData&&(o.telemetryData.inputTokens>0||o.telemetryData.outputTokens>0),n;if(t){let e=o.telemetryData.totalCost||0,t=o.telemetryData.currency||`USD`;n=`✅ Task Generation Completed | Tokens (I/O): ${o.telemetryData.inputTokens}/${o.telemetryData.outputTokens} | Cost: ${t===`USD`?`$`:t}${e.toFixed(4)}`}else n=`✅ Task Generation Completed | ~Tokens (I/O): ${s}/${a?c:`unknown`} | Cost: ~$0.00`;await e.reportProgress({progress:e.numTasks,total:e.numTasks,message:n})}e.outputFormat===`text`&&!e.isMCP&&(a&&t.summary?await On({processedTasks:n,nextId:i,summary:t.summary,prdPath:e.prdPath,tasksPath:e.tasksPath,usedFallback:t.usedFallback,aiServiceResponse:o}):a||kn({processedTasks:n,research:e.research,finalTasks:r,tasksPath:e.tasksPath,aiServiceResponse:o}))}async function Pr(e,t,n,r={}){return Mr(new Qt(e,t,n,r),hr,!0)}async function Fr(e,t,n,r={}){return Mr(new Qt(e,t,n,r),An,!1)}async function Ir(e,t,n,r={}){let i=new Qt(e,t,n,r);if(i.useStreaming)try{return await Pr(e,t,n,r)}catch(a){if(a instanceof Kt||a.code===qt.NOT_ASYNC_ITERABLE||a.code===qt.STREAM_PROCESSING_FAILED||a.code===qt.STREAM_NOT_ITERABLE||Jt.isTimeoutError(a)){let o=new $t(i.mcpLog,i.reportProgress);return i.outputFormat===`text`&&!i.isMCP?console.log(V.yellow(`⚠️ Streaming operation ${a.message.includes(`timed out`)?`timed out`:`failed`}. Falling back to non-streaming mode...`)):o.report(`Streaming failed (${a.message}), falling back to non-streaming mode...`,`warn`),await Fr(e,t,n,r)}throw a}return await Fr(e,t,n,r)}async function Lr(e,t,n=!1,r=!1,i={}){let{projectRoot:a,tag:s}=i;try{o(`debug`,`Removing subtask ${t}...`);let r=P(e,a,s);if(!r||!r.tasks)throw Error(`Invalid or missing tasks file at ${e}`);if(!t.includes(`.`))throw Error(`Invalid subtask ID format: ${t}. Expected format: "parentId.subtaskId"`);let[i,c]=t.split(`.`),l=parseInt(i,10),u=parseInt(c,10),d=r.tasks.find(e=>e.id===l);if(!d)throw Error(`Parent task with ID ${l} not found`);if(!d.subtasks||d.subtasks.length===0)throw Error(`Parent task ${l} has no subtasks`);let f=d.subtasks.findIndex(e=>e.id===u);if(f===-1)throw Error(`Subtask ${t} not found`);let p={...d.subtasks[f]};d.subtasks.splice(f,1),d.subtasks.length===0&&(d.subtasks=void 0);let m=null;if(n){o(`debug`,`Converting subtask ${t} to a standalone task...`);let e=Math.max(...r.tasks.map(e=>e.id))+1;m={id:e,title:p.title,description:p.description||``,details:p.details||``,status:p.status||`pending`,dependencies:p.dependencies||[],priority:d.priority||`medium`},m.dependencies.includes(l)||m.dependencies.push(l),r.tasks.push(m),o(`info`,`Created new task ${e} from subtask ${t}`)}else o(`debug`,`Subtask ${t} deleted`);return E(e,r,a,s),m}catch(e){throw o(`debug`,`Error removing subtask: ${e.message}`),e}}function Rr(e,t){if(typeof t==`string`&&t.includes(`.`)){let n=t.split(`.`);if(n.length!==2||!n[0]||!n[1]){let n=parseInt(t,10);return e.some(e=>e.id===n)}let[r,i]=n,a=parseInt(r,10),o=parseInt(i,10),s=e.find(e=>e.id===a);return s&&s.subtasks&&s.subtasks.some(e=>e.id===o)}let n=parseInt(t,10);return e.some(e=>e.id===n)}async function zr(e,t,n={}){let{projectRoot:r,tag:i}=n,a={success:!0,messages:[],errors:[],removedTasks:[]},s=t.split(`,`).map(e=>e.trim()).filter(Boolean);if(s.length===0)return a.success=!1,a.errors.push(`No valid task IDs provided.`),a;try{let t=P(e,r,i);if(!t)throw Error(`Could not read tasks file at ${e}`);let n=t._rawTaggedData||t;if(!n[i]||!n[i].tasks)throw Error(`Tag '${i}' not found or has no tasks.`);let c=n[i].tasks,l=[];for(let e of s)if(Rr(c,e))try{if(typeof e==`string`&&e.includes(`.`)){let[t,n]=e.split(`.`).map(e=>parseInt(e,10)),r=c.find(e=>e.id===t);if(!r||!r.subtasks)throw Error(`Parent task ${t} or its subtasks not found for subtask ${e}`);let o=r.subtasks.findIndex(e=>e.id===n);if(o===-1)throw Error(`Subtask ${n} not found in parent task ${t}`);let s={...r.subtasks[o],parentTaskId:t};a.removedTasks.push(s),r.subtasks.splice(o,1),a.messages.push(`Successfully removed subtask ${e} from tag '${i}'`)}else{let t=parseInt(e,10),n=c.findIndex(e=>e.id===t);if(n===-1)throw Error(`Task with ID ${e} not found in tag '${i}'`);let r=c[n];a.removedTasks.push(r),l.push(t),c.splice(n,1),a.messages.push(`Successfully removed task ${e} from tag '${i}'`)}}catch(t){let n=`Error processing ID ${e}: ${t.message}`;a.errors.push(n),a.success=!1,o(`warn`,n)}else{let t=`Task with ID ${e} in tag '${i}' not found or already removed.`;a.errors.push(t),a.success=!1}if(a.removedTasks.length>0){let t=new Set(s.map(e=>typeof e==`string`&&e.includes(`.`)?e:parseInt(e,10)));n[i].tasks=c;for(let e in n)Object.prototype.hasOwnProperty.call(n,e)&&n[e]&&n[e].tasks&&n[e].tasks.forEach(e=>{e.dependencies&&=e.dependencies.filter(e=>!t.has(e)),e.subtasks&&e.subtasks.forEach(n=>{n.dependencies&&=n.dependencies.filter(n=>!t.has(`${e.id}.${n}`)&&!t.has(n))})});E(e,n,r,i);for(let t of l){let n=H.join(H.dirname(e),`task_${t.toString().padStart(3,`0`)}.txt`);if(ge.existsSync(n))try{ge.unlinkSync(n),a.messages.push(`Deleted task file: ${n}`)}catch(e){let t=`Failed to delete task file ${n}: ${e.message}`;a.errors.push(t),a.success=!1,o(`warn`,t)}}}else a.errors.length===0&&a.messages.push(`No tasks found matching the provided IDs.`);let u=a.messages.join(`
|
|
612
|
+
`),d=a.errors.join(`
|
|
613
|
+
`);return{success:a.success,message:u||`No tasks were removed.`,error:d||null,removedTasks:a.removedTasks}}catch(e){return o(`error`,`Error removing tasks: ${e.message}`),{success:!1,message:``,error:`Operation failed: ${e.message}`,removedTasks:[]}}}function Br(e){return e.replace(/<think>[\s\S]*?<\/think>/g,``).trim()}async function Vr(e,n={},r={},i=`text`,a=!0){let{taskIds:s=[],filePaths:c=[],customContext:d=``,includeProjectTree:f=!1,detailLevel:p=`medium`,projectRoot:m,tag:h,saveToFile:g=!1}=n,{session:_,mcpLog:v,commandName:y=`research`,outputType:b=`cli`}=r,x=!!v,S=i===`text`,C=m||l();if(!C)throw Error(`Could not determine project root directory`);let w=x?v:{info:(...e)=>o(`debug`,...e),warn:(...e)=>o(`warn`,...e),error:(...e)=>o(`debug`,...e),debug:(...e)=>o(`debug`,...e),success:(...e)=>o(`debug`,...e)},T=new ot(C,h),E=s.map(String),D=[];try{let t=H.join(C,`.taskgraph`,`tasks`,`tasks.json`),n=await P(t,C,h);if(n&&n.tasks&&n.tasks.length>0){let t=new ft(u(n.tasks),`research`),r=t.findRelevantTasks(e,{maxResults:8,includeRecent:!0,includeCategoryMatches:!0});D=t.getTaskIds(r).map(String).filter(e=>!E.includes(e))}}catch(e){w.debug(`Could not auto-discover tasks: ${e.message}`)}let O=[...E,...D],k=await T.gather({tasks:O,files:c,customContext:d,includeProjectTree:f,format:`research`,includeTokenCounts:!0}),A=k.context,j=k.tokenBreakdown,M=it(),N={query:e,gatheredContext:A||``,detailLevel:p,projectInfo:{root:C,taskCount:O.length,fileCount:c.length}},{systemPrompt:F,userPrompt:ee}=await M.loadPrompt(`research`,N),I=T.countTokens(F),L=T.countTokens(ee),te=I+L;if(S){let e=pe({taskIds:E,relatedTaskIds:D,files:c,projectTree:f,customContext:!!d});e&&console.log(e)}w.info(`Calling AI service with research role, context size: ${j.total} tokens (${A.length} characters)`);let ne=null,re=null;if(S){let e=Date.now();ne=X(`Researching…`),ne&&(re=setInterval(()=>{let t=Math.round((Date.now()-e)/1e3);ne.text=`Researching… ${t}s`},1e3))}let R;try{R=await t({role:`research`,session:_,projectRoot:C,systemPrompt:F,prompt:ee,commandName:y,outputType:b})}catch(e){throw w.error(`Research query failed: ${e.message}`),e}finally{re&&clearInterval(re),Z(ne)}let ie=Br(R.mainResult||``),ae=R.telemetryData,oe=R.tagInfo,z={interactiveSaveOccurred:!1},se;S&&(console.log(`\n${ce(ie)}`),ae&&Q(ae,`cli`));let le=[{question:e,answer:ie,type:`initial`,timestamp:(/* @__PURE__ */ new Date()).toISOString()}];return g&&(se=await Gr(le,C,r,w,i)),S&&a&&!x&&process.stdin.isTTY&&process.stdout.isTTY&&(z=await Hr(n,r,i,C,w,le)),w.success(`Research query completed successfully`),{query:e,result:ie,contextSize:A.length,contextTokens:j.total,tokenBreakdown:j,systemPromptTokens:I,userPromptTokens:L,totalInputTokens:te,detailLevel:p,telemetryData:ae,tagInfo:oe,...se?{savedFilePath:se}:{},interactiveSaveOccurred:z?.interactiveSaveOccurred||!1}}async function Hr(e,t,n,r,i,a){let o=!1;try{for(;;){console.log();let{action:s}=await xe.prompt([{type:`select`,name:`action`,message:`What next?`,choices:[{name:`Ask a follow-up`,value:`followup`},{name:`Save to a file`,value:`savefile`},{name:`Save to a task`,value:`save`},{name:`Done`,value:`quit`}]}]);if(s===`quit`)break;if(s===`savefile`)try{await Gr(a,r,t,i,n)}catch{}else if(s===`save`)await Wr(a,r,t,i)&&(o=!0);else if(s===`followup`){let{followUpQuery:r}=await xe.prompt([{type:`input`,name:`followUpQuery`,message:`Follow-up question:`,validate:e=>e&&e.trim().length>0?!0:`Type a question, or press Ctrl-C to stop`}]);console.log();let i=Jr(a),o={...e,taskIds:[],saveToFile:!1,customContext:i+(e.customContext?`\n\n--- Original Context ---\n${e.customContext}`:``)},s=await Vr(r.trim(),o,t,n,!1);a.push({question:r.trim(),answer:s.result,type:`followup`,timestamp:(/* @__PURE__ */ new Date()).toISOString()})}}}catch(e){e?.name!==`ExitPromptError`&&console.log(V.red(`✗ ${e.message}`)),i.debug(`Follow-up ended: ${e.message}`)}return{interactiveSaveOccurred:o}}function Ur(e,t,n,r={}){let{projectRoot:i,tag:a}=r,o=String(t).trim();if(!/^\d+(\.\d+)?$/.test(o))throw Error(`"${o}" isn't a task ID like 15 or 15.2`);let s=P(e,i,a);if(!s||!Array.isArray(s.tasks))throw Error(`No tasks found`);let[c,l]=o.split(`.`).map(e=>Number.parseInt(e,10)),u=s.tasks.find(e=>Number(e.id)===c);if(!u)throw Error(`Task ${c} doesn't exist`);let d=u;if(l!==void 0&&(d=(u.subtasks||[]).find(e=>Number(e.id)===l),!d))throw Error(`Subtask ${o} doesn't exist`);let f=(/* @__PURE__ */ new Date()).toISOString(),p=`<info added on ${f}>\n${n.trim()}\n</info added on ${f}>`;return d.details=d.details?`${d.details}\n${p}`:p,E(e,s,i,a),{id:o,title:d.title}}async function Wr(e,t,n,r){let{taskId:i}=await xe.prompt([{type:`input`,name:`taskId`,message:`Task ID (15, or 15.2 for a subtask):`,validate:e=>/^\d+(\.\d+)?$/.test((e||``).trim())?!0:`Use 15 for a task or 15.2 for a subtask`}]),a={kind:`task`,id:i.trim()},o=H.join(t,`.taskgraph`,`tasks`,`tasks.json`);try{return Ur(o,a.id,qr(e),{projectRoot:t,tag:n.tag}),console.log(fe(a)),!0}catch(e){return console.log(R(a,e.message)),r.debug(`Error saving conversation: ${e.message}`),!1}}async function Gr(e,t,n,r,i=`text`){try{let n=H.join(t,`.taskgraph`,`docs`,`research`);W.existsSync(n)||W.mkdirSync(n,{recursive:!0});let a=e[0]?.question||`research-query`,o=`${(/* @__PURE__ */ new Date()).toISOString().split(`T`)[0]}_${a.toLowerCase().replace(/[^a-z0-9\s-]/g,``).replace(/\s+/g,`-`).replace(/-+/g,`-`).substring(0,50).replace(/^-+|-+$/g,``)}.md`,s=H.join(n,o),c=Kr(e,a);W.writeFileSync(s,c,`utf8`);let l=H.relative(t,s);return i===`text`&&console.log(fe({kind:`file`,path:l})),r.success(`Research conversation saved to ${l}`),s}catch(e){throw i===`text`&&console.log(R({kind:`file`,path:``},e.message)),r.error(`Error saving research file: ${e.message}`),e}}function Kr(e,t){let n=(/* @__PURE__ */ new Date()).toISOString(),r=`---
|
|
614
|
+
title: Research Session
|
|
615
|
+
query: "${t}"
|
|
616
|
+
date: ${(/* @__PURE__ */ new Date()).toLocaleDateString()}
|
|
617
|
+
time: ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}
|
|
618
|
+
timestamp: ${n}
|
|
619
|
+
exchanges: ${e.length}
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
# Research Session
|
|
623
|
+
|
|
624
|
+
`;return e.forEach((t,n)=>{t.type===`initial`?r+=`## Initial Query\n\n**Question:** ${t.question}\n\n**Response:**\n\n${t.answer}\n\n`:r+=`## Follow-up ${n}\n\n**Question:** ${t.question}\n\n**Response:**\n\n${t.answer}\n\n`,n<e.length-1&&(r+=`---
|
|
625
|
+
|
|
626
|
+
`)}),r+=`\n---\n\n*Generated by TaskGraph Research Command* \n*Timestamp: ${n}*\n`,r}function qr(e){(/* @__PURE__ */ new Date()).toISOString();let t=`## Research Session - ${(/* @__PURE__ */ new Date()).toLocaleDateString()} ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}\n\n`;return e.forEach((n,r)=>{n.type===`initial`?(t+=`**Initial Query:** ${n.question}\n\n`,t+=`**Response:** ${n.answer}\n\n`):(t+=`**Follow-up ${r}:** ${n.question}\n\n`,t+=`**Response:** ${n.answer}\n\n`),r<e.length-1&&(t+=`---
|
|
627
|
+
|
|
628
|
+
`)}),t}function Jr(e){if(e.length===0)return``;let t=[`--- Conversation History ---`];return e.forEach((e,n)=>{let r=e.type===`initial`?`Initial Question`:`Follow-up ${n}`,i=e.type===`initial`?`Initial Answer`:`Answer ${n}`;t.push(`\n${r}: ${e.question}`),t.push(`${i}: ${e.answer}`)}),t.join(`
|
|
629
|
+
`)}const Yr=[`light`,`regular`,`heavy`],Xr=[`done`,`in-progress`,`review`,`cancelled`,`deferred`,`blocked`],Zr=[`pending`];function Qr(e){return Yr.includes(e)}async function $r(e,t,n){let{projectRoot:r,tag:i,session:a}=n;try{let n={tasks:[e],metadata:{analyzedAt:(/* @__PURE__ */ new Date()).toISOString()}},s=f(null,{projectRoot:r,tag:i},null);if(!s)return o(`warn`,`No complexity report found - cannot re-analyze complexity`),null;await mt({file:t,output:s,id:e.id.toString(),projectRoot:r,tag:i,_filteredTasksData:n,_originalTaskCount:1},{session:a});let c=O(s);if(c){let t=N(c,e.id);if(t)return o(`info`,`Re-analyzed task ${e.id} complexity: ${t.complexityScore}/10`),t.complexityScore}return o(`warn`,`Could not find updated complexity analysis for task ${e.id}`),null}catch(e){return o(`error`,`Failed to re-analyze task complexity: ${e.message}`),null}}function ei(e,t){let{projectRoot:n,tag:r}=t;try{let t=f(null,{projectRoot:n,tag:r},null);if(!t)return null;let i=O(t);if(!i)return null;let a=N(i,e);return a?a.complexityScore:null}catch(e){return o(`debug`,`Could not read current complexity score: ${e.message}`),null}}async function ti(e,t,n,i,a=`regular`,s=null){let{projectRoot:c,tag:l,session:u}=n;if(!e.subtasks||!Array.isArray(e.subtasks)||e.subtasks.length===0)return{updatedTask:e,regenerated:!1,preserved:0,generated:0};let d=e.subtasks.filter(e=>Xr.includes(e.status)),f=e.subtasks.filter(e=>Zr.includes(e.status));if(f.length===0)return{updatedTask:e,regenerated:!1,preserved:d.length,generated:0};let p,m=d.length,h=f.length,g=s?Math.max(.5,s/10):1,_=s?` (original complexity: ${s}/10)`:``;if(i===`up`){if(a===`light`){let e=Math.max(5,m+Math.ceil(h*1.1));p=Math.ceil(e*(.8+.4*g))}else if(a===`regular`){let e=Math.max(6,m+Math.ceil(h*1.3));p=Math.ceil(e*(.8+.4*g))}else{let e=Math.max(8,m+Math.ceil(h*1.6));p=Math.ceil(e*(.8+.6*g))}}else{let e=s>=8?.7:s>=6?.85:1;if(a===`light`){let t=Math.max(3,m+Math.ceil(h*.8));p=Math.ceil(t*e)}else if(a===`regular`){let t=Math.max(3,m+Math.ceil(h*.5));p=Math.ceil(t*e)}else{let e=s>=9?.3:s>=7?.5:.7,t=Math.max(2,m+Math.ceil(h*.25));p=Math.max(1,Math.ceil(t*e))}}o(`debug`,`Complexity-aware subtask calculation${_}: ${h} pending -> target ${p} total`),o(`debug`,`Complexity-aware calculation${_}: ${h} pending -> ${p} total subtasks (${a} ${i})`);let v=Math.max(1,p-m);try{let t=`Based on this updated task, generate ${v} NEW subtasks that reflect the ${i===`up`?`increased`:`decreased`} complexity level:
|
|
630
|
+
|
|
631
|
+
**Task Title**: ${e.title}
|
|
632
|
+
**Task Description**: ${e.description}
|
|
633
|
+
**Implementation Details**: ${e.details}
|
|
634
|
+
**Test Strategy**: ${e.testStrategy}
|
|
635
|
+
|
|
636
|
+
**Complexity Direction**: This task was recently scoped ${i} (${a} strength) to ${i===`up`?`increase`:`decrease`} complexity.
|
|
637
|
+
${s?`**Original Complexity**: ${s}/10 - consider this when determining appropriate scope level.`:``}
|
|
638
|
+
|
|
639
|
+
${m>0?`**Preserved Subtasks**: ${m} existing subtasks with work already done will be kept.`:``}
|
|
640
|
+
|
|
641
|
+
Generate subtasks that:
|
|
642
|
+
${i===`up`?a===`heavy`?`- Add comprehensive implementation steps with advanced features
|
|
643
|
+
- Include extensive error handling, validation, and edge cases
|
|
644
|
+
- Cover multiple integration scenarios and advanced testing
|
|
645
|
+
- Provide thorough documentation and optimization approaches`:a===`regular`?`- Add more detailed implementation steps
|
|
646
|
+
- Include additional error handling and validation
|
|
647
|
+
- Cover more edge cases and advanced features
|
|
648
|
+
- Provide more comprehensive testing approaches`:`- Add some additional implementation details
|
|
649
|
+
- Include basic error handling considerations
|
|
650
|
+
- Cover a few common edge cases
|
|
651
|
+
- Enhance testing approaches slightly`:a===`heavy`?`- Focus ONLY on absolutely essential core functionality
|
|
652
|
+
- Strip out ALL non-critical features (error handling, advanced testing, etc.)
|
|
653
|
+
- Provide only the minimum viable implementation
|
|
654
|
+
- Eliminate any complex integrations or advanced scenarios
|
|
655
|
+
- Aim for the simplest possible working solution`:a===`regular`?`- Focus on core functionality only
|
|
656
|
+
- Simplify implementation steps
|
|
657
|
+
- Remove non-essential features
|
|
658
|
+
- Streamline to basic requirements`:`- Focus mainly on core functionality
|
|
659
|
+
- Slightly simplify implementation steps
|
|
660
|
+
- Remove some non-essential features
|
|
661
|
+
- Streamline most requirements`}
|
|
662
|
+
|
|
663
|
+
Return a JSON object with a "subtasks" array. Each subtask should have:
|
|
664
|
+
- id: Sequential NUMBER starting from 1 (e.g., 1, 2, 3 - NOT "1", "2", "3")
|
|
665
|
+
- title: Clear, specific title
|
|
666
|
+
- description: Detailed description
|
|
667
|
+
- dependencies: Array of dependency IDs as STRINGS (use format ["${e.id}.1", "${e.id}.2"] for siblings, or empty array [] for no dependencies)
|
|
668
|
+
- details: Implementation guidance
|
|
669
|
+
- status: "pending"
|
|
670
|
+
- testStrategy: Testing approach
|
|
671
|
+
|
|
672
|
+
IMPORTANT:
|
|
673
|
+
- The 'id' field must be a NUMBER, not a string!
|
|
674
|
+
- Dependencies must be strings, not numbers!
|
|
675
|
+
|
|
676
|
+
Ensure the JSON is valid and properly formatted.`,o=U.object({subtasks:U.array(U.object({id:U.int().positive(),title:U.string().min(5),description:U.string().min(10),dependencies:U.array(U.string()),details:U.string().min(20),status:U.string(),testStrategy:U.string()}))}),c=(await r({role:n.research?`research`:`main`,session:n.session,systemPrompt:`You are an expert project manager who creates task breakdowns that match complexity levels.`,prompt:t,schema:o,objectName:`subtask_regeneration`,commandName:n.commandName||`subtask-regen-${i}`,outputType:n.outputType||`cli`,projectRoot:n.projectRoot})).mainResult.subtasks||[];ni(c);let l=c.map(e=>({...e,status:e.status||`pending`,testStrategy:e.testStrategy||``})),u=d.reduce((e,t)=>Math.max(e,t.id||0),0)+1,f=/* @__PURE__ */ new Map,p=l.map(e=>{let t=e.id,n=u++;return f.set(t,n),{...e,id:n}}).map(t=>({...t,dependencies:(t.dependencies||[]).map(t=>{if(typeof t!=`string`||!t.startsWith(`${e.id}.`))return t;let[,n]=t.split(`.`),r=Number.parseInt(n,10),i=f.get(r);return i?`${e.id}.${i}`:t})}));return e.subtasks=[...d,...p],{updatedTask:e,regenerated:!0,preserved:d.length,generated:p.length}}catch(t){return o(`warn`,`Failed to regenerate subtasks for task ${e.id}: ${t.message}`),{updatedTask:e,regenerated:!1,preserved:d.length,generated:0,error:t.message}}}function ni(e){if(!Array.isArray(e)||e.length===0)return;let t=e.map(e=>e.id);if(t.some(e=>!Number.isInteger(e)||e<1))throw Error(`Generated subtask ids must be positive integers`);let n=new Set(t);if(n.size!==t.length)throw Error(`Generated subtasks must have unique ids`);let r=[...n].sort((e,t)=>e-t);for(let e=0;e<r.length;e+=1)if(r[e]!==e+1)throw Error(`Generated subtask ids must be sequential starting from 1`)}function ri(e,t,n,r){let i=t===`up`,a={light:i?`minor enhancements`:`slight simplifications`,regular:i?`moderate complexity increases`:`moderate simplifications`,heavy:i?`significant complexity additions`:`major simplifications`},o=`You are tasked with adjusting the complexity of a task.
|
|
677
|
+
|
|
678
|
+
CURRENT TASK:
|
|
679
|
+
Title: ${e.title}
|
|
680
|
+
Description: ${e.description}
|
|
681
|
+
Details: ${e.details}
|
|
682
|
+
Test Strategy: ${e.testStrategy||`Not specified`}
|
|
683
|
+
|
|
684
|
+
ADJUSTMENT REQUIREMENTS:
|
|
685
|
+
- Direction: ${i?`INCREASE`:`DECREASE`} complexity
|
|
686
|
+
- Strength: ${n} (${a[n]})
|
|
687
|
+
- Preserve the core purpose and functionality of the task
|
|
688
|
+
- Maintain consistency with the existing task structure`;return o+=i?`
|
|
689
|
+
- Add more detailed requirements, edge cases, or advanced features
|
|
690
|
+
- Include additional implementation considerations
|
|
691
|
+
- Enhance error handling and validation requirements
|
|
692
|
+
- Expand testing strategies with more comprehensive scenarios`:`
|
|
693
|
+
- Focus on core functionality and essential requirements
|
|
694
|
+
- Remove or simplify non-essential features
|
|
695
|
+
- Streamline implementation details
|
|
696
|
+
- Simplify testing to focus on basic functionality`,r&&(o+=`\n\nCUSTOM INSTRUCTIONS:\n${r}`),o+=`
|
|
697
|
+
|
|
698
|
+
Return a JSON object with the updated task containing these fields:
|
|
699
|
+
- title: Updated task title
|
|
700
|
+
- description: Updated task description
|
|
701
|
+
- details: Updated implementation details
|
|
702
|
+
- testStrategy: Updated test strategy
|
|
703
|
+
- priority: Task priority ('low', 'medium', or 'high')
|
|
704
|
+
|
|
705
|
+
Ensure the JSON is valid and properly formatted.`,o}async function ii(e,t,n,i,a){let o=ri(e,t,n,i),s=U.object({title:U.string().min(1).describe(`Updated task title reflecting scope adjustment`),description:U.string().min(1).describe(`Updated task description with adjusted scope`),details:U.string().min(1).describe(`Updated implementation details with adjusted complexity`),testStrategy:U.string().min(1).describe(`Updated testing approach for the adjusted scope`),priority:U.enum([`low`,`medium`,`high`]).describe(`Task priority level`)}),c=await r({role:a.research?`research`:`main`,session:a.session,systemPrompt:`You are an expert software project manager who helps adjust task complexity while maintaining clarity and actionability.`,prompt:o,schema:s,objectName:`updated_task`,commandName:a.commandName||`scope-${t}`,outputType:a.outputType||`cli`,projectRoot:a.projectRoot}),l=c.mainResult,u={...l,priority:l.priority||e.priority||`medium`};return{updatedTask:{...e,...u},telemetryData:c.telemetryData}}async function ai(e,t,n=`regular`,r=null,i={},a=`text`){if(!Qr(n))throw Error(`Invalid strength level: ${n}. Must be one of: ${Yr.join(`, `)}`);let{projectRoot:s=`.`,tag:c=`master`}=i,l=P(e,s,c),u=l?.tasks||[];for(let e of t)if(!Rr(u,e))throw Error(`Task with ID ${e} not found`);let f=[],p=null;for(let m of t){let t=d(u,m).task;if(!t)throw Error(`Task with ID ${m} not found`);a===`text`&&o(`debug`,`Scoping up task ${m}: ${t.title}`);let h=ei(m,i);h&&a===`text`&&o(`debug`,`Original complexity: ${h}/10`);let g=await ii(t,`up`,n,r,i),_=await ti(g.updatedTask,e,i,`up`,n,h);a===`text`&&_.regenerated&&o(`info`,`Regenerated ${_.generated} pending subtasks (preserved ${_.preserved} completed)`);let v=l.tasks.findIndex(e=>e.id===m);if(v!==-1&&(l.tasks[v]=_.updatedTask,f.push(_.updatedTask)),i.session&&h)try{E(e,l,s,c);let t=await $r(_.updatedTask,e,i);if(t&&a===`text`){let e=t-h;o(`info`,`New complexity: ${h}/10 ${e>0?`↗️`:e<0?`↘️`:`➡️`} ${t}/10 (${e>0?`+`:``}${e})`)}}catch(e){a===`text`&&o(`warn`,`Could not re-analyze complexity: ${e.message}`)}g.telemetryData&&(p?(p.inputTokens+=g.telemetryData.inputTokens||0,p.outputTokens+=g.telemetryData.outputTokens||0,p.totalTokens+=g.telemetryData.totalTokens||0,p.totalCost+=g.telemetryData.totalCost||0):p={...g.telemetryData})}return E(e,l,s,c),a===`text`&&o(`debug`,`Successfully scoped up ${f.length} task(s)`),{updatedTasks:f,telemetryData:p}}async function oi(e,t,n=`regular`,r=null,i={},a=`text`){if(!Qr(n))throw Error(`Invalid strength level: ${n}. Must be one of: ${Yr.join(`, `)}`);let{projectRoot:s=`.`,tag:c=`master`}=i,l=P(e,s,c),u=l?.tasks||[];for(let e of t)if(!Rr(u,e))throw Error(`Task with ID ${e} not found`);let f=[],p=null;for(let m of t){let t=d(u,m).task;if(!t)throw Error(`Task with ID ${m} not found`);a===`text`&&o(`debug`,`Scoping down task ${m}: ${t.title}`);let h=ei(m,i);h&&a===`text`&&o(`debug`,`Original complexity: ${h}/10`);let g=await ii(t,`down`,n,r,i),_=await ti(g.updatedTask,e,i,`down`,n,h);a===`text`&&_.regenerated&&o(`info`,`Regenerated ${_.generated} pending subtasks (preserved ${_.preserved} completed)`);let v=l.tasks.findIndex(e=>e.id===m);if(v!==-1&&(l.tasks[v]=_.updatedTask,f.push(_.updatedTask)),i.session&&h)try{E(e,l,s,c);let t=await $r(_.updatedTask,e,i);if(t&&a===`text`){let e=t-h;o(`info`,`New complexity: ${h}/10 ${e>0?`↗️`:e<0?`↘️`:`➡️`} ${t}/10 (${e>0?`+`:``}${e})`)}}catch(e){a===`text`&&o(`warn`,`Could not re-analyze complexity: ${e.message}`)}g.telemetryData&&(p?(p.inputTokens+=g.telemetryData.inputTokens||0,p.outputTokens+=g.telemetryData.outputTokens||0,p.totalTokens+=g.telemetryData.totalTokens||0,p.totalCost+=g.telemetryData.totalCost||0):p={...g.telemetryData})}return E(e,l,s,c),a===`text`&&o(`debug`,`Successfully scoped down ${f.length} task(s)`),{updatedTasks:f,telemetryData:p}}async function si(e,t,n,r,i=!0){if(!Oe(n))throw Error(`Error: Invalid status value: ${n}. Use one of: ${TASK_STATUS_OPTIONS.join(`, `)}`);if(t.includes(`.`)){let[e,a]=t.split(`.`).map(e=>parseInt(e,10)),s=r.tasks.find(t=>t.id===e);if(!s)throw Error(`Parent task ${e} not found`);if(!s.subtasks)throw Error(`Parent task ${e} has no subtasks`);let c=s.subtasks.find(e=>e.id===a);if(!c)throw Error(`Subtask ${a} not found in parent task ${e}`);let l=c.status||`pending`;c.status=n,o(`debug`,`Updated subtask ${e}.${a} status from '${l}' to '${n}'`),(n.toLowerCase()===`done`||n.toLowerCase()===`completed`)&&s.subtasks.every(e=>e.status===`done`||e.status===`completed`)&&s.status!==`done`&&s.status!==`completed`&&i&&(console.log(V.yellow(`All subtasks of parent task ${e} are now marked as done.`)),console.log(V.yellow(`Consider updating the parent task status with: taskgraph set-status --id=${e} --status=done`)))}else{let e=parseInt(t,10),i=r.tasks.find(t=>t.id===e);if(!i)throw Error(`Task ${e} not found`);let a=i.status||`pending`;if(i.status=n,o(`debug`,`Updated task ${e} status from '${a}' to '${n}'`),(n.toLowerCase()===`done`||n.toLowerCase()===`completed`)&&i.subtasks&&i.subtasks.length>0){let e=i.subtasks.filter(e=>e.status!==`done`&&e.status!==`completed`);e.length>0&&(o(`info`,`Also marking ${e.length} subtasks as '${n}'`),e.forEach(e=>{e.status=n}))}}}async function ci(e,t,n,r={}){let{projectRoot:i,tag:a}=r;try{if(!Oe(n))throw Error(`Error: Invalid status value: ${n}. Use one of: ${De.join(`, `)}`);let s=!!r?.mcpLog;s||console.log(G(w.text.bold(`Updating Task Status to: ${n}`),{padding:1,borderColor:b,borderStyle:`round`})),o(`debug`,`Reading tasks from ${e}...`);let c=P(e,i,a);if(c&&c._rawTaggedData&&(c=c._rawTaggedData),!c||!c[a]||!Array.isArray(c[a].tasks))throw Error(`Invalid tasks file or tag "${a}" not found at ${e}`);let l={tasks:c[a].tasks,tag:a,_rawTaggedData:c};if(!l||!l.tasks)throw Error(`No valid tasks found in ${e}`);let u=t.split(`,`).map(e=>e.trim()),d=[];for(let t of u){let r=`unknown`;if(t.includes(`.`)){let[e,n]=t.split(`.`).map(e=>parseInt(e,10)),i=l.tasks.find(t=>t.id===e);i?.subtasks&&(r=i.subtasks.find(e=>e.id===n)?.status||`pending`)}else{let e=parseInt(t,10);r=l.tasks.find(t=>t.id===e)?.status||`pending`}await si(e,t,n,l,!s),d.push({id:t,oldStatus:r,newStatus:n})}if(c[a].tasks=l.tasks,h(c[a],{description:`Tasks for ${a} context`}),E(e,c,i,a),o(`debug`,`Validating dependencies after status update...`),Ui(l.tasks),!s)for(let e of d){let{id:t,oldStatus:n,newStatus:r}=e;console.log(G(w.text.bold(`Successfully updated task ${t} status:`)+`
|
|
706
|
+
From: ${V.yellow(n)}\nTo: ${V.green(r)}`,{padding:1,borderColor:`green`,borderStyle:`round`}))}return{success:!0,updatedTasks:d.map(({id:e,oldStatus:t,newStatus:n})=>({id:e,oldStatus:t,newStatus:n}))}}catch(e){if(o(`error`,`Error setting task status: ${e.message}`),!r?.mcpLog)console.error(V.red(`Error: ${e.message}`)),k(r?.session)&&console.error(e),process.exit(1);else throw e}}async function li(e,n,r,i=!1,a={},s=a.mcpLog?`json`:`text`){let{session:d,mcpLog:f,projectRoot:m,tag:h,metadata:g}=a,_=f||o,v=!!f,b=(e,...t)=>{v?typeof _[e]==`function`?_[e](...t):_.info(...t):p()||_(e,...t)},x=null;try{if(b(`debug`,`Updating subtask ${n} with prompt: "${r}"`),!n||typeof n!=`string`)throw Error(`Subtask ID cannot be empty.`);if((!r||typeof r!=`string`||r.trim()===``)&&!g)throw Error(`Prompt cannot be empty unless metadata is provided. Please provide context for the subtask update or metadata to merge.`);let a=m||l();if(!a)throw Error(`Could not determine project root directory`);if(!n.includes(`.`))throw Error(`Invalid subtask ID format: ${n}. In solo mode, subtask ID must be in format "parentId.subtaskId" (e.g., "5.2").`);if(!W.existsSync(e))throw Error(`Tasks file not found at path: ${e}`);let o=P(e,a,h);if(!o||!o.tasks)throw Error(`No valid tasks found in ${e}. The file may be corrupted or have an invalid format.`);let[f,p]=n.split(`.`),_=parseInt(f,10),S=parseInt(p,10);if(Number.isNaN(_)||_<=0||Number.isNaN(S)||S<=0)throw Error(`Invalid subtask ID format: ${n}. Both parent ID and subtask ID must be positive integers.`);let C=o.tasks.find(e=>e.id===_);if(!C)throw Error(`Task ${_} not found`);if(!C.subtasks||!Array.isArray(C.subtasks))throw Error(`Parent task ${_} has no subtasks.`);let T=C.subtasks.findIndex(e=>e.id===S);if(T===-1)throw Error(`Subtask ${n} not found`);let D=C.subtasks[T];if(g&&(!r||r.trim()===``))return b(`debug`,`Metadata-only update for subtask ${n}`),D.metadata={...D.metadata||{},...g},C.subtasks[T]=D,E(e,o,a,h),b(`success`,`Successfully updated metadata for subtask ${n}`),{updatedSubtask:D,telemetryData:null,tagInfo:{tag:h}};let O=``;try{let e=new ot(a,h),t=new ft(u(o.tasks),`update-subtask`),i=`${C.title} ${D.title} ${r}`,s=t.findRelevantTasks(i,{maxResults:5,includeSelf:!0}),c=t.getTaskIds(s),l=[.../* @__PURE__ */ new Set([n.toString(),...c])];l.length>0&&(O=(await e.gather({tasks:l,format:`research`})).context||``)}catch(e){b(`warn`,`Could not gather context: ${e.message}`)}s===`text`&&(x=X(`Updating subtask ${n}: ${y(D.title,50)}${i?` (with research)`:``}`));let A=``,j=``,M=null;try{let e={id:C.id,title:C.title},n=T>0?{id:`${C.id}.${C.subtasks[T-1].id}`,title:C.subtasks[T-1].title,status:C.subtasks[T-1].status}:void 0,o=T<C.subtasks.length-1?{id:`${C.id}.${C.subtasks[T+1].id}`,title:C.subtasks[T+1].title,status:C.subtasks[T+1].status}:void 0,l=it(),u={parentTask:e,prevSubtask:n,nextSubtask:o,currentDetails:D.details||`(No existing details)`,updatePrompt:r,useResearch:i,gatheredContext:O||``,hasCodebaseAnalysis:c(i,a,d),projectRoot:a},f=i?`research`:`default`,{systemPrompt:p,userPrompt:m}=await l.loadPrompt(`update-subtask`,u,f),h=i?`research`:`main`;b(`debug`,`Using AI text service with role: ${h}`),M=await t({prompt:m,systemPrompt:p,role:h,session:d,projectRoot:a,maxRetries:2,commandName:`update-subtask`,outputType:v?`mcp`:`cli`}),M&&M.mainResult&&typeof M.mainResult==`string`?A=M.mainResult:(A=``,b(`warn`,`AI service response did not contain expected text string.`)),s===`text`&&x&&(Z(x),x=null)}catch(e){throw s===`text`&&x&&(Z(x),x=null),e}if(A&&A.trim()){let e=(/* @__PURE__ */ new Date()).toISOString(),t=`<info added on ${e}>\n${A.trim()}\n</info added on ${e}>`;j=t,D.details=(D.details?D.details+`
|
|
707
|
+
`:``)+t}else b(`warn`,`AI response was empty or whitespace after trimming. Original details remain unchanged.`),j=`No new details were added by the AI.`;let N=C.subtasks[T];return g&&(N.metadata={...N.metadata||{},...g}),s===`text`&&k(d)&&console.log(`>>> DEBUG: Subtask details AFTER AI update:`,N.details),N.description&&r.length<100&&(s===`text`&&k(d)&&console.log(`>>> DEBUG: Subtask description BEFORE append:`,N.description),N.description+=` [Updated: ${(/* @__PURE__ */ new Date()).toLocaleDateString()}]`,s===`text`&&k(d)&&console.log(`>>> DEBUG: Subtask description AFTER append:`,N.description)),s===`text`&&k(d)&&console.log(`>>> DEBUG: About to call writeJSON with updated data...`),E(e,o,a,h),s===`text`&&k(d)&&console.log(`>>> DEBUG: writeJSON call completed.`),b(`debug`,`Successfully updated subtask ${n}`),s===`text`&&(x&&=(Z(x),null),console.log(G(V.green(`Successfully updated subtask #${n}`)+`
|
|
708
|
+
|
|
709
|
+
`+w.text.bold(`Title:`)+` `+N.title+`
|
|
710
|
+
|
|
711
|
+
`+w.text.bold(`Newly Added Snippet:`)+`
|
|
712
|
+
`+w.text(j),{padding:1,borderColor:`green`,borderStyle:`round`}))),s===`text`&&M.telemetryData&&Q(M.telemetryData,`cli`),{updatedSubtask:N,telemetryData:M.telemetryData,tagInfo:M.tagInfo}}catch(e){throw s===`text`&&x&&(Z(x),x=null),s!==`text`&&b(`error`,`Error updating subtask: ${e.message}`),e}}async function ui(e,n,i,a=!1,o={},s=`text`,d=!1){let{session:f,mcpLog:p,projectRoot:m,tag:h,metadata:g}=o,{report:_,isMCP:v}=vt(p,f);try{if(_(`debug`,`Updating single task ${n} with prompt: "${i}"`),n==null||String(n).trim()===``)throw Error(`Task ID cannot be empty.`);if((!i||typeof i!=`string`||i.trim()===``)&&!g)throw Error(`Prompt cannot be empty unless metadata is provided for update.`);let o=m||l();if(!o)throw Error(`Could not determine project root directory`);if(!W.existsSync(e))throw Error(`Tasks file not found: ${e}`);let p=P(e,o,h);if(!p||!p.tasks)throw Error(`No valid tasks found in ${e}.`);let b=String(n).trim();if(!/^\d+$/.test(b))throw Error(`taskId must be a positive integer. Use update-subtask-by-id for IDs like "1.2".`);let x=Number(b),S=p.tasks.findIndex(e=>e.id===x);if(S===-1)throw Error(`Task ${x} not found`);let C=p.tasks[S];if(C.status===`done`||C.status===`completed`)return _(`warn`,`Task ${n} is already marked as done and cannot be updated`),s===`text`&&console.log(G(V.yellow(`Task ${n} is already marked as ${C.status} and cannot be updated.`)+`
|
|
713
|
+
|
|
714
|
+
`+w.text(`Completed tasks are locked to maintain consistency. To modify a completed task, you must first:`)+`
|
|
715
|
+
`+w.text(`1. Change its status to "pending" or "in-progress"`)+`
|
|
716
|
+
`+w.text(`2. Then run the update-task command`),{padding:1,borderColor:`yellow`,borderStyle:`round`})),null;if(g&&(!i||i.trim()===``))return _(`debug`,`Metadata-only update for task ${n}`),C.metadata={...C.metadata||{},...g},p.tasks[S]=C,E(e,p,o,h),_(`success`,`Successfully updated metadata for task ${n}`),{updatedTask:C,telemetryData:null,tagInfo:{tag:h}};let T=``;try{let e=new ot(o,h),t=new ft(u(p.tasks),`update-task`),r=`${C.title} ${C.description} ${i}`,a=t.findRelevantTasks(r,{maxResults:5,includeSelf:!0}),s=t.getTaskIds(a),c=[.../* @__PURE__ */ new Set([n.toString(),...s])];c.length>0&&(T=(await e.gather({tasks:c,format:`research`})).context||``)}catch(e){_(`warn`,`Could not gather context: ${e.message}`)}let D=it(),O={task:C,taskJson:JSON.stringify(C,null,2),updatePrompt:i,appendMode:d,useResearch:a,currentDetails:C.details||`(No existing details)`,gatheredContext:T||``,hasCodebaseAnalysis:c(a,o,f),projectRoot:o},k=d?`append`:a?`research`:`default`;_(`debug`,`Loading prompt template with variant: ${k}, appendMode: ${d}, useResearch: ${a}`);let A,j;try{let e=D.loadPrompt(`update-task`,O,k);_(`debug`,`Prompt result type: ${typeof e}, keys: ${e?Object.keys(e).join(`, `):`null`}`),A=e.systemPrompt,j=e.userPrompt,_(`debug`,`Loaded prompts - systemPrompt length: ${A?.length}, userPrompt length: ${j?.length}`)}catch(e){throw _(`error`,`Failed to load prompt template: ${e.message}`),Error(`Failed to load prompt template: ${e.message}`)}if(!A||!j)throw Error(`Failed to load prompts: systemPrompt=${!!A}, userPrompt=${!!j}`);let M=null,N=null;!v&&s===`text`&&(M=X(`Updating task ${n}: ${y(C.title,50)}${a?` (with research)`:``}`));try{let c=a?`research`:`main`;if(N=d?await t({role:c,session:f,projectRoot:o,systemPrompt:A,prompt:j,commandName:`update-task`,outputType:v?`mcp`:`cli`}):await r({role:c,session:f,projectRoot:o,systemPrompt:A,prompt:j,schema:Ke[`update-task-by-id`],objectName:`task`,commandName:`update-task`,outputType:v?`mcp`:`cli`}),M&&Z(M,`AI update complete.`),d){let t=N.mainResult,r=``;if(t&&t.trim()){let e=(/* @__PURE__ */ new Date()).toISOString(),n=`<info added on ${e}>\n${t.trim()}\n</info added on ${e}>`;r=n,C.details=(C.details?C.details+`
|
|
717
|
+
`:``)+n}else _(`warn`,`AI response was empty or whitespace after trimming. Original details remain unchanged.`),r=`No new details were added by the AI.`;return i.length<100&&C.description&&(C.description+=` [Updated: ${(/* @__PURE__ */ new Date()).toLocaleDateString()}]`),g&&(C.metadata={...C.metadata||{},...g}),p.tasks[S]=C,E(e,p,o,h),_(`debug`,`Successfully appended to task ${n}`),s===`text`&&console.log(G(V.green(`Successfully appended to task #${n}`)+`
|
|
718
|
+
|
|
719
|
+
`+w.text.bold(`Title:`)+` `+C.title+`
|
|
720
|
+
|
|
721
|
+
`+w.text.bold(`Newly Added Content:`)+`
|
|
722
|
+
`+w.text(r),{padding:1,borderColor:`green`,borderStyle:`round`})),s===`text`&&N.telemetryData&&Q(N.telemetryData,`cli`),{updatedTask:C,telemetryData:N.telemetryData,tagInfo:N.tagInfo}}let l=N.mainResult?.task;if(!l||typeof l!=`object`)throw Error(`Received invalid task object from AI.`);let u={...l,dependencies:l.dependencies??[],priority:l.priority??null,details:l.details??null,testStrategy:l.testStrategy??null};if(!u.title||!u.description)throw Error(`Updated task missing required fields.`);if(u.id!==n&&(_(`debug`,`AI changed task ID. Restoring original ID ${n}.`),u.id=n),u.status!==C.status&&!i.toLowerCase().includes(`status`)&&(_(`warn`,`AI changed task status. Restoring original status '${C.status}'.`),u.status=C.status),u.subtasks&&Array.isArray(u.subtasks)){let e=1;u.subtasks=u.subtasks.map(t=>{let n=C.subtasks?.find(e=>String(e.id)===String(t.id)||t.title&&e.title===t.title),r={...t,id:e,dependencies:Array.isArray(t.dependencies)?t.dependencies.map(e=>typeof e==`string`?parseInt(e,10):e).filter(t=>!Number.isNaN(t)&&t>=1&&t<e):[],status:t.status||`pending`,testStrategy:t.testStrategy??null,...n?.metadata&&{metadata:n.metadata}};return e++,r}),_(`debug`,`Fixed ${u.subtasks.length} subtask IDs to be sequential numeric IDs.`)}if(C.subtasks?.length>0){if(!u.subtasks)_(`warn`,`Subtasks removed by AI. Restoring original subtasks.`),u.subtasks=C.subtasks;else{C.subtasks.filter(e=>e.status===`done`||e.status===`completed`).forEach(e=>{let t=u.subtasks.find(t=>t.id===e.id);(!t||JSON.stringify(t)!==JSON.stringify(e))&&(_(`warn`,`Completed subtask ${e.id} was modified or removed. Restoring.`),u.subtasks=u.subtasks.filter(t=>t.id!==e.id),u.subtasks.push(e))});let e=/* @__PURE__ */ new Set;u.subtasks=u.subtasks.filter(t=>e.has(t.id)?(_(`warn`,`Duplicate subtask ID ${t.id} removed.`),!1):(e.add(t.id),!0))}}return(C.metadata||g)&&(u.metadata={...C.metadata||{},...g||{}}),p.tasks[S]=u,E(e,p,o,h),_(`success`,`Updated task ${n}`),s===`text`&&N.telemetryData&&Q(N.telemetryData,`cli`),{updatedTask:u,telemetryData:N.telemetryData,tagInfo:N.tagInfo}}catch(e){throw M&&Z(M),e}}catch(e){throw s!==`text`&&_(`error`,`Error updating task: ${e.message}`),e}}async function di(e,t,n,i=!1,a={},s=`text`){let{session:d,mcpLog:f,projectRoot:p,tag:m}=a,h=f||o,g=!!f;g?h.debug(`updateTasks called with context: session=${!!d}`):h(`info`,`updateTasks called`);try{g?h.debug(`Updating tasks from ID ${t}`):h(`debug`,`Updating tasks from ID ${t} with prompt: "${n}"`);let a=p||l();if(!a)throw Error(`Could not determine project root directory`);let o=P(e,a,m);if(!o||!o.tasks)throw Error(`No valid tasks found in ${e}`);let f=o.tasks.filter(e=>e.id>=t&&e.status!==`done`);if(f.length===0){g?h.info(`No tasks to update (ID >= ${t} and not 'done').`):h(`info`,`No tasks to update (ID >= ${t} and not 'done').`),s===`text`&&console.log();return}let _=``;try{let e=new ot(a,m),t=new ft(u(o.tasks),`update`),r=t.findRelevantTasks(n,{maxResults:5,includeSelf:!0}),i=t.getTaskIds(r),s=f.map(e=>e.id.toString()),c=[.../* @__PURE__ */ new Set([...s,...i])];c.length>0&&(_=(await e.gather({tasks:c,format:`research`})).context||``)}catch(e){h(`warn`,`Could not gather additional context: ${e.message}`)}if(s===`text`){let e=new ye({head:[V.cyan.bold(`ID`),V.cyan.bold(`Title`),V.cyan.bold(`Status`)],colWidths:[5,70,20],style:{border:D}});f.forEach(t=>{e.push([t.id,y(t.title,57),xi(t.status)])}),console.log(G(w.text.bold(`Updating ${f.length} tasks`),{padding:1,borderColor:b,borderStyle:`round`,margin:{top:1,bottom:0}})),console.log(e.toString())}let{systemPrompt:v,userPrompt:x}=await it().loadPrompt(`update-tasks`,{tasks:f,updatePrompt:n,useResearch:i,projectContext:_,hasCodebaseAnalysis:c(i,a,d),projectRoot:a}),S=null,C=null;!g&&s===`text`&&(S=X(`Updating tasks with AI...
|
|
723
|
+
`));try{C=await r({role:i?`research`:`main`,session:d,projectRoot:a,systemPrompt:v,prompt:x,schema:Ke[`update-tasks`],objectName:`tasks`,commandName:`update-tasks`,outputType:g?`mcp`:`cli`}),S&&Z(S,`AI update complete.`);let t=C.mainResult.tasks.map(e=>({...e,dependencies:e.dependencies??[],priority:e.priority??null,details:e.details??null,testStrategy:e.testStrategy??null,subtasks:e.subtasks?e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})):null}));if(!Array.isArray(t))throw Error(`Parsed AI response for updated tasks was not an array.`);g?h.info(`Received ${t.length} updated tasks from AI.`):h(`debug`,`Received ${t.length} updated tasks from AI.`);let n=new Map(t.map(e=>[e.id,e])),c=0;return o.tasks.forEach((e,t)=>{if(n.has(e.id)){let r=n.get(e.id);o.tasks[t]={...e,...r,subtasks:r.subtasks===void 0?e.subtasks:r.subtasks},c++}}),g?h.info(`Applied updates to ${c} tasks in the dataset.`):h(`debug`,`Applied updates to ${c} tasks in the dataset.`),E(e,o,a,m),g?h.info(`Successfully updated ${c} tasks in ${e}`):h(`success`,`Successfully updated ${c} tasks in ${e}`),s===`text`&&C.telemetryData&&Q(C.telemetryData,`cli`),{success:!0,updatedTasks:t,telemetryData:C.telemetryData,tagInfo:C.tagInfo}}catch(e){throw S&&Z(S),g?h.error(`Error during AI service call: ${e.message}`):h(`error`,`Error during AI service call: ${e.message}`),e.message.includes(`API key`)&&(g?h.error(`Please ensure API keys are configured correctly in .env or mcp.json.`):h(`error`,`Please ensure API keys are configured correctly in .env or mcp.json.`)),e}finally{S&&Z(S)}}catch(e){if(g?h.error(`Error updating tasks: ${e.message}`):h(`error`,`Error updating tasks: ${e.message}`),s===`text`)console.error(V.red(`Error: ${e.message}`)),k(d)&&console.error(e),process.exit(1);else throw e}}const{theme:Y,BORDER_COLOR:fi,TABLE_BORDER:pi}=me;ve(L);function mi(e){!p()&&e&&e._migrationHappened&&console.log(G(V.bold(`FYI: `)+Y.muted(`TaskGraph now supports separate task lists per tag. `)+V.cyan(`Use the --tag flag to create/read/update/filter tasks by tag.`),{padding:{top:0,bottom:0,left:2,right:2},borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}))}async function hi(e,t={}){if(p())return;let{skipIfMaster:n=!1,dim:r=!1}=t;if(n&&e===`master`)return;let i=r?Y.muted(`[tag] ${e}`):V.dim(`[tag] `)+V.cyan(e);console.log(i)}function gi(){p()||ie({version:ke(),projectName:S(null)})}function X(e){return p()?null:ue(e).start()}function _i(e){return p()?null:new z(e).start()}function Z(e){e&&typeof e.stop==`function`&&e.stop()}function vi(e,t=null){e&&typeof e.succeed==`function`&&(t?e.succeed(t):e.succeed())}function yi(e,t=null){e&&typeof e.fail==`function`&&(t?e.fail(t):e.fail())}function bi(e,t=30,n=null){let r=n?Math.min(100,e+(n.deferred||0)+(n.cancelled||0)):e,i=Math.round(e*t/100),a=Math.round(r*t/100),o=a-i,s=t-a,c;c=e<25?V.red:e<50||e<75?V.yellow:V.green;let l=c(`█`.repeat(i)),u=Y.muted(`─`.repeat(o)),d=``;if(n&&s>0){let e={pending:e=>V.yellow(`░`.repeat(e)),"in-progress":e=>Y.active(`▓`.repeat(e)),blocked:e=>V.red(`!`.repeat(e)),review:e=>V.magenta(`▒`.repeat(e))},t=Object.entries(n).filter(([e])=>![`deferred`,`cancelled`,`done`,`completed`].includes(e)).reduce((e,[t,n])=>e+n,0);if(t<=0)d=Y.muted(`░`.repeat(s));else{let r=0;for(let[i,a]of Object.entries(n)){if([`deferred`,`cancelled`,`done`,`completed`].includes(i))continue;let n=Math.round(a/t*s),o=Math.min(n,s-r),c=e[i]||(e=>Y.muted(`░`.repeat(e)));d+=c(o),r+=o}r<s&&(d+=Y.muted(`░`.repeat(s-r)))}}else d=Y.muted(`░`.repeat(s));let f=e===100?V.green:r===100?Y.muted:c;return`${l}${u}${d} ${f(`${r.toFixed(0)}%`)}`}function xi(e,t=!1){if(!e)return Y.muted(`? unknown`);let n={done:{color:V.green,icon:`✓`,tableIcon:`✓`},completed:{color:V.green,icon:`✓`,tableIcon:`✓`},pending:{color:V.yellow,icon:`○`,tableIcon:`⏱`},"in-progress":{color:Y.active,icon:`▶`,tableIcon:`▶`},deferred:{color:Y.muted,icon:`x`,tableIcon:`⏱`},blocked:{color:V.red,icon:`!`,tableIcon:`✗`},review:{color:V.magenta,icon:`?`,tableIcon:`?`},cancelled:{color:Y.muted,icon:`x`,tableIcon:`x`}}[e.toLowerCase()]||{color:V.red,icon:`✗`,tableIcon:`✗`};if(t){let t={done:`✓`,completed:`✓`,pending:`○`,"in-progress":`►`,deferred:`x`,blocked:`!`,review:`?`}[e.toLowerCase()]||`x`;return n.color(`${t} ${e}`)}return n.color(`${n.icon} ${e}`)}function Si(e,t,n=!1,r=null){return!e||!Array.isArray(e)||e.length===0?n?Y.muted(`None`):`None`:e.map(e=>{let i=e.toString();if(i.includes(`.`)){let a=i.split(`.`);if(a.length!==2||!a[0]||!a[1]){let a=d(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?V.green.bold(i):c?V.yellow.bold(i):V.red.bold(i):i}let[o,s]=a.map(e=>parseInt(e,10)),c=t.find(e=>e.id===o);if(!c||!c.subtasks)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let l=c.subtasks.find(e=>e.id===s);if(!l)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let u=l.status||`pending`,f=u.toLowerCase()===`done`||u.toLowerCase()===`completed`,p=u.toLowerCase()===`in-progress`;return n?f?V.green.bold(i):p?Y.active.bold(i):V.red.bold(i):i}let a=d(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?V.green.bold(i):c?V.yellow.bold(i):V.red.bold(i):i}).join(`, `)}function Ci(){let e=process.stdout.columns||100;console.log(G(V.bold(`TaskGraph CLI`),{padding:1,borderColor:fi,borderStyle:`round`,margin:{top:1,bottom:1}})),[{title:`Project Setup & Configuration`,color:`blue`,commands:[{name:`init`,args:`[--name=<name>] [--description=<desc>] [-y]`,desc:`Initialize a new project with TaskGraph structure`},{name:`models`,args:``,desc:`View current AI model configuration and available models`},{name:`models --setup`,args:``,desc:`Run interactive setup to configure AI models`},{name:`models --set-main`,args:`<model_id>`,desc:`Set the primary model for task generation`},{name:`models --set-research`,args:`<model_id>`,desc:`Set the model for research operations`},{name:`models --set-fallback`,args:`<model_id>`,desc:`Set the fallback model (optional)`},{name:`completion --install`,args:``,desc:`Set up Tab completion for your shell`}]},{title:`Task Generation`,color:`cyan`,commands:[{name:`parse-prd`,args:`--input=<file.txt> [--num-tasks=10]`,desc:`Generate tasks from a PRD document`},{name:`generate`,args:``,desc:`Create individual task files from tasks.json`}]},{title:`Task Management`,color:`green`,commands:[{name:`list`,args:`[<status>|all] [-s <status>] [-t <tag>]`,desc:`List all tasks - use "all" to show with subtasks`},{name:`list`,args:`[--with-subtasks] [-f <format>] [--json] [-c]`,desc:`Options: format (text/json/compact), subtasks`},{name:`list`,args:`[-w] [--ready] [--blocking] [--all-tags]`,desc:`Options: watch mode, ready/blocking filters, all tags`},{name:`set-status`,args:`<id> <status>`,desc:`Update task status (${De.join(`, `)})`},{name:`sync-readme`,args:`[--with-subtasks] [--status=<status>]`,desc:`Export tasks to README.md with professional formatting`},{name:`update`,args:`--from=<id> --prompt="<context>"`,desc:`Update multiple tasks based on new requirements`},{name:`update-task`,args:`<id> <prompt...>`,desc:`Update a single task (no quotes needed for multi-word prompts)`},{name:`update-subtask`,args:`--id=<parentId.subtaskId> --prompt="<context>"`,desc:`Append additional information to a subtask`},{name:`add-task`,args:`--prompt="<text>" [--dependencies=<ids>] [--priority=<priority>]`,desc:`Add a new task using AI`},{name:`remove-task`,args:`--id=<id> [-y]`,desc:`Permanently remove a task or subtask`}]},{title:`Subtask Management`,color:`yellow`,commands:[{name:`add-subtask`,args:`--parent=<id> --title="<title>" [--description="<desc>"]`,desc:`Add a new subtask to a parent task`},{name:`add-subtask`,args:`--parent=<id> --task-id=<id>`,desc:`Convert an existing task into a subtask`},{name:`remove-subtask`,args:`--id=<parentId.subtaskId> [--convert]`,desc:`Remove a subtask (optionally convert to standalone task)`},{name:`clear-subtasks`,args:`--id=<id>`,desc:`Remove all subtasks from specified tasks`},{name:`clear-subtasks --all`,args:``,desc:`Remove subtasks from all tasks`}]},{title:`Task Analysis & Breakdown`,color:`magenta`,commands:[{name:`analyze-complexity`,args:`[--research] [--threshold=5]`,desc:`Analyze tasks and generate expansion recommendations`},{name:`complexity-report`,args:`[--file=<path>]`,desc:`Display the complexity analysis report`},{name:`expand`,args:`--id=<id> [--num=5] [--research] [--prompt="<context>"]`,desc:`Break down tasks into detailed subtasks`},{name:`expand --all`,args:`[--force] [--research]`,desc:`Expand all pending tasks with subtasks`},{name:`research`,args:`"<prompt>" [-i=<task_ids>] [-f=<file_paths>] [-c="<context>"] [--tree] [-s=<save_file>] [-d=<detail_level>]`,desc:`Perform AI-powered research queries with project context`}]},{title:`Task Navigation & Viewing`,color:`cyan`,commands:[{name:`next`,args:``,desc:`Show the next task to work on based on dependencies`},{name:`graph`,args:`[--id=<id>]`,desc:`Show tasks as a dependency tree, with the next task marked`},{name:`show`,args:`<id>`,desc:`Display detailed information about a specific task`}]},{title:`Tag Management`,color:`magenta`,commands:[{name:`tags`,args:`[list] [--show-metadata] [--ready]`,desc:`List all available tags with task counts`},{name:`tags add`,args:`<name> [--description <desc>] [--copy-from <tag>]`,desc:`Create a new tag (--from-branch for git branch name)`},{name:`tags use`,args:`<name>`,desc:`Switch to a different tag context`},{name:`tags remove`,args:`<name> [-y]`,desc:`Delete an existing tag and all its tasks`},{name:`tags rename`,args:`<oldName> <newName>`,desc:`Rename an existing tag`},{name:`tags copy`,args:`<source> <target> [--description <desc>]`,desc:`Copy a tag with all its tasks`}]},{title:`Dependency Management`,color:`blue`,commands:[{name:`add-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Add a dependency to a task`},{name:`remove-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Remove a dependency from a task`},{name:`validate-dependencies`,args:``,desc:`Identify invalid dependencies without fixing them`},{name:`fix-dependencies`,args:``,desc:`Fix invalid dependencies automatically`}]}].forEach(t=>{console.log(G(V[t.color].bold(t.title),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:t.color,borderStyle:`round`}));let n=Math.max(25,Math.floor(e*.2)),r=Math.max(40,Math.floor(e*.35)),i=Math.max(45,Math.floor(e*.45)-10),a=new ye({colWidths:[n,r,i],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});t.commands.forEach((e,t)=>{a.push([`${V.yellow.bold(e.name)}${V.reset(``)}`,`${V.reset(e.args)}${V.reset(``)}`,`${V.dim(e.desc)}${V.reset(``)}`])}),console.log(a.toString()),console.log(``)}),console.log(G(V.cyan.bold(`Configuration`),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:`cyan`,borderStyle:`round`}));let t=e||process.stdout.columns||100,n=Math.max(30,Math.floor(t*.25)),r=Math.max(50,Math.floor(t*.45)),i=Math.max(30,Math.floor(t*.3)-10),a=new ye({colWidths:[n,r,i],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});a.push([`${V.yellow(ne)}${V.reset(``)}`,`${V.reset(`AI model configuration file (project root)`)}${V.reset(``)}`,`${V.dim(`Managed by models cmd`)}${V.reset(``)}`],[`${V.yellow(`Claude Code`)}${V.reset(``)}`,`${V.reset(`Install and sign in to Claude Code (no API keys needed)`)}${V.reset(``)}`,`${V.dim(`Required on PATH`)}${V.reset(``)}`]),console.log(a.toString()),console.log(``),console.log(G(V.bold(`Quick Start:`)+`
|
|
724
|
+
|
|
725
|
+
`+V.cyan(`1. Create Project: `)+V.reset(`taskgraph init`)+`
|
|
726
|
+
`+V.cyan(`2. Setup Models: `)+V.reset(`taskgraph models --setup`)+`
|
|
727
|
+
`+V.cyan(`3. Parse PRD: `)+V.reset(`taskgraph parse-prd --input=<prd-file>`)+`
|
|
728
|
+
`+V.cyan(`4. List Tasks: `)+V.reset(`taskgraph list`)+`
|
|
729
|
+
`+V.cyan(`5. Find Next Task: `)+V.reset(`taskgraph next`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1},width:Math.min(t-10,100)}))}function wi(e){return e<=3?V.green(`● ${e}`):e<=6?V.yellow(`● ${e}`):V.red(`● ${e}`)}async function Ti(e){W.existsSync(e)||(B(`No complexity report for this tag yet`,"Run `taskgraph analyze-complexity` to create one"),process.exit(1));let t;try{t=JSON.parse(W.readFileSync(e,`utf8`))}catch(e){B(`Couldn't read the complexity report: ${e.message}`,"Run `taskgraph analyze-complexity` to create it again"),process.exit(1)}console.log(ae(t))}async function Ei(e){console.log(G(V.yellow(`It looks like you've already generated tasks for this project.
|
|
730
|
+
`)+V.yellow(`Executing this command will overwrite any existing tasks.`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}));let t=_e.createInterface({input:process.stdin,output:process.stdout}),n=await new Promise(e=>{t.question(V.cyan(`Are you sure you wish to continue? (y/N): `),e)});return t.close(),n.toLowerCase()===`y`||n.toLowerCase()===`yes`}function Di(e,t){!p()&&t?.length&&console.log(`\n${se(e,t)}`)}function Q(e,t=`cli`){if(t!==`cli`&&t!==`text`||!e||p())return;let n=le(e);n&&console.log(`\n${Y.muted(n)}`)}function Oi(e,t,n){if(p()||!e)return;let{highRelevance:r,mediumRelevance:i,recentTasks:a,allRelevantTasks:o}=e,s=V.bold(`Context Analysis`)+`
|
|
731
|
+
|
|
732
|
+
`;s+=Y.muted(`Query: `)+V.reset(`"${t}"`)+`
|
|
733
|
+
`,s+=Y.muted(`Context size: `)+V.cyan(`${n.toLocaleString()} characters`)+`
|
|
734
|
+
`,s+=Y.muted(`Tasks found: `)+V.yellow(`${o.length} relevant tasks`)+`
|
|
735
|
+
|
|
736
|
+
`,r.length>0&&(s+=V.green.bold(`High relevance matches:`)+`
|
|
737
|
+
`,r.slice(0,3).forEach(e=>{s+=V.green(` • Task ${e.id}: ${y(e.title,50)}`)+`
|
|
738
|
+
`}),r.length>3&&(s+=V.green(` • ... and ${r.length-3} more high relevance tasks`)+`
|
|
739
|
+
`),s+=`
|
|
740
|
+
`),i.length>0&&(s+=V.yellow.bold(`Medium relevance matches:`)+`
|
|
741
|
+
`,i.slice(0,3).forEach(e=>{s+=V.yellow(` • Task ${e.id}: ${y(e.title,50)}`)+`
|
|
742
|
+
`}),i.length>3&&(s+=V.yellow(` • ... and ${i.length-3} more medium relevance tasks`)+`
|
|
743
|
+
`),s+=`
|
|
744
|
+
`);let c=a.filter(e=>!r.some(t=>t.id===e.id)&&!i.some(t=>t.id===e.id));c.length>0&&(s+=V.cyan.bold(`Recent tasks (for context):`)+`
|
|
745
|
+
`,c.slice(0,2).forEach(e=>{s+=V.cyan(` • Task ${e.id}: ${y(e.title,50)}`)+`
|
|
746
|
+
`}),c.length>2&&(s+=V.cyan(` • ... and ${c.length-2} more recent tasks`)+`
|
|
747
|
+
`)),console.log(G(s,{padding:{top:1,bottom:1,left:2,right:2},margin:{top:1,bottom:0},borderStyle:`round`,borderColor:fi,title:V.cyan(`Context gathering`),titleAlignment:`center`}))}function ki(e,t,n,r){console.log(V.red(`\n✗ Cannot move tasks from "${t}" to "${n}"`)),console.log(V.yellow(`
|
|
748
|
+
Cross-tag dependency conflicts detected:`)),e.length>0&&e.forEach(e=>{console.log(` • ${e.message}`)}),console.log(V.cyan(`
|
|
749
|
+
Resolution options:`)),console.log(` 1. Move with dependencies: taskgraph move --from=${r} --from-tag=${t} --to-tag=${n} --with-dependencies`),console.log(` 2. Break dependencies: taskgraph move --from=${r} --from-tag=${t} --to-tag=${n} --ignore-dependencies`),console.log(` 3. Validate and fix dependencies: taskgraph validate-dependencies && taskgraph fix-dependencies`),e.length>0&&console.log(` 4. Move dependencies first: taskgraph move --from=${e.map(e=>e.dependencyId).join(`,`)} --from-tag=${e[0].dependencyTag} --to-tag=${n}`)}function Ai(e){return e===null?`null`:e===void 0?`undefined`:e===``?`(empty)`:_(e)||`unknown`}function ji(e,t,n){let r=Ai(e),i=e||`unknown`,a=i;if(i.includes(`.`)){let e=i.split(`.`);e.length===2&&e[0]&&e[1]?a=e[0]:(console.log(V.yellow(`\n⚠ Warning: Unexpected taskId format "${i}". Using as-is for command suggestions.`)),a=i)}console.log(V.red(`\n✗ Cannot move subtask ${r} directly between tags`)),console.log(V.yellow(`
|
|
750
|
+
Subtask movement restriction:`)),console.log(` • Subtasks cannot be moved directly between tags`),console.log(` • They must be promoted to full tasks first`),console.log(` • Source tag: "${t}"`),console.log(` • Target tag: "${n}"`),console.log(V.cyan(`
|
|
751
|
+
Resolution options:`)),console.log(` 1. Promote subtask to full task: taskgraph remove-subtask --id=${r} --convert`),console.log(` 2. Then move the promoted task: taskgraph move --from=${a} --from-tag=${t} --to-tag=${n}`),console.log(` 3. Or move the parent task with all subtasks: taskgraph move --from=${a} --from-tag=${t} --to-tag=${n} --with-dependencies`)}function Mi(e,t,n){console.log(V.red(`
|
|
752
|
+
✗ Invalid tag combination`)),console.log(V.yellow(`
|
|
753
|
+
Error details:`)),console.log(` • Source tag: "${e}"`),console.log(` • Target tag: "${t}"`),console.log(` • Reason: ${n}`),console.log(V.cyan(`
|
|
754
|
+
Resolution options:`)),console.log(` 1. Use different tags for cross-tag moves`),console.log(` 2. Use within-tag move: taskgraph move --from=<id> --to=<id> --tag=${e}`),console.log(` 3. Check available tags: taskgraph tags`)}function Ni(e=`general`){let t={"before-move":[`Tip: Run "taskgraph validate-dependencies" to check for dependency issues before moving tasks`,`Tip: Use "taskgraph fix-dependencies" to automatically resolve common dependency problems`,`Tip: Consider using --with-dependencies flag to move dependent tasks together`],"after-error":[`Quick fix: Run "taskgraph validate-dependencies" to identify specific issues`,`Quick fix: Use "taskgraph fix-dependencies" to automatically resolve problems`,`Quick fix: Check "taskgraph show <id>" to see task dependencies before moving`],general:[`Tip: Use "taskgraph validate-dependencies" to check for dependency issues`,`Tip: Use "taskgraph fix-dependencies" to automatically resolve problems`,`Tip: Use "taskgraph show <id>" to view task dependencies`,`Tip: Use --with-dependencies flag to move dependent tasks together`]},n=t[e]||t.general;console.log(V.cyan(`
|
|
755
|
+
Helpful hints:`)),new Set(n).forEach(e=>{console.log(` ${e}`)})}const Pi="Run `taskgraph list` to see task IDs",Fi="Create some with `taskgraph parse-prd <file>`";function $(e,t){p()?o(`error`,e):B(e,t),process.exit(1)}var Ii=class extends Error{constructor(e,t,n={}){super(t),this.name=`DependencyError`,this.code=e,this.data=n}};const Li={CANNOT_MOVE_SUBTASK:`CANNOT_MOVE_SUBTASK`,INVALID_TASK_ID:`INVALID_TASK_ID`,INVALID_SOURCE_TAG:`INVALID_SOURCE_TAG`,INVALID_TARGET_TAG:`INVALID_TARGET_TAG`};async function Ri(e,t,n,r={}){o(`debug`,`Adding dependency ${n} to task ${t}...`);let i=P(e,r.projectRoot,r.tag);(!i||!i.tasks)&&$(`No tasks yet`,Fi);let a=typeof t==`string`&&t.includes(`.`)?t:parseInt(t,10),s=_(n);A(i.tasks,s)||$(`Task ${s} not found`,Pi);let c=null;if(typeof a==`string`&&a.includes(`.`)){let[e,t]=a.split(`.`).map(e=>parseInt(e,10)),n=i.tasks.find(t=>t.id===e);n||$(`Task ${e} not found`,Pi),n.subtasks||$(`Task ${e} has no subtasks`,`Add some with \`taskgraph expand --id=${e}\``),c=n.subtasks.find(e=>e.id===t),c||$(`Subtask ${a} not found`,Pi)}else c=i.tasks.find(e=>e.id===a),c||$(`Task ${a} not found`,Pi);if(c.dependencies||(c.dependencies=[]),c.dependencies.some(e=>String(e)===String(s))){o(`info`,`Task ${a} already depends on task ${s}; nothing changed`);return}String(a)===String(s)&&$(`Task ${a} can't depend on itself`);let l=!1;if(typeof a==`string`&&typeof s==`string`&&a.includes(`.`)&&s.includes(`.`)){let[e]=a.split(`.`),[t]=s.split(`.`);l=a===s,o(`debug`,`Adding dependency between subtasks: ${a} depends on ${s}`),o(`debug`,`Parent IDs: ${e} and ${t}, Self-dependency check: ${l}`)}l&&$(`Subtask ${a} can't depend on itself`);let u=[a];Bi(i.tasks,s,u)?$(`That would make a loop: task ${s} already depends on task ${a}`,"Run `taskgraph graph` to see how they connect"):(c.dependencies.push(s),c.dependencies.sort((e,t)=>{if(typeof e==`number`&&typeof t==`number`)return e-t;if(typeof e==`string`&&typeof t==`string`){let[n,r]=e.split(`.`).map(Number),[i,a]=t.split(`.`).map(Number);return n===i?r-a:n-i}return typeof e==`number`?-1:1}),E(e,i,r.projectRoot,r.tag),o(`success`,`Task ${a} now depends on task ${s}`),o(`debug`,`Task files regenerated with updated dependencies.`))}async function zi(e,t,n,r={}){o(`debug`,`Removing dependency ${n} from task ${t}...`);let i=P(e,r.projectRoot,r.tag);(!i||!i.tasks)&&$(`No tasks yet`,Fi);let a=typeof t==`string`&&t.includes(`.`)?t:parseInt(t,10),s=_(n),c=null,l=!1;if(typeof a==`string`&&a.includes(`.`)){let[e,t]=a.split(`.`).map(e=>parseInt(e,10)),n=i.tasks.find(t=>t.id===e);n||$(`Task ${e} not found`,Pi),n.subtasks||$(`Task ${e} has no subtasks`,`Add some with \`taskgraph expand --id=${e}\``),c=n.subtasks.find(e=>e.id===t),l=!0,c||$(`Subtask ${a} not found`,Pi)}else c=i.tasks.find(e=>e.id===a),c||$(`Task ${a} not found`,Pi);if(!c.dependencies||c.dependencies.length===0){o(`info`,`Task ${a} has no dependencies; nothing changed`);return}let u=String(s),d=c.dependencies.findIndex(e=>{if(String(e)===u)return!0;if(typeof e==`number`&&e<100&&l){let[t]=a.split(`.`);if(`${t}.${e}`===u)return!0}return!1});d===-1?o(`info`,`Task ${a} doesn't depend on task ${s}; nothing changed`):(c.dependencies.splice(d,1),E(e,i,r.projectRoot,r.tag),o(`success`,`Task ${a} no longer depends on task ${s}`))}function Bi(e,t,n=[]){let r=String(t);if(n.some(e=>String(e)===r))return!0;let i=null,a=null;if(r.includes(`.`)){let[t,n]=r.split(`.`).map(Number),o=e.find(e=>e.id===t);a=t,o&&o.subtasks&&(i=o.subtasks.find(e=>e.id===n))}else{let t=parseInt(r,10);i=e.find(e=>e.id===t||String(e.id)===r)}if(!i||!i.dependencies||i.dependencies.length===0)return!1;let o=[...n,r];return i.dependencies.some(t=>{let n=String(t);return typeof t==`number`&&a!==null&&(n=`${a}.${t}`),Bi(e,n,o)})}function Vi(e,{subtasksOnly:t=!1}={}){let n=/* @__PURE__ */ new Map,r=(e,r)=>{let i=r.filter(n=>n!==e&&(!t||n.includes(`.`)));n.set(e,i)};for(let n of e){let e=String(n.id);t||r(e,(n.dependencies||[]).map(String));for(let t of n.subtasks||[])r(`${e}.${t.id}`,(t.dependencies||[]).map(t=>typeof t==`number`&&t<100?`${e}.${t}`:String(t)))}return n}function Hi(e,t){let n=(r,i)=>r===t||!i.has(r)&&(i.add(r),(e.get(r)||[]).some(e=>n(e,i))),r=/* @__PURE__ */ new Set;return(e.get(t)||[]).some(e=>n(e,r))}function Ui(e){let t=[],n=Vi(e),r=Vi(e,{subtasksOnly:!0});return e.forEach(i=>{i.dependencies&&(i.dependencies.forEach(n=>{String(n)===String(i.id)?t.push({type:`self`,taskId:i.id,message:`Task ${i.id} depends on itself`}):A(e,n)||t.push({type:`missing`,taskId:i.id,dependencyId:n,message:`Task ${i.id} depends on non-existent task ${n}`})}),Hi(n,String(i.id))&&t.push({type:`circular`,taskId:i.id,fixable:!1,message:`Task ${i.id} is part of a circular dependency chain`}),i.subtasks&&i.subtasks.length>0&&i.subtasks.forEach(a=>{if(!a.dependencies)return;let o=`${i.id}.${a.id}`;a.dependencies.forEach(n=>{if(String(n)===String(o)||typeof n==`number`&&n===a.id){t.push({type:`self`,taskId:o,message:`Subtask ${o} depends on itself`});return}let r=typeof n==`number`&&n<100?`${i.id}.${n}`:n;A(e,r)||t.push({type:`missing`,taskId:o,dependencyId:r,message:`Subtask ${o} depends on non-existent task/subtask ${n}`})}),Hi(n,o)&&t.push({type:`circular`,taskId:o,fixable:Hi(r,o),message:`Subtask ${o} is part of a circular dependency chain`})}))}),{valid:t.length===0,issues:t}}async function Wi(e,t={}){let{context:n={}}=t;o(`debug`,`Checking for invalid dependencies in task files...`);let r=P(e,n.projectRoot,n.tag);(!r||!r.tasks)&&$(`No tasks yet`,Fi);let i=Gi(r.tasks);o(`debug`,`Analyzing dependencies for ${i.taskCount} tasks and ${i.subtaskCount} subtasks...`);let{valid:a,issues:s}=Ui(r.tasks);return{valid:a,issues:s,...i}}function Gi(e){let t=e.reduce((e,t)=>e+(Array.isArray(t.subtasks)?t.subtasks.length:0),0);return{taskCount:e.length,subtaskCount:t,dependencyCount:Ki(e)}}function Ki(e){let t=0;return e.forEach(e=>{e.dependencies&&Array.isArray(e.dependencies)&&(t+=e.dependencies.length),e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(e=>{e.dependencies&&Array.isArray(e.dependencies)&&(t+=e.dependencies.length)})}),t}async function qi(e,t={}){let{context:n={}}=t;o(`debug`,`Checking for and fixing invalid dependencies in tasks.json...`);try{let t=P(e,n.projectRoot,n.tag);(!t||!t.tasks)&&$(`No tasks yet`,Fi);let r=[],i=JSON.parse(JSON.stringify(t)),a={nonExistentDependenciesRemoved:0,selfDependenciesRemoved:0,duplicateDependenciesRemoved:0,circularDependenciesFixed:0,tasksFixed:0,subtasksFixed:0};t.tasks.forEach(e=>{if(e.dependencies&&Array.isArray(e.dependencies)){let t=/* @__PURE__ */ new Set,n=e.dependencies.length;e.dependencies=e.dependencies.filter(n=>{let i=String(n);return t.has(i)?(r.push({type:`duplicate`,taskId:e.id,dependencyId:n}),a.duplicateDependenciesRemoved++,!1):(t.add(i),!0)}),e.dependencies.length<n&&a.tasksFixed++}e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)){let n=/* @__PURE__ */ new Set,i=t.dependencies.length;t.dependencies=t.dependencies.filter(i=>{let o=String(i);return typeof i==`number`&&i<100&&(o=`${e.id}.${i}`),n.has(o)?(r.push({type:`duplicate`,taskId:`${e.id}.${t.id}`,dependencyId:o}),a.duplicateDependenciesRemoved++,!1):(n.add(o),!0)}),t.dependencies.length<i&&a.subtasksFixed++}})});let s=new Set(t.tasks.map(e=>e.id)),c=/* @__PURE__ */ new Set;t.tasks.forEach(e=>{e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{c.add(`${e.id}.${t.id}`)})}),t.tasks.forEach(e=>{if(e.dependencies&&Array.isArray(e.dependencies)){let t=e.dependencies.length;e.dependencies=e.dependencies.filter(t=>{if(String(t)===String(e.id))return r.push({type:`self`,taskId:e.id}),a.selfDependenciesRemoved++,!1;if(typeof t==`string`&&t.includes(`.`))return c.has(t)?!0:(r.push({type:`missing`,taskId:e.id,dependencyId:t}),a.nonExistentDependenciesRemoved++,!1);{let n=typeof t==`string`?parseInt(t,10):t;return s.has(n)?!0:(r.push({type:`missing`,taskId:e.id,dependencyId:t}),a.nonExistentDependenciesRemoved++,!1)}}),e.dependencies.length<t&&a.tasksFixed++}e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)){let n=t.dependencies.length,i=`${e.id}.${t.id}`;t.dependencies.some(e=>typeof e==`string`&&e.includes(`.`)?e===i:typeof e==`number`&&e<100&&e===t.id)&&(t.dependencies=t.dependencies.filter(t=>(typeof t==`number`&&t<100?`${e.id}.${t}`:String(t))!==i||(r.push({type:`self`,taskId:i}),a.selfDependenciesRemoved++,!1))),t.dependencies=t.dependencies.filter(t=>{if(typeof t==`string`&&t.includes(`.`))return c.has(t)?!0:(r.push({type:`missing`,taskId:i,dependencyId:t}),a.nonExistentDependenciesRemoved++,!1);let n=typeof t==`number`?t:parseInt(t,10);if(typeof t==`number`&&n<100){let t=`${e.id}.${n}`;return c.has(t)?!0:(r.push({type:`missing`,taskId:i,dependencyId:t}),a.nonExistentDependenciesRemoved++,!1)}return s.has(n)?!0:(r.push({type:`missing`,taskId:i,dependencyId:t}),a.nonExistentDependenciesRemoved++,!1)}),t.dependencies.length<n&&a.subtasksFixed++}})}),o(`debug`,`Checking for circular dependencies...`);let l=/* @__PURE__ */ new Map;t.tasks.forEach(e=>{e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{let n=`${e.id}.${t.id}`;if(t.dependencies&&Array.isArray(t.dependencies)){let r=t.dependencies.map(t=>typeof t==`string`&&t.includes(`.`)?t:typeof t==`number`&&t<100?`${e.id}.${t}`:String(t));l.set(n,r)}else l.set(n,[])})});let u=(e,t,n=/* @__PURE__ */ new Set)=>e===t||!n.has(e)&&(n.add(e),(l.get(e)||[]).some(e=>u(e,t,n)));for(let[e,n]of l.entries()){let[i,o]=e.split(`.`).map(Number),s=t.tasks.find(e=>e.id===i)?.subtasks?.find(e=>e.id===o);if(s?.dependencies)for(let t of[...n]){if(!u(t,e))continue;let o=s.dependencies.length;s.dependencies=s.dependencies.filter(e=>(typeof e==`number`&&e<100?`${i}.${e}`:String(e))!==t),n.splice(n.indexOf(t),1),s.dependencies.length<o&&(r.push({type:`circular`,taskId:e,dependencyId:t}),a.circularDependenciesFixed++,a.subtasksFixed++)}}let d=JSON.stringify(t)!==JSON.stringify(i);return d?(E(e,t,n.projectRoot,n.tag),o(`debug`,`Fixed ${r.length} dependency problems`,a)):o(`debug`,`No changes needed to fix dependencies`),{fixes:r,remaining:Ui(t.tasks).issues,changed:d,...Gi(t.tasks)}}catch(e){$(`Couldn't fix dependencies: ${e.message}`)}}function Ji(e,t,n,r=!1){let i=parseInt(e,10),a=n.find(e=>e.id===i);if(a&&a.subtasks&&Array.isArray(a.subtasks)){let n=a.subtasks.find(e=>r?String(e.id)===String(t):e.id===t);if(n)return{...n,id:`${e}.${n.id}`}}return null}function Yi(e,t,n){if(!e)return null;let r=String(e),i=null;if(i=n.find(e=>String(e.id)===r),!i&&r.includes(`.`)){let[e,t]=r.split(`.`);i=Ji(e,t,n,!0)}if(!i&&!isNaN(e)){let r=parseInt(e,10);if(t&&typeof t==`string`&&t.includes(`.`)){let[e]=t.split(`.`);i=Ji(e,r,n,!1)}}return i}function Xi(e,t,n){let r=[];return!Array.isArray(e.dependencies)||e.dependencies.length===0||e.dependencies.filter(e=>e!=null).forEach(i=>{let a=Yi(i,e.id,n);a&&a.tag!==t&&r.push({taskId:e.id,dependencyId:i,dependencyTag:a.tag,message:`Task ${e.id} depends on ${i} (in ${a.tag})`})}),r}function Zi(e,t,n,r){if(!Array.isArray(e))throw Error(`Source tasks parameter must be an array`);if(!t||typeof t!=`string`)throw Error(`Source tag must be a valid string`);if(!n||typeof n!=`string`)throw Error(`Target tag must be a valid string`);if(!Array.isArray(r))throw Error(`All tasks parameter must be an array`);let i=[];return e.forEach(e=>{if(!e||typeof e!=`object`||!Array.isArray(e.dependencies)||e.dependencies.length===0)return;let t=Xi(e,n,r);i.push(...t)}),i}function Qi(e,t,n){if(!e||typeof e!=`string`)throw new Ii(Li.INVALID_TASK_ID,`Task ID must be a valid string`);if(!t||typeof t!=`string`)throw new Ii(Li.INVALID_SOURCE_TAG,`Source tag must be a valid string`);if(!n||typeof n!=`string`)throw new Ii(Li.INVALID_TARGET_TAG,`Target tag must be a valid string`);if(e.includes(`.`))throw new Ii(Li.CANNOT_MOVE_SUBTASK,`Cannot move subtask ${e} directly between tags.
|
|
756
|
+
|
|
757
|
+
First promote it to a full task using:
|
|
758
|
+
taskgraph remove-subtask --id=${e} --convert`,{taskId:e,sourceTag:t,targetTag:n})}export{Lr as A,ct as B,oi as C,Vr as D,Ur as E,xt as F,ke as H,bt as I,yt as L,jt as M,Wt as N,zr as O,St as P,_t as R,si as S,Qr as T,Ae as V,Z as _,Ei as a,li as b,ki as c,Ci as d,Mi as f,X as g,xi as h,Wi as i,Ir as j,Rr as k,hi as l,mi as m,qi as n,gi as o,ji as p,zi as r,Ti as s,Ri as t,Ni as u,di as v,ai as w,ci as x,ui as y,mt as z};
|