taskgraph-ai 0.54.14 → 0.54.22
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/README.md +1 -1
- package/dist/{ai-services-unified-CvcPXr89.js → ai-services-unified-B45jIPar.js} +1 -1
- package/dist/ai-services-unified-DUvxqUPT.js +1 -0
- package/dist/assets/AGENTS.md +9 -429
- package/dist/commands-CqI6qTC_.js +125 -0
- package/dist/config-manager-DP3N5npn.js +1 -0
- package/dist/config-manager-DTkRerDn.js +1 -0
- package/dist/init-DyCHcgGz.js +24 -0
- package/dist/mcp-server.js +3 -2
- package/dist/{research-CEiR5MKk.js → research-8cDDG5MH.js} +1 -1
- package/dist/{research-DcB3PdqA.js → research-DbaGD34z.js} +26 -43
- package/dist/{response-language-BdYSHT6o.js → response-language-CbtAaYK6.js} +1 -1
- package/dist/response-language-cUVFE-lr.js +1 -0
- package/dist/src-BQZsjzA5.js +207 -0
- package/dist/src-CpPJ2WS1.js +489 -0
- package/dist/tag-management-bTibzuNg.js +1 -0
- package/dist/task-manager-CHSNsnL1.js +129 -0
- package/dist/task-manager-CUvgnPJh.js +1 -0
- package/dist/taskgraph.js +1 -1
- package/package.json +1 -1
- package/dist/ai-services-unified-COsdujxy.js +0 -1
- package/dist/commands-C59cmYBr.js +0 -126
- package/dist/config-manager-Cs19NriM.js +0 -1
- package/dist/config-manager-CtE1yo1I.js +0 -1
- package/dist/init-DXIlIKlc.js +0 -24
- package/dist/response-language-Cve83SLc.js +0 -1
- package/dist/src-DvvdBXWU.js +0 -207
- package/dist/src-Dz_uZuYA.js +0 -468
- package/dist/tag-management-BH0vY7RP.js +0 -1
- package/dist/task-manager-C-lF7v2M.js +0 -167
- package/dist/task-manager-rfPalXaq.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{c as createTagFromBranch,m as useTag}from"./src-CpPJ2WS1.js";
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import{$ as e,A as t,F as n,I as r,L as i,M as a,N as o,P as s,Q as c,R as l,j as u,y as d,z as f}from"./src-BQZsjzA5.js";import{$ as p,B as m,C as h,G as g,J as _,K as v,N as y,Q as b,V as x,W as S,X as C,Y as w,_t as T,c as E,ct as D,dt as O,et as k,g as A,h as j,ht as M,it as N,l as ee,lt as P,nt as te,o as F,p as I,pt as L,q as ne,rt as re,st as ie,tt as ae,u as oe,v as se,z as R}from"./config-manager-DTkRerDn.js";import{B as ce,C as le,F as ue,I as de,J as z,L as fe,N as pe,P as me,R as he,Z as ge,h as _e,j as ve}from"./src-CpPJ2WS1.js";import{C as ye,O as be,S as B,_ as xe,a as V,b as Se,d as H,g as Ce,h as we,i as U,k as W,r as Te,u as Ee,v as De,x as Oe,y as ke}from"./research-DbaGD34z.js";import{i as Ae,n as je,r as Me,t as Ne}from"./ai-services-unified-B45jIPar.js";import"./response-language-CbtAaYK6.js";import G from"chalk";import Pe from"path";import{z as K}from"zod";import q,*as Fe from"fs";import J from"boxen";import Ie from"cli-table3";import"fuse.js";import{APICallError as Le}from"ai";import"@streamparser/json";import Re from"cli-progress";function ze(e,t,n){let r=e=>t===void 0?String(e):f(t,e),i=n===void 0?void 0:String(n),o=[...new Set((e.dependencies??[]).map(r))].filter(e=>e!==i),c=s(e,t,i,r);return{dependencies:o,metadata:a({dependencies:o,metadata:c},i)}}function Be(e,t){return ze(e,void 0,t)}function Ve(e,r,i){let a=(e,i,a,o)=>{e.dependencies?.some(e=>i(e)===r)&&(e.dependencies=e.dependencies.map(e=>i(e)===r?a:e),t(e,n(e.metadata,r,String(a),o)))};for(let t of e){a(t,String,i);for(let e of t.subtasks??[])a(e,e=>f(t.id,e),String(i),t.id)}}const He="Run `taskgraph list` to see task IDs",Ue="Create some with `taskgraph parse-prd <file>`";function We(e,n,i,a){t(e,r(e.metadata,n,i,a))}function Ge(e){for(let n of e||[]){n.metadata&&t(n,a(n));for(let e of n.subtasks||[])e.metadata&&t(e,a(e,n.id))}}var Ke=class extends Error{constructor(e,t,n={},r){super(t,r),this.name=`DependencyError`,this.code=e,this.data=n}};const Y={NO_TASKS:`NO_TASKS`,TASK_NOT_FOUND:`TASK_NOT_FOUND`,NO_SUBTASKS:`NO_SUBTASKS`,SELF_DEPENDENCY:`SELF_DEPENDENCY`,CIRCULAR_DEPENDENCY:`CIRCULAR_DEPENDENCY`,FIX_FAILED:`FIX_FAILED`,CANNOT_MOVE_SUBTASK:`CANNOT_MOVE_SUBTASK`,INVALID_TASK_ID:`INVALID_TASK_ID`,INVALID_SOURCE_TAG:`INVALID_SOURCE_TAG`,INVALID_TARGET_TAG:`INVALID_TARGET_TAG`};function X(e,t,n,r){return new Ke(e,t,{hint:n},r&&{cause:r})}async function qe(e,t,n,r={}){p(`debug`,`Adding dependency ${n} to task ${t}...`);let i=N(e,r.projectRoot,r.tag);if(!i||!i.tasks)throw X(Y.NO_TASKS,`No tasks yet`,Ue);let a=typeof t==`string`&&t.includes(`.`)?t:parseInt(t,10),o=w(n);if(!ie(i.tasks,o))throw X(Y.TASK_NOT_FOUND,`Task ${o} not found`,He);let s=null,c;if(typeof a==`string`&&a.includes(`.`)){let[e,t]=a.split(`.`).map(e=>parseInt(e,10)),n=i.tasks.find(t=>t.id===e);if(!n)throw X(Y.TASK_NOT_FOUND,`Task ${e} not found`,He);if(!n.subtasks)throw X(Y.NO_SUBTASKS,`Task ${e} has no subtasks`,`Add some with \`taskgraph expand --id=${e}\``);if(s=n.subtasks.find(e=>e.id===t),c=e,!s)throw X(Y.TASK_NOT_FOUND,`Subtask ${a} not found`,He)}else if(s=i.tasks.find(e=>e.id===a),!s)throw X(Y.TASK_NOT_FOUND,`Task ${a} not found`,He);if(s.dependencies||(s.dependencies=[]),u(s,o,c)){let t=JSON.stringify(s.metadata);if(We(s,o,`explicit`,c),JSON.stringify(s.metadata)!==t){O(e,i,r.projectRoot,r.tag),p(`success`,`Task ${a} now lists task ${o} as an explicit dependency`);return}p(`info`,`Task ${a} already depends on task ${o}; nothing changed`);return}if(String(a)===String(o))throw X(Y.SELF_DEPENDENCY,`Task ${a} can't depend on itself`);let l=!1;if(typeof a==`string`&&typeof o==`string`&&a.includes(`.`)&&o.includes(`.`)){let[e]=a.split(`.`),[t]=o.split(`.`);l=a===o,p(`debug`,`Adding dependency between subtasks: ${a} depends on ${o}`),p(`debug`,`Parent IDs: ${e} and ${t}, Self-dependency check: ${l}`)}if(l)throw X(Y.SELF_DEPENDENCY,`Subtask ${a} can't depend on itself`);let d=[a];if(!Ye(i.tasks,o,d))s.dependencies.push(o),We(s,o,`explicit`,c),s.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}),O(e,i,r.projectRoot,r.tag),p(`success`,`Task ${a} now depends on task ${o}`),p(`debug`,`Task files regenerated with updated dependencies.`);else throw X(Y.CIRCULAR_DEPENDENCY,`That would make a loop: task ${o} already depends on task ${a}`,"Run `taskgraph graph` to see how they connect")}async function Je(e,t,n,r={}){p(`debug`,`Removing dependency ${n} from task ${t}...`);let i=N(e,r.projectRoot,r.tag);if(!i||!i.tasks)throw X(Y.NO_TASKS,`No tasks yet`,Ue);let a=typeof t==`string`&&t.includes(`.`)?t:parseInt(t,10),o=w(n),s=null,c=!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);if(!n)throw X(Y.TASK_NOT_FOUND,`Task ${e} not found`,He);if(!n.subtasks)throw X(Y.NO_SUBTASKS,`Task ${e} has no subtasks`,`Add some with \`taskgraph expand --id=${e}\``);if(s=n.subtasks.find(e=>e.id===t),c=!0,!s)throw X(Y.TASK_NOT_FOUND,`Subtask ${a} not found`,He)}else if(s=i.tasks.find(e=>e.id===a),!s)throw X(Y.TASK_NOT_FOUND,`Task ${a} not found`,He);if(!s.dependencies||s.dependencies.length===0){p(`info`,`Task ${a} has no dependencies; nothing changed`);return}let l=String(o),u=s.dependencies.findIndex(e=>(c?f(a.split(`.`)[0],e):String(e))===l);if(u===-1){p(`info`,`Task ${a} doesn't depend on task ${o}; nothing changed`);return}let[d]=s.dependencies.splice(u,1);We(s,d,`explicit`,c?a.split(`.`)[0]:void 0),O(e,i,r.projectRoot,r.tag),p(`success`,`Task ${a} no longer depends on task ${o}`)}function Ye(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=>Ye(e,a===null?String(t):f(a,t),o))}function Xe(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=>f(e,t)))}return n}function Ze(e){let t=/* @__PURE__ */ new Map,n=/* @__PURE__ */ new Map,r=/* @__PURE__ */ new Set,i=[],a=/* @__PURE__ */ new Set,o=0,s=a=>(t.set(a,o),n.set(a,o),o++,i.push(a),r.add(a),{id:a,edges:e.get(a),next:0});for(let o of e.keys()){if(t.has(o))continue;let c=[s(o)];for(;c.length>0;){let o=c[c.length-1];if(o.next<o.edges.length){let i=o.edges[o.next++];if(i===o.id&&a.add(i),!e.has(i))continue;t.has(i)?r.has(i)&&n.set(o.id,Math.min(n.get(o.id),t.get(i))):c.push(s(i));continue}if(c.pop(),n.get(o.id)===t.get(o.id)){let e=[],t;do t=i.pop(),r.delete(t),e.push(t);while(t!==o.id);if(e.length>1)for(let t of e)a.add(t)}let l=c[c.length-1];l&&n.set(l.id,Math.min(n.get(l.id),n.get(o.id)))}}return a}function Qe(e){let t=/* @__PURE__ */ new Map;for(let n of e)t.has(n.id)||t.set(n.id,n.subtasks?new Set(n.subtasks.map(e=>e.id)):null);return e=>{if(!e)return!1;if(typeof e==`string`&&e.includes(`.`)){let[n,r]=e.split(`.`).map(e=>parseInt(e,10));return Number.isNaN(n)||Number.isNaN(r)?!1:t.get(n)?.has(r)??!1}let n=parseInt(e,10);return!Number.isNaN(n)&&t.has(n)}}function $e(e){let t=[],n=Ze(Xe(e)),r=Ze(Xe(e,{subtasksOnly:!0})),i=Qe(e);return e.forEach(e=>{e.dependencies&&(e.dependencies.forEach(n=>{String(n)===String(e.id)?t.push({type:`self`,taskId:e.id,message:`Task ${e.id} depends on itself`}):i(n)||t.push({type:`missing`,taskId:e.id,dependencyId:n,message:`Task ${e.id} depends on non-existent task ${n}`})}),n.has(String(e.id))&&t.push({type:`circular`,taskId:e.id,fixable:!1,message:`Task ${e.id} is part of a circular dependency chain`}),e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(a=>{if(!a.dependencies)return;let o=`${e.id}.${a.id}`;a.dependencies.forEach(n=>{if(String(n)===String(o)||l(n)&&n===a.id){t.push({type:`self`,taskId:o,message:`Subtask ${o} depends on itself`});return}let r=l(n)?f(e.id,n):n;i(r)||t.push({type:`missing`,taskId:o,dependencyId:r,message:`Subtask ${o} depends on non-existent task/subtask ${n}`})}),n.has(o)&&t.push({type:`circular`,taskId:o,fixable:r.has(o),message:`Subtask ${o} is part of a circular dependency chain`})}))}),{valid:t.length===0,issues:t}}async function et(e,t={}){let{context:n={}}=t;p(`debug`,`Checking for invalid dependencies in task files...`);let r=N(e,n.projectRoot,n.tag);if(!r||!r.tasks)throw X(Y.NO_TASKS,`No tasks yet`,Ue);let i=tt(r.tasks);p(`debug`,`Analyzing dependencies for ${i.taskCount} tasks and ${i.subtaskCount} subtasks...`);let{valid:a,issues:o}=$e(r.tasks);return{valid:a,issues:o,...i}}function tt(e){let t=e.reduce((e,t)=>e+(Array.isArray(t.subtasks)?t.subtasks.length:0),0);return{taskCount:e.length,subtaskCount:t,dependencyCount:nt(e)}}function nt(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 rt(e,t={}){let{context:n={}}=t;p(`debug`,`Checking for and fixing invalid dependencies in tasks.json...`);let r=N(e,n.projectRoot,n.tag);if(!r||!r.tasks)throw X(Y.NO_TASKS,`No tasks yet`,Ue);try{let t=[],i=JSON.parse(JSON.stringify(r)),a={nonExistentDependenciesRemoved:0,selfDependenciesRemoved:0,duplicateDependenciesRemoved:0,circularDependenciesFixed:0,tasksFixed:0,subtasksFixed:0};r.tasks.forEach(e=>{if(e.dependencies&&Array.isArray(e.dependencies)){let n=/* @__PURE__ */ new Set,r=e.dependencies.length;e.dependencies=e.dependencies.filter(r=>{let i=String(r);return n.has(i)?(t.push({type:`duplicate`,taskId:e.id,dependencyId:r}),a.duplicateDependenciesRemoved++,!1):(n.add(i),!0)}),e.dependencies.length<r&&a.tasksFixed++}e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(n=>{if(n.dependencies&&Array.isArray(n.dependencies)){let r=/* @__PURE__ */ new Set,i=n.dependencies.length;n.dependencies=n.dependencies.filter(i=>{let o=f(e.id,i);return r.has(o)?(t.push({type:`duplicate`,taskId:`${e.id}.${n.id}`,dependencyId:o}),a.duplicateDependenciesRemoved++,!1):(r.add(o),!0)}),n.dependencies.length<i&&a.subtasksFixed++}})});let o=new Set(r.tasks.map(e=>e.id)),s=/* @__PURE__ */ new Set;r.tasks.forEach(e=>{e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{s.add(`${e.id}.${t.id}`)})}),r.tasks.forEach(e=>{if(e.dependencies&&Array.isArray(e.dependencies)){let n=e.dependencies.length;e.dependencies=e.dependencies.filter(n=>{if(String(n)===String(e.id))return t.push({type:`self`,taskId:e.id}),a.selfDependenciesRemoved++,!1;if(typeof n==`string`&&n.includes(`.`))return s.has(n)?!0:(t.push({type:`missing`,taskId:e.id,dependencyId:n}),a.nonExistentDependenciesRemoved++,!1);{let r=typeof n==`string`?parseInt(n,10):n;return o.has(r)?!0:(t.push({type:`missing`,taskId:e.id,dependencyId:n}),a.nonExistentDependenciesRemoved++,!1)}}),e.dependencies.length<n&&a.tasksFixed++}e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(n=>{if(n.dependencies&&Array.isArray(n.dependencies)){let r=n.dependencies.length,i=`${e.id}.${n.id}`;n.dependencies.some(e=>typeof e==`string`&&e.includes(`.`)?e===i:l(e)?e===n.id:!1)&&(n.dependencies=n.dependencies.filter(n=>f(e.id,n)!==i||(t.push({type:`self`,taskId:i}),a.selfDependenciesRemoved++,!1))),n.dependencies=n.dependencies.filter(n=>{if(typeof n==`string`&&n.includes(`.`))return s.has(n)?!0:(t.push({type:`missing`,taskId:i,dependencyId:n}),a.nonExistentDependenciesRemoved++,!1);let r=typeof n==`number`?n:parseInt(n,10);if(l(n)){let n=`${e.id}.${r}`;return s.has(n)?!0:(t.push({type:`missing`,taskId:i,dependencyId:n}),a.nonExistentDependenciesRemoved++,!1)}return o.has(r)?!0:(t.push({type:`missing`,taskId:i,dependencyId:n}),a.nonExistentDependenciesRemoved++,!1)}),n.dependencies.length<r&&a.subtasksFixed++}})}),p(`debug`,`Checking for circular dependencies...`);let c=/* @__PURE__ */ new Map;r.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:f(e.id,t));c.set(n,r)}else c.set(n,[])})});let u=(e,t,n=/* @__PURE__ */ new Set)=>e===t||!n.has(e)&&(n.add(e),(c.get(e)||[]).some(e=>u(e,t,n)));for(let[e,n]of c.entries()){let[i,o]=e.split(`.`).map(Number),s=r.tasks.find(e=>e.id===i)?.subtasks?.find(e=>e.id===o);if(s?.dependencies)for(let r of[...n]){if(!u(r,e))continue;let o=s.dependencies.length;s.dependencies=s.dependencies.filter(e=>f(i,e)!==r),n.splice(n.indexOf(r),1),s.dependencies.length<o&&(t.push({type:`circular`,taskId:e,dependencyId:r}),a.circularDependenciesFixed++,a.subtasksFixed++)}}Ge(r.tasks);let d=JSON.stringify(r)!==JSON.stringify(i);return d?(O(e,r,n.projectRoot,n.tag),p(`debug`,`Fixed ${t.length} dependency problems`,a)):p(`debug`,`No changes needed to fix dependencies`),{fixes:t,remaining:$e(r.tasks).issues,changed:d,...tt(r.tasks)}}catch(e){throw X(Y.FIX_FAILED,`Couldn't fix dependencies: ${e.message}`,void 0,e)}}function it(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 at(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=it(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=it(e,r,n,!1)}}return i}function ot(e,t,n){let r=[];return!Array.isArray(e.dependencies)||e.dependencies.length===0||e.dependencies.filter(e=>e!=null).forEach(i=>{let a=at(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 st(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=ot(e,n,r);i.push(...t)}),i}function ct(e,t,n){if(!e||typeof e!=`string`)throw new Ke(Y.INVALID_TASK_ID,`Task ID must be a valid string`);if(!t||typeof t!=`string`)throw new Ke(Y.INVALID_SOURCE_TAG,`Source tag must be a valid string`);if(!n||typeof n!=`string`)throw new Ke(Y.INVALID_TARGET_TAG,`Target tag must be a valid string`);if(e.includes(`.`))throw new Ke(Y.CANNOT_MOVE_SUBTASK,`Cannot move subtask ${e} directly between tags.
|
|
2
|
+
|
|
3
|
+
First promote it to a full task using:
|
|
4
|
+
taskgraph remove-subtask --id=${e} --convert`,{taskId:e,sourceTag:t,targetTag:n})}async function lt(e,n,r=null,i=null,a=!1,o={}){let{projectRoot:s,tag:c}=o;try{p(`debug`,`Adding subtask to parent task ${n}...`);let a=N(e,s,c);if(!a||!a.tasks)throw Error(`Invalid or missing tasks file at ${e}`);let o=parseInt(n,10),l=a.tasks.find(e=>e.id===o);if(!l)throw Error(`Parent task with ID ${o} not found`);l.subtasks||=[];let u;if(r!==null){let e=parseInt(r,10),n=a.tasks.findIndex(t=>t.id===e);if(n===-1)throw Error(`Task with ID ${e} not found`);let i=a.tasks[n];if(i.parentTaskId)throw Error(`Task ${e} is already a subtask of task ${i.parentTaskId}`);if(e===o)throw Error(`Cannot make a task a subtask of itself`);if(Lt(a.tasks,l,e))throw Error(`Cannot create circular dependency: task ${o} 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,{dependencies:c,metadata:d}=Be(i,o);u={...i,id:s,parentTaskId:o,dependencies:c},t(u,d),l.subtasks.push(u),a.tasks.splice(n,1),Ve(a.tasks,String(e),`${o}.${s}`),p(`debug`,`Converted task ${e} to subtask ${o}.${s}`)}else if(i){let e=(l.subtasks.length>0?Math.max(...l.subtasks.map(e=>e.id)):0)+1;u={id:e,title:i.title,description:i.description||``,details:i.details||``,status:i.status||`pending`,dependencies:i.dependencies||[],parentTaskId:o},l.subtasks.push(u),p(`debug`,`Created new subtask ${o}.${e}`)}else throw Error(`Either existingTaskId or newSubtaskData must be provided`);return O(e,a,s,c),u}catch(e){throw p(`debug`,`Error adding subtask: ${e.message}`),e}}const ut=[`high`,`medium`,`low`],dt=`medium`;function ft(e){return ut.includes(e?.toLowerCase())}function pt(e){if(!e)return null;let t=e.toLowerCase();return ft(t)?t:null}const mt=K.object({title:K.string().describe(`Clear, concise title for the task`),description:K.string().describe(`A one or two sentence description of the task`),details:K.string().describe(`In-depth implementation details, considerations, and guidance`),testStrategy:K.string().describe(`Detailed approach for verifying task completion`),dependencies:K.array(K.number()).nullable().describe(`Array of task IDs that this task depends on (must be completed before this task can start)`)}).strict(),ht=K.object({taskId:K.number().int().positive(),taskTitle:K.string(),complexityScore:K.number().min(1).max(10),recommendedSubtasks:K.number().int().nonnegative(),expansionPrompt:K.string(),reasoning:K.string()}).strict(),gt=K.object({complexityAnalysis:K.array(ht)}).strict(),_t=K.enum([`pending`,`in-progress`,`blocked`,`done`,`cancelled`,`deferred`]),vt=K.object({id:K.number().int().positive(),title:K.string().min(1).max(200),description:K.string().min(1),status:_t,dependencies:K.array(K.union([K.number().int().positive(),K.string()])),priority:K.enum([`low`,`medium`,`high`,`critical`]).nullable(),details:K.string().nullable(),testStrategy:K.string().nullable()}).strict(),yt=K.object({id:K.number().int().positive(),title:K.string().min(5).max(200),description:K.string().min(10),dependencies:K.array(K.number().int().positive()),details:K.string().min(20),status:K.enum([`pending`,`done`,`completed`]),testStrategy:K.string().nullable()}).strict(),bt=K.object({subtasks:K.array(yt)}).strict(),xt=K.object({id:K.number().int().positive(),title:K.string().min(1),description:K.string().min(1),details:K.string().nullable(),testStrategy:K.string().nullable(),priority:K.enum([`high`,`medium`,`low`]).nullable(),dependencies:K.array(K.number().int().positive()).nullable(),status:K.string().nullable()}).strict(),St=K.object({tasks:K.array(xt)}).strict(),Ct=K.object({subtask:yt}).strict(),wt=vt.extend({subtasks:K.array(yt).nullable()}).strict(),Tt={"update-tasks":K.object({tasks:K.array(wt)}).strict(),"expand-task":bt,"analyze-complexity":gt,"update-subtask-by-id":Ct,"update-task-by-id":K.object({task:wt}),"add-task":mt,"parse-prd":St};async function Et(e,t,n,r={}){let i;return await ae(e,a=>{let o=a??{};!o[t]&&r.createWith&&Object.keys(o).length===0&&(o[t]=r.createWith);let s=o[t];if(!s||!Array.isArray(s.tasks))throw Error(`Tag "${t}" no longer exists in ${e}`);return i=n(s),o}),i}function Dt(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 Ot(n,r,i=[],a=null,s={},c=`text`,l=null,u=!1,d={}){let{session:f,mcpLog:m,projectRoot:g,commandName:_,outputType:v,tag:y}=s,x=!!m,C=x?m:{info:(...e)=>p(`info`,...e),warn:(...e)=>p(`warn`,...e),error:(...e)=>p(`error`,...e),debug:(...e)=>p(`debug`,...e),success:(...e)=>p(`success`,...e)},w=a||E(g)||`medium`;if(a){let e=pt(a);e?w=e:(c===`text`&&p(`warn`,`Invalid priority "${a}". Using default priority "${dt}".`),w=dt)}C.debug(`Adding new task with prompt: "${r}", Priority: ${w}, Dependencies: ${i.join(`, `)||`None`}, Research: ${u}, ProjectRoot: ${g}`),y&&C.debug(`Using tag context: ${y}`);let T=null,D=null,O=(e,t=`info`)=>{m?m[t](e):c===`text`&&p(t,e)};function A(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=A(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 a=N(n,g,y);a&&a._rawTaggedData&&(a=a._rawTaggedData),a||=(O(`tasks.json not found or invalid. Initializing new structure.`,`info`),{master:{tasks:[],metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),description:`Default tasks context`}}}),a&&Array.isArray(a.tasks)&&!a._rawTaggedData&&(O(`Legacy format detected. Migrating to tagged format...`,`info`),a={master:{tasks:a.tasks,metadata:a.metadata||{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for master context`}}},S(a.master,{description:`Tasks for master context`}),te(n),k(n),O(`Successfully migrated to tagged format.`,`success`));let s=y;if(!a[s])throw O(`Tag "${s}" does not exist. Please create it first using the 'add-tag' command.`,`error`),Error(`Tag "${s}" not found.`);a[s].tasks||(a[s].tasks=[]),a[s].metadata||(a[s].metadata={created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:``});let p=Dt(a),m=a[s].tasks,C=(m.length>0?Math.max(...m.map(e=>e.id)):0)+1,E=i.filter(e=>{let t=parseInt(e,10);return Number.isNaN(t)||!p.some(e=>e.id===t)});E.length>0&&(O(`${E.length===1?`Task`:`Tasks`} ${E.join(`, `)} ${E.length===1?`doesn't`:`don't`} exist; adding the task without ${E.length===1?`that dependency`:`those dependencies`}`,`warn`),i=i.filter(e=>!E.includes(e)));let j=i.map(e=>parseInt(e,10)),M=[],ee=/* @__PURE__ */ new Set,P=/* @__PURE__ */ new Map;for(let e of j){let t=A(p,e,/* @__PURE__ */ new Set,P);t&&M.push(t)}for(let[e,t]of P.entries())ee.add(e);let F;if(l){if(O(`Using manually provided task data`,`debug`),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${r}`,`debug`);let e=await new U(g,y).gather({semanticQuery:r,maxSemanticResults:10,dependencyTasks:j,format:`research`}),t=e.context,n=e.analysisData;if(c===`text`&&n&&!b()){let e=j.map(String),t=ce({taskIds:e,relatedTaskIds:n.allRelevantTasks.slice(0,10).map(e=>String(e.id)).filter(t=>!e.includes(t)),files:[]});t&&console.log(t)}let i=``;l?.title&&(i+=`\n- Suggested Title: "${l.title}"`),l?.description&&(i+=`\n- Suggested Description: "${l.description}"`),l?.details&&(i+=`\n- Additional Details Context: "${l.details}"`),l?.testStrategy&&(i+=`\n- Additional Test Strategy Context: "${l.testStrategy}"`);let{systemPrompt:a,userPrompt:o}=await V().loadPrompt(`add-task`,{prompt:r,newTaskId:C,existingTasks:p,gatheredContext:t,contextFromArgs:i,useResearch:u,priority:w,dependencies:j,hasCodebaseAnalysis:h(u,g,f),projectRoot:g});c===`text`&&(T=Se(`Writing the new task${u?` with research`:``}…`));try{let e=u?`research`:`main`;if(O(`DEBUG: Calling generateObjectService...`,`debug`),D=await Ne({role:e,session:f,projectRoot:g,schema:Tt[`add-task`],objectName:`newTaskData`,systemPrompt:a,prompt:o,commandName:_||`add-task`,outputType:v||(x?`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&&=(B(T),null)}catch(e){throw T&&=(ke(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&&B(T)}}let I={id:C,title:F.title,description:F.description,details:F.details||``,testStrategy:F.testStrategy||``,status:`pending`,dependencies:F.dependencies?.length?F.dependencies:j,priority:w,subtasks:[]},L=e(d.acceptanceCriteria);if(L.length>0&&(I.acceptanceCriteria=L),F.dependencies?.length&&(F.dependencies.every(e=>{let t=parseInt(e,10);return!Number.isNaN(t)&&p.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)&&p.some(e=>e.id===t)}))),t(I,o(I,{dependencies:j})),O(`DEBUG: Writing tasks.json...`,`debug`),await Et(n,s,e=>{e.tasks.some(e=>e.id===I.id)&&(I.id=Math.max(...e.tasks.map(e=>e.id))+1),e.tasks.push(I),S(e,{description:`Tasks for ${s} context`})},{createWith:a[s]}),C=I.id,O(`DEBUG: tasks.json written.`,`debug`),c===`text`){let e=e=>t=>String(e)===String(t),t=t=>p.find(n=>e(t)(n.id))?.title??``;console.log(ve({id:C,title:I.title,priority:I.priority,dependencies:I.dependencies.map(n=>({id:n,title:t(n),addedByAi:!j.some(e(n))})),unused:j.filter(t=>!I.dependencies.some(e(t))).map(e=>({id:e,title:t(e)}))})),D&&D.telemetryData&&(v===`cli`||v===`text`)&&H(D.telemetryData,`cli`)}return O(`DEBUG: Returning new task ID: ${C} and telemetry.`,`debug`),{newTaskId:C,telemetryData:D?D.telemetryData:null,tagInfo:D?D.tagInfo:null}}catch(e){throw T&&B(T),c!==`text`&&O(`Error adding task: ${e.message}`,`error`),e}}function kt(e,t){let n=Pe.relative(t||process.cwd(),e);return n&&!n.startsWith(`..`)?n:e}async function At(e,t={}){let{session:n,mcpLog:r}=t,i=e.file||`.taskgraph/tasks/tasks.json`,a=parseFloat(e.threshold||`5`),o=e.research||!1,s=e.projectRoot,c=e.tag,l=e.id?e.id.split(`,`).map(e=>parseInt(e.trim(),10)).filter(e=>!Number.isNaN(e)):null,u=e.from===void 0?null:parseInt(e.from,10),d=e.to===void 0?null:parseInt(e.to,10),f=r?`json`:`text`,m=(e,t=`info`)=>{r?r[t](e):!b()&&f===`text`&&p(t===`warn`||t===`error`?t:`debug`,e)},g=R(e.output,{projectRoot:s,tag:c},m);try{m(`Reading tasks from ${i}...`,`info`);let t,v=0,y=null,b=0;if(e._filteredTasksData){if(t=e._filteredTasksData,v=e._originalTaskCount||t.tasks.length,!e._originalTaskCount)try{y=N(i,s,c),y&&y.tasks&&(v=y.tasks.length)}catch(e){p(`warn`,`Could not read original tasks file: ${e.message}`)}}else{if(y=N(i,s,c),!y||!y.tasks||!Array.isArray(y.tasks)||y.tasks.length===0)throw Error(`No tasks found in the tasks file`);v=y.tasks.length;let e=[`pending`,`blocked`,`in-progress`],n=t=>e.includes(t.status?.toLowerCase()||`pending`),r=()=>!0,a=y.tasks.filter(n);if(l&&l.length>0){if(m(`Filtering tasks by specific IDs: ${l.join(`, `)}`,`info`),r=e=>l.includes(e.id),a=a.filter(r),f===`text`){if(a.length===0&&l.length>0)console.log(G.yellow(`Warning: No active tasks found with IDs: ${l.join(`, `)}`));else if(a.length<l.length){let e=a.map(e=>e.id),t=l.filter(t=>!e.includes(t));console.log(G.yellow(`Warning: Some requested task IDs were not found or are not active: ${t.join(`, `)}`))}}}else if(u!==null||d!==null){let e=u===null?1:u,t=d===null?Math.max(...y.tasks.map(e=>e.id)):d;m(`Filtering tasks by ID range: ${e} to ${t}`,`info`),r=n=>n.id>=e&&n.id<=t,a=a.filter(r),f===`text`&&a.length===0&&console.log(G.yellow(`Warning: No active tasks found in range: ${e}-${t}`))}b=y.tasks.filter(e=>r(e)&&!n(e)).length,t={...y,tasks:a,_originalTaskCount:v}}let x=``;if(y&&y.tasks.length>0)try{let e=new U(s,c),n=_(y.tasks),r=new Te(n,`analyze-complexity`),i=t.tasks.map(e=>`${e.title} ${e.description}`).join(` `),a=r.findRelevantTasks(i,{maxResults:10}),o=r.getTaskIds(a);o.length>0&&(x=(await e.gather({tasks:o,format:`research`})).context||``)}catch(e){m(`Could not gather additional context: ${e.message}`,`warn`)}m(`Found ${v} total tasks in the task file.`,`info`),l||u!==null||d!==null?m(l?`Analyzing ${t.tasks.length} tasks with specific IDs: ${l.join(`, `)}`:`Analyzing ${t.tasks.length} tasks in range: ${u||1} to ${d||`end`}`,`info`):b>0&&m(`Skipping ${b} tasks marked as done/cancelled/deferred. Analyzing ${t.tasks.length} active tasks.`,`info`);let S=null,C=/* @__PURE__ */ new Map;try{q.existsSync(g)&&(S=JSON.parse(q.readFileSync(g,`utf8`)),m(`Found existing complexity report at ${g}`,`info`),S&&S.complexityAnalysis&&Array.isArray(S.complexityAnalysis)&&(S.complexityAnalysis.forEach(e=>{C.set(e.taskId,e)}),m(`Existing report contains ${S.complexityAnalysis.length} task analyses`,`info`)))}catch(e){m(`Warning: Could not read existing report: ${e.message}`,`warn`),S=null,C.clear()}if(t.tasks.length===0){if(S&&(l||u!==null||d!==null))return m(`No matching tasks found for analysis. Keeping existing report.`,`info`),f===`text`&&console.log(G.dim(`The complexity report is unchanged`)),{report:S,telemetryData:null};let e={meta:{generatedAt:(/* @__PURE__ */ new Date()).toISOString(),tasksAnalyzed:0,thresholdScore:a,projectName:A(n),usedResearch:o},complexityAnalysis:S?.complexityAnalysis||[]};return m(`Writing complexity report to ${g}...`,`info`),q.writeFileSync(g,JSON.stringify(e,null,` `),`utf8`),m(`Task complexity analysis complete. Report written to ${g}`,`success`),f===`text`&&console.log(z({analyses:[],skipped:b,kept:0,reportPath:kt(g,s)})),{report:e,telemetryData:null}}let w=V(),T={tasks:t.tasks,gatheredContext:x||``,useResearch:o,hasCodebaseAnalysis:h(o,s,n),projectRoot:s||``},{systemPrompt:E,userPrompt:D}=await w.loadPrompt(`analyze-complexity`,T,`default`),O=null;if(f===`text`){let e=t.tasks.length;O=Se(`Analyzing ${e} ${e===1?`task`:`tasks`}${o?` with web research`:``}…`)}let k=null,j=null;try{k=await Ne({prompt:D,systemPrompt:E,role:o?`research`:`main`,session:n,projectRoot:s,schema:Tt[`analyze-complexity`],objectName:`complexityAnalysis`,commandName:`analyze-complexity`,outputType:r?`mcp`:`cli`}),O&&=(B(O),null),j=k.mainResult?.complexityAnalysis,m(`Received ${j.length} complexity analyses from AI.`,`info`);let e=t.tasks.map(e=>e.id),i=j.map(e=>e.taskId),c=e.filter(e=>!i.includes(e));if(c.length>0){m(`Missing analysis for ${c.length} tasks: ${c.join(`, `)}`,`warn`);for(let e of c){let n=t.tasks.find(t=>t.id===e);n&&(m(`Adding default analysis for task ${e}`,`info`),j.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 l=[];if(S&&Array.isArray(S.complexityAnalysis)){let e=new Set(j.map(e=>e.taskId)),n=new Set((y?.tasks??t.tasks).map(e=>e.id)),r=S.complexityAnalysis.filter(t=>!e.has(t.taskId)&&n.has(t.taskId));l=[...r,...j],m(`Merged ${j.length} new analyses with ${r.length} existing entries from current tag`,`info`)}else l=j;let u={meta:{generatedAt:(/* @__PURE__ */ new Date()).toISOString(),tasksAnalyzed:t.tasks.length,totalTasks:v,analysisCount:l.length,thresholdScore:a,projectName:A(n),usedResearch:o},complexityAnalysis:l};return m(`Writing complexity report to ${g}...`,`info`),q.writeFileSync(g,JSON.stringify(u,null,` `),`utf8`),m(`Task complexity analysis complete. Report written to ${g}`,`success`),f===`text`&&(console.log(z({analyses:j,skipped:b,kept:l.length-j.length,reportPath:kt(g,s),usedResearch:o})),F(n)&&console.debug(G.dim(`Final analysis object: ${JSON.stringify(u,null,2)}`)),k.telemetryData&&H(k.telemetryData,`cli`)),{report:u,telemetryData:k?.telemetryData,tagInfo:k?.tagInfo}}catch(e){throw O&&B(O),r&&m(`Error during AI service call: ${e.message}`,`error`),e}}catch(e){if(r&&m(`Error analyzing task complexity: ${e.message}`,`error`),f===`text`)le(`Couldn't analyze task complexity: ${e.message}`),F(n)&&console.error(e),process.exit(1);else throw e}}var jt=class extends Error{constructor(e,t,n){super(t),this.name=`ClearSubtasksError`,this.code=e,this.taskId=n}};function Mt(e,t){let n=[...new Set(String(t).split(`,`).map(e=>e.trim()).filter(Boolean))];if(n.length===0)throw new jt(`INVALID_TASK_ID`,`No task IDs given`);return n.map(t=>{if(/^\d+\.\d+/.test(t))throw new jt(`SUBTASK_ID`,`${t} is a subtask, not a task`,t);if(!/^\d+$/.test(t))throw new jt(`INVALID_TASK_ID`,`"${t}" isn't a task ID`,t);let n=e.find(e=>String(e.id)===t);if(!n)throw new jt(`TASK_NOT_FOUND`,`Task ${t} not found`,t);return n})}function Nt(e,t,n={}){let{projectRoot:r,tag:i}=n;p(`debug`,`Reading tasks from ${e}...`);let a=N(e,r,i);if(!a||!a.tasks)throw new jt(`NO_TASKS`,`No valid tasks found`);let o=Mt(a.tasks,t),s=[],c=[];for(let e of o){let t=e.subtasks?.length??0;t===0?c.push({id:e.id,title:e.title}):(e.subtasks=[],s.push({id:e.id,title:e.title,count:t}),p(`debug`,`Cleared ${t} subtasks from task ${e.id}`))}return s.length>0&&O(e,a,r,i),{cleared:s,empty:c}}function Pt(e,t){let n=!!e,r=e||{info:e=>!b()&&p(`info`,e),warn:e=>!b()&&p(`warn`,e),error:e=>!b()&&p(`error`,e),debug:e=>!b()&&F(t)&&p(`debug`,e)};return{logger:r,report:(e,...t)=>{n?typeof r[e]==`function`?r[e](...t):r.info(...t):b()||p(e,...t)},isMCP:n}}async function Ft(e,n,r,i=!1,a=``,s={},c=!1){let{session:l,mcpLog:u,projectRoot:d,tag:f,complexityReportPath:p}=s,m=u?`json`:`text`,v=d||g(e),{logger:y,report:b,isMCP:x}=Pt(u,l);x&&y.debug(`expandTask called with context: session=${!!l}`);try{y.debug(`Reading tasks from ${e}`);let u=N(e,v,f);if(!u||!u.tasks)throw Error(`Invalid tasks data in ${e}`);let d=u.tasks.findIndex(e=>e.id===parseInt(n,10));if(d===-1)throw Error(`Task ${n} not found`);let g=u.tasks[d];y.debug(`Expanding task ${n}: ${g.title}${i?` with research`:``}`),c&&Array.isArray(g.subtasks)&&g.subtasks.length>0&&(y.debug(`Force flag set. Clearing existing ${g.subtasks.length} subtasks for task ${n}.`),g.subtasks=[]);let b=``;try{let e=new U(v,f),t=_(u.tasks),r=new Te(t,`expand-task`),i=`${g.title} ${g.description}`,a=r.findRelevantTasks(i,{maxResults:5,includeSelf:!0}),o=r.getTaskIds(a),s=[.../* @__PURE__ */ new Set([n.toString(),...o])];s.length>0&&(b=(await e.gather({tasks:s,format:`research`})).context||``)}catch(e){y.warn(`Could not gather context: ${e.message}`)}let x,S=``,C=null;y.debug(`Looking for complexity report at: ${p}${f===`master`?``:` (tag-specific for '${f}')`}`);try{q.existsSync(p)?(C=N(p)?.complexityAnalysis?.find(e=>e.taskId===g.id),C?(y.debug(`Found complexity analysis for task ${g.id}: Score ${C.complexityScore}`),C.reasoning&&(S=`\nComplexity Analysis Reasoning: ${C.reasoning}`)):y.debug(`No complexity analysis found for task ${g.id} in report.`)):y.debug(`Complexity report not found at ${p}. Skipping complexity check.`)}catch(e){y.warn(`Could not read or parse complexity report: ${e.message}. Proceeding without it.`)}let w=parseInt(r,10);if(!Number.isNaN(w)&&w>=0)x=w,y.debug(`Using explicitly provided subtask count: ${x}`);else if(C?.recommendedSubtasks!=null){if(x=parseInt(C.recommendedSubtasks,10),y.debug(`Using subtask count from complexity report: ${x}`),x===0)return y.debug(`Complexity report recommends no expansion for task ${n}. Skipping.`),{task:g,skipped:!0}}else x=ee(l),y.debug(`Using default number of subtasks: ${x}`);(Number.isNaN(x)||x<0)&&(y.warn(`Invalid subtask count determined (${x}), defaulting to 3.`),x=3);let T=(g.subtasks?.length||0)+1,E=V(),D=h(i,v,l),O=``;(a||S)&&(O=`\n\n${a}${S}`.trim()),b&&(O=`${O}\n\n# Project Context\n\n${b}`.trim());let k;C?.expansionPrompt&&(typeof C.expansionPrompt==`string`?k=C.expansionPrompt:typeof C.expansionPrompt==`object`&&C.expansionPrompt.text&&(k=C.expansionPrompt.text));let A=b;typeof b==`object`&&b&&(A=b.data?b.data:b.text?b.text:JSON.stringify(b));let j={task:g,subtaskCount:x,nextSubtaskId:T,additionalContext:a,complexityReasoningContext:S,gatheredContext:A||``,useResearch:i,expansionPrompt:k||void 0,hasCodebaseAnalysis:D,projectRoot:v||``},M=`default`;k?(M=`complexity-report`,y.debug(`Using expansion prompt from complexity report for task ${g.id}.`)):i?(M=`research`,y.debug(`Using research variant for task ${g.id}.`)):y.debug(`Using standard prompt generation for task ${g.id}.`);let{systemPrompt:P,userPrompt:te}=E.loadPrompt(`expand-task`,j,M);y.debug(`Selected variant: ${M}`),y.debug(`Prompt params passed: ${JSON.stringify(j,null,2)}`),y.debug(`System prompt (first 500 chars): ${P.substring(0,500)}...`),y.debug(`User prompt (first 500 chars): ${te.substring(0,500)}...`);let F=[],I=null;m===`text`&&(I=Se(`Breaking task ${g.id} into ${x||`a few`} subtasks…`));let L=null;try{L=await Ne({prompt:te,systemPrompt:P,role:i?`research`:`main`,session:l,projectRoot:v,schema:Tt[`expand-task`],objectName:`subtasks`,commandName:`expand-task`,outputType:m});let e=L?.mainResult;if(!e||!Array.isArray(e.subtasks))throw Error(`AI response did not include a valid subtasks array.`);F=e.subtasks.map(e=>{let n={...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null};return t(n,o(n,void 0,g.id)),n}),y.debug(`Received ${F.length} subtasks from AI.`)}catch(e){throw I&&B(I),e}finally{I&&B(I)}return await Et(e,f??u.tag??`master`,e=>{let t=e.tasks.find(e=>e.id===g.id);if(!t)throw Error(`Task ${n} was removed while it was being expanded`);(c||!Array.isArray(t.subtasks))&&(t.subtasks=[]),t.subtasks.push(...F),g=t}),m===`text`&&Ee(g.id,F),m===`text`&&s.showUsage!==!1&&L&&L.telemetryData&&H(L.telemetryData,`cli`),{task:g,telemetryData:L?.telemetryData,tagInfo:L?.tagInfo}}catch(e){throw m!==`text`&&y.error(`Error expanding task ${n}: ${e.message}`,`error`),e}}async function It(e,t,n=!1,r=``,i=!1,a={},o=`text`){let{session:s,mcpLog:c,projectRoot:l,tag:u,complexityReportPath:d}=a,f=!!c,m=l||g();if(!m)throw Error(`Could not determine project root directory`);let h=c||(o===`json`?{info:e=>{},warn:e=>{},error:e=>console.error(`ERROR: ${e}`),debug:e=>{}}:{info:e=>!b()&&p(`info`,e),warn:e=>!b()&&p(`warn`,e),error:e=>!b()&&p(`error`,e),debug:e=>!b()&&F(s)&&p(`debug`,e)}),_=e=>f?h.info(e):h.debug(e),v=0,y=0,S=0,C=0,w=[];try{h.debug(`Reading tasks from ${e}`);let s=N(e,m,u);if(!s||!s.tasks)throw Error(`Invalid tasks data in ${e}`);let c=s.tasks.filter(e=>(e.status===`pending`||e.status===`in-progress`)&&(!e.subtasks||e.subtasks.length===0||i));C=c.length;let l=i?0:s.tasks.filter(e=>(e.status===`pending`||e.status===`in-progress`)&&e.subtasks?.length>0).length;if(_(`Found ${C} tasks eligible for expansion.`),C===0)return _(`No tasks eligible for expansion.`),o===`text`&&!f&&!b()&&console.log(pe({expandedCount:0,skippedCount:0,failedCount:0,tasksToExpand:0,alreadyExpandedCount:l})),{success:!0,expandedCount:0,failedCount:0,skippedCount:0,tasksToExpand:0,alreadyExpandedCount:l,telemetryData:w,message:`No tasks eligible for expansion.`};for(let o of c)try{let c=await Ft(e,o.id,t,n,r,{...a,projectRoot:m,tag:s.tag||u,complexityReportPath:d,showUsage:!1},i);if(c?.skipped){S++,_(`Skipped task ${o.id}: complexity report recommends no expansion.`);continue}v++,c&&c.telemetryData&&w.push(c.telemetryData),_(`Expanded task ${o.id}.`)}catch(e){y++,h.error(`Couldn't expand task ${o.id}: ${e.message}`)}_(`Expansion complete: ${v} expanded, ${S} skipped, ${y} failed.`);let p=x(w,`expand-all-tasks`);return o===`text`&&!f&&!b()&&console.log(`\n${pe({expandedCount:v,skippedCount:S,failedCount:y,tasksToExpand:C})}`),o===`text`&&p&&H(p,`cli`),{success:!0,expandedCount:v,failedCount:y,skippedCount:S,tasksToExpand:C,alreadyExpandedCount:l,telemetryData:p}}catch(e){throw h.error(`Error during expand all operation: ${e.message}`),!f&&F(s)&&console.error(e),e}}function Lt(e,t,n,r){let i=String(n);if(t.parentTaskId!==void 0&&String(t.parentTaskId)===i)return!0;let a=(t.dependencies||[]).map(e=>r===void 0?String(e):f(r,e));if(a.includes(i))return!0;for(let t of a){let r=e.find(e=>String(e.id)===t);if(r&&Lt(e,r,n))return!0}if(t.subtasks){for(let r of t.subtasks)if(Lt(e,r,n,t.id))return!0}return!1}async function Rt(e,t,n=null,r=!1,i=`text`,a={}){let{projectRoot:o,tag:s}=a;try{let a;try{let e=await(await d({projectPath:o||process.cwd()})).tasks.list({tag:s});a={tasks:e.tasks},p(`debug`,`Loaded ${e.tasks.length} tasks via tm-core`)}catch(t){p(`warn`,`TmCore failed, falling back to legacy readJSON: ${t.message}`),a=N(e,o,s)}if(!a||!a.tasks)throw Error(`No valid tasks found in ${e}`);let c=re(n);c&&c.complexityAnalysis&&a.tasks.forEach(e=>m(e,c));let l;if(t&&t.toLowerCase()!==`all`){let e=t.split(`,`).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0);l=a.tasks.filter(t=>t.status&&e.includes(t.status.toLowerCase()))}else l=a.tasks;let u=a.tasks.length,f=a.tasks.filter(e=>e.status===`done`||e.status===`completed`).length,h=u>0?f/u*100:0,g=f,_=a.tasks.filter(e=>e.status===`in-progress`).length,v=a.tasks.filter(e=>e.status===`pending`).length,y=a.tasks.filter(e=>e.status===`blocked`).length,b=a.tasks.filter(e=>e.status===`deferred`).length,x=a.tasks.filter(e=>e.status===`cancelled`).length,S=a.tasks.filter(e=>e.status===`review`).length,C=0,w=0,T=0,E=0,D=0,O=0,k=0,A=0;a.tasks.forEach(e=>{e.subtasks&&e.subtasks.length>0&&(C+=e.subtasks.length,w+=e.subtasks.filter(e=>e.status===`done`||e.status===`completed`).length,T+=e.subtasks.filter(e=>e.status===`in-progress`).length,E+=e.subtasks.filter(e=>e.status===`pending`).length,D+=e.subtasks.filter(e=>e.status===`blocked`).length,O+=e.subtasks.filter(e=>e.status===`deferred`).length,k+=e.subtasks.filter(e=>e.status===`cancelled`).length,A+=e.subtasks.filter(e=>e.status===`review`).length)});let j=C>0?w/C*100:0,ee=new Set(a.tasks.filter(e=>e.status===`done`||e.status===`completed`).map(e=>e.id)),te=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&(!e.dependencies||e.dependencies.length===0)).length,F=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>ee.has(e))).length,I=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&!e.dependencies.every(e=>ee.has(e))).length,L=te+F,ne={};a.tasks.forEach(e=>{e.dependencies&&e.dependencies.length>0&&e.dependencies.forEach(e=>{ne[e]=(ne[e]||0)+1})});let ie=null,ae=0;for(let[e,t]of Object.entries(ne))t>ae&&(ae=t,ie=parseInt(e));let oe=ie===null?null:a.tasks.find(e=>e.id===ie),se=a.tasks.reduce((e,t)=>e+(t.dependencies?t.dependencies.length:0),0)/a.tasks.length,R=_e(a.tasks,c);if(i===`json`)return{tasks:l.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:u,completed:g,inProgress:_,pending:v,blocked:y,deferred:b,cancelled:x,review:S,completionPercentage:h,subtasks:{total:C,completed:w,inProgress:T,pending:E,blocked:D,deferred:O,cancelled:k,completionPercentage:j}}};if(i===`markdown-readme`)return Bt(a,l,{totalTasks:u,completedTasks:f,completionPercentage:h,doneCount:g,inProgressCount:_,pendingCount:v,blockedCount:y,deferredCount:b,cancelledCount:x,totalSubtasks:C,completedSubtasks:w,subtaskCompletionPercentage:j,inProgressSubtasks:T,pendingSubtasks:E,blockedSubtasks:D,deferredSubtasks:O,cancelledSubtasks:k,reviewSubtasks:A,tasksWithNoDeps:te,tasksReadyToWork:L,tasksWithUnsatisfiedDeps:I,mostDependedOnTask:oe,mostDependedOnTaskId:ie,maxDependents:ae,avgDependenciesPerTask:se,complexityReport:c,withSubtasks:r,nextItem:R});if(i===`compact`)return Wt(l,r);let ce={"in-progress":u>0?_/u*100:0,pending:u>0?v/u*100:0,blocked:u>0?y/u*100:0,deferred:u>0?b/u*100:0,cancelled:u>0?x/u*100:0,review:u>0?S/u*100:0},le={"in-progress":C>0?T/C*100:0,pending:C>0?E/C*100:0,blocked:C>0?D/C*100:0,deferred:C>0?O/C*100:0,cancelled:C>0?k/C*100:0,review:C>0?A/C*100:0},ue=we(h,30,ce),de=we(j,30,le),z;try{z=process.stdout.columns}catch{p(`debug`,`Could not determine terminal width, using default`)}z||=80,z=Math.max(z,80);let fe=G.bold(`Project Dashboard`)+`
|
|
5
|
+
Tasks Progress: ${G.greenBright(ue)} ${h.toFixed(0)}%\n${G.green(`█`)} Done: ${G.green(g)} ${G.cyan(`▓`)} In Progress: ${G.cyan(_)} ${G.yellow(`░`)} Pending: ${G.yellow(v)} ${G.red(`!`)} Blocked: ${G.red(y)} ${W.muted(`─`)} Deferred: ${W.muted(b)} ${W.muted(`─`)} Cancelled: ${W.muted(x)}\n\nSubtasks Progress: ${G.cyan(de)} ${j.toFixed(0)}%\n${G.green(`█`)} Completed: ${G.green(w)}/${C} ${G.cyan(`▓`)} In Progress: ${G.cyan(T)} ${G.yellow(`░`)} Pending: ${G.yellow(E)} ${G.red(`!`)} Blocked: ${G.red(D)} ${W.muted(`─`)} Deferred: ${W.muted(O)} ${W.muted(`─`)} Cancelled: ${W.muted(k)}\n\n`+G.cyan.bold(`Priority Breakdown:`)+`
|
|
6
|
+
${G.red(`•`)} ${G.reset(`High priority:`)} ${a.tasks.filter(e=>e.priority===`high`).length}\n${G.yellow(`•`)} ${G.reset(`Medium priority:`)} ${a.tasks.filter(e=>e.priority===`medium`).length}\n${G.green(`•`)} ${G.reset(`Low priority:`)} ${a.tasks.filter(e=>e.priority===`low`).length}`,pe=G.bold(`Dependency Status & Next Task`)+`
|
|
7
|
+
`+G.cyan.bold(`Dependency Metrics:`)+`
|
|
8
|
+
${G.green(`•`)} ${G.reset(`Tasks with no dependencies:`)} ${te}\n${G.green(`•`)} ${G.reset(`Tasks ready to work on:`)} ${L}\n${G.yellow(`•`)} ${G.reset(`Tasks blocked by dependencies:`)} ${I}\n${G.magenta(`•`)} ${G.reset(`Most depended-on task:`)} ${oe?G.cyan(`#${ie} (${ae} dependents)`):W.muted(`None`)}\n${G.cyan(`•`)} ${G.reset(`Avg dependencies per task:`)} ${se.toFixed(1)}\n\n`+G.cyan.bold(`Next Task:`)+`
|
|
9
|
+
ID: ${G.cyan(R?R.id:`N/A`)} - ${R?G.bold(P(R.title,40)):G.yellow(`No task available`)}
|
|
10
|
+
Priority: ${R?G.reset(R.priority||`medium`):``} Dependencies: ${R?Ce(R.dependencies,a.tasks,!0,c):``}
|
|
11
|
+
Complexity: ${R&&R.complexityScore?xe(R.complexityScore):W.muted(`N/A`)}`;if(z>=104){let e=Math.floor(z/2),t=e-4,n=J(fe,{padding:1,borderColor:be,borderStyle:`round`,width:t,dimBorder:!1}),r=J(pe,{padding:1,borderColor:`magenta`,borderStyle:`round`,width:t,dimBorder:!1}),i=n.split(`
|
|
12
|
+
`),a=r.split(`
|
|
13
|
+
`),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(`
|
|
14
|
+
`))}else{let e=J(fe,{padding:1,borderColor:be,borderStyle:`round`,margin:{top:0,bottom:1}}),t=J(pe,{padding:1,borderColor:`magenta`,borderStyle:`round`,margin:{top:0,bottom:1}});console.log(e),console.log(t)}if(l.length===0){console.log(J(t?G.yellow(`No tasks with status '${t}' found`):G.yellow(`No tasks found`),{padding:1,borderColor:`yellow`,borderStyle:`round`}));return}let me=r?10:7,he=100-me-15-12-20-10,ve=z-10,ye=Math.floor(me/100*ve),B=Math.floor(15/100*ve),V=Math.floor(12/100*ve),Se=Math.floor(20/100*ve),H=Math.floor(10/100*ve),U=Math.floor(he/100*ve),Te=new Ie({head:[G.cyan.bold(`ID`),G.cyan.bold(`Title`),G.cyan.bold(`Status`),G.cyan.bold(`Priority`),G.cyan.bold(`Dependencies`),G.cyan.bold(`Complexity`)],colWidths:[ye,U,B,V,Se,H],style:{head:[],border:[],compact:!1},wordWrap:!0,wrapOnWordBoundary:!0});l.forEach(e=>{let t=`None`;t=e.dependencies&&e.dependencies.length>0?Ce(e.dependencies,a.tasks,!0,c):W.muted(`None`);let n=e.title.replace(/\n/g,` `),i={high:G.red,medium:G.yellow,low:W.muted}[e.priority||`medium`]||G.reset,o=De(e.status,!0);Te.push([e.id.toString(),P(n,U-3),o,i(P(e.priority||`medium`,V-2)),t,e.complexityScore?xe(e.complexityScore):W.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?G.green.bold(`${e.id}.${t}`):i?W.active.bold(`${e.id}.${t}`):G.red.bold(`${e.id}.${t}`)}}let n=a.tasks.find(e=>e.id===t);if(n){m(n,c);let e=n.status===`done`||n.status===`completed`,r=n.status===`in-progress`;return e?G.green.bold(`${t}`):r?W.active.bold(`${t}`):G.red.bold(`${t}`)}return G.cyan(t.toString())}).join(`, `)||W.muted(`None`)),Te.push([`${e.id}.${t.id}`,G.dim(`└─ ${P(t.title,U-5)}`),De(t.status,!0),G.dim(`-`),n,t.complexityScore?W.muted(`${t.complexityScore}`):W.muted(`N/A`)])})});try{console.log(Te.toString())}catch(e){p(`error`,`Error rendering table: ${e.message}`),console.log(G.yellow(`
|
|
15
|
+
Falling back to simple task list due to terminal width constraints:`)),l.forEach(e=>{console.log(`${G.cyan(e.id)}: ${G.reset(e.title)} - ${De(e.status)}`)})}t&&(console.log(G.yellow(`\nFiltered by status: ${t}`)),console.log(G.yellow(`Showing ${l.length} of ${u} tasks`)));let Ee={high:G.red.bold,medium:G.yellow,low:W.muted};if(R){let e=``,t=a.tasks.find(e=>String(e.id)===String(R.id));t&&t.subtasks&&t.subtasks.length>0&&(e=`\n\n${G.bold(`Subtasks:`)}\n`,e+=t.subtasks.map(e=>{m(e,c);let n=e.status||`pending`,r={done:G.green,completed:G.green,pending:G.yellow,"in-progress":G.cyan,deferred:W.muted,blocked:G.red,cancelled:W.muted}[n.toLowerCase()]||G.reset;return`${G.cyan(`${t.id}.${e.id}`)} [${r(n)}] ${e.title}`}).join(`
|
|
16
|
+
`));let n=ge(R.id,R.status,!!t?.subtasks?.length).slice(0,2).map(e=>`${G.cyan(`Next step:`)} ${G.yellow(e.command)} ${W.muted(e.description)}`).join(`
|
|
17
|
+
`);console.log(J(W.heading(`Next task: #${R.id} - ${R.title}`)+`
|
|
18
|
+
|
|
19
|
+
${G.reset(`Priority:`)} ${Ee[R.priority||`medium`](R.priority||`medium`)} ${G.reset(`Status:`)} ${De(R.status,!0)}\n${G.reset(`Dependencies:`)} ${R.dependencies&&R.dependencies.length>0?Ce(R.dependencies,a.tasks,!0,c):W.muted(`None`)}\n\n${G.reset(`Description:`)} ${zt(R,a.tasks)}`+e+`
|
|
20
|
+
|
|
21
|
+
${n}\n${G.cyan(`View details:`)} ${G.yellow(`taskgraph show ${R.id}`)}`,{padding:{left:2,right:2,top:1,bottom:1},borderColor:be,borderStyle:`round`,margin:{top:1,bottom:1},title:`Next task`,titleAlignment:`center`,width:z-4,fullscreen:!1}))}else console.log(J(W.heading(`No eligible next task found`)+`
|
|
22
|
+
|
|
23
|
+
All pending tasks have dependencies that are not yet completed, or all tasks are done.`,{padding:1,borderColor:be,borderStyle:`round`,margin:{top:1,bottom:1},title:`Next task`,titleAlignment:`center`,width:z-4}));console.log(J(G.bold(`Suggested Next Steps:`)+`
|
|
24
|
+
|
|
25
|
+
${G.cyan(`1.`)} Run ${G.yellow(`taskgraph next`)} to see what to work on next\n${G.cyan(`2.`)} Run ${G.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks\n${G.cyan(`3.`)} Run ${G.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(p(`error`,`Error listing tasks: ${e.message}`),i===`json`)throw{code:`TASK_LIST_ERROR`,message:e.message,details:e.stack};console.error(G.red(`Error: ${e.message}`)),process.exit(1)}}function zt(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 Bt(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 | |
|
|
26
|
+
`,A+=`| :- |:-|
|
|
27
|
+
`,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+=`|-|-|
|
|
28
|
+
`,A+=`| Subtask Progress | ${N} ${Math.round(m)}% |\n`,A+=`| Completed | ${p} |\n`,A+=`| In Progress | ${h} |\n`,A+=`| Pending | ${g} |\n`,A+=`
|
|
29
|
+
|
|
30
|
+
`,A+=`| ID | Title | Status | Priority | Dependencies | Complexity |
|
|
31
|
+
`,A+=`| :- | :- | :- | :- | :- | :- |
|
|
32
|
+
`;let ee=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`}},P=(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=ee(t.status),i=t.priority||`medium`,a=P(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=ee(n.status),a=P(n.dependencies,e.tasks),o=n.complexityScore?n.complexityScore.toString():`N/A`;A+=`| ${t.id}.${n.id} | ${r} | ${i} | - | ${a} | ${o} |\n`})}),A}function Vt(e){if(!e||e.length===0)return``;if(e.length>5){let t=e.slice(0,5).join(`,`),n=e.length-5;return` → ${G.cyan(t)}${W.muted(`... (+`+n+` more)`)}`}return` → ${G.cyan(e.join(`,`))}`}function Ht(e,t=50){let n=e.status||`pending`,r=e.priority||`medium`,i=P(e.title||`Untitled`,t),a=De(n,!0),o={high:G.red,medium:G.yellow,low:W.muted}[r]||G.reset,s=Vt(e.dependencies);return`${G.cyan(e.id)} ${a} ${G.reset(i)} ${o(`(`+r+`)`)}${s}`}function Ut(e,t,n=47){let r=e.status||`pending`,i=P(e.title||`Untitled`,n),a=De(r,!0),o=Vt(e.dependencies);return` ${G.cyan(t+`.`+e.id)} ${a} ${G.dim(i)}${o}`}function Wt(e,t){if(e.length===0){console.log(`No tasks found`);return}let n=[];e.forEach(e=>{n.push(Ht(e)),t&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(t=>{n.push(Ut(t,e.id))})}),console.log(n.join(`
|
|
33
|
+
`))}function Gt(e,r,i,a){t(e,n(e.metadata,r,i,a))}function Kt(e,t,n,r){return s(e,t,n,r)}function qt(e,t,n={}){return D(e,t,{...n,direction:`forward`,logger:{warn:console.warn}})}var Z=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_MOVE:`INVALID_MOVE`,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 Jt(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 Yt(e,t,n,r=!1,i={}){let{projectRoot:a,tag:o}=i,s=t.split(`,`).map(e=>e.trim()),c=n.split(`,`).map(e=>e.trim());if(s.length!==c.length)throw new Z(Q.ID_COUNT_MISMATCH,`Number of source IDs (${s.length}) must match number of destination IDs (${c.length})`);if(s.length>1){let t=[];for(let n=0;n<s.length;n++){let r=await Yt(e,s[n],c[n],!1,i);t.push(r)}return{message:`Successfully moved ${s.length} tasks/subtasks`,moves:t}}let l=N(e,a,o);if(l&&l._rawTaggedData&&(l=l._rawTaggedData),!l||!l[o]||!Array.isArray(l[o].tasks))throw new Z(Q.INVALID_TASKS_FILE,`Invalid tasks file or tag "${o}" not found at ${e}`);let u=l[o].tasks;p(`debug`,`Moving task/subtask ${t} to ${n} (tag: ${o})`);let d=t.includes(`.`),f=n.includes(`.`),m;return m=d&&f?Xt(u,t,n):d&&!f?Zt(u,t,n):!d&&f?Qt(u,t,n):$t(u,t,n),l[o].tasks=u,O(e,l,i.projectRoot,o),m}function Xt(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 Z(Q.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!c)throw new Z(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 Z(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{if(c.subtasks.some(e=>e.id===o))throw new Z(Q.TASK_ALREADY_EXISTS,`Subtask ${a}.${o} already exists. Use a different destination ID`);en(u,s,l,c,o,e)}return{message:`Moved subtask ${t} to ${n}`,movedItem:u}}function Zt(e,n,r){let[i,a]=n.split(`.`).map(e=>parseInt(e,10)),o=parseInt(r,10),s=e.find(e=>e.id===i);if(!s)throw new Z(Q.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${i} not found`);if(!s.subtasks)throw new Z(Q.PARENT_TASK_NO_SUBTASKS,`Source parent task ${i} has no subtasks`);let c=s.subtasks.findIndex(e=>e.id===a);if(c===-1)throw new Z(Q.SUBTASK_NOT_FOUND,`Source subtask ${n} not found`);let l=s.subtasks[c];if(e.find(e=>e.id===o))throw new Z(Q.TASK_ALREADY_EXISTS,`Cannot move to existing task ID ${o}. Choose a different ID or use subtask destination.`);let u=ze(l,s.id,void 0),d={id:o,title:l.title,description:l.description,status:l.status||`pending`,dependencies:u.dependencies,priority:l.priority||`medium`,details:l.details||``,testStrategy:l.testStrategy||``,subtasks:[]};t(d,u.metadata),s.subtasks.splice(c,1),Ve(e,`${s.id}.${a}`,o);let f=e.findIndex(e=>e.id>o);return f===-1?e.push(d):e.splice(f,0,d),{message:`Converted subtask ${n} to task ${r}`,movedItem:d}}function Qt(e,n,r){let i=parseInt(n,10),[a,o]=r.split(`.`).map(e=>parseInt(e,10)),s=e.findIndex(e=>e.id===i),c=e.find(e=>e.id===a);if(s===-1)throw new Z(Q.TASK_NOT_FOUND,`Source task with ID ${i} not found`);if(!c)throw new Z(Q.PARENT_TASK_NOT_FOUND,`Destination parent task with ID ${a} not found`);let l=e[s];if(a===i)throw new Z(Q.INVALID_MOVE,`Cannot move task ${i} inside itself`);if(l.subtasks?.length>0)throw new Z(Q.INVALID_MOVE,`Task ${i} has subtasks and cannot become a subtask. Move or remove its subtasks first`);if(c.subtasks?.some(e=>e.id===o))throw new Z(Q.TASK_ALREADY_EXISTS,`Subtask ${a}.${o} already exists. Use a different destination ID`);c.subtasks||=[];let u=Be(l,c.id),d={id:o,title:l.title,description:l.description,status:l.status||`pending`,dependencies:u.dependencies,details:l.details||``,testStrategy:l.testStrategy||``};t(d,u.metadata);let f=-1;c.subtasks.length>0&&(f=c.subtasks.findIndex(e=>e.id===o),f===-1&&(f=c.subtasks.length-1));let p=f===-1?0:f+1;return c.subtasks.splice(p,0,d),e.splice(s,1),Ve(e,String(i),`${c.id}.${o}`),{message:`Converted task ${n} to subtask ${r}`,movedItem:d}}function $t(e,t,n){let r=parseInt(t,10),i=parseInt(n,10),a=e.findIndex(e=>e.id===r);if(a===-1)throw new Z(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 Z(Q.TASK_ALREADY_EXISTS,`Task with ID ${i} already exists. Use a different destination ID.`);return tn(e,a,o,i)}function en(e,n,r,i,a,o){let s=parseInt(a,10),c=ze(e,n.id,i.id),l={...e,id:s,dependencies:c.dependencies};t(l,c.metadata),i.subtasks||=[];let u=-1;i.subtasks.length>0&&(u=i.subtasks.findIndex(e=>e.id===s),u===-1&&(u=i.subtasks.length-1));let d=u===-1?0:u+1;return i.subtasks.splice(d,0,l),n.subtasks.splice(r,1),Ve(o,`${n.id}.${e.id}`,`${i.id}.${s}`),l}function tn(e,n,r,i){let a=e.findIndex(e=>e.id===i),o={...r,id:i},s=String(r.id),c=String(i);e.forEach(e=>{e.dependencies?.some(e=>String(e)===s)&&(e.dependencies=e.dependencies.map(e=>String(e)===s?i:e),Gt(e,s,c)),e.subtasks&&e.subtasks.forEach(t=>{let n=t=>f(e.id,t)===s;t.dependencies?.some(n)&&(t.dependencies=t.dependencies.map(e=>n(e)?c:e),Gt(t,s,c,e.id))})}),Array.isArray(o.subtasks)&&o.subtasks.forEach(e=>{if(Array.isArray(e.dependencies)){let n=e=>{if(typeof e==`string`&&e.includes(`.`)){let[t,n]=e.split(`.`);if(parseInt(t,10)===r.id)return`${i}.${n}`}return e};e.metadata&&t(e,Kt(e,r.id,i,n)),e.dependencies=e.dependencies.map(n)}}),e.splice(n,1);let l=n<a?a-1:a;return l>=0&&l<e.length?e[l]=o:e.push(o),p(`debug`,`Moved task ${r.id} to new ID ${i}`),{message:`Moved task ${r.id} to new ID ${i}`,movedItem:o}}function nn(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 rn(e,t,n,r,i){let{projectRoot:a}=i,o=N(e,a,n);if(o&&o._rawTaggedData&&(o=o._rawTaggedData),!o||!o[n]||!Array.isArray(o[n].tasks))throw new Z(Q.INVALID_SOURCE_TAG,`Source tag "${n}" not found or invalid`);o[r]||(o[r]={tasks:[]},p(`info`,`Created new tag "${r}"`));let s=t.map(e=>String(e)),c=o[n].tasks.filter(e=>{let t=String(e.id);return s.includes(t)});return t.forEach(e=>{ct(e,n,r)}),{rawData:o,sourceTasks:c}}async function an(e){let{rawData:t,sourceTasks:n}=e;return{rawData:t,sourceTasks:n,allTasks:nn(t)}}async function on(e,n,r,i,o,s){let{withDependencies:c=!1,ignoreDependencies:l=!1}=r,u=Array.isArray(n)?n.filter(e=>e&&e.tag===o):[];if(c){let t=qt(e,u,{maxDepth:100,includeSelf:!1}),n=new Set(u.map(e=>typeof e.id==`string`?parseInt(e.id,10):e.id)),r=t.filter(e=>{let t=Jt(e);return Number.isFinite(t)&&n.has(t)}),a=[.../* @__PURE__ */ new Set([...i,...r])];return p(`info`,`Moving ${a.length} tasks (including dependencies): ${a.join(`, `)}`),{tasksToMove:a,dependencyResolution:{type:`with-dependencies`,dependentTasks:r}}}let d=st(e,o,s,n);if(d.length>0){if(l)return e.forEach(e=>{let r=u,i=Array.isArray(n)?n.filter(e=>e&&e.tag===s):[];e.dependencies=e.dependencies.filter(e=>{let t=Jt(e);return Number.isFinite(t)&&r.some(e=>e.id===t)?!1:(Number.isFinite(t)&&i.some(e=>e.id===t),!0)}),e.metadata&&t(e,a(e))}),p(`warn`,`Removed ${d.length} cross-tag dependencies`),{tasksToMove:i,dependencyResolution:{type:`ignored-dependencies`,conflicts:d}};throw new Z(Q.CROSS_TAG_DEPENDENCY_CONFLICTS,`Cannot move tasks: ${d.length} cross-tag dependency conflicts found`,{conflicts:d,sourceTag:o,targetTag:s,taskIds:i})}return{tasksToMove:i,dependencyResolution:{type:`no-conflicts`}}}async function sn(e,t,n,r,i,a){let{projectRoot:o}=i,s=[];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 Z(Q.TASK_NOT_FOUND,`Task ${i} not found in source tag "${t}"`);let o=r[t].tasks[a];if(r[n].tasks.findIndex(t=>t.id===e)!==-1)throw new Z(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 c=un(o,t,n);r[n].tasks.push(c),s.push({id:i,fromTag:t,toTag:n}),p(`debug`,`Moved task ${i} from "${t}" to "${n}"`)}return{rawData:r,movedTasks:s}}async function cn(e,t,n,r,i,a){let{projectRoot:o}=n,{rawData:s,movedTasks:c}=e;O(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 ln(e,t,n,r,i={},a={}){let{rawData:o,sourceTasks:s,allTasks:c}=await an(await rn(e,t,n,r,a)),{tasksToMove:l,dependencyResolution:u}=await on(s,c,i,t,n,r);return await cn(await sn(l,n,r,o,a,e),e,a,n,r,u)}function un(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 dn=class e extends Error{constructor(t,n){super(t),this.name=`StreamingError`,this.code=n,Error.captureStackTrace&&Error.captureStackTrace(this,e)}};const fn={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 pn=class e{static async withTimeout(e,t,n=`Operation`){let r,i=new Promise((e,i)=>{r=setTimeout(()=>{i(new dn(`${n} timed out after ${t/1e3} seconds`,fn.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 dn&&e.code===fn.STREAM_PROCESSING_FAILED&&e.message.includes(`timed out`)}},mn=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 hn=K.object({id:K.number(),title:K.string().min(1),description:K.string().min(1),details:K.string(),testStrategy:K.string(),priority:K.enum(ut),dependencies:K.array(K.number()),status:K.string()}),gn=K.object({tasks:K.array(hn),metadata:K.union([K.object({projectName:K.string(),totalTasks:K.number(),sourceFile:K.string(),generatedAt:K.string()}),K.null()]).default(null)});var _n=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||mn.seconds(180).milliseconds,this.targetTag=this.tag||C(this.projectRoot)||`master`,this.isMCP=!!this.mcpLog,this.outputFormat=this.isMCP&&!this.reportProgress?`json`:`text`,this.useStreaming=!1}hasCodebaseAnalysis(){return h(this.research,this.projectRoot,this.session)}},vn=class{constructor(e,t){this.isMCP=!!e,this.outputFormat=this.isMCP&&!t?`json`:`text`,this.logFn=e||{info:(...e)=>p(`info`,...e),warn:(...e)=>p(`warn`,...e),error:(...e)=>p(`error`,...e),debug:(...e)=>p(`debug`,...e),success:(...e)=>p(`success`,...e)}}report(e,t=`info`){this.logFn&&typeof this.logFn[t]==`function`?this.logFn[t](e):!b()&&this.outputFormat===`text`&&p(t,e)}};function yn(e){return`${Math.floor(e/60)}m ${Math.floor(e%60).toString().padStart(2,`0`)}s`}const bn={BAR_WIDTH:40,TABLE_COL_WIDTHS:[28,50],DEFAULT_MODEL:`Default`,DEFAULT_TEMPERATURE:.7},$={HIGH:`high`,MEDIUM:`medium`,LOW:`low`},xn={[$.HIGH]:G.red,[$.MEDIUM]:G.yellow,[$.LOW]:T.muted},Sn={main:{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderColor:L,borderStyle:`round`},summary:{padding:{top:1,right:1,bottom:1,left:1},borderColor:L,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 Cn({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+=` | ${G.cyan.bold(`🔬 Research Mode`)}`),G.bold(`🤖 Parsing PRD and ${s} Tasks`)+`
|
|
34
|
+
`+G.dim(c)+`
|
|
35
|
+
|
|
36
|
+
`+T.brand(`Input: ${e}`)+`
|
|
37
|
+
`+T.brand(`Output: ${t}`)+`
|
|
38
|
+
`+T.brand(`Tasks to ${a?`Append`:`Generate`}: ${n}`)}function wn(e){console.log(J(e,Sn.main))}function Tn(e,t){console.log(G.yellow.bold(`📝 Append mode`)+` - Adding to ${e} existing tasks (next ID: ${t})`)}function En(e){let t=G.red.bold(`⚠️ Force flag enabled`);return e?`${t} - Will overwrite if conflicts occur`:`${t} - Overwriting existing tasks`}function Dn({prdFilePath:e,outputPath:t,numTasks:n,model:r=bn.DEFAULT_MODEL,temperature:i=bn.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`);wn(Cn({prdFilePath:e,outputPath:t,numTasks:n,model:r,temperature:i,append:a,research:o})),(a||s)&&(a&&Tn(c.length,l),s&&console.log(En(a)),console.log())}function On(e,t){let n={};return Object.values($).forEach(r=>{let i=e[r]||0;n[r]={count:i,percentage:t>0?Math.round(i/t*100):0}}),n}function kn(e,t){let n=bn.BAR_WIDTH,r={};if(t===0)return Object.values($).forEach(e=>{r[e]=0}),r;let i={};Object.values($).forEach(r=>{i[r]=e[r].count/t*n}),Object.values($).forEach(e=>{r[e]=Math.floor(i[e])}),Object.values($).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($).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 An(e){let t=``;t+=xn[$.HIGH](`█`.repeat(e[$.HIGH])),t+=xn[$.MEDIUM](`█`.repeat(e[$.MEDIUM])),t+=xn[$.LOW](`█`.repeat(e[$.LOW]));let n=Object.values(e).reduce((e,t)=>e+t,0);return n<bn.BAR_WIDTH&&(t+=T.muted(`░`.repeat(bn.BAR_WIDTH-n))),t}function jn(e){let t=[];return Object.entries($).forEach(([n,r])=>{let i=e[r],a=xn[r],o=n.charAt(0)+n.slice(1).toLowerCase();t.push(`${a.bold(i.count)} ${a(o)} (${i.percentage}%)`)}),[G.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=yn(a),l=new Ie({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:bn.TABLE_COL_WIDTHS});if(l.push([G.cyan(`Total tasks ${s}:`),G.bold(t)],[G.cyan(`Processing time:`),G.bold(c)]),n&&Object.keys(n).length>0){let e=On(n,t),r=jn(e);l.push(r);let i=An(kn(e,t));l.push([G.cyan(`Distribution:`),i])}l.push([G.cyan(`PRD source:`),G.italic(r)],[G.cyan(`Tasks file:`),G.italic(i)]),o&&l.push([G.yellow(`Fallback parsing:`),G.yellow(`✓ Used fallback parsing`)]);let u=[G.bold.underline(`PRD Parsing Complete - Tasks ${s.charAt(0).toUpperCase()+s.slice(1)}`),``,l.toString()].join(`
|
|
39
|
+
`);console.log(J(u,Sn.summary)),o&&Nn(),Pn()}function Nn(){let e=G.yellow.bold(`⚠️ Fallback Parsing Used`)+`
|
|
40
|
+
|
|
41
|
+
`+T.text(`The system used fallback parsing to complete task generation.`)+`
|
|
42
|
+
`+T.text(`This typically happens when streaming JSON parsing is incomplete.`)+`
|
|
43
|
+
`+T.text(`Your tasks were successfully generated, but consider:`)+`
|
|
44
|
+
`+T.text(`• Reviewing task completeness`)+`
|
|
45
|
+
`+T.text(`• Checking for any missing details`)+`
|
|
46
|
+
|
|
47
|
+
`+T.text(`This is normal and usually doesn't indicate any issues.`);console.log(J(e,Sn.warning))}function Pn(){let e=T.text.bold(`Next Steps:`)+`
|
|
48
|
+
|
|
49
|
+
${G.cyan(`1.`)} Run ${G.yellow(`taskgraph list`)} to view all tasks\n${G.cyan(`2.`)} Run ${G.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks\n${G.cyan(`3.`)} Run ${G.yellow(`taskgraph analyze-complexity`)} to analyze task complexity`;console.log(J(e,Sn.nextSteps))}function Fn(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 In(e){let t=Fn(e);if(!t)return null;try{let e=gn.safeParse(JSON.parse(t));return e.success?e.data:null}catch{return null}}function Ln(e){return Math.ceil(e.length/4)}function Rn(e){let t=q.readFileSync(e,`utf8`);if(!t)throw Error(`Input file ${e} is empty or could not be read.`);return t}function zn(e,t){let n=[],r=1,i=Bn(e);return i[t]?.tasks&&Array.isArray(i[t].tasks)&&(n=i[t].tasks,n.length>0&&(r=Math.max(...n.map(e=>e.id||0))+1)),{existingTasks:n,nextId:r}}function Bn(e){if(!q.existsSync(e))return{};let t=q.readFileSync(e,`utf8`);if(t.trim()===``)return{};try{return JSON.parse(t)}catch(t){throw Error(`${e} is not valid JSON (${t.message}). Fix or remove the file, then run this again`)}}function Vn({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(G.red(n)),process.exit(1)}a.report(`Force flag enabled. Overwriting existing tasks in tag '${t}'.`,`debug`)}}function Hn(e,n,r,i){Un(e,n);let a=n,s=/* @__PURE__ */ new Map,c=e.map(e=>{let t=a++;return s.set(e.id,t),{...e,id:t,status:e.status||`pending`,priority:e.priority||i,dependencies:Array.isArray(e.dependencies)?e.dependencies:[],subtasks:e.subtasks||[],title:e.title||``,description:e.description||``,details:e.details||``,testStrategy:e.testStrategy||``}});return c.forEach(e=>{e.dependencies=e.dependencies.map(e=>s.get(e)).filter(t=>t!=null&&t<e.id&&(v(r,t)||c.some(e=>e.id===t))),t(e,o(e))}),c}function Un(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 Wn(e,t,n,r){let i=Pe.dirname(e);q.existsSync(i)||q.mkdirSync(i,{recursive:!0});let a=Bn(e);a[n]={tasks:t,metadata:{...a[n]?.metadata,created:a[n]?.metadata?.created||(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for ${n} context`}},S(a[n],{description:`Tasks for ${n} context`}),q.writeFileSync(e,JSON.stringify(a,null,2)),r.report(`Successfully saved ${t.length} tasks to ${e}`,`debug`)}async function Gn(e,t,n){let r=V(),i=E(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 Kn({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 qn({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 pn.withSoftTimeout(o.mainResult.usage,1e3,void 0),H(o.telemetryData,`cli`))}function Jn({processedTasks:e,research:t,finalTasks:n,tasksPath:r,aiServiceResponse:i}){console.log(me({tasksPath:Pe.relative(process.cwd(),r)||r,added:e.length,total:n.length,research:t})),i?.telemetryData&&H(i.telemetryData,`cli`)}async function Yn(e,t,n,r=1){let i=new vn(e.mcpLog,e.reportProgress),a=Ln(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=Oe({prdName:Pe.basename(e.prdPath||`PRD`),numTasks:n,startId:r,research:e.research}),{...await Xn(e,t,o),estimatedInputTokens:a}}catch(t){if(Le.isInstance(t)&&!$n(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(`${G.yellow(`⚠`)} Live output stopped. Asking Claude again in one request; the final tasks may differ from the ones above.`)}}return{...await Qn(e,t,o),estimatedInputTokens:a}}async function Xn(e,t,n){let r=await Ae({...er(e,t)}),i=r?.mainResult,a=i?.partialObjectStream;if(!a)throw Error(`AI service did not return a stream`);for await(let e of a)n?.update(e);let o;try{o=await i.object}catch(e){if(o=In(e?.text),!o)throw e}if(!o||!Array.isArray(o.tasks))throw Error(`AI service returned unexpected data structure.`);return n?.succeed(o),r.telemetryData=await Zn(i,r,e),{parsedTasks:o.tasks,aiServiceResponse:r}}async function Zn(e,t,n){let r=t.telemetryData;if(!r?.userId)return r;try{let i=await e.usage;return await Me({userId:r.userId,commandName:`parse-prd`,providerName:t.providerName,modelId:t.modelId,inputTokens:i?.inputTokens??i?.promptTokens??0,outputTokens:i?.outputTokens??i?.completionTokens??0,cachedInputTokens:i?.inputTokenDetails?.cacheReadTokens??0,outputType:n.isMCP?`mcp`:`cli`})||r}catch{return r}}async function Qn(e,t,n){let r=n?Se(`Parsing PRD and generating tasks…`):null;try{let n=await Ne(er(e,t)),i=tr(n?.mainResult);if(!i)throw Error(`AI service returned unexpected data structure after validation.`);return r&&ye(r,`${i.tasks.length} tasks generated`),{parsedTasks:i.tasks,aiServiceResponse:n}}catch(e){throw r&&ke(r,`Couldn't generate tasks`),e}}function $n(e){let t=e.projectRoot,n=e.research?se(t):I(t);return[I(t),oe(t),se(t)].filter(Boolean).some(e=>e!==n)}function er(e,t){return{role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:gn,objectName:`tasks_data`,systemPrompt:t.systemPrompt,prompt:t.userPrompt,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}}function tr(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[nr,rr,ir]=ut,ar=/* @__PURE__ */ new Map;var or=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]||T.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 sr={cli:{filled:`●`,empty:`○`},statusBar:{high:`⋮`,medium:`:`,low:`.`},mcp:{high:`🔴`,medium:`🟠`,low:`🟢`}},cr=new or(`priority`,[nr,rr,ir],{[nr]:G.red,[rr]:G.yellow,[ir]:T.muted});function lr(e,t){let n=sr.cli.filled,r=sr.cli.empty,i=``;for(let a=0;a<3;a++)i+=a<e?t(n):T.text(r);return i}function ur(e,t){return 3-t.indexOf(e)}function dr(e,t){if(ar.has(e))return ar.get(e);let n=t();return ar.set(e,n),n}function fr(){return dr(`mcp-priority-all`,()=>({[nr]:sr.mcp.high,[rr]:sr.mcp.medium,[ir]:sr.mcp.low}))}function pr(){return dr(`cli-priority-all`,()=>{let e={};return cr.levels.forEach(t=>{let n=ur(t,cr.levels),r=cr.getColor(t);e[t]=lr(n,r)}),e})}function mr(){return dr(`statusbar-priority-all`,()=>{let e={};return cr.levels.forEach((t,n)=>{let r=n===0?sr.statusBar.high:n===1?sr.statusBar.medium:sr.statusBar.low,i=cr.getColor(t);e[t]=i(r)}),e})}function hr(){return{[nr]:cr.colors[nr],[rr]:cr.colors[rr],[ir]:cr.colors[ir]}}function gr(e=!1){return e?fr():pr()}function _r(e,t=!1){let n=gr(t);return n[e]||n[rr]}new or(`complexity`,[`high`,`medium`,`low`],{high:G.red,medium:G.yellow,low:G.green},{high:e=>e>=7,medium:e=>e>=4&&e<=6,low:e=>e<=3});const vr={clearOnComplete:!1,stopOnComplete:!0,hideCursor:!0,barsize:40},yr={shades_classic:Re.Presets.shades_classic,shades_grey:Re.Presets.shades_grey,rect:Re.Presets.rect,legacy:Re.Presets.legacy},br=new class{constructor(e={},t=yr.shades_classic){this.defaultOptions={...vr,...e},this.defaultPreset=t}createSingleBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new Re.SingleBar(n,r)}createMultiBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new Re.MultiBar(n,r)}_mergeConfig(e){return{...this.defaultOptions,...e}}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}setDefaultPreset(e){this.defaultPreset=e}};function xr(e={}){return br.createMultiBar(e)}var Sr=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=xr(),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(){}},Cr=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 wr(e,t,n){new Cr(e).createHeader(t,n)}function Tr(e,t,n){new Cr(e).createRow(t,n)}function Er(e,t){new Cr(e).createBorder(t)}pr();const Dr=mr();hr();const Or={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 kr=class{constructor(e=Or.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}},Ar=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():Or.DEFAULT_PRIORITY;return Or.VALID_PRIORITIES.includes(t)?t:Or.DEFAULT_PRIORITY}getCounts(){return{...this.priorities}}},jr=class{static formatTitle(e,t){return e?e.length>Or.MAX_TITLE_LENGTH?e.substring(0,Or.TRUNCATED_LENGTH)+`...`:e:`Task ${t}`}static formatPriority(e){return _r(e,!1).padEnd(Or.PRIORITY_PAD_END,` `)}static formatTaskId(e){return e.toString().padStart(Or.TASK_ID_PAD_START,` `).padEnd(Or.TASK_ID_PAD_END,` `)}},Mr=class extends Sr{_initializeCustomProperties(e){this.append=e.append,this.priorityManager=new Ar,this.debouncer=new kr,this.headerShown=!1}_getTimeTokensBarFormat(){return`{clock} {elapsed} | ${Dr.high} {high} ${Dr.medium} {medium} ${Dr.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,wr(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=jr.formatTitle(t,e),i=jr.formatPriority(n),a=jr.formatTaskId(e);Tr(this.multibar,` ${a} | ${i} | {title}`,{title:r}),Er(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 Nr(e={}){return new Mr(e)}async function Pr(e,t,n){let r=Fr(e,t,n);await Lr(e,n,r.estimatedInputTokens);let i=await Rr(e,t,e.streamingTimeout),{progressTracker:a,priorityMap:o}=await zr(e,n),s=await Br(i.mainResult,e,t,n,a,o,r.defaultPriority,r.estimatedInputTokens,r.logger);if(Ir(s),s.usage&&e.projectRoot){let{logAiUsage:t}=await import(`./ai-services-unified-DUvxqUPT.js`),{getUserId:n}=await import(`./config-manager-DP3N5npn.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 Xr(s,i,r.estimatedInputTokens,a)}function Fr(e,t,n){let{systemPrompt:r,userPrompt:i}=t;return{logger:new vn(e.mcpLog,e.reportProgress),estimatedInputTokens:Ln(r+i),defaultPriority:E(e.projectRoot)||`medium`}}function Ir(e){if(e.parsedTasks.length===0)throw Error(`No tasks were generated from the PRD`)}async function Lr(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 Rr(e,t,n){let{systemPrompt:r,userPrompt:i}=t;return await pn.withTimeout(Ae({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:gn,systemPrompt:r,prompt:i,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),n,`Streaming operation`)}async function zr(e,t){let n=gr(e.isMCP),r=null;if(e.outputFormat===`text`&&!e.isMCP){r=Nr({numUnits:t,unitName:`task`,append:e.append});let n=e.research?se():I(),i=j(e.research?`research`:`main`);Dn({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 Br(e,t,n,r,i,a,o,s,c){let{systemPrompt:l,userPrompt:u}=n,d={config:{...t,schema:gn},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 Vr(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 Gr(t,d)}catch(e){return c.report(`StreamObject processing failed: ${e.message}. Falling back to generateObject.`,`debug`),await Yr(d,c)}}async function Vr(e,t,n){for await(let r of e)t.lastPartialObject=r,r&&(t.estimatedOutputTokens=Ln(JSON.stringify(r))),await Hr(r,t,n)}async function Hr(e,t,n){if(!e?.tasks||!Array.isArray(e.tasks))return;let r=e.tasks.length;r>t.taskCount?(await Ur(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 Ur(e,t,n,r,i){for(let a=t;a<n;a++){let t=e[a]||{};t.title?await Kn({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 Wr(a+1,r,i)}}async function Wr(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 Gr(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 Kr(n.tasks,i,a?o:r,t,a?s:null),{parsedTasks:n.tasks,estimatedOutputTokens:o,actualInputTokens:s,usage:a,usedFallback:!1}}async function Kr(e,t,n,r,i=null){let{progressTracker:a,defaultPriority:o,estimatedInputTokens:s}=r;t>0?qr(e,a,o):await Jr(e,n,r),a.updateTokens(i||s,n,!1),a.stop()}function qr(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 Jr(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&await Kn({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 Yr(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 Ne({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}),r=n?.mainResult||n;if(r&&Array.isArray(r.tasks)&&(r.tasks=r.tasks.map(e=>({...e,dependencies:e.dependencies??[],priority:e.priority??null,details:e.details??null,testStrategy:e.testStrategy??null}))),r&&Array.isArray(r.tasks)){if(e.progressTracker){for(let t=0;t<r.tasks.length;t++){let n=r.tasks[t];n&&n.title&&e.progressTracker.addTaskLine(t+1,n.title,n.priority||e.defaultPriority)}let t=n.telemetryData?.outputTokens||Ln(JSON.stringify(r)),i=n.telemetryData?.inputTokens||e.estimatedInputTokens;e.progressTracker.updateTokens(i,t,!1)}return{parsedTasks:r.tasks,estimatedOutputTokens:n.telemetryData?.outputTokens||Ln(JSON.stringify(r)),actualInputTokens:n.telemetryData?.inputTokens,telemetryData:n.telemetryData,usedFallback:!0}}throw Error(`Failed to generate tasks using generateObject fallback`)}function Xr(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 Zr(e,t,n){let r=new vn(e.mcpLog,e.reportProgress);r.report(`Parsing PRD file: ${e.prdPath}, Force: ${e.force}, Append: ${e.append}, Research: ${e.research}`,`debug`);try{let i=zn(e.tasksPath,e.targetTag),a=e.append?i.existingTasks:[],o=e.append?i.nextId:1;Vn({existingTasks:i.existingTasks,targetTag:e.targetTag,append:e.append,force:e.force,isMCP:e.isMCP,logger:r});let s=await t(e,await Gn(e,Rn(e.prdPath),o),e.numTasks,o),c=E(e.projectRoot)||`medium`,l=Hn(s.parsedTasks,o,a,c),u=e.append?[...a,...l]:l;return Wn(e.tasksPath,u,e.targetTag,r),await Qr(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`):F(e.projectRoot)&&console.error(t),t}}async function Qr(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 qn({processedTasks:n,nextId:i,summary:t.summary,prdPath:e.prdPath,tasksPath:e.tasksPath,usedFallback:t.usedFallback,aiServiceResponse:o}):a||Jn({processedTasks:n,research:e.research,finalTasks:r,tasksPath:e.tasksPath,aiServiceResponse:o}))}async function $r(e,t,n,r={}){return Zr(new _n(e,t,n,r),Pr,!0)}async function ei(e,t,n,r={}){return Zr(new _n(e,t,n,r),Yn,!1)}async function ti(e,t,n,r={}){let i=new _n(e,t,n,r);if(i.useStreaming)try{return await $r(e,t,n,r)}catch(a){if(a instanceof dn||a.code===fn.NOT_ASYNC_ITERABLE||a.code===fn.STREAM_PROCESSING_FAILED||a.code===fn.STREAM_NOT_ITERABLE||pn.isTimeoutError(a)){let o=new vn(i.mcpLog,i.reportProgress);return i.outputFormat===`text`&&!i.isMCP?console.log(G.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 ei(e,t,n,r)}throw a}return await ei(e,t,n,r)}async function ni(e,n,r=!1,i=!1,a={}){let{projectRoot:o,tag:s}=a;try{p(`debug`,`Removing subtask ${n}...`);let i=N(e,o,s);if(!i||!i.tasks)throw Error(`Invalid or missing tasks file at ${e}`);if(!n.includes(`.`))throw Error(`Invalid subtask ID format: ${n}. Expected format: "parentId.subtaskId"`);let[a,c]=n.split(`.`),l=parseInt(a,10),u=parseInt(c,10),d=i.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 ${n} not found`);let m={...d.subtasks[f]};d.subtasks.splice(f,1),d.subtasks.length===0&&(d.subtasks=void 0);let h=null;if(r){p(`debug`,`Converting subtask ${n} to a standalone task...`);let e=Math.max(...i.tasks.map(e=>e.id))+1,r=ze(m,l,void 0);h={id:e,title:m.title,description:m.description||``,details:m.details||``,status:m.status||`pending`,dependencies:r.dependencies,priority:d.priority||`medium`},t(h,r.metadata),h.dependencies.includes(String(l))||h.dependencies.push(String(l)),Ve(i.tasks,`${l}.${u}`,e),i.tasks.push(h),p(`info`,`Created new task ${e} from subtask ${n}`)}else p(`debug`,`Subtask ${n} deleted`);return O(e,i,o,s),h}catch(e){throw p(`debug`,`Error removing subtask: ${e.message}`),e}}function ri(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 ii(e,n,r={}){let{projectRoot:i,tag:o}=r,s={success:!0,messages:[],errors:[],removedTasks:[]},c=n.split(`,`).map(e=>e.trim()).filter(Boolean);if(c.length===0)return s.success=!1,s.errors.push(`No valid task IDs provided.`),s;try{let n=N(e,i,o);if(!n)throw Error(`Could not read tasks file at ${e}`);let r=n._rawTaggedData||n;if(!r[o]||!r[o].tasks)throw Error(`Tag '${o}' not found or has no tasks.`);let l=[];if(await Et(e,o,e=>{let n=e.tasks;for(let e of c)if(ri(n,e))try{if(typeof e==`string`&&e.includes(`.`)){let[t,r]=e.split(`.`).map(e=>parseInt(e,10)),i=n.find(e=>e.id===t);if(!i||!i.subtasks)throw Error(`Parent task ${t} or its subtasks not found for subtask ${e}`);let a=i.subtasks.findIndex(e=>e.id===r);if(a===-1)throw Error(`Subtask ${r} not found in parent task ${t}`);let c={...i.subtasks[a],parentTaskId:t};s.removedTasks.push(c),i.subtasks.splice(a,1),s.messages.push(`Successfully removed subtask ${e} from tag '${o}'`)}else{let t=parseInt(e,10),r=n.findIndex(e=>e.id===t);if(r===-1)throw Error(`Task with ID ${e} not found in tag '${o}'`);let i=n[r];s.removedTasks.push(i),l.push(t),n.splice(r,1),s.messages.push(`Successfully removed task ${e} from tag '${o}'`)}}catch(t){let n=`Error processing ID ${e}: ${t.message}`;s.errors.push(n),s.success=!1,p(`warn`,n)}else{let t=`Task with ID ${e} in tag '${o}' not found or already removed.`;s.errors.push(t),s.success=!1}if(s.removedTasks.length>0){let e=new Set(c.map(e=>typeof e==`string`&&e.includes(`.`)?e:String(parseInt(e,10))));n.forEach(n=>{n.dependencies&&(n.dependencies=n.dependencies.filter(t=>!e.has(String(t))),t(n,a(n))),n.subtasks&&n.subtasks.forEach(r=>{r.dependencies&&(r.dependencies=r.dependencies.filter(t=>!e.has(f(n.id,t))),t(r,a(r,n.id)))})})}}),s.removedTasks.length>0)for(let t of l){let n=Pe.join(Pe.dirname(e),`task_${t.toString().padStart(3,`0`)}.txt`);if(Fe.existsSync(n))try{Fe.unlinkSync(n),s.messages.push(`Deleted task file: ${n}`)}catch(e){let t=`Failed to delete task file ${n}: ${e.message}`;s.errors.push(t),s.success=!1,p(`warn`,t)}}else s.errors.length===0&&s.messages.push(`No tasks found matching the provided IDs.`);let u=s.messages.join(`
|
|
50
|
+
`),d=s.errors.join(`
|
|
51
|
+
`);return{success:s.success,message:u||`No tasks were removed.`,error:d||null,removedTasks:s.removedTasks}}catch(e){return p(`error`,`Error removing tasks: ${e.message}`),{success:!1,message:``,error:`Operation failed: ${e.message}`,removedTasks:[]}}}const ai=[`light`,`regular`,`heavy`],oi=[`done`,`in-progress`,`review`,`cancelled`,`deferred`,`blocked`],si=[`pending`];function ci(e){return ai.includes(e)}async function li(e,t,n){let{projectRoot:r,tag:i,session:a}=n;try{let n={tasks:[e],metadata:{analyzedAt:(/* @__PURE__ */ new Date()).toISOString()}},o=y(null,{projectRoot:r,tag:i},null);if(!o)return p(`warn`,`No complexity report found - cannot re-analyze complexity`),null;await At({file:t,output:o,id:e.id.toString(),projectRoot:r,tag:i,_filteredTasksData:n,_originalTaskCount:1},{session:a});let s=re(o);if(s){let t=ne(s,e.id);if(t)return p(`info`,`Re-analyzed task ${e.id} complexity: ${t.complexityScore}/10`),t.complexityScore}return p(`warn`,`Could not find updated complexity analysis for task ${e.id}`),null}catch(e){return p(`error`,`Failed to re-analyze task complexity: ${e.message}`),null}}function ui(e,t){let{projectRoot:n,tag:r}=t;try{let t=y(null,{projectRoot:n,tag:r},null);if(!t)return null;let i=re(t);if(!i)return null;let a=ne(i,e);return a?a.complexityScore:null}catch(e){return p(`debug`,`Could not read current complexity score: ${e.message}`),null}}async function di(e,n,r,i,a=`regular`,s=null){let{projectRoot:c,tag:l,session:u}=r;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=>oi.includes(e.status)),f=e.subtasks.filter(e=>si.includes(e.status));if(f.length===0)return{updatedTask:e,regenerated:!1,preserved:d.length,generated:0};let m,h=d.length,g=f.length,_=s?Math.max(.5,s/10):1,v=s?` (original complexity: ${s}/10)`:``;if(i===`up`){if(a===`light`){let e=Math.max(5,h+Math.ceil(g*1.1));m=Math.ceil(e*(.8+.4*_))}else if(a===`regular`){let e=Math.max(6,h+Math.ceil(g*1.3));m=Math.ceil(e*(.8+.4*_))}else{let e=Math.max(8,h+Math.ceil(g*1.6));m=Math.ceil(e*(.8+.6*_))}}else{let e=s>=8?.7:s>=6?.85:1;if(a===`light`){let t=Math.max(3,h+Math.ceil(g*.8));m=Math.ceil(t*e)}else if(a===`regular`){let t=Math.max(3,h+Math.ceil(g*.5));m=Math.ceil(t*e)}else{let e=s>=9?.3:s>=7?.5:.7,t=Math.max(2,h+Math.ceil(g*.25));m=Math.max(1,Math.ceil(t*e))}}p(`debug`,`Complexity-aware subtask calculation${v}: ${g} pending -> target ${m} total`),p(`debug`,`Complexity-aware calculation${v}: ${g} pending -> ${m} total subtasks (${a} ${i})`);let y=Math.max(1,m-h);try{let n=`Based on this updated task, generate ${y} NEW subtasks that reflect the ${i===`up`?`increased`:`decreased`} complexity level:
|
|
52
|
+
|
|
53
|
+
**Task Title**: ${e.title}
|
|
54
|
+
**Task Description**: ${e.description}
|
|
55
|
+
**Implementation Details**: ${e.details}
|
|
56
|
+
**Test Strategy**: ${e.testStrategy}
|
|
57
|
+
|
|
58
|
+
**Complexity Direction**: This task was recently scoped ${i} (${a} strength) to ${i===`up`?`increase`:`decrease`} complexity.
|
|
59
|
+
${s?`**Original Complexity**: ${s}/10 - consider this when determining appropriate scope level.`:``}
|
|
60
|
+
|
|
61
|
+
${h>0?`**Preserved Subtasks**: ${h} existing subtasks with work already done will be kept.`:``}
|
|
62
|
+
|
|
63
|
+
Generate subtasks that:
|
|
64
|
+
${i===`up`?a===`heavy`?`- Add comprehensive implementation steps with advanced features
|
|
65
|
+
- Include extensive error handling, validation, and edge cases
|
|
66
|
+
- Cover multiple integration scenarios and advanced testing
|
|
67
|
+
- Provide thorough documentation and optimization approaches`:a===`regular`?`- Add more detailed implementation steps
|
|
68
|
+
- Include additional error handling and validation
|
|
69
|
+
- Cover more edge cases and advanced features
|
|
70
|
+
- Provide more comprehensive testing approaches`:`- Add some additional implementation details
|
|
71
|
+
- Include basic error handling considerations
|
|
72
|
+
- Cover a few common edge cases
|
|
73
|
+
- Enhance testing approaches slightly`:a===`heavy`?`- Focus ONLY on absolutely essential core functionality
|
|
74
|
+
- Strip out ALL non-critical features (error handling, advanced testing, etc.)
|
|
75
|
+
- Provide only the minimum viable implementation
|
|
76
|
+
- Eliminate any complex integrations or advanced scenarios
|
|
77
|
+
- Aim for the simplest possible working solution`:a===`regular`?`- Focus on core functionality only
|
|
78
|
+
- Simplify implementation steps
|
|
79
|
+
- Remove non-essential features
|
|
80
|
+
- Streamline to basic requirements`:`- Focus mainly on core functionality
|
|
81
|
+
- Slightly simplify implementation steps
|
|
82
|
+
- Remove some non-essential features
|
|
83
|
+
- Streamline most requirements`}
|
|
84
|
+
|
|
85
|
+
Return a JSON object with a "subtasks" array. Each subtask should have:
|
|
86
|
+
- id: Sequential NUMBER starting from 1 (e.g., 1, 2, 3 - NOT "1", "2", "3")
|
|
87
|
+
- title: Clear, specific title
|
|
88
|
+
- description: Detailed description
|
|
89
|
+
- dependencies: Array of dependency IDs as STRINGS (use format ["${e.id}.1", "${e.id}.2"] for siblings, or empty array [] for no dependencies)
|
|
90
|
+
- details: Implementation guidance
|
|
91
|
+
- status: "pending"
|
|
92
|
+
- testStrategy: Testing approach
|
|
93
|
+
|
|
94
|
+
IMPORTANT:
|
|
95
|
+
- The 'id' field must be a NUMBER, not a string!
|
|
96
|
+
- Dependencies must be strings, not numbers!
|
|
97
|
+
|
|
98
|
+
Ensure the JSON is valid and properly formatted.`,c=K.object({subtasks:K.array(K.object({id:K.int().positive(),title:K.string().min(5),description:K.string().min(10),dependencies:K.array(K.string()),details:K.string().min(20),status:K.string(),testStrategy:K.string()}))}),l=(await Ne({role:r.research?`research`:`main`,session:r.session,systemPrompt:`You are an expert project manager who creates task breakdowns that match complexity levels.`,prompt:n,schema:c,objectName:`subtask_regeneration`,commandName:r.commandName||`subtask-regen-${i}`,outputType:r.outputType||`cli`,projectRoot:r.projectRoot})).mainResult.subtasks||[];fi(l);let u=l.map(e=>({...e,status:e.status||`pending`,testStrategy:e.testStrategy||``})),f=d.reduce((e,t)=>Math.max(e,t.id||0),0)+1,p=/* @__PURE__ */ new Map,m=u.map(e=>{let t=e.id,n=f++;return p.set(t,n),{...e,id:n}}).map(n=>{let r={...n,dependencies:(n.dependencies||[]).map(t=>{if(typeof t!=`string`||!t.startsWith(`${e.id}.`))return t;let[,n]=t.split(`.`),r=Number.parseInt(n,10),i=p.get(r);return i?`${e.id}.${i}`:t})};return t(r,o(r,void 0,e.id)),r});return e.subtasks=[...d,...m],{updatedTask:e,regenerated:!0,preserved:d.length,generated:m.length}}catch(t){return p(`warn`,`Failed to regenerate subtasks for task ${e.id}: ${t.message}`),{updatedTask:e,regenerated:!1,preserved:d.length,generated:0,error:t.message}}}function fi(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 pi(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.
|
|
99
|
+
|
|
100
|
+
CURRENT TASK:
|
|
101
|
+
Title: ${e.title}
|
|
102
|
+
Description: ${e.description}
|
|
103
|
+
Details: ${e.details}
|
|
104
|
+
Test Strategy: ${e.testStrategy||`Not specified`}
|
|
105
|
+
|
|
106
|
+
ADJUSTMENT REQUIREMENTS:
|
|
107
|
+
- Direction: ${i?`INCREASE`:`DECREASE`} complexity
|
|
108
|
+
- Strength: ${n} (${a[n]})
|
|
109
|
+
- Preserve the core purpose and functionality of the task
|
|
110
|
+
- Maintain consistency with the existing task structure`;return o+=i?`
|
|
111
|
+
- Add more detailed requirements, edge cases, or advanced features
|
|
112
|
+
- Include additional implementation considerations
|
|
113
|
+
- Enhance error handling and validation requirements
|
|
114
|
+
- Expand testing strategies with more comprehensive scenarios`:`
|
|
115
|
+
- Focus on core functionality and essential requirements
|
|
116
|
+
- Remove or simplify non-essential features
|
|
117
|
+
- Streamline implementation details
|
|
118
|
+
- Simplify testing to focus on basic functionality`,r&&(o+=`\n\nCUSTOM INSTRUCTIONS:\n${r}`),o+=`
|
|
119
|
+
|
|
120
|
+
Return a JSON object with the updated task containing these fields:
|
|
121
|
+
- title: Updated task title
|
|
122
|
+
- description: Updated task description
|
|
123
|
+
- details: Updated implementation details
|
|
124
|
+
- testStrategy: Updated test strategy
|
|
125
|
+
- priority: Task priority ('low', 'medium', or 'high')
|
|
126
|
+
|
|
127
|
+
Ensure the JSON is valid and properly formatted.`,o}async function mi(e,t,n,r,i){let a=pi(e,t,n,r),o=K.object({title:K.string().min(1).describe(`Updated task title reflecting scope adjustment`),description:K.string().min(1).describe(`Updated task description with adjusted scope`),details:K.string().min(1).describe(`Updated implementation details with adjusted complexity`),testStrategy:K.string().min(1).describe(`Updated testing approach for the adjusted scope`),priority:K.enum([`low`,`medium`,`high`]).describe(`Task priority level`)}),s=await Ne({role:i.research?`research`:`main`,session:i.session,systemPrompt:`You are an expert software project manager who helps adjust task complexity while maintaining clarity and actionability.`,prompt:a,schema:o,objectName:`updated_task`,commandName:i.commandName||`scope-${t}`,outputType:i.outputType||`cli`,projectRoot:i.projectRoot}),c=s.mainResult,l={...c,priority:c.priority||e.priority||`medium`};return{updatedTask:{...e,...l},telemetryData:s.telemetryData}}async function hi(e,t,n=`regular`,r=null,i={},a=`text`){if(!ci(n))throw Error(`Invalid strength level: ${n}. Must be one of: ${ai.join(`, `)}`);let{projectRoot:o=`.`,tag:s=`master`}=i,c=N(e,o,s),l=c?.tasks||[];for(let e of t)if(!ri(l,e))throw Error(`Task with ID ${e} not found`);let u=[],d=null;for(let f of t){let t=v(l,f).task;if(!t)throw Error(`Task with ID ${f} not found`);a===`text`&&p(`debug`,`Scoping up task ${f}: ${t.title}`);let m=ui(f,i);m&&a===`text`&&p(`debug`,`Original complexity: ${m}/10`);let h=await mi(t,`up`,n,r,i),g=await di(h.updatedTask,e,i,`up`,n,m);a===`text`&&g.regenerated&&p(`info`,`Regenerated ${g.generated} pending subtasks (preserved ${g.preserved} completed)`);let _=c.tasks.findIndex(e=>e.id===f);if(_!==-1&&(c.tasks[_]=g.updatedTask,u.push(g.updatedTask)),i.session&&m)try{O(e,c,o,s);let t=await li(g.updatedTask,e,i);if(t&&a===`text`){let e=t-m;p(`info`,`New complexity: ${m}/10 ${e>0?`↗️`:e<0?`↘️`:`➡️`} ${t}/10 (${e>0?`+`:``}${e})`)}}catch(e){a===`text`&&p(`warn`,`Could not re-analyze complexity: ${e.message}`)}h.telemetryData&&(d?(d.inputTokens+=h.telemetryData.inputTokens||0,d.outputTokens+=h.telemetryData.outputTokens||0,d.totalTokens+=h.telemetryData.totalTokens||0,d.totalCost+=h.telemetryData.totalCost||0):d={...h.telemetryData})}return O(e,c,o,s),a===`text`&&p(`debug`,`Successfully scoped up ${u.length} task(s)`),{updatedTasks:u,telemetryData:d}}async function gi(e,t,n=`regular`,r=null,i={},a=`text`){if(!ci(n))throw Error(`Invalid strength level: ${n}. Must be one of: ${ai.join(`, `)}`);let{projectRoot:o=`.`,tag:s=`master`}=i,c=N(e,o,s),l=c?.tasks||[];for(let e of t)if(!ri(l,e))throw Error(`Task with ID ${e} not found`);let u=[],d=null;for(let f of t){let t=v(l,f).task;if(!t)throw Error(`Task with ID ${f} not found`);a===`text`&&p(`debug`,`Scoping down task ${f}: ${t.title}`);let m=ui(f,i);m&&a===`text`&&p(`debug`,`Original complexity: ${m}/10`);let h=await mi(t,`down`,n,r,i),g=await di(h.updatedTask,e,i,`down`,n,m);a===`text`&&g.regenerated&&p(`info`,`Regenerated ${g.generated} pending subtasks (preserved ${g.preserved} completed)`);let _=c.tasks.findIndex(e=>e.id===f);if(_!==-1&&(c.tasks[_]=g.updatedTask,u.push(g.updatedTask)),i.session&&m)try{O(e,c,o,s);let t=await li(g.updatedTask,e,i);if(t&&a===`text`){let e=t-m;p(`info`,`New complexity: ${m}/10 ${e>0?`↗️`:e<0?`↘️`:`➡️`} ${t}/10 (${e>0?`+`:``}${e})`)}}catch(e){a===`text`&&p(`warn`,`Could not re-analyze complexity: ${e.message}`)}h.telemetryData&&(d?(d.inputTokens+=h.telemetryData.inputTokens||0,d.outputTokens+=h.telemetryData.outputTokens||0,d.totalTokens+=h.telemetryData.totalTokens||0,d.totalCost+=h.telemetryData.totalCost||0):d={...h.telemetryData})}return O(e,c,o,s),a===`text`&&p(`debug`,`Successfully scoped down ${u.length} task(s)`),{updatedTasks:u,telemetryData:d}}async function _i(e,t,n,r=!1,a={},o=a.mcpLog?`json`:`text`){let{session:s,mcpLog:c,projectRoot:l,tag:u}=a,d=i(a.metadata),f=c||p,m=!!c,v=(e,...t)=>{m?typeof f[e]==`function`?f[e](...t):f.info(...t):b()||f(e,...t)},y=null;try{if(v(`debug`,`Updating subtask ${t} with prompt: "${n}"`),!t||typeof t!=`string`)throw Error(`Subtask ID cannot be empty.`);if((!n||typeof n!=`string`||n.trim()===``)&&!d)throw Error(`Prompt cannot be empty unless metadata is provided. Please provide context for the subtask update or metadata to merge.`);let i=l||g();if(!i)throw Error(`Could not determine project root directory`);if(!t.includes(`.`))throw Error(`Invalid subtask ID format: ${t}. In solo mode, subtask ID must be in format "parentId.subtaskId" (e.g., "5.2").`);if(!q.existsSync(e))throw Error(`Tasks file not found at path: ${e}`);let a=N(e,i,u);if(!a||!a.tasks)throw Error(`No valid tasks found in ${e}. The file may be corrupted or have an invalid format.`);let[c,f]=t.split(`.`),p=parseInt(c,10),b=parseInt(f,10);if(Number.isNaN(p)||p<=0||Number.isNaN(b)||b<=0)throw Error(`Invalid subtask ID format: ${t}. Both parent ID and subtask ID must be positive integers.`);let x=a.tasks.find(e=>e.id===p);if(!x)throw Error(`Task ${p} not found`);if(!x.subtasks||!Array.isArray(x.subtasks))throw Error(`Parent task ${p} has no subtasks.`);let S=x.subtasks.findIndex(e=>e.id===b);if(S===-1)throw Error(`Subtask ${t} not found`);let C=x.subtasks[S];if(d&&(!n||n.trim()===``))return v(`debug`,`Metadata-only update for subtask ${t}`),C.metadata={...C.metadata||{},...d},x.subtasks[S]=C,O(e,a,i,u),v(`success`,`Successfully updated metadata for subtask ${t}`),{updatedSubtask:C,telemetryData:null,tagInfo:{tag:u}};let w=``;try{let e=new U(i,u),r=_(a.tasks),o=new Te(r,`update-subtask`),s=`${x.title} ${C.title} ${n}`,c=o.findRelevantTasks(s,{maxResults:5,includeSelf:!0}),l=o.getTaskIds(c),d=[.../* @__PURE__ */ new Set([t.toString(),...l])];d.length>0&&(w=(await e.gather({tasks:d,format:`research`})).context||``)}catch(e){v(`warn`,`Could not gather context: ${e.message}`)}o===`text`&&(y=Se(`Updating subtask ${t}: ${P(C.title,50)}${r?` (with research)`:``}`));let T=``,E=null;try{let e={id:x.id,title:x.title},t=S>0?{id:`${x.id}.${x.subtasks[S-1].id}`,title:x.subtasks[S-1].title,status:x.subtasks[S-1].status}:void 0,a=S<x.subtasks.length-1?{id:`${x.id}.${x.subtasks[S+1].id}`,title:x.subtasks[S+1].title,status:x.subtasks[S+1].status}:void 0,c=V(),l={parentTask:e,prevSubtask:t,nextSubtask:a,currentDetails:C.details||`(No existing details)`,updatePrompt:n,useResearch:r,gatheredContext:w||``,hasCodebaseAnalysis:h(r,i,s),projectRoot:i},u=r?`research`:`default`,{systemPrompt:d,userPrompt:f}=await c.loadPrompt(`update-subtask`,l,u),p=r?`research`:`main`;v(`debug`,`Using AI text service with role: ${p}`),E=await je({prompt:f,systemPrompt:d,role:p,session:s,projectRoot:i,maxRetries:2,commandName:`update-subtask`,outputType:m?`mcp`:`cli`}),E&&E.mainResult&&typeof E.mainResult==`string`?T=E.mainResult:(T=``,o!==`text`&&v(`warn`,`AI service response did not contain expected text string.`)),o===`text`&&y&&(B(y),y=null)}catch(e){throw o===`text`&&y&&(B(y),y=null),e}if(T&&T.trim()){let e=(/* @__PURE__ */ new Date()).toISOString(),t=`<info added on ${e}>\n${T.trim()}\n</info added on ${e}>`;C.details=(C.details?C.details+`
|
|
128
|
+
`:``)+t}else o!==`text`&&v(`warn`,`AI response was empty or whitespace after trimming. Original details remain unchanged.`);let D=x.subtasks[S];return d&&(D.metadata={...D.metadata||{},...d}),o===`text`&&F(s)&&console.log(`>>> DEBUG: Subtask details AFTER AI update:`,D.details),D.description&&n.length<100&&(o===`text`&&F(s)&&console.log(`>>> DEBUG: Subtask description BEFORE append:`,D.description),D.description+=` [Updated: ${(/* @__PURE__ */ new Date()).toLocaleDateString()}]`,o===`text`&&F(s)&&console.log(`>>> DEBUG: Subtask description AFTER append:`,D.description)),o===`text`&&F(s)&&console.log(`>>> DEBUG: About to call writeJSON with updated data...`),O(e,a,i,u),o===`text`&&F(s)&&console.log(`>>> DEBUG: writeJSON call completed.`),v(`debug`,`Successfully updated subtask ${t}`),o===`text`&&(y&&=(B(y),null),console.log(ue({kind:`subtask`,id:t,title:D.title},T?.trim()??``))),o===`text`&&E.telemetryData&&H(E.telemetryData,`cli`),{updatedSubtask:D,telemetryData:E.telemetryData,tagInfo:E.tagInfo}}catch(e){throw o===`text`&&y&&(B(y),y=null),o!==`text`&&v(`error`,`Error updating subtask: ${e.message}`),e}}async function vi(e,n,r,a=!1,s={},l=`text`,u=!1){let{session:d,mcpLog:f,projectRoot:p,tag:m}=s,v=i(s.metadata),{report:y,isMCP:b}=Pt(f,d);try{if(y(`debug`,`Updating single task ${n} with prompt: "${r}"`),n==null||String(n).trim()===``)throw Error(`Task ID cannot be empty.`);if((!r||typeof r!=`string`||r.trim()===``)&&!v)throw Error(`Prompt cannot be empty unless metadata is provided for update.`);let i=p||g();if(!i)throw Error(`Could not determine project root directory`);if(!q.existsSync(e))throw Error(`Tasks file not found: ${e}`);let s=N(e,i,m);if(!s||!s.tasks)throw Error(`No valid tasks found in ${e}.`);let f=String(n).trim();if(!/^\d+$/.test(f))throw Error(`taskId must be a positive integer. Use update-subtask-by-id for IDs like "1.2".`);let x=Number(f),S=s.tasks.findIndex(e=>e.id===x);if(S===-1)throw Error(`Task ${x} not found`);let C=s.tasks[S];if(C.status===`done`||C.status===`completed`)return l!==`text`&&y(`warn`,`Task ${n} is already marked as done and cannot be updated`),null;if(v&&(!r||r.trim()===``))return y(`debug`,`Metadata-only update for task ${n}`),C.metadata={...C.metadata||{},...v},s.tasks[S]=C,O(e,s,i,m),y(`success`,`Successfully updated metadata for task ${n}`),{updatedTask:C,telemetryData:null,tagInfo:{tag:m}};let w=``;try{let e=new U(i,m),t=_(s.tasks),a=new Te(t,`update-task`),o=`${C.title} ${C.description} ${r}`,c=a.findRelevantTasks(o,{maxResults:5,includeSelf:!0}),l=a.getTaskIds(c),u=[.../* @__PURE__ */ new Set([n.toString(),...l])];u.length>0&&(w=(await e.gather({tasks:u,format:`research`})).context||``)}catch(e){y(`warn`,`Could not gather context: ${e.message}`)}let T=V(),E={task:C,taskJson:JSON.stringify(C,null,2),updatePrompt:r,appendMode:u,useResearch:a,currentDetails:C.details||`(No existing details)`,gatheredContext:w||``,hasCodebaseAnalysis:h(a,i,d),projectRoot:i},D=u?`append`:a?`research`:`default`;y(`debug`,`Loading prompt template with variant: ${D}, appendMode: ${u}, useResearch: ${a}`);let k,A;try{let e=T.loadPrompt(`update-task`,E,D);y(`debug`,`Prompt result type: ${typeof e}, keys: ${e?Object.keys(e).join(`, `):`null`}`),k=e.systemPrompt,A=e.userPrompt,y(`debug`,`Loaded prompts - systemPrompt length: ${k?.length}, userPrompt length: ${A?.length}`)}catch(e){throw y(`error`,`Failed to load prompt template: ${e.message}`),Error(`Failed to load prompt template: ${e.message}`)}if(!k||!A)throw Error(`Failed to load prompts: systemPrompt=${!!k}, userPrompt=${!!A}`);let j=null,M=null;!b&&l===`text`&&(j=Se(`Updating task ${n}: ${P(C.title,50)}${a?` (with research)`:``}`));try{let f=a?`research`:`main`;if(M=u?await je({role:f,session:d,projectRoot:i,systemPrompt:k,prompt:A,commandName:`update-task`,outputType:b?`mcp`:`cli`}):await Ne({role:f,session:d,projectRoot:i,systemPrompt:k,prompt:A,schema:Tt[`update-task-by-id`],objectName:`task`,commandName:`update-task`,outputType:b?`mcp`:`cli`}),j&&B(j,`AI update complete.`),u){let t=M.mainResult,a=typeof t==`string`?t.trim():``;if(a){let e=(/* @__PURE__ */ new Date()).toISOString(),t=`<info added on ${e}>\n${a}\n</info added on ${e}>`;C.details=(C.details?C.details+`
|
|
129
|
+
`:``)+t}else l!==`text`&&y(`warn`,`AI response was empty or whitespace after trimming. Original details remain unchanged.`);return r.length<100&&C.description&&(C.description+=` [Updated: ${(/* @__PURE__ */ new Date()).toLocaleDateString()}]`),v&&(C.metadata={...C.metadata||{},...v}),s.tasks[S]=C,O(e,s,i,m),y(`debug`,`Successfully appended to task ${n}`),l===`text`&&console.log(ue({kind:`task`,id:n,title:C.title},a)),l===`text`&&M.telemetryData&&H(M.telemetryData,`cli`),{updatedTask:C,telemetryData:M.telemetryData,tagInfo:M.tagInfo}}let p=M.mainResult?.task;if(!p||typeof p!=`object`)throw Error(`Received invalid task object from AI.`);let h={...p,dependencies:p.dependencies??[],priority:p.priority??null,details:p.details??null,testStrategy:p.testStrategy??null};if(!h.title||!h.description)throw Error(`Updated task missing required fields.`);if(h.id!==n&&(y(`debug`,`AI changed task ID. Restoring original ID ${n}.`),h.id=n),h.status!==C.status&&!r.toLowerCase().includes(`status`)&&(y(`warn`,`AI changed task status. Restoring original status '${C.status}'.`),h.status=C.status),h.subtasks&&Array.isArray(h.subtasks)){let e=1;h.subtasks=h.subtasks.map(n=>{let r=C.subtasks?.find(e=>String(e.id)===String(n.id)||n.title&&e.title===n.title),i={...n,id:e,dependencies:Array.isArray(n.dependencies)?n.dependencies.map(e=>typeof e==`string`?parseInt(e,10):e).filter(t=>!Number.isNaN(t)&&t>=1&&t<e):[],status:n.status||`pending`,testStrategy:n.testStrategy??null,...r?.metadata&&{metadata:r.metadata}};return c(i,r),e++,t(i,o(i,r,C.id)),i}),y(`debug`,`Fixed ${h.subtasks.length} subtask IDs to be sequential numeric IDs.`)}if(C.subtasks?.length>0){if(!h.subtasks)y(`warn`,`Subtasks removed by AI. Restoring original subtasks.`),h.subtasks=C.subtasks;else{C.subtasks.filter(e=>e.status===`done`||e.status===`completed`).forEach(e=>{let t=h.subtasks.find(t=>t.id===e.id);(!t||JSON.stringify(t)!==JSON.stringify(e))&&(y(`warn`,`Completed subtask ${e.id} was modified or removed. Restoring.`),h.subtasks=h.subtasks.filter(t=>t.id!==e.id),h.subtasks.push(e))});let e=/* @__PURE__ */ new Set;h.subtasks=h.subtasks.filter(t=>e.has(t.id)?(y(`warn`,`Duplicate subtask ID ${t.id} removed.`),!1):(e.add(t.id),!0))}}let g=o(h,C);return(g||v)&&(h.metadata={...g||{},...v||{}}),c(h,C),s.tasks[S]=h,O(e,s,i,m),l===`text`?console.log(fe(h)):y(`success`,`Updated task ${n}`),l===`text`&&M.telemetryData&&H(M.telemetryData,`cli`),{updatedTask:h,telemetryData:M.telemetryData,tagInfo:M.tagInfo}}catch(e){throw j&&B(j),e}}catch(e){throw l!==`text`&&y(`error`,`Error updating task: ${e.message}`),e}}async function yi(e,n,r,i=!1,a={},s=`text`){let{session:l,mcpLog:u,projectRoot:d,tag:f}=a,m=u||p,v=!!u;v?m.debug(`updateTasks called with context: session=${!!l}`):m(`debug`,`updateTasks called`);try{v?m.debug(`Updating tasks from ID ${n}`):m(`debug`,`Updating tasks from ID ${n} with prompt: "${r}"`);let a=d||g();if(!a)throw Error(`Could not determine project root directory`);let u=N(e,a,f);if(!u||!u.tasks)throw Error(`No valid tasks found in ${e}`);let p=u.tasks.filter(e=>e.id>=n&&e.status!==`done`);if(p.length===0){v?m.info(`No tasks to update (ID >= ${n} and not 'done').`):s===`text`?console.log(de(n)):m(`info`,`No tasks to update (ID >= ${n} and not 'done').`);return}let y=``;try{let e=new U(a,f),t=_(u.tasks),n=new Te(t,`update`),i=n.findRelevantTasks(r,{maxResults:5,includeSelf:!0}),o=n.getTaskIds(i),s=p.map(e=>e.id.toString()),c=[.../* @__PURE__ */ new Set([...s,...o])];c.length>0&&(y=(await e.gather({tasks:c,format:`research`})).context||``)}catch(e){m(`warn`,`Could not gather additional context: ${e.message}`)}let{systemPrompt:b,userPrompt:x}=await V().loadPrompt(`update-tasks`,{tasks:p,updatePrompt:r,useResearch:i,projectContext:y,hasCodebaseAnalysis:h(i,a,l),projectRoot:a}),S=null,C=null;!v&&s===`text`&&(S=Se(`Updating ${p.length} ${p.length===1?`task`:`tasks`} from ID ${n}${i?` (with research)`:``}…`));try{C=await Ne({role:i?`research`:`main`,session:l,projectRoot:a,systemPrompt:b,prompt:x,schema:Tt[`update-tasks`],objectName:`tasks`,commandName:`update-tasks`,outputType:v?`mcp`:`cli`}),S&&B(S,`AI update complete.`);let n=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(n))throw Error(`Parsed AI response for updated tasks was not an array.`);v?m.info(`Received ${n.length} updated tasks from AI.`):m(`debug`,`Received ${n.length} updated tasks from AI.`);let r=new Map(n.map(e=>[e.id,e])),d=new Set(p.map(e=>e.id)),h=0,g=[];return u.tasks.forEach((e,n)=>{if(d.has(e.id)&&r.has(e.id)){let i=r.get(e.id),a={...e,...i,subtasks:i.subtasks==null?e.subtasks:i.subtasks};for(let t of[`priority`,`details`,`testStrategy`])i[t]??(a[t]=e[t]);t(a,o(a,e)),Array.isArray(a.subtasks)&&(a.subtasks=a.subtasks.map(n=>{let r=e.subtasks?.find(e=>String(e.id)===String(n.id)),i={...n};return delete i.metadata,i.testStrategy==null&&r&&(i.testStrategy=r.testStrategy),c(i,r),t(i,o(n,r,e.id)),i})),u.tasks[n]=a,h++,g.push(a)}}),v?m.info(`Applied updates to ${h} tasks in the dataset.`):m(`debug`,`Applied updates to ${h} tasks in the dataset.`),O(e,u,a,f),v?m.info(`Successfully updated ${h} tasks in ${e}`):s===`text`&&console.log(he(g)),s===`text`&&C.telemetryData&&H(C.telemetryData,`cli`),{success:!0,updatedTasks:n,telemetryData:C.telemetryData,tagInfo:C.tagInfo}}catch(e){throw S&&B(S),v?m.error(`Error during AI service call: ${e.message}`):m(`error`,`Error during AI service call: ${e.message}`),e.message.includes(`API key`)&&(v?m.error(`Please ensure API keys are configured correctly in .env or mcp.json.`):m(`error`,`Please ensure API keys are configured correctly in .env or mcp.json.`)),e}finally{S&&B(S)}}catch(e){if(v?m.error(`Error updating tasks: ${e.message}`):m(`error`,`Error updating tasks: ${e.message}`),s===`text`)console.error(G.red(`Error: ${e.message}`)),F(l)&&console.error(e),process.exit(1);else throw e}}export{rt as C,qe as S,et as T,Nt as _,hi as a,lt as b,ri as c,Yt as d,ln as f,Ft as g,It as h,gi as i,ni as l,Lt as m,vi as n,ci as o,Rt as p,_i as r,ii as s,yi as t,ti as u,At as v,Je as w,Ke as x,Ot as y};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{K as e,rt as t}from"./config-manager-DTkRerDn.js";import{_ as n,a as r,b as i,c as a,d as o,g as s,h as c,i as l,l as u,m as d,n as f,o as p,p as m,r as h,s as g,t as _,u as v,v as y,y as b}from"./task-manager-CHSNsnL1.js";import{h as x}from"./src-CpPJ2WS1.js";import{n as S}from"./research-DbaGD34z.js";import{t as C}from"./response-language-CbtAaYK6.js";export{i as addSubtask,b as addTask,y as analyzeTaskComplexity,n as clearSubtasks,c as expandAllTasks,s as expandTask,x as findNextTask,e as findTaskById,d as isTaskDependentOn,m as listTasks,o as moveTask,v as parsePRD,S as performResearch,t as readComplexityReport,u as removeSubtask,g as removeTask,l as scopeDownTask,r as scopeUpTask,C as setResponseLanguage,a as taskExists,h as updateSubtaskById,f as updateTaskById,_ as updateTasks,p as validateStrength};
|
package/dist/taskgraph.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
2
|
+
import{g as e}from"./src-BQZsjzA5.js";import t from"chalk";import{join as n}from"node:path";import r from"dotenv";function i(e,n=t){e.NO_COLOR&&e.FORCE_COLOR===void 0&&(e.FORCE_COLOR=`0`,n.level=0)}i(process.env);const a=process.cwd(),o=e();r.config({path:n(o,`.env`),quiet:!0}),process.env.TASKGRAPH_ORIGINAL_CWD=a,process.env.DEBUG===`1`&&console.error(`DEBUG - dev.js received args:`,process.argv.slice(2));const{runCLI:s}=await import(`./commands-CqI6qTC_.js`);s(process.argv);export{};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taskgraph-ai",
|
|
3
|
-
"version": "0.54.
|
|
3
|
+
"version": "0.54.22",
|
|
4
4
|
"description": "Task management for AI-driven development, built for Claude Code: plan from a PRD, then work tasks one at a time with slash commands, a CLI or an MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{r as logAiUsage}from"./ai-services-unified-CvcPXr89.js";
|